root/trunk/wifidog/src/fw_iptables.c @ 1378

Revision 1378, 20.5 KB (checked in by wichert, 14 years ago)

Add exitcode to iptables failure errors

  • 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_id);
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                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 */
131static char *
132iptables_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 */
175static void
176iptables_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
193void
194iptables_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
200void
201iptables_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 */
219int
220iptables_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 */
353int
354iptables_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 */
427int
428iptables_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 */
480int
481iptables_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 */
505int
506iptables_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}
Note: See TracBrowser for help on using the browser.