/// <summary> /// Waits until the connected client sends a SOCKS5 request. /// </summary> /// <returns>The SOCKS5 request sent by the client.</returns> /// <exception cref="Socks5Exception">The data sent by the client /// is not a valid SOCKS5 request.</exception> SocksRequest WaitForRequest() { ByteBuilder b = new ByteBuilder(); using (var r = new BinaryReader(stream, Encoding.UTF8, true)) { byte[] bytes = r.ReadBytes(4); b.Append(bytes); ATyp atyp = (ATyp)bytes[3]; switch (atyp) { case ATyp.IPv4: case ATyp.IPv6: b.Append(r.ReadBytes(atyp == ATyp.IPv4 ? 4 : 16)); break; case ATyp.Domain: byte length = r.ReadByte(); b.Append(length).Append(r.ReadBytes(length)); break; } b.Append(r.ReadBytes(2)); } try { return(SocksRequest.Deserialize(b.ToArray())); } catch (Exception e) { throw new Socks5Exception("The request could not be serialized.", e); } }
/// <summary> /// Performs the specified SOCKS5 request. /// </summary> /// <param name="request">The SOCKS5 request to issue to the server.</param> /// <returns>The SOCKS5 reply sent by the server.</returns> /// <exception cref="ArgumentNullException">The request parameter is /// null.</exception> /// <exception cref="ObjectDisposedException">The object has been /// disposed.</exception> /// <exception cref="Socks5Exception">The request could not be performed. /// Consult the InnerException property of the Socks5Exception to learn /// the reason.</exception> public SocksReply Request(SocksRequest request) { request.ThrowIfNull("request"); AssertValid(); try { byte[] bytes = request.Serialize(); stream.Write(bytes, 0, bytes.Length); ByteBuilder b = new ByteBuilder(); using (var r = new BinaryReader(stream, Encoding.UTF8, true)) { bytes = r.ReadBytes(4); b.Append(bytes); ATyp atyp = (ATyp)bytes[3]; switch (atyp) { case ATyp.IPv4: case ATyp.IPv6: b.Append(r.ReadBytes(atyp == ATyp.IPv4 ? 4 : 16)); break; case ATyp.Domain: byte length = r.ReadByte(); b.Append(length).Append(r.ReadBytes(length)); break; } b.Append(r.ReadBytes(2)); } return(SocksReply.Deserialize(b.ToArray())); } catch (Exception e) { throw new Socks5Exception("The request could not be performed.", e); } }
/// <summary> /// Serializes the instance into an array of bytes. /// </summary> /// <returns>An array of bytes representing the instance of the /// ClientGreeting class.</returns> public byte[] Serialize() { ByteBuilder b = new ByteBuilder() .Append(version) .Append((byte)methods.Count); foreach (AuthMethod m in Methods) { b.Append((byte)m); } return(b.ToArray()); }
/// <summary> /// Performs the initial greeting. /// </summary> /// <exception cref="Socks5Exception">The client sent invalid data, or /// requires authentication.</exception> /// <exception cref="IOException">The stream could not be read, or the /// operation timed out.</exception> void PerformGreeting() { ByteBuilder b = new ByteBuilder(); using (var r = new BinaryReader(stream, Encoding.UTF8, true)) { byte[] bytes = r.ReadBytes(2); b.Append(bytes); // The number of method-bytes following is contained in the second byte. b.Append(r.ReadBytes(bytes[1])); } ClientGreeting greeting = ClientGreeting.Deserialize(b.ToArray()); // We only accept an authentication method of 'none'. if (!greeting.Methods.Contains(AuthMethod.None)) { Dispose(); throw new Socks5Exception("Client requires authentication."); } // Send back our greeting response. var response = new ServerGreeting(AuthMethod.None).Serialize(); stream.Write(response, 0, response.Length); }