现在的位置: 首页 > 综合 > 正文

使用Https隧道穿越Http代理服务器

2014年01月02日 ⁄ 综合 ⁄ 共 3588字 ⁄ 字号 评论关闭

原文:http://www.codeguru.com/cpp/i-n/internet/http/article.php/c6209/

 

Http隧道:

当你处在一个LAN中,并且只有一个http代理服务器与外界通信时,那么你就只能使用http协议来发送和接收你所需要的消息,也就是说在这个环境下你将不能使用你自己的协议与外界进行网络通信,自己的网络程序(如果不是基于http的话)也将不能通过这个http代理。那么这时候如果你希望使用这个代理服务器来收发自己的协议数据(比如基于tcp或udp),可以选择使用https。

 

Https:

Https是一个基于二进制的安全http协议,当使用https通过http代理服务时,http代理会认为这是一个安全https链接,将会放行https封包,所以我们可以使用https来欺骗http代理服务器,而我们自行构建的https封包中则可以封装我们自定义协议的真实数据(因为https是二进制的)。这一切让http代理看起来就像是我们在进行安全http连接一样。

 

以下是当浏览器使用Https连接代理服务器时发送的请求:

 

CONNECT neurospeech.com:443 HTTP/1.0 <CR><LF>
HOST neurospeech.com:443<CR><LF>
[... other HTTP header lines ending with <CR><LF> if required]>
<CR><LF>    // Last Empty Line

 

当代理服务器收到以上指令后就认为这是一个安全的http连接(https),然后为请求中指定的服务端地址打开一个二进制流式连接,如果成功,则返回以下响应:

 

HTTP/1.0 200 Connection Established<CR><LF>
[.... other HTTP header lines ending with <CR><LF>..
ignore all of them]
<CR><LF>    // Last Empty Line

 

现在,浏览器与远端主机(非代理服务器)的连接就建立起来了,并可以通过这个链接进行二进制数据的收发。

 

那么,当我们自己的程序要使用https来传送自己的协议数据时应该怎么办呢?

 

1.首先需要连接到代理服务器
2.发送 CONNECT Host:Port HTTP/1.1<CR><LF>.
3.发送 <CR><LF>.
4.等待一行字符串响应. 如果包含 HTTP/1.X 200 那么就说明链接成功建立了。
5.读取收到的响应字符串直到收到一个空行为止
6.现在,你已经通过一个http代理连接到外面的世界了,ok,开始你自己真正的数据传送吧。、

 

以下是示例代码:

 

 // You need to connect to mail.yahoo.com on port 25
  // Through a proxy on 192.0.1.1, on HTTP Proxy 4480
  // CSocketClient is Socket wrapping class
  // When you apply operator << on CString, it writes CString
  // To Socket ending with CRLF
  // When you apply operator >> on CString, it receives
  // a Line of response from socket until CRLF

  try
  {
    CString Request,Response;
    CSocketClient Client;

    Client.ConnectTo("192.0.1.1",4480);

    // Issue CONNECT Command
    Request = "CONNECT mail.yahoo.com:25 HTTP/1.0";
    Client<<Request;

    // Issue empty line
    Request = "";
    Client<<Request;

    // Receive Response From Server
    Client>>Response;

    // Ignore HTTP Version

    int n = Response.Find(' ');
    Response = Response.Mid(n+1);

    // Http Response Must be 200 only
    if(Response.Left(3)!="200")
    {
      // Connection refused from HTTP Proxy Server
      AfxMessageBox(Response);
    }

    // Read Response Lines until you receive an empty line.
    do
    {
      Client>>Response;
      if (Response.IsEmpty())
        break;
    }while (true);

    // Coooooooool.... Now connected to mail.yahoo.com:25
    // Do further SMTP Protocol here..

  }
  catch (CSocketException * pE)
  {
    pE->ReportError();
  }

 

使用到的库和源码:

文件 Dns.h 包含所有DNS相关的代码. 但他也使用了其他库, 例如:SocketEx.h, SocketClient.h,  NeuroBuffer.h.

 

类的说明:

CSocketEx
Socket functions as a wrapper class. (CSocket is very heavy and unreliable if you don't have the exact idea of how it works.) All the functions are of same name as CSocket. You can use this class directly.

CSocketClient
Derived from CSocketEx and throws proper exceptions with details of Winsock errors. It defines two operators, >> and <<, for easy sending and receiving; it also changes network to host and host to network order of bytes if required.

CHttpProxySocketClient

继承自 CSocketClient, 方法SetProxySettings(ProxyServer,Port)用来设置代理. 然后你就可以连接到你所希望的主机了. 方法ConnectTo用来连接到真正的远端主机。

 

CHttpProxySocketClient的使用:
// e.g. You need to connect to mail.yahoo.com on port 25
  // Through a proxy on 192.0.1.1, on HTTP Proxy 4480
  // CSocketClient is Socket wrapping class
  // When you apply operator << on CString, it writes CString
  // To Socket ending with CRLF
  // When you apply operator >> on CString, it receives
  // Line of response from socket until CRLF
  try
  {
    CHttpProxySocketClient Client;

    Client.SetProxySettings("192.0.1.1",1979);

    // Connect to server mail.yahoo.com on port 25
    Client.ConnectTo("mail.yahoo.com",25);

    // You now have access to mail.yahoo.com on port 25
    // If you do not call SetProxySettings, then
    // you are connected to mail.yahoo.com directly if
    // you have direct access, so always use
    // CHttpProxySocketClient and no need to do any
    // extra coding.

  }
  catch(CSocketException * pE) {
    pE->ReportError();
  }

 

 

源码下载:

http://www.codeguru.com/code/legacy/internet/HttpProxy_Src.zip

 

抱歉!评论已关闭.