private Socks5ClientRequestReply AssocCore(IPAddress addr, int port)
        {
            Socks5ClientRequest request = new Socks5ClientRequest {
                Command            = Socks5Command.UDPMap,
                AddressType        = Socks5AddressType.IPv4,
                DestinationAddress = addr.ToString(),
                DestinationPort    = (ushort)port
            };

            _socks_control.Client.Send(request.GetBytes());

            byte[] connect_request_reply = new byte[Socks5Packet.MessageMaxLength]; // for everything
            _socks_control.Client.Receive(connect_request_reply);

            Socks5ClientRequestReply request_reply = new Socks5ClientRequestReply(connect_request_reply);

            if (request_reply.ResponseCode != Socks5ResponseCode.OK)
            {
                throw new Socks5Exception("SOCKS5 server reports: "
                                          + request_reply.ResponseCode);
            }

            this._established          = true;
            this._socks_endpoint       = new IPEndPoint(_socks_addr, request_reply.RemoteLocalPort);
            this.Client.ReceiveTimeout = 1000;
            return(request_reply);
        }
        protected Socks5ClientRequestReply RemoteConnectTo(String hostname, ushort port)
        {
            Socks5ClientRequest request = new Socks5ClientRequest {
                Command            = Socks5Command.TCPConnect,
                DestinationAddress = hostname,
                DestinationPort    = port,
                AddressType        = Socks5AddressType.Hostname
            };

            return(RemoteConnectCore(request));
        }
        protected void RemoteConnectTo(IPAddress addr, ushort port)
        {
            Socks5ClientRequest request = new Socks5ClientRequest {
                Command            = Socks5Command.TCPConnect,
                DestinationAddress = addr.ToString(),
                DestinationPort    = port
            };

            switch (addr.AddressFamily)
            {
            case AddressFamily.InterNetwork: request.AddressType = Socks5AddressType.IPv4; break;

            case AddressFamily.InterNetworkV6: request.AddressType = Socks5AddressType.IPv6; break;

            default: throw new Socks5Exception("Supported only IPv4 and IPv6");
            }
            RemoteConnectCore(request);
        }
        protected Socks5ClientRequestReply RemoteBindCore(Socks5ClientRequest request)
        {
            this.Client.Send(request.GetBytes());

            byte[] connect_request_reply = new byte[Socks5Packet.MessageMaxLength]; // for everything
            this.Client.Receive(connect_request_reply);

            Socks5ClientRequestReply request_reply = new Socks5ClientRequestReply(connect_request_reply);

            if (request_reply.ResponseCode != Socks5ResponseCode.OK)
            {
                throw new Socks5Exception("SOCKS5 server reports: "
                                          + request_reply.ResponseCode);
            }

            this._established = true;
            return(request_reply);
        }
        protected Socks5ClientRequestReply RemoteConnectCore(Socks5ClientRequest request)
        {
            this.Client.Send(request.GetBytes());

            byte[] connect_request_reply = new byte[Socks5Packet.MessageMaxLength]; // for everything
            this.Client.Receive(connect_request_reply);

            Socks5ClientRequestReply request_reply = new Socks5ClientRequestReply(connect_request_reply);

            if (request_reply.ResponseCode != Socks5ResponseCode.OK)
            {
                throw new Socks5Exception("SOCKS5 server reports: "
                                          + request_reply.ResponseCode);
            }
            //if(request_reply.AddressType != request.AddressType)
            //    throw new ApplicationException("SOCKS5 reply address type does not match");
            this._established = true;
            return(request_reply);
        }
        protected Socks5ClientRequestReply RemoteBind(Socks5AddressType addressType, ushort preferPort)
        {
            if (addressType != Socks5AddressType.IPv4 && addressType != Socks5AddressType.IPv6)
            {
                throw new Socks5Exception("You can request only IPv4/IPv6 binding, not hostname");
            }
            Socks5ClientRequest request = new Socks5ClientRequest {
                Command         = Socks5Command.TCPBind,
                AddressType     = addressType,
                DestinationPort = preferPort
            };

            if (addressType == Socks5AddressType.IPv4)
            {
                request.DestinationAddress = "0.0.0.0";
            }
            else if (addressType == Socks5AddressType.IPv6)
            {
                request.DestinationAddress = "::";
            }

            return(RemoteBindCore(request));
        }