Example #1
0
        /// <summary>
        /// When Tor receives a "RESOLVE" SOCKS command, it initiates
        /// a remote lookup of the hostname provided as the target address in the SOCKS
        /// request.
        /// </summary>
        internal async Task <IPAddress> ResolveAsync(string host)
        {
            // https://gitweb.torproject.org/torspec.git/tree/socks-extensions.txt#n44

            host = Guard.NotNullOrEmptyOrWhitespace(nameof(host), host, true);

            if (TorSocks5EndPoint is null)
            {
                var hostAddresses = await Dns.GetHostAddressesAsync(host);

                return(hostAddresses.First());
            }

            var cmd = CmdField.Resolve;

            var dstAddr = new AddrField(host);

            var dstPort = new PortField(0);

            var resolveRequest = new TorSocks5Request(cmd, dstAddr, dstPort);
            var sendBuffer     = resolveRequest.ToBytes();

            var receiveBuffer = await SendAsync(sendBuffer);

            var resolveResponse = new TorSocks5Response();

            resolveResponse.FromBytes(receiveBuffer);

            if (resolveResponse.Rep != RepField.Succeeded)
            {
                throw new TorSocks5FailureResponseException(resolveResponse.Rep);
            }
            return(IPAddress.Parse(resolveResponse.BndAddr.DomainOrIPv4));
        }
Example #2
0
 public TorSocks5Request(CmdField cmd, AddrField dstAddr, PortField dstPort)
 {
     Cmd     = Guard.NotNull(nameof(cmd), cmd);
     DstAddr = Guard.NotNull(nameof(dstAddr), dstAddr);
     DstPort = Guard.NotNull(nameof(dstPort), dstPort);
     Ver     = VerField.Socks5;
     Rsv     = RsvField.X00;
     Atyp    = dstAddr.Atyp;
 }
Example #3
0
 public TorSocks5Response(RepField rep, AddrField bndAddr, PortField bndPort)
 {
     Rep     = Guard.NotNull(nameof(rep), rep);
     BndAddr = Guard.NotNull(nameof(bndAddr), bndAddr);
     BndPort = Guard.NotNull(nameof(bndPort), bndPort);
     Ver     = VerField.Socks5;
     Rsv     = RsvField.X00;
     Atyp    = bndAddr.Atyp;
 }
        public override void FromBytes(byte[] bytes)
        {
            Guard.NotNullOrEmpty(nameof(bytes), bytes);
            Guard.MinimumAndNotNull($"{nameof(bytes)}.{nameof(bytes.Length)}", bytes.Length, 6);

            Ver = new VerField(bytes[0]);

            Rep = new RepField();
            Rep.FromByte(bytes[1]);

            Rsv = new RsvField();
            Rsv.FromByte(bytes[2]);

            Atyp = new AtypField(bytes[3]);

            BndAddr = new AddrField();
            BndAddr.FromBytes(bytes[4..^ 2]);
Example #5
0
        public override void FromBytes(byte[] bytes)
        {
            Guard.NotNullOrEmpty(nameof(bytes), bytes);
            Guard.MinimumAndNotNull($"{nameof(bytes)}.{nameof(bytes.Length)}", bytes.Length, 6);

            Ver = new VerField();
            Ver.FromByte(bytes[0]);

            Cmd = new CmdField();
            Cmd.FromByte(bytes[1]);

            Rsv = new RsvField();
            Rsv.FromByte(bytes[2]);

            Atyp = new AtypField();
            Atyp.FromByte(bytes[3]);

            DstAddr = new AddrField();
            DstAddr.FromBytes(bytes.Skip(4).Take(bytes.Length - 4 - 2).ToArray());

            DstPort = new PortField();
            DstPort.FromBytes(bytes.Skip(bytes.Length - 2).ToArray());
        }
Example #6
0
        /// <summary>
        /// Tor attempts to find the canonical hostname for that IPv4 record
        /// </summary>
        internal async Task <string> ReverseResolveAsync(IPAddress iPv4)
        {
            // https://gitweb.torproject.org/torspec.git/tree/socks-extensions.txt#n55

            Guard.NotNull(nameof(iPv4), iPv4);

            if (TorSocks5EndPoint is null)             // Only Tor is iPv4 dependent
            {
                var host = await Dns.GetHostEntryAsync(iPv4);

                return(host.HostName);
            }

            Guard.Same($"{nameof(iPv4)}.{nameof(iPv4.AddressFamily)}", AddressFamily.InterNetwork, iPv4.AddressFamily);

            var cmd = CmdField.ResolvePtr;

            var dstAddr = new AddrField(iPv4.ToString());

            var dstPort = new PortField(0);

            var resolveRequest = new TorSocks5Request(cmd, dstAddr, dstPort);
            var sendBuffer     = resolveRequest.ToBytes();

            var receiveBuffer = await SendAsync(sendBuffer);

            var resolveResponse = new TorSocks5Response();

            resolveResponse.FromBytes(receiveBuffer);

            if (resolveResponse.Rep != RepField.Succeeded)
            {
                throw new TorSocks5FailureResponseException(resolveResponse.Rep);
            }
            return(resolveResponse.BndAddr.DomainOrIPv4);
        }
        /// <param name="host">IPv4 or domain</param>
        internal async Task ConnectToDestinationAsync(string host, int port, bool isRecursiveCall = false)
        {
            host = Guard.NotNullOrEmptyOrWhitespace(nameof(host), host, true);
            Guard.MinimumAndNotNull(nameof(port), port, 0);

            if (TorSocks5EndPoint is null)
            {
                using (await AsyncLock.LockAsync().ConfigureAwait(false))
                {
                    TcpClient?.Dispose();
                    TcpClient = IPAddress.TryParse(host, out IPAddress ip) ? new TcpClient(ip.AddressFamily) : new TcpClient();
                    await TcpClient.ConnectAsync(host, port).ConfigureAwait(false);

                    Stream         = TcpClient.GetStream();
                    RemoteEndPoint = TcpClient.Client.RemoteEndPoint;
                }

                return;
            }

            var cmd = CmdField.Connect;

            var dstAddr = new AddrField(host);

            DestinationHost = dstAddr.DomainOrIPv4;

            var dstPort = new PortField(port);

            DestinationPort = dstPort.DstPort;

            var connectionRequest = new TorSocks5Request(cmd, dstAddr, dstPort);
            var sendBuffer        = connectionRequest.ToBytes();

            var receiveBuffer = await SendAsync(sendBuffer, isRecursiveCall : isRecursiveCall).ConfigureAwait(false);

            var connectionResponse = new TorSocks5Response();

            connectionResponse.FromBytes(receiveBuffer);

            if (connectionResponse.Rep != RepField.Succeeded)
            {
                // https://www.ietf.org/rfc/rfc1928.txt
                // When a reply(REP value other than X'00') indicates a failure, the
                // SOCKS server MUST terminate the TCP connection shortly after sending
                // the reply.This must be no more than 10 seconds after detecting the
                // condition that caused a failure.
                DisposeTcpClient();
                throw new TorSocks5FailureResponseException(connectionResponse.Rep);
            }

            // Do not check the Bnd. Address and Bnd. Port. because Tor does not seem to return any, ever. It returns zeros instead.
            // Generally also do not check anything but the success response, according to Socks5 RFC

            // If the reply code(REP value of X'00') indicates a success, and the
            // request was either a BIND or a CONNECT, the client may now start
            // passing data. If the selected authentication method supports
            // encapsulation for the purposes of integrity, authentication and / or
            // confidentiality, the data are encapsulated using the method-dependent
            // encapsulation.Similarly, when data arrives at the SOCKS server for
            // the client, the server MUST encapsulate the data as appropriate for
            // the authentication method in use.
        }