路過proxy的socket


主題:用socket在做網路的溝通,中間想透過proxy server該怎麼辦???


簡單來說就下面這幾步,其中跟一般建connection不同的就只有第二步,要先做handshaking
0.建socket
1.跟proxy建立connection
2.丟Sock4/Sock5的protocol給proxy
3.之後丟message都透過這個socket

簡單的code來解釋
0. int Socket = socket( AF_INET, SOCK_STREAM, 0 );
1. connect(Socket, <struct sockaddr with proxy info>, sizeof(struct sockaddr));
2. a. send(Socket, <protocol packet>, <packet size>, 0);
    b. recv(Socket, <reply packet>, <reply packet size>);
    c. // check the 2nd byte of the reply packet
3. send(Socket, <a buffer with your message>, <message length>, 0);

重點就是在第2步啦!
接下來,看看Sock4/Sock5所需準備的packet format

SOCK4
Request Format:
         +----+----+----+----+----+----+----+----+----+----+....+----+
    | VN | CD | DSTPORT |      DSTIP        | USERID       |NULL|
    +----+----+----+----+----+----+----+----+----+----+....+----+
# of bytes: 1    1      2              4           variable        1
packet[0] = 4;                                 // version
packet[1] = 1;                                 // connection
packet[2] = htons(port);                  // port
packet[4] = inet_addr(host_name); // ip
packet[8] = 0;                                 // NULL terminator


Reply Format:
                +----+----+----+----+----+----+----+----+
           | VN | CD | DSTPORT |      DSTIP        |
           +----+----+----+----+----+----+----+----+
# of bytes:  1    1      2              4

VN: reply code, should be 0
CD: result code, as following,
    90: request granted
    91: request rejected or failed
    92: request rejected because SOCKS server cannot connect to identd on the client
    93: request rejected because the client program and identd report different user-ids



SOCK5:
這邊填的值略有不同
packet[0] = 5;           // version
packet[1] = 2;           // 有幾個method
packet[2] = 0;           // 第一個method, 0:不需驗證
packet[3] = 2;           // 第二個method, 2:要驗證

Reply Format:
                +----+-----+-------+------+----------+----------+
        |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
        +----+-----+-------+------+----------+----------+
        | 1  |  1  | X'00' |  1   | Variable |    2     |
        +----+-----+-------+------+----------+----------+
VER: version, should be '5'
REP: reply code, 0:不需驗證, 2:要驗證, others:failed


接下來程序比較複雜,需要多送一次authentication跟建connection

SEND: Authentication Request Format:
       +----+------+----------+------+----------+
     |VER | ULEN |  UNAME   | PLEN |  PASSWD  |
     +----+------+----------+------+----------+
     | 1  |  1   | 1 to 255 |  1   | 1 to 255 |
     +----+------+----------+------+----------+
packet[0] = 1;                          // i don't know why...authentication version??
packet[1] = strlen(username);
memcpy(packet+2, username, strlen(username)));
packet[2 + strlen(username)] = strlen(password);
memcpy(packet + strlen(username) + 3, password, strlen(password)));

REPLY:
驗證成功:
reply[0] == 1 &&  // version we sent
reply[1] == 0       // reply code, always should be 0

SEND: Ask For Connection:
packet[0] = 5;                                   // version
packet[1] = 1;                                   // connection request
packet[2] = 0;                                   // reserved, must be 0
packet[3] = 1;                                   // IPv4 = 1
packet[4] = inet_addr(host_name);  // the server host name
packet[8] = htons(port);                   // the server port

REPLY:
connection結果:
reply[0] == 5 &&  // version we sent
reply[1] == 0       // reply code, always should be 0

ref:
http://blog.csdn.net/bodybo/article/details/7274865
http://www.cppblog.com/zuhd/archive/2010/06/08/117366.html
http://www.opensource.apple.com/source/curl/curl-42/curl/lib/socks.c

留言

這個網誌中的熱門文章

What's New in Ethereum Serenity (2.0)

瑞士滑雪分享2 - 策馬特

動手實做零知識 - circom