/// <summary>
        /// IP end point format: "IP:Port number".
        /// IPV6 formats: [xx:xx:xx:xx:xx:xx:xx:xx]:port number, [xx:xx:xx:xx:xx:xx:xx:xx], xx:xx:xx:xx:xx:xx:xx:xx.
        /// IPV4 formats: x.x.x.x:port number, x.x.x.x.
        /// Extract IP address from "IP:Port number" end point format.
        /// </summary>
        private static string ExtractIpAddress(string endPoint)
        {
            IPAddress ipAddress = null;

            if (IPEndPointParser.TryParse(endPoint, out IPEndPoint ipEndPoint))
            {
                ipAddress = ipEndPoint.Address;
            }

            return(ipAddress?.ToString());
        }
Пример #2
0
        public void TestInvalid()
        {
            IPEndPoint ep;

            Assert.False(IPEndPointParser.TryParse(null, out ep));
            Assert.False(IPEndPointParser.TryParse("", out ep));
            Assert.False(IPEndPointParser.TryParse("132", out ep));
            Assert.False(IPEndPointParser.TryParse("300.0.0.1:1000", out ep));
            Assert.False(IPEndPointParser.TryParse("gggg::1", out ep));
            Assert.False(IPEndPointParser.TryParse("127.0.0.1:-1", out ep));
            Assert.False(IPEndPointParser.TryParse("::1:70000", out ep));
        }
Пример #3
0
        public IPEndPoint EndPoint()
        {
            if (string.IsNullOrWhiteSpace(Host))
            {
                return(null);
            }

            if (IPEndPointParser.TryParse(Host, out var endpoint))
            {
                return(endpoint);
            }

            return(null);
        }
        public void Should_TryParse()
        {
            IPEndPoint res;

            IPEndPointParser.TryParse("127.0.0.1", out res).Should().BeTrue();
            res.Should().BeEquivalentTo(new IPEndPoint(new IPAddress(new byte[] { 127, 0, 0, 1 }), 0));

            IPEndPointParser.TryParse("192.168.1.10:80", out res).Should().BeTrue();
            res.Should().BeEquivalentTo(new IPEndPoint(new IPAddress(new byte[] { 192, 168, 1, 10 }), 80));

            var ipV6      = "2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d";
            var ipV6Bytes = new byte[] { 32, 1, 13, 184, 17, 163, 9, 215, 31, 52, 138, 46, 7, 160, 118, 93 };

            IPEndPointParser.TryParse(ipV6, out res).Should().BeTrue();
            res.Should().BeEquivalentTo(new IPEndPoint(new IPAddress(ipV6Bytes), 0));

            IPEndPointParser.TryParse($"[{ipV6}]", out res).Should().BeTrue();
            res.Should().BeEquivalentTo(new IPEndPoint(new IPAddress(ipV6Bytes), 0));

            IPEndPointParser.TryParse($"[{ipV6}]:80", out res).Should().BeTrue();
            res.Should().BeEquivalentTo(new IPEndPoint(new IPAddress(ipV6Bytes), 80));
        }
Пример #5
0
        public void ApplyForwarders(HttpContext context)
        {
            // Gather expected headers. Enabled headers must have the same number of entries.
            string[] forwardedFor = null, forwardedProto = null, forwardedHost = null;
            bool     checkFor = false, checkProto = false, checkHost = false;
            int      entryCount = 0;

            if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedFor) == ForwardedHeaders.XForwardedFor)
            {
                checkFor     = true;
                forwardedFor = context.Request.Headers.GetCommaSeparatedValues(XForwardedForHeaderName);
                entryCount   = Math.Max(forwardedFor.Length, entryCount);
            }

            if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedProto) == ForwardedHeaders.XForwardedProto)
            {
                checkProto     = true;
                forwardedProto = context.Request.Headers.GetCommaSeparatedValues(XForwardedProtoHeaderName);
                if (_options.RequireHeaderSymmetry && checkFor && forwardedFor.Length != forwardedProto.Length)
                {
                    _logger.LogDebug(1, "Parameter count mismatch between X-Forwarded-For and X-Forwarded-Proto.");
                    return;
                }
                entryCount = Math.Max(forwardedProto.Length, entryCount);
            }

            if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedHost) == ForwardedHeaders.XForwardedHost)
            {
                checkHost     = true;
                forwardedHost = context.Request.Headers.GetCommaSeparatedValues(XForwardedHostHeaderName);
                if (_options.RequireHeaderSymmetry &&
                    ((checkFor && forwardedFor.Length != forwardedHost.Length) ||
                     (checkProto && forwardedProto.Length != forwardedHost.Length)))
                {
                    _logger.LogDebug(1, "Parameter count mismatch between X-Forwarded-Host and X-Forwarded-For or X-Forwarded-Proto.");
                    return;
                }
                entryCount = Math.Max(forwardedHost.Length, entryCount);
            }

            // Apply ForwardLimit, if any
            if (_options.ForwardLimit.HasValue && entryCount > _options.ForwardLimit)
            {
                entryCount = _options.ForwardLimit.Value;
            }

            // Group the data together.
            var sets = new SetOfForwarders[entryCount];

            for (int i = 0; i < sets.Length; i++)
            {
                // They get processed in reverse order, right to left.
                var set = new SetOfForwarders();
                if (checkFor && i < forwardedFor.Length)
                {
                    set.IpAndPortText = forwardedFor[forwardedFor.Length - i - 1];
                }
                if (checkProto && i < forwardedProto.Length)
                {
                    set.Scheme = forwardedProto[forwardedProto.Length - i - 1];
                }
                if (checkHost && i < forwardedHost.Length)
                {
                    set.Host = forwardedHost[forwardedHost.Length - i - 1];
                }
                sets[i] = set;
            }

            // Gather initial values
            var connection    = context.Connection;
            var request       = context.Request;
            var currentValues = new SetOfForwarders()
            {
                RemoteIpAndPort = connection.RemoteIpAddress != null ? new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort) : null,
                // Host and Scheme initial values are never inspected, no need to set them here.
            };

            var  checkKnownIps   = _options.KnownNetworks.Count > 0 || _options.KnownProxies.Count > 0;
            bool applyChanges    = false;
            int  entriesConsumed = 0;

            for ( ; entriesConsumed < sets.Length; entriesConsumed++)
            {
                var set = sets[entriesConsumed];
                if (checkFor)
                {
                    // For the first instance, allow remoteIp to be null for servers that don't support it natively.
                    if (currentValues.RemoteIpAndPort != null && checkKnownIps && !CheckKnownAddress(currentValues.RemoteIpAndPort.Address))
                    {
                        // Stop at the first unknown remote IP, but still apply changes processed so far.
                        _logger.LogDebug(1, $"Unknown proxy: {currentValues.RemoteIpAndPort}");
                        break;
                    }

                    IPEndPoint parsedEndPoint;
                    if (IPEndPointParser.TryParse(set.IpAndPortText, out parsedEndPoint))
                    {
                        applyChanges                  = true;
                        set.RemoteIpAndPort           = parsedEndPoint;
                        currentValues.IpAndPortText   = set.IpAndPortText;
                        currentValues.RemoteIpAndPort = set.RemoteIpAndPort;
                    }
                    else if (_options.RequireHeaderSymmetry)
                    {
                        _logger.LogDebug(2, $"Failed to parse forwarded IPAddress: {currentValues.IpAndPortText}");
                        return;
                    }
                }

                if (checkProto)
                {
                    if (!string.IsNullOrEmpty(set.Scheme))
                    {
                        applyChanges         = true;
                        currentValues.Scheme = set.Scheme;
                    }
                    else if (_options.RequireHeaderSymmetry)
                    {
                        _logger.LogDebug(3, $"Failed to parse forwarded scheme: {set.Scheme}");
                        return;
                    }
                }

                if (checkHost)
                {
                    if (!string.IsNullOrEmpty(set.Host))
                    {
                        applyChanges       = true;
                        currentValues.Host = set.Host;
                    }
                    else if (_options.RequireHeaderSymmetry)
                    {
                        _logger.LogDebug(4, $"Failed to parse forwarded host: {set.Host}");
                        return;
                    }
                }
            }

            if (applyChanges)
            {
                if (checkFor && currentValues.RemoteIpAndPort != null)
                {
                    if (connection.RemoteIpAddress != null)
                    {
                        // Save the original
                        request.Headers[XOriginalForName] = new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort).ToString();
                    }
                    if (forwardedFor.Length > entriesConsumed)
                    {
                        // Truncate the consumed header values
                        request.Headers[XForwardedForHeaderName] = forwardedFor.Take(forwardedFor.Length - entriesConsumed).ToArray();
                    }
                    else
                    {
                        // All values were consumed
                        request.Headers.Remove(XForwardedForHeaderName);
                    }
                    connection.RemoteIpAddress = currentValues.RemoteIpAndPort.Address;
                    connection.RemotePort      = currentValues.RemoteIpAndPort.Port;
                }

                if (checkProto && currentValues.Scheme != null)
                {
                    // Save the original
                    request.Headers[XOriginalProtoName] = request.Scheme;
                    if (forwardedProto.Length > entriesConsumed)
                    {
                        // Truncate the consumed header values
                        request.Headers[XForwardedProtoHeaderName] = forwardedProto.Take(forwardedProto.Length - entriesConsumed).ToArray();
                    }
                    else
                    {
                        // All values were consumed
                        request.Headers.Remove(XForwardedProtoHeaderName);
                    }
                    request.Scheme = currentValues.Scheme;
                }

                if (checkHost && currentValues.Host != null)
                {
                    // Save the original
                    request.Headers[XOriginalHostName] = request.Host.ToString();
                    if (forwardedHost.Length > entriesConsumed)
                    {
                        // Truncate the consumed header values
                        request.Headers[XForwardedHostHeaderName] = forwardedHost.Take(forwardedHost.Length - entriesConsumed).ToArray();
                    }
                    else
                    {
                        // All values were consumed
                        request.Headers.Remove(XForwardedHostHeaderName);
                    }
                    request.Host = HostString.FromUriComponent(currentValues.Host);
                }
            }
        }
        public virtual Url parse(string url)
        {
            if (string.IsNullOrWhiteSpace(url))
            {
                throw new ArgumentException("Illegal format address string [" + url + "], should not be blank! ");
            }
            Url parsedUrl = tryGet(url);

            if (null != parsedUrl)
            {
                return(parsedUrl);
            }
            IPAddress  ip         = null;
            int        port       = 0;
            Properties properties = null;

            int size = url.Length;
            int pos  = 0;

            //for (int i = 0; i < size; ++i)
            //{
            //    if (RemotingAddressParser_Fields.COLON == url[i])
            //    {
            //        ip = url.Substring(pos, i - pos);
            //        pos = i;
            //        // should not end with COLON
            //        if (i == size - 1)
            //        {
            //            throw new ArgumentException("Illegal format address string [" + url + "], should not end with COLON[:]! ");
            //        }
            //        break;
            //    }
            //    // must have one COLON
            //    if (i == size - 1)
            //    {
            //        throw new ArgumentException("Illegal format address string [" + url + "], must have one COLON[:]! ");
            //    }
            //}

            for (int i = 0; i < size; ++i)
            {
                if (RemotingAddressParser_Fields.QUES == url[i])
                {
                    var ipEndPointString = url.Substring(pos, i - pos);
                    IPEndPointParser.TryParse(ipEndPointString, out var ipEndPoint);
                    ip   = ipEndPoint.Address;
                    port = ipEndPoint.Port;
                    pos  = i;
                    if (i == size - 1)
                    {
                        // should not end with QUES
                        throw new ArgumentException("Illegal format address string [" + url + "], should not end with QUES[?]! ");
                    }
                    break;
                }
                // end without a QUES
                if (i == size - 1)
                {
                    var ipEndPointString          = url.Substring(pos, i - pos + 1);
                    var ipOrHostAndPortSplitIndex = ipEndPointString.LastIndexOf(':');

                    var ipOrHost   = ipEndPointString.Substring(0, ipOrHostAndPortSplitIndex);
                    var portString = ipEndPointString.Substring(ipOrHostAndPortSplitIndex + 1);
                    if (int.TryParse(portString, out var portParsed))
                    {
                        port = portParsed;
                    }
                    else
                    {
                        throw new ArgumentException("Illegal format address string [" + url + "], must have a valid port! ");
                    }

                    if (port <= 0)
                    {
                        throw new ArgumentException("Illegal format address string [" + url + "], must have a valid port! ");
                    }

                    if (IPAddress.TryParse(ipOrHost, out var ipAddress))
                    {
                        ip = ipAddress;
                    }
                    else
                    {
                        var addresses = Dns.GetHostAddresses(ipOrHost);
                        if (addresses.Length == 0)
                        {
                            throw new ArgumentException("Unable to retrieve address from specified host name!");
                        }
                        ip = addresses[0];
                    }

                    pos = size;
                }
            }

            if (pos < (size - 1))
            {
                properties = new Properties();
                while (pos < (size - 1))
                {
                    string key   = null;
                    string value = null;
                    for (int i = pos; i < size; ++i)
                    {
                        if (RemotingAddressParser_Fields.EQUAL == url[i])
                        {
                            key = url.Substring(pos + 1, i - (pos + 1));
                            pos = i;
                            if (i == size - 1)
                            {
                                // should not end with EQUAL
                                throw new ArgumentException("Illegal format address string [" + url + "], should not end with EQUAL[=]! ");
                            }
                            break;
                        }
                        if (i == size - 1)
                        {
                            // must have one EQUAL
                            throw new ArgumentException("Illegal format address string [" + url + "], must have one EQUAL[=]! ");
                        }
                    }
                    for (int i = pos; i < size; ++i)
                    {
                        if (RemotingAddressParser_Fields.AND == url[i])
                        {
                            value = url.Substring(pos + 1, i - (pos + 1));
                            pos   = i;
                            if (i == size - 1)
                            {
                                // should not end with AND
                                throw new ArgumentException("Illegal format address string [" + url + "], should not end with AND[&]! ");
                            }
                            break;
                        }
                        // end without more AND
                        if (i == size - 1)
                        {
                            value = url.Substring(pos + 1, i + 1 - (pos + 1));
                            pos   = size;
                        }
                    }
                    properties.put(key, value);
                }
            }
            parsedUrl = new Url(url, ip, port, properties);
            initUrlArgs(parsedUrl);
            Url.parsedUrls.AddOrUpdate(url, new SoftReference(parsedUrl), (key, oldValue) => new SoftReference(parsedUrl));
            return(parsedUrl);
        }