原理
HTTP代理服务器中能够提供一种HTTP CONNECT代理服务,能够允许用户建立TCP连接到任何端口。通过CONNECT方法穿透代理的实现方法为:
CONNECT代理服务器的代理端口(如:8080);如果成功返回就可以按照正常的Socket进行通讯。当然在此之前需要先获得代理相关的信息。
如何获取HTTP代理相关信息
程序中是通过读取注册表来获取计算机HTTP代理相关信息的,在注册表的\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings键值下就保存着HTTP代理服务器及端口等信息,
根据该键值下的ProxyEnable值可以判断是否有HTTP代理,没有代理的情况下ProxyEnable值为0。
当然一般情况下程序去中访问该键值可能是受限的,所有就需要获取到访问令牌不受限制的UserSid,使用该UserSid去读取HTTP代理信息。
1char tmpBuffer[128] = { 0 }; 2 ::sprintf(tmpBuffer, "CONNECT %s:%d HTTP/1.1\r\nUser-Agent: Mozilla/4.0\r\nConnection: Keep-Alive\r\n\r\n", ip.c_str(), port); 3 Send(tmpBuffer, strlen(tmpBuffer)); 4 Receive(tmpBuffer, sizeof(tmpBuffer));
实现
头文件
1#pragma once 2 3#include <string> 4#include <vector> 5 6using namespace std; 7 8class addrinfo; 9 10class CHttpProxy 11{ 12public: 13 CHttpProxy(std::string ip, unsigned short port) 14 :m_proxyIp(ip), m_proxyPort(port), m_socket(-1) 15 {} 16 17 ~CHttpProxy(void); 18 19 void ConnectProxyServer(); 20 void ConnectServer(std::string ip, unsigned short port); 21 22 bool Send(const char* buf, int len); 23 int Receive(char* buf, int bufLen); 24 25 int GetSocket() 26 { 27 return m_socket; 28 } 29private: 30 std::string m_proxyIp; 31 addrinfo* m_addrinfo = nullptr; 32 unsigned short m_proxyPort; 33 int m_socket; 34};
实现
1#include "HttpProxy.h" 2#include <string.h> 3 4#include <time.h> 5#ifdef WIN32 6#include <WS2tcpip.h> 7#else 8#include <unistd.h> 9#include <netdb.h> 10#include <arpa/inet.h> 11#include <sys/types.h> /* See NOTES */ 12#include <sys/socket.h> 13#include <netinet/in.h> 14#define INVALID_SOCKET -1 15#endif 16 17CHttpProxy::~CHttpProxy(void) 18{ 19 if (m_addrinfo) 20 { 21 freeaddrinfo(m_addrinfo); 22 } 23} 24void CHttpProxy::ConnectProxyServer() 25{ 26 struct sockaddr_in addr; 27 m_socket = socket(AF_INET, SOCK_STREAM, 0); 28 if (m_socket == INVALID_SOCKET) 29 { 30 throw CException("Error on creating socket fd"); 31 } 32 33 addrinfo inAddrInfo = { 0 }; 34 inAddrInfo.ai_family = AF_INET; 35 inAddrInfo.ai_socktype = SOCK_STREAM; 36 37 std::string strPort = std::to_string(m_proxyPort); 38 if (getaddrinfo(m_proxyIp.c_str(), strPort.c_str(), &inAddrInfo, &m_addrinfo) != 0) // error occurs 39 { 40 throw CException("Error on calling getadrrinfo()."); 41 } 42 43 if (connect(m_socket, m_addrinfo->ai_addr, m_addrinfo->ai_addrlen)) 44 { 45 throw CException("Error on calling connect()."); 46 } 47} 48 49void CHttpProxy::ConnectServer(std::string ip, unsigned short port) 50{ 51 if (m_socket == INVALID_SOCKET) 52 { 53 throw CException("Invalid socket fd"); 54 } 55 char tmpBuffer[128] = { 0 }; 56 ::sprintf(tmpBuffer, "CONNECT %s:%d HTTP/1.1\r\nUser-Agent: Mozilla/4.0\r\nConnection: Keep-Alive\r\n\r\n", ip.c_str(), port); 57 Send(tmpBuffer, strlen(tmpBuffer)); 58 Receive(tmpBuffer, sizeof(tmpBuffer)); 59 60 int mj, mi, code; 61 ::sscanf(tmpBuffer, "HTTP/%d.%d %d", &mj, &mi, &code); 62 if (code != 200) 63 { 64 throw CException("http connect emial server faild"); 65 } 66} 67 68int CHttpProxy::Receive(char* buf, int bufLen) 69{ 70 return recv(m_socket, buf, bufLen, 0); 71} 72 73bool CHttpProxy::Send(const char* buf, int len) 74{ 75 long ilen = len; 76 int sendCnt = 0; 77 int ret; 78 79 while (sendCnt < ilen) 80 { 81 if ((ret = send(m_socket, buf + sendCnt, ilen - sendCnt, 0)) == INVALID_SOCKET) 82 { 83 return false; 84 } 85 else 86 { 87 sendCnt += ret; 88 } 89 } 90 91 return true; 92}