為你的QQ造一個SOCK5 PROXY(Gcc篇)之二


本文以QQ為對像,教你如何寫一個SOCK5 PROXY
本章主要介紹Launch_TCP()的工作原理

一、握手過程
===================
先看看Proxy的輸出結果:


< TCP/IP Session - START >

RECV ==> 3 bytes: (0x5)(0x1)(0x0)
SEND ==> 2 bytes: (0x5)(0x0)

RECV ==> 10 bytes: (0x5)(0x3)(0x0)(0x1)(0x0)(0x0)(0x0)(0x0)(0x6)(0x32)
SEND ==> 10 bytes: (0x5)(0x0)(0x0)(0x1)(0x7f)(0x0)(0x0)(0x1)(0x22)(0x6b)

< TCP/IP Session - END >

 

如果不需要身份驗證的話,SOCK5 PROXY和客戶端的握手過程只有四句,
由於SOCK5協議包括很多內容,這裏只對本例中所用到的部份作出說明,
餘者可參考rfc1928.txt

以下逐句分析:
1. 第一句,客戶端→PROXY
  (0x5)版本號
  (0x1)代表有1 byte的資料
  (0x0)登入模式,0x0代表不用身份驗證,0x2代表需要usrname/password

2. 第二句,PROXY→客戶端
  (0x5)版本號
  (0x0)成功

3. 第三句,客戶端→PROXY
  (0x5)版本號
  (0x3)要求使用的協議類型,0x3代表UDP
  (0x0)保留字
  (0x1)地址類型,0x1代表IPv4,0x3代表Domain name,0x4代表IPv6
  (0x0)(0x0)(0x0)(0x0)這4個bytes代表客戶端的地址
  (0x6)(0x32)客戶端用作UDP傳輸的端口號

4. 第四句,PROXY→客戶端
  (0x5)版本號
  (0x0)成功
  (0x0)保留字
  (0x1)地址類型
  PROXY提供的UDP SOCKET地址和端口號,一定要準確無誤,客戶端需要連接到這個地址.
  (0x7f)(0x0)(0x0)(0x1)
  (0x22)(0x6b)

●註:如果地址類型為Domain name(0x3)的話,第1 byte是域名長度,之後n bytes就是地址

 

二、源代碼
===================


void Launch_TCP( int service_port, const char *udp_proxy_ip, int udp_proxy_port, short *clt_udp_port )
{
 //port is NOT network orders

 struct sockaddr_in servaddr,clientaddr;
 int clientlen;
 int listenfd, connfd;
 int n;

 //定義socket, bind, listen, accept,關於這些操作的資料太多了,不詳述
 memset(&servaddr, 0, sizeof(servaddr));
 servaddr.sin_family = AF_INET;
 servaddr.sin_port = htons(service_port);
 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

 listenfd = socket(AF_INET, SOCK_STREAM, 0);
 if(listenfd < 0) {
  p_error("socket error");
  exit(-1);
 }

 if( bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0 ) {
  p_error("bind error");
  exit(-1);
 }
 
 if( listen(listenfd, 5) < 0 ) {
  p_error("listen error");
  exit(-1);
 }

 connfd = accept( listenfd, (struct sockaddr *)&clientaddr, &clientlen );
 if( connfd < 0 ) {
  p_error("accept error");
  exit(-1);
 }

 printf("< TCP/IP Session - START >/n/n");

 //接受第一句請求
 n = recv( connfd, buf, BUFSZ, 0 );
 debug_showbin( buf, n, "RECV", "/n" );

 //目前我們只支持無身份驗證的請求,即"05 01 00"
 if( buf[0]==0x5 && buf[1]==0x1 && buf[2]==0x0) {
  buf[0] = 0x5;
  buf[1] = 0x0;

  //返回"05 00",代表成功
  send( connfd, buf, 2, 0 );
  debug_showbin( buf, 2, "SEND", "/n/n" );
 } else {
  p_error("Session ERROR!/n");
  exit(-1);
 }

 //接受第二句請求
 n = recv( connfd, buf, BUFSZ, 0 );
 debug_showbin( buf, n, "RECV", "/n" );

 //只處理UDP請求(0x03)
 if( buf[0]==0x5 && buf[1]==0x3 ) { //Client request a UDP Proxy

  short udp_port;
  long udp_ip;

  //提取並儲存客戶端的UDP端口號
  int seg=4;
  if( buf[3] == 0x3 )
   seg = buf[4]+1;
  memcpy( clt_udp_port, &buf[4+seg], 2 );
  *clt_udp_port = ntohs( *clt_udp_port );

  buf[0] = 0x5;
  buf[1] = 0x0;
  buf[2] = 0x0;
  buf[3] = 0x1;

  //把本機UDP SOCKET的IP和PORT返回給QQ
  udp_ip = inet_addr( udp_proxy_ip );
  udp_port = htons( udp_proxy_port );
  memcpy( &buf[4], &udp_ip, 4 );
  memcpy( &buf[8], &udp_port, 2 );

  send(connfd, buf, 10, 0 );
  debug_showbin( buf, 10, "SEND", "/n/n" );
 } else {
  p_error("Session ERROR: Client doesn't need a UDP Proxy!/n");
  exit(-1);
 }

 //握手過程完成
 close(connfd);
 close(listenfd);
 
 printf("< TCP/IP Session - END >/n/n");
}

三、測試
===================
1.現在可以先把程序編譯,運行後程序將會在accept()這句搪塞,直至有請求連入.

2.打開QQ,在[系統參數->網絡設置]中選取使用SOCK5代理,在地址欄填入127.0.0.1或localhost,端口填8888,切記要把用戶名和密碼欄清空,因我們的程序只能處理無身份驗證的請求(即握手的第一句為"05 01 00"),如果用戶名和密碼欄不為空的話,QQ將會發送"05 01 02"至Proxy.

3.按一下[測試],看看成不成功,再自己研究一下握手的內容:)


下載本章的源代碼 → mysock5_2.c

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值