I have recently set up a website which uses geographic DNS to resolve the DNS to two different IP's depending on your location.
However, this means to monitor the websites, I need to make sure the site is available in both geographical locations. To do this I wrote a small program in .net to continually try and HttpWebRequest to get a small html file on the website once using the local internet settings and once using a proxy based in the region which will resolve the name to the second IP address.
This works fine on my laptop at home, however in the office, to connect to the internet on almost all machines you will need to go via a proxy, which means the proxy I set earlier no longer works.
What I need to be able to do is send the request through the office proxy, then through the proxy in the remote country and finally to the website.
Let me know if this is not clear enough!
First you need to ensure that both proxies are HTTPS and they both support CONNECT method, i.e. "proxy chaining". Design of usual HTTP protocol doesn't provide support for "proxy chaining".
The idea is to establish 2 CONNECT tunnels, one inside another.
The algorithm is the following:
- Connect to the 1st proxy via TCP
- Request CONNECT tunnel to 2nd proxy
- Once tunnel is created, request tunnel to target host
Send request. Request will go to target host through proxy #1 and proxy #2.
Below is a sample code which I have tested on my box:
string host = "encrypted.google.com";
string proxy2 = "213.240.237.149";//host;
int proxyPort2 = 3128;//443;
string proxy = "180.183.236.63";//host;
int proxyPort = 3128;//443;
byte[] buffer = new byte[2048];
int bytes;
// Connect to the 1st proxy
TcpClient client = new TcpClient(proxy, proxyPort);
NetworkStream stream = client.GetStream();
// Establish tunnel to 2nd proxy
byte[] tunnelRequest = Encoding.UTF8.GetBytes(String.Format("CONNECT {0}:{1} HTTP/1.1\r\nHost:{0}\r\n\r\n", proxy2, proxyPort2));
stream.Write(tunnelRequest, 0, tunnelRequest.Length);
stream.Flush();
// Read response to CONNECT request
// There should be loop that reads multiple packets
bytes = stream.Read(buffer, 0, buffer.Length);
Console.Write(Encoding.UTF8.GetString(buffer, 0, bytes));
// Establish tunnel to target host
tunnelRequest = Encoding.UTF8.GetBytes(String.Format("CONNECT {0}:443 HTTP/1.1\r\nHost:{0}\r\n\r\n", host));
stream.Write(tunnelRequest, 0, tunnelRequest.Length);
stream.Flush();
// Read response to CONNECT request
// There should be loop that reads multiple packets
bytes = stream.Read(buffer, 0, buffer.Length);
Console.Write(Encoding.UTF8.GetString(buffer, 0, bytes));
// Wrap into SSL stream
SslStream sslStream2 = new SslStream(stream);
sslStream2.AuthenticateAsClient(host);
// Send request
byte[] request = Encoding.UTF8.GetBytes(String.Format("GET https://{0}/ HTTP/1.1\r\nHost: {0}\r\n\r\n", host));
sslStream2.Write(request, 0, request.Length);
sslStream2.Flush();
// Read response
do
{
bytes = sslStream2.Read(buffer, 0, buffer.Length);
Console.Write(Encoding.UTF8.GetString(buffer, 0, bytes));
} while (bytes != 0);
client.Close();
Console.ReadKey();