private async void ProcessLocalConnection(object state) { var connection = (ConnectionInfo)state; var buffer = new byte[BufferSize]; try { var bytesRead = connection.LocalSocket.Receive(buffer); if (bytesRead < 1 || buffer[0] != Protocol.Socks4.Version) { connection.Terminate(); return; } OnLogMessage?.Invoke(this, $"Got {bytesRead} bytes from "); } catch (SocketException ex) { OnLogMessage?.Invoke(this, $"Caught SocketException in ProcessLocalConnection with error code {ex.SocketErrorCode}"); } try { switch (buffer[1]) { case Protocol.Socks4.CommandStreamConnection: { var portBuffer = new[] { buffer[2], buffer[3] }; var port = (ushort)(portBuffer[0] << 8 | portBuffer[1]); var address = new[] { buffer[4], buffer[5], buffer[6], buffer[7] }; var destAddress = new IPAddress(address).ToString(); var destAddressFamily = AddressFamily.InterNetwork; if (IsSocks4AProtocol(address)) { var hostBuffer = new byte[256]; Buffer.BlockCopy(buffer, 9, hostBuffer, 0, 100); // Resolve hostname, fallback to remote proxy dns resolution var hostname = Encoding.ASCII.GetString(hostBuffer).TrimEnd((char)0); if (!ResolveHostnamesRemotely) { var resolvedHostname = await DnsResolver.TryResolve(hostname); if (resolvedHostname == null) { OnLogMessage?.Invoke(this, $"DNS resolution failed for {hostname}"); SendSocks4Reply(connection.LocalSocket, Protocol.Socks4.StatusRequestGranted, address, portBuffer); connection.Terminate(); break; } destAddress = resolvedHostname.ToString(); destAddressFamily = resolvedHostname.AddressFamily; } else { destAddress = hostname; destAddressFamily = AddressFamily.Unspecified; } } connection.RemoteSocket = Socks5Client.Connect( RemotEndPoint.Address.ToString(), RemotEndPoint.Port, destAddress, port, Username, Password, SendTimeout, ReceiveTimeout); OnRemoteConnect?.Invoke(this, new DnsEndPoint(destAddress, port, destAddressFamily)); if (connection.RemoteSocket.Connected) { OnLogMessage?.Invoke(this, "RelayBiDirectionally between server and client started"); SendSocks4Reply(connection.LocalSocket, Protocol.Socks4.StatusRequestGranted, address, portBuffer); SocketRelay.RelayBiDirectionally(connection.RemoteSocket, connection.LocalSocket); } else { OnLogMessage?.Invoke(this, "RemoteSocket connection failed"); SendSocks4Reply(connection.LocalSocket, Protocol.Socks4.StatusRequestFailed, address, portBuffer); connection.Terminate(); } break; } case Protocol.Socks4.CommandBindingConnection: { var portBuffer = new[] { buffer[2], buffer[3] }; var address = new[] { buffer[4], buffer[5], buffer[6], buffer[7] }; // TCP/IP port binding not supported SendSocks4Reply(connection.LocalSocket, Protocol.Socks4.StatusRequestFailed, address, portBuffer); connection.Terminate(); break; } default: OnLogMessage?.Invoke(this, "Unknown protocol on LocalSocket"); connection.Terminate(); break; } } catch (SocketException ex) { OnLogMessage?.Invoke(this, $"Caught SocketException in ProcessLocalConnection with error code {ex.SocketErrorCode.ToString()}"); } catch (Socks5Exception ex) { var portBuffer = new[] { buffer[2], buffer[3] }; var address = new[] { buffer[4], buffer[5], buffer[6], buffer[7] }; SendSocks4Reply(connection.LocalSocket, Protocol.Socks4.StatusRequestFailed, address, portBuffer); connection.Terminate(); OnLogMessage?.Invoke(this, $"Caught Socks5Exception in ProcessLocalConnection with message {ex.Message}"); } }
public static Socket Connect(string socksAddress, int socksPort, string destAddress, int destPort, string username, string password, int sendTimeout, int receiveTimeout) { var client = new Socks5Client(socksAddress, socksPort, destAddress, destPort, username, password, sendTimeout, receiveTimeout); return(client.Connect()); }
private void ProcessLocalConnection(object state) { var connection = (ConnectionInfo)state; var buffer = new byte[BufferSize]; int bytesRead; try { bytesRead = connection.LocalSocket.Receive(buffer); if (bytesRead < 1 || buffer[0] != Protocol.Socks4.Version) { connection.LocalSocket.Close(); return; } OnLogMessage?.Invoke(this, $"LocalSocket.Receive {bytesRead}"); } catch (SocketException ex) { OnLogMessage?.Invoke(this, $"Caught SocketException in ProcessLocalConnection with error code {ex.SocketErrorCode.ToString()}"); } try { switch (buffer[1]) { case Protocol.Socks4.CommandStreamConnection: { var portBuffer = new[] { buffer[2], buffer[3] }; var port = (ushort)(portBuffer[0] << 8 | portBuffer[1]); var ipBuffer = new[] { buffer[4], buffer[5], buffer[6], buffer[7] }; var ip = new IPAddress(ipBuffer); var destinationEndPoint = new IPEndPoint(ip, port); if (IsSocks4AProtocol(ipBuffer)) { var hostBuffer = new byte[256]; Buffer.BlockCopy(buffer, 9, hostBuffer, 0, 100); // Resolve hostname, fallback to remote proxy dns resolution var hostname = Encoding.ASCII.GetString(hostBuffer).TrimEnd((char)0); var destinationIp = ResolveHostnamesRemotely ? null : DnsResolver.TryResolve(hostname); connection.RemoteSocket = Socks5Client.Connect( RemotEndPoint.Address.ToString(), RemotEndPoint.Port, destinationIp == null ? hostname : destinationIp.ToString(), port, Username, Password, SendTimeout, ReceiveTimeout ); OnRemoteConnect?.Invoke(this, destinationEndPoint); } else { destinationEndPoint = new IPEndPoint(new IPAddress(ipBuffer), port); connection.RemoteSocket = Socks5Client.Connect( RemotEndPoint.Address.ToString(), RemotEndPoint.Port, destinationEndPoint.Address.ToString(), port, Username, Password, SendTimeout, ReceiveTimeout ); OnRemoteConnect?.Invoke(this, destinationEndPoint); } if (connection.RemoteSocket.Connected) { SendSocks4Reply(connection.LocalSocket, Protocol.Socks4.StatusRequestGranted, ipBuffer, portBuffer); // Create the thread for the receives. connection.RemoteThread = new Thread(ProcessRemoteConnection) { IsBackground = true }; connection.RemoteThread.Start(connection); } else { OnLogMessage?.Invoke(this, "RemoteSocket connection failed"); SendSocks4Reply(connection.LocalSocket, Protocol.Socks4.StatusRequestFailed, ipBuffer, portBuffer); connection.LocalSocket.Close(); } break; } case Protocol.Socks4.CommandBindingConnection: { var portBuffer = new[] { buffer[2], buffer[3] }; var ipBuffer = new[] { buffer[4], buffer[5], buffer[6], buffer[7] }; // TCP/IP port binding not supported SendSocks4Reply(connection.LocalSocket, Protocol.Socks4.StatusRequestFailed, ipBuffer, portBuffer); connection.LocalSocket.Close(); break; } default: OnLogMessage?.Invoke(this, "Unknown protocol on LocalSocket"); connection.LocalSocket.Close(); break; } // start receiving actual data if the socket still open while (true) { if (!connection.LocalSocket.Connected || !connection.RemoteSocket.Connected) { break; } bytesRead = connection.LocalSocket.Receive(buffer); if (bytesRead == 0) { break; } if (connection.RemoteSocket.Connected) { connection.RemoteSocket.Send(buffer, bytesRead, SocketFlags.None); OnLogMessage?.Invoke(this, $"Forwarded {bytesRead} bytes from LocalSocket to RemoteSocket"); } } } catch (SocketException ex) { OnLogMessage?.Invoke(this, $"Caught SocketException in ProcessLocalConnection with error code {ex.SocketErrorCode.ToString()}"); } catch (Socks5Exception ex) { var portBuffer = new[] { buffer[2], buffer[3] }; var ipBuffer = new[] { buffer[4], buffer[5], buffer[6], buffer[7] }; SendSocks4Reply(connection.LocalSocket, Protocol.Socks4.StatusRequestFailed, ipBuffer, portBuffer); connection.LocalSocket.Close(); OnLogMessage?.Invoke(this, $"Caught Socks5Exception in ProcessLocalConnection with message {ex.Message}"); } if (connection.LocalSocket.Connected) { OnLogMessage?.Invoke(this, "Closing LocalSocket"); connection.LocalSocket.Close(); } lock (_connections) { _connections.Remove(connection); } }