Wifidog是一个linux下开源的认证网关软件,它主要用于配合认证服务器实现无线路由器的认证放行功能。
wifidog是一个后台的服务程序,可以通过wdctrl命令对wifidog主程序进行控制。
本文解释wifidog在启动阶段所做的初始化主要工作(代码片段1.1)
- 初始化配置(先将配置结构体初始化为默认值,在读取配置文件修改配置结构体)
- 初始化已连接客户端列表(如果是通过wdctrl重启wifidog,将会读取之前wifidog的已连接客户端列表 代码片段1.2 代码片段1.3)
- 如无特殊情况,分离进程,建立守护进程 (代码片段1.1)
- 添加多个http请求回调函数(包括404错误回调函数) (见之后章节)
- 摧毁删除现有的iptables路由表规则 (见之后章节)
- 建立新的iptables路由表规则 (见之后章节)
- 启动多个功能线程 (见之后章节)
- 循环等待客户端连接 (见之后章节)
代码片段1.1
1 int main(int argc, char **argv) { 2 3 s_config *config = config_get_config(); //就是返回全局变量config结构体的地址 4 config_init(); //初始化全局变量config结构体为默认值 5 6 parse_commandline(argc, argv); //根据传入参数执行操作(如果参数有-x则会设置restart_orig_pid为已运行的wifidog的pid) 7 8 /* Initialize the config */ 9 config_read(config->configfile); //根据配置文件设置全局变量config结构体 10 config_validate(); //判断GatewayInterface和AuthServer是否为空,空则无效退出程序。 11 12 /* Initializes the linked list of connected clients */ 13 client_list_init(); //将已连接客户端链表置空。 14 15 /* Init the signals to catch chld/quit/etc */ 16 init_signals(); //初始化一些信号 17 18 if (restart_orig_pid) { //用于restart,如果有已运行的wifidog,先会kill它 19 /* 20 * We were restarted and our parent is waiting for us to talk to it over the socket 21 */ 22 get_clients_from_parent(); //从已运行的wifidog中获取客户端列表,详见 代码片段1.2 23 24 /* 25 * At this point the parent will start destroying itself and the firewall. Let it finish it's job before we continue 26 */ 27 28 while (kill(restart_orig_pid, 0) != -1) { //kill已运行的wifidog 29 debug(LOG_INFO, "Waiting for parent PID %d to die before continuing loading", restart_orig_pid); 30 sleep(1); 31 } 32 33 debug(LOG_INFO, "Parent PID %d seems to be dead. Continuing loading."); 34 } 35 36 if (config->daemon) { //创建为守护进程,config->daemon默认值为-1 37 38 debug(LOG_INFO, "Forking into background"); 39 40 switch(safe_fork()) { 41 case 0: /* child */ 42 setsid(); //创建新会话,脱离此终端,实现守护进程 43 append_x_restartargv(); 44 main_loop(); //进入主循环(核心代码在此)。 45 break; 46 47 default: /* parent */ 48 exit(0); 49 break; 50 } 51 } 52 else { 53 append_x_restartargv(); 54 main_loop(); 55 } 56 57 return(0); /* never reached */ 58 }
代码片段1.2(获取已启动的wifidog的客户端列表):
此段代表描述了新启动的wifidog如何从已启动的wifidog程序中获取已连接的客户端列表。发送端见 代码片段1.3
1 void get_clients_from_parent(void) { 2 int sock; 3 struct sockaddr_un sa_un; 4 s_config * config = NULL; 5 char linebuffer[MAX_BUF]; 6 int len = 0; 7 char *running1 = NULL; 8 char *running2 = NULL; 9 char *token1 = NULL; 10 char *token2 = NULL; 11 char onechar; 12 char *command = NULL; 13 char *key = NULL; 14 char *value = NULL; 15 t_client * client = NULL; 16 t_client * lastclient = NULL; 17 18 config = config_get_config(); 19 20 debug(LOG_INFO, "Connecting to parent to download clients"); 21 22 /* 连接socket */ 23 sock = socket(AF_UNIX, SOCK_STREAM, 0); 24 memset(&sa_un, 0, sizeof(sa_un)); 25 sa_un.sun_family = AF_UNIX; 26 strncpy(sa_un.sun_path, config->internal_sock, (sizeof(sa_un.sun_path) - 1)); //config->internal_sock的值为"/tmp/wifidog.sock" 27 28 /* 连接已启动的wifidog */ 29 if (connect(sock, (struct sockaddr *)&sa_un, strlen(sa_un.sun_path) + sizeof(sa_un.sun_family))) { 30 debug(LOG_ERR, "Failed to connect to parent (%s) - client list not downloaded", strerror(errno)); 31 return; 32 } 33 34 debug(LOG_INFO, "Connected to parent. Downloading clients"); 35 36 LOCK_CLIENT_LIST(); 37 38 command = NULL; 39 memset(linebuffer, 0, sizeof(linebuffer)); 40 len = 0; 41 client = NULL; 42 /* 接收数据,逐个字符接收 */ 43 /* 数据包格式为 CLIENT|ip=%s|mac=%s|token=%s|fw_connection_state=%u|fd=%d|counters_incoming=%llu|counters_outgoing=%llu|counters_last_updated=%lu */ 44 while (read(sock, &onechar, 1) == 1) { 45 if (onechar == ' ') { 46 /* 如果接收到末尾(' '),则转为' ' */ 47 onechar = '