Пример #1
0
        /// <summary>
        /// This is the core request handler method for a particular connection from client
        /// </summary>
        /// <param name="client"></param>
        /// <param name="httpCmd"></param>
        /// <param name="clientStream"></param>
        /// <param name="clientStreamReader"></param>
        /// <param name="clientStreamWriter"></param>
        /// <param name="httpsHostName"></param>
        /// <returns></returns>
        private async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream,
                                                    CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string httpsHostName, ProxyEndPoint endPoint, List <HttpHeader> connectHeaders, ExternalProxy customUpStreamHttpProxy = null, ExternalProxy customUpStreamHttpsProxy = null)
        {
            TcpConnection connection = null;

            //Loop through each subsequest request on this particular client connection
            //(assuming HTTP connection is kept alive by client)
            while (true)
            {
                if (string.IsNullOrEmpty(httpCmd))
                {
                    Dispose(clientStream, clientStreamReader, clientStreamWriter, null);
                    break;
                }

                var args = new SessionEventArgs(BUFFER_SIZE, HandleHttpSessionResponse);
                args.ProxyClient.TcpClient     = client;
                args.WebSession.ConnectHeaders = connectHeaders;

                args.WebSession.ProcessId = new Lazy <int>(() =>
                {
                    var remoteEndPoint = (IPEndPoint)args.ProxyClient.TcpClient.Client.RemoteEndPoint;

                    //If client is localhost get the process id
                    if (NetworkHelper.IsLocalIpAddress(remoteEndPoint.Address))
                    {
                        return(NetworkHelper.GetProcessIdFromPort(remoteEndPoint.Port, endPoint.IpV6Enabled));
                    }

                    //can't access process Id of remote request from remote machine
                    return(-1);
                });
                try
                {
                    //break up the line into three components (method, remote URL & Http Version)
                    var httpCmdSplit = httpCmd.Split(ProxyConstants.SpaceSplit, 3);

                    var httpMethod = httpCmdSplit[0];

                    //find the request HTTP version
                    Version httpVersion = new Version(1, 1);
                    if (httpCmdSplit.Length == 3)
                    {
                        var httpVersionString = httpCmdSplit[2].ToLower().Trim();

                        if (httpVersionString == "http/1.0")
                        {
                            httpVersion = new Version(1, 0);
                        }
                    }


                    //Read the request headers in to unique and non-unique header collections
                    string tmpLine;
                    while (!string.IsNullOrEmpty(tmpLine = await clientStreamReader.ReadLineAsync()))
                    {
                        var header = tmpLine.Split(ProxyConstants.ColonSplit, 2);

                        var newHeader = new HttpHeader(header[0], header[1]);

                        //if header exist in non-unique header collection add it there
                        if (args.WebSession.Request.NonUniqueRequestHeaders.ContainsKey(newHeader.Name))
                        {
                            args.WebSession.Request.NonUniqueRequestHeaders[newHeader.Name].Add(newHeader);
                        }
                        //if header is alread in unique header collection then move both to non-unique collection
                        else if (args.WebSession.Request.RequestHeaders.ContainsKey(newHeader.Name))
                        {
                            var existing = args.WebSession.Request.RequestHeaders[newHeader.Name];

                            var nonUniqueHeaders = new List <HttpHeader>();

                            nonUniqueHeaders.Add(existing);
                            nonUniqueHeaders.Add(newHeader);

                            args.WebSession.Request.NonUniqueRequestHeaders.Add(newHeader.Name, nonUniqueHeaders);
                            args.WebSession.Request.RequestHeaders.Remove(newHeader.Name);
                        }
                        //add to unique header collection
                        else
                        {
                            args.WebSession.Request.RequestHeaders.Add(newHeader.Name, newHeader);
                        }
                    }

                    var httpRemoteUri = new Uri(httpsHostName == null ? httpCmdSplit[1]
                        : (string.Concat("https://", args.WebSession.Request.Host == null ?
                                         httpsHostName : args.WebSession.Request.Host, httpCmdSplit[1])));

                    args.WebSession.Request.RequestUri = httpRemoteUri;

                    args.WebSession.Request.Method      = httpMethod.Trim().ToUpper();
                    args.WebSession.Request.HttpVersion = httpVersion;
                    args.ProxyClient.ClientStream       = clientStream;
                    args.ProxyClient.ClientStreamReader = clientStreamReader;
                    args.ProxyClient.ClientStreamWriter = clientStreamWriter;

                    if (httpsHostName == null && (await CheckAuthorization(clientStreamWriter, args.WebSession.Request.RequestHeaders.Values) == false))
                    {
                        Dispose(clientStream, clientStreamReader, clientStreamWriter, args);
                        break;
                    }

                    PrepareRequestHeaders(args.WebSession.Request.RequestHeaders, args.WebSession);
                    args.WebSession.Request.Host = args.WebSession.Request.RequestUri.Authority;

                    //If user requested interception do it
                    if (BeforeRequest != null)
                    {
                        Delegate[] invocationList = BeforeRequest.GetInvocationList();
                        Task[]     handlerTasks   = new Task[invocationList.Length];

                        for (int i = 0; i < invocationList.Length; i++)
                        {
                            handlerTasks[i] = ((Func <object, SessionEventArgs, Task>)invocationList[i])(null, args);
                        }

                        await Task.WhenAll(handlerTasks);
                    }

                    //if upgrading to websocket then relay the requet without reading the contents
                    if (args.WebSession.Request.UpgradeToWebSocket)
                    {
                        await TcpHelper.SendRaw(BUFFER_SIZE, ConnectionTimeOutSeconds, httpRemoteUri.Host, httpRemoteUri.Port,
                                                httpCmd, httpVersion, args.WebSession.Request.RequestHeaders, args.IsHttps,
                                                SupportedSslProtocols, new RemoteCertificateValidationCallback(ValidateServerCertificate),
                                                new LocalCertificateSelectionCallback(SelectClientCertificate),
                                                clientStream, tcpConnectionFactory);

                        Dispose(clientStream, clientStreamReader, clientStreamWriter, args);
                        break;
                    }

                    //construct the web request that we are going to issue on behalf of the client.
                    await HandleHttpSessionRequestInternal(connection, args, customUpStreamHttpProxy, customUpStreamHttpsProxy, false).ConfigureAwait(false);


                    if (args.WebSession.Request.CancelRequest)
                    {
                        break;
                    }

                    //if connection is closing exit
                    if (args.WebSession.Response.ResponseKeepAlive == false)
                    {
                        break;
                    }

                    // read the next request
                    httpCmd = await clientStreamReader.ReadLineAsync();
                }
                catch (Exception e)
                {
                    ExceptionFunc(new ProxyHttpException("Error occured whilst handling session request", e, args));
                    Dispose(clientStream, clientStreamReader, clientStreamWriter, args);
                    break;
                }
            }

            if (connection != null)
            {
                //dispose
                connection.Dispose();
            }
        }
Пример #2
0
        //This is called when client is aware of proxy
        private static void HandleClient(ExplicitProxyEndPoint endPoint, TcpClient client)
        {
            Stream clientStream       = client.GetStream();
            var    clientStreamReader = new CustomBinaryReader(clientStream, Encoding.ASCII);
            var    clientStreamWriter = new StreamWriter(clientStream);

            Uri httpRemoteUri;

            try
            {
                //read the first line HTTP command

                var httpCmd = clientStreamReader.ReadLine();

                if (string.IsNullOrEmpty(httpCmd))
                {
                    Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
                    return;
                }

                //break up the line into three components (method, remote URL & Http Version)
                var httpCmdSplit = httpCmd.Split(SpaceSplit, 3);

                var httpVerb = httpCmdSplit[0];

                if (httpVerb.ToUpper() == "CONNECT")
                {
                    httpRemoteUri = new Uri("http://" + httpCmdSplit[1]);
                }
                else
                {
                    httpRemoteUri = new Uri(httpCmdSplit[1]);
                }

                var httpVersion = httpCmdSplit[2];

                var excluded = endPoint.ExcludedHttpsHostNameRegex != null?endPoint.ExcludedHttpsHostNameRegex.Any(x => Regex.IsMatch(httpRemoteUri.Host, x)) : false;

                //Client wants to create a secure tcp tunnel (its a HTTPS request)
                if (httpVerb.ToUpper() == "CONNECT" && !excluded && httpRemoteUri.Port != 80)
                {
                    httpRemoteUri = new Uri("https://" + httpCmdSplit[1]);
                    clientStreamReader.ReadAllLines();

                    WriteConnectResponse(clientStreamWriter, httpVersion);

                    var certificate = CertManager.CreateCertificate(httpRemoteUri.Host);

                    SslStream sslStream = null;

                    try
                    {
                        sslStream = new SslStream(clientStream, true);

                        //Successfully managed to authenticate the client using the fake certificate
                        sslStream.AuthenticateAsServer(certificate, false,
                                                       SupportedProtocols, false);

                        clientStreamReader = new CustomBinaryReader(sslStream, Encoding.ASCII);
                        clientStreamWriter = new StreamWriter(sslStream);
                        //HTTPS server created - we can now decrypt the client's traffic
                        clientStream = sslStream;
                    }

                    catch
                    {
                        if (sslStream != null)
                        {
                            sslStream.Dispose();
                        }

                        Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
                        return;
                    }


                    httpCmd = clientStreamReader.ReadLine();
                }
                else if (httpVerb.ToUpper() == "CONNECT")
                {
                    clientStreamReader.ReadAllLines();
                    WriteConnectResponse(clientStreamWriter, httpVersion);

                    TcpHelper.SendRaw(clientStream, null, null, httpRemoteUri.Host, httpRemoteUri.Port,
                                      false);

                    Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
                    return;
                }

                //Now create the request

                HandleHttpSessionRequest(client, httpCmd, clientStream, clientStreamReader, clientStreamWriter,
                                         httpRemoteUri.Scheme == Uri.UriSchemeHttps ? true : false);
            }
            catch
            {
                Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
            }
        }
Пример #3
0
        //This is called when client is aware of proxy
        //So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy
        private async Task HandleClient(ExplicitProxyEndPoint endPoint, TcpClient tcpClient)
        {
            Stream clientStream = tcpClient.GetStream();

            clientStream.ReadTimeout  = ConnectionTimeOutSeconds * 1000;
            clientStream.WriteTimeout = ConnectionTimeOutSeconds * 1000;

            var clientStreamReader = new CustomBinaryReader(clientStream);
            var clientStreamWriter = new StreamWriter(clientStream);

            Uri httpRemoteUri;

            try
            {
                //read the first line HTTP command
                var httpCmd = await clientStreamReader.ReadLineAsync();

                if (string.IsNullOrEmpty(httpCmd))
                {
                    Dispose(clientStream, clientStreamReader, clientStreamWriter, null);
                    return;
                }

                //break up the line into three components (method, remote URL & Http Version)
                var httpCmdSplit = httpCmd.Split(ProxyConstants.SpaceSplit, 3);

                //Find the request Verb
                var httpVerb = httpCmdSplit[0];

                if (httpVerb.ToUpper() == "CONNECT")
                {
                    httpRemoteUri = new Uri("http://" + httpCmdSplit[1]);
                }
                else
                {
                    httpRemoteUri = new Uri(httpCmdSplit[1]);
                }

                //parse the HTTP version
                Version version = new Version(1, 1);
                if (httpCmdSplit.Length == 3)
                {
                    string httpVersion = httpCmdSplit[2].Trim();

                    if (httpVersion == "http/1.0")
                    {
                        version = new Version(1, 0);
                    }
                }
                //filter out excluded host names
                var excluded = endPoint.ExcludedHttpsHostNameRegex != null?
                               endPoint.ExcludedHttpsHostNameRegex.Any(x => Regex.IsMatch(httpRemoteUri.Host, x)) : false;


                List <HttpHeader> connectRequestHeaders = null;

                //Client wants to create a secure tcp tunnel (its a HTTPS request)
                if (httpVerb.ToUpper() == "CONNECT" && !excluded && httpRemoteUri.Port != 80)
                {
                    httpRemoteUri = new Uri("https://" + httpCmdSplit[1]);
                    string tmpLine = null;
                    connectRequestHeaders = new List <HttpHeader>();
                    while (!string.IsNullOrEmpty(tmpLine = await clientStreamReader.ReadLineAsync()))
                    {
                        var header = tmpLine.Split(ProxyConstants.ColonSplit, 2);

                        var newHeader = new HttpHeader(header[0], header[1]);
                        connectRequestHeaders.Add(newHeader);
                    }

                    if (await CheckAuthorization(clientStreamWriter, connectRequestHeaders) == false)
                    {
                        Dispose(clientStream, clientStreamReader, clientStreamWriter, null);
                        return;
                    }

                    await WriteConnectResponse(clientStreamWriter, version);

                    SslStream sslStream = null;

                    try
                    {
                        sslStream = new SslStream(clientStream, true);
                        var certificate = certificateCacheManager.CreateCertificate(httpRemoteUri.Host, false);
                        //Successfully managed to authenticate the client using the fake certificate
                        await sslStream.AuthenticateAsServerAsync(certificate, false,
                                                                  SupportedSslProtocols, false);

                        //HTTPS server created - we can now decrypt the client's traffic
                        clientStream = sslStream;

                        clientStreamReader = new CustomBinaryReader(sslStream);
                        clientStreamWriter = new StreamWriter(sslStream);
                    }
                    catch
                    {
                        if (sslStream != null)
                        {
                            sslStream.Dispose();
                        }

                        Dispose(clientStream, clientStreamReader, clientStreamWriter, null);
                        return;
                    }

                    //Now read the actual HTTPS request line
                    httpCmd = await clientStreamReader.ReadLineAsync();
                }
                //Sorry cannot do a HTTPS request decrypt to port 80 at this time
                else if (httpVerb.ToUpper() == "CONNECT")
                {
                    //Cyphen out CONNECT request headers
                    await clientStreamReader.ReadAllLinesAsync();

                    //write back successfull CONNECT response
                    await WriteConnectResponse(clientStreamWriter, version);

                    await TcpHelper.SendRaw(BUFFER_SIZE, ConnectionTimeOutSeconds, httpRemoteUri.Host, httpRemoteUri.Port,
                                            httpCmd, version, null,
                                            false, SupportedSslProtocols,
                                            new RemoteCertificateValidationCallback(ValidateServerCertificate),
                                            new LocalCertificateSelectionCallback(SelectClientCertificate),
                                            clientStream, tcpConnectionFactory);

                    Dispose(clientStream, clientStreamReader, clientStreamWriter, null);
                    return;
                }
                //Now create the request
                await HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamReader, clientStreamWriter,
                                               httpRemoteUri.Scheme == Uri.UriSchemeHttps?httpRemoteUri.Host : null, endPoint, connectRequestHeaders, null, null);
            }
            catch (Exception)
            {
                Dispose(clientStream, clientStreamReader, clientStreamWriter, null);
            }
        }
        /// <summary>
        ///     This is the core request handler method for a particular connection from client.
        ///     Will create new session (request/response) sequence until
        ///     client/server abruptly terminates connection or by normal HTTP termination.
        /// </summary>
        /// <param name="endPoint">The proxy endpoint.</param>
        /// <param name="clientConnection">The client connection.</param>
        /// <param name="clientStream">The client stream.</param>
        /// <param name="clientStreamWriter">The client stream writer.</param>
        /// <param name="cancellationTokenSource">The cancellation token source for this async task.</param>
        /// <param name="httpsConnectHostname">
        ///     The https hostname as appeared in CONNECT request if this is a HTTPS request from
        ///     explicit endpoint.
        /// </param>
        /// <param name="connectRequest">The Connect request if this is a HTTPS request from explicit endpoint.</param>
        private async Task HandleHttpSessionRequest(ProxyEndPoint endPoint, TcpClientConnection clientConnection,
                                                    CustomBufferedStream clientStream, HttpResponseWriter clientStreamWriter,
                                                    CancellationTokenSource cancellationTokenSource, string httpsConnectHostname, ConnectRequest connectRequest)
        {
            var cancellationToken = cancellationTokenSource.Token;
            TcpServerConnection serverConnection = null;

            try
            {
                // Loop through each subsequest request on this particular client connection
                // (assuming HTTP connection is kept alive by client)
                while (true)
                {
                    // read the request line
                    string httpCmd = await clientStream.ReadLineAsync(cancellationToken);

                    if (string.IsNullOrEmpty(httpCmd))
                    {
                        return;
                    }

                    var args = new SessionEventArgs(BufferSize, endPoint, cancellationTokenSource, ExceptionFunc)
                    {
                        ProxyClient = { ClientConnection = clientConnection },
                        WebSession  = { ConnectRequest = connectRequest }
                    };

                    try
                    {
                        try
                        {
                            Request.ParseRequestLine(httpCmd, out string httpMethod, out string httpUrl,
                                                     out var version);

                            // Read the request headers in to unique and non-unique header collections
                            await HeaderParser.ReadHeaders(clientStream, args.WebSession.Request.Headers,
                                                           cancellationToken);

                            Uri httpRemoteUri;
                            if (uriSchemeRegex.IsMatch(httpUrl))
                            {
                                try
                                {
                                    httpRemoteUri = new Uri(httpUrl);
                                }
                                catch (Exception ex)
                                {
                                    throw new Exception($"Invalid URI: '{httpUrl}'", ex);
                                }
                            }
                            else
                            {
                                string host        = args.WebSession.Request.Host ?? httpsConnectHostname;
                                string hostAndPath = host;
                                if (httpUrl.StartsWith("/"))
                                {
                                    hostAndPath += httpUrl;
                                }

                                string url = string.Concat(httpsConnectHostname == null ? "http://" : "https://",
                                                           hostAndPath);
                                try
                                {
                                    httpRemoteUri = new Uri(url);
                                }
                                catch (Exception ex)
                                {
                                    throw new Exception($"Invalid URI: '{url}'", ex);
                                }
                            }

                            var request = args.WebSession.Request;
                            request.RequestUri  = httpRemoteUri;
                            request.OriginalUrl = httpUrl;

                            request.Method                      = httpMethod;
                            request.HttpVersion                 = version;
                            args.ProxyClient.ClientStream       = clientStream;
                            args.ProxyClient.ClientStreamWriter = clientStreamWriter;

                            if (!args.IsTransparent)
                            {
                                // proxy authorization check
                                if (httpsConnectHostname == null && await CheckAuthorization(args) == false)
                                {
                                    await InvokeBeforeResponse(args);

                                    // send the response
                                    await clientStreamWriter.WriteResponseAsync(args.WebSession.Response,
                                                                                cancellationToken : cancellationToken);

                                    return;
                                }

                                PrepareRequestHeaders(request.Headers);
                                request.Host = request.RequestUri.Authority;
                            }

                            // if win auth is enabled
                            // we need a cache of request body
                            // so that we can send it after authentication in WinAuthHandler.cs
                            if (isWindowsAuthenticationEnabledAndSupported && request.HasBody)
                            {
                                await args.GetRequestBody(cancellationToken);
                            }

                            request.OriginalHasBody = request.HasBody;

                            // If user requested interception do it
                            await InvokeBeforeRequest(args);

                            var response = args.WebSession.Response;

                            if (request.CancelRequest)
                            {
                                // syphon out the request body from client before setting the new body
                                await args.SyphonOutBodyAsync(true, cancellationToken);

                                await HandleHttpSessionResponse(args);

                                if (!response.KeepAlive)
                                {
                                    return;
                                }

                                continue;
                            }

                            // create a new connection if hostname/upstream end point changes
                            if (serverConnection != null &&
                                (!serverConnection.HostName.EqualsIgnoreCase(request.RequestUri.Host) ||
                                 args.WebSession.UpStreamEndPoint?.Equals(serverConnection.UpStreamEndPoint) ==
                                 false))
                            {
                                serverConnection.Dispose();
                                serverConnection = null;
                            }

                            if (serverConnection == null)
                            {
                                serverConnection = await GetServerConnection(args, false, clientConnection.NegotiatedApplicationProtocol, cancellationToken);
                            }

                            // if upgrading to websocket then relay the requet without reading the contents
                            if (request.UpgradeToWebSocket)
                            {
                                // prepare the prefix content
                                await serverConnection.StreamWriter.WriteLineAsync(httpCmd, cancellationToken);

                                await serverConnection.StreamWriter.WriteHeadersAsync(request.Headers,
                                                                                      cancellationToken : cancellationToken);

                                string httpStatus = await serverConnection.Stream.ReadLineAsync(cancellationToken);

                                Response.ParseResponseLine(httpStatus, out var responseVersion,
                                                           out int responseStatusCode,
                                                           out string responseStatusDescription);
                                response.HttpVersion       = responseVersion;
                                response.StatusCode        = responseStatusCode;
                                response.StatusDescription = responseStatusDescription;

                                await HeaderParser.ReadHeaders(serverConnection.Stream, response.Headers,
                                                               cancellationToken);

                                if (!args.IsTransparent)
                                {
                                    await clientStreamWriter.WriteResponseAsync(response,
                                                                                cancellationToken : cancellationToken);
                                }

                                // If user requested call back then do it
                                if (!args.WebSession.Response.Locked)
                                {
                                    await InvokeBeforeResponse(args);
                                }

                                await TcpHelper.SendRaw(clientStream, serverConnection.Stream, BufferSize,
                                                        (buffer, offset, count) => { args.OnDataSent(buffer, offset, count); },
                                                        (buffer, offset, count) => { args.OnDataReceived(buffer, offset, count); },
                                                        cancellationTokenSource, ExceptionFunc);

                                return;
                            }

                            // construct the web request that we are going to issue on behalf of the client.
                            await HandleHttpSessionRequestInternal(serverConnection, args);

                            if (args.WebSession.ServerConnection == null)
                            {
                                return;
                            }

                            // if connection is closing exit
                            if (!response.KeepAlive)
                            {
                                return;
                            }

                            if (cancellationTokenSource.IsCancellationRequested)
                            {
                                throw new Exception("Session was terminated by user.");
                            }
                        }
                        catch (Exception e) when(!(e is ProxyHttpException))
                        {
                            throw new ProxyHttpException("Error occured whilst handling session request", e, args);
                        }
                    }
                    catch (Exception e)
                    {
                        args.Exception = e;
                        throw;
                    }
                    finally
                    {
                        await InvokeAfterResponse(args);

                        args.Dispose();
                    }
                }
            }
            finally
            {
                serverConnection?.Dispose();
            }
        }
Пример #5
0
        private static void HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream,
                                                     CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, bool IsHttps)
        {
            TcpConnection connection          = null;
            string        lastRequestHostName = null;

            while (true)
            {
                if (string.IsNullOrEmpty(httpCmd))
                {
                    Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
                    break;
                }

                var args = new SessionEventArgs(BUFFER_SIZE);
                args.Client.TcpClient = client;

                try
                {
                    //break up the line into three components (method, remote URL & Http Version)
                    var httpCmdSplit = httpCmd.Split(SpaceSplit, 3);

                    var httpMethod = httpCmdSplit[0];


                    var httpVersion = httpCmdSplit[2];

                    Version version;
                    if (httpVersion == "HTTP/1.1")
                    {
                        version = new Version(1, 1);
                    }
                    else
                    {
                        version = new Version(1, 0);
                    }


                    args.ProxySession.Request.RequestHeaders = new List <HttpHeader>();

                    string tmpLine;
                    while (!string.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
                    {
                        var header = tmpLine.Split(new char[] { ':' }, 2);
                        args.ProxySession.Request.RequestHeaders.Add(new HttpHeader(header[0], header[1]));
                    }

                    SetRequestHeaders(args.ProxySession.Request.RequestHeaders, args.ProxySession);

                    var httpRemoteUri = new Uri(!IsHttps ? httpCmdSplit[1] : (string.Concat("https://", args.ProxySession.Request.Hostname, httpCmdSplit[1])));
                    args.IsHttps = IsHttps;

                    if (args.ProxySession.Request.UpgradeToWebSocket)
                    {
                        TcpHelper.SendRaw(clientStream, httpCmd, args.ProxySession.Request.RequestHeaders,
                                          httpRemoteUri.Host, httpRemoteUri.Port, args.IsHttps);
                        Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
                        return;
                    }

                    args.ProxySession.Request.RequestUri = httpRemoteUri;

                    args.ProxySession.Request.Method      = httpMethod;
                    args.ProxySession.Request.HttpVersion = httpVersion;
                    args.Client.ClientStream           = clientStream;
                    args.Client.ClientStreamReader     = clientStreamReader;
                    args.Client.ClientStreamWriter     = clientStreamWriter;
                    args.ProxySession.Request.Hostname = args.ProxySession.Request.RequestUri.Host;
                    args.ProxySession.Request.Url      = args.ProxySession.Request.RequestUri.OriginalString;
                    args.Client.ClientPort             = ((IPEndPoint)client.Client.RemoteEndPoint).Port;
                    args.Client.ClientIpAddress        = ((IPEndPoint)client.Client.RemoteEndPoint).Address;


                    //If requested interception
                    if (BeforeRequest != null)
                    {
                        args.ProxySession.Request.Encoding = args.ProxySession.GetEncoding();
                        BeforeRequest(null, args);
                    }

                    args.ProxySession.Request.RequestLocked = true;

                    if (args.ProxySession.Request.CancelRequest)
                    {
                        Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
                        break;
                    }


                    //construct the web request that we are going to issue on behalf of the client.
                    connection = connection == null?
                                 TcpConnectionManager.GetClient(args.ProxySession.Request.RequestUri.Host, args.ProxySession.Request.RequestUri.Port, args.IsHttps)
                                     : lastRequestHostName != args.ProxySession.Request.Hostname ? TcpConnectionManager.GetClient(args.ProxySession.Request.RequestUri.Host, args.ProxySession.Request.RequestUri.Port, args.IsHttps)
                            : connection;

                    lastRequestHostName = args.ProxySession.Request.Hostname;

                    args.ProxySession.SetConnection(connection);
                    args.ProxySession.SendRequest();

                    //If request was modified by user
                    if (args.ProxySession.Request.RequestBodyRead)
                    {
                        args.ProxySession.Request.ContentLength = args.ProxySession.Request.RequestBody.Length;
                        var newStream = args.ProxySession.ProxyClient.ServerStreamReader.BaseStream;
                        newStream.Write(args.ProxySession.Request.RequestBody, 0, args.ProxySession.Request.RequestBody.Length);
                    }
                    else
                    {
                        //If its a post/put request, then read the client html body and send it to server
                        if (httpMethod.ToUpper() == "POST" || httpMethod.ToUpper() == "PUT")
                        {
                            SendClientRequestBody(args);
                        }
                    }

                    HandleHttpSessionResponse(args);

                    //if connection is closing exit
                    if (args.ProxySession.Response.ResponseKeepAlive == false)
                    {
                        connection.TcpClient.Close();
                        Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
                        return;
                    }

                    // read the next request
                    httpCmd = clientStreamReader.ReadLine();
                }
                catch
                {
                    Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
                    break;
                }
            }

            if (connection != null)
            {
                TcpConnectionManager.ReleaseClient(connection);
            }
        }
Пример #6
0
 /// <summary>
 /// 构造函数
 /// </summary>
 /// <param name="ip">服务IP</param>
 /// <param name="port">服务端口</param>
 public TcpContextBase(string ip, int port)
 {
     tcp = new TcpHelper(ip, port);
 }
Пример #7
0
        /// <summary>
        /// This is called when client is aware of proxy
        /// So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy
        /// </summary>
        /// <param name="endPoint"></param>
        /// <param name="tcpClient"></param>
        /// <returns></returns>
        private async Task HandleClient(ExplicitProxyEndPoint endPoint, TcpClient tcpClient)
        {
            var clientStream = new CustomBufferedStream(tcpClient.GetStream(), BufferSize);

            var clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
            var clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);

            try
            {
                string connectHostname = null;

                ConnectRequest connectRequest = null;

                //Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request)
                if (await HttpHelper.IsConnectMethod(clientStream) == 1)
                {
                    //read the first line HTTP command
                    string httpCmd = await clientStreamReader.ReadLineAsync();

                    if (string.IsNullOrEmpty(httpCmd))
                    {
                        return;
                    }

                    Request.ParseRequestLine(httpCmd, out string _, out string httpUrl, out var version);

                    var httpRemoteUri = new Uri("http://" + httpUrl);
                    connectHostname = httpRemoteUri.Host;

                    //filter out excluded host names
                    bool excluded = false;

                    if (endPoint.ExcludedHttpsHostNameRegex != null)
                    {
                        excluded = endPoint.ExcludedHttpsHostNameRegexList.Any(x => x.IsMatch(connectHostname));
                    }

                    if (endPoint.IncludedHttpsHostNameRegex != null)
                    {
                        excluded = !endPoint.IncludedHttpsHostNameRegexList.Any(x => x.IsMatch(connectHostname));
                    }

                    if (endPoint.BeforeTunnelConnect != null)
                    {
                        excluded = await endPoint.BeforeTunnelConnect(connectHostname);
                    }

                    connectRequest = new ConnectRequest
                    {
                        RequestUri  = httpRemoteUri,
                        OriginalUrl = httpUrl,
                        HttpVersion = version,
                    };

                    await HeaderParser.ReadHeaders(clientStreamReader, connectRequest.Headers);

                    var connectArgs = new TunnelConnectSessionEventArgs(BufferSize, endPoint, connectRequest, ExceptionFunc);
                    connectArgs.ProxyClient.TcpClient    = tcpClient;
                    connectArgs.ProxyClient.ClientStream = clientStream;

                    await endPoint.InvokeTunnectConnectRequest(this, connectArgs, ExceptionFunc);


                    if (await CheckAuthorization(clientStreamWriter, connectArgs) == false)
                    {
                        await endPoint.InvokeTunnectConnectResponse(this, connectArgs, ExceptionFunc);

                        return;
                    }

                    //write back successfull CONNECT response
                    var response = ConnectResponse.CreateSuccessfullConnectResponse(version);
                    response.Headers.FixProxyHeaders();
                    connectArgs.WebSession.Response = response;

                    await clientStreamWriter.WriteResponseAsync(response);

                    var clientHelloInfo = await SslTools.PeekClientHello(clientStream);

                    bool isClientHello = clientHelloInfo != null;
                    if (isClientHello)
                    {
                        connectRequest.ClientHelloInfo = clientHelloInfo;
                    }

                    await endPoint.InvokeTunnectConnectResponse(this, connectArgs, ExceptionFunc, isClientHello);

                    if (!excluded && isClientHello)
                    {
                        connectRequest.RequestUri = new Uri("https://" + httpUrl);

                        SslStream sslStream = null;

                        try
                        {
                            sslStream = new SslStream(clientStream);

                            string certName = HttpHelper.GetWildCardDomainName(connectHostname);

                            var certificate = endPoint.GenericCertificate ?? await CertificateManager.CreateCertificateAsync(certName);

                            //Successfully managed to authenticate the client using the fake certificate
                            await sslStream.AuthenticateAsServerAsync(certificate, false, SupportedSslProtocols, false);

                            //HTTPS server created - we can now decrypt the client's traffic
                            clientStream = new CustomBufferedStream(sslStream, BufferSize);

                            clientStreamReader.Dispose();
                            clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
                            clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
                        }
                        catch
                        {
                            sslStream?.Dispose();
                            return;
                        }

                        if (await HttpHelper.IsConnectMethod(clientStream) == -1)
                        {
                            // It can be for example some Google (Cloude Messaging for Chrome) magic
                            excluded = true;
                        }
                    }

                    //Hostname is excluded or it is not an HTTPS connect
                    if (excluded || !isClientHello)
                    {
                        //create new connection
                        using (var connection = await GetServerConnection(connectArgs, true))
                        {
                            if (isClientHello)
                            {
                                int available = clientStream.Available;
                                if (available > 0)
                                {
                                    //send the buffered data
                                    var data = BufferPool.GetBuffer(BufferSize);

                                    try
                                    {
                                        // clientStream.Available sbould be at most BufferSize because it is using the same buffer size
                                        await clientStream.ReadAsync(data, 0, available);

                                        await connection.StreamWriter.WriteAsync(data, 0, available, true);
                                    }
                                    finally
                                    {
                                        BufferPool.ReturnBuffer(data);
                                    }
                                }

                                var serverHelloInfo = await SslTools.PeekServerHello(connection.Stream);

                                ((ConnectResponse)connectArgs.WebSession.Response).ServerHelloInfo = serverHelloInfo;
                            }

                            await TcpHelper.SendRaw(clientStream, connection.Stream, BufferSize,
                                                    (buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); },
                                                    (buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); },
                                                    ExceptionFunc);
                        }

                        return;
                    }
                }

                //Now create the request
                await HandleHttpSessionRequest(tcpClient, clientStream, clientStreamReader, clientStreamWriter, connectHostname, endPoint, connectRequest);
            }
            catch (ProxyHttpException e)
            {
                ExceptionFunc(e);
            }
            catch (IOException e)
            {
                ExceptionFunc(new Exception("Connection was aborted", e));
            }
            catch (SocketException e)
            {
                ExceptionFunc(new Exception("Could not connect", e));
            }
            catch (Exception e)
            {
                ExceptionFunc(new Exception("Error occured in whilst handling the client", e));
            }
            finally
            {
                clientStreamReader.Dispose();
                clientStream.Dispose();
            }
        }
Пример #8
0
        public void HandshakeTest()
        {
            TcpClient tcpClient = new TcpClient();

            tcpClient.Client.Connect(new IPEndPoint(IPAddress.Parse(SERVER_ADDRESS), SERVER_PORT));

            Assert.IsTrue(tcpClient.Connected);

            using (NetworkStream tcpStream = tcpClient.GetStream())
            {
                RSAParameters clientPK = CryptographyHelper.GetKeyPair();
                RSAParameters serverPK = new RSAParameters();

                // Client >> HELLO <public-key>
                byte[] outdata = Encoding.UTF8.GetBytes(String.Format("HELLO {0}\r\n", CryptographyHelper.ToBase64(clientPK)));
                tcpStream.Write(outdata, 0, outdata.Length);
                tcpStream.Flush();

                // Server >> OK <public-key>
                TcpHelper.WaitForDataAvailable(tcpStream);
                if (tcpStream.DataAvailable)
                {
                    byte[] indata = new byte[512];
                    int    count  = tcpStream.Read(indata, 0, indata.Length);

                    Assert.IsTrue(count > 0);

                    string action = Encoding.UTF8.GetString(indata).Substring(0, 2);
                    string base64 = Encoding.UTF8.GetString(indata).Substring(3, (count - (action.Length + 3)));

                    Assert.AreEqual <string>("OK", action);
                    Assert.IsNotNull(base64);

                    serverPK = CryptographyHelper.FromBase64(base64);

                    Assert.IsNotNull(serverPK);
                    Assert.IsNotNull(serverPK.Exponent);
                    Assert.IsNotNull(serverPK.Modulus);
                    Assert.IsTrue(serverPK.Exponent.Length == 3);
                    Assert.IsTrue(serverPK.Modulus.Length == 256);
                }

                byte[] clientCK = Encoding.UTF8.GetBytes(Guid.NewGuid().ToString("N"));

                RSA rsa = CryptographyHelper.CreateAsymmetricCryptographyProvider();
                rsa.ImportParameters(serverPK);

                byte[] encClientCK = rsa.Encrypt(clientCK, RSAEncryptionPadding.OaepSHA1);

                // Client >> ENCRYPT <crypto-key>
                outdata = Encoding.UTF8.GetBytes(String.Format("ENCRYPT {0}\r\n", Convert.ToBase64String(encClientCK)));
                tcpStream.Write(outdata, 0, outdata.Length);
                tcpStream.Flush();

                // Server >> OK <crypto-key>
                TcpHelper.WaitForDataAvailable(tcpStream);
                if (tcpStream.DataAvailable)
                {
                    byte[] indata = new byte[512];
                    int    count  = tcpStream.Read(indata, 0, indata.Length);

                    Assert.IsTrue(count > 0);

                    string action = Encoding.UTF8.GetString(indata).Substring(0, 2);
                    string base64 = Encoding.UTF8.GetString(indata).Substring(3, (count - (action.Length + 3)));

                    Assert.AreEqual <string>("OK", action);
                    Assert.IsNotNull(base64);

                    byte[] encServerCK = Convert.FromBase64String(base64);

                    Assert.IsNotNull(encServerCK);
                    Assert.IsNotNull(encServerCK.Length == 256);

                    rsa = CryptographyHelper.CreateAsymmetricCryptographyProvider();
                    rsa.ImportParameters(clientPK);

                    byte[] serverCK = rsa.Decrypt(encServerCK, RSAEncryptionPadding.OaepSHA1);

                    Assert.IsNotNull(serverCK);
                    Assert.IsNotNull(serverCK.Length == 32);
                }

                Assert.IsTrue(tcpClient.Connected);
            }

            if (tcpClient.Connected)
            {
                tcpClient.Dispose();
            }
        }
Пример #9
0
        /// <summary>
        /// TODO: needs a big rewrite
        /// </summary>
        /// <param name="inputDataItems"></param>
        /// <returns></returns>
        protected override PropertyBagDataItem[] GetOutputData(DataItemBase[] inputDataItems)
        {
            var result = new List <PropertyBagDataItem>();

            TcpClient tcpClient;

            if (Array.IndexOf(TcpHelper.SecureSchemes, _testUri.Scheme.ToLowerInvariant()) == -1)
            {
                return(result.ToArray()); // skip checks if scheme is not secure (nothing to check)
            }
            bool authSuccess = false;

            try
            {
                if (_customDnsServers.Count > 0)
                {
                    tcpClient = new TcpClient(TcpHelper.ResolveHostName(_testUri.DnsSafeHost, _customDnsServers.ToArray())[0].ToString(), _testUri.Port); // it always return and address OR exception
                }
                else
                {
                    tcpClient = new TcpClient(_testUri.DnsSafeHost, _testUri.Port);
                }
            }
            catch (Exception ex)
            {
                _logger.WriteLog(TraceEventType.Warning, 175, $"Unable to test certificate. Can't connect to {_testUri.Host}. \n\n {ex}");
                return(result.ToArray());
            }

            X509Certificate2 remoteCert = null;

            using (var sslStream = new SslStream(tcpClient.GetStream(), false, new RemoteCertificateValidationCallback(RecordCertificateProperties)))
            {
                foreach (SslProtocols protocolType in Enum.GetValues(typeof(SslProtocols)))
                {
                    if (protocolType == SslProtocols.None)
                    {
                        continue;
                    }


                    sslStream.ReadTimeout  = 15000;
                    sslStream.WriteTimeout = 15000;

                    try
                    {
                        sslStream.AuthenticateAsClient(_testUri.Host, null, protocolType, false);
                    }
                    catch
                    {
                        continue;
                    };

                    authSuccess = true;

                    break;
                }

                if (!authSuccess)
                {
                    return(result.ToArray());
                }

                remoteCert = new X509Certificate2(sslStream.RemoteCertificate.GetRawCertData());
            }

            try
            {
                // dump some cert properties in a property bag
                var bagItem = new Dictionary <string, object>
                {
                    { "DaysToExpire", Math.Round(remoteCert.NotAfter.Subtract(DateTime.UtcNow).TotalDays, 2) },
                    { "StartDate", remoteCert.NotBefore.ToString("yyyy-MM-dd HH:mm:ss") },
                    { "EndDate", remoteCert.NotAfter.ToString("yyyy-MM-dd HH:mm:ss") },
                    { "Issuer", remoteCert.Issuer },
                    { "Subject", remoteCert.Subject },
                    { "SerialNumber", remoteCert.SerialNumber },
                    { "SignatureAlgorithm", remoteCert.SignatureAlgorithm.FriendlyName }
                };

                if (_disabledHashes.TrueForAll(x => x.Value != remoteCert.SignatureAlgorithm.Value))
                {
                    bagItem.Add("SignatureAlgorithmDisabled", "false");
                }
                else
                {
                    bagItem.Add("SignatureAlgorithmDisabled", "true");
                }

                bagItem.Add("Thumbprint", remoteCert.Thumbprint);

                if (_policyErrors == SslPolicyErrors.None)
                {
                    bagItem.Add("PolicyErrors", "NONE");
                }
                else
                {
                    bagItem.Add("PolicyErrors", _policyErrors.ToString());
                }

                // Verify the cert chain
                if (_validateCertificate)
                {
                    var certificateChain = new X509Chain(true); // Use Machine Context
                    certificateChain.ChainPolicy.RevocationFlag    = X509RevocationFlag.EntireChain;
                    certificateChain.ChainPolicy.RevocationMode    = X509RevocationMode.Online;
                    certificateChain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
                    certificateChain.Build(remoteCert);

                    if (certificateChain.ChainStatus.Length == 0)
                    {
                        bagItem.Add("CertificateIsValid", "true");
                        bagItem.Add("CertificateStatus", "");
                    }
                    else
                    {
                        bagItem.Add("CertificateIsValid", "false");

                        string strStatusMessage = string.Empty;
                        foreach (var status in certificateChain.ChainStatus)
                        {
                            strStatusMessage += $"{status.StatusInformation}; ";
                        }

                        bagItem.Add("CertificateStatus", strStatusMessage);
                    }
                }
                else
                {
                    bagItem.Add("CertificateIsValid", "true");
                    bagItem.Add("CertificateStatus", "");
                }

                result.Add(new PropertyBagDataItem(null, new Dictionary <string, Dictionary <string, object> >
                {
                    { string.Empty, bagItem }
                }));
            }
            catch (Exception ex)
            {
                //_logger.TraceEvent(TraceEventType.Warning)
            }

            return(result.ToArray());
        }
Пример #10
0
        private void Send()
        {
            switch (Const.Locator.ParameterSetting.CommModel)
            {
            case Commom.CommModel.NetPort:    //网口通讯
                if (string.IsNullOrWhiteSpace(Cmd))
                {
                    throw new Exception("Request cmd can not be null.");
                }
                if (string.IsNullOrWhiteSpace(Request))
                {
                    throw new Exception("Request can not be null.");
                }

                _netClient = new TcpHelper();
                if (string.IsNullOrWhiteSpace(Const.Locator.ParameterSetting.SdcUrl))
                {
                    MessageBoxEx.Show("EFD URL can not be null.", MessageBoxButton.OK);
                    return;
                }
                string[] sdc = Const.Locator.ParameterSetting.SdcUrl.Split(':');
                if (sdc != null && sdc.Count() != 2)
                {
                    MessageBoxEx.Show("EFD URL is not in the right format.", MessageBoxButton.OK);
                    return;
                }
                bool isConn = _netClient.Connect(IPAddress.Parse(sdc[0]), int.Parse(sdc[1]));
                if (!isConn)
                {
                    MessageBoxEx.Show("Failed to connect to EFD.", MessageBoxButton.OK);
                    return;
                }

                _netClient.Complated -= _client_Complated;
                _netClient.Complated += _client_Complated;
                switch (Cmd)
                {
                case "Status":
                    _netClient.Send(0x01, Request);
                    break;

                case "Sign":
                    _netClient.Send(0x02, Request);
                    break;

                case "Report":
                    _netClient.Send(0x04, Request);
                    break;

                default:
                    break;
                }
                _netClient.ReciveAsync();
                break;

            case Commom.CommModel.SerialPort:    //串口通讯
                if (string.IsNullOrWhiteSpace(Const.Locator.ParameterSetting.SelectedPort))
                {
                    throw new Exception("Port can not be null.");
                }
                if (string.IsNullOrWhiteSpace(Const.Locator.ParameterSetting.SelectedDataBits))
                {
                    throw new Exception("DataBits can not be null.");
                }
                if (string.IsNullOrWhiteSpace(Const.Locator.ParameterSetting.SelectedBaudRate))
                {
                    throw new Exception("BaudRate can not be null.");
                }
                if (string.IsNullOrWhiteSpace(Const.Locator.ParameterSetting.SelectedParity))
                {
                    throw new Exception("Parity can not be null.");
                }
                if (string.IsNullOrWhiteSpace(Const.Locator.ParameterSetting.SelectedStopBits))
                {
                    throw new Exception("StopBits can not be null.");
                }
                if (string.IsNullOrWhiteSpace(Cmd))
                {
                    throw new Exception("Request cmd can not be null.");
                }
                if (string.IsNullOrWhiteSpace(Request))
                {
                    throw new Exception("Request can not be null.");
                }
                _client = new SerialClient(Const.Locator.ParameterSetting.SelectedPort,
                                           int.Parse(Const.Locator.ParameterSetting.SelectedBaudRate),
                                           (Parity)Enum.Parse(typeof(Parity), Const.Locator.ParameterSetting.SelectedParity),
                                           int.Parse(Const.Locator.ParameterSetting.SelectedDataBits),
                                           (StopBits)Enum.Parse(typeof(StopBits), Const.Locator.ParameterSetting.SelectedStopBits));
                _client.Open();
                _isCanSend         = false;
                _client.Complated += _client_Complated;
                switch (Cmd)
                {
                case "Status":
                    _client.Send(0x01, Request);
                    break;

                case "Sign":
                    _client.Send(0x02, Request);
                    break;

                case "Report":
                    _client.Send(0x04, Request);
                    break;

                default:
                    break;
                }
                break;

            default:
                break;
            }
        }
        /// <summary>
        ///     This is called when this proxy acts as a reverse proxy (like a real http server).
        ///     So for HTTPS requests we would start SSL negotiation right away without expecting a CONNECT request from client
        /// </summary>
        /// <param name="endPoint">The transparent endpoint.</param>
        /// <param name="clientConnection">The client connection.</param>
        /// <returns></returns>
        private async Task handleClient(TransparentProxyEndPoint endPoint, TcpClientConnection clientConnection)
        {
            var cancellationTokenSource = new CancellationTokenSource();
            var cancellationToken       = cancellationTokenSource.Token;

            var clientStream       = new CustomBufferedStream(clientConnection.GetStream(), BufferPool, BufferSize);
            var clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize);

            Task <TcpServerConnection> prefetchConnectionTask = null;
            bool closeServerConnection = false;
            bool calledRequestHandler  = false;

            try
            {
                var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken);

                bool   isHttps       = clientHelloInfo != null;
                string httpsHostName = null;

                if (isHttps)
                {
                    httpsHostName = clientHelloInfo.GetServerName() ?? endPoint.GenericCertificateName;

                    var args = new BeforeSslAuthenticateEventArgs(cancellationTokenSource)
                    {
                        SniHostName = httpsHostName
                    };

                    await endPoint.InvokeBeforeSslAuthenticate(this, args, ExceptionFunc);

                    if (cancellationTokenSource.IsCancellationRequested)
                    {
                        throw new Exception("Session was terminated by user.");
                    }

                    if (endPoint.DecryptSsl && args.DecryptSsl)
                    {
                        //don't pass cancellation token here
                        //it could cause floating server connections when client exits
                        prefetchConnectionTask = tcpConnectionFactory.GetClient(httpsHostName, endPoint.Port,
                                                                                null, true, null, false, this,
                                                                                UpStreamEndPoint, UpStreamHttpsProxy, false, CancellationToken.None);

                        SslStream sslStream = null;

                        //do client authentication using fake certificate
                        try
                        {
                            sslStream = new SslStream(clientStream);

                            string certName    = HttpHelper.GetWildCardDomainName(httpsHostName);
                            var    certificate = await CertificateManager.CreateCertificateAsync(certName);

                            // Successfully managed to authenticate the client using the fake certificate
                            await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false);

                            // HTTPS server created - we can now decrypt the client's traffic
                            clientStream = new CustomBufferedStream(sslStream, BufferPool, BufferSize);

                            clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize);
                        }
                        catch (Exception e)
                        {
                            sslStream?.Dispose();
                            throw new ProxyConnectException(
                                      $"Could'nt authenticate client '{httpsHostName}' with fake certificate.", e, null);
                        }
                    }
                    else
                    {
                        var connection = await tcpConnectionFactory.GetClient(httpsHostName, endPoint.Port,
                                                                              null, false, null,
                                                                              true, this, UpStreamEndPoint, UpStreamHttpsProxy, true, cancellationToken);

                        try
                        {
                            CustomBufferedStream serverStream = null;
                            int available = clientStream.Available;

                            if (available > 0)
                            {
                                // send the buffered data
                                var data = BufferPool.GetBuffer(BufferSize);
                                try
                                {
                                    // clientStream.Available sbould be at most BufferSize because it is using the same buffer size
                                    await clientStream.ReadAsync(data, 0, available, cancellationToken);

                                    serverStream = connection.Stream;
                                    await serverStream.WriteAsync(data, 0, available, cancellationToken);

                                    await serverStream.FlushAsync(cancellationToken);
                                }
                                finally
                                {
                                    BufferPool.ReturnBuffer(data);
                                }
                            }

                            await TcpHelper.SendRaw(clientStream, serverStream, BufferPool, BufferSize,
                                                    null, null, cancellationTokenSource, ExceptionFunc);
                        }
                        finally
                        {
                            await tcpConnectionFactory.Release(connection, true);
                        }

                        return;
                    }
                }
                calledRequestHandler = true;
                // HTTPS server created - we can now decrypt the client's traffic
                // Now create the request
                await handleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter,
                                               cancellationTokenSource, isHttps?httpsHostName : null, null, prefetchConnectionTask);
            }
            catch (ProxyException e)
            {
                closeServerConnection = true;
                onException(clientStream, e);
            }
            catch (IOException e)
            {
                closeServerConnection = true;
                onException(clientStream, new Exception("Connection was aborted", e));
            }
            catch (SocketException e)
            {
                closeServerConnection = true;
                onException(clientStream, new Exception("Could not connect", e));
            }
            catch (Exception e)
            {
                closeServerConnection = true;
                onException(clientStream, new Exception("Error occured in whilst handling the client", e));
            }
            finally
            {
                if (!calledRequestHandler &&
                    prefetchConnectionTask != null)
                {
                    var connection = await prefetchConnectionTask;
                    await tcpConnectionFactory.Release(connection, closeServerConnection);
                }

                clientStream.Dispose();

                if (!cancellationTokenSource.IsCancellationRequested)
                {
                    cancellationTokenSource.Cancel();
                }
            }
        }
Пример #12
0
 private void OnKick(int pos)
 {
     TcpHelper.CtosMessage_HsKick(pos);
 }
Пример #13
0
    public void AddChatMsg(string msg, int player)
    {
        string result = "";

        switch (player)
        {
        case -1:     //local name
            result += Program.I().selectServer.name;
            result += ":";
            break;

        case 0:     //from host
            result += Program.I().ocgcore.name_0;
            result += ":";
            break;

        case 1:     //from client
            result += Program.I().ocgcore.name_1;
            result += ":";
            break;

        case 2:     //host tag
            result += Program.I().ocgcore.name_0_tag;
            result += ":";
            break;

        case 3:     //client tag
            result += Program.I().ocgcore.name_1_tag;
            result += ":";
            break;

        case 7:     //---
            result += "[---]";
            result += ":";
            break;

        case 8:     //system custom message, no prefix.
            result += "[System]";
            result += ":";
            break;

        case 9:     //error message
            result += "[Script error]";
            result += ":";
            break;

        default:     //from watcher or unknown
            result += "[---]";
            result += ":";
            break;
        }
        result += msg;
        string res = "[888888]" + result + "[-]";

        Program.I().book.add(res);
        Package p = new Package();

        p.Fuction = (int)YGOSharp.OCGWrapper.Enums.GameMessage.sibyl_chat;
        p.Data    = new BinaryMaster();
        p.Data.writer.WriteUnicode(res, res.Length + 1);
        TcpHelper.AddRecordLine(p);
        switch ((YGOSharp.Network.Enums.PlayerType)player)
        {
        case YGOSharp.Network.Enums.PlayerType.Red:
            result = "[FF3030]" + result + "[-]";
            break;

        case YGOSharp.Network.Enums.PlayerType.Green:
            result = "[7CFC00]" + result + "[-]";
            break;

        case YGOSharp.Network.Enums.PlayerType.Blue:
            result = "[4876FF]" + result + "[-]";
            break;

        case YGOSharp.Network.Enums.PlayerType.BabyBlue:
            result = "[63B8FF]" + result + "[-]";
            break;

        case YGOSharp.Network.Enums.PlayerType.Pink:
            result = "[EED2EE]" + result + "[-]";
            break;

        case YGOSharp.Network.Enums.PlayerType.Yellow:
            result = "[EEEE00]" + result + "[-]";
            break;

        case YGOSharp.Network.Enums.PlayerType.White:
            result = "[FAF0E6]" + result + "[-]";
            break;

        case YGOSharp.Network.Enums.PlayerType.Gray:
            result = "[CDC9C9]" + result + "[-]";
            break;
        }
        RMSshow_none(result);
    }
Пример #14
0
 void handler(byte[] buffer)
 {
     TcpHelper.CtosMessage_Response(buffer);
 }
Пример #15
0
    void Update()
    {
        if (preWid != Screen.width || preheight != Screen.height)
        {
            Resources.UnloadUnusedAssets();
            onRESIZED();
        }
        fixALLcamerasPreFrame();
        wheelValue        = UICamera.GetAxis("Mouse ScrollWheel") * 50;
        pointedGameObject = null;
        pointedCollider   = null;
        Ray        line = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;

        if (Physics.Raycast(line, out hit, (float)1000, rayFilter))
        {
            pointedGameObject = hit.collider.gameObject;
            pointedCollider   = hit.collider;
        }
        GameObject hoverobject = UICamera.Raycast(Input.mousePosition) ? UICamera.lastHit.collider.gameObject : null;

        if (hoverobject != null)
        {
            if (hoverobject.layer == 11 || pointedGameObject == null)
            {
                pointedGameObject = hoverobject;
                pointedCollider   = UICamera.lastHit.collider;
            }
        }
        InputGetMouseButtonDown_0 = Input.GetMouseButtonDown(0);
        InputGetMouseButtonUp_0   = Input.GetMouseButtonUp(0);
        InputGetMouseButtonDown_1 = Input.GetMouseButtonDown(1);
        InputGetMouseButtonUp_1   = Input.GetMouseButtonUp(1);
        InputEnterDown            = Input.GetKeyDown(KeyCode.Return);
        InputGetMouseButton_0     = Input.GetMouseButton(0);
        for (int i = 0; i < servants.Count; i++)
        {
            servants[i].Update();
        }
        TcpHelper.preFrameFunction();
        delayedTask remove = null;

        while (true)
        {
            remove = null;
            for (int i = 0; i < delayedTasks.Count; i++)
            {
                if (Program.TimePassed() > delayedTasks[i].timeToBeDone)
                {
                    remove = delayedTasks[i];
                    try
                    {
                        remove.act();
                    }
                    catch (System.Exception e)
                    {
                        UnityEngine.Debug.Log(e);
                    }
                    break;
                }
            }
            if (remove != null)
            {
                delayedTasks.Remove(remove);
            }
            else
            {
                break;
            }
        }
    }
Пример #16
0
        /// <summary>
        /// This is the core request handler method for a particular connection from client
        /// Will create new session (request/response) sequence until
        /// client/server abruptly terminates connection or by normal HTTP termination
        /// </summary>
        /// <param name="client"></param>
        /// <param name="clientStream"></param>
        /// <param name="clientStreamReader"></param>
        /// <param name="clientStreamWriter"></param>
        /// <param name="httpsConnectHostname"></param>
        /// <param name="endPoint"></param>
        /// <param name="connectRequest"></param>
        /// <param name="isTransparentEndPoint"></param>
        /// <returns></returns>
        private async Task HandleHttpSessionRequest(TcpClient client, CustomBufferedStream clientStream,
                                                    CustomBinaryReader clientStreamReader, HttpResponseWriter clientStreamWriter, string httpsConnectHostname,
                                                    ProxyEndPoint endPoint, ConnectRequest connectRequest, bool isTransparentEndPoint = false)
        {
            TcpConnection connection = null;

            try
            {
                //Loop through each subsequest request on this particular client connection
                //(assuming HTTP connection is kept alive by client)
                while (true)
                {
                    // read the request line
                    string httpCmd = await clientStreamReader.ReadLineAsync();

                    if (string.IsNullOrEmpty(httpCmd))
                    {
                        break;
                    }

                    var args = new SessionEventArgs(BufferSize, endPoint, ExceptionFunc)
                    {
                        ProxyClient = { TcpClient = client },
                        WebSession  = { ConnectRequest = connectRequest }
                    };

                    try
                    {
                        Request.ParseRequestLine(httpCmd, out string httpMethod, out string httpUrl, out var version);

                        //Read the request headers in to unique and non-unique header collections
                        await HeaderParser.ReadHeaders(clientStreamReader, args.WebSession.Request.Headers);

                        Uri httpRemoteUri;
                        if (uriSchemeRegex.IsMatch(httpUrl))
                        {
                            try
                            {
                                httpRemoteUri = new Uri(httpUrl);
                            }
                            catch (Exception ex)
                            {
                                throw new Exception($"Invalid URI: '{httpUrl}'", ex);
                            }
                        }
                        else
                        {
                            string host        = args.WebSession.Request.Host ?? httpsConnectHostname;
                            string hostAndPath = host;
                            if (httpUrl.StartsWith("/"))
                            {
                                hostAndPath += httpUrl;
                            }

                            string url = string.Concat(httpsConnectHostname == null ? "http://" : "https://", hostAndPath);
                            try
                            {
                                httpRemoteUri = new Uri(url);
                            }
                            catch (Exception ex)
                            {
                                throw new Exception($"Invalid URI: '{url}'", ex);
                            }
                        }

                        args.WebSession.Request.RequestUri  = httpRemoteUri;
                        args.WebSession.Request.OriginalUrl = httpUrl;

                        args.WebSession.Request.Method      = httpMethod;
                        args.WebSession.Request.HttpVersion = version;
                        args.ProxyClient.ClientStream       = clientStream;
                        args.ProxyClient.ClientStreamReader = clientStreamReader;
                        args.ProxyClient.ClientStreamWriter = clientStreamWriter;

                        //proxy authorization check
                        if (!args.IsTransparent && httpsConnectHostname == null && await CheckAuthorization(clientStreamWriter, args) == false)
                        {
                            break;
                        }

                        if (!isTransparentEndPoint)
                        {
                            PrepareRequestHeaders(args.WebSession.Request.Headers);
                            args.WebSession.Request.Host = args.WebSession.Request.RequestUri.Authority;
                        }

                        //if win auth is enabled
                        //we need a cache of request body
                        //so that we can send it after authentication in WinAuthHandler.cs
                        if (isWindowsAuthenticationEnabledAndSupported && args.WebSession.Request.HasBody)
                        {
                            await args.GetRequestBody();
                        }

                        //If user requested interception do it
                        if (BeforeRequest != null)
                        {
                            await BeforeRequest.InvokeAsync(this, args, ExceptionFunc);
                        }

                        var response = args.WebSession.Response;

                        if (args.WebSession.Request.CancelRequest)
                        {
                            await HandleHttpSessionResponse(args);

                            if (!response.KeepAlive)
                            {
                                break;
                            }

                            continue;
                        }

                        //create a new connection if hostname/upstream end point changes
                        if (connection != null &&
                            (!connection.HostName.Equals(args.WebSession.Request.RequestUri.Host, StringComparison.OrdinalIgnoreCase) ||
                             (args.WebSession.UpStreamEndPoint != null &&
                              !args.WebSession.UpStreamEndPoint.Equals(connection.UpStreamEndPoint))))
                        {
                            connection.Dispose();
                            connection = null;
                        }

                        if (connection == null)
                        {
                            connection = await GetServerConnection(args, false);
                        }

                        //if upgrading to websocket then relay the requet without reading the contents
                        if (args.WebSession.Request.UpgradeToWebSocket)
                        {
                            //prepare the prefix content
                            var requestHeaders = args.WebSession.Request.Headers;
                            await connection.StreamWriter.WriteLineAsync(httpCmd);

                            await connection.StreamWriter.WriteHeadersAsync(requestHeaders);

                            string httpStatus = await connection.StreamReader.ReadLineAsync();

                            Response.ParseResponseLine(httpStatus, out var responseVersion, out int responseStatusCode, out string responseStatusDescription);
                            response.HttpVersion       = responseVersion;
                            response.StatusCode        = responseStatusCode;
                            response.StatusDescription = responseStatusDescription;

                            await HeaderParser.ReadHeaders(connection.StreamReader, response.Headers);

                            if (!args.IsTransparent)
                            {
                                await clientStreamWriter.WriteResponseAsync(response);
                            }

                            //If user requested call back then do it
                            if (BeforeResponse != null && !args.WebSession.Response.ResponseLocked)
                            {
                                await BeforeResponse.InvokeAsync(this, args, ExceptionFunc);
                            }

                            await TcpHelper.SendRaw(clientStream, connection.Stream, BufferSize,
                                                    (buffer, offset, count) => { args.OnDataSent(buffer, offset, count); },
                                                    (buffer, offset, count) => { args.OnDataReceived(buffer, offset, count); },
                                                    ExceptionFunc);

                            break;
                        }

                        //construct the web request that we are going to issue on behalf of the client.
                        await HandleHttpSessionRequestInternal(connection, args);

                        //if connection is closing exit
                        if (!response.KeepAlive)
                        {
                            break;
                        }
                    }
                    catch (Exception e) when(!(e is ProxyHttpException))
                    {
                        throw new ProxyHttpException("Error occured whilst handling session request", e, args);
                    }
                    finally
                    {
                        args.Dispose();
                    }
                }
            }
            finally
            {
                connection?.Dispose();
            }
        }
Пример #17
0
        public void OnHandleNextRequest()
        {
            TcpHelper helper = new TcpHelper(client);

            helper.ReadJsonData(OnReceivedNextRequest);
        }
Пример #18
0
        private static void HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream,
                                                     CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string secureTunnelHostName)
        {
            if (string.IsNullOrEmpty(httpCmd))
            {
                Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
                return;
            }

            var args = new SessionEventArgs(BUFFER_SIZE);

            args.Client = client;


            try
            {
                //break up the line into three components (method, remote URL & Http Version)
                var httpCmdSplit = httpCmd.Split(SpaceSplit, 3);

                var httpMethod    = httpCmdSplit[0];
                var httpRemoteUri =
                    new Uri(secureTunnelHostName == null ? httpCmdSplit[1] : (secureTunnelHostName + httpCmdSplit[1]));
                var httpVersion = httpCmdSplit[2];

                Version version;
                if (httpVersion == "HTTP/1.1")
                {
                    version = new Version(1, 1);
                }
                else
                {
                    version = new Version(1, 0);
                }

                if (httpRemoteUri.Scheme == Uri.UriSchemeHttps)
                {
                    args.IsHttps = true;
                }

                args.RequestHeaders = new List <HttpHeader>();

                string tmpLine;

                while (!string.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
                {
                    var header = tmpLine.Split(ColonSpaceSplit, 2, StringSplitOptions.None);
                    args.RequestHeaders.Add(new HttpHeader(header[0], header[1]));
                }

                for (var i = 0; i < args.RequestHeaders.Count; i++)
                {
                    var rawHeader = args.RequestHeaders[i];


                    //if request was upgrade to web-socket protocol then relay the request without proxying
                    if ((rawHeader.Name.ToLower() == "upgrade") && (rawHeader.Value.ToLower() == "websocket"))
                    {
                        TcpHelper.SendRaw(clientStreamReader.BaseStream, httpCmd, args.RequestHeaders,
                                          httpRemoteUri.Host, httpRemoteUri.Port, httpRemoteUri.Scheme == Uri.UriSchemeHttps);
                        Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
                        return;
                    }
                }

                //验证服务器证书回调自动验证
                System.Net.ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult);
                //construct the web request that we are going to issue on behalf of the client.
                args.ProxyRequest       = (HttpWebRequest)WebRequest.Create(httpRemoteUri);
                args.ProxyRequest.Proxy = null;
                args.ProxyRequest.UseDefaultCredentials = true;
                args.ProxyRequest.Method          = httpMethod;
                args.ProxyRequest.ProtocolVersion = version;
                args.ClientStream                        = clientStream;
                args.ClientStreamReader                  = clientStreamReader;
                args.ClientStreamWriter                  = clientStreamWriter;
                args.ProxyRequest.AllowAutoRedirect      = false;
                args.ProxyRequest.AutomaticDecompression = DecompressionMethods.None;
                args.RequestHostname                     = args.ProxyRequest.RequestUri.Host;
                args.RequestUrl         = args.ProxyRequest.RequestUri.OriginalString;
                args.ClientPort         = ((IPEndPoint)client.Client.RemoteEndPoint).Port;
                args.ClientIpAddress    = ((IPEndPoint)client.Client.RemoteEndPoint).Address;
                args.RequestHttpVersion = version;
                args.RequestIsAlive     = args.ProxyRequest.KeepAlive;
                args.ProxyRequest.ConnectionGroupName       = args.RequestHostname;
                args.ProxyRequest.AllowWriteStreamBuffering = true;


                //If requested interception
                if (BeforeRequest != null)
                {
                    args.RequestEncoding = args.ProxyRequest.GetEncoding();
                    BeforeRequest(null, args);
                }

                args.RequestLocked = true;

                if (args.CancelRequest)
                {
                    Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
                    return;
                }

                SetRequestHeaders(args.RequestHeaders, args.ProxyRequest);

                //If request was modified by user
                if (args.RequestBodyRead)
                {
                    args.ProxyRequest.ContentLength = args.RequestBody.Length;
                    var newStream = args.ProxyRequest.GetRequestStream();
                    newStream.Write(args.RequestBody, 0, args.RequestBody.Length);

                    args.ProxyRequest.BeginGetResponse(HandleHttpSessionResponse, args);
                }
                else
                {
                    //If its a post/put request, then read the client html body and send it to server
                    if (httpMethod.ToUpper() == "POST" || httpMethod.ToUpper() == "PUT")
                    {
                        SendClientRequestBody(args);
                    }
                    //Http request body sent, now wait asynchronously for response
                    args.ProxyRequest.BeginGetResponse(HandleHttpSessionResponse, args);
                }

                //Now read the next request (if keep-Alive is enabled, otherwise exit this thread)
                //If client is pipeling the request, this will be immediately hit before response for previous request was made
                httpCmd = clientStreamReader.ReadLine();
                //Http request body sent, now wait for next request
                Task.Factory.StartNew(
                    () =>
                    HandleHttpSessionRequest(args.Client, httpCmd, args.ClientStream, args.ClientStreamReader,
                                             args.ClientStreamWriter, secureTunnelHostName));
            }
            catch
            {
                Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
            }
        }