Beispiel #1
0
    private static async Task InternalEventLoopAsync(AxisService service, Socket socket, CancellationToken cancellationToken = default)
    {
        using var socketCap = new SocketCap(socket);

        var bytesPool = BytesPool.Shared;

        await using var batchActionDispatcher = new BatchActionDispatcher(TimeSpan.FromMilliseconds(10));

        var bridgeConnectionOptions = new BridgeConnectionOptions(int.MaxValue);

        await using var bridgeConnection = new BridgeConnection(socketCap, null, null, batchActionDispatcher, bytesPool, bridgeConnectionOptions);

        var multiplexerOption = new OmniConnectionMultiplexerOptions(OmniConnectionMultiplexerType.Accepted, TimeSpan.FromMinutes(1), 3, 1024 * 1024 * 4, 3);

        await using var multiplexer = OmniConnectionMultiplexer.CreateV1(bridgeConnection, batchActionDispatcher, bytesPool, multiplexerOption);

        await multiplexer.HandshakeAsync(cancellationToken);

        var errorMessageFactory = new DefaultErrorMessageFactory();
        var listenerFactory     = new RocketRemotingListenerFactory <DefaultErrorMessage>(multiplexer, errorMessageFactory, bytesPool);

        try
        {
            _logger.Debug("InternalEventLoopAsync: Start");

            var server = new AxisServiceRemoting.Server <DefaultErrorMessage>(service, listenerFactory, bytesPool);

            var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
            using var onCloseListener = bridgeConnection.Events.OnClosed.Listen(() => linkedCancellationTokenSource.Cancel());

            await server.EventLoopAsync(linkedCancellationTokenSource.Token);
        }
        catch (Exception e)
        {
            _logger.Error(e);
        }
        finally
        {
            _logger.Debug("InternalEventLoopAsync: End");
        }
    }
Beispiel #2
0
        public Cap ConnectCap(string uri)
        {
            if (_disposed)
            {
                return(null);
            }
            if (this.State == ManagerState.Stop)
            {
                return(null);
            }

            if (!uri.StartsWith("tcp:"))
            {
                return(null);
            }

            var garbages = new List <IDisposable>();

            try
            {
                var config = this.Config;

                var result = UriUtils.Parse(uri);
                if (result == null)
                {
                    throw new Exception();
                }

                string scheme = result.GetValue <string>("Scheme");
                if (scheme != "tcp")
                {
                    return(null);
                }

                string address = result.GetValue <string>("Address");
                int    port    = result.GetValueOrDefault <int>("Port", () => 4050);

                // Check
                {
                    IPAddress ipAddress;

                    if (!IPAddress.TryParse(address, out ipAddress))
                    {
                        return(null);
                    }

#if !DEBUG
                    if (!IsGlobalIpAddress(ipAddress))
                    {
                        return(null);
                    }
#endif

                    if (!config.Type.HasFlag(TcpConnectionType.Ipv4) &&
                        ipAddress.AddressFamily == AddressFamily.InterNetwork)
                    {
                        return(null);
                    }
                    if (!config.Type.HasFlag(TcpConnectionType.Ipv6) &&
                        ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
                    {
                        return(null);
                    }

                    if (!_catharsisManager.Check(ipAddress))
                    {
                        _blockCount.Increment();

                        return(null);
                    }
                }

                if (!string.IsNullOrWhiteSpace(config.ProxyUri))
                {
                    var result2 = UriUtils.Parse(config.ProxyUri);
                    if (result2 == null)
                    {
                        throw new Exception();
                    }

                    string proxyScheme = result2.GetValue <string>("Scheme");

                    if (proxyScheme == "socks" || proxyScheme == "socks5")
                    {
                        string proxyAddress = result2.GetValue <string>("Address");
                        int    proxyPort    = result2.GetValueOrDefault <int>("Port", () => 1080);

                        var socket = Connect(new IPEndPoint(GetIpAddress(proxyAddress), proxyPort));
                        garbages.Add(socket);

                        var proxy = new Socks5ProxyClient(address, port);
                        proxy.Create(socket, new TimeSpan(0, 0, 30));

                        var cap = new SocketCap(socket);
                        garbages.Add(cap);

                        return(cap);
                    }
                    else if (proxyScheme == "http")
                    {
                        string proxyAddress = result2.GetValue <string>("Address");
                        int    proxyPort    = result2.GetValueOrDefault <int>("Port", () => 80);

                        var socket = Connect(new IPEndPoint(GetIpAddress(proxyAddress), proxyPort));
                        garbages.Add(socket);

                        var proxy = new HttpProxyClient(address, port);
                        proxy.Create(socket, new TimeSpan(0, 0, 30));

                        var cap = new SocketCap(socket);
                        garbages.Add(cap);

                        return(cap);
                    }
                }
                else
                {
                    var socket = Connect(new IPEndPoint(IPAddress.Parse(address), port));
                    garbages.Add(socket);

                    var cap = new SocketCap(socket);
                    garbages.Add(cap);

                    return(cap);
                }
            }
            catch (Exception)
            {
                foreach (var item in garbages)
                {
                    item.Dispose();
                }
            }

            return(null);
        }
            public Cap ConnectCap(string uri)
            {
                if (_isDisposed)
                {
                    return(null);
                }
                if (this.State == ManagerState.Stop)
                {
                    return(null);
                }

                var garbages = new List <IDisposable>();

                try
                {
                    var config = this.Config;

                    var result = UriUtils.Parse(uri);
                    if (result == null)
                    {
                        throw new Exception();
                    }

                    string scheme  = result.GetValue <string>("Scheme");
                    string address = result.GetValue <string>("Address");
                    int    port    = result.GetValueOrDefault <int>("Port", () => 4050);

                    var connectionFilter = config.ConnectionFilters.FirstOrDefault(n => n.Scheme == scheme);
                    if (connectionFilter == null || connectionFilter.Type == ConnectionType.None)
                    {
                        return(null);
                    }

                    if (connectionFilter.Type == ConnectionType.Tcp)
                    {
                        // Check
                        {
                            IPAddress ipAddress;

                            if (!IPAddress.TryParse(address, out ipAddress))
                            {
                                return(null);
                            }

#if !DEBUG
                            if (!CheckGlobalIpAddress(ipAddress))
                            {
                                return(null);
                            }
#endif

                            if (!_catharsisManager.Check(ipAddress))
                            {
                                _blockCount.Increment();

                                return(null);
                            }
                        }

                        var socket = Connect(new IPEndPoint(IPAddress.Parse(address), port));
                        garbages.Add(socket);

                        var cap = new SocketCap(socket);
                        garbages.Add(cap);

                        return(cap);
                    }
                    else if (connectionFilter.Type == ConnectionType.Socks5Proxy ||
                             connectionFilter.Type == ConnectionType.HttpProxy)
                    {
                        var result2 = UriUtils.Parse(connectionFilter.ProxyUri);
                        if (result2 == null)
                        {
                            throw new Exception();
                        }

                        string proxyScheme = result2.GetValue <string>("Scheme");
                        if (proxyScheme != "tcp")
                        {
                            throw new Exception();
                        }

                        if (connectionFilter.Type == ConnectionType.HttpProxy)
                        {
                            string proxyAddress = result2.GetValue <string>("Address");
                            int    proxyPort    = result2.GetValueOrDefault <int>("Port", () => 1080);

                            var socket = Connect(new IPEndPoint(GetIpAddress(proxyAddress), proxyPort));
                            garbages.Add(socket);

                            var proxy = new HttpProxyClient(address, port);
                            proxy.Create(socket, new TimeSpan(0, 0, 30));

                            var cap = new SocketCap(socket);
                            garbages.Add(cap);

                            return(cap);
                        }
                        else if (connectionFilter.Type == ConnectionType.Socks5Proxy)
                        {
                            string proxyAddress = result2.GetValue <string>("Address");
                            int    proxyPort    = result2.GetValueOrDefault <int>("Port", () => 80);

                            var socket = Connect(new IPEndPoint(GetIpAddress(proxyAddress), proxyPort));
                            garbages.Add(socket);

                            var proxy = new Socks5ProxyClient(address, port);
                            proxy.Create(socket, new TimeSpan(0, 0, 30));

                            var cap = new SocketCap(socket);
                            garbages.Add(cap);

                            return(cap);
                        }
                    }
                }
                catch (Exception)
                {
                    foreach (var item in garbages)
                    {
                        item.Dispose();
                    }
                }

                return(null);
            }
Beispiel #4
0
        public Connection CreateConnection(string uri, BandwidthLimit bandwidthLimit)
        {
            List <IDisposable> garbages = new List <IDisposable>();

            try
            {
                Connection connection = null;

                if (connection == null)
                {
                    // Overlay network
                    var cap = this.OnCreateCapEvent(uri);
                    if (cap == null)
                    {
                        goto End;
                    }

                    garbages.Add(cap);

                    connection = new BaseConnection(cap, bandwidthLimit, _maxReceiveCount, _bufferManager);
                    garbages.Add(connection);

                    End :;
                }

                if (connection == null)
                {
                    ConnectionFilter connectionFilter = null;

                    lock (this.ThisLock)
                    {
                        foreach (var filter in this.Filters)
                        {
                            if (filter.UriCondition.IsMatch(uri))
                            {
                                if (filter.ConnectionType != ConnectionType.None)
                                {
                                    connectionFilter = filter.Clone();
                                }

                                break;
                            }
                        }
                    }

                    if (connectionFilter == null)
                    {
                        return(null);
                    }

                    string scheme = null;
                    string host   = null;
                    int    port   = -1;

                    {
                        var match = _regex.Match(uri);

                        if (match.Success)
                        {
                            scheme = match.Groups[1].Value;
                            host   = match.Groups[2].Value;
                            port   = int.Parse(match.Groups[3].Value);
                        }
                        else
                        {
                            var match2 = _regex2.Match(uri);

                            if (match2.Success)
                            {
                                scheme = match2.Groups[1].Value;
                                host   = match2.Groups[2].Value;
                                port   = 4050;
                            }
                        }
                    }

                    if (host == null)
                    {
                        return(null);
                    }

                    IList <KeyValuePair <string, string> > options = null;

                    if (!string.IsNullOrWhiteSpace(connectionFilter.Option))
                    {
                        options = ClientManager.Decode(connectionFilter.Option).OfType <KeyValuePair <string, string> >().ToList();
                    }

                    if (connectionFilter.ConnectionType == ConnectionType.Tcp)
                    {
                        var ipAddress = ClientManager.GetIpAddress(host);
                        if (ipAddress == null)
                        {
                            return(null);
                        }

                        host = ipAddress.ToString();
                        uri  = string.Format("{0}:{1}:{2}", scheme, host, port);

                        if (!this.OnCheckUriEvent(uri))
                        {
                            return(null);
                        }

#if !DEBUG
                        // Check
                        {
                            Uri url = new Uri(string.Format("{0}://{1}:{2}", scheme, host, port));

                            if (url.HostNameType == UriHostNameType.IPv4)
                            {
                                if (IPAddress.Any.ToString() == ipAddress.ToString() ||
                                    IPAddress.Loopback.ToString() == ipAddress.ToString() ||
                                    IPAddress.Broadcast.ToString() == ipAddress.ToString())
                                {
                                    return(null);
                                }
                                if (CollectionUtilities.Compare(ipAddress.GetAddressBytes(), IPAddress.Parse("10.0.0.0").GetAddressBytes()) >= 0 &&
                                    CollectionUtilities.Compare(ipAddress.GetAddressBytes(), IPAddress.Parse("10.255.255.255").GetAddressBytes()) <= 0)
                                {
                                    return(null);
                                }
                                if (CollectionUtilities.Compare(ipAddress.GetAddressBytes(), IPAddress.Parse("172.16.0.0").GetAddressBytes()) >= 0 &&
                                    CollectionUtilities.Compare(ipAddress.GetAddressBytes(), IPAddress.Parse("172.31.255.255").GetAddressBytes()) <= 0)
                                {
                                    return(null);
                                }
                                if (CollectionUtilities.Compare(ipAddress.GetAddressBytes(), IPAddress.Parse("127.0.0.0").GetAddressBytes()) >= 0 &&
                                    CollectionUtilities.Compare(ipAddress.GetAddressBytes(), IPAddress.Parse("127.255.255.255").GetAddressBytes()) <= 0)
                                {
                                    return(null);
                                }
                                if (CollectionUtilities.Compare(ipAddress.GetAddressBytes(), IPAddress.Parse("192.168.0.0").GetAddressBytes()) >= 0 &&
                                    CollectionUtilities.Compare(ipAddress.GetAddressBytes(), IPAddress.Parse("192.168.255.255").GetAddressBytes()) <= 0)
                                {
                                    return(null);
                                }
                            }
                            else if (url.HostNameType == UriHostNameType.IPv6)
                            {
                                if (IPAddress.IPv6Any.ToString() == ipAddress.ToString() ||
                                    IPAddress.IPv6Loopback.ToString() == ipAddress.ToString() ||
                                    IPAddress.IPv6None.ToString() == ipAddress.ToString())
                                {
                                    return(null);
                                }
                                if (ipAddress.ToString().ToLower().StartsWith("fe80:"))
                                {
                                    return(null);
                                }
                            }
                        }
#endif

                        var socket = ClientManager.Connect(new IPEndPoint(ipAddress, port), new TimeSpan(0, 0, 10));
                        garbages.Add(socket);

                        var cap = new SocketCap(socket);
                        garbages.Add(cap);

                        connection = new BaseConnection(cap, bandwidthLimit, _maxReceiveCount, _bufferManager);
                        garbages.Add(connection);
                    }
                    else
                    {
                        if (!this.OnCheckUriEvent(uri))
                        {
                            return(null);
                        }

                        string proxyScheme = null;
                        string proxyHost   = null;
                        int    proxyPort   = -1;

                        {
                            var match = _regex.Match(connectionFilter.ProxyUri);

                            if (match.Success)
                            {
                                proxyScheme = match.Groups[1].Value;
                                proxyHost   = match.Groups[2].Value;
                                proxyPort   = int.Parse(match.Groups[3].Value);
                            }
                            else
                            {
                                var match2 = _regex2.Match(connectionFilter.ProxyUri);

                                if (match2.Success)
                                {
                                    proxyScheme = match2.Groups[1].Value;
                                    proxyHost   = match2.Groups[2].Value;

                                    if (connectionFilter.ConnectionType == ConnectionType.Socks4Proxy ||
                                        connectionFilter.ConnectionType == ConnectionType.Socks4aProxy ||
                                        connectionFilter.ConnectionType == ConnectionType.Socks5Proxy)
                                    {
                                        proxyPort = 1080;
                                    }
                                    else if (connectionFilter.ConnectionType == ConnectionType.HttpProxy)
                                    {
                                        proxyPort = 80;
                                    }
                                }
                            }
                        }

                        if (proxyHost == null)
                        {
                            return(null);
                        }

                        if (connectionFilter.ConnectionType == ConnectionType.Socks4Proxy ||
                            connectionFilter.ConnectionType == ConnectionType.Socks4aProxy ||
                            connectionFilter.ConnectionType == ConnectionType.Socks5Proxy ||
                            connectionFilter.ConnectionType == ConnectionType.HttpProxy)
                        {
                            var socket = ClientManager.Connect(new IPEndPoint(ClientManager.GetIpAddress(proxyHost), proxyPort), new TimeSpan(0, 0, 10));
                            garbages.Add(socket);

                            ProxyClientBase proxy = null;

                            if (connectionFilter.ConnectionType == ConnectionType.Socks4Proxy)
                            {
                                var user = (options != null) ? options.Where(n => n.Key.ToLower().StartsWith("user")).Select(n => n.Value).FirstOrDefault() : null;
                                proxy = new Socks4ProxyClient(socket, user, host, port);
                            }
                            else if (connectionFilter.ConnectionType == ConnectionType.Socks4aProxy)
                            {
                                var user = (options != null) ? options.Where(n => n.Key.ToLower().StartsWith("user")).Select(n => n.Value).FirstOrDefault() : null;
                                proxy = new Socks4aProxyClient(socket, user, host, port);
                            }
                            else if (connectionFilter.ConnectionType == ConnectionType.Socks5Proxy)
                            {
                                var user = (options != null) ? options.Where(n => n.Key.ToLower().StartsWith("user")).Select(n => n.Value).FirstOrDefault() : null;
                                var pass = (options != null) ? options.Where(n => n.Key.ToLower().StartsWith("pass")).Select(n => n.Value).FirstOrDefault() : null;
                                proxy = new Socks5ProxyClient(socket, user, pass, host, port);
                            }
                            else if (connectionFilter.ConnectionType == ConnectionType.HttpProxy)
                            {
                                proxy = new HttpProxyClient(socket, host, port);
                            }

                            var cap = new SocketCap(proxy.Create(new TimeSpan(0, 0, 30)));
                            garbages.Add(cap);

                            connection = new BaseConnection(cap, bandwidthLimit, _maxReceiveCount, _bufferManager);
                            garbages.Add(connection);
                        }
                    }
                }

                if (connection == null)
                {
                    return(null);
                }

                var secureConnection = new SecureConnection(SecureConnectionVersion.Version3, SecureConnectionType.Connect, connection, null, _bufferManager);
                garbages.Add(secureConnection);

                secureConnection.Connect(new TimeSpan(0, 0, 30));

                var compressConnection = new CompressConnection(secureConnection, _maxReceiveCount, _bufferManager);
                garbages.Add(compressConnection);

                compressConnection.Connect(new TimeSpan(0, 0, 10));

                return(compressConnection);
            }
            catch (Exception)
            {
                foreach (var item in garbages)
                {
                    item.Dispose();
                }
            }

            return(null);
        }
Beispiel #5
0
        public Connection AcceptConnection(out string uri, BandwidthLimit bandwidthLimit)
        {
            uri = null;
            List <IDisposable> garbages = new List <IDisposable>();

            try
            {
                Connection connection = null;

                foreach (var type in (new int[] { 0, 1 }).Randomize())
                {
                    if (this.State == ManagerState.Stop)
                    {
                        return(null);
                    }

                    if (type == 0)
                    {
                        lock (this.ThisLock)
                        {
                            foreach (var item in _tcpListeners)
                            {
                                if (item.Value.Pending())
                                {
                                    var socket = item.Value.AcceptTcpClient().Client;
                                    garbages.Add(socket);

                                    {
                                        var remoteEndPoint = (IPEndPoint)socket.RemoteEndPoint;

                                        uri = string.Format("tcp:{0}:{1}", remoteEndPoint.Address, remoteEndPoint.Port);
                                    }

                                    if (!this.OnCheckUriEvent(uri))
                                    {
                                        _blockedCount.Increment();

                                        continue;
                                    }

                                    var cap = new SocketCap(socket);
                                    garbages.Add(cap);

                                    connection = new BaseConnection(cap, bandwidthLimit, _maxReceiveCount, _bufferManager);
                                    garbages.Add(connection);
                                }
                            }
                        }
                    }
                    else if (type == 1)
                    {
                        // Overlay network
                        var cap = this.OnAcceptCapEvent(out uri);
                        if (cap == null)
                        {
                            continue;
                        }

                        garbages.Add(cap);

                        connection = new BaseConnection(cap, bandwidthLimit, _maxReceiveCount, _bufferManager);
                        garbages.Add(connection);
                    }

                    if (connection != null)
                    {
                        break;
                    }
                }

                if (connection == null)
                {
                    return(null);
                }

                var secureConnection = new SecureConnection(SecureConnectionVersion.Version3, SecureConnectionType.Accept, connection, null, _bufferManager);
                garbages.Add(secureConnection);

                secureConnection.Connect(new TimeSpan(0, 0, 30));

                var compressConnection = new CompressConnection(secureConnection, _maxReceiveCount, _bufferManager);
                garbages.Add(compressConnection);

                compressConnection.Connect(new TimeSpan(0, 0, 10));

                return(compressConnection);
            }
            catch (Exception)
            {
                foreach (var item in garbages)
                {
                    item.Dispose();
                }
            }

            return(null);
        }
Beispiel #6
0
        public async ValueTask <ICap?> ConnectAsync(OmniAddress address, CancellationToken cancellationToken = default)
        {
            using (await _asyncLock.LockAsync())
            {
                this.ThrowIfDisposingRequested();

                var config = _tcpConnectOptions;
                if (config == null || !config.Enabled)
                {
                    return(null);
                }

                if (!TryGetEndpoint(address, out var ipAddress, out ushort port))
                {
                    return(null);
                }

                var disposableList = new List <IDisposable>();

                try
                {
#if !DEBUG
                    if (!IsGlobalIpAddress(ipAddress))
                    {
                        return(null);
                    }
#endif

                    if (config.ProxyOptions != null)
                    {
                        if (!TryGetEndpoint(config.ProxyOptions.Address, out var proxyAddress, out ushort proxyPort, true))
                        {
                            return(null);
                        }

                        if (config.ProxyOptions.Type == TcpProxyType.Socks5Proxy)
                        {
                            var socket = await ConnectAsync(new IPEndPoint(proxyAddress, proxyPort));

                            if (socket == null)
                            {
                                return(null);
                            }

                            disposableList.Add(socket);

                            var proxy = new Socks5ProxyClient(ipAddress.ToString(), port);
                            await proxy.ConnectAsync(socket, cancellationToken);

                            var cap = new SocketCap(socket);
                            disposableList.Add(cap);

                            return(cap);
                        }
                        else if (config.ProxyOptions.Type == TcpProxyType.HttpProxy)
                        {
                            var socket = await ConnectAsync(new IPEndPoint(proxyAddress, proxyPort));

                            if (socket == null)
                            {
                                return(null);
                            }

                            disposableList.Add(socket);

                            var proxy = new HttpProxyClient(ipAddress.ToString(), port);
                            await proxy.ConnectAsync(socket, cancellationToken);

                            var cap = new SocketCap(socket);
                            disposableList.Add(cap);

                            return(cap);
                        }
                    }
                    else
                    {
                        var socket = await ConnectAsync(new IPEndPoint(ipAddress, port));

                        if (socket == null)
                        {
                            return(null);
                        }

                        disposableList.Add(socket);

                        var cap = new SocketCap(socket);
                        disposableList.Add(cap);

                        return(cap);
                    }
                }
                catch (Exception e)
                {
                    _logger.Error(e);

                    foreach (var item in disposableList)
                    {
                        item.Dispose();
                    }
                }

                return(null);
            }
        }
        public Connection AcceptConnection(out string uri, BandwidthLimit bandwidthLimit)
        {
            uri = null;
            var garbages = new List<IDisposable>();

            try
            {
                Connection connection = null;

                foreach (var type in (new int[] { 0, 1 }).Randomize())
                {
                    if (this.State == ManagerState.Stop) return null;

                    if (type == 0)
                    {
                        lock (_thisLock)
                        {
                            foreach (var item in _tcpListeners)
                            {
                                if (item.Value.Pending())
                                {
                                    var socket = item.Value.AcceptTcpClient().Client;
                                    garbages.Add(socket);

                                    {
                                        var remoteEndPoint = (IPEndPoint)socket.RemoteEndPoint;

                                        uri = string.Format("tcp:{0}:{1}", remoteEndPoint.Address, remoteEndPoint.Port);
                                    }

                                    if (!this.OnCheckUriEvent(uri))
                                    {
                                        _blockedCount.Increment();

                                        continue;
                                    }

                                    var cap = new SocketCap(socket);
                                    garbages.Add(cap);

                                    connection = new BaseConnection(cap, bandwidthLimit, _maxReceiveCount, _bufferManager);
                                    garbages.Add(connection);
                                }
                            }
                        }
                    }
                    else if (type == 1)
                    {
                        // Overlay network
                        var cap = this.OnAcceptCapEvent(out uri);
                        if (cap == null) continue;

                        garbages.Add(cap);

                        connection = new BaseConnection(cap, bandwidthLimit, _maxReceiveCount, _bufferManager);
                        garbages.Add(connection);
                    }

                    if (connection != null) break;
                }

                if (connection == null) return null;

                var secureConnection = new SecureConnection(SecureConnectionVersion.Version3, SecureConnectionType.Accept, connection, null, _bufferManager);
                garbages.Add(secureConnection);

                secureConnection.Connect(new TimeSpan(0, 0, 30));

                var compressConnection = new CompressConnection(secureConnection, _maxReceiveCount, _bufferManager);
                garbages.Add(compressConnection);

                compressConnection.Connect(new TimeSpan(0, 0, 10));

                return compressConnection;
            }
            catch (Exception)
            {
                foreach (var item in garbages)
                {
                    item.Dispose();
                }
            }

            return null;
        }
    public async ValueTask <ICap?> ConnectCapAsync(OmniAddress address, CancellationToken cancellationToken = default)
    {
        this.ThrowIfDisposingRequested();

        if (!address.TryGetTcpEndpoint(out var ipAddress, out ushort port))
        {
            return(null);
        }

#if !DEBUG
        if (!Internal.IpAddressHelper.IsGlobalIpAddress(ipAddress))
        {
            return(null);
        }
#endif

        var disposableList = new List <IDisposable>();

        try
        {
            if (_options.Proxy?.Address is not null && _options.Proxy.Address.TryGetTcpEndpoint(out var proxyAddress, out ushort proxyPort, true))
            {
                if (_socks5ProxyClientFactory is not null && _options.Proxy.Type == TcpProxyType.Socks5Proxy)
                {
                    var socket = await ConnectSocketAsync(new IPEndPoint(proxyAddress, proxyPort), cancellationToken);

                    if (socket == null)
                    {
                        return(null);
                    }

                    disposableList.Add(socket);

                    var proxy = _socks5ProxyClientFactory.Create(ipAddress.ToString(), port);
                    await proxy.ConnectAsync(socket, cancellationToken);

                    var cap = new SocketCap(socket);
                    disposableList.Add(cap);

                    return(cap);
                }
                else if (_httpProxyClientFactory is not null && _options.Proxy.Type == TcpProxyType.HttpProxy)
                {
                    var socket = await ConnectSocketAsync(new IPEndPoint(proxyAddress, proxyPort), cancellationToken);

                    if (socket == null)
                    {
                        return(null);
                    }

                    disposableList.Add(socket);

                    var proxy = _httpProxyClientFactory.Create(ipAddress.ToString(), port);
                    await proxy.ConnectAsync(socket, cancellationToken);

                    var cap = new SocketCap(socket);
                    disposableList.Add(cap);

                    return(cap);
                }
            }
        public Connection CreateConnection(string uri, BandwidthLimit bandwidthLimit)
        {
            var garbages = new List<IDisposable>();

            try
            {
                Connection connection = null;

                if (connection == null)
                {
                    // Overlay network
                    var cap = this.OnCreateCapEvent(uri);
                    if (cap == null) goto End;

                    garbages.Add(cap);

                    connection = new BaseConnection(cap, bandwidthLimit, _maxReceiveCount, _bufferManager);
                    garbages.Add(connection);

                    End:;
                }

                if (connection == null)
                {
                    ConnectionFilter connectionFilter = null;

                    lock (_thisLock)
                    {
                        foreach (var filter in this.Filters)
                        {
                            if (filter.UriCondition.IsMatch(uri))
                            {
                                if (filter.ConnectionType != ConnectionType.None)
                                {
                                    connectionFilter = filter;
                                }

                                break;
                            }
                        }
                    }

                    if (connectionFilter == null) return null;

                    string scheme = null;
                    string host = null;
                    int port = -1;

                    {
                        var match = _regex.Match(uri);

                        if (match.Success)
                        {
                            scheme = match.Groups[1].Value;
                            host = match.Groups[2].Value;
                            port = int.Parse(match.Groups[3].Value);
                        }
                        else
                        {
                            var match2 = _regex2.Match(uri);

                            if (match2.Success)
                            {
                                scheme = match2.Groups[1].Value;
                                host = match2.Groups[2].Value;
                                port = 4050;
                            }
                        }
                    }

                    if (host == null) return null;

                    IList<KeyValuePair<string, string>> options = null;

                    if (!string.IsNullOrWhiteSpace(connectionFilter.Option))
                    {
                        options = ClientManager.Decode(connectionFilter.Option).OfType<KeyValuePair<string, string>>().ToList();
                    }

                    if (connectionFilter.ConnectionType == ConnectionType.Tcp)
                    {
                        var ipAddress = ClientManager.GetIpAddress(host);
                        if (ipAddress == null) return null;

                        host = ipAddress.ToString();
                        uri = string.Format("{0}:{1}:{2}", scheme, host, port);

                        if (!this.OnCheckUriEvent(uri))
                        {
                            return null;
                        }

            #if !DEBUG
                        // Check
                        {
                            Uri url = new Uri(string.Format("{0}://{1}:{2}", scheme, host, port));

                            if (url.HostNameType == UriHostNameType.IPv4)
                            {
                                if (IPAddress.Any.ToString() == ipAddress.ToString()
                                    || IPAddress.Loopback.ToString() == ipAddress.ToString()
                                    || IPAddress.Broadcast.ToString() == ipAddress.ToString())
                                {
                                    return null;
                                }
                                if (CollectionUtils.Compare(ipAddress.GetAddressBytes(), IPAddress.Parse("10.0.0.0").GetAddressBytes()) >= 0
                                    && CollectionUtils.Compare(ipAddress.GetAddressBytes(), IPAddress.Parse("10.255.255.255").GetAddressBytes()) <= 0)
                                {
                                    return null;
                                }
                                if (CollectionUtils.Compare(ipAddress.GetAddressBytes(), IPAddress.Parse("172.16.0.0").GetAddressBytes()) >= 0
                                    && CollectionUtils.Compare(ipAddress.GetAddressBytes(), IPAddress.Parse("172.31.255.255").GetAddressBytes()) <= 0)
                                {
                                    return null;
                                }
                                if (CollectionUtils.Compare(ipAddress.GetAddressBytes(), IPAddress.Parse("127.0.0.0").GetAddressBytes()) >= 0
                                    && CollectionUtils.Compare(ipAddress.GetAddressBytes(), IPAddress.Parse("127.255.255.255").GetAddressBytes()) <= 0)
                                {
                                    return null;
                                }
                                if (CollectionUtils.Compare(ipAddress.GetAddressBytes(), IPAddress.Parse("192.168.0.0").GetAddressBytes()) >= 0
                                    && CollectionUtils.Compare(ipAddress.GetAddressBytes(), IPAddress.Parse("192.168.255.255").GetAddressBytes()) <= 0)
                                {
                                    return null;
                                }
                            }
                            else if (url.HostNameType == UriHostNameType.IPv6)
                            {
                                if (IPAddress.IPv6Any.ToString() == ipAddress.ToString()
                                    || IPAddress.IPv6Loopback.ToString() == ipAddress.ToString()
                                    || IPAddress.IPv6None.ToString() == ipAddress.ToString())
                                {
                                    return null;
                                }
                                if (ipAddress.ToString().ToLower().StartsWith("fe80:"))
                                {
                                    return null;
                                }
                            }
                        }
            #endif

                        var socket = ClientManager.Connect(new IPEndPoint(ipAddress, port), new TimeSpan(0, 0, 10));
                        garbages.Add(socket);

                        var cap = new SocketCap(socket);
                        garbages.Add(cap);

                        connection = new BaseConnection(cap, bandwidthLimit, _maxReceiveCount, _bufferManager);
                        garbages.Add(connection);
                    }
                    else
                    {
                        if (!this.OnCheckUriEvent(uri))
                        {
                            return null;
                        }

                        string proxyScheme = null;
                        string proxyHost = null;
                        int proxyPort = -1;

                        {
                            var match = _regex.Match(connectionFilter.ProxyUri);

                            if (match.Success)
                            {
                                proxyScheme = match.Groups[1].Value;
                                proxyHost = match.Groups[2].Value;
                                proxyPort = int.Parse(match.Groups[3].Value);
                            }
                            else
                            {
                                var match2 = _regex2.Match(connectionFilter.ProxyUri);

                                if (match2.Success)
                                {
                                    proxyScheme = match2.Groups[1].Value;
                                    proxyHost = match2.Groups[2].Value;

                                    if (connectionFilter.ConnectionType == ConnectionType.Socks5Proxy)
                                    {
                                        proxyPort = 1080;
                                    }
                                    else if (connectionFilter.ConnectionType == ConnectionType.HttpProxy)
                                    {
                                        proxyPort = 80;
                                    }
                                }
                            }
                        }

                        if (proxyHost == null) return null;

                        if (connectionFilter.ConnectionType == ConnectionType.Socks5Proxy
                            || connectionFilter.ConnectionType == ConnectionType.HttpProxy)
                        {
                            var socket = ClientManager.Connect(new IPEndPoint(ClientManager.GetIpAddress(proxyHost), proxyPort), new TimeSpan(0, 0, 10));
                            garbages.Add(socket);

                            ProxyClientBase proxy = null;

                            if (connectionFilter.ConnectionType == ConnectionType.Socks5Proxy)
                            {
                                var user = (options != null) ? options.Where(n => n.Key.ToLower().StartsWith("user")).Select(n => n.Value).FirstOrDefault() : null;
                                var pass = (options != null) ? options.Where(n => n.Key.ToLower().StartsWith("pass")).Select(n => n.Value).FirstOrDefault() : null;
                                proxy = new Socks5ProxyClient(user, pass, host, port);
                            }
                            else if (connectionFilter.ConnectionType == ConnectionType.HttpProxy)
                            {
                                proxy = new HttpProxyClient(host, port);
                            }

                            proxy.Create(socket, new TimeSpan(0, 0, 30));

                            var cap = new SocketCap(socket);
                            garbages.Add(cap);

                            connection = new BaseConnection(cap, bandwidthLimit, _maxReceiveCount, _bufferManager);
                            garbages.Add(connection);
                        }
                    }
                }

                if (connection == null) return null;

                var secureConnection = new SecureConnection(SecureConnectionVersion.Version3, SecureConnectionType.Connect, connection, null, _bufferManager);
                garbages.Add(secureConnection);

                secureConnection.Connect(new TimeSpan(0, 0, 30));

                var compressConnection = new CompressConnection(secureConnection, _maxReceiveCount, _bufferManager);
                garbages.Add(compressConnection);

                compressConnection.Connect(new TimeSpan(0, 0, 10));

                return compressConnection;
            }
            catch (Exception)
            {
                foreach (var item in garbages)
                {
                    item.Dispose();
                }
            }

            return null;
        }