首页 > 代码库 > wifidog源码分析 - 初始化阶段
wifidog源码分析 - 初始化阶段
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 socket21 */22 get_clients_from_parent(); //从已运行的wifidog中获取客户端列表,详见 代码片段1.223 24 /*25 * At this point the parent will start destroying itself and the firewall. Let it finish it‘s job before we continue26 */27 28 while (kill(restart_orig_pid, 0) != -1) { //kill已运行的wifidog29 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默认值为-137 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 =http://www.mamicode.com/ 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\n */ 44 while (read(sock, &onechar, 1) == 1) { 45 if (onechar == ‘\n‘) { 46 /* 如果接收到末尾(‘\n‘),则转为‘\0‘ */ 47 onechar = ‘\0‘; 48 } 49 linebuffer[len++] = onechar; 50 51 if (!onechar) { 52 /* 以下将数据转化为t_client结构体添加到客户端列表 */ 53 debug(LOG_DEBUG, "Received from parent: [%s]", linebuffer); 54 running1 = linebuffer; 55 while ((token1 = strsep(&running1, "|")) != NULL) { 56 if (!command) { 57 /* The first token is the command */ 58 command = token1; 59 } 60 else { 61 /* Token1 has something like "foo=bar" */ 62 running2 = token1; 63 key = value =http://www.mamicode.com/ NULL; 64 while ((token2 = strsep(&running2, "=")) != NULL) { 65 if (!key) { 66 key = token2; 67 } 68 else if (!value) { 69 value =http://www.mamicode.com/ token2; 70 } 71 } 72 } 73 74 if (strcmp(command, "CLIENT") == 0) { 75 /* This line has info about a client in the client list */ 76 if (!client) { 77 /* Create a new client struct */ 78 client = safe_malloc(sizeof(t_client)); 79 memset(client, 0, sizeof(t_client)); 80 } 81 } 82 83 if (key && value) { 84 if (strcmp(command, "CLIENT") == 0) { 85 /* Assign the key into the appropriate slot in the connection structure */ 86 if (strcmp(key, "ip") == 0) { 87 client->ip = safe_strdup(value); 88 } 89 else if (strcmp(key, "mac") == 0) { 90 client->mac = safe_strdup(value); 91 } 92 else if (strcmp(key, "token") == 0) { 93 client->token = safe_strdup(value); 94 } 95 else if (strcmp(key, "fw_connection_state") == 0) { 96 client->fw_connection_state = atoi(value); 97 } 98 else if (strcmp(key, "fd") == 0) { 99 client->fd = atoi(value);100 }101 else if (strcmp(key, "counters_incoming") == 0) {102 client->counters.incoming_history = atoll(value);103 client->counters.incoming = client->counters.incoming_history;104 }105 else if (strcmp(key, "counters_outgoing") == 0) {106 client->counters.outgoing_history = atoll(value);107 client->counters.outgoing = client->counters.outgoing_history;108 }109 else if (strcmp(key, "counters_last_updated") == 0) {110 client->counters.last_updated = atol(value);111 }112 else {113 debug(LOG_NOTICE, "I don‘t know how to inherit key [%s] value [%s] from parent", key, value);114 }115 }116 }117 }118 119 /* End of parsing this command */120 if (client) {121 /* Add this client to the client list */122 if (!firstclient) {123 firstclient = client;124 lastclient = firstclient;125 }126 else {127 lastclient->next = client;128 lastclient = client;129 }130 }131 132 /* Clean up */133 command = NULL;134 memset(linebuffer, 0, sizeof(linebuffer));135 len = 0;136 client = NULL;137 }138 }139 140 UNLOCK_CLIENT_LIST();141 debug(LOG_INFO, "Client list downloaded successfully from parent");142 143 close(sock);144 }
代码片段1.3(已启动的wifidog发送客户端列表到新启动的wifidog):
1 //thread_wdctl_handler(void *arg)函数是wifidog创建的控制线程,主要用于与wdctrl进行socket通信,根据wdctrl命令执行不同的操作。这里我们着重讲解的是wdctrl发送restart后wifidog的执行逻辑。 2 static void * 3 thread_wdctl_handler(void *arg) 4 { 5 int fd, 6 done, 7 i; 8 char request[MAX_BUF]; 9 ssize_t read_bytes, 10 len; 11 12 debug(LOG_DEBUG, "Entering thread_wdctl_handler...."); 13 14 fd = (int)arg; 15 16 debug(LOG_DEBUG, "Read bytes and stuff from %d", fd); 17 18 /* 初始化变量 */ 19 read_bytes = 0; 20 done = 0; 21 memset(request, 0, sizeof(request)); 22 23 /* 读取命令 */ 24 while (!done && read_bytes < (sizeof(request) - 1)) { 25 len = read(fd, request + read_bytes, 26 sizeof(request) - read_bytes); //读取wdctrl发送的命令 27 28 /* 判断命令正确性 */ 29 for (i = read_bytes; i < (read_bytes + len); i++) { 30 if (request[i] == ‘\r‘ || request[i] == ‘\n‘) { 31 request[i] = ‘\0‘; 32 done = 1; 33 } 34 } 35 36 /* Increment position */ 37 read_bytes += len; 38 } 39 40 //判断命令 41 if (strncmp(request, "status", 6) == 0) { 42 wdctl_status(fd); 43 } else if (strncmp(request, "stop", 4) == 0) { 44 wdctl_stop(fd); 45 } else if (strncmp(request, "reset", 5) == 0) { 46 wdctl_reset(fd, (request + 6)); 47 } else if (strncmp(request, "restart", 7) == 0) { 48 wdctl_restart(fd); //执行wdctl_restart(int afd)函数 49 } 50 51 if (!done) { 52 debug(LOG_ERR, "Invalid wdctl request."); 53 //关闭套接字 54 shutdown(fd, 2); 55 close(fd); 56 pthread_exit(NULL); 57 } 58 59 debug(LOG_DEBUG, "Request received: [%s]", request); 60 61 //关闭套接字 62 shutdown(fd, 2); 63 close(fd); 64 debug(LOG_DEBUG, "Exiting thread_wdctl_handler...."); 65 66 return NULL; 67 } 68 69 70 //wdctl_restart(int afd)函数详解 71 static void 72 wdctl_restart(int afd) 73 { 74 int sock, 75 fd; 76 char *sock_name; 77 struct sockaddr_un sa_un; 78 s_config * conf = NULL; 79 t_client * client = NULL; 80 char * tempstring = NULL; 81 pid_t pid; 82 ssize_t written; 83 socklen_t len; 84 85 conf = config_get_config(); 86 87 debug(LOG_NOTICE, "Will restart myself"); 88 89 /* 90 * 准备内部连接socket 91 */ 92 memset(&sa_un, 0, sizeof(sa_un)); 93 sock_name = conf->internal_sock; //conf->internal_sock值为"/tmp/wifidog.sock" 94 debug(LOG_DEBUG, "Socket name: %s", sock_name); 95 96 if (strlen(sock_name) > (sizeof(sa_un.sun_path) - 1)) { 97 98 debug(LOG_ERR, "INTERNAL socket name too long"); 99 return;100 }101 102 debug(LOG_DEBUG, "Creating socket");103 sock = socket(PF_UNIX, SOCK_STREAM, 0); //建立内部socket套接字104 105 debug(LOG_DEBUG, "Got internal socket %d", sock);106 107 /* 如果sock_name文件存在,则删除*/108 unlink(sock_name);109 110 debug(LOG_DEBUG, "Filling sockaddr_un");111 strcpy(sa_un.sun_path, sock_name); 112 sa_un.sun_family = AF_UNIX;113 114 debug(LOG_DEBUG, "Binding socket (%s) (%d)", sa_un.sun_path, strlen(sock_name));115 116 117 if (bind(sock, (struct sockaddr *)&sa_un, strlen(sock_name) + sizeof(sa_un.sun_family))) {118 debug(LOG_ERR, "Could not bind internal socket: %s", strerror(errno));119 return;120 }121 122 if (listen(sock, 5)) {123 debug(LOG_ERR, "Could not listen on internal socket: %s", strerror(errno));124 return;125 }126 127 /*128 * socket建立完成,创建子进程129 */130 debug(LOG_DEBUG, "Forking in preparation for exec()...");131 pid = safe_fork();132 if (pid > 0) {133 /* 父进程 */134 135 /* 等待子进程连接此socket :*/136 debug(LOG_DEBUG, "Waiting for child to connect on internal socket");137 len = sizeof(sa_un);138 if ((fd = accept(sock, (struct sockaddr *)&sa_un, &len)) == -1){ //接受连接139 debug(LOG_ERR, "Accept failed on internal socket: %s", strerror(errno));140 close(sock);141 return;142 }143 144 close(sock);145 146 debug(LOG_DEBUG, "Received connection from child. Sending them all existing clients");147 148 /*子进程已经完成连接,发送客户端列表 */149 LOCK_CLIENT_LIST();150 client = client_get_first_client(); //获取第一个客户端151 while (client) {152 /* Send this client */153 safe_asprintf(&tempstring, "CLIENT|ip=%s|mac=%s|token=%s|fw_connection_state=%u|fd=%d|counters_incoming=%llu|counters_outgoing=%llu|counters_last_updated=%lu\n", client->ip, client->mac, client->token, client->fw_connection_state, client->fd, client->counters.incoming, client->counters.outgoing, client->counters.last_updated);154 debug(LOG_DEBUG, "Sending to child client data: %s", tempstring);155 len = 0;156 while (len != strlen(tempstring)) {157 written = write(fd, (tempstring + len), strlen(tempstring) - len); //发送给子进程158 if (written == -1) {159 debug(LOG_ERR, "Failed to write client data to child: %s", strerror(errno));160 free(tempstring);161 break;162 }163 else {164 len += written;165 }166 }167 free(tempstring);168 client = client->next;169 }170 UNLOCK_CLIENT_LIST();171 172 close(fd);173 174 debug(LOG_INFO, "Sent all existing clients to child. Committing suicide!");175 176 shutdown(afd, 2);177 close(afd);178 179 180 wdctl_stop(afd);181 }182 else {183 /* 子进程,先关闭资源 */184 close(wdctl_socket_server);185 close(icmp_fd);186 close(sock);187 shutdown(afd, 2);188 close(afd);189 debug(LOG_NOTICE, "Re-executing myself (%s)", restartargv[0]);190 191 setsid();192 execvp(restartargv[0], restartargv); //执行外部命令,这里重新启动wifidog193 194 debug(LOG_ERR, "I failed to re-execute myself: %s", strerror(errno));195 debug(LOG_ERR, "Exiting without cleanup");196 exit(1);197 }198 }
wifidog源码分析 - 初始化阶段
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。