예제 #1
0
 public Plugin.ISocksMessage Create <T>(BinaryReader reader) where T : Plugin.ISocksMessage
 {
     Plugin.ISocksMessage message = (Plugin.ISocksMessage)Activator.CreateInstance(typeof(T));
     if (message.Parse(reader))
     {
         return(message);
     }
     return(null);
 }
예제 #2
0
        /// <summary>
        /// IStateDependentHandler.Awaiting implementation for AuthenticationState.Awaiting
        /// </summary>
        /// <returns>True if connection left open, false if not</returns>
        async Task <bool> Plugin.IStateDependentHandler.Awaiting(Client client, Plugin.ISocksMessage message)
        {
            Awaiting typedMessage = message as Awaiting;

            if (typedMessage.SocksVersion == Socks.Constants.Socks.Version)
            {
                // TODO: Make other authentication methods available. Not?
                if (typedMessage.AvailableMethods.Contains(Socks.Constants.AuthenticationMethod.UsernamePassword))
                {
                    client.Data.AuthenticationMethod = Socks.Constants.AuthenticationMethod.UsernamePassword;
                    client.Data.AuthenticationState  = Socks.Constants.AuthenticationState.Authenticating;
                    await client.Send(new byte[] { Socks.Constants.Socks.Version, (byte)client.Data.AuthenticationMethod });

                    return(true);
                }
                else
                {
                    await client.Send(new byte[] { Socks.Constants.Socks.Version, (byte)Socks.Constants.AuthenticationMethod.NoAcceptableMethod });
                }
            }
            return(false);
        }
예제 #3
0
        /// <summary>
        /// Create a message by a clients authentication state and authentication method
        /// </summary>
        /// <param name="data">Input data received from client</param>
        /// <param name="authenticationState">Clients current authentication state</param>
        /// <param name="authenticationMethod">If authentication state is Authenticating, a authenticationMethod is required to return a message according to sub negotation</param>
        /// <returns>A socks message, or null if Parsing failed</returns>
        private Plugin.ISocksMessage GetMessage(byte[] data, Socks.Constants.AuthenticationState authenticationState, Socks.Constants.AuthenticationMethod authenticationMethod)
        {
            Plugin.ISocksMessage message = null;

            using (MemoryStream stream = new MemoryStream(data))
                using (BinaryReader reader = new BinaryReader(stream))
                {
                    if (authenticationState == Socks.Constants.AuthenticationState.Awaiting)
                    {
                        message = this.SocksMessageFactory.Create <Socks.Message.Awaiting>(reader);
                    }
                    else if (authenticationState == Socks.Constants.AuthenticationState.Authenticating &&
                             authenticationMethod == Socks.Constants.AuthenticationMethod.UsernamePassword)
                    {
                        message = this.SocksMessageFactory.Create <Socks.Message.Authentication.UsernamePassword>(reader);
                    }
                    else if (authenticationState == Socks.Constants.AuthenticationState.Authenticated)
                    {
                        message = this.SocksMessageFactory.Create <Socks.Message.Command>(reader);
                    }
                }

            return(message);
        }
예제 #4
0
        /// <summary>
        /// IStateDependentHandler.Authenticating implementation for AuthenticationState.Authenticating
        /// </summary>
        /// <returns>True if connection left open, false if not</returns>
        async Task <bool> Plugin.IStateDependentHandler.Authenticating(Client client, Plugin.ISocksMessage message)
        {
            if (client.Data.AuthenticationMethod == Socks.Constants.AuthenticationMethod.UsernamePassword)
            {
                Socks5S.Socks.Message.Authentication.UsernamePassword typedMessage = message as Socks5S.Socks.Message.Authentication.UsernamePassword;
                if (typedMessage.Version == 1)
                {
                    if (await client.Data.Authenticate(typedMessage.Username, typedMessage.Password))
                    {
                        // 0x00 means success, everything else is failure
                        Program.GetInstance().Log.DebugFormat("Authentication (Method: {0}) successful for {1}: {2}", client.Data.AuthenticationMethod, client.RemoteEndPoint, typedMessage.Username);
                        client.Data.AuthenticationState = Socks.Constants.AuthenticationState.Authenticated;
                        await client.Send(new byte[] { typedMessage.Version, 0x00 });

                        return(true);
                    }
                }
                else
                {
                    Program.GetInstance().Log.DebugFormat("Authentication (Method: {0}) failed for {1}: {2}, invalid version {3}", client.Data.AuthenticationMethod, client.RemoteEndPoint, typedMessage.Username, typedMessage.Version);
                }
            }
            else
            {
                throw new NotImplementedException("AuthenticationMethod " + client.Data.AuthenticationMethod.ToString() + " not implemented yet");
            }

            Program.GetInstance().Log.DebugFormat("Authentication (Method: {0}) failed for {1}", client.Data.AuthenticationMethod, client.RemoteEndPoint);
            await client.Send(new byte[] { Socks.Constants.Socks.Version, 0xFF });

            return(false);
        }
예제 #5
0
        /// <summary>
        /// IStateDependentHandler.Command implementation for AuthenticationState.Authenticated
        /// </summary>
        /// <returns>True if connection left open, false if not</returns>
        async Task <bool> Plugin.IStateDependentHandler.Command(Client client, Plugin.ISocksMessage message)
        {
            bool returnData = false;

            Socks5S.Socks.Message.Command typedMessage = message as Socks5S.Socks.Message.Command;

            if (typedMessage.SocksCommand != Socks.Constants.Command.Connect)
            {
                Program.GetInstance().Log.InfoFormat("COMMAND: {0}", typedMessage.SocksCommand);
            }

            if (typedMessage.SocksVersion == Socks.Constants.Socks.Version)
            {
                using (MemoryStream responseStream = new MemoryStream())
                    using (BinaryWriter responseWriter = new BinaryWriter(responseStream))
                    {
                        if (typedMessage.AddressType == Socks.Constants.AddressType.Domain && !typedMessage.DnsSuccess)
                        {
                            // domain resolve error
                            responseWriter.Write(Socks.Constants.Socks.Version);
                            responseWriter.Write((byte)Socks.Constants.Reply.HostUnreachable);
                            responseWriter.Write((byte)0);
                            responseWriter.Write((byte)Socks.Constants.AddressType.Domain);
                            responseWriter.Write((byte)typedMessage.Domain.Length);
                            responseWriter.Write(Encoding.UTF8.GetBytes(typedMessage.Domain));
                            responseWriter.Write((short)IPAddress.HostToNetworkOrder(typedMessage.DestinationPort));
                            responseWriter.Flush();

                            byte[] responseHostUnreachableData = responseStream.GetBuffer();
                            Array.Resize(ref responseHostUnreachableData, (int)responseStream.Length);

                            await client.Send(responseHostUnreachableData);
                        }
                        else
                        {
                            if (typedMessage.DestinationAddress == IPAddress.Loopback ||
                                typedMessage.DestinationAddress == IPAddress.IPv6Loopback)
                            {
                                // not allowed to access local network
                                responseWriter.Write(Socks.Constants.Socks.Version);
                                responseWriter.Write((byte)Socks.Constants.Reply.ConnectionNotAllowedByRuleset);
                                responseWriter.Write((byte)0);
                                responseWriter.Write((byte)(typedMessage.AddressType == Socks.Constants.AddressType.Domain ? Socks.Constants.AddressType.IPv4 : typedMessage.AddressType));
                                responseWriter.Write(typedMessage.DestinationAddress.GetAddressBytes());
                                responseWriter.Write((short)IPAddress.HostToNetworkOrder(typedMessage.DestinationPort));
                                responseWriter.Flush();

                                byte[] responseHostUnreachableData = responseStream.GetBuffer();
                                Array.Resize(ref responseHostUnreachableData, (int)responseStream.Length);

                                await client.Send(responseHostUnreachableData);
                            }



                            IPEndPoint remoteEndPoint = new IPEndPoint(typedMessage.DestinationAddress, typedMessage.DestinationPort);
                            if (this._associations[client.Id] == null)
                            {
                                Association.Carrier carrier = null;

                                bool isImplemented = true;
                                try
                                {
                                    if (typedMessage.SocksCommand == Socks.Constants.Command.Connect)
                                    {
                                        carrier = new Association.Carrier(Socks.Constants.Command.Connect, remoteEndPoint, ProtocolType.Tcp, this._bufferManager[client.Id].Data);
                                    }
                                    else if (typedMessage.SocksCommand == Socks.Constants.Command.UdpAssociate)
                                    {
                                        carrier = new Association.Carrier(Socks.Constants.Command.UdpAssociate, remoteEndPoint, ProtocolType.Udp, this._bufferManager[client.Id].Data);
                                    }
                                }
                                catch (NotImplementedException)
                                { isImplemented = false; }

                                if (!isImplemented)
                                {
                                    responseWriter.Write(Socks.Constants.Socks.Version);
                                    responseWriter.Write((byte)Socks.Constants.Reply.CommandNotSupported);
                                    responseWriter.Write((byte)0);
                                    responseWriter.Write((byte)(typedMessage.AddressType == Socks.Constants.AddressType.Domain ? Socks.Constants.AddressType.IPv4 : typedMessage.AddressType));
                                    responseWriter.Write(typedMessage.DestinationAddress.GetAddressBytes());
                                    responseWriter.Write((short)IPAddress.HostToNetworkOrder(typedMessage.DestinationPort));
                                    responseWriter.Flush();

                                    byte[] errorResponse = responseStream.GetBuffer();
                                    Array.Resize(ref errorResponse, (int)responseStream.Length);

                                    await client.Send(errorResponse);
                                }

                                // terminate the function on catch, can't return asynchronous on catch
                                if (carrier == null)
                                {
                                    return(false);
                                }

                                bool connectSuccess = false;
                                carrier.Data.Client.OnClientDisconnected += (s, e) =>
                                {
                                    if (connectSuccess)
                                    {
                                        Program.GetInstance().Log.DebugFormat("Proxy connection {0} quit connection to {1}", remoteEndPoint, client.RemoteEndPoint);
                                    }
                                    client.Disconnect();
                                };
                                carrier.Data.Client.OnClientConnected += (s, e) =>
                                {
                                    connectSuccess = true;
                                    Program.GetInstance().Log.DebugFormat("Client {0} opened connection on {1} successfully", client.RemoteEndPoint, remoteEndPoint);
                                };
                                carrier.Data.Client.OnClientDataReceived += async(s, e) =>
                                {
                                    carrier.WiredRx += e.Data.Length;
                                    //Program.GetInstance().Log.DebugFormat("Recv: {0}", BitConverter.ToString(e.Data));
                                    await client.Send(e.Data);
                                };
                                this._associations[client.Id] = carrier;

                                await Task.Run(() => { carrier.Data.Client.Connect(); });

                                if (!connectSuccess)
                                {
                                    Program.GetInstance().Log.DebugFormat("Client {0} connection to {1} failed", client.RemoteEndPoint, remoteEndPoint);
                                }
                                carrier.CommandSuccess = connectSuccess;

                                responseWriter.Write(Socks.Constants.Socks.Version);
                                responseWriter.Write(connectSuccess ? (byte)Socks.Constants.Reply.Succeeded : (byte)Socks.Constants.Reply.ConnectionRefused);
                                responseWriter.Write((byte)0);

                                if (typedMessage.DestinationAddress.AddressFamily == AddressFamily.InterNetwork)
                                {
                                    responseWriter.Write((byte)Socks.Constants.AddressType.IPv4);
                                }
                                else if (typedMessage.DestinationAddress.AddressFamily == AddressFamily.InterNetworkV6)
                                {
                                    responseWriter.Write((byte)Socks.Constants.AddressType.IPv6);
                                }

                                responseWriter.Write(typedMessage.DestinationAddress.GetAddressBytes());
                                responseWriter.Write((short)IPAddress.HostToNetworkOrder(typedMessage.DestinationPort));
                                responseWriter.Flush();

                                byte[] responseCommand = responseStream.GetBuffer();
                                Array.Resize(ref responseCommand, (int)responseStream.Length);

                                client.Data.AuthenticationState = Socks.Constants.AuthenticationState.Transmitting;
                                await client.Send(responseCommand);

                                returnData = connectSuccess;
                            }
                            else
                            {
                                throw new Exception("Proxy data already associated for client id " + client.Id.ToString() + ", " + client.RemoteEndPoint.ToString());
                            }
                        }

                        /*
                         * // Command not supported response
                         * {
                         *  responseWriter.Write(Socks.Constants.Socks.Version);
                         *  responseWriter.Write((byte)Socks.Constants.Reply.CommandNotSupported);
                         *  responseWriter.Write((byte)0);
                         *  responseWriter.Write((byte)(typedMessage.AddressType == Socks.Constants.AddressType.Domain ? Socks.Constants.AddressType.IPv4 : typedMessage.AddressType));
                         *  responseWriter.Write(typedMessage.DestinationAddress.GetAddressBytes());
                         *  responseWriter.Write((short)IPAddress.HostToNetworkOrder(typedMessage.DestinationPort));
                         *  responseWriter.Flush();
                         *
                         *  byte[] responseData = responseStream.GetBuffer();
                         *  Array.Resize(ref responseData, (int)responseStream.Length);
                         *
                         *  client.Send(responseData);
                         * }
                         */
                    }
            }
            return(returnData);
        }
예제 #6
0
        /// <summary>
        /// EventHandler for AsyncTCPLib.Server.OnClientDataReceived
        /// </summary>
        private async void OnClientDataReceived(object sender, OnClientDataReceivedEventArgs <Socks.Client> e)
        {
            var localEvent = new OnClientDataReceivedEventArgs <VirtualClient>(e.Client, e.Data, e.RemoteEndPoint);


            Socks.Constants.AuthenticationState currentState = e.Client.Data.AuthenticationState;
            Plugin.ISocksMessage message = this.GetMessage(e.Data, currentState, e.Client.Data.AuthenticationMethod);

            if (currentState != Socks.Constants.AuthenticationState.Transmitting && message == null)
            {
                this.Log.Debug("Received invalid data from ");
                e.Client.Disconnect();
                return;
            }

            // go through each plugin to process data
            foreach (Plugin.IPlugin plugin in this.Plugins)
            {
                if (plugin.HasRawHandler())
                {
                    plugin.RawHandler.OnClientDataReceived(localEvent);
                }
                if (plugin.HasStateDependentHandler())
                {
                    // AuthenticationState.Awaiting
                    if (currentState == Socks.Constants.AuthenticationState.Awaiting)
                    {
                        if (!await plugin.StateDependentHandler.Awaiting(e.Client, message))
                        {
                            e.Client.Disconnect();
                            return;
                        }
                    }
                    // AuthenticationState.Authenticating, awaiting sub negotiation
                    else if (currentState == Socks.Constants.AuthenticationState.Authenticating)
                    {
                        if (!await plugin.StateDependentHandler.Authenticating(e.Client, message))
                        {
                            e.Client.Disconnect();
                            return;
                        }
                    }
                    // AuthenticationState.Authenticated
                    else if (currentState == Socks.Constants.AuthenticationState.Authenticated)
                    {
                        if (!await plugin.StateDependentHandler.Command(e.Client, message))
                        {
                            e.Client.Disconnect();
                            return;
                        }
                    }
                    else if (currentState == Socks.Constants.AuthenticationState.Transmitting)
                    {
                        if (!await plugin.StateDependentHandler.Transmission(e.Client, e.Data))
                        {
                            e.Client.Disconnect();
                            return;
                        }
                    }
                }
            }
        }