1 | /********************************************************************\ |
---|
2 | * This program is free software; you can redistribute it and/or * |
---|
3 | * modify it under the terms of the GNU General Public License as * |
---|
4 | * published by the Free Software Foundation; either version 2 of * |
---|
5 | * the License, or (at your option) any later version. * |
---|
6 | * * |
---|
7 | * This program is distributed in the hope that it will be useful, * |
---|
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
---|
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
---|
10 | * GNU General Public License for more details. * |
---|
11 | * * |
---|
12 | * You should have received a copy of the GNU General Public License* |
---|
13 | * along with this program; if not, contact: * |
---|
14 | * * |
---|
15 | * Free Software Foundation Voice: +1-617-542-5942 * |
---|
16 | * 59 Temple Place - Suite 330 Fax: +1-617-542-2652 * |
---|
17 | * Boston, MA 02111-1307, USA gnu@gnu.org * |
---|
18 | * * |
---|
19 | \********************************************************************/ |
---|
20 | |
---|
21 | /* $Id$ */ |
---|
22 | /** @internal |
---|
23 | @file fw_iptables.c |
---|
24 | @brief Firewall iptables functions |
---|
25 | @author Copyright (C) 2004 Philippe April <papril777@yahoo.com> |
---|
26 | */ |
---|
27 | |
---|
28 | #define _GNU_SOURCE |
---|
29 | |
---|
30 | #include <stdio.h> |
---|
31 | #include <stdlib.h> |
---|
32 | #include <stdarg.h> |
---|
33 | #include <syslog.h> |
---|
34 | #include <errno.h> |
---|
35 | #include <string.h> |
---|
36 | #include <pthread.h> |
---|
37 | #include <sys/socket.h> |
---|
38 | #include <netinet/in.h> |
---|
39 | #include <arpa/inet.h> |
---|
40 | |
---|
41 | #include "common.h" |
---|
42 | |
---|
43 | #include "safe.h" |
---|
44 | #include "conf.h" |
---|
45 | #include "fw_iptables.h" |
---|
46 | #include "firewall.h" |
---|
47 | #include "debug.h" |
---|
48 | #include "util.h" |
---|
49 | #include "client_list.h" |
---|
50 | |
---|
51 | static int iptables_do_command(const char *format, ...); |
---|
52 | static char *iptables_compile(const char *, const char *, const t_firewall_rule *); |
---|
53 | static void iptables_load_ruleset(const char *, const char *, const char *); |
---|
54 | |
---|
55 | extern pthread_mutex_t client_list_mutex; |
---|
56 | extern pthread_mutex_t config_mutex; |
---|
57 | |
---|
58 | /** |
---|
59 | Used to supress the error output of the firewall during destruction */ |
---|
60 | static int fw_quiet = 0; |
---|
61 | |
---|
62 | /** @internal |
---|
63 | * @brief Insert $ID$ with the gateway's id in a string. |
---|
64 | * |
---|
65 | * This function can replace the input string with a new one. It assumes |
---|
66 | * the input string is dynamically allocted and can be free()ed safely. |
---|
67 | * |
---|
68 | * This function must be called with the CONFIG_LOCK held. |
---|
69 | */ |
---|
70 | static void |
---|
71 | iptables_insert_gateway_id(char **input) |
---|
72 | { |
---|
73 | char *token; |
---|
74 | const s_config *config; |
---|
75 | char *buffer; |
---|
76 | |
---|
77 | if (strstr(*input, "$ID$")==NULL) |
---|
78 | return; |
---|
79 | |
---|
80 | |
---|
81 | while ((token=strstr(*input, "$ID$"))!=NULL) |
---|
82 | /* This string may look odd but it's standard POSIX and ISO C */ |
---|
83 | memcpy(token, "%1$s", 4); |
---|
84 | |
---|
85 | config = config_get_config(); |
---|
86 | safe_asprintf(&buffer, *input, config->gw_id); |
---|
87 | |
---|
88 | free(*input); |
---|
89 | *input=buffer; |
---|
90 | } |
---|
91 | |
---|
92 | /** @internal |
---|
93 | * */ |
---|
94 | static int |
---|
95 | iptables_do_command(const char *format, ...) |
---|
96 | { |
---|
97 | va_list vlist; |
---|
98 | char *fmt_cmd; |
---|
99 | char *cmd; |
---|
100 | int rc; |
---|
101 | |
---|
102 | va_start(vlist, format); |
---|
103 | safe_vasprintf(&fmt_cmd, format, vlist); |
---|
104 | va_end(vlist); |
---|
105 | |
---|
106 | safe_asprintf(&cmd, "iptables %s", fmt_cmd); |
---|
107 | free(fmt_cmd); |
---|
108 | |
---|
109 | iptables_insert_gateway_id(&cmd); |
---|
110 | |
---|
111 | debug(LOG_DEBUG, "Executing command: %s", cmd); |
---|
112 | |
---|
113 | rc = execute(cmd, fw_quiet); |
---|
114 | |
---|
115 | if (rc!=0) |
---|
116 | debug(LOG_ERR, "iptables comand failed(%d): %s", rc, cmd); |
---|
117 | |
---|
118 | free(cmd); |
---|
119 | |
---|
120 | return rc; |
---|
121 | } |
---|
122 | |
---|
123 | /** |
---|
124 | * @internal |
---|
125 | * Compiles a struct definition of a firewall rule into a valid iptables |
---|
126 | * command. |
---|
127 | * @arg table Table containing the chain. |
---|
128 | * @arg chain Chain that the command will be (-A)ppended to. |
---|
129 | * @arg rule Definition of a rule into a struct, from conf.c. |
---|
130 | */ |
---|
131 | static char * |
---|
132 | iptables_compile(const char * table, const char *chain, const t_firewall_rule *rule) |
---|
133 | { |
---|
134 | char command[MAX_BUF], |
---|
135 | *mode; |
---|
136 | |
---|
137 | memset(command, 0, MAX_BUF); |
---|
138 | |
---|
139 | if (rule->block_allow == 1) { |
---|
140 | mode = safe_strdup("ACCEPT"); |
---|
141 | } else { |
---|
142 | mode = safe_strdup("REJECT"); |
---|
143 | } |
---|
144 | |
---|
145 | snprintf(command, sizeof(command), "-t %s -A %s ",table, chain); |
---|
146 | if (rule->mask != NULL) { |
---|
147 | snprintf((command + strlen(command)), (sizeof(command) - |
---|
148 | strlen(command)), "-d %s ", rule->mask); |
---|
149 | } |
---|
150 | if (rule->protocol != NULL) { |
---|
151 | snprintf((command + strlen(command)), (sizeof(command) - |
---|
152 | strlen(command)), "-p %s ", rule->protocol); |
---|
153 | } |
---|
154 | if (rule->port != NULL) { |
---|
155 | snprintf((command + strlen(command)), (sizeof(command) - |
---|
156 | strlen(command)), "--dport %s ", rule->port); |
---|
157 | } |
---|
158 | snprintf((command + strlen(command)), (sizeof(command) - |
---|
159 | strlen(command)), "-j %s", mode); |
---|
160 | |
---|
161 | free(mode); |
---|
162 | |
---|
163 | /* XXX The buffer command, an automatic variable, will get cleaned |
---|
164 | * off of the stack when we return, so we strdup() it. */ |
---|
165 | return(safe_strdup(command)); |
---|
166 | } |
---|
167 | |
---|
168 | /** |
---|
169 | * @internal |
---|
170 | * Load all the rules in a rule set. |
---|
171 | * @arg ruleset Name of the ruleset |
---|
172 | * @arg table Table containing the chain. |
---|
173 | * @arg chain IPTables chain the rules go into |
---|
174 | */ |
---|
175 | static void |
---|
176 | iptables_load_ruleset(const char * table, const char *ruleset, const char *chain) |
---|
177 | { |
---|
178 | t_firewall_rule *rule; |
---|
179 | char *cmd; |
---|
180 | |
---|
181 | debug(LOG_DEBUG, "Load ruleset %s into table %s, chain %s", ruleset, table, chain); |
---|
182 | |
---|
183 | for (rule = get_ruleset(ruleset); rule != NULL; rule = rule->next) { |
---|
184 | cmd = iptables_compile(table, chain, rule); |
---|
185 | debug(LOG_DEBUG, "Loading rule \"%s\" into table %s, chain %s", cmd, table, chain); |
---|
186 | iptables_do_command(cmd); |
---|
187 | free(cmd); |
---|
188 | } |
---|
189 | |
---|
190 | debug(LOG_DEBUG, "Ruleset %s loaded into table %s, chain %s", ruleset, table, chain); |
---|
191 | } |
---|
192 | |
---|
193 | void |
---|
194 | iptables_fw_clear_authservers(void) |
---|
195 | { |
---|
196 | iptables_do_command("-t filter -F " TABLE_WIFIDOG_AUTHSERVERS); |
---|
197 | iptables_do_command("-t nat -F " TABLE_WIFIDOG_AUTHSERVERS); |
---|
198 | } |
---|
199 | |
---|
200 | void |
---|
201 | iptables_fw_set_authservers(void) |
---|
202 | { |
---|
203 | const s_config *config; |
---|
204 | t_auth_serv *auth_server; |
---|
205 | |
---|
206 | config = config_get_config(); |
---|
207 | |
---|
208 | for (auth_server = config->auth_servers; auth_server != NULL; auth_server = auth_server->next) { |
---|
209 | if (auth_server->last_ip && strcmp(auth_server->last_ip, "0.0.0.0") != 0) { |
---|
210 | iptables_do_command("-t filter -A " TABLE_WIFIDOG_AUTHSERVERS " -d %s -j ACCEPT", auth_server->last_ip); |
---|
211 | iptables_do_command("-t nat -A " TABLE_WIFIDOG_AUTHSERVERS " -d %s -j ACCEPT", auth_server->last_ip); |
---|
212 | } |
---|
213 | } |
---|
214 | |
---|
215 | } |
---|
216 | |
---|
217 | /** Initialize the firewall rules |
---|
218 | */ |
---|
219 | int |
---|
220 | iptables_fw_init(void) |
---|
221 | { |
---|
222 | const s_config *config; |
---|
223 | char * ext_interface = NULL; |
---|
224 | int gw_port = 0; |
---|
225 | t_trusted_mac *p; |
---|
226 | |
---|
227 | fw_quiet = 0; |
---|
228 | |
---|
229 | LOCK_CONFIG(); |
---|
230 | config = config_get_config(); |
---|
231 | gw_port = config->gw_port; |
---|
232 | if (config->external_interface) { |
---|
233 | ext_interface = safe_strdup(config->external_interface); |
---|
234 | } else { |
---|
235 | ext_interface = get_ext_iface(); |
---|
236 | } |
---|
237 | |
---|
238 | if (ext_interface == NULL) { |
---|
239 | UNLOCK_CONFIG(); |
---|
240 | debug(LOG_ERR, "FATAL: no external interface"); |
---|
241 | return 0; |
---|
242 | } |
---|
243 | /* |
---|
244 | * |
---|
245 | * Everything in the MANGLE table |
---|
246 | * |
---|
247 | */ |
---|
248 | |
---|
249 | /* Create new chains */ |
---|
250 | iptables_do_command("-t mangle -N " TABLE_WIFIDOG_TRUSTED); |
---|
251 | iptables_do_command("-t mangle -N " TABLE_WIFIDOG_OUTGOING); |
---|
252 | iptables_do_command("-t mangle -N " TABLE_WIFIDOG_INCOMING); |
---|
253 | |
---|
254 | /* Assign links and rules to these new chains */ |
---|
255 | iptables_do_command("-t mangle -I PREROUTING 1 -i %s -j " TABLE_WIFIDOG_OUTGOING, config->gw_interface); |
---|
256 | iptables_do_command("-t mangle -I PREROUTING 1 -i %s -j " TABLE_WIFIDOG_TRUSTED, config->gw_interface);//this rule will be inserted before the prior one |
---|
257 | iptables_do_command("-t mangle -I POSTROUTING 1 -o %s -j " TABLE_WIFIDOG_INCOMING, config->gw_interface); |
---|
258 | |
---|
259 | for (p = config->trustedmaclist; p != NULL; p = p->next) |
---|
260 | iptables_do_command("-t mangle -A " TABLE_WIFIDOG_TRUSTED " -m mac --mac-source %s -j MARK --set-mark %d", p->mac, FW_MARK_KNOWN); |
---|
261 | |
---|
262 | /* |
---|
263 | * |
---|
264 | * Everything in the NAT table |
---|
265 | * |
---|
266 | */ |
---|
267 | |
---|
268 | /* Create new chains */ |
---|
269 | iptables_do_command("-t nat -N " TABLE_WIFIDOG_OUTGOING); |
---|
270 | iptables_do_command("-t nat -N " TABLE_WIFIDOG_WIFI_TO_ROUTER); |
---|
271 | iptables_do_command("-t nat -N " TABLE_WIFIDOG_WIFI_TO_INTERNET); |
---|
272 | iptables_do_command("-t nat -N " TABLE_WIFIDOG_GLOBAL); |
---|
273 | iptables_do_command("-t nat -N " TABLE_WIFIDOG_UNKNOWN); |
---|
274 | iptables_do_command("-t nat -N " TABLE_WIFIDOG_AUTHSERVERS); |
---|
275 | |
---|
276 | /* Assign links and rules to these new chains */ |
---|
277 | iptables_do_command("-t nat -A PREROUTING -i %s -j " TABLE_WIFIDOG_OUTGOING, config->gw_interface); |
---|
278 | |
---|
279 | iptables_do_command("-t nat -A " TABLE_WIFIDOG_OUTGOING " -d %s -j " TABLE_WIFIDOG_WIFI_TO_ROUTER, config->gw_address); |
---|
280 | iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_ROUTER " -j ACCEPT"); |
---|
281 | |
---|
282 | iptables_do_command("-t nat -A " TABLE_WIFIDOG_OUTGOING " -j " TABLE_WIFIDOG_WIFI_TO_INTERNET); |
---|
283 | iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j ACCEPT", FW_MARK_KNOWN); |
---|
284 | iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j ACCEPT", FW_MARK_PROBATION); |
---|
285 | iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_UNKNOWN); |
---|
286 | |
---|
287 | iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -j " TABLE_WIFIDOG_AUTHSERVERS); |
---|
288 | iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -j " TABLE_WIFIDOG_GLOBAL); |
---|
289 | iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -p tcp --dport 80 -j REDIRECT --to-ports %d", gw_port); |
---|
290 | |
---|
291 | |
---|
292 | /* |
---|
293 | * |
---|
294 | * Everything in the FILTER table |
---|
295 | * |
---|
296 | */ |
---|
297 | |
---|
298 | /* Create new chains */ |
---|
299 | iptables_do_command("-t filter -N " TABLE_WIFIDOG_WIFI_TO_INTERNET); |
---|
300 | iptables_do_command("-t filter -N " TABLE_WIFIDOG_AUTHSERVERS); |
---|
301 | iptables_do_command("-t filter -N " TABLE_WIFIDOG_LOCKED); |
---|
302 | iptables_do_command("-t filter -N " TABLE_WIFIDOG_GLOBAL); |
---|
303 | iptables_do_command("-t filter -N " TABLE_WIFIDOG_VALIDATE); |
---|
304 | iptables_do_command("-t filter -N " TABLE_WIFIDOG_KNOWN); |
---|
305 | iptables_do_command("-t filter -N " TABLE_WIFIDOG_UNKNOWN); |
---|
306 | |
---|
307 | /* Assign links and rules to these new chains */ |
---|
308 | |
---|
309 | /* Insert at the beginning */ |
---|
310 | iptables_do_command("-t filter -I FORWARD -i %s -j " TABLE_WIFIDOG_WIFI_TO_INTERNET, config->gw_interface); |
---|
311 | |
---|
312 | |
---|
313 | iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m state --state INVALID -j DROP"); |
---|
314 | |
---|
315 | /* XXX: Why this? it means that connections setup after authentication |
---|
316 | stay open even after the connection is done... |
---|
317 | iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m state --state RELATED,ESTABLISHED -j ACCEPT");*/ |
---|
318 | |
---|
319 | //Won't this rule NEVER match anyway?!?!? benoitg, 2007-06-23 |
---|
320 | //iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -i %s -m state --state NEW -j DROP", ext_interface); |
---|
321 | |
---|
322 | /* TCPMSS rule for PPPoE */ |
---|
323 | iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -o %s -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu", ext_interface); |
---|
324 | |
---|
325 | iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_AUTHSERVERS); |
---|
326 | iptables_fw_set_authservers(); |
---|
327 | |
---|
328 | iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j " TABLE_WIFIDOG_LOCKED, FW_MARK_LOCKED); |
---|
329 | iptables_load_ruleset("filter", "locked-users", TABLE_WIFIDOG_LOCKED); |
---|
330 | |
---|
331 | iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_GLOBAL); |
---|
332 | iptables_load_ruleset("filter", "global", TABLE_WIFIDOG_GLOBAL); |
---|
333 | iptables_load_ruleset("nat", "global", TABLE_WIFIDOG_GLOBAL); |
---|
334 | |
---|
335 | iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j " TABLE_WIFIDOG_VALIDATE, FW_MARK_PROBATION); |
---|
336 | iptables_load_ruleset("filter", "validating-users", TABLE_WIFIDOG_VALIDATE); |
---|
337 | |
---|
338 | iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j " TABLE_WIFIDOG_KNOWN, FW_MARK_KNOWN); |
---|
339 | iptables_load_ruleset("filter", "known-users", TABLE_WIFIDOG_KNOWN); |
---|
340 | |
---|
341 | iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_UNKNOWN); |
---|
342 | iptables_load_ruleset("filter", "unknown-users", TABLE_WIFIDOG_UNKNOWN); |
---|
343 | iptables_do_command("-t filter -A " TABLE_WIFIDOG_UNKNOWN " -j REJECT --reject-with icmp-port-unreachable"); |
---|
344 | |
---|
345 | UNLOCK_CONFIG(); |
---|
346 | return 1; |
---|
347 | } |
---|
348 | |
---|
349 | /** Remove the firewall rules |
---|
350 | * This is used when we do a clean shutdown of WiFiDog and when it starts to make |
---|
351 | * sure there are no rules left over |
---|
352 | */ |
---|
353 | int |
---|
354 | iptables_fw_destroy(void) |
---|
355 | { |
---|
356 | fw_quiet = 1; |
---|
357 | |
---|
358 | debug(LOG_DEBUG, "Destroying our iptables entries"); |
---|
359 | |
---|
360 | /* |
---|
361 | * |
---|
362 | * Everything in the MANGLE table |
---|
363 | * |
---|
364 | */ |
---|
365 | debug(LOG_DEBUG, "Destroying chains in the MANGLE table"); |
---|
366 | iptables_fw_destroy_mention("mangle", "PREROUTING", TABLE_WIFIDOG_TRUSTED); |
---|
367 | iptables_fw_destroy_mention("mangle", "PREROUTING", TABLE_WIFIDOG_OUTGOING); |
---|
368 | iptables_fw_destroy_mention("mangle", "POSTROUTING", TABLE_WIFIDOG_INCOMING); |
---|
369 | iptables_do_command("-t mangle -F " TABLE_WIFIDOG_TRUSTED); |
---|
370 | iptables_do_command("-t mangle -F " TABLE_WIFIDOG_OUTGOING); |
---|
371 | iptables_do_command("-t mangle -F " TABLE_WIFIDOG_INCOMING); |
---|
372 | iptables_do_command("-t mangle -X " TABLE_WIFIDOG_TRUSTED); |
---|
373 | iptables_do_command("-t mangle -X " TABLE_WIFIDOG_OUTGOING); |
---|
374 | iptables_do_command("-t mangle -X " TABLE_WIFIDOG_INCOMING); |
---|
375 | |
---|
376 | /* |
---|
377 | * |
---|
378 | * Everything in the NAT table |
---|
379 | * |
---|
380 | */ |
---|
381 | debug(LOG_DEBUG, "Destroying chains in the NAT table"); |
---|
382 | iptables_fw_destroy_mention("nat", "PREROUTING", TABLE_WIFIDOG_OUTGOING); |
---|
383 | iptables_do_command("-t nat -F " TABLE_WIFIDOG_AUTHSERVERS); |
---|
384 | iptables_do_command("-t nat -F " TABLE_WIFIDOG_OUTGOING); |
---|
385 | iptables_do_command("-t nat -F " TABLE_WIFIDOG_WIFI_TO_ROUTER); |
---|
386 | iptables_do_command("-t nat -F " TABLE_WIFIDOG_WIFI_TO_INTERNET); |
---|
387 | iptables_do_command("-t nat -F " TABLE_WIFIDOG_GLOBAL); |
---|
388 | iptables_do_command("-t nat -F " TABLE_WIFIDOG_UNKNOWN); |
---|
389 | iptables_do_command("-t nat -X " TABLE_WIFIDOG_AUTHSERVERS); |
---|
390 | iptables_do_command("-t nat -X " TABLE_WIFIDOG_OUTGOING); |
---|
391 | iptables_do_command("-t nat -X " TABLE_WIFIDOG_WIFI_TO_ROUTER); |
---|
392 | iptables_do_command("-t nat -X " TABLE_WIFIDOG_WIFI_TO_INTERNET); |
---|
393 | iptables_do_command("-t nat -X " TABLE_WIFIDOG_GLOBAL); |
---|
394 | iptables_do_command("-t nat -X " TABLE_WIFIDOG_UNKNOWN); |
---|
395 | |
---|
396 | /* |
---|
397 | * |
---|
398 | * Everything in the FILTER table |
---|
399 | * |
---|
400 | */ |
---|
401 | debug(LOG_DEBUG, "Destroying chains in the FILTER table"); |
---|
402 | iptables_fw_destroy_mention("filter", "FORWARD", TABLE_WIFIDOG_WIFI_TO_INTERNET); |
---|
403 | iptables_do_command("-t filter -F " TABLE_WIFIDOG_WIFI_TO_INTERNET); |
---|
404 | iptables_do_command("-t filter -F " TABLE_WIFIDOG_AUTHSERVERS); |
---|
405 | iptables_do_command("-t filter -F " TABLE_WIFIDOG_LOCKED); |
---|
406 | iptables_do_command("-t filter -F " TABLE_WIFIDOG_GLOBAL); |
---|
407 | iptables_do_command("-t filter -F " TABLE_WIFIDOG_VALIDATE); |
---|
408 | iptables_do_command("-t filter -F " TABLE_WIFIDOG_KNOWN); |
---|
409 | iptables_do_command("-t filter -F " TABLE_WIFIDOG_UNKNOWN); |
---|
410 | iptables_do_command("-t filter -X " TABLE_WIFIDOG_WIFI_TO_INTERNET); |
---|
411 | iptables_do_command("-t filter -X " TABLE_WIFIDOG_AUTHSERVERS); |
---|
412 | iptables_do_command("-t filter -X " TABLE_WIFIDOG_LOCKED); |
---|
413 | iptables_do_command("-t filter -X " TABLE_WIFIDOG_GLOBAL); |
---|
414 | iptables_do_command("-t filter -X " TABLE_WIFIDOG_VALIDATE); |
---|
415 | iptables_do_command("-t filter -X " TABLE_WIFIDOG_KNOWN); |
---|
416 | iptables_do_command("-t filter -X " TABLE_WIFIDOG_UNKNOWN); |
---|
417 | |
---|
418 | return 1; |
---|
419 | } |
---|
420 | |
---|
421 | /* |
---|
422 | * Helper for iptables_fw_destroy |
---|
423 | * @param table The table to search |
---|
424 | * @param chain The chain in that table to search |
---|
425 | * @param mention A word to find and delete in rules in the given table+chain |
---|
426 | */ |
---|
427 | int |
---|
428 | iptables_fw_destroy_mention( |
---|
429 | const char * table, |
---|
430 | const char * chain, |
---|
431 | const char * mention |
---|
432 | ) { |
---|
433 | FILE *p = NULL; |
---|
434 | char *command = NULL; |
---|
435 | char *command2 = NULL; |
---|
436 | char line[MAX_BUF]; |
---|
437 | char rulenum[10]; |
---|
438 | int deleted = 0; |
---|
439 | |
---|
440 | debug(LOG_DEBUG, "Attempting to destroy all mention of %s from %s.%s", mention, table, chain); |
---|
441 | |
---|
442 | safe_asprintf(&command, "iptables -t %s -L %s -n --line-numbers -v", table, chain); |
---|
443 | iptables_insert_gateway_id(&command); |
---|
444 | |
---|
445 | if ((p = popen(command, "r"))) { |
---|
446 | /* Skip first 2 lines */ |
---|
447 | while (!feof(p) && fgetc(p) != '\n'); |
---|
448 | while (!feof(p) && fgetc(p) != '\n'); |
---|
449 | /* Loop over entries */ |
---|
450 | while (fgets(line, sizeof(line), p)) { |
---|
451 | /* Look for mention */ |
---|
452 | if (strstr(line, mention)) { |
---|
453 | /* Found mention - Get the rule number into rulenum*/ |
---|
454 | if (sscanf(line, "%9[0-9]", rulenum) == 1) { |
---|
455 | /* Delete the rule: */ |
---|
456 | debug(LOG_DEBUG, "Deleting rule %s from %s.%s because it mentions %s", rulenum, table, chain, mention); |
---|
457 | safe_asprintf(&command2, "-t %s -D %s %s", table, chain, rulenum); |
---|
458 | iptables_do_command(command2); |
---|
459 | free(command2); |
---|
460 | deleted = 1; |
---|
461 | /* Do not keep looping - the captured rulenums will no longer be accurate */ |
---|
462 | break; |
---|
463 | } |
---|
464 | } |
---|
465 | } |
---|
466 | pclose(p); |
---|
467 | } |
---|
468 | |
---|
469 | free(command); |
---|
470 | |
---|
471 | if (deleted) { |
---|
472 | /* Recurse just in case there are more in the same table+chain */ |
---|
473 | iptables_fw_destroy_mention(table, chain, mention); |
---|
474 | } |
---|
475 | |
---|
476 | return (deleted); |
---|
477 | } |
---|
478 | |
---|
479 | /** Set if a specific client has access through the firewall */ |
---|
480 | int |
---|
481 | iptables_fw_access(fw_access_t type, const char *ip, const char *mac, int tag) |
---|
482 | { |
---|
483 | int rc; |
---|
484 | |
---|
485 | fw_quiet = 0; |
---|
486 | |
---|
487 | switch(type) { |
---|
488 | case FW_ACCESS_ALLOW: |
---|
489 | iptables_do_command("-t mangle -A " TABLE_WIFIDOG_OUTGOING " -s %s -m mac --mac-source %s -j MARK --set-mark %d", ip, mac, tag); |
---|
490 | rc = iptables_do_command("-t mangle -A " TABLE_WIFIDOG_INCOMING " -d %s -j ACCEPT", ip); |
---|
491 | break; |
---|
492 | case FW_ACCESS_DENY: |
---|
493 | iptables_do_command("-t mangle -D " TABLE_WIFIDOG_OUTGOING " -s %s -m mac --mac-source %s -j MARK --set-mark %d", ip, mac, tag); |
---|
494 | rc = iptables_do_command("-t mangle -D " TABLE_WIFIDOG_INCOMING " -d %s -j ACCEPT", ip); |
---|
495 | break; |
---|
496 | default: |
---|
497 | rc = -1; |
---|
498 | break; |
---|
499 | } |
---|
500 | |
---|
501 | return rc; |
---|
502 | } |
---|
503 | |
---|
504 | /** Update the counters of all the clients in the client list */ |
---|
505 | int |
---|
506 | iptables_fw_counters_update(void) |
---|
507 | { |
---|
508 | FILE *output; |
---|
509 | char *script, |
---|
510 | ip[16], |
---|
511 | rc; |
---|
512 | unsigned long long int counter; |
---|
513 | t_client *p1; |
---|
514 | struct in_addr tempaddr; |
---|
515 | |
---|
516 | /* Look for outgoing traffic */ |
---|
517 | safe_asprintf(&script, "%s %s", "iptables", "-v -n -x -t mangle -L " TABLE_WIFIDOG_OUTGOING); |
---|
518 | iptables_insert_gateway_id(&script); |
---|
519 | output = popen(script, "r"); |
---|
520 | free(script); |
---|
521 | if (!output) { |
---|
522 | debug(LOG_ERR, "popen(): %s", strerror(errno)); |
---|
523 | return -1; |
---|
524 | } |
---|
525 | |
---|
526 | /* skip the first two lines */ |
---|
527 | while (('\n' != fgetc(output)) && !feof(output)) |
---|
528 | ; |
---|
529 | while (('\n' != fgetc(output)) && !feof(output)) |
---|
530 | ; |
---|
531 | while (output && !(feof(output))) { |
---|
532 | rc = fscanf(output, "%*s %llu %*s %*s %*s %*s %*s %15[0-9.] %*s %*s %*s %*s %*s 0x%*u", &counter, ip); |
---|
533 | if (2 == rc && EOF != rc) { |
---|
534 | /* Sanity*/ |
---|
535 | if (!inet_aton(ip, &tempaddr)) { |
---|
536 | debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip); |
---|
537 | continue; |
---|
538 | } |
---|
539 | debug(LOG_DEBUG, "Read outgoing traffic for %s: Bytes=%llu", ip, counter); |
---|
540 | LOCK_CLIENT_LIST(); |
---|
541 | if ((p1 = client_list_find_by_ip(ip))) { |
---|
542 | if ((p1->counters.outgoing - p1->counters.outgoing_history) < counter) { |
---|
543 | p1->counters.outgoing = p1->counters.outgoing_history + counter; |
---|
544 | p1->counters.last_updated = time(NULL); |
---|
545 | debug(LOG_DEBUG, "%s - Updated counter.outgoing to %llu bytes. Updated last_updated to %d", ip, counter, p1->counters.last_updated); |
---|
546 | } |
---|
547 | } else { |
---|
548 | debug(LOG_ERR, "Could not find %s in client list", ip); |
---|
549 | } |
---|
550 | UNLOCK_CLIENT_LIST(); |
---|
551 | } |
---|
552 | } |
---|
553 | pclose(output); |
---|
554 | |
---|
555 | /* Look for incoming traffic */ |
---|
556 | safe_asprintf(&script, "%s %s", "iptables", "-v -n -x -t mangle -L " TABLE_WIFIDOG_INCOMING); |
---|
557 | iptables_insert_gateway_id(&script); |
---|
558 | output = popen(script, "r"); |
---|
559 | free(script); |
---|
560 | if (!output) { |
---|
561 | debug(LOG_ERR, "popen(): %s", strerror(errno)); |
---|
562 | return -1; |
---|
563 | } |
---|
564 | |
---|
565 | /* skip the first two lines */ |
---|
566 | while (('\n' != fgetc(output)) && !feof(output)) |
---|
567 | ; |
---|
568 | while (('\n' != fgetc(output)) && !feof(output)) |
---|
569 | ; |
---|
570 | while (output && !(feof(output))) { |
---|
571 | rc = fscanf(output, "%*s %llu %*s %*s %*s %*s %*s %*s %15[0-9.]", &counter, ip); |
---|
572 | if (2 == rc && EOF != rc) { |
---|
573 | /* Sanity*/ |
---|
574 | if (!inet_aton(ip, &tempaddr)) { |
---|
575 | debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip); |
---|
576 | continue; |
---|
577 | } |
---|
578 | debug(LOG_DEBUG, "Read incoming traffic for %s: Bytes=%llu", ip, counter); |
---|
579 | LOCK_CLIENT_LIST(); |
---|
580 | if ((p1 = client_list_find_by_ip(ip))) { |
---|
581 | if ((p1->counters.incoming - p1->counters.incoming_history) < counter) { |
---|
582 | p1->counters.incoming = p1->counters.incoming_history + counter; |
---|
583 | debug(LOG_DEBUG, "%s - Updated counter.incoming to %llu bytes", ip, counter); |
---|
584 | } |
---|
585 | } else { |
---|
586 | debug(LOG_ERR, "Could not find %s in client list", ip); |
---|
587 | } |
---|
588 | UNLOCK_CLIENT_LIST(); |
---|
589 | } |
---|
590 | } |
---|
591 | pclose(output); |
---|
592 | |
---|
593 | return 1; |
---|
594 | } |
---|