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

Revision 256, 11.4 KB (checked in by alexcv, 9 years ago)

Extra mutex logging and extra logging in ping_thread()

  • 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/* $Header$ */
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
38#include "conf.h"
39#include "fw_iptables.h"
40#include "firewall.h"
41#include "debug.h"
42#include "util.h"
43#include "client_list.h"
44
45static int iptables_do_command(char *format, ...);
46
47extern pthread_mutex_t  client_list_mutex;
48extern pthread_mutex_t  config_mutex;
49
50/**
51Used to supress the error output of the firewall during destruction */ 
52static int fw_quiet = 0;
53
54/** @internal */
55static int
56iptables_do_command(char *format, ...)
57{
58    va_list vlist;
59    char *fmt_cmd,
60        *cmd;
61    int rc;
62
63    va_start(vlist, format);
64    vasprintf(&fmt_cmd, format, vlist);
65    asprintf(&cmd, "iptables %s", fmt_cmd);
66
67    rc = execute(cmd, fw_quiet);
68
69    free(fmt_cmd);
70    free(cmd);
71
72    return rc;
73}
74
75/** Initialize the firewall rules
76 */
77int
78iptables_fw_init(void)
79{
80    s_config *config;
81    t_auth_serv *auth_server;
82   
83    config = config_get_config();
84    fw_quiet = 0;
85   
86    iptables_do_command("-t nat -N " TABLE_WIFIDOG_VALIDATE);
87    iptables_do_command("-t nat -A " TABLE_WIFIDOG_VALIDATE " -d %s -j ACCEPT", config->gw_address);
88
89    LOCK_CONFIG();
90   
91    for (auth_server = config->auth_servers; auth_server != NULL;
92                    auth_server = auth_server->next) {
93        iptables_do_command("-t nat -A " TABLE_WIFIDOG_VALIDATE " -d %s -j ACCEPT", auth_server->authserv_hostname);
94    }
95
96    UNLOCK_CONFIG();
97
98    /** Insert global rules BEFORE the "defaults" */
99   
100    iptables_do_command("-t nat -A " TABLE_WIFIDOG_VALIDATE " -p udp --dport 67 -j ACCEPT");
101    iptables_do_command("-t nat -A " TABLE_WIFIDOG_VALIDATE " -p tcp --dport 67 -j ACCEPT");
102    iptables_do_command("-t nat -A " TABLE_WIFIDOG_VALIDATE " -p udp --dport 53 -j ACCEPT");
103    iptables_do_command("-t nat -A " TABLE_WIFIDOG_VALIDATE " -p tcp --dport 80 -j ACCEPT");
104    iptables_do_command("-t nat -A " TABLE_WIFIDOG_VALIDATE " -p tcp --dport 110 -j ACCEPT");
105    iptables_do_command("-t nat -A " TABLE_WIFIDOG_VALIDATE " -p tcp --dport 995 -j ACCEPT");
106    iptables_do_command("-t nat -A " TABLE_WIFIDOG_VALIDATE " -p tcp --dport 143 -j ACCEPT");
107    iptables_do_command("-t nat -A " TABLE_WIFIDOG_VALIDATE " -p tcp --dport 993 -j ACCEPT");
108    iptables_do_command("-t nat -A " TABLE_WIFIDOG_VALIDATE " -p tcp --dport 220 -j ACCEPT");
109    iptables_do_command("-t nat -A " TABLE_WIFIDOG_VALIDATE " -p tcp --dport 993 -j ACCEPT");
110    iptables_do_command("-t nat -A " TABLE_WIFIDOG_VALIDATE " -p tcp --dport 443 -j ACCEPT");
111    iptables_do_command("-t nat -A " TABLE_WIFIDOG_VALIDATE " -j DROP");
112
113    iptables_do_command("-t nat -N " TABLE_WIFIDOG_UNKNOWN);
114    iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -d %s -j ACCEPT", config->gw_address);
115
116    LOCK_CONFIG();
117   
118    for (auth_server = config->auth_servers; auth_server != NULL;
119                    auth_server = auth_server->next) {
120        iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -d %s -j ACCEPT", auth_server->authserv_hostname);
121    }
122
123    UNLOCK_CONFIG();
124
125    /** Insert global rules BEFORE the "defaults" */
126
127    iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -p udp --dport 67 -j ACCEPT");
128    iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -p tcp --dport 67 -j ACCEPT");
129    iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -p udp --dport 53 -j ACCEPT");
130    iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -p tcp --dport 80 -j REDIRECT --to-ports %d", config->gw_port);
131    iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -j DROP");
132
133    iptables_do_command("-t nat -N " TABLE_WIFIDOG_KNOWN);
134
135    /** Insert global rules BEFORE the "defaults" */
136
137    iptables_do_command("-t nat -A " TABLE_WIFIDOG_KNOWN " -j ACCEPT");
138
139    iptables_do_command("-t nat -N " TABLE_WIFIDOG_LOCKED);
140    iptables_do_command("-t nat -A " TABLE_WIFIDOG_LOCKED " -j DROP");
141
142    iptables_do_command("-t nat -N " TABLE_WIFIDOG_CLASS);
143    iptables_do_command("-t nat -A " TABLE_WIFIDOG_CLASS " -i %s -m mark --mark 0x%u -j " TABLE_WIFIDOG_VALIDATE, config->gw_interface, FW_MARK_PROBATION);
144    iptables_do_command("-t nat -A " TABLE_WIFIDOG_CLASS " -i %s -m mark --mark 0x%u -j " TABLE_WIFIDOG_KNOWN, config->gw_interface, FW_MARK_KNOWN);
145    iptables_do_command("-t nat -A " TABLE_WIFIDOG_CLASS " -i %s -m mark --mark 0x%u -j " TABLE_WIFIDOG_LOCKED, config->gw_interface, FW_MARK_LOCKED);
146    iptables_do_command("-t nat -A " TABLE_WIFIDOG_CLASS " -i %s -j " TABLE_WIFIDOG_UNKNOWN, config->gw_interface);
147    iptables_do_command("-t nat -I PREROUTING 1 -i %s -j " TABLE_WIFIDOG_CLASS, config->gw_interface);
148
149    iptables_do_command("-t mangle -N " TABLE_WIFIDOG_OUTGOING);
150    iptables_do_command("-t mangle -I PREROUTING 1 -i %s -j " TABLE_WIFIDOG_OUTGOING, config->gw_interface);
151
152    iptables_do_command("-t mangle -N " TABLE_WIFIDOG_INCOMING);
153    iptables_do_command("-t mangle -I FORWARD 1 -i %s -j " TABLE_WIFIDOG_INCOMING, config->external_interface);
154
155    return 1;
156}
157
158/** Remove the firewall rules
159 * This is used when we do a clean shutdown of WiFiDog and when it starts to make
160 * sure there are no rules left over
161 */
162int
163iptables_fw_destroy(void)
164{
165    int rc;
166    s_config *config = config_get_config();
167
168    fw_quiet = 1;
169    iptables_do_command("-t nat -F " TABLE_WIFIDOG_CLASS);
170    iptables_do_command("-t mangle -F " TABLE_WIFIDOG_OUTGOING);
171    iptables_do_command("-t mangle -F " TABLE_WIFIDOG_INCOMING);
172
173    iptables_do_command("-t nat -F " TABLE_WIFIDOG_VALIDATE);
174    iptables_do_command("-t nat -F " TABLE_WIFIDOG_UNKNOWN);
175    iptables_do_command("-t nat -F " TABLE_WIFIDOG_KNOWN);
176    iptables_do_command("-t nat -F " TABLE_WIFIDOG_LOCKED);
177    iptables_do_command("-t nat -X " TABLE_WIFIDOG_VALIDATE);
178    iptables_do_command("-t nat -X " TABLE_WIFIDOG_UNKNOWN);
179    iptables_do_command("-t nat -X " TABLE_WIFIDOG_KNOWN);
180    iptables_do_command("-t nat -X " TABLE_WIFIDOG_LOCKED);
181
182    /* We loop in case wifidog has crashed and left some unwanted rules,
183     * maybe we shouldn't loop forever, we'll try anyway
184     */
185    rc = 0;
186    while (rc == 0) {
187        rc = iptables_do_command("-t nat -D PREROUTING -i %s -j " TABLE_WIFIDOG_CLASS, config->gw_interface);
188    }
189    iptables_do_command("-t nat -X " TABLE_WIFIDOG_CLASS);
190
191    rc = 0;
192    while (rc == 0) {
193        rc = iptables_do_command("-t mangle -D PREROUTING -i %s -j " TABLE_WIFIDOG_OUTGOING, config->gw_interface);
194    }
195    iptables_do_command("-t mangle -X " TABLE_WIFIDOG_OUTGOING);
196
197    rc = 0;
198    while (rc == 0) {
199        rc = iptables_do_command("-t mangle -D FORWARD -i %s -j " TABLE_WIFIDOG_INCOMING, config->external_interface);
200    }
201    iptables_do_command("-t mangle -X " TABLE_WIFIDOG_INCOMING);
202
203    return 1;
204}
205
206/** Set the firewall access for a specific client */
207int
208iptables_fw_access(fw_access_t type, char *ip, char *mac, int tag)
209{
210    int rc;
211
212    fw_quiet = 0;
213
214    switch(type) {
215        case FW_ACCESS_ALLOW:
216            iptables_do_command("-t mangle -A " TABLE_WIFIDOG_OUTGOING " -s %s -m mac --mac-source %s -j MARK --set-mark %d", ip, mac, tag);
217            rc = iptables_do_command("-t mangle -A " TABLE_WIFIDOG_INCOMING " -d %s -j ACCEPT", ip);
218            break;
219        case FW_ACCESS_DENY:
220            iptables_do_command("-t mangle -D " TABLE_WIFIDOG_OUTGOING " -s %s -m mac --mac-source %s -j MARK --set-mark %d", ip, mac, tag);
221            rc = iptables_do_command("-t mangle -D " TABLE_WIFIDOG_INCOMING " -d %s -j ACCEPT", ip);
222            break;
223        default:
224            rc = -1;
225            break;
226    }
227
228    return rc;
229}
230
231/** Update the counters of all the clients in the client list */
232int
233iptables_fw_counters_update(void)
234{
235    FILE *output;
236    char *script,
237        ip[16],
238        rc;
239    unsigned long int counter;
240    t_client *p1;
241
242    /* Look for outgoing traffic */
243    asprintf(&script, "%s %s", "iptables", "-v -x -t mangle -L " TABLE_WIFIDOG_OUTGOING);
244    if (!(output = popen(script, "r"))) {
245        debug(LOG_ERR, "popen(): %s", strerror(errno));
246        return -1;
247    }
248    free(script);
249
250    /* skip the first two lines */
251    while (('\n' != fgetc(output)) && !feof(output))
252        ;
253    while (('\n' != fgetc(output)) && !feof(output))
254        ;
255    while (output && !(feof(output))) {
256        rc = fscanf(output, "%*s %lu %*s %*s %*s %*s %*s %s %*s %*s %*s %*s %*s 0x%*u", &counter, ip);
257        if (2 == rc && EOF != rc) {
258            debug(LOG_DEBUG, "Outgoing %s Bytes=%ld", ip, counter);
259            LOCK_CLIENT_LIST();
260            if ((p1 = client_list_find_by_ip(ip))) {
261                if (p1->counters.outgoing < counter) {
262                    p1->counters.outgoing = counter;
263                    p1->counters.last_updated = time(NULL);
264                    debug(LOG_DEBUG, "%s - Updated counter to %ld bytes", ip, counter);
265                }
266            } else {
267                debug(LOG_ERR, "Could not find %s in client list", ip);
268            }
269            UNLOCK_CLIENT_LIST();
270        }
271    }
272    pclose(output);
273
274    /* Look for incoming traffic */
275    asprintf(&script, "%s %s", "iptables", "-v -x -t mangle -L " TABLE_WIFIDOG_INCOMING);
276    if (!(output = popen(script, "r"))) {
277        debug(LOG_ERR, "popen(): %s", strerror(errno));
278        return -1;
279    }
280    free(script);
281
282    /* skip the first two lines */
283    while (('\n' != fgetc(output)) && !feof(output))
284        ;
285    while (('\n' != fgetc(output)) && !feof(output))
286        ;
287    while (output && !(feof(output))) {
288        rc = fscanf(output, "%*s %lu %*s %*s %*s %*s %*s %*s %s", &counter, ip);
289        if (2 == rc && EOF != rc) {
290            debug(LOG_DEBUG, "Incoming %s Bytes=%ld", ip, counter);
291            LOCK_CLIENT_LIST();
292            if ((p1 = client_list_find_by_ip(ip))) {
293                if (p1->counters.incoming < counter) {
294                    p1->counters.incoming = counter;
295                    p1->counters.last_updated = time(NULL);
296                    debug(LOG_DEBUG, "%s - Updated counter to %ld bytes", ip, counter);
297                }
298            } else {
299                debug(LOG_ERR, "Could not find %s in client list", ip);
300            }
301            UNLOCK_CLIENT_LIST();
302        }
303    }
304    pclose(output);
305
306    return 1;
307}
308
Note: See TracBrowser for help on using the browser.