root/trunk/wifidog/src/fw_iptables.c

Revision 1454, 20.9 KB (checked in by gbastien, 3 years ago)

Committed patch for #501 by Benoît Grégoire and Mac Jones

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
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
51static int iptables_do_command(const char *format, ...);
52static char *iptables_compile(const char *, const char *, const t_firewall_rule *);
53static void iptables_load_ruleset(const char *, const char *, const char *);
54
55extern pthread_mutex_t  client_list_mutex;
56extern pthread_mutex_t  config_mutex;
57
58/**
59Used to supress the error output of the firewall during destruction */ 
60static 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 */
70static void
71iptables_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_interface);
87
88        free(*input);
89        *input=buffer;
90}
91
92/** @internal
93 * */
94static int
95iptables_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                // If quiet, do not display the error
117                if (fw_quiet == 0)
118                        debug(LOG_ERR, "iptables command failed(%d): %s", rc, cmd);
119                else if (fw_quiet == 1)
120                        debug(LOG_DEBUG, "iptables command failed(%d): %s", rc, cmd);
121        }
122
123        free(cmd);
124
125        return rc;
126}
127
128/**
129 * @internal
130 * Compiles a struct definition of a firewall rule into a valid iptables
131 * command.
132 * @arg table Table containing the chain.
133 * @arg chain Chain that the command will be (-A)ppended to.
134 * @arg rule Definition of a rule into a struct, from conf.c.
135 */
136        static char *
137iptables_compile(const char * table, const char *chain, const t_firewall_rule *rule)
138{
139        char    command[MAX_BUF],
140                *mode;
141
142        memset(command, 0, MAX_BUF);
143
144        if (rule->block_allow == 1) {
145                mode = safe_strdup("ACCEPT");
146        } else {
147                mode = safe_strdup("REJECT");
148        }
149
150        snprintf(command, sizeof(command),  "-t %s -A %s ",table, chain);
151        if (rule->mask != NULL) {
152                snprintf((command + strlen(command)), (sizeof(command) - 
153                                        strlen(command)), "-d %s ", rule->mask);
154        }
155        if (rule->protocol != NULL) {
156                snprintf((command + strlen(command)), (sizeof(command) -
157                                        strlen(command)), "-p %s ", rule->protocol);
158        }
159        if (rule->port != NULL) {
160                snprintf((command + strlen(command)), (sizeof(command) -
161                                        strlen(command)), "--dport %s ", rule->port);
162        }
163        snprintf((command + strlen(command)), (sizeof(command) - 
164                                strlen(command)), "-j %s", mode);
165
166        free(mode);
167
168        /* XXX The buffer command, an automatic variable, will get cleaned
169         * off of the stack when we return, so we strdup() it. */
170        return(safe_strdup(command));
171}
172
173/**
174 * @internal
175 * Load all the rules in a rule set.
176 * @arg ruleset Name of the ruleset
177 * @arg table Table containing the chain.
178 * @arg chain IPTables chain the rules go into
179 */
180        static void
181iptables_load_ruleset(const char * table, const char *ruleset, const char *chain)
182{
183        t_firewall_rule         *rule;
184        char                    *cmd;
185
186        debug(LOG_DEBUG, "Load ruleset %s into table %s, chain %s", ruleset, table, chain);
187
188        for (rule = get_ruleset(ruleset); rule != NULL; rule = rule->next) {
189                cmd = iptables_compile(table, chain, rule);
190                debug(LOG_DEBUG, "Loading rule \"%s\" into table %s, chain %s", cmd, table, chain);
191                iptables_do_command(cmd);
192                free(cmd);
193        }
194
195        debug(LOG_DEBUG, "Ruleset %s loaded into table %s, chain %s", ruleset, table, chain);
196}
197
198        void
199iptables_fw_clear_authservers(void)
200{
201        iptables_do_command("-t filter -F " TABLE_WIFIDOG_AUTHSERVERS);
202        iptables_do_command("-t nat -F " TABLE_WIFIDOG_AUTHSERVERS);
203}
204
205        void
206iptables_fw_set_authservers(void)
207{
208        const s_config *config;
209        t_auth_serv *auth_server;
210
211        config = config_get_config();
212
213        for (auth_server = config->auth_servers; auth_server != NULL; auth_server = auth_server->next) {
214                if (auth_server->last_ip && strcmp(auth_server->last_ip, "0.0.0.0") != 0) {
215                        iptables_do_command("-t filter -A " TABLE_WIFIDOG_AUTHSERVERS " -d %s -j ACCEPT", auth_server->last_ip);
216                        iptables_do_command("-t nat -A " TABLE_WIFIDOG_AUTHSERVERS " -d %s -j ACCEPT", auth_server->last_ip);
217                }
218        }
219
220}
221
222/** Initialize the firewall rules
223*/
224        int
225iptables_fw_init(void)
226{
227        const s_config *config;
228        char * ext_interface = NULL;
229        int gw_port = 0;
230        t_trusted_mac *p;
231
232        fw_quiet = 0;
233
234        LOCK_CONFIG();
235        config = config_get_config();
236        gw_port = config->gw_port;
237        if (config->external_interface) {
238                ext_interface = safe_strdup(config->external_interface);
239        } else {
240                ext_interface = get_ext_iface();
241        }
242
243        if (ext_interface == NULL) {
244                UNLOCK_CONFIG();
245                debug(LOG_ERR, "FATAL: no external interface");
246                return 0;
247        }
248        /*
249         *
250         * Everything in the MANGLE table
251         *
252         */
253
254        /* Create new chains */
255        iptables_do_command("-t mangle -N " TABLE_WIFIDOG_TRUSTED);
256        iptables_do_command("-t mangle -N " TABLE_WIFIDOG_OUTGOING);
257        iptables_do_command("-t mangle -N " TABLE_WIFIDOG_INCOMING);
258
259        /* Assign links and rules to these new chains */
260        iptables_do_command("-t mangle -I PREROUTING 1 -i %s -j " TABLE_WIFIDOG_OUTGOING, config->gw_interface);
261        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
262        iptables_do_command("-t mangle -I POSTROUTING 1 -o %s -j " TABLE_WIFIDOG_INCOMING, config->gw_interface);
263
264        for (p = config->trustedmaclist; p != NULL; p = p->next)
265                iptables_do_command("-t mangle -A " TABLE_WIFIDOG_TRUSTED " -m mac --mac-source %s -j MARK --set-mark %d", p->mac, FW_MARK_KNOWN);
266
267        /*
268         *
269         * Everything in the NAT table
270         *
271         */
272
273        /* Create new chains */
274        iptables_do_command("-t nat -N " TABLE_WIFIDOG_OUTGOING);
275        iptables_do_command("-t nat -N " TABLE_WIFIDOG_WIFI_TO_ROUTER);
276        iptables_do_command("-t nat -N " TABLE_WIFIDOG_WIFI_TO_INTERNET);
277        iptables_do_command("-t nat -N " TABLE_WIFIDOG_GLOBAL);
278        iptables_do_command("-t nat -N " TABLE_WIFIDOG_UNKNOWN);
279        iptables_do_command("-t nat -N " TABLE_WIFIDOG_AUTHSERVERS);
280
281        /* Assign links and rules to these new chains */
282        iptables_do_command("-t nat -A PREROUTING -i %s -j " TABLE_WIFIDOG_OUTGOING, config->gw_interface);
283
284        iptables_do_command("-t nat -A " TABLE_WIFIDOG_OUTGOING " -d %s -j " TABLE_WIFIDOG_WIFI_TO_ROUTER, config->gw_address);
285        iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_ROUTER " -j ACCEPT");
286
287        iptables_do_command("-t nat -A " TABLE_WIFIDOG_OUTGOING " -j " TABLE_WIFIDOG_WIFI_TO_INTERNET);
288        iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j ACCEPT", FW_MARK_KNOWN);
289        iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j ACCEPT", FW_MARK_PROBATION);
290        iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_UNKNOWN);
291
292        iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -j " TABLE_WIFIDOG_AUTHSERVERS);
293        iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -j " TABLE_WIFIDOG_GLOBAL);
294        iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -p tcp --dport 80 -j REDIRECT --to-ports %d", gw_port);
295
296
297        /*
298         *
299         * Everything in the FILTER table
300         *
301         */
302
303        /* Create new chains */
304        iptables_do_command("-t filter -N " TABLE_WIFIDOG_WIFI_TO_INTERNET);
305        iptables_do_command("-t filter -N " TABLE_WIFIDOG_AUTHSERVERS);
306        iptables_do_command("-t filter -N " TABLE_WIFIDOG_LOCKED);
307        iptables_do_command("-t filter -N " TABLE_WIFIDOG_GLOBAL);
308        iptables_do_command("-t filter -N " TABLE_WIFIDOG_VALIDATE);
309        iptables_do_command("-t filter -N " TABLE_WIFIDOG_KNOWN);
310        iptables_do_command("-t filter -N " TABLE_WIFIDOG_UNKNOWN);
311
312        /* Assign links and rules to these new chains */
313
314        /* Insert at the beginning */
315        iptables_do_command("-t filter -I FORWARD -i %s -j " TABLE_WIFIDOG_WIFI_TO_INTERNET, config->gw_interface);
316
317
318        iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m state --state INVALID -j DROP");
319
320        /* XXX: Why this? it means that connections setup after authentication
321           stay open even after the connection is done...
322           iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m state --state RELATED,ESTABLISHED -j ACCEPT");*/
323
324        //Won't this rule NEVER match anyway?!?!? benoitg, 2007-06-23
325        //iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -i %s -m state --state NEW -j DROP", ext_interface);
326
327        /* TCPMSS rule for PPPoE */
328        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);
329
330        iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_AUTHSERVERS);
331        iptables_fw_set_authservers();
332
333        iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j " TABLE_WIFIDOG_LOCKED, FW_MARK_LOCKED);
334        iptables_load_ruleset("filter", "locked-users", TABLE_WIFIDOG_LOCKED);
335
336        iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_GLOBAL);
337        iptables_load_ruleset("filter", "global", TABLE_WIFIDOG_GLOBAL);
338        iptables_load_ruleset("nat", "global", TABLE_WIFIDOG_GLOBAL);
339
340        iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j " TABLE_WIFIDOG_VALIDATE, FW_MARK_PROBATION);
341        iptables_load_ruleset("filter", "validating-users", TABLE_WIFIDOG_VALIDATE);
342
343        iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j " TABLE_WIFIDOG_KNOWN, FW_MARK_KNOWN);
344        iptables_load_ruleset("filter", "known-users", TABLE_WIFIDOG_KNOWN);
345
346        iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_UNKNOWN);
347        iptables_load_ruleset("filter", "unknown-users", TABLE_WIFIDOG_UNKNOWN);
348        iptables_do_command("-t filter -A " TABLE_WIFIDOG_UNKNOWN " -j REJECT --reject-with icmp-port-unreachable");
349
350        UNLOCK_CONFIG();
351        return 1;
352}
353
354/** Remove the firewall rules
355 * This is used when we do a clean shutdown of WiFiDog and when it starts to make
356 * sure there are no rules left over
357 */
358        int
359iptables_fw_destroy(void)
360{
361        fw_quiet = 1;
362
363        debug(LOG_DEBUG, "Destroying our iptables entries");
364
365        /*
366         *
367         * Everything in the MANGLE table
368         *
369         */
370        debug(LOG_DEBUG, "Destroying chains in the MANGLE table");
371        iptables_fw_destroy_mention("mangle", "PREROUTING", TABLE_WIFIDOG_TRUSTED);
372        iptables_fw_destroy_mention("mangle", "PREROUTING", TABLE_WIFIDOG_OUTGOING);
373        iptables_fw_destroy_mention("mangle", "POSTROUTING", TABLE_WIFIDOG_INCOMING);
374        iptables_do_command("-t mangle -F " TABLE_WIFIDOG_TRUSTED);
375        iptables_do_command("-t mangle -F " TABLE_WIFIDOG_OUTGOING);
376        iptables_do_command("-t mangle -F " TABLE_WIFIDOG_INCOMING);
377        iptables_do_command("-t mangle -X " TABLE_WIFIDOG_TRUSTED);
378        iptables_do_command("-t mangle -X " TABLE_WIFIDOG_OUTGOING);
379        iptables_do_command("-t mangle -X " TABLE_WIFIDOG_INCOMING);
380
381        /*
382         *
383         * Everything in the NAT table
384         *
385         */
386        debug(LOG_DEBUG, "Destroying chains in the NAT table");
387        iptables_fw_destroy_mention("nat", "PREROUTING", TABLE_WIFIDOG_OUTGOING);
388        iptables_do_command("-t nat -F " TABLE_WIFIDOG_AUTHSERVERS);
389        iptables_do_command("-t nat -F " TABLE_WIFIDOG_OUTGOING);
390        iptables_do_command("-t nat -F " TABLE_WIFIDOG_WIFI_TO_ROUTER);
391        iptables_do_command("-t nat -F " TABLE_WIFIDOG_WIFI_TO_INTERNET);
392        iptables_do_command("-t nat -F " TABLE_WIFIDOG_GLOBAL);
393        iptables_do_command("-t nat -F " TABLE_WIFIDOG_UNKNOWN);
394        iptables_do_command("-t nat -X " TABLE_WIFIDOG_AUTHSERVERS);
395        iptables_do_command("-t nat -X " TABLE_WIFIDOG_OUTGOING);
396        iptables_do_command("-t nat -X " TABLE_WIFIDOG_WIFI_TO_ROUTER);
397        iptables_do_command("-t nat -X " TABLE_WIFIDOG_WIFI_TO_INTERNET);
398        iptables_do_command("-t nat -X " TABLE_WIFIDOG_GLOBAL);
399        iptables_do_command("-t nat -X " TABLE_WIFIDOG_UNKNOWN);
400
401        /*
402         *
403         * Everything in the FILTER table
404         *
405         */
406        debug(LOG_DEBUG, "Destroying chains in the FILTER table");
407        iptables_fw_destroy_mention("filter", "FORWARD", TABLE_WIFIDOG_WIFI_TO_INTERNET);
408        iptables_do_command("-t filter -F " TABLE_WIFIDOG_WIFI_TO_INTERNET);
409        iptables_do_command("-t filter -F " TABLE_WIFIDOG_AUTHSERVERS);
410        iptables_do_command("-t filter -F " TABLE_WIFIDOG_LOCKED);
411        iptables_do_command("-t filter -F " TABLE_WIFIDOG_GLOBAL);
412        iptables_do_command("-t filter -F " TABLE_WIFIDOG_VALIDATE);
413        iptables_do_command("-t filter -F " TABLE_WIFIDOG_KNOWN);
414        iptables_do_command("-t filter -F " TABLE_WIFIDOG_UNKNOWN);
415        iptables_do_command("-t filter -X " TABLE_WIFIDOG_WIFI_TO_INTERNET);
416        iptables_do_command("-t filter -X " TABLE_WIFIDOG_AUTHSERVERS);
417        iptables_do_command("-t filter -X " TABLE_WIFIDOG_LOCKED);
418        iptables_do_command("-t filter -X " TABLE_WIFIDOG_GLOBAL);
419        iptables_do_command("-t filter -X " TABLE_WIFIDOG_VALIDATE);
420        iptables_do_command("-t filter -X " TABLE_WIFIDOG_KNOWN);
421        iptables_do_command("-t filter -X " TABLE_WIFIDOG_UNKNOWN);
422
423        return 1;
424}
425
426/*
427 * Helper for iptables_fw_destroy
428 * @param table The table to search
429 * @param chain The chain in that table to search
430 * @param mention A word to find and delete in rules in the given table+chain
431 */
432int
433iptables_fw_destroy_mention(
434                const char * table,
435                const char * chain,
436                const char * mention
437                ) {
438        FILE *p = NULL;
439        char *command = NULL;
440        char *command2 = NULL;
441        char line[MAX_BUF];
442        char rulenum[10];
443        char *victim = safe_strdup(mention);
444        int deleted = 0;
445
446        iptables_insert_gateway_id(&victim);
447
448        debug(LOG_DEBUG, "Attempting to destroy all mention of %s from %s.%s", victim, table, chain);
449
450        safe_asprintf(&command, "iptables -t %s -L %s -n --line-numbers -v", table, chain);
451        iptables_insert_gateway_id(&command);
452
453        if ((p = popen(command, "r"))) {
454                /* Skip first 2 lines */
455                while (!feof(p) && fgetc(p) != '\n');
456                while (!feof(p) && fgetc(p) != '\n');
457                /* Loop over entries */
458                while (fgets(line, sizeof(line), p)) {
459                        /* Look for victim */
460                        if (strstr(line, victim)) {
461                                /* Found victim - Get the rule number into rulenum*/
462                                if (sscanf(line, "%9[0-9]", rulenum) == 1) {
463                                        /* Delete the rule: */
464                                        debug(LOG_DEBUG, "Deleting rule %s from %s.%s because it mentions %s", rulenum, table, chain, victim);
465                                        safe_asprintf(&command2, "-t %s -D %s %s", table, chain, rulenum);
466                                        iptables_do_command(command2);
467                                        free(command2);
468                                        deleted = 1;
469                                        /* Do not keep looping - the captured rulenums will no longer be accurate */
470                                        break;
471                                }
472                        }
473                }
474                pclose(p);
475        }
476
477        free(command);
478        free(victim);
479
480        if (deleted) {
481                /* Recurse just in case there are more in the same table+chain */
482                iptables_fw_destroy_mention(table, chain, mention);
483        }
484
485        return (deleted);
486}
487
488/** Set if a specific client has access through the firewall */
489        int
490iptables_fw_access(fw_access_t type, const char *ip, const char *mac, int tag)
491{
492        int rc;
493
494        fw_quiet = 0;
495
496        switch(type) {
497                case FW_ACCESS_ALLOW:
498                        iptables_do_command("-t mangle -A " TABLE_WIFIDOG_OUTGOING " -s %s -m mac --mac-source %s -j MARK --set-mark %d", ip, mac, tag);
499                        rc = iptables_do_command("-t mangle -A " TABLE_WIFIDOG_INCOMING " -d %s -j ACCEPT", ip);
500                        break;
501                case FW_ACCESS_DENY:
502                        iptables_do_command("-t mangle -D " TABLE_WIFIDOG_OUTGOING " -s %s -m mac --mac-source %s -j MARK --set-mark %d", ip, mac, tag);
503                        rc = iptables_do_command("-t mangle -D " TABLE_WIFIDOG_INCOMING " -d %s -j ACCEPT", ip);
504                        break;
505                default:
506                        rc = -1;
507                        break;
508        }
509
510        return rc;
511}
512
513/** Update the counters of all the clients in the client list */
514        int
515iptables_fw_counters_update(void)
516{
517        FILE *output;
518        char *script,
519             ip[16],
520             rc;
521        unsigned long long int counter;
522        t_client *p1;
523        struct in_addr tempaddr;
524
525        /* Look for outgoing traffic */
526        safe_asprintf(&script, "%s %s", "iptables", "-v -n -x -t mangle -L " TABLE_WIFIDOG_OUTGOING);
527        iptables_insert_gateway_id(&script);
528        output = popen(script, "r");
529        free(script);
530        if (!output) {
531                debug(LOG_ERR, "popen(): %s", strerror(errno));
532                return -1;
533        }
534
535        /* skip the first two lines */
536        while (('\n' != fgetc(output)) && !feof(output))
537                ;
538        while (('\n' != fgetc(output)) && !feof(output))
539                ;
540        while (output && !(feof(output))) {
541                rc = fscanf(output, "%*s %llu %*s %*s %*s %*s %*s %15[0-9.] %*s %*s %*s %*s %*s %*s", &counter, ip);
542                //rc = fscanf(output, "%*s %llu %*s %*s %*s %*s %*s %15[0-9.] %*s %*s %*s %*s %*s 0x%*u", &counter, ip);
543                if (2 == rc && EOF != rc) {
544                        /* Sanity*/
545                        if (!inet_aton(ip, &tempaddr)) {
546                                debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip);
547                                continue;
548                        }
549                        debug(LOG_DEBUG, "Read outgoing traffic for %s: Bytes=%llu", ip, counter);
550                        LOCK_CLIENT_LIST();
551                        if ((p1 = client_list_find_by_ip(ip))) {
552                                if ((p1->counters.outgoing - p1->counters.outgoing_history) < counter) {
553                                        p1->counters.outgoing = p1->counters.outgoing_history + counter;
554                                        p1->counters.last_updated = time(NULL);
555                                        debug(LOG_DEBUG, "%s - Updated counter.outgoing to %llu bytes.  Updated last_updated to %d", ip, counter, p1->counters.last_updated);
556                                }
557                        } else {
558                                debug(LOG_ERR, "iptables_fw_counters_update(): Could not find %s in client list, this should not happen unless if the gateway crashed", ip);
559                                debug(LOG_ERR, "Preventively deleting firewall rules for %s in table %s", ip, TABLE_WIFIDOG_OUTGOING);
560                                iptables_fw_destroy_mention("mangle", TABLE_WIFIDOG_OUTGOING, ip);
561                                debug(LOG_ERR, "Preventively deleting firewall rules for %s in table %s", ip, TABLE_WIFIDOG_INCOMING);
562                                iptables_fw_destroy_mention("mangle", TABLE_WIFIDOG_INCOMING, ip);
563                        }
564                        UNLOCK_CLIENT_LIST();
565                }
566        }
567        pclose(output);
568
569        /* Look for incoming traffic */
570        safe_asprintf(&script, "%s %s", "iptables", "-v -n -x -t mangle -L " TABLE_WIFIDOG_INCOMING);
571        iptables_insert_gateway_id(&script);
572        output = popen(script, "r");
573        free(script);
574        if (!output) {
575                debug(LOG_ERR, "popen(): %s", strerror(errno));
576                return -1;
577        }
578
579        /* skip the first two lines */
580        while (('\n' != fgetc(output)) && !feof(output))
581                ;
582        while (('\n' != fgetc(output)) && !feof(output))
583                ;
584        while (output && !(feof(output))) {
585                rc = fscanf(output, "%*s %llu %*s %*s %*s %*s %*s %*s %15[0-9.]", &counter, ip);
586                if (2 == rc && EOF != rc) {
587                        /* Sanity*/
588                        if (!inet_aton(ip, &tempaddr)) {
589                                debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip);
590                                continue;
591                        }
592                        debug(LOG_DEBUG, "Read incoming traffic for %s: Bytes=%llu", ip, counter);
593                        LOCK_CLIENT_LIST();
594                        if ((p1 = client_list_find_by_ip(ip))) {
595                                if ((p1->counters.incoming - p1->counters.incoming_history) < counter) {
596                                        p1->counters.incoming = p1->counters.incoming_history + counter;
597                                        debug(LOG_DEBUG, "%s - Updated counter.incoming to %llu bytes", ip, counter);
598                                }
599                        } else {
600                                debug(LOG_ERR, "iptables_fw_counters_update(): Could not find %s in client list, this should not happen unless if the gateway crashed", ip);
601                                debug(LOG_ERR, "Preventively deleting firewall rules for %s in table %s", ip, TABLE_WIFIDOG_OUTGOING);
602                                iptables_fw_destroy_mention("mangle", TABLE_WIFIDOG_OUTGOING, ip);
603                                debug(LOG_ERR, "Preventively deleting firewall rules for %s in table %s", ip, TABLE_WIFIDOG_INCOMING);
604                                iptables_fw_destroy_mention("mangle", TABLE_WIFIDOG_INCOMING, ip);
605                        }
606                        UNLOCK_CLIENT_LIST();
607                }
608        }
609        pclose(output);
610
611        return 1;
612}
Note: See TracBrowser for help on using the browser.