1 /* **************************************** 2 * Name : Vtun 源码详细分析 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是一个短小精悍的开源VPN项目, 9 * 这里分析了其客户端和服务器的源码。 10 * 2.vtun源码可以从下面网址下载 11 * http://vtun.sourceforge.net/ 12 **************************************** */ 13 14 15 /* ********************************************** client端代码执行基本流程分析 *********************************************** */ 16 /* *************************************************************** 17 *原型:int main(int argc, char* argv[], char* env[]); 18 *功能:初始化操作,确定是client端还是server端。 19 *下一步:根据命令行参数选择执行client或者server分支,先分析client。 20 **************************************************************** */ 21 int main( int argc, char *argv[], char * env[]) 22 { 23 ...... 24 ...... // 初始化vtun结构体。 25 while ((opt = getopt(argc, argv, " misf:P:L:t:npq " )) != EOF) // 获取命令行参数并进行相应操作。 26 { 27 ...... 28 } 29 reread_config( 0 ); // 读配置文件。 30 ...... 31 clear_nat_hack_flags(svr); // 清除另一方的nat_hack标志。 32 if (!svr) // 根据命令行参数进行客户端配置。 33 { 34 ...... 35 hst = argv[optind++]; // vtund server [ip]的第二个参数给hst,这个参数是服务器给客户端定义的名字。 36 host = find_host(hst); // hst是命令行参数,host是配置文件中的对应该参数的会话信息。 37 ...... 38 } 39 vtun.svr_name = strdup(argv[optind]); // vtund server [ip]的ip给vtun.srv_name 40 ...... // 如果vtun结构体的一些成员没有被初试话,则赋予默认值。 41 switch (vtun.svr_type) // 判断vtun的类型,VTUN_STAND_ALONE VTUN_INETD. 42 { 43 ...... 44 } 45 if (daemon) // 是否要创建守护进程 46 { 47 if (dofork && fork()) // 当命令行设置为超级守护进程时不执行该操作。 48 ... 49 } 50 if (svr) 51 { 52 memset(&sa, 0 , sizeof (sa)); // 挂起时读取配置文件。 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(); // 将当前pid写入文件中 59 60 server(sock); // 执行服务器操作 61 } 62 else 63 { 64 init_title(argc, argv, env, " vtund[c]: " ); 65 client(host); // 执行客户端操作,host就是从配置文件读取出的对应命令行参数会话名的信息。 66 } 67 ...... 68 } 69 70 71 /* *********************************************************** 72 *原型:void client(struct vtun_host *host); 73 *参数:host是从配置文件中读出某个会话名所包含的信息。 74 *功能:建立socket以及bind、connect、select等,认证暨建立隧道。 75 *下一步:认证auth_client(s, host)后再执行tunnel(host)即开启隧道。 76 ************************************************************ */ 77 void client( struct vtun_host *host) // host参数是main函数中传递的配置文件中的会话信息。 78 { 79 ...... 80 ...... // 结束,挂起等信号处理函数。 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)) // 认证,也就是隧道建立过程 103 { 104 ... 105 client_term = tunnel(host); // 开启隧道,host是配置文件相应会话信息。 106 ... 107 } 108 else 109 { 110 ...... // 认证失败 111 } 112 } 113 close(s); 114 free_sopt(&host-> sopt); 115 } // end while 116 ...... 117 } 118 119 /* *************************************************************************** 120 *补充:在执行tunnel(host)前先来看看上面client函数中的connect_t函数。 121 *原型:int connect_t(int s, struct sockaddr *svr, time_t timeout); 122 *参数:s是client中建立的套接字描述符。 123 *功能:与服务器建立连接。 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 )... // 设置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 *补充:在执行tunnel(host)前再来看看上面client函数中的auth_client. 152 *原型:int auth_client(int fd, struct vtun_host *host); 153 *参数:fd是client端创建的套接字描述符,host是配置文件中某个会话所包含的信息 154 *功能:认证过程,也是隧道建立过程。 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 ) // 读取服务器发来认证信息。 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发送HOST:[host]。 170 continue ; 171 } 172 break ; 173 case ST_HOST: 174 if (!strncmp(buf, " OK " , 2 ) && cs2cl(buf, chal)) // 接收到请求发送密码信息 OK CHAL:[chal] 175 { 176 stage = ST_CHAL; 177 encrypt_chal(chal, host-> passwd); 178 print_p(fd, " CHAL: %s\n " , cl2cs(chal)); // 发送配置文件中本次会话密码CHAL:[chal] 179 continue ; 180 } 181 break ; 182 case ST_CHAL: 183 if (!strncmp(buf, " OK " , 2 ) && cf2bf(buf, host)) // 接收到OK FLAGS:[host]认证成功信息 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 *参数:host是配置文件中某个会话所包含的信息 195 *功能:开启隧道即初试话设备读写函数,初始化封装后发送接收所用协议。 196 *下一步:linkfd(host); 197 ************************************************************************* */ 198 int tunnel( struct vtun_host * host) 199 { 200 ...... 201 if ((host->persist == VTUN_PERSIST_KEEPIF) && (host->loc_fd >= 0 )) // 接口是否已经打开 202 interface_already_open = 1 ; 203 if (host->dev){...} // 判断虚拟设备类型 204 if (!interface_already_open) // 虚拟网卡没有打开,则打开之 205 206 ... 207 switch (host->flags & VTUN_TYPE_MASK) 208 { 209 ... 210 case VTUN_TUN: 211 if ((fd[ 0 ]=tun_open(dev)) < 0 ) // 打开虚拟网卡,获取描述符 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 ]; // 虚拟设备文件描述符存在host->loc_fd中 219 } 220 switch (host->flags & VTUN_PROT_MASK) // 初始化协议,tcp还是udp 221 { 222 ...... 223 case VTUN_UDP: 224 if ((opt = udp_session(host)) == - 1 ){.....} // 进行udp的socket创建等操作 225 proto_write = udp_write; 226 proto_read = udp_read; 227 } 228 switch ((pid = fork())){...} // 建立子进程 229 switch (host->flags & VTUN_TYPE_MASK) // 根据虚拟设备类型,选择相应虚拟设备读写方式 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 *补充:在linkfd之前,我们先来看看tunnel函数中udp_session. 244 *原型:int udp_session(struct vtun_host *host); 245 *参数:host是配置文件中某个会话所包含的信息。 246 *功能:udp socket的创建、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 *参数:host是配置文件中某个会话所包含的信息。 334 *功能:初始化加密解密压缩解压模块。 335 *下一步:虚拟网卡读写以及数据的接收发送lfd_linker(); 336 ************************************************************************* */ 337 int linkfd( struct vtun_host * host) 338 { 339 ...... 340 lfd_host = host; 341 old_prio = getpriority(PRIO_PROCESS, 0 ); // 取得进程优先级 342 setpriority(PRIO_PROCESS, 0 , LINKFD_PRIO); 343 ...... // Build modules stack加密压缩等。 344 ...... // 结束进程等信号处理函数。 345 io_init(); 346 lfd_linker(); // 虚拟网卡读写,封装解封以及发送。 347 ...... // 闹钟信号等。 348 } 349 350 /* ************************************************************************ 351 *原型:int lfd_linker(void) 352 *功能:虚拟网卡读写以及数据的接收发送lfd_linker(); 353 *下一步:结束。 354 ************************************************************************* */ 355 int lfd_linker( void ) 356 { 357 int fd1 = lfd_host->rmt_fd; // fd1是网络套接字描述符,也就是最后封装发送的那个套接字描述符。 358 int fd2 = lfd_host->loc_fd; // fd2是虚拟网卡设备文件描述符。 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循环体从虚拟网卡读数据后发送;将接收的数据写入虚拟网卡。 367 { 368 ...... 369 FD_ZERO(&fdset); // 等待数据 370 FD_SET(fd1, & fdset); 371 FD_SET(fd2, & fdset); 372 tv.tv_sec = lfd_host->ka_interval; // 非阻塞超时时间 373 tv.tv_usec = 0 ; 374 if ((len = select (maxfd, &fdset, NULL, NULL, &tv)) < 0 ) 375 { 376 ....,. 377 } // select非阻塞监控 378 if (ka_need_verify) // ka_need_verify和信号处理函数有关 379 { 380 ... // No input frames, check connection with ECHO,没输入信息,发送请求信息。 381 } 382 if (send_a_packet) // 默认为0不加密 383 { 384 ... // 加密发送 385 } 386 if (FD_ISSET(fd1,&fdset) && lfd_check_up()) // 网络套接字fd1是否有数据到达,加解密模块是否准备就绪。 387 { 388 .... 389 if ((len = proto_read(fd1, buf)) <= 0 )... // 接收网络中数据存到buf 390 fl = len & ~VTUN_FSIZE_MASK; // 获取帧标志 391 len = len & VTUN_FSIZE_MASK; 392 if (fl) // fl即frame flags帧标志 393 { 394 ... // 判断是何种帧,即判断接收到数据的类型请求、应答、坏帧、关闭 。 395 } 396 if ((len = lfd_run_up(len, buf, & out )) == - 1 )... // 解密 397 if (len && dev_write(fd2, out , len) < 0 ) 398 { 399 ... // 将网络套接字fd1的数据写入虚拟网卡fd2。 400 } 401 } 402 if (FD_ISSET(fd2, &fdset) && lfd_check_down()) // 虚拟网卡中是否有数据,加解密模块是否就绪。 403 { 404 if ((len = dev_read(fd2, buf, VTUN_FRAME_SIZE)) < 0 ) 405 { 406 ... // 读取虚拟网卡中数据 407 } 408 if ((len = lfd_run_down(len, buf, & out )) == - 1 )... // 加密 409 if (len && proto_write(fd1, out , len) < 0 ) 410 { 411 ... // 将虚拟网卡fd2中数据通过网络套接字fd1发送。 412 } 413 ... 414 } 415 ... 416 } // end while 417 ... 418 proto_write(fd1, buf, VTUN_CONN_CLOSE); // 通知其他终端本终端连接关闭 419 ... 420 return 0 ; 421 } 422 423 424 425 426 /* ********************************************** server端代码执行基本流程分析 *********************************************** */ 427 /* *************************************************************** 428 *原型:int main(int argc, char* argv[], char* env[]); 429 *功能:初始化操作,确定是client端还是server端。 430 *下一步:根据命令行参数选择执行client或者server分支,分析server。 431 **************************************************************** */ 432 int main( int argc, char *argv[], char * env[]) 433 { 434 ...... 435 ...... // 初始化vtun结构体。 436 while ((opt = getopt(argc, argv, " misf:P:L:t:npq " )) != EOF) // 获取命令行参数并进行相应操作。 437 { 438 ...... 439 } 440 reread_config( 0 ); // 读配置文件。 441 ...... 442 clear_nat_hack_flags(svr); 443 if (!svr) // 如果不是服务器,再根据命令行参数进行配置。 444 { 445 ...... 446 hst = argv[optind++]; // vtund server [ip]的第二个参数给hst,这个参数是服务器给客户端定义的名字。 447 host = find_host(hst); // hst是命令行参数,host是配置文件中的对应该参数的会话信息。 448 ...... 449 } 450 vtun.svr_name = strdup(argv[optind]); // vtund server [ip]的ip给vtun.srv_name 451 ...... // 如果vtun结构体的一些成员没有被初试话,则赋予默认值。 452 switch (vtun.svr_type) // 判断vtun的类型,VTUN_STAND_ALONE VTUN_INETD. 453 { 454 ...... 455 } 456 if (daemon) // 是否要创建守护进程 457 { 458 if (dofork && fork()) 459 ... 460 } 461 if (svr) 462 { 463 memset(&sa, 0 , sizeof (sa)); // 挂起时读取配置文件。 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); // 执行服务器操作 473 } 474 else 475 { 476 init_title(argc, argv, env, " vtund[c]: " ); 477 client(host); // 执行客户端操作,host就是从配置文件读取出的对应命令行参数会话名的信息。 478 } 479 ...... 480 } 481 482 /* *********************************************************** 483 *原型:void server(int sock); 484 *参数:sock = 0. 485 *功能:建立socket以及bind、connect、select等,认证暨建立隧道。 486 *下一步:根据守护进程类型选择执行listener还是connection。 487 ************************************************************ */ 488 void server( int sock) 489 { 490 struct sigaction sa; // 忽略接收进程信号。 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端的类型独立启动守护进程or超级守护进程。 503 { 504 case VTUN_STAND_ALONE: // 独立启动守护进程 505 listener(); // 开始监听 506 break ; 507 // 超级守护进程没有socket、bind、listen、accept过程(inetd实现该过程),而是直接读写开始。 508 case VTUN_INETD: // 守护进程 509 connection(sock); 510 break ; 511 } 512 } 513 514 /* *********************************************************** 515 *这里分析独立守护进程时的操作。 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 ) ... // 设置监听地址 524 if ((s = socket(AF_INET, SOCK_STREAM, 0 )) == - 1 )... // 创建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 ... // 信号处理,防止僵尸进程 530 while ((!server_term) || (server_term == VTUN_SIG_HUP)) 531 { 532 // 注意这个循环条件要和linkfd里的循环条件结合起来,这里的循环条件实际是挂起状态才执行该循环, 533 // 而不是没有结束循环或者挂起状态二者满足其一执行循环! 534 if ((s1 = accept(s,( struct sockaddr *)&cl_addr,&opt)) < 0 ).. // accept 535 switch (fork()) // 创建子进程 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 *参数:注意这里的sock是已连接套接字描述符。 553 *功能:建立socket、bind、listen、accept、connection等。 554 *下一步:认证成功后开启隧道即执行tunnel。 555 ************************************************************ */ 556 void connection( int sock) // sock是已连接套接字描述符,和server端监听套接字描述符不同。 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))) // 认证 564 { 565 ... // 忽略挂起信号 566 ... // 设置host的一些成员 567 } 568 tunnel(host); // 开启隧道。 569 ...... 570 } 571 572 /* *********************************************************************** 573 *补充:在开启隧道之前先来看看上面函数涉及的server端认证auth_server(sock); 574 *原型:void connection(int sock); 575 *参数:注意这里的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 ) // 接收来自客户端的认证信息。 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)); // 发送请求发送秘密信息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)); // 发送成功信息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 *参数:host是配置文件中某个会话所包含的信息 632 *功能:开启隧道即初试话设备读写函数,初始化封装后发送接收所用协议。 633 *下一步:linkfd(host); 634 ************************************************************************* */ 635 int tunnel( struct vtun_host * host) 636 { 637 ...... 638 ...... // 接口是否打开 639 if (host-> dev) 640 { ...} // 判断虚拟设备类型 641 if (!interface_already_open) // 获取虚拟设备文件描述符 642 { 643 ... host->loc_fd = fd[ 0 ]; // 虚拟设备文件描述符存在host->loc_fd中 644 } 645 switch (host->flags & VTUN_PROT_MASK) // 初始化协议,tcp还是udp 646 647 { 648 ...... 649 case VTUN_UDP: 650 if ((opt = udp_session(host)) == - 1 ) 651 { .....} // 进行udp的socket创建等操作 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) // 根据虚拟设备类型,选择相应虚拟设备读写方式, 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 *参数:host是配置文件中某个会话所包含的信息 675 *功能:初始化加密解密压缩解压模块。 676 *下一步:虚拟网卡读写以及数据的接收发送lfd_linker(); 677 ************************************************************************* */ 678 int linkfd( struct vtun_host *host) // 链接虚拟网卡文件描述符和封装后用于发送接收的套接字描述符。 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 ...... // 结束进程等信号处理函数。 686 io_init(); 687 lfd_linker(); // 虚拟网卡读写,封装解封以及发送。 688 ...... // 闹钟信号等。 689 } 690 691 /* ************************************************************************ 692 *原型:int lfd_linker(void) 693 *功能:虚拟网卡读写以及数据的接收发送lfd_linker(); 694 *下一步:结束。 695 ************************************************************************* */ 696 int lfd_linker( void ) 697 { 698 int fd1 = lfd_host->rmt_fd; // fd1是网络套接字描述符,也就是最后封装发送的那个套接字描述符。 699 int fd2 = lfd_host->loc_fd; // fd2是虚拟网卡设备文件描述符。 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循环体从虚拟网卡读数据后发送;将接收的数据写入虚拟网卡。 708 { 709 ...... 710 FD_ZERO(&fdset); // 等待数据 711 FD_SET(fd1, & fdset); 712 FD_SET(fd2, & fdset); 713 tv.tv_sec = lfd_host->ka_interval; // 非阻塞超时时间 714 tv.tv_usec = 0 ; 715 if ((len = select (maxfd, &fdset, NULL, NULL, &tv)) < 0 ) 716 { ...} // select非阻塞监控 717 if (ka_need_verify) // ka_need_verify和信号处理函数有关 718 { 719 ... // No input frames, check connection with ECHO,没输入信息,发送请求信息。 720 } 721 if (send_a_packet) // 默认为0不加密 722 { 723 ... // 加密发送 724 } 725 if (FD_ISSET(fd1,&fdset) && lfd_check_up()) // 网络套接字fd1是否有数据到达,加解密模块是否准备就绪。 726 { 727 .... 728 if ((len = proto_read(fd1, buf)) < = 0 )... // 接收网络中数据存到buf 729 fl = len & ~VTUN_FSIZE_MASK; // 获取帧标志 730 len = len & VTUN_FSIZE_MASK; 731 if (fl) // fl即frame flags帧标志 732 { 733 ... // 判断是何种帧,即判断接收到数据的类型请求、应答、坏帧、关闭 。 734 } 735 if ((len = lfd_run_up(len, buf, & out )) == - 1 )... // 解密 736 if (len && dev_write(fd2, out , len) < 0 ) 737 { 738 ... // 将网络套接字fd1的数据写入虚拟网卡fd2。 739 } 740 } 741 if (FD_ISSET(fd2, &fdset) && lfd_check_down()) // 虚拟网卡中是否有数据,加解密模块是否就绪。 742 { 743 if ((len = dev_read(fd2, buf, VTUN_FRAME_SIZE)) < 0 ) 744 { 745 ... // 读取虚拟网卡中数据 746 } 747 if ((len = lfd_run_down(len, buf, & out )) == - 1 )... // 加密 748 if (len && proto_write(fd1, out , len) < 0 ) 749 { 750 ... // 将虚拟网卡fd2中数据通过网络套接字fd1发送。 751 } 752 ... 753 } 754 ... 755 } // end while 756 ... 757 proto_write(fd1, buf, VTUN_CONN_CLOSE); // 通知其他终端本终端连接关闭 758 ... 759 return 0 ; 760 }