穿透代理服务器编程

来源:互联网 发布:多重宇宙 知乎 编辑:程序博客网 时间:2024/05/16 16:12

 田进恩   allfresh@263.net  
          关键词:代理服务器、Socks4、Socks5、Http代理      
          在网络程序设计过程中,我们经常要与各种类型的代理服务器打交道,比如在企业内部网通过代理去访问Internet网上的服务器等等,一般代理服务器支持几种常见的代理协议标准,如Socks4,Socks5,Http代理,其中Socks5需要用户验证,代理相对复杂。我在查阅RFC文档和相关资料后,特总结一些TCP协议穿透代理服务器的程序片断,希望对大家有所帮助。  
   
  //使用到的结构  
  struct   sock4req1  
  {  
  char   VN;  
  char   CD;  
  unsigned   short   Port;  
  unsigned   long   IPAddr;  
  char   other[1];  
  };  
   
  struct   sock4ans1  
  {  
  char   VN;  
  char   CD;  
  };  
   
  struct   sock5req1  
  {  
  char   Ver;  
  char   nMethods;  
  char   Methods[255];  
  };  
   
  struct   sock5ans1  
  {  
  char   Ver;  
  char   Method;  
  };  
   
  struct   sock5req2  
  {  
  char   Ver;  
  char   Cmd;  
  char   Rsv;  
  char   Atyp;  
  char   other[1];  
  };  
   
  struct   sock5ans2  
  {  
  char   Ver;  
  char   Rep;  
  char   Rsv;  
  char   Atyp;  
  char   other[1];  
  };  
   
  struct   authreq  
  {  
  char   Ver;  
  char   Ulen;  
  char   Name[255];  
  char   PLen;  
  char   Pass[255];  
  };  
   
  struct   authans  
  {  
  char   Ver;  
  char   Status;  
  };  
   
  //通过Socks4方式代理  
  if(   !ClientSock.Connect(   g_ProxyInfo.m_strProxyIP,g_ProxyInfo.m_nProxyPort)   )  
  {  
  m_sError   =   _T("不能连接到代理服务器!");  
  ClientSock.Close();  
  return   FALSE;  
  }  
  char   buff[100];  
  memset(buff,0,100);  
  struct   sock4req1   *m_proxyreq;  
  m_proxyreq   =   (struct   sock4req1   *)buff;  
  m_proxyreq->VN   =   4;  
  m_proxyreq->CD   =   1;  
  m_proxyreq->Port   =   ntohs(GetPort());  
  m_proxyreq->IPAddr   =   inet_addr(GetServerHostName());  
  ClientSock.Send(buff,9);  
  struct   sock4ans1   *m_proxyans;  
  m_proxyans   =   (struct   sock4ans1   *)buff;  
  memset(buff,0,100);  
  ClientSock.Receive(buff,100);  
  if(m_proxyans->VN   !=   0   ||   m_proxyans->CD   !=   90)  
  {  
  m_sError   =   _T("通过代理连接主站不成功!");  
  ClientSock.Close();  
  return   FALSE;  
  }  
   
   
       
   
  //通过Socks5方式代理  
  if(   !ClientSock.Connect(   g_ProxyInfo.m_strProxyIP,g_ProxyInfo.m_nProxyPort)   )  
  {  
  m_sError   =   _T("不能连接到代理服务器!");  
  ClientSock.Close();  
  return   FALSE;  
  }  
  char   buff[600];  
  struct   sock5req1   *m_proxyreq1;  
  m_proxyreq1   =   (struct   sock5req1   *)buff;  
  m_proxyreq1->Ver   =   5;  
  m_proxyreq1->nMethods   =   2;  
  m_proxyreq1->Methods[0]   =   0;  
  m_proxyreq1->Methods[1]   =   2;  
  ClientSock.Send(buff,4);  
  struct   sock5ans1   *m_proxyans1;  
  m_proxyans1   =   (struct   sock5ans1   *)buff;  
  memset(buff,0,600);  
  ClientSock.Receive(buff,600);  
  if(m_proxyans1->Ver   !=   5   ||   (m_proxyans1->Method!=0   &&   m_proxyans1->Method!=2))  
  {  
  m_sError   =   _T("通过代理连接主站不成功!");  
  ClientSock.Close();  
  return   FALSE;  
  }  
  if(m_proxyans1->Method   ==   2)  
  {  
  int   nUserLen   =   strlen(g_ProxyInfo.m_strProxyUser);  
  int   nPassLen   =   strlen(g_ProxyInfo.m_strProxyPass);  
  struct   authreq   *m_authreq;  
  m_authreq   =   (struct   authreq   *)buff;  
  m_authreq->Ver   =   1;  
  m_authreq->Ulen   =   nUserLen;  
  strcpy(m_authreq->Name,g_ProxyInfo.m_strProxyUser);  
  m_authreq->PLen   =   nPassLen;  
  strcpy(m_authreq->Pass,g_ProxyInfo.m_strProxyPass);  
  ClientSock.Send(buff,513);  
  struct   authans   *m_authans;  
  m_authans   =   (struct   authans   *)buff;  
  memset(buff,0,600);  
  ClientSock.Receive(buff,600);  
  if(m_authans->Ver   !=   1   ||   m_authans->Status   !=   0)  
  {  
  m_sError   =   _T("代理服务器用户验证不成功!");  
  ClientSock.Close();  
  return   FALSE;  
  }  
  }  
  struct   sock5req2   *m_proxyreq2;  
  m_proxyreq2   =   (struct   sock5req2   *)buff;  
  m_proxyreq2->Ver   =   5;  
  m_proxyreq2->Cmd   =   1;  
  m_proxyreq2->Rsv   =   0;  
  m_proxyreq2->Atyp   =   1;  
  unsigned   long   tmpLong   =   inet_addr(GetServerHostName());  
  unsigned   short   port   =   ntohs(GetPort());  
  memcpy(m_proxyreq2->other,&tmpLong,4);  
  memcpy(m_proxyreq2->other+4,&port,2);  
  ClientSock.Send(buff,sizeof(struct   sock5req2)+5);  
  struct   sock5ans2   *m_proxyans2;  
  memset(buff,0,600);  
  m_proxyans2   =   (struct   sock5ans2   *)buff;  
  ClientSock.Receive(buff,600);  
  if(m_proxyans2->Ver   !=   5   ||   m_proxyans2->Rep   !=   0)  
  {  
  m_sError   =   _T("通过代理连接主站不成功!");  
  ClientSock.Close();  
  return   FALSE;  
  } 

//通过HTTP方式代理  
  if(   !ClientSock.Connect(   g_ProxyInfo.m_strProxyIP,g_ProxyInfo.m_nProxyPort)   )  
  {  
  m_sError   =   _T("不能连接到代理服务器!");  
  ClientSock.Close();  
  return   FALSE;  
  }  
  char   buff[600];  
  sprintf(   buff,   "%s%s:%d%s","CONNECT   ",GetServerHostName(),GetPort(),"   HTTP/1.1/r/nUser-Agent:   MyApp/0.1/r/n/r/n");  
  ClientSock.Send(buff,strlen(buff));   //发送请求  
  memset(buff,0,600);  
  ClientSock.Receive(buff,600);  
  if(strstr(buff,   "HTTP/1.0   200   Connection   established")   ==   NULL)   //连接不成功  
  {  
  m_sError   =   _T("通过代理连接主站不成功!");  
  ClientSock.Close();  
  return   FALSE;  
  }  
   
   
          我们一般先与代理服务器连通,然后向代理服务器发送代理验证的用户名和密码(如果需要,如Socks5代理),验证成功后,再向代理服务器发送需要连接的目的地址和端口。以上代码仅用于TCP连接,如果在内部网侦听或通过UDP协议发送信息,可查阅RFC1829等文档资料。  
   
   
   
   
   
  //   与代理服务器建立CONNECT;          
          int   retErr   =   connect(m_hSocketpop,(SOCKADDR*)&ToAddr,sizeof(ToAddr));  
          if(retErr   ==   SOCKET_ERROR)  
          {  
                  printf("connect   error");  
                  return   -1;  
          }  
          char   buf[100];  
          //   让PROXY选择认证方法  
          buf[0]   =   0x05;  
          buf[1]   =   0x01;  
          buf[2]   =   0x00;   //   无需认证  
          send(m_hSocketpop,(const   far   char*)buf,3,0);  
          recv(m_hSocketpop,buf,10,0);  
          if(buf[1]   !=   0x00)  
                  printf("Need   to   authenticate!/n");  
          //   向PROXY服务器发送CONNECT   请求,  
          WORD   port   =   80;  
          buf[0]   =   0x05;  
          buf[1]   =   0x01;         //   connection   request.  
          buf[2]   =   0x00;         //   reserved!  
          buf[3]   =   0x01;         //   address   type:Ip   V4   ;  
          buf[4]   =   0xd3;    
          buf[5]   =   0x64;    
          buf[6]   =   0x1f;    
          buf[7]   =   0x61;  
          buf[8]   =   port/256;                         //0x80;  
          buf[9]   =   (BYTE)port%256;         //0x00;  
          port   +=   1;  
          send(m_hSocketpop,(const   far   char*)buf,10,0);  
          //   接收PROXY服务器返回的REPLY  
          recv(m_hSocketpop,buf,20,0);  
          if(buf[1]   !=   0)   //   只有当第二个字节为0时,才表示成功。  
          {  
                  printf("Cannot   connect   to   the   remote   server!/n");  
                  return   -1;  
          }  
          //   用PROXY服务器返回的REPLY中的地址与端口号来CONNECT   目的主机  
          SOCKADDR_IN   SockAddr;  
          SOCKET   prxSock;  
          prxSock   =   socket(AF_INET,   SOCK_STREAM   ,0);     //   SOCK_DGRAM  
          port   =   ((WORD)buf[8])*256   +   (WORD)buf[9];   //   返回的端口号在buf[8]   和   buf[9]   中  
          memset(&SockAddr,0,sizeof(SockAddr));  
          SockAddr.sin_family   =   AF_INET;  
          SockAddr.sin_port   =   port;  
          SockAddr.sin_addr.S_un.S_un_b.s_b1   =   buf[4];    
          SockAddr.sin_addr.S_un.S_un_b.s_b2   =   buf[5];  
          SockAddr.sin_addr.S_un.S_un_b.s_b3   =   buf[6];  
          SockAddr.sin_addr.S_un.S_un_b.s_b4   =   buf[7];  
          retErr   =   connect(prxSock,(SOCKADDR*)&SockAddr,sizeof(SockAddr));  
          if(retErr   ==   SOCKET_ERROR)  
                  printf("error");    
          /*连接已经建立好了,下面你就可以用prxSock用send发送数据了。*/  
          char   *pInfo   =   (char   *)malloc(100);  
          strcpy(pInfo,"Only   a   test");  
          send(prxSock,pInfo,100,0);

原创粉丝点击