1 /* **************************************** 2 * Name : Vtun 源碼詳細(xì)分析 3 * Version : 3.0.3 4 * Date : Jan. 22, 2014 5 * Author : lucas 6 * Email : lucasysfeng@gmail.com 7 * Blog : http://www.cnblogs.com/lucasysfeng/ 8 * Description : 1.Vtun是一個(gè)短小精悍的開源VPN項(xiàng)目, 9 * 這里分析了其客戶端和服務(wù)器的源碼。 10 * 2.vtun源碼可以從下面網(wǎng)址下載 11 * http://vtun.sourceforge.net/ 12 **************************************** */ 13 14 15 /* ********************************************** client端代碼執(zhí)行基本流程分析 *********************************************** */ 16 /* *************************************************************** 17 *原型:int main(int argc, char* argv[], char* env[]); 18 *功能:初始化操作,確定是client端還是server端。 19 *下一步:根據(jù)命令行參數(shù)選擇執(zhí)行client或者server分支,先分析client。 20 **************************************************************** */ 21 int main( int argc, char *argv[], char * env[]) 22 { 23 ...... 24 ...... // 初始化vtun結(jié)構(gòu)體。 25 while ((opt = getopt(argc, argv, " misf:P:L:t:npq " )) != EOF) // 獲取命令行參數(shù)并進(jìn)行相應(yīng)操作。 26 { 27 ...... 28 } 29 reread_config( 0 ); // 讀配置文件。 30 ...... 31 clear_nat_hack_flags(svr); // 清除另一方的nat_hack標(biāo)志。 32 if (!svr) // 根據(jù)命令行參數(shù)進(jìn)行客戶端配置。 33 { 34 ...... 35 hst = argv[optind++]; // vtund server [ip]的第二個(gè)參數(shù)給hst,這個(gè)參數(shù)是服務(wù)器給客戶端定義的名字。 36 host = find_host(hst); // hst是命令行參數(shù),host是配置文件中的對應(yīng)該參數(shù)的會(huì)話信息。 37 ...... 38 } 39 vtun.svr_name = strdup(argv[optind]); // vtund server [ip]的ip給vtun.srv_name 40 ...... // 如果vtun結(jié)構(gòu)體的一些成員沒有被初試話,則賦予默認(rèn)值。 41 switch (vtun.svr_type) // 判斷vtun的類型,VTUN_STAND_ALONE VTUN_INETD. 42 { 43 ...... 44 } 45 if (daemon) // 是否要?jiǎng)?chuàng)建守護(hù)進(jìn)程 46 { 47 if (dofork && fork()) // 當(dāng)命令行設(shè)置為超級(jí)守護(hù)進(jìn)程時(shí)不執(zhí)行該操作。 48 ... 49 } 50 if (svr) 51 { 52 memset(&sa, 0 , sizeof (sa)); // 掛起時(shí)讀取配置文件。 53 sa.sa_handler = reread_config; 54 sigaction(SIGHUP, & sa, NULL); 55 init_title(argc, argv, env, " vtund[s]: " ); 56 57 if (vtun.svr_type == VTUN_STAND_ALONE) 58 write_pid(); // 將當(dāng)前pid寫入文件中 59 60 server(sock); // 執(zhí)行服務(wù)器操作 61 } 62 else 63 { 64 init_title(argc, argv, env, " vtund[c]: " ); 65 client(host); // 執(zhí)行客戶端操作,host就是從配置文件讀取出的對應(yīng)命令行參數(shù)會(huì)話名的信息。 66 } 67 ...... 68 } 69 70 71 /* *********************************************************** 72 *原型:void client(struct vtun_host *host); 73 *參數(shù):host是從配置文件中讀出某個(gè)會(huì)話名所包含的信息。 74 *功能:建立socket以及bind、connect、select等,認(rèn)證暨建立隧道。 75 *下一步:認(rèn)證auth_client(s, host)后再執(zhí)行tunnel(host)即開啟隧道。 76 ************************************************************ */ 77 void client( struct vtun_host *host) // host參數(shù)是main函數(shù)中傳遞的配置文件中的會(huì)話信息。 78 { 79 ...... 80 ...... // 結(jié)束,掛起等信號(hào)處理函數(shù)。 81 while ((!client_term) || (client_term == VTUN_SIG_HUP)) 82 { 83 if (reconnect && (client_term != VTUN_SIG_HUP)) { ...... } // 重連 84 ...... 85 if (server_addr(&svr_addr, host) < 0 ) continue ; // Set server address 86 if (local_addr(&my_addr, host, 0 ) < 0 ) continue ; // Set local address 87 if ((s = socket(AF_INET, SOCK_STREAM, 0 )) == - 1 ) { ...... } // 建立socket套接字 88 opt = 1 ; 89 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)); // Required when client is forced to bind to specific port 90 if (bind(s, ( struct sockaddr *)&my_addr, sizeof (my_addr))){.....} // bind 91 host->spd_in = host->spd_out = 0 ; 92 host->flags &= VTUN_CLNT_MASK; // Clear speed and flags which will be supplied by server. 93 io_init(); 94 ...... 95 96 if (connect_t(s,( struct sockaddr *) &svr_addr, host-> timeout)) 97 { 98 ..... 99 } 100 else 101 { 102 if (auth_client(s, host)) // 認(rèn)證,也就是隧道建立過程 103 { 104 ... 105 client_term = tunnel(host); // 開啟隧道,host是配置文件相應(yīng)會(huì)話信息。 106 ... 107 } 108 else 109 { 110 ...... // 認(rèn)證失敗 111 } 112 } 113 close(s); 114 free_sopt(&host-> sopt); 115 } // end while 116 ...... 117 } 118 119 /* *************************************************************************** 120 *補(bǔ)充:在執(zhí)行tunnel(host)前先來看看上面client函數(shù)中的connect_t函數(shù)。 121 *原型:int connect_t(int s, struct sockaddr *svr, time_t timeout); 122 *參數(shù):s是client中建立的套接字描述符。 123 *功能:與服務(wù)器建立連接。 124 **************************************************************************** */ 125 int connect_t( int s, struct sockaddr * svr, time_t timeout) 126 { 127 #if defined(VTUN_SOCKS) && VTUN_SOCKS == 2 128 /* Some SOCKS implementations don't support 129 * non blocking connect */ 130 return connect(s, svr, sizeof ( struct sockaddr)); 131 #else 132 sock_flags = fcntl(s, F_GETFL); 133 if (fcntl(s, F_SETFL, O_NONBLOCK) < 0 )... // 設(shè)置s為非阻塞? 134 if (connect(s, svr, sizeof ( struct sockaddr)) < 0 && errno != EINPROGRESS)... 135 ...... 136 if ( select (s+ 1 , NULL, &fdset, NULL, timeout?&tv:NULL) > 0 ) 137 { 138 ... 139 getsockopt(s, SOL_SOCKET, SO_ERROR, &errno, &l); // ? 140 } 141 else 142 { 143 errno = ETIMEDOUT; 144 fcntl(s, F_SETFL, sock_flags); 145 ... 146 } 147 #endif 148 } // end connect_t 149 150 /* ************************************************************************ 151 *補(bǔ)充:在執(zhí)行tunnel(host)前再來看看上面client函數(shù)中的auth_client. 152 *原型:int auth_client(int fd, struct vtun_host *host); 153 *參數(shù):fd是client端創(chuàng)建的套接字描述符,host是配置文件中某個(gè)會(huì)話所包含的信息 154 *功能:認(rèn)證過程,也是隧道建立過程。 155 ************************************************************************* */ 156 int auth_client( int fd, struct vtun_host * host) 157 { 158 ...... 159 stage = ST_INIT; // #define ST_INIT 0 160 while (readn_t(fd, buf, VTUN_MESG_SIZE, vtun.timeout) > 0 ) // 讀取服務(wù)器發(fā)來認(rèn)證信息。 161 { 162 buf[ sizeof (buf)- 1 ]= ' \0 ' ; 163 switch (stage) 164 { 165 case ST_INIT: 166 if (!strncmp(buf, " VTUN " , 4 )) 167 { 168 stage = ST_HOST; 169 print_p(fd, " HOST: %s\n " ,host->host); // print_p向server發(fā)送HOST:[host]。 170 continue ; 171 } 172 break ; 173 case ST_HOST: 174 if (!strncmp(buf, " OK " , 2 ) && cs2cl(buf, chal)) // 接收到請求發(fā)送密碼信息 OK CHAL:[chal] 175 { 176 stage = ST_CHAL; 177 encrypt_chal(chal, host-> passwd); 178 print_p(fd, " CHAL: %s\n " , cl2cs(chal)); // 發(fā)送配置文件中本次會(huì)話密碼CHAL:[chal] 179 continue ; 180 } 181 break ; 182 case ST_CHAL: 183 if (!strncmp(buf, " OK " , 2 ) && cf2bf(buf, host)) // 接收到OK FLAGS:[host]認(rèn)證成功信息 184 success = 1 ; 185 break ; 186 } 187 break ; 188 } // end while 189 return success; 190 } 191 192 /* ************************************************************************ 193 *原型:int tunnel(strucnt vtun_host* host); 194 *參數(shù):host是配置文件中某個(gè)會(huì)話所包含的信息 195 *功能:開啟隧道即初試話設(shè)備讀寫函數(shù),初始化封裝后發(fā)送接收所用協(xié)議。 196 *下一步:linkfd(host); 197 ************************************************************************* */ 198 int tunnel( struct vtun_host * host) 199 { 200 ...... 201 if ((host->persist == VTUN_PERSIST_KEEPIF) && (host->loc_fd >= 0 )) // 接口是否已經(jīng)打開 202 interface_already_open = 1 ; 203 if (host->dev){...} // 判斷虛擬設(shè)備類型 204 if (!interface_already_open) // 虛擬網(wǎng)卡沒有打開,則打開之 205 206 ... 207 switch (host->flags & VTUN_TYPE_MASK) 208 { 209 ... 210 case VTUN_TUN: 211 if ((fd[ 0 ]=tun_open(dev)) < 0 ) // 打開虛擬網(wǎng)卡,獲取描述符 212 { 213 vtun_syslog(LOG_ERR, " Can't allocate tun device %s. %s(%d) " , dev, strerror(errno), errno); 214 return - 1 ; 215 } 216 break ; 217 } 218 host->loc_fd = fd[ 0 ]; // 虛擬設(shè)備文件描述符存在host->loc_fd中 219 } 220 switch (host->flags & VTUN_PROT_MASK) // 初始化協(xié)議,tcp還是udp 221 { 222 ...... 223 case VTUN_UDP: 224 if ((opt = udp_session(host)) == - 1 ){.....} // 進(jìn)行udp的socket創(chuàng)建等操作 225 proto_write = udp_write; 226 proto_read = udp_read; 227 } 228 switch ((pid = fork())){...} // 建立子進(jìn)程 229 switch (host->flags & VTUN_TYPE_MASK) // 根據(jù)虛擬設(shè)備類型,選擇相應(yīng)虛擬設(shè)備讀寫方式 230 { 231 ..... 232 case VTUN_TUN: 233 set_title( " %s tun %s " , host-> host, dev); 234 dev_read = tun_read; 235 dev_write = tun_write; 236 break ; 237 } 238 opt = linkfd(host); 239 ....... 240 } 241 242 /* ************************************************************************ 243 *補(bǔ)充:在linkfd之前,我們先來看看tunnel函數(shù)中udp_session. 244 *原型:int udp_session(struct vtun_host *host); 245 *參數(shù):host是配置文件中某個(gè)會(huì)話所包含的信息。 246 *功能:udp socket的創(chuàng)建、bind、connect等。 247 ************************************************************************* */ 248 int udp_session( struct vtun_host * host) 249 { 250 struct sockaddr_in saddr; 251 short port; 252 int s, opt; 253 extern int is_rmt_fd_connected; 254 255 if ((s = socket(AF_INET, SOCK_DGRAM, 0 )) == - 1 ) 256 { 257 vtun_syslog(LOG_ERR, " Can't create socket " ); 258 return - 1 ; 259 } 260 261 opt = 1 ; 262 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)); 263 264 /* Set local address and port */ 265 local_addr(&saddr, host, 1 ); 266 if (bind(s, ( struct sockaddr *) &saddr, sizeof (saddr))) 267 { 268 vtun_syslog(LOG_ERR, " Can't bind to the socket " ); 269 return - 1 ; 270 } 271 272 opt = sizeof (saddr); 273 if (getsockname(s, ( struct sockaddr *) &saddr, & opt)) 274 { 275 vtun_syslog(LOG_ERR, " Can't get socket name " ); 276 return - 1 ; 277 } 278 279 /* Write port of the new UDP socket */ 280 port = saddr.sin_port; 281 if (write_n(host->rmt_fd, ( char *) &port, sizeof ( short )) < 0 ) 282 { 283 vtun_syslog(LOG_ERR, " Can't write port number " ); 284 return - 1 ; 285 } 286 host->sopt.lport = htons(port); 287 288 /* Read port of the other's end UDP socket */ 289 if (readn_t(host->rmt_fd, &port, sizeof ( short ), host->timeout) < 0 ) 290 { 291 vtun_syslog(LOG_ERR, " Can't read port number %s " , strerror(errno)); 292 return - 1 ; 293 } 294 295 opt = sizeof (saddr); 296 if (getpeername(host->rmt_fd, ( struct sockaddr *) &saddr, & opt)) 297 { 298 vtun_syslog(LOG_ERR, " Can't get peer name " ); 299 return - 1 ; 300 } 301 302 saddr.sin_port = port; 303 304 /* if the config says to delay the UDP connection, we wait for an 305 incoming packet and then force a connection back. We need to 306 put this here because we need to keep that incoming triggering 307 packet and pass it back up the chain. */ 308 309 if (VTUN_USE_NAT_HACK(host)) 310 is_rmt_fd_connected = 0 ; 311 else 312 { 313 if (connect(s, ( struct sockaddr *)&saddr, sizeof (saddr))) 314 { 315 vtun_syslog(LOG_ERR, " Can't connect socket " ); 316 return - 1 ; 317 } 318 is_rmt_fd_connected = 1 ; 319 } 320 321 host->sopt.rport = htons(port); 322 323 /* Close TCP socket and replace with UDP socket */ 324 close(host-> rmt_fd); 325 host->rmt_fd = s; // 將TCP套接字替換為UDP套接字。 326 327 vtun_syslog(LOG_INFO, " UDP connection initialized " ); 328 return s; 329 } 330 331 /* ************************************************************************ 332 *原型:int linkfd(struct vtun_host *host); 333 *參數(shù):host是配置文件中某個(gè)會(huì)話所包含的信息。 334 *功能:初始化加密解密壓縮解壓模塊。 335 *下一步:虛擬網(wǎng)卡讀寫以及數(shù)據(jù)的接收發(fā)送lfd_linker(); 336 ************************************************************************* */ 337 int linkfd( struct vtun_host * host) 338 { 339 ...... 340 lfd_host = host; 341 old_prio = getpriority(PRIO_PROCESS, 0 ); // 取得進(jìn)程優(yōu)先級(jí) 342 setpriority(PRIO_PROCESS, 0 , LINKFD_PRIO); 343 ...... // Build modules stack加密壓縮等。 344 ...... // 結(jié)束進(jìn)程等信號(hào)處理函數(shù)。 345 io_init(); 346 lfd_linker(); // 虛擬網(wǎng)卡讀寫,封裝解封以及發(fā)送。 347 ...... // 鬧鐘信號(hào)等。 348 } 349 350 /* ************************************************************************ 351 *原型:int lfd_linker(void) 352 *功能:虛擬網(wǎng)卡讀寫以及數(shù)據(jù)的接收發(fā)送lfd_linker(); 353 *下一步:結(jié)束。 354 ************************************************************************* */ 355 int lfd_linker( void ) 356 { 357 int fd1 = lfd_host->rmt_fd; // fd1是網(wǎng)絡(luò)套接字描述符,也就是最后封裝發(fā)送的那個(gè)套接字描述符。 358 int fd2 = lfd_host->loc_fd; // fd2是虛擬網(wǎng)卡設(shè)備文件描述符。 359 ...... 360 /* Delay sending of first UDP packet over broken NAT routers 361 because we will probably be disconnected. Wait for the remote 362 end to send us something first, and use that connection. */ 363 if (!VTUN_USE_NAT_HACK(lfd_host)) // ? 364 proto_write(fd1, buf, VTUN_ECHO_REQ); 365 ...... 366 while (!linker_term) // while循環(huán)體從虛擬網(wǎng)卡讀數(shù)據(jù)后發(fā)送;將接收的數(shù)據(jù)寫入虛擬網(wǎng)卡。 367 { 368 ...... 369 FD_ZERO(&fdset); // 等待數(shù)據(jù) 370 FD_SET(fd1, & fdset); 371 FD_SET(fd2, & fdset); 372 tv.tv_sec = lfd_host->ka_interval; // 非阻塞超時(shí)時(shí)間 373 tv.tv_usec = 0 ; 374 if ((len = select (maxfd, &fdset, NULL, NULL, &tv)) < 0 ) 375 { 376 ....,. 377 } // select非阻塞監(jiān)控 378 if (ka_need_verify) // ka_need_verify和信號(hào)處理函數(shù)有關(guān) 379 { 380 ... // No input frames, check connection with ECHO,沒輸入信息,發(fā)送請求信息。 381 } 382 if (send_a_packet) // 默認(rèn)為0不加密 383 { 384 ... // 加密發(fā)送 385 } 386 if (FD_ISSET(fd1,&fdset) && lfd_check_up()) // 網(wǎng)絡(luò)套接字fd1是否有數(shù)據(jù)到達(dá),加解密模塊是否準(zhǔn)備就緒。 387 { 388 .... 389 if ((len = proto_read(fd1, buf)) <= 0 )... // 接收網(wǎng)絡(luò)中數(shù)據(jù)存到buf 390 fl = len & ~VTUN_FSIZE_MASK; // 獲取幀標(biāo)志 391 len = len & VTUN_FSIZE_MASK; 392 if (fl) // fl即frame flags幀標(biāo)志 393 { 394 ... // 判斷是何種幀,即判斷接收到數(shù)據(jù)的類型請求、應(yīng)答、壞幀、關(guān)閉 。 395 } 396 if ((len = lfd_run_up(len, buf, & out )) == - 1 )... // 解密 397 if (len && dev_write(fd2, out , len) < 0 ) 398 { 399 ... // 將網(wǎng)絡(luò)套接字fd1的數(shù)據(jù)寫入虛擬網(wǎng)卡fd2。 400 } 401 } 402 if (FD_ISSET(fd2, &fdset) && lfd_check_down()) // 虛擬網(wǎng)卡中是否有數(shù)據(jù),加解密模塊是否就緒。 403 { 404 if ((len = dev_read(fd2, buf, VTUN_FRAME_SIZE)) < 0 ) 405 { 406 ... // 讀取虛擬網(wǎng)卡中數(shù)據(jù) 407 } 408 if ((len = lfd_run_down(len, buf, & out )) == - 1 )... // 加密 409 if (len && proto_write(fd1, out , len) < 0 ) 410 { 411 ... // 將虛擬網(wǎng)卡fd2中數(shù)據(jù)通過網(wǎng)絡(luò)套接字fd1發(fā)送。 412 } 413 ... 414 } 415 ... 416 } // end while 417 ... 418 proto_write(fd1, buf, VTUN_CONN_CLOSE); // 通知其他終端本終端連接關(guān)閉 419 ... 420 return 0 ; 421 } 422 423 424 425 426 /* ********************************************** server端代碼執(zhí)行基本流程分析 *********************************************** */ 427 /* *************************************************************** 428 *原型:int main(int argc, char* argv[], char* env[]); 429 *功能:初始化操作,確定是client端還是server端。 430 *下一步:根據(jù)命令行參數(shù)選擇執(zhí)行client或者server分支,分析server。 431 **************************************************************** */ 432 int main( int argc, char *argv[], char * env[]) 433 { 434 ...... 435 ...... // 初始化vtun結(jié)構(gòu)體。 436 while ((opt = getopt(argc, argv, " misf:P:L:t:npq " )) != EOF) // 獲取命令行參數(shù)并進(jìn)行相應(yīng)操作。 437 { 438 ...... 439 } 440 reread_config( 0 ); // 讀配置文件。 441 ...... 442 clear_nat_hack_flags(svr); 443 if (!svr) // 如果不是服務(wù)器,再根據(jù)命令行參數(shù)進(jìn)行配置。 444 { 445 ...... 446 hst = argv[optind++]; // vtund server [ip]的第二個(gè)參數(shù)給hst,這個(gè)參數(shù)是服務(wù)器給客戶端定義的名字。 447 host = find_host(hst); // hst是命令行參數(shù),host是配置文件中的對應(yīng)該參數(shù)的會(huì)話信息。 448 ...... 449 } 450 vtun.svr_name = strdup(argv[optind]); // vtund server [ip]的ip給vtun.srv_name 451 ...... // 如果vtun結(jié)構(gòu)體的一些成員沒有被初試話,則賦予默認(rèn)值。 452 switch (vtun.svr_type) // 判斷vtun的類型,VTUN_STAND_ALONE VTUN_INETD. 453 { 454 ...... 455 } 456 if (daemon) // 是否要?jiǎng)?chuàng)建守護(hù)進(jìn)程 457 { 458 if (dofork && fork()) 459 ... 460 } 461 if (svr) 462 { 463 memset(&sa, 0 , sizeof (sa)); // 掛起時(shí)讀取配置文件。 464 sa.sa_handler = reread_config; 465 sigaction(SIGHUP, & sa, NULL); 466 467 init_title(argc, argv, env, " vtund[s]: " ); 468 469 if (vtun.svr_type == VTUN_STAND_ALONE) 470 write_pid(); 471 472 server(sock); // 執(zhí)行服務(wù)器操作 473 } 474 else 475 { 476 init_title(argc, argv, env, " vtund[c]: " ); 477 client(host); // 執(zhí)行客戶端操作,host就是從配置文件讀取出的對應(yīng)命令行參數(shù)會(huì)話名的信息。 478 } 479 ...... 480 } 481 482 /* *********************************************************** 483 *原型:void server(int sock); 484 *參數(shù):sock = 0. 485 *功能:建立socket以及bind、connect、select等,認(rèn)證暨建立隧道。 486 *下一步:根據(jù)守護(hù)進(jìn)程類型選擇執(zhí)行l(wèi)istener還是connection。 487 ************************************************************ */ 488 void server( int sock) 489 { 490 struct sigaction sa; // 忽略接收進(jìn)程信號(hào)。 491 sa.sa_handler = SIG_IGN; 492 sa.sa_flags = SA_NOCLDWAIT; 493 ; 494 sigaction(SIGINT, & sa, NULL); 495 sigaction(SIGQUIT, & sa, NULL); 496 sigaction(SIGCHLD, & sa, NULL); 497 sigaction(SIGPIPE, & sa, NULL); 498 sigaction(SIGUSR1, & sa, NULL); 499 vtun_syslog(LOG_INFO, " VTUN server ver %s (%s) " , VTUN_VER, 500 vtun.svr_type == VTUN_INETD ? " inetd " : " stand " ); 501 switch (vtun.svr_type) 502 // 判斷sever端的類型獨(dú)立啟動(dòng)守護(hù)進(jìn)程or超級(jí)守護(hù)進(jìn)程。 503 { 504 case VTUN_STAND_ALONE: // 獨(dú)立啟動(dòng)守護(hù)進(jìn)程 505 listener(); // 開始監(jiān)聽 506 break ; 507 // 超級(jí)守護(hù)進(jìn)程沒有socket、bind、listen、accept過程(inetd實(shí)現(xiàn)該過程),而是直接讀寫開始。 508 case VTUN_INETD: // 守護(hù)進(jìn)程 509 connection(sock); 510 break ; 511 } 512 } 513 514 /* *********************************************************** 515 *這里分析獨(dú)立守護(hù)進(jìn)程時(shí)的操作。 516 *原型:void listener(void); 517 *功能:建立socket、bind、listen、accept、connection等。 518 *下一步:connection。 519 ************************************************************ */ 520 void listener( void ) 521 { 522 ... 523 if (generic_addr(&my_addr, &vtun.bind_addr) < 0 ) ... // 設(shè)置監(jiān)聽地址 524 if ((s = socket(AF_INET, SOCK_STREAM, 0 )) == - 1 )... // 創(chuàng)建socket 525 opt = 1 ; 526 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)); 527 if (bind(s, ( struct sockaddr *)&my_addr, sizeof (my_addr)))... // bind 528 if (listen(s, 10 ))... 529 ... // 信號(hào)處理,防止僵尸進(jìn)程 530 while ((!server_term) || (server_term == VTUN_SIG_HUP)) 531 { 532 // 注意這個(gè)循環(huán)條件要和linkfd里的循環(huán)條件結(jié)合起來,這里的循環(huán)條件實(shí)際是掛起狀態(tài)才執(zhí)行該循環(huán), 533 // 而不是沒有結(jié)束循環(huán)或者掛起狀態(tài)二者滿足其一執(zhí)行循環(huán)! 534 if ((s1 = accept(s,( struct sockaddr *)&cl_addr,&opt)) < 0 ).. // accept 535 switch (fork()) // 創(chuàng)建子進(jìn)程 536 { 537 case 0 : 538 close(s); 539 connection(s1); // 和client建立連接,s1是accept返回的已連接套接字描述符(表示此次TCP三次握手連接成功)。 540 break ; 541 case - 1 : 542 vtun_syslog(LOG_ERR, " Couldn't fork() " ); 543 default : 544 close(s1); 545 break ; 546 } 547 } 548 } 549 550 /* *********************************************************** 551 *原型:void connection(int sock); 552 *參數(shù):注意這里的sock是已連接套接字描述符。 553 *功能:建立socket、bind、listen、accept、connection等。 554 *下一步:認(rèn)證成功后開啟隧道即執(zhí)行tunnel。 555 ************************************************************ */ 556 void connection( int sock) // sock是已連接套接字描述符,和server端監(jiān)聽套接字描述符不同。 557 { 558 if (getpeername(sock, ( struct sockaddr *) &cl_addr, &opt))... // 獲取client端地址 559 ... 560 if (getsockname(sock, ( struct sockaddr *) &my_addr, &opt) < 0 )... 561 ... 562 io_init(); 563 if ((host = auth_server(sock))) // 認(rèn)證 564 { 565 ... // 忽略掛起信號(hào) 566 ... // 設(shè)置host的一些成員 567 } 568 tunnel(host); // 開啟隧道。 569 ...... 570 } 571 572 /* *********************************************************************** 573 *補(bǔ)充:在開啟隧道之前先來看看上面函數(shù)涉及的server端認(rèn)證auth_server(sock); 574 *原型:void connection(int sock); 575 *參數(shù):注意這里的sock是已連接套接字描述符。 576 *功能:建立socket、bind、listen、accept、connection等。 577 ************************************************************************ */ 578 struct vtun_host * auth_server( int fd) 579 { 580 ...... 581 while (readn_t(fd, buf, VTUN_MESG_SIZE, vtun.timeout) > 0 ) // 接收來自客戶端的認(rèn)證信息。 582 { 583 ... 584 switch (stage) 585 { 586 case ST_HOST: 587 if (!strcmp(str1, " HOST " )) // 接收來自client的HOST:[host] 588 589 { 590 host = strdup(str2); 591 gen_chal(chal_req); 592 print_p(fd, " OK CHAL: %s\n " , cl2cs(chal_req)); // 發(fā)送請求發(fā)送秘密信息OK CHAL:[chal] 593 stage = ST_CHAL; 594 continue ; 595 } 596 break ; 597 case ST_CHAL: 598 if (!strcmp(str1, " CHAL " )) // 接收密碼 599 600 { 601 if (! cs2cl(str2, chal_res)) 602 break ; 603 if (!(h = find_host(host))) 604 break ; 605 decrypt_chal(chal_res, h-> passwd); 606 if (!memcmp(chal_req, chal_res, VTUN_CHAL_SIZE)) // 與配置文件中密碼比較 607 608 { 609 /* Auth successeful. */ 610 /* Lock host */ 611 if (lock_host(h) < 0 ) 612 { 613 /* Multiple connections are denied */ 614 h = NULL; 615 break ; 616 } 617 print_p(fd, " OK FLAGS: %s\n " , bf2cf(h)); // 發(fā)送成功信息OK FLAGS:[host] 618 } 619 else 620 h = NULL; 621 } 622 break ; 623 } // end switch 624 break ; 625 } // end while 626 ...... 627 } 628 629 /* ************************************************************************ 630 *原型:int tunnel(strucnt vtun_host* host); 631 *參數(shù):host是配置文件中某個(gè)會(huì)話所包含的信息 632 *功能:開啟隧道即初試話設(shè)備讀寫函數(shù),初始化封裝后發(fā)送接收所用協(xié)議。 633 *下一步:linkfd(host); 634 ************************************************************************* */ 635 int tunnel( struct vtun_host * host) 636 { 637 ...... 638 ...... // 接口是否打開 639 if (host-> dev) 640 { ...} // 判斷虛擬設(shè)備類型 641 if (!interface_already_open) // 獲取虛擬設(shè)備文件描述符 642 { 643 ... host->loc_fd = fd[ 0 ]; // 虛擬設(shè)備文件描述符存在host->loc_fd中 644 } 645 switch (host->flags & VTUN_PROT_MASK) // 初始化協(xié)議,tcp還是udp 646 647 { 648 ...... 649 case VTUN_UDP: 650 if ((opt = udp_session(host)) == - 1 ) 651 { .....} // 進(jìn)行udp的socket創(chuàng)建等操作 652 proto_write = udp_write; 653 proto_read = udp_read; 654 } 655 switch ((pid = fork())) 656 { 657 ... 658 } 659 switch (host->flags & VTUN_TYPE_MASK) // 根據(jù)虛擬設(shè)備類型,選擇相應(yīng)虛擬設(shè)備讀寫方式, 660 { 661 ..... 662 case VTUN_TUN: 663 set_title( " %s tun %s " , host-> host, dev); 664 dev_read = tun_read; 665 dev_write = tun_write; 666 break ; 667 } 668 opt = linkfd(host); 669 ....... 670 } 671 672 /* ************************************************************************ 673 *原型:int linkfd(struct vtun_host *host); 674 *參數(shù):host是配置文件中某個(gè)會(huì)話所包含的信息 675 *功能:初始化加密解密壓縮解壓模塊。 676 *下一步:虛擬網(wǎng)卡讀寫以及數(shù)據(jù)的接收發(fā)送lfd_linker(); 677 ************************************************************************* */ 678 int linkfd( struct vtun_host *host) // 鏈接虛擬網(wǎng)卡文件描述符和封裝后用于發(fā)送接收的套接字描述符。 679 { 680 ...... 681 lfd_host = host; 682 old_prio = getpriority(PRIO_PROCESS, 0 ); 683 setpriority(PRIO_PROCESS, 0 , LINKFD_PRIO); 684 ...... // Build modules stack加密壓縮等。 685 ...... // 結(jié)束進(jìn)程等信號(hào)處理函數(shù)。 686 io_init(); 687 lfd_linker(); // 虛擬網(wǎng)卡讀寫,封裝解封以及發(fā)送。 688 ...... // 鬧鐘信號(hào)等。 689 } 690 691 /* ************************************************************************ 692 *原型:int lfd_linker(void) 693 *功能:虛擬網(wǎng)卡讀寫以及數(shù)據(jù)的接收發(fā)送lfd_linker(); 694 *下一步:結(jié)束。 695 ************************************************************************* */ 696 int lfd_linker( void ) 697 { 698 int fd1 = lfd_host->rmt_fd; // fd1是網(wǎng)絡(luò)套接字描述符,也就是最后封裝發(fā)送的那個(gè)套接字描述符。 699 int fd2 = lfd_host->loc_fd; // fd2是虛擬網(wǎng)卡設(shè)備文件描述符。 700 ...... 701 /* Delay sending of first UDP packet over broken NAT routers 702 because we will probably be disconnected. Wait for the remote 703 end to send us something first, and use that connection. */ 704 if (!VTUN_USE_NAT_HACK(lfd_host)) // ? 705 proto_write(fd1, buf, VTUN_ECHO_REQ); 706 ...... 707 while (!linker_term) // while循環(huán)體從虛擬網(wǎng)卡讀數(shù)據(jù)后發(fā)送;將接收的數(shù)據(jù)寫入虛擬網(wǎng)卡。 708 { 709 ...... 710 FD_ZERO(&fdset); // 等待數(shù)據(jù) 711 FD_SET(fd1, & fdset); 712 FD_SET(fd2, & fdset); 713 tv.tv_sec = lfd_host->ka_interval; // 非阻塞超時(shí)時(shí)間 714 tv.tv_usec = 0 ; 715 if ((len = select (maxfd, &fdset, NULL, NULL, &tv)) < 0 ) 716 { ...} // select非阻塞監(jiān)控 717 if (ka_need_verify) // ka_need_verify和信號(hào)處理函數(shù)有關(guān) 718 { 719 ... // No input frames, check connection with ECHO,沒輸入信息,發(fā)送請求信息。 720 } 721 if (send_a_packet) // 默認(rèn)為0不加密 722 { 723 ... // 加密發(fā)送 724 } 725 if (FD_ISSET(fd1,&fdset) && lfd_check_up()) // 網(wǎng)絡(luò)套接字fd1是否有數(shù)據(jù)到達(dá),加解密模塊是否準(zhǔn)備就緒。 726 { 727 .... 728 if ((len = proto_read(fd1, buf)) < = 0 )... // 接收網(wǎng)絡(luò)中數(shù)據(jù)存到buf 729 fl = len & ~VTUN_FSIZE_MASK; // 獲取幀標(biāo)志 730 len = len & VTUN_FSIZE_MASK; 731 if (fl) // fl即frame flags幀標(biāo)志 732 { 733 ... // 判斷是何種幀,即判斷接收到數(shù)據(jù)的類型請求、應(yīng)答、壞幀、關(guān)閉 。 734 } 735 if ((len = lfd_run_up(len, buf, & out )) == - 1 )... // 解密 736 if (len && dev_write(fd2, out , len) < 0 ) 737 { 738 ... // 將網(wǎng)絡(luò)套接字fd1的數(shù)據(jù)寫入虛擬網(wǎng)卡fd2。 739 } 740 } 741 if (FD_ISSET(fd2, &fdset) && lfd_check_down()) // 虛擬網(wǎng)卡中是否有數(shù)據(jù),加解密模塊是否就緒。 742 { 743 if ((len = dev_read(fd2, buf, VTUN_FRAME_SIZE)) < 0 ) 744 { 745 ... // 讀取虛擬網(wǎng)卡中數(shù)據(jù) 746 } 747 if ((len = lfd_run_down(len, buf, & out )) == - 1 )... // 加密 748 if (len && proto_write(fd1, out , len) < 0 ) 749 { 750 ... // 將虛擬網(wǎng)卡fd2中數(shù)據(jù)通過網(wǎng)絡(luò)套接字fd1發(fā)送。 751 } 752 ... 753 } 754 ... 755 } // end while 756 ... 757 proto_write(fd1, buf, VTUN_CONN_CLOSE); // 通知其他終端本終端連接關(guān)閉 758 ... 759 return 0 ; 760 }
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
