private SocksHttpWebResponse InternalGetResponse() { Uri requestUri = RequestUri; int redirects = 0; const int maxAutoredirectCount = 10; while (redirects++ < maxAutoredirectCount) { // Loop while redirecting var proxyUri = Proxy.GetProxy(requestUri); var ipAddress = GetProxyIpAddress(proxyUri); var response = new List <byte>(); using (var client = new TcpClient(ipAddress.ToString(), proxyUri.Port)) { int timeout = Timeout; if (timeout == 0) { timeout = 30 * 1000; } client.ReceiveTimeout = timeout; client.SendTimeout = timeout; var networkStream = client.GetStream(); // auth var buf = new byte[300]; buf[0] = 0x05; // Version buf[1] = 0x01; // NMETHODS buf[2] = 0x00; // No auth-method networkStream.Write(buf, 0, 3); networkStream.Read(buf, 0, 2); if (buf[0] != 0x05) { throw new IOException("Invalid Socks Version"); } if (buf[1] == 0xff) { throw new IOException("Socks Server does not support no-auth"); } if (buf[1] != 0x00) { throw new Exception("Socks Server did choose bogus auth"); } // connect var destIP = Dns.GetHostEntry(requestUri.DnsSafeHost).AddressList[0]; var index = 0; buf[index++] = 0x05; // version 5 . buf[index++] = 0x01; // command = connect. buf[index++] = 0x00; // Reserve = must be 0x00 buf[index++] = 0x01; // Address is full-qualified domain name. var rawBytes = destIP.GetAddressBytes(); rawBytes.CopyTo(buf, index); index += (ushort)rawBytes.Length; var portBytes = BitConverter.GetBytes(Uri.UriSchemeHttps == requestUri.Scheme ? 443 : 80); for (var i = portBytes.Length - 3; i >= 0; i--) { buf[index++] = portBytes[i]; } networkStream.Write(buf, 0, index); networkStream.Read(buf, 0, 4); if (buf[0] != 0x05) { throw new IOException("Invalid Socks Version"); } if (buf[1] != 0x00) { throw new IOException($"Socks Error {buf[1]:X}"); } var rdest = string.Empty; switch (buf[3]) { case 0x01: // IPv4 networkStream.Read(buf, 0, 4); var v4 = BitConverter.ToUInt32(buf, 0); rdest = new IPAddress(v4).ToString(); break; case 0x03: // Domain name networkStream.Read(buf, 0, 1); if (buf[0] == 0xff) { throw new IOException("Invalid Domain Name"); } networkStream.Read(buf, 1, buf[0]); rdest = Encoding.ASCII.GetString(buf, 1, buf[0]); break; case 0x04: // IPv6 var octets = new byte[16]; networkStream.Read(octets, 0, 16); rdest = new IPAddress(octets).ToString(); break; default: throw new IOException("Invalid Address type"); } networkStream.Read(buf, 0, 2); var rport = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(buf, 0)); Stream readStream = null; if (Uri.UriSchemeHttps == requestUri.Scheme) { var ssl = new SslStream(networkStream); ssl.AuthenticateAsClient(requestUri.DnsSafeHost); readStream = ssl; } else { readStream = networkStream; } string requestString = BuildHttpRequestMessage(requestUri); var request = Encoding.ASCII.GetBytes(requestString); readStream.Write(request, 0, request.Length); readStream.Flush(); var buffer = new byte[client.ReceiveBufferSize]; var readlen = 0; do { readlen = readStream.Read(buffer, 0, buffer.Length); response.AddRange(buffer.Take(readlen)); } while (readlen != 0); readStream.Close(); } var webResponse = new SocksHttpWebResponse(requestUri, response.ToArray()); if (webResponse.StatusCode == HttpStatusCode.Moved || webResponse.StatusCode == HttpStatusCode.MovedPermanently) { string redirectUrl = webResponse.Headers["Location"]; if (string.IsNullOrEmpty(redirectUrl)) { throw new WebException("Missing location for redirect"); } requestUri = new Uri(requestUri, redirectUrl); if (AllowAutoRedirect) { continue; } return(webResponse); } if ((int)webResponse.StatusCode < 200 || (int)webResponse.StatusCode > 299) { throw new WebException(webResponse.StatusDescription, null, WebExceptionStatus.UnknownError, webResponse); } return(webResponse); } throw new WebException("Too many redirects", null, WebExceptionStatus.ProtocolError, SocksHttpWebResponse.CreateErrorResponse(HttpStatusCode.BadRequest)); }