コード例 #1
0
        async Task <Socket> ConnectAsync(string host, int port, bool doAsync, CancellationToken cancellationToken)
        {
            Socks5AddressType addrType;
            IPAddress         ip;

            ValidateArguments(host, port);

            addrType = GetAddressType(host, out ip);

            cancellationToken.ThrowIfCancellationRequested();

            var socket = await SocketUtils.ConnectAsync(ProxyHost, ProxyPort, null, doAsync, cancellationToken).ConfigureAwait(false);

            var method = ProxyCredentials != null ? Socks5AuthMethod.UserPassword : Socks5AuthMethod.Anonymous;

            byte[] domain     = null, addr = null;
            int    bufferSize = 6;

            switch (addrType)
            {
            case Socks5AddressType.Domain:
                domain      = Encoding.UTF8.GetBytes(host);
                bufferSize += 1 + domain.Length;
                break;

            case Socks5AddressType.IPv6:
                bufferSize += 16;
                break;

            case Socks5AddressType.IPv4:
                bufferSize += 4;
                break;
            }

            try {
                method = NegotiateAuthMethod(socket, cancellationToken, method);

                switch (method)
                {
                case Socks5AuthMethod.UserPassword:
                    Authenticate(socket, cancellationToken);
                    break;

                case Socks5AuthMethod.Anonymous:
                    break;

                default:
                    //throw new ProxyProtocolException ("Failed to negotiate authentication method with the proxy server.");
                    break;
                }

                // +----+-----+-------+------+----------+----------+
                // |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
                // +----+-----+-------+------+----------+----------+
                // | 1  |  1  | X'00' |  1   | Variable |    2     |
                // +----+-----+-------+------+----------+----------+
                var buffer = new byte[bufferSize];
                int nread, n = 0;

                buffer [n++] = (byte)SocksVersion;
                buffer[n++]  = (byte)Socks5Command.Connect;
                buffer[n++]  = 0x00;
                buffer[n++]  = (byte)addrType;
                switch (addrType)
                {
                case Socks5AddressType.Domain:
                    buffer[n++] = (byte)domain.Length;
                    Buffer.BlockCopy(domain, 0, buffer, n, domain.Length);
                    n += domain.Length;
                    break;

                case Socks5AddressType.IPv6:
                    addr = ip.GetAddressBytes();
                    Buffer.BlockCopy(addr, 0, buffer, n, addr.Length);
                    n += 16;
                    break;

                case Socks5AddressType.IPv4:
                    addr = ip.GetAddressBytes();
                    Buffer.BlockCopy(addr, 0, buffer, n, addr.Length);
                    n += 4;
                    break;
                }
                buffer[n++] = (byte)(port >> 8);
                buffer[n++] = (byte)port;

                SocketUtils.Poll(socket, SelectMode.SelectWrite, cancellationToken);
                socket.Send(buffer, 0, n, SocketFlags.None);

                // +-----+-----+-------+------+----------+----------+
                // | VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
                // +-----+-----+-------+------+----------+----------+
                // |  1  |  1  | X'00' |  1   | Variable |    2     |
                // +-----+-----+-------+------+----------+----------+

                // Note: We know we'll need at least 4 bytes of header + a minimum of 1 byte
                // to determine the length of the BND.ADDR field if ATYP is a domain.
                int need = 5;
                n = 0;

                do
                {
                    SocketUtils.Poll(socket, SelectMode.SelectRead, cancellationToken);
                    if ((nread = socket.Receive(buffer, 0 + n, need - n, SocketFlags.None)) > 0)
                    {
                        n += nread;
                    }
                } while (n < need);

                if (buffer[1] != (byte)Socks5Reply.Success)
                {
                    throw new ProxyProtocolException(string.Format("Failed to connect to {0}:{1}: {2}", host, port, GetFailureReason(buffer[1])));
                }

                addrType = (Socks5AddressType)buffer[3];

                switch (addrType)
                {
                case Socks5AddressType.Domain: need += buffer[4] + 2; break;

                case Socks5AddressType.IPv6: need += (16 - 1) + 2; break;

                case Socks5AddressType.IPv4: need += (4 - 1) + 2; break;

                default: throw new ProxyProtocolException("Proxy server returned unknown address type.");
                }

                do
                {
                    SocketUtils.Poll(socket, SelectMode.SelectRead, cancellationToken);
                    if ((nread = socket.Receive(buffer, 0 + n, need - n, SocketFlags.None)) > 0)
                    {
                        n += nread;
                    }
                } while (n < need);

                // TODO: do we care about BND.ADDR and BND.PORT?

                return(socket);
            } catch (OperationCanceledException) {
                socket.Disconnect(false);
                socket.Dispose();
                throw;
            } catch {
                socket.Dispose();
                throw;
            }
        }
コード例 #2
0
ファイル: Socks4Client.cs プロジェクト: pmacapal/MailKit
        async Task <Socket> ConnectAsync(string host, int port, bool doAsync, CancellationToken cancellationToken)
        {
            byte[]    addr, domain = null;
            IPAddress ip;

            ValidateArguments(host, port);

            if (!IPAddress.TryParse(host, out ip))
            {
                domain = Encoding.UTF8.GetBytes(host);
                addr   = InvalidIPAddress;
            }
            else
            {
                if (ip.AddressFamily != AddressFamily.InterNetwork)
                {
                    throw new ArgumentException(nameof(host));
                }

                addr = ip.GetAddressBytes();
            }

            cancellationToken.ThrowIfCancellationRequested();

            var socket = await SocketUtils.ConnectAsync(ProxyHost, ProxyPort, null, doAsync, cancellationToken).ConfigureAwait(false);

            var user = ProxyCredentials != null?Encoding.UTF8.GetBytes(ProxyCredentials.UserName) : new byte[0];

            try {
                // +----+-----+----------+----------+----------+-------+--------------+-------+
                // |VER | CMD | DST.PORT | DST.ADDR |  USERID  | NULL  |  DST.DOMAIN  | NULL  |
                // +----+-----+----------+----------+----------+-------+--------------+-------+
                // | 1  |  1  |    2     |    4     | VARIABLE | X'00' |   VARIABLE   | X'00' |
                // +----+-----+----------+----------+----------+-------+--------------+-------+
                int bufferSize = 9 + user.Length + (domain != null ? domain.Length + 1 : 0);
                var buffer = new byte[bufferSize];
                int nread, n = 0;

                buffer[n++] = (byte)SocksVersion;
                buffer[n++] = (byte)Socks4Command.Connect;
                buffer[n++] = (byte)(port >> 8);
                buffer[n++] = (byte)port;
                Buffer.BlockCopy(addr, 0, buffer, n, 4);
                n += 4;
                Buffer.BlockCopy(user, 0, buffer, n, user.Length);
                n          += user.Length;
                buffer[n++] = 0x00;
                if (domain != null)
                {
                    Buffer.BlockCopy(domain, 0, buffer, n, domain.Length);
                    n          += domain.Length;
                    buffer[n++] = 0x00;
                }

                SocketUtils.Poll(socket, SelectMode.SelectWrite, cancellationToken);
                socket.Send(buffer, 0, n, SocketFlags.None);

                // +-----+-----+----------+----------+
                // | VER | REP | BND.PORT | BND.ADDR |
                // +-----+-----+----------+----------+
                // |  1  |  1  |    2     |    4     |
                // +-----+-----+----------+----------+
                n = 0;

                do
                {
                    SocketUtils.Poll(socket, SelectMode.SelectRead, cancellationToken);
                    if ((nread = socket.Receive(buffer, 0 + n, 8 - n, SocketFlags.None)) > 0)
                    {
                        n += nread;
                    }
                } while (n < 8);

                if (buffer[1] != (byte)Socks4Reply.RequestGranted)
                {
                    throw new ProxyProtocolException(string.Format("Failed to connect to {0}:{1}: {2}", host, port, GetFailureReason(buffer[1])));
                }

                // TODO: do we care about BND.ADDR and BND.PORT?

                return(socket);
            } catch (OperationCanceledException) {
                socket.Disconnect(false);
                socket.Dispose();
                throw;
            } catch {
                socket.Dispose();
                throw;
            }
        }