private static async Task PerformAuth(Socket socket, Socks5Options options) { /* +-----+------+----------+------+----------+ | VER | ULEN | UNAME | PLEN | PASSWD | +----+-------+----------+------+----------+ | 1 | 1 | 1 to 255 | 1 | 1 to 255 | +----+-------+----------+------+----------+ */ var buffer = ConstructAuthBuffer(options.Credentials.Username, options.Credentials.Password); await socket.SendAsync(buffer, SocketFlags.None); /* +----+--------+ |VER | STATUS | +----+--------+ | 1 | 1 | +----+--------+ */ var response = new byte[2]; var read = await socket.ReceiveAsync(response, SocketFlags.None); if (read != 2) { throw new SocksocketException($"Failed to perform authentication, the server sent {read} bytes."); } if (response[1] != 0) { socket.Close(); throw new SocksocketException("Proxy authentication failed."); } }
private static async Task SelectAuth(Socket socket, Socks5Options options) { /* +----+----------+----------+ | VER | NMETHODS | METHODS | +----+----------+----------+ | 1 | 1 | 1 to 255 | +----+----------+----------+ */ var buffer = new byte[4] { 5, 2, Socks5Constants.AuthMethodNoAuthenticationRequired, Socks5Constants.AuthMethodUsernamePassword }; await socket.SendAsync(buffer, SocketFlags.None); /* +-----+--------+ | VER | METHOD | +-----+--------+ | 1 | 1 | +-----+--------+ */ var response = new byte[2]; var read = await socket.ReceiveAsync(response, SocketFlags.None); if (read != 2) { throw new SocksocketException($"Failed to select an authentication method, the server sent {read} bytes."); } if (response[1] == Socks5Constants.AuthMethodReplyNoAcceptableMethods) { socket.Close(); throw new SocksocketException("The proxy destination does not accept the supported proxy client authentication methods."); } if (response[1] == Socks5Constants.AuthMethodUsernamePassword && options.Auth == AuthType.None) { socket.Close(); throw new SocksocketException("The proxy destination requires a username and password for authentication."); } if (response[1] == Socks5Constants.AuthMethodNoAuthenticationRequired) { return; } await PerformAuth(socket, options); }
public static async Task <Socket> Connect(Func <Socket> socketFactory, Socks5Options options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } var socket = socketFactory(); await socket.ConnectAsync(options.ProxyHost, options.ProxyPort); await SelectAuth(socket, options); await Connect(socket, options); return(socket); }
private static async Task Connect(Socket socket, Socks5Options options) { /* +-----+-----+-------+------+----------+----------+ | VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | +--- -+-----+-------+------+----------+----------+ | 1 | 1 | X'00' | 1 | Variable | 2 | +-----+-----+-------+------+----------+----------+ */ var addressType = GetDestAddressType(options.DestinationHost); var destAddr = GetDestAddressBytes(addressType, options.DestinationHost); var destPort = GetDestPortBytes(options.DestinationPort); var buffer = new byte[6 + options.DestinationHost.Length]; buffer[0] = 5; buffer[1] = Socks5Constants.CmdConnect; buffer[2] = Socks5Constants.Reserved; buffer[3] = addressType; destAddr.CopyTo(buffer, 4); destPort.CopyTo(buffer, 4 + destAddr.Length); await socket.SendAsync(buffer, SocketFlags.None); /* +---- +-----+-------+------+----------+----------+ | VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | +-----+-----+-------+------+----------+----------+ | 1 | 1 | X'00' | 1 | Variable | 2 | +-----+-----+-------+------+----------+----------+ */ var response = new byte[255]; await socket.ReceiveAsync(response, SocketFlags.None); if (response[1] != Socks5Constants.CmdReplySucceeded) { HandleProxyCommandError(response, options.DestinationHost, options.DestinationPort); } }