wifidogソース分析-クライアント検出スレッド
37613 ワード
引用する
wifidogが起動すると、スレッド(thread_client_timeout_check)が起動してクライアントリストを維持します.具体的には、wifidogはクライアントリストの各クライアントがオンラインかどうかをタイミング的に検出しなければなりません.wifidogは、iptablesでクライアントの出入り総流量をタイミング的に取得してクライアント時間を更新する2つの方法でクライアントのオンライン状況を検出します.最近の更新時間で判断する(新しい出入り流量があればクライアント時間を更新し、その後最新のクライアント時間と現在の時間で判断する)ことで、クエリー認証サーバ、認証サーバの返却情報により判断する(クライアントIPとステータス要求を認証サーバに送信すると、認証サーバはクライアントがオンラインであるか否かを返す.この場合、クライアントが認証サーバ上で正常に登録されている場合に用いる).
thread_client_timeout_check
このスレッド実行関数は、クライアントリストを維持するために使用されます.このスレッドはwhile(1)サイクルであり、1つのプロファイル内のcheckinterval間隔ごとにfw_を実行します.sync_with_authserver関数、コアコードはfw_にありますsync_with_authserver関数では、まず具体的なコードを使用します.
コードフラグメント1.1
fw_sync_with_authserver
この関数はこのスレッドの核心関数であり、クライアントリストを維持することはここで、まずクライアントリストを遍歴し、iptablesを通じて各クライアントリストの出入り流量を取得し、その後、出口流量(入口流量は判断せず、詳細はコード断片1.3を参照)に基づいて、より新しいクライアントの最近の更新時間(last_updated)を更新する.その後、各クライアントの最近の更新時間を現在時間と比較し、タイムアウト間隔を超えるとオフラインと判断し、タイムアウトしない場合は認証サーバからこのクライアントステータスを取得し、オンラインかどうかを判断します.具体的な流れは以下の通りです.はクライアントの出入り口流量を更新し、出口流量に応じて各クライアントの最近の更新時間 を更新する.クライアントがタイムアウトすると、クライアントリストから削除され、iptablesを介してネットワークへのアクセスが禁止され、認証サーバにこのクライアントのオフライン が通知される.クライアントがタイムアウトすることなく認証サーバからこのクライアント情報を取得し、認証サーバのオフライン を通過するか否かを判断する.
コードフラグメント1.2
コードフラグメント1.3
wifidogが起動すると、スレッド(thread_client_timeout_check)が起動してクライアントリストを維持します.具体的には、wifidogはクライアントリストの各クライアントがオンラインかどうかをタイミング的に検出しなければなりません.wifidogは、iptablesでクライアントの出入り総流量をタイミング的に取得してクライアント時間を更新する2つの方法でクライアントのオンライン状況を検出します.最近の更新時間で判断する(新しい出入り流量があればクライアント時間を更新し、その後最新のクライアント時間と現在の時間で判断する)ことで、クエリー認証サーバ、認証サーバの返却情報により判断する(クライアントIPとステータス要求を認証サーバに送信すると、認証サーバはクライアントがオンラインであるか否かを返す.この場合、クライアントが認証サーバ上で正常に登録されている場合に用いる).
thread_client_timeout_check
このスレッド実行関数は、クライアントリストを維持するために使用されます.このスレッドはwhile(1)サイクルであり、1つのプロファイル内のcheckinterval間隔ごとにfw_を実行します.sync_with_authserver関数、コアコードはfw_にありますsync_with_authserver関数では、まず具体的なコードを使用します.
コードフラグメント1.1
1 void
2 thread_client_timeout_check(const void *arg)
3 {
4 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
5 pthread_mutex_t cond_mutex = PTHREAD_MUTEX_INITIALIZER;
6 struct timespec timeout;
7
8 while (1) {
9 /* */
10 timeout.tv_sec = time(NULL) + config_get_config()->checkinterval;
11 timeout.tv_nsec = 0;
12
13 /* pthread_cond_timedwait */
14 pthread_mutex_lock(&cond_mutex);
15
16 /* */
17 pthread_cond_timedwait(&cond, &cond_mutex, &timeout);
18
19 /* */
20 pthread_mutex_unlock(&cond_mutex);
21
22 debug(LOG_DEBUG, "Running fw_counter()");
23
24 /* */
25 fw_sync_with_authserver();
26 }
27 }
fw_sync_with_authserver
この関数はこのスレッドの核心関数であり、クライアントリストを維持することはここで、まずクライアントリストを遍歴し、iptablesを通じて各クライアントリストの出入り流量を取得し、その後、出口流量(入口流量は判断せず、詳細はコード断片1.3を参照)に基づいて、より新しいクライアントの最近の更新時間(last_updated)を更新する.その後、各クライアントの最近の更新時間を現在時間と比較し、タイムアウト間隔を超えるとオフラインと判断し、タイムアウトしない場合は認証サーバからこのクライアントステータスを取得し、オンラインかどうかを判断します.具体的な流れは以下の通りです.
コードフラグメント1.2
1 void
2 fw_sync_with_authserver(void)
3 {
4 t_authresponse authresponse;
5 char *token, *ip, *mac;
6 t_client *p1, *p2;
7 unsigned long long incoming, outgoing;
8 s_config *config = config_get_config();
9
10 /* iptables , 1.3 */
11 if (-1 == iptables_fw_counters_update()) {
12 debug(LOG_ERR, "Could not get counters from firewall!");
13 return;
14 }
15
16 LOCK_CLIENT_LIST();
17
18 /* */
19 for (p1 = p2 = client_get_first_client(); NULL != p1; p1 = p2) {
20 p2 = p1->next;
21
22 ip = safe_strdup(p1->ip);
23 token = safe_strdup(p1->token);
24 mac = safe_strdup(p1->mac);
25 outgoing = p1->counters.outgoing;
26 incoming = p1->counters.incoming;
27
28 UNLOCK_CLIENT_LIST();
29 /* ping , */
30 icmp_ping(ip);
31 /* , wifidog */
32 if (config->auth_servers != NULL) {
33 auth_server_request(&authresponse, REQUEST_TYPE_COUNTERS, ip, mac, token, incoming, outgoing);
34 }
35 LOCK_CLIENT_LIST();
36
37 /* IP,MAC */
38 if (!(p1 = client_list_find(ip, mac))) {
39 debug(LOG_ERR, "Node %s was freed while being re-validated!", ip);
40 } else {
41 time_t current_time=time(NULL);
42 debug(LOG_INFO, "Checking client %s for timeout: Last updated %ld (%ld seconds ago), timeout delay %ld seconds, current time %ld, ",
43 p1->ip, p1->counters.last_updated, current_time-p1->counters.last_updated, config->checkinterval * config->clienttimeout, current_time);
44 /* ,( + <= ) , */
45 if (p1->counters.last_updated +
46 (config->checkinterval * config->clienttimeout)
47 <= current_time) {
48 debug(LOG_INFO, "%s - Inactive for more than %ld seconds, removing client and denying in firewall",
49 p1->ip, config->checkinterval * config->clienttimeout);
50 /* iptables */
51 fw_deny(p1->ip, p1->mac, p1->fw_connection_state);
52 /* */
53 client_list_delete(p1);
54
55 /* */
56 if (config->auth_servers != NULL) {
57 UNLOCK_CLIENT_LIST();
58 auth_server_request(&authresponse, REQUEST_TYPE_LOGOUT, ip, mac, token, 0, 0);
59 LOCK_CLIENT_LIST();
60 }
61 } else {
62 /* */
63 if (config->auth_servers != NULL) {
64 /* */
65 switch (authresponse.authcode) {
66 /* ( ) */
67 case AUTH_DENIED:
68 debug(LOG_NOTICE, "%s - Denied. Removing client and firewall rules", p1->ip);
69 fw_deny(p1->ip, p1->mac, p1->fw_connection_state);
70 client_list_delete(p1);
71 break;
72
73 case AUTH_VALIDATION_FAILED:
74 debug(LOG_NOTICE, "%s - Validation timeout, now denied. Removing client and firewall rules", p1->ip);
75 fw_deny(p1->ip, p1->mac, p1->fw_connection_state);
76 client_list_delete(p1);
77 break;
78
79 /* ( ) */
80 case AUTH_ALLOWED:
81 if (p1->fw_connection_state != FW_MARK_KNOWN) {
82 debug(LOG_INFO, "%s - Access has changed to allowed, refreshing firewall and clearing counters", p1->ip);
83 if (p1->fw_connection_state != FW_MARK_PROBATION) {
84 p1->counters.incoming = p1->counters.outgoing = 0;
85 }
86 else {
87
88 debug(LOG_INFO, "%s - Skipped clearing counters after all, the user was previously in validation", p1->ip);
89 }
90 p1->fw_connection_state = FW_MARK_KNOWN;
91 fw_allow(p1->ip, p1->mac, p1->fw_connection_state);
92 }
93 break;
94
95 case AUTH_VALIDATION:
96 debug(LOG_INFO, "%s - User in validation period", p1->ip);
97 break;
98
99 case AUTH_ERROR:
100 debug(LOG_WARNING, "Error communicating with auth server - leaving %s as-is for now", p1->ip);
101 break;
102
103 default:
104 debug(LOG_ERR, "I do not know about authentication code %d", authresponse.authcode);
105 break;
106 }
107 }
108 }
109 }
110
111 free(token);
112 free(ip);
113 free(mac);
114 }
115 UNLOCK_CLIENT_LIST();
116 }
コードフラグメント1.3
1 int
2 iptables_fw_counters_update(void)
3 {
4 FILE *output;
5 char *script,
6 ip[16],
7 rc;
8 unsigned long long int counter;
9 t_client *p1;
10 struct in_addr tempaddr;
11
12 /* iptables */
13 safe_asprintf(&script, "%s %s", "iptables", "-v -n -x -t mangle -L " TABLE_WIFIDOG_OUTGOING);
14 iptables_insert_gateway_id(&script);
15 output = popen(script, "r");
16 free(script);
17 if (!output) {
18 debug(LOG_ERR, "popen(): %s", strerror(errno));
19 return -1;
20 }
21
22 /* iptables */
23 while (('
' != fgetc(output)) && !feof(output))
24 ;
25 while (('
' != fgetc(output)) && !feof(output))
26 ;
27 while (output && !(feof(output))) {
28 rc = fscanf(output, "%*s %llu %*s %*s %*s %*s %*s %15[0-9.] %*s %*s %*s %*s %*s %*s", &counter, ip);
29 //rc = fscanf(output, "%*s %llu %*s %*s %*s %*s %*s %15[0-9.] %*s %*s %*s %*s %*s 0x%*u", &counter, ip);
30 if (2 == rc && EOF != rc) {
31 if (!inet_aton(ip, &tempaddr)) {
32 debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip);
33 continue;
34 }
35 debug(LOG_DEBUG, "Read outgoing traffic for %s: Bytes=%llu", ip, counter);
36 LOCK_CLIENT_LIST();
37 /* ip */
38 if ((p1 = client_list_find_by_ip(ip))) {
39 /* ( (outgoing) + wifidog (outgoing_history) < iptables ) */
40 if ((p1->counters.outgoing - p1->counters.outgoing_history) < counter) {
41 /* (outgoing) wifidog (outgoing_history) + iptables (counter) */
42 p1->counters.outgoing = p1->counters.outgoing_history + counter;
43 /* */
44 p1->counters.last_updated = time(NULL);
45 debug(LOG_DEBUG, "%s - Updated counter.outgoing to %llu bytes. Updated last_updated to %d", ip, counter, p1->counters.last_updated);
46 }
47 } else {
48 debug(LOG_ERR, "Could not find %s in client list", ip);
49 }
50 UNLOCK_CLIENT_LIST();
51 }
52 }
53 pclose(output);
54
55 /* iptables , , , , */
56 safe_asprintf(&script, "%s %s", "iptables", "-v -n -x -t mangle -L " TABLE_WIFIDOG_INCOMING);
57 iptables_insert_gateway_id(&script);
58 output = popen(script, "r");
59 free(script);
60 if (!output) {
61 debug(LOG_ERR, "popen(): %s", strerror(errno));
62 return -1;
63 }
64
65
66 while (('
' != fgetc(output)) && !feof(output))
67 ;
68 while (('
' != fgetc(output)) && !feof(output))
69 ;
70 while (output && !(feof(output))) {
71 rc = fscanf(output, "%*s %llu %*s %*s %*s %*s %*s %*s %15[0-9.]", &counter, ip);
72 if (2 == rc && EOF != rc) {
73
74 if (!inet_aton(ip, &tempaddr)) {
75 debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip);
76 continue;
77 }
78 debug(LOG_DEBUG, "Read incoming traffic for %s: Bytes=%llu", ip, counter);
79 LOCK_CLIENT_LIST();
80 if ((p1 = client_list_find_by_ip(ip))) {
81 if ((p1->counters.incoming - p1->counters.incoming_history) < counter) {
82 p1->counters.incoming = p1->counters.incoming_history + counter;
83 debug(LOG_DEBUG, "%s - Updated counter.incoming to %llu bytes", ip, counter);
84 }
85 } else {
86 debug(LOG_ERR, "Could not find %s in client list", ip);
87 }
88 UNLOCK_CLIENT_LIST();
89 }
90 }
91 pclose(output);
92
93 return 1;
94 }