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); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
/// <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; } } } } }