public static async Task <SocksProxyRequest> ReadRequestAsync(Stream s) { SocksProxyRequest request = new SocksProxyRequest(); byte[] buffer = new byte[3]; await s.ReadBytesAsync(buffer, 0, 3); request._version = buffer[0]; request._command = (SocksProxyRequestCommand)buffer[1]; request._dstEP = await SocksProxyServer.ReadEndPointAsync(s); return(request); }
private static async Task <EndPoint> RequestAsync(Stream s, SocksProxyRequest request) { await request.WriteToAsync(s); await s.FlushAsync(); SocksProxyReply reply = await SocksProxyReply.ReadReplyAsync(s); if (!reply.IsVersionSupported) { throw new SocksProxyException("Socks version 5 is not supported by the proxy server."); } if (reply.ReplyCode != SocksProxyReplyCode.Succeeded) { throw new SocksProxyException("Socks proxy server request failed: " + reply.ReplyCode.ToString(), reply.ReplyCode); } return(reply.BindEndPoint); }
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(); } } }