private void socket_Receive(IAsyncResult ar) { try { int received = Handle.EndReceive(ar); if (received <= 0) { Disconnect(); return; } if (received > 5000 || _handshakeStream.Length + received > 5000) { //attack prevention of overflowing the HandshakeStream //It's really impossible for Socks or HTTPS proxies to use even 5000 for Initial Packets Disconnect(); return; } LengthReceived += received; _handshakeStream.Write(_buffer, 0, received); } catch { Disconnect(); return; } byte[] payload = _handshakeStream.ToArray(); switch (PacketsReceived) { case 0: { //initial Socks packet if (payload.Length >= 3) { string headerStr = Encoding.ASCII.GetString(payload); //check the proxy client if (payload[0] == SOCKS5_VERSION_NUMBER) { Type = ProxyType.Socks5; } else if (headerStr.StartsWith("CONNECT") && headerStr.Contains(":")) { Type = ProxyType.HTTPS; //Grab here the IP / PORT using (StreamReader sr = new StreamReader(new MemoryStream(payload))) { string line = sr.ReadLine(); if (line == null) { break; } //could have done it better with RegEx... oh well string[] split = line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); if (split.Length > 0) { try { string ipPort = split[1]; this.TargetServer = ipPort.Split(':')[0]; this.TargetPort = ushort.Parse(ipPort.Split(':')[1]); this._isConnectCommand = true; this._isDomainNameType = true; //Send Command to client and wait for response from CommandHandler new ReverseProxyConnect(ConnectionId, this.TargetServer, this.TargetPort).Execute(Client); Server.CallonConnectionEstablished(this); return; //Quit receiving and wait for client's response } catch { Disconnect(); } } } } else { break; } if (CheckProxyVersion(payload)) { SendSuccessToClient(); PacketsReceived++; _handshakeStream.SetLength(0); Server.CallonConnectionEstablished(this); } } break; } case 1: { //Socks command int MinPacketLen = 6; if (payload.Length >= MinPacketLen) { if (!CheckProxyVersion(payload)) { return; } this._isConnectCommand = payload[1] == 1; this._isBindCommand = payload[1] == 2; this._isUdpCommand = payload[1] == 3; this._isIpType = payload[3] == 1; this._isDomainNameType = payload[3] == 3; this._isIPv6NameType = payload[3] == 4; Array.Reverse(payload, payload.Length - 2, 2); this.TargetPort = BitConverter.ToUInt16(payload, payload.Length - 2); if (_isConnectCommand) { if (_isIpType) { this.TargetServer = payload[4] + "." + payload[5] + "." + payload[6] + "." + payload[7]; } else if (_isDomainNameType) { int domainLen = payload[4]; if (MinPacketLen + domainLen < payload.Length) { this.TargetServer = Encoding.ASCII.GetString(payload, 5, domainLen); } } if (this.TargetServer.Length > 0) { //Send Command to client and wait for response from CommandHandler new ReverseProxyConnect(ConnectionId, this.TargetServer, this.TargetPort).Execute(Client); } } else { SendFailToClient(); return; } Server.CallonUpdateConnection(this); //Quit receiving data and wait for Client's response return; } break; } } try { Handle.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, socket_Receive, null); } catch { Disconnect(); } }