Socks4Connector
Establishes a tunnel via a SOCKS4 proxy server.
using Renci.SshNet.Abstractions;
using Renci.SshNet.Common;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Renci.SshNet.Connection
{
internal sealed class Socks4Connector : ProxyConnector
{
public Socks4Connector(ISocketFactory socketFactory)
: base(socketFactory)
{
}
protected override void HandleProxyConnect(IConnectionInfo connectionInfo, Socket socket)
{
byte[] data = CreateSocks4ConnectionRequest(connectionInfo.Host, (ushort)connectionInfo.Port, connectionInfo.ProxyUsername);
SocketAbstraction.Send(socket, data);
if (ConnectorBase.SocketReadByte(socket, connectionInfo.Timeout) != 0)
throw new ProxyException("SOCKS4: Null is expected.");
switch (ConnectorBase.SocketReadByte(socket, connectionInfo.Timeout)) {
case 91:
throw new ProxyException("SOCKS4: Connection rejected.");
case 92:
throw new ProxyException("SOCKS4: Client is not running identd or not reachable from the server.");
case 93:
throw new ProxyException("SOCKS4: Client's identd could not confirm the user ID string in the request.");
default:
throw new ProxyException("SOCKS4: Not valid response.");
case 90: {
byte[] array = new byte[6];
ConnectorBase.SocketRead(socket, array, 0, array.Length, connectionInfo.Timeout);
break;
}
}
}
private static byte[] CreateSocks4ConnectionRequest(string hostname, ushort port, string username)
{
byte[] socks4DestinationAddress = GetSocks4DestinationAddress(hostname);
byte[] proxyUserBytes = GetProxyUserBytes(username);
byte[] array = new byte[4 + socks4DestinationAddress.Length + proxyUserBytes.Length + 1];
int num = 0;
array[num++] = 4;
array[num++] = 1;
Pack.UInt16ToBigEndian(port, array, num);
num += 2;
Buffer.BlockCopy(socks4DestinationAddress, 0, array, num, socks4DestinationAddress.Length);
num += socks4DestinationAddress.Length;
Buffer.BlockCopy(proxyUserBytes, 0, array, num, proxyUserBytes.Length);
num += proxyUserBytes.Length;
array[num] = 0;
return array;
}
private static byte[] GetSocks4DestinationAddress(string hostname)
{
IPAddress[] hostAddresses = DnsAbstraction.GetHostAddresses(hostname);
foreach (IPAddress iPAddress in hostAddresses) {
if (iPAddress.AddressFamily == AddressFamily.InterNetwork)
return iPAddress.GetAddressBytes();
}
throw new ProxyException($"""{hostname}""");
}
private static byte[] GetProxyUserBytes(string proxyUser)
{
if (proxyUser == null)
return Array.Empty<byte>();
return Encoding.ASCII.GetBytes(proxyUser);
}
}
}