Ejemplo n.º 1
0
        /// <summary>
        /// Creates a TCP connection to server
        /// </summary>
        /// <param name="server"></param>
        /// <param name="remoteHostName"></param>
        /// <param name="remotePort"></param>
        /// <param name="httpVersion"></param>
        /// <param name="isHttps"></param>
        /// <param name="externalHttpProxy"></param>
        /// <param name="externalHttpsProxy"></param>
        /// <returns></returns>
        internal async Task <TcpConnection> CreateClient(ProxyServer server,
                                                         string remoteHostName, int remotePort, Version httpVersion,
                                                         bool isHttps,
                                                         ExternalProxy externalHttpProxy, ExternalProxy externalHttpsProxy)
        {
            bool useHttpProxy = false;

            //check if external proxy is set for HTTP
            if (!isHttps && externalHttpProxy != null &&
                !(externalHttpProxy.HostName == remoteHostName &&
                  externalHttpProxy.Port == remotePort))
            {
                useHttpProxy = true;

                //check if we need to ByPass
                if (externalHttpProxy.BypassLocalhost &&
                    NetworkHelper.IsLocalIpAddress(remoteHostName))
                {
                    useHttpProxy = false;
                }
            }

            bool useHttpsProxy = false;

            //check if external proxy is set for HTTPS
            if (isHttps && externalHttpsProxy != null &&
                !(externalHttpsProxy.HostName == remoteHostName &&
                  externalHttpsProxy.Port == remotePort))
            {
                useHttpsProxy = true;

                //check if we need to ByPass
                if (externalHttpsProxy.BypassLocalhost &&
                    NetworkHelper.IsLocalIpAddress(remoteHostName))
                {
                    useHttpsProxy = false;
                }
            }

            TcpClient            client = null;
            CustomBufferedStream stream = null;

            try
            {
                if (isHttps)
                {
                    //If this proxy uses another external proxy then create a tunnel request for HTTPS connections
                    if (useHttpsProxy)
                    {
                        client = new TcpClient(server.UpStreamEndPoint);
                        await client.ConnectAsync(externalHttpsProxy.HostName, externalHttpsProxy.Port);

                        stream = new CustomBufferedStream(client.GetStream(), server.BufferSize);

                        using (var writer = new StreamWriter(stream, Encoding.ASCII, server.BufferSize, true)
                        {
                            NewLine = ProxyConstants.NewLine
                        })
                        {
                            await writer.WriteLineAsync($"CONNECT {remoteHostName}:{remotePort} HTTP/{httpVersion}");

                            await writer.WriteLineAsync($"Host: {remoteHostName}:{remotePort}");

                            await writer.WriteLineAsync("Connection: Keep-Alive");

                            if (!string.IsNullOrEmpty(externalHttpsProxy.UserName) && externalHttpsProxy.Password != null)
                            {
                                await writer.WriteLineAsync("Proxy-Connection: keep-alive");

                                await writer.WriteLineAsync("Proxy-Authorization" + ": Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(externalHttpsProxy.UserName + ":" + externalHttpsProxy.Password)));
                            }
                            await writer.WriteLineAsync();

                            await writer.FlushAsync();

                            writer.Close();
                        }

                        using (var reader = new CustomBinaryReader(stream, server.BufferSize))
                        {
                            var result = await reader.ReadLineAsync();

                            if (!new[] { "200 OK", "connection established" }.Any(s => result.ContainsIgnoreCase(s)))
                            {
                                throw new Exception("Upstream proxy failed to create a secure tunnel");
                            }

                            await reader.ReadAndIgnoreAllLinesAsync();
                        }
                    }
                    else
                    {
                        client = new TcpClient(server.UpStreamEndPoint);
                        await client.ConnectAsync(remoteHostName, remotePort);

                        stream = new CustomBufferedStream(client.GetStream(), server.BufferSize);
                    }

                    var sslStream = new SslStream(stream, false, server.ValidateServerCertificate, server.SelectClientCertificate);
                    stream = new CustomBufferedStream(sslStream, server.BufferSize);

                    await sslStream.AuthenticateAsClientAsync(remoteHostName, null, server.SupportedSslProtocols, server.CheckCertificateRevocation);
                }
                else
                {
                    if (useHttpProxy)
                    {
                        client = new TcpClient(server.UpStreamEndPoint);
                        await client.ConnectAsync(externalHttpProxy.HostName, externalHttpProxy.Port);

                        stream = new CustomBufferedStream(client.GetStream(), server.BufferSize);
                    }
                    else
                    {
                        client = new TcpClient(server.UpStreamEndPoint);
                        await client.ConnectAsync(remoteHostName, remotePort);

                        stream = new CustomBufferedStream(client.GetStream(), server.BufferSize);
                    }
                }

                client.ReceiveTimeout = server.ConnectionTimeOutSeconds * 1000;
                client.SendTimeout    = server.ConnectionTimeOutSeconds * 1000;
            }
            catch (Exception)
            {
                stream?.Dispose();
                client?.Close();
                throw;
            }

            Interlocked.Increment(ref server.serverConnectionCount);

            return(new TcpConnection
            {
                UpStreamHttpProxy = externalHttpProxy,
                UpStreamHttpsProxy = externalHttpsProxy,
                HostName = remoteHostName,
                Port = remotePort,
                IsHttps = isHttps,
                TcpClient = client,
                StreamReader = new CustomBinaryReader(stream, server.BufferSize),
                Stream = stream,
                Version = httpVersion
            });
        }
        /// <summary>
        ///  Creates a TCP connection to server
        /// </summary>
        /// <param name="server"></param>
        /// <param name="remoteHostName"></param>
        /// <param name="remotePort"></param>
        /// <param name="httpVersion"></param>
        /// <param name="isHttps"></param>
        /// <param name="isConnect"></param>
        /// <param name="upStreamEndPoint"></param>
        /// <param name="externalProxy"></param>
        /// <returns></returns>
        internal async Task <TcpConnection> CreateClient(ProxyServer server,
                                                         string remoteHostName, int remotePort, Version httpVersion, bool isHttps,
                                                         bool isConnect, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy)
        {
            bool useUpstreamProxy = false;

            //check if external proxy is set for HTTP/HTTPS
            if (externalProxy != null && !(externalProxy.HostName == remoteHostName && externalProxy.Port == remotePort))
            {
                useUpstreamProxy = true;

                //check if we need to ByPass
                if (externalProxy.BypassLocalhost && NetworkHelper.IsLocalIpAddress(remoteHostName))
                {
                    useUpstreamProxy = false;
                }
            }

            TcpClient            client = null;
            CustomBufferedStream stream = null;

            try
            {
                client = new TcpClient(upStreamEndPoint);

                //If this proxy uses another external proxy then create a tunnel request for HTTP/HTTPS connections
                if (useUpstreamProxy)
                {
                    await client.ConnectAsync(externalProxy.HostName, externalProxy.Port);
                }
                else
                {
                    await client.ConnectAsync(remoteHostName, remotePort);
                }

                stream = new CustomBufferedStream(client.GetStream(), server.BufferSize);

                if (useUpstreamProxy && (isConnect || isHttps))
                {
                    var writer = new HttpRequestWriter(stream, server.BufferSize);
                    await writer.WriteLineAsync($"CONNECT {remoteHostName}:{remotePort} HTTP/{httpVersion}");

                    await writer.WriteLineAsync($"Host: {remoteHostName}:{remotePort}");

                    await writer.WriteLineAsync($"{KnownHeaders.Connection}: {KnownHeaders.ConnectionKeepAlive}");

                    if (!string.IsNullOrEmpty(externalProxy.UserName) && externalProxy.Password != null)
                    {
                        await HttpHeader.ProxyConnectionKeepAlive.WriteToStreamAsync(writer);

                        await writer.WriteLineAsync(KnownHeaders.ProxyAuthorization + ": Basic " +
                                                    Convert.ToBase64String(Encoding.UTF8.GetBytes(
                                                                               externalProxy.UserName + ":" + externalProxy.Password)));
                    }

                    await writer.WriteLineAsync();

                    using (var reader = new CustomBinaryReader(stream, server.BufferSize))
                    {
                        string result = await reader.ReadLineAsync();

                        if (!new[] { "200 OK", "connection established" }.Any(s => result.ContainsIgnoreCase(s)))
                        {
                            throw new Exception("Upstream proxy failed to create a secure tunnel");
                        }

                        await reader.ReadAndIgnoreAllLinesAsync();
                    }
                }

                if (isHttps)
                {
                    var sslStream = new SslStream(stream, false, server.ValidateServerCertificate, server.SelectClientCertificate);
                    stream = new CustomBufferedStream(sslStream, server.BufferSize);

                    await sslStream.AuthenticateAsClientAsync(remoteHostName, null, server.SupportedSslProtocols, server.CheckCertificateRevocation);
                }

                client.ReceiveTimeout = server.ConnectionTimeOutSeconds * 1000;
                client.SendTimeout    = server.ConnectionTimeOutSeconds * 1000;
            }
            catch (Exception)
            {
                stream?.Dispose();
                client?.Close();
                throw;
            }

            return(new TcpConnection(server)
            {
                UpStreamProxy = externalProxy,
                UpStreamEndPoint = upStreamEndPoint,
                HostName = remoteHostName,
                Port = remotePort,
                IsHttps = isHttps,
                UseUpstreamProxy = useUpstreamProxy,
                TcpClient = client,
                StreamReader = new CustomBinaryReader(stream, server.BufferSize),
                StreamWriter = new HttpRequestWriter(stream, server.BufferSize),
                Stream = stream,
                Version = httpVersion
            });
        }