This article uses QQ as an object, teach you how to write a SOCK5 Proxy this chapter mainly introduces the working principle of launch_tcp ()
First, the handshake process =================== look at the output of Proxy first:
RECV ==> 3 bytes: (0x5) (0x1) (0x0) send ==> 2 Bytes: (0x5) (0x0)
Recv ==> 10 bytes: (0x5) (0 × 3) (0x0) (0x0) (0x0) (0x0) (0x6) (0x6) Send ==> 10 BYTES: (0x5) (0x0) (0x0) (0x7) (0x7F) (0x0) (0x1) (0x22) (0x6b)
If you do not need authentication, the Handshake process of Sock5 Proxy and Clients has only four sentences. Since the SOCK5 protocol consists of a lot of content, only the part used in this example, the rest can refer to RFC1928.txt
The following sentences: 1. First sentence, client → proxy (0x5) version number (0x1) represents 1 byte's data (0x0) login mode, 0x0 represents no authentication, 0x2 represents USRNAME / Password
2. Second sentence, proxy → client (0x5) version number (0x0) successfully
3. Third sentence, client → proxy (0x5) version number (0x3) requires the protocol type, 0x3 represents UDP (0x0) reserved word (0x1) address type, 0x1 represents IPv4,0x3 represents Domain Name, 0x4 represents IPv6 (0x0) (0x0) (0x0) (0x0) These 4 BYtes represent the client's address (0x6) (0x32) client as a port number for UDP transmission
4. The fourth sentence, Proxy → Client (0x5) version number (0x0) Success (0x0) Reserved Word (0x1) Address Type Proxy provides the UDP Socket address and port number provided, must be accurate, the client needs to connect to this Address. (0x7F) (0x0) (0x1) (0x22) (0x6B)
● Note: If the address type is domain name (0x3), the first byte is the length of the domain name, then n bytes is address
Second, source code ===================
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;
// Define Socket, Bind, Listen, Accept, there are too many information about these operations, not detail 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 (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 ("
// Accept the first sentence request n = Recv (connfd, buf, bufsz, 0); debug_showbin (buf, n, "rv", "/ n");
// We only support the authenticated request, ie "05 01 00" if (BUF [0] == 0x5 && buf [1] == 0x1 && buf [2] == 0x0) {buf [0] = 0x5; buf [1] = 0x0;
// Return "05 00", represent success Send (connfd, buf, 2, 0); debug_showbin (buf, 2, "send", "/ n / n");} else {p_ERROR ("session error! / N "); Exit (-1);}
// Accept the second sentence request n = Recv (connfd, buf, bufsz, 0); debug_showbin (buf, n, "rv", "/ n");
// Process UDP request (0x03) IF (BUF [0] == 0x5 && buf [1] == 0x3) {// Client Request A UDP Proxy
Short udp_port; long udp_ip;
// Extract and save the client's UDP port number 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;
/ / Return the IP and PORT of the unit UDP Socket to 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);} // Handshake process Complete Close (Connfd); Close (Listenfd); Printf ("
Third, the test ==================== 1. You can now compile the program first. After running the program, the program will succeed until there is a request.
2. Open QQ, select the SOCK5 agent in [System Parameters -> Network Settings], fill in 127.0.0.1 or localhost, fill in the address bar, to fill in 8888, remember to clear the username and password bar, because our program can only Processing a request without authentication (ie the first sentence of the handshake is "05 01 00"), if the username and the password column are not empty, QQ will send "05 01 02" to Proxy.
3. Press [Test] to see if it is unsuccessful, then study the contents of shaking hands :)
Download the source code of this chapter → mysock5_2.c