示例#1
0
            public async Task StartAsync()
            {
                bool dontDispose = false;

                try
                {
                    NetworkStream localNetworkStream = new NetworkStream(_localSocket);
                    Stream        localStream        = new WriteBufferedStream(localNetworkStream, 512);

                    #region authenticate

                    SocksProxyNegotiationRequest negotiationRequest = await SocksProxyNegotiationRequest.ReadRequestAsync(localStream).WithTimeout(CLIENT_WAIT_TIMEOUT);

                    if (!negotiationRequest.IsVersionSupported)
                    {
                        await new SocksProxyNegotiationReply(SocksProxyAuthenticationMethod.NoAcceptableMethods).WriteToAsync(localStream);
                        await localStream.FlushAsync();

                        return;
                    }

                    //match method and authenticate
                    bool methodMatched = false;
                    SocksProxyAuthenticationMethod serverMethod = _authenticationManager == null ? SocksProxyAuthenticationMethod.NoAuthenticationRequired : SocksProxyAuthenticationMethod.UsernamePassword;

                    foreach (SocksProxyAuthenticationMethod method in negotiationRequest.Methods)
                    {
                        if (method == serverMethod)
                        {
                            //method matches
                            await new SocksProxyNegotiationReply(method).WriteToAsync(localStream);
                            await localStream.FlushAsync();

                            switch (serverMethod)
                            {
                            case SocksProxyAuthenticationMethod.NoAuthenticationRequired:
                                methodMatched = true;
                                break;

                            case SocksProxyAuthenticationMethod.UsernamePassword:
                                //read method version

                                SocksProxyAuthenticationRequest authenticationRequest = await SocksProxyAuthenticationRequest.ReadRequestAsync(localStream).WithTimeout(CLIENT_WAIT_TIMEOUT);

                                if (!authenticationRequest.IsVersionSupported)
                                {
                                    await new SocksProxyAuthenticationReply(SocksProxyAuthenticationStatus.Failure).WriteToAsync(localStream);
                                    await localStream.FlushAsync();

                                    return;
                                }

                                if (!_authenticationManager.Authenticate(authenticationRequest.Username, authenticationRequest.Password))
                                {
                                    await new SocksProxyAuthenticationReply(SocksProxyAuthenticationStatus.Failure).WriteToAsync(localStream);
                                    await localStream.FlushAsync();

                                    return;
                                }

                                await new SocksProxyAuthenticationReply(SocksProxyAuthenticationStatus.Success).WriteToAsync(localStream);
                                await localStream.FlushAsync();

                                methodMatched = true;
                                break;
                            }

                            break;
                        }
                    }

                    if (!methodMatched)
                    {
                        //no method matched
                        await new SocksProxyNegotiationReply(SocksProxyAuthenticationMethod.NoAcceptableMethods).WriteToAsync(localStream);
                        await localStream.FlushAsync();

                        return;
                    }

                    #endregion

                    #region process request

                    //read request
                    SocksProxyRequest request = await SocksProxyRequest.ReadRequestAsync(localStream).WithTimeout(CLIENT_WAIT_TIMEOUT);

                    if (!request.IsVersionSupported)
                    {
                        await new SocksProxyReply(SocksProxyReplyCode.GeneralSocksServerFailure).WriteToAsync(localStream);
                        await localStream.FlushAsync();

                        return;
                    }

                    //process command
                    SocksProxyReplyCode reply;
                    EndPoint            bindEP;

                    switch (request.Command)
                    {
                    case SocksProxyRequestCommand.Connect:
                    {
                        try
                        {
                            _remoteSocket = await _connectionManager.ConnectAsync(request.DestinationEndPoint);

                            reply  = SocksProxyReplyCode.Succeeded;
                            bindEP = _remoteSocket.LocalEndPoint;
                        }
                        catch (SocketException ex)
                        {
                            switch (ex.SocketErrorCode)
                            {
                            case SocketError.NetworkUnreachable:
                                reply = SocksProxyReplyCode.NetworkUnreachable;
                                break;

                            case SocketError.HostUnreachable:
                                reply = SocksProxyReplyCode.HostUnreachable;
                                break;

                            case SocketError.ConnectionRefused:
                                reply = SocksProxyReplyCode.ConnectionRefused;
                                break;

                            default:
                                reply = SocksProxyReplyCode.GeneralSocksServerFailure;
                                break;
                            }

                            bindEP = new IPEndPoint(IPAddress.Any, 0);
                        }
                    }
                    break;

                    case SocksProxyRequestCommand.Bind:
                    {
                        _bindHandler = await _connectionManager.GetBindHandlerAsync(request.DestinationEndPoint.AddressFamily);

                        reply  = _bindHandler.ReplyCode;
                        bindEP = _bindHandler.ProxyLocalEndPoint;
                    }
                    break;

                    case SocksProxyRequestCommand.UdpAssociate:
                    {
                        switch (_localSocket.LocalEndPoint.AddressFamily)
                        {
                        case AddressFamily.InterNetwork:
                        case AddressFamily.InterNetworkV6:
                            EndPoint localEP = new IPEndPoint((_localSocket.LocalEndPoint as IPEndPoint).Address, 0);

                            _udpRelaySocket = new Socket(localEP.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
                            _udpRelaySocket.Bind(localEP);

                            reply  = SocksProxyReplyCode.Succeeded;
                            bindEP = _udpRelaySocket.LocalEndPoint as IPEndPoint;
                            break;

                        default:
                            reply  = SocksProxyReplyCode.AddressTypeNotSupported;
                            bindEP = new IPEndPoint(IPAddress.Any, 0);
                            break;
                        }
                    }
                    break;

                    default:
                        reply  = SocksProxyReplyCode.CommandNotSupported;
                        bindEP = new IPEndPoint(IPAddress.Any, 0);
                        break;
                    }

                    //send response
                    await new SocksProxyReply(reply, bindEP).WriteToAsync(localStream);
                    await localStream.FlushAsync();

                    if (reply != SocksProxyReplyCode.Succeeded)
                    {
                        return; //nothing to do further
                    }
                    //final command process
                    switch (request.Command)
                    {
                    case SocksProxyRequestCommand.Connect:
                    {
                        //pipe sockets
                        _           = _localSocket.CopyToAsync(_remoteSocket).ContinueWith(delegate(Task prevTask) { Dispose(); });
                        _           = _remoteSocket.CopyToAsync(_localSocket).ContinueWith(delegate(Task prevTask) { Dispose(); });
                        dontDispose = true;
                    }
                    break;

                    case SocksProxyRequestCommand.Bind:
                    {
                        try
                        {
                            _remoteSocket = await _bindHandler.AcceptAsync().WithTimeout(CLIENT_WAIT_TIMEOUT);
                        }
                        catch (SocksProxyException ex)
                        {
                            //send second reply
                            await new SocksProxyReply(ex.ReplyCode, _bindHandler.ProxyLocalEndPoint).WriteToAsync(localStream);
                            await localStream.FlushAsync();
                        }
                        catch
                        {
                            //send second reply
                            await new SocksProxyReply(SocksProxyReplyCode.GeneralSocksServerFailure, _bindHandler.ProxyLocalEndPoint).WriteToAsync(localStream);
                            await localStream.FlushAsync();
                        }

                        if (_remoteSocket != null)
                        {
                            _bindHandler.Dispose();

                            //send second reply
                            await new SocksProxyReply(SocksProxyReplyCode.Succeeded, _bindHandler.ProxyRemoteEndPoint).WriteToAsync(localStream);
                            await localStream.FlushAsync();

                            //pipe sockets
                            _           = _localSocket.CopyToAsync(_remoteSocket).ContinueWith(delegate(Task prevTask) { Dispose(); });
                            _           = _remoteSocket.CopyToAsync(_localSocket).ContinueWith(delegate(Task prevTask) { Dispose(); });
                            dontDispose = true;
                        }
                    }
                    break;

                    case SocksProxyRequestCommand.UdpAssociate:
                    {
                        EndPoint localEP = null;

                        switch (_localSocket.LocalEndPoint.AddressFamily)
                        {
                        case AddressFamily.InterNetwork:
                            localEP = new IPEndPoint(IPAddress.Any, 0);
                            break;

                        case AddressFamily.InterNetworkV6:
                            localEP = new IPEndPoint(IPAddress.IPv6Any, 0);
                            break;

                        default:
                            throw new NotSupportedException();
                        }

                        using (IProxyServerUdpAssociateHandler udpRemoteHandler = await _connectionManager.GetUdpAssociateHandlerAsync(localEP))
                        {
                            using (IProxyServerUdpAssociateHandler udpLocalHandler = new SocksProxyUdpAssociateHandler(_localSocket, _udpRelaySocket, new IPEndPoint((_localSocket.RemoteEndPoint as IPEndPoint).Address, (request.DestinationEndPoint as IPEndPoint).Port)))
                            {
                                _ = CopyToAsync(udpRemoteHandler, udpLocalHandler);
                                await CopyToAsync(udpLocalHandler, udpRemoteHandler);
                            }
                        }
                    }
                    break;
                    }

                    #endregion
                }
                finally
                {
                    if (!dontDispose)
                    {
                        Dispose();
                    }
                }
            }
示例#2
0
            public async Task StartAsync()
            {
                bool dontDispose = false;

                try
                {
                    NetworkStream localStream  = new NetworkStream(_localSocket);
                    Stream        remoteStream = null;

                    string lastHost = null;
                    int    lastPort = 0;

                    while (true)
                    {
                        HttpRequest httpRequest;
                        {
                            Task <HttpRequest> task = HttpRequest.ReadRequestAsync(localStream);

                            using (CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource())
                            {
                                if (await Task.WhenAny(task, Task.Delay(CLIENT_REQUEST_TIMEOUT, timeoutCancellationTokenSource.Token)) != task)
                                {
                                    return;                              //request timed out
                                }
                                timeoutCancellationTokenSource.Cancel(); //cancel delay task
                            }

                            httpRequest = await task;
                        }

                        if (httpRequest == null)
                        {
                            return; //connection closed gracefully by client
                        }
                        if (_authenticationManager != null)
                        {
                            string proxyAuth = httpRequest.Headers[HttpRequestHeader.ProxyAuthorization];
                            if (string.IsNullOrEmpty(proxyAuth))
                            {
                                await SendResponseAsync(407, "<h1>Proxy Authentication Required</h1>");

                                return;
                            }

                            string username;
                            string password;
                            {
                                string[] parts = proxyAuth.Split(new char[] { ' ' }, 2);

                                if (!parts[0].Equals("BASIC", StringComparison.OrdinalIgnoreCase) || (parts.Length < 2))
                                {
                                    await SendResponseAsync(407, "<h1>Proxy Authentication Required</h1><p>Proxy authentication method is not supported.</p>");

                                    return;
                                }

                                string[] credParts = Encoding.ASCII.GetString(Convert.FromBase64String(parts[1])).Split(new char[] { ':' }, 2);
                                if (credParts.Length != 2)
                                {
                                    await SendResponseAsync(407, "<h1>Proxy Authentication Required</h1><p>Proxy authentication method is not supported.</p>");

                                    return;
                                }

                                username = credParts[0];
                                password = credParts[1];
                            }

                            if (!_authenticationManager.Authenticate(username, password))
                            {
                                await SendResponseAsync(407, "<h1>Proxy Authentication Required</h1><p>Invalid username or password.</p>");

                                return;
                            }
                        }

                        if (httpRequest.HttpMethod.Equals("CONNECT", StringComparison.OrdinalIgnoreCase))
                        {
                            await DoConnectAsync(localStream, httpRequest);

                            dontDispose = true;
                            break;
                        }
                        else
                        {
                            #region connect to remote server

                            string host;
                            int    port;
                            string requestPathAndQuery;

                            if (Uri.TryCreate(httpRequest.RequestPathAndQuery, UriKind.Absolute, out Uri requestUri))
                            {
                                host = requestUri.Host;
                                port = requestUri.Port;
                                requestPathAndQuery = requestUri.PathAndQuery;
                            }
                            else
                            {
                                string hostHeader = httpRequest.Headers[HttpRequestHeader.Host];
                                if (string.IsNullOrEmpty(hostHeader))
                                {
                                    throw new HttpProxyServerException("Invalid proxy request.");
                                }

                                string[] parts = hostHeader.Split(':');

                                host = parts[0];

                                if (parts.Length > 1)
                                {
                                    port = int.Parse(parts[1]);
                                }
                                else
                                {
                                    port = 80;
                                }

                                requestPathAndQuery = httpRequest.RequestPathAndQuery;
                            }

                            if (!host.Equals(lastHost) || port != lastPort || !_remoteSocket.Connected)
                            {
                                if (_remoteSocket != null)
                                {
                                    if (_remoteSocket.Connected)
                                    {
                                        try
                                        {
                                            _remoteSocket.Shutdown(SocketShutdown.Both);
                                        }
                                        catch
                                        { }
                                    }

                                    _remoteSocket.Dispose();
                                }

                                _remoteSocket = await _connectionManager.ConnectAsync(EndPointExtension.GetEndPoint(host, port));

                                remoteStream = new WriteBufferedStream(new NetworkStream(_remoteSocket), 512);

                                lastHost = host;
                                lastPort = port;

                                //pipe response stream
                                _ = _remoteSocket.CopyToAsync(_localSocket).ContinueWith(delegate(Task prevTask) { Dispose(); });
                            }

                            #endregion

                            #region relay client request to server

                            foreach (string header in httpRequest.Headers.AllKeys)
                            {
                                if (header.StartsWith("Proxy-", StringComparison.OrdinalIgnoreCase))
                                {
                                    httpRequest.Headers.Remove(header);
                                }
                            }

                            await remoteStream.WriteAsync(Encoding.ASCII.GetBytes(httpRequest.HttpMethod + " " + requestPathAndQuery + " " + httpRequest.Protocol + "\r\n"));

                            await remoteStream.WriteAsync(httpRequest.Headers.ToByteArray());

                            if (httpRequest.InputStream != null)
                            {
                                await httpRequest.InputStream.CopyToAsync(remoteStream);
                            }

                            await remoteStream.FlushAsync();

                            #endregion
                        }
                    }
                }
                catch (Exception ex)
                {
                    await SendResponseAsync(ex);
                }
                finally
                {
                    if (!dontDispose)
                    {
                        Dispose();
                    }
                }
            }