荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: michaelx (好好学习), 信区: Program
标  题: 為你的QQ造一個SOCK5 PROXY(Gcc篇)之二
发信站: 荔园晨风BBS站 (Fri Mar 28 18:58:52 2003), 站内信件


一、握手過程
===================
先看看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.按一下[測試],看看成不成功,再自己研究一下握手的內容:)
--

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 220.112.3.40]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店