root/branches/WIFIDOG_1_0_X/wifidog/src/fw_iptables.c @ 275

Revision 275, 11.5 KB (checked in by alexcv, 9 years ago)

Merged in phil's patch

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