00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00028 #define _GNU_SOURCE
00029
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <stdarg.h>
00033 #include <syslog.h>
00034 #include <errno.h>
00035 #include <string.h>
00036 #include <pthread.h>
00037 #include <sys/socket.h>
00038 #include <netinet/in.h>
00039 #include <arpa/inet.h>
00040
00041 #include "common.h"
00042
00043 #include "safe.h"
00044 #include "conf.h"
00045 #include "fw_iptables.h"
00046 #include "firewall.h"
00047 #include "debug.h"
00048 #include "util.h"
00049 #include "client_list.h"
00050
00051 static int iptables_do_command(char *format, ...);
00052 static char *iptables_compile(char *, char *, t_firewall_rule *);
00053 static void iptables_load_ruleset(char *, char *, char *);
00054
00055 extern pthread_mutex_t client_list_mutex;
00056 extern pthread_mutex_t config_mutex;
00057
00060 static int fw_quiet = 0;
00061
00064 static int
00065 iptables_do_command(char *format, ...)
00066 {
00067 va_list vlist;
00068 char *fmt_cmd,
00069 *cmd;
00070 int rc;
00071
00072 va_start(vlist, format);
00073 safe_vasprintf(&fmt_cmd, format, vlist);
00074 va_end(vlist);
00075
00076 safe_asprintf(&cmd, "iptables %s", fmt_cmd);
00077
00078 free(fmt_cmd);
00079
00080 debug(LOG_DEBUG, "Executing command: %s", cmd);
00081
00082 rc = execute(cmd, fw_quiet);
00083
00084 free(cmd);
00085
00086 return rc;
00087 }
00088
00097 static char *
00098 iptables_compile(char * table, char *chain, t_firewall_rule *rule)
00099 {
00100 char command[MAX_BUF],
00101 *mode;
00102
00103 memset(command, 0, MAX_BUF);
00104
00105 if (rule->block_allow == 1) {
00106 mode = safe_strdup("ACCEPT");
00107 } else {
00108 mode = safe_strdup("REJECT");
00109 }
00110
00111 snprintf(command, sizeof(command), "-t %s -A %s ",table, chain);
00112 if (rule->mask != NULL) {
00113 snprintf((command + strlen(command)), (sizeof(command) -
00114 strlen(command)), "-d %s ", rule->mask);
00115 }
00116 if (rule->protocol != NULL) {
00117 snprintf((command + strlen(command)), (sizeof(command) -
00118 strlen(command)), "-p %s ", rule->protocol);
00119 }
00120 if (rule->port != NULL) {
00121 snprintf((command + strlen(command)), (sizeof(command) -
00122 strlen(command)), "--dport %s ", rule->port);
00123 }
00124 snprintf((command + strlen(command)), (sizeof(command) -
00125 strlen(command)), "-j %s", mode);
00126
00127 free(mode);
00128
00129
00130
00131 return(safe_strdup(command));
00132 }
00133
00141 static void
00142 iptables_load_ruleset(char * table, char *ruleset, char *chain)
00143 {
00144 t_firewall_rule *rule;
00145 char *cmd;
00146
00147 debug(LOG_DEBUG, "Load ruleset %s into table %s, chain %s", ruleset, table, chain);
00148
00149 for (rule = get_ruleset(ruleset); rule != NULL; rule = rule->next) {
00150 cmd = iptables_compile(table, chain, rule);
00151 debug(LOG_DEBUG, "Loading rule \"%s\" into table %s, chain %s", cmd, table, chain);
00152 iptables_do_command(cmd);
00153 free(cmd);
00154 }
00155
00156 debug(LOG_DEBUG, "Ruleset %s loaded into table %s, chain %s", ruleset, table, chain);
00157 }
00158
00159 void
00160 iptables_fw_clear_authservers(void)
00161 {
00162 iptables_do_command("-t filter -F " TABLE_WIFIDOG_AUTHSERVERS);
00163 iptables_do_command("-t nat -F " TABLE_WIFIDOG_AUTHSERVERS);
00164 }
00165
00166 void
00167 iptables_fw_set_authservers(void)
00168 {
00169 s_config *config;
00170 t_auth_serv *auth_server;
00171
00172 config = config_get_config();
00173
00174 for (auth_server = config->auth_servers; auth_server != NULL; auth_server = auth_server->next) {
00175 if (auth_server->last_ip && strcmp(auth_server->last_ip, "0.0.0.0") != 0) {
00176 iptables_do_command("-t filter -A " TABLE_WIFIDOG_AUTHSERVERS " -d %s -j ACCEPT", auth_server->last_ip);
00177 iptables_do_command("-t nat -A " TABLE_WIFIDOG_AUTHSERVERS " -d %s -j ACCEPT", auth_server->last_ip);
00178 }
00179 }
00180
00181 }
00182
00185 int
00186 iptables_fw_init(void)
00187 {
00188 s_config *config;
00189 char * gw_interface = NULL;
00190 char * gw_address = NULL;
00191 char * ext_interface = NULL;
00192 int gw_port = 0;
00193 t_trusted_mac *p;
00194
00195 fw_quiet = 0;
00196
00197 LOCK_CONFIG();
00198 config = config_get_config();
00199 gw_interface = safe_strdup(config->gw_interface);
00200 gw_address = safe_strdup(config->gw_address);
00201 gw_port = config->gw_port;
00202 if (config->external_interface) {
00203 ext_interface = safe_strdup(config->external_interface);
00204 } else {
00205 ext_interface = get_ext_iface();
00206 }
00207 UNLOCK_CONFIG();
00208
00209 if (ext_interface == NULL) {
00210 debug(LOG_ERR, "FATAL: no external interface");
00211
00212 return 0;
00213 }
00214
00215
00216
00217
00218
00219
00220
00221 iptables_do_command("-t mangle -N " TABLE_WIFIDOG_TRUSTED);
00222 iptables_do_command("-t mangle -N " TABLE_WIFIDOG_OUTGOING);
00223 iptables_do_command("-t mangle -N " TABLE_WIFIDOG_INCOMING);
00224
00225
00226 iptables_do_command("-t mangle -I PREROUTING 1 -i %s -j " TABLE_WIFIDOG_OUTGOING, gw_interface);
00227 iptables_do_command("-t mangle -I PREROUTING 1 -i %s -j " TABLE_WIFIDOG_TRUSTED, gw_interface);
00228 iptables_do_command("-t mangle -I POSTROUTING 1 -o %s -j " TABLE_WIFIDOG_INCOMING, gw_interface);
00229
00230 for (p = config->trustedmaclist; p != NULL; p = p->next)
00231 iptables_do_command("-t mangle -A " TABLE_WIFIDOG_TRUSTED " -m mac --mac-source %s -j MARK --set-mark %d", p->mac, FW_MARK_KNOWN);
00232
00233
00234
00235
00236
00237
00238
00239
00240 iptables_do_command("-t nat -N " TABLE_WIFIDOG_OUTGOING);
00241 iptables_do_command("-t nat -N " TABLE_WIFIDOG_WIFI_TO_ROUTER);
00242 iptables_do_command("-t nat -N " TABLE_WIFIDOG_WIFI_TO_INTERNET);
00243 iptables_do_command("-t nat -N " TABLE_WIFIDOG_GLOBAL);
00244 iptables_do_command("-t nat -N " TABLE_WIFIDOG_UNKNOWN);
00245 iptables_do_command("-t nat -N " TABLE_WIFIDOG_AUTHSERVERS);
00246
00247
00248 iptables_do_command("-t nat -A PREROUTING -i %s -j " TABLE_WIFIDOG_OUTGOING, gw_interface);
00249
00250 iptables_do_command("-t nat -A " TABLE_WIFIDOG_OUTGOING " -d %s -j " TABLE_WIFIDOG_WIFI_TO_ROUTER, gw_address);
00251 iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_ROUTER " -j ACCEPT");
00252
00253 iptables_do_command("-t nat -A " TABLE_WIFIDOG_OUTGOING " -j " TABLE_WIFIDOG_WIFI_TO_INTERNET);
00254 iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j ACCEPT", FW_MARK_KNOWN);
00255 iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j ACCEPT", FW_MARK_PROBATION);
00256 iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_UNKNOWN);
00257
00258 iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -j " TABLE_WIFIDOG_AUTHSERVERS);
00259 iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -j " TABLE_WIFIDOG_GLOBAL);
00260 iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -p tcp --dport 80 -j REDIRECT --to-ports %d", gw_port);
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270 iptables_do_command("-t filter -N " TABLE_WIFIDOG_WIFI_TO_INTERNET);
00271 iptables_do_command("-t filter -N " TABLE_WIFIDOG_AUTHSERVERS);
00272 iptables_do_command("-t filter -N " TABLE_WIFIDOG_LOCKED);
00273 iptables_do_command("-t filter -N " TABLE_WIFIDOG_GLOBAL);
00274 iptables_do_command("-t filter -N " TABLE_WIFIDOG_VALIDATE);
00275 iptables_do_command("-t filter -N " TABLE_WIFIDOG_KNOWN);
00276 iptables_do_command("-t filter -N " TABLE_WIFIDOG_UNKNOWN);
00277
00278
00279
00280
00281 iptables_do_command("-t filter -I FORWARD -i %s -j " TABLE_WIFIDOG_WIFI_TO_INTERNET, gw_interface);
00282
00283
00284 iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m state --state INVALID -j DROP");
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294 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);
00295
00296 iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_AUTHSERVERS);
00297 iptables_fw_set_authservers();
00298
00299 iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j " TABLE_WIFIDOG_LOCKED, FW_MARK_LOCKED);
00300 iptables_load_ruleset("filter", "locked-users", TABLE_WIFIDOG_LOCKED);
00301
00302 iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_GLOBAL);
00303 iptables_load_ruleset("filter", "global", TABLE_WIFIDOG_GLOBAL);
00304 iptables_load_ruleset("nat", "global", TABLE_WIFIDOG_GLOBAL);
00305
00306 iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j " TABLE_WIFIDOG_VALIDATE, FW_MARK_PROBATION);
00307 iptables_load_ruleset("filter", "validating-users", TABLE_WIFIDOG_VALIDATE);
00308
00309 iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j " TABLE_WIFIDOG_KNOWN, FW_MARK_KNOWN);
00310 iptables_load_ruleset("filter", "known-users", TABLE_WIFIDOG_KNOWN);
00311
00312 iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_UNKNOWN);
00313 iptables_load_ruleset("filter", "unknown-users", TABLE_WIFIDOG_UNKNOWN);
00314 iptables_do_command("-t filter -A " TABLE_WIFIDOG_UNKNOWN " -j REJECT --reject-with icmp-port-unreachable");
00315
00316 free(gw_interface);
00317 free(gw_address);
00318
00319 return 1;
00320 }
00321
00326 int
00327 iptables_fw_destroy(void)
00328 {
00329 fw_quiet = 1;
00330
00331 debug(LOG_DEBUG, "Destroying our iptables entries");
00332
00333
00334
00335
00336
00337
00338 debug(LOG_DEBUG, "Destroying chains in the MANGLE table");
00339 iptables_fw_destroy_mention("mangle", "PREROUTING", TABLE_WIFIDOG_TRUSTED);
00340 iptables_fw_destroy_mention("mangle", "PREROUTING", TABLE_WIFIDOG_OUTGOING);
00341 iptables_fw_destroy_mention("mangle", "POSTROUTING", TABLE_WIFIDOG_INCOMING);
00342 iptables_do_command("-t mangle -F " TABLE_WIFIDOG_TRUSTED);
00343 iptables_do_command("-t mangle -F " TABLE_WIFIDOG_OUTGOING);
00344 iptables_do_command("-t mangle -F " TABLE_WIFIDOG_INCOMING);
00345 iptables_do_command("-t mangle -X " TABLE_WIFIDOG_TRUSTED);
00346 iptables_do_command("-t mangle -X " TABLE_WIFIDOG_OUTGOING);
00347 iptables_do_command("-t mangle -X " TABLE_WIFIDOG_INCOMING);
00348
00349
00350
00351
00352
00353
00354 debug(LOG_DEBUG, "Destroying chains in the NAT table");
00355 iptables_fw_destroy_mention("nat", "PREROUTING", TABLE_WIFIDOG_OUTGOING);
00356 iptables_do_command("-t nat -F " TABLE_WIFIDOG_AUTHSERVERS);
00357 iptables_do_command("-t nat -F " TABLE_WIFIDOG_OUTGOING);
00358 iptables_do_command("-t nat -F " TABLE_WIFIDOG_WIFI_TO_ROUTER);
00359 iptables_do_command("-t nat -F " TABLE_WIFIDOG_WIFI_TO_INTERNET);
00360 iptables_do_command("-t nat -F " TABLE_WIFIDOG_GLOBAL);
00361 iptables_do_command("-t nat -F " TABLE_WIFIDOG_UNKNOWN);
00362 iptables_do_command("-t nat -X " TABLE_WIFIDOG_AUTHSERVERS);
00363 iptables_do_command("-t nat -X " TABLE_WIFIDOG_OUTGOING);
00364 iptables_do_command("-t nat -X " TABLE_WIFIDOG_WIFI_TO_ROUTER);
00365 iptables_do_command("-t nat -X " TABLE_WIFIDOG_WIFI_TO_INTERNET);
00366 iptables_do_command("-t nat -X " TABLE_WIFIDOG_GLOBAL);
00367 iptables_do_command("-t nat -X " TABLE_WIFIDOG_UNKNOWN);
00368
00369
00370
00371
00372
00373
00374 debug(LOG_DEBUG, "Destroying chains in the FILTER table");
00375 iptables_fw_destroy_mention("filter", "FORWARD", TABLE_WIFIDOG_WIFI_TO_INTERNET);
00376 iptables_do_command("-t filter -F " TABLE_WIFIDOG_WIFI_TO_INTERNET);
00377 iptables_do_command("-t filter -F " TABLE_WIFIDOG_AUTHSERVERS);
00378 iptables_do_command("-t filter -F " TABLE_WIFIDOG_LOCKED);
00379 iptables_do_command("-t filter -F " TABLE_WIFIDOG_GLOBAL);
00380 iptables_do_command("-t filter -F " TABLE_WIFIDOG_VALIDATE);
00381 iptables_do_command("-t filter -F " TABLE_WIFIDOG_KNOWN);
00382 iptables_do_command("-t filter -F " TABLE_WIFIDOG_UNKNOWN);
00383 iptables_do_command("-t filter -X " TABLE_WIFIDOG_WIFI_TO_INTERNET);
00384 iptables_do_command("-t filter -X " TABLE_WIFIDOG_AUTHSERVERS);
00385 iptables_do_command("-t filter -X " TABLE_WIFIDOG_LOCKED);
00386 iptables_do_command("-t filter -X " TABLE_WIFIDOG_GLOBAL);
00387 iptables_do_command("-t filter -X " TABLE_WIFIDOG_VALIDATE);
00388 iptables_do_command("-t filter -X " TABLE_WIFIDOG_KNOWN);
00389 iptables_do_command("-t filter -X " TABLE_WIFIDOG_UNKNOWN);
00390
00391 return 1;
00392 }
00393
00394
00395
00396
00397
00398
00399
00400 int
00401 iptables_fw_destroy_mention(
00402 char * table,
00403 char * chain,
00404 char * mention
00405 ) {
00406 FILE *p = NULL;
00407 char *command = NULL;
00408 char *command2 = NULL;
00409 char line[MAX_BUF];
00410 char rulenum[10];
00411 int deleted = 0;
00412
00413 debug(LOG_DEBUG, "Attempting to destroy all mention of %s from %s.%s", mention, table, chain);
00414
00415 safe_asprintf(&command, "iptables -t %s -L %s -n --line-numbers -v", table, chain);
00416
00417 if ((p = popen(command, "r"))) {
00418
00419 while (!feof(p) && fgetc(p) != '\n');
00420 while (!feof(p) && fgetc(p) != '\n');
00421
00422 while (fgets(line, sizeof(line), p)) {
00423
00424 if (strstr(line, mention)) {
00425
00426 if (sscanf(line, "%9[0-9]", rulenum) == 1) {
00427
00428 debug(LOG_DEBUG, "Deleting rule %s from %s.%s because it mentions %s", rulenum, table, chain, mention);
00429 safe_asprintf(&command2, "-t %s -D %s %s", table, chain, rulenum);
00430 iptables_do_command(command2);
00431 free(command2);
00432 deleted = 1;
00433
00434 break;
00435 }
00436 }
00437 }
00438 pclose(p);
00439 }
00440
00441 free(command);
00442
00443 if (deleted) {
00444
00445 iptables_fw_destroy_mention(table, chain, mention);
00446 }
00447
00448 return (deleted);
00449 }
00450
00452 int
00453 iptables_fw_access(fw_access_t type, char *ip, char *mac, int tag)
00454 {
00455 int rc;
00456
00457 fw_quiet = 0;
00458
00459 switch(type) {
00460 case FW_ACCESS_ALLOW:
00461 iptables_do_command("-t mangle -A " TABLE_WIFIDOG_OUTGOING " -s %s -m mac --mac-source %s -j MARK --set-mark %d", ip, mac, tag);
00462 rc = iptables_do_command("-t mangle -A " TABLE_WIFIDOG_INCOMING " -d %s -j ACCEPT", ip);
00463 break;
00464 case FW_ACCESS_DENY:
00465 iptables_do_command("-t mangle -D " TABLE_WIFIDOG_OUTGOING " -s %s -m mac --mac-source %s -j MARK --set-mark %d", ip, mac, tag);
00466 rc = iptables_do_command("-t mangle -D " TABLE_WIFIDOG_INCOMING " -d %s -j ACCEPT", ip);
00467 break;
00468 default:
00469 rc = -1;
00470 break;
00471 }
00472
00473 return rc;
00474 }
00475
00477 int
00478 iptables_fw_counters_update(void)
00479 {
00480 FILE *output;
00481 char *script,
00482 ip[16],
00483 rc;
00484 unsigned long long int counter;
00485 t_client *p1;
00486 struct in_addr tempaddr;
00487
00488
00489 safe_asprintf(&script, "%s %s", "iptables", "-v -n -x -t mangle -L " TABLE_WIFIDOG_OUTGOING);
00490 output = popen(script, "r");
00491 free(script);
00492 if (!output) {
00493 debug(LOG_ERR, "popen(): %s", strerror(errno));
00494 return -1;
00495 }
00496
00497
00498 while (('\n' != fgetc(output)) && !feof(output))
00499 ;
00500 while (('\n' != fgetc(output)) && !feof(output))
00501 ;
00502 while (output && !(feof(output))) {
00503 rc = fscanf(output, "%*s %llu %*s %*s %*s %*s %*s %15[0-9.] %*s %*s %*s %*s %*s 0x%*u", &counter, ip);
00504 if (2 == rc && EOF != rc) {
00505
00506 if (!inet_aton(ip, &tempaddr)) {
00507 debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip);
00508 continue;
00509 }
00510 debug(LOG_DEBUG, "Read outgoing traffic for %s: Bytes=%llu", ip, counter);
00511 LOCK_CLIENT_LIST();
00512 if ((p1 = client_list_find_by_ip(ip))) {
00513 if ((p1->counters.outgoing - p1->counters.outgoing_history) < counter) {
00514 p1->counters.outgoing = p1->counters.outgoing_history + counter;
00515 p1->counters.last_updated = time(NULL);
00516 debug(LOG_DEBUG, "%s - Updated counter.outgoing to %llu bytes. Updated last_updated to %d", ip, counter, p1->counters.last_updated);
00517 }
00518 } else {
00519 debug(LOG_ERR, "Could not find %s in client list", ip);
00520 }
00521 UNLOCK_CLIENT_LIST();
00522 }
00523 }
00524 pclose(output);
00525
00526
00527 safe_asprintf(&script, "%s %s", "iptables", "-v -n -x -t mangle -L " TABLE_WIFIDOG_INCOMING);
00528 output = popen(script, "r");
00529 free(script);
00530 if (!output) {
00531 debug(LOG_ERR, "popen(): %s", strerror(errno));
00532 return -1;
00533 }
00534
00535
00536 while (('\n' != fgetc(output)) && !feof(output))
00537 ;
00538 while (('\n' != fgetc(output)) && !feof(output))
00539 ;
00540 while (output && !(feof(output))) {
00541 rc = fscanf(output, "%*s %llu %*s %*s %*s %*s %*s %*s %15[0-9.]", &counter, ip);
00542 if (2 == rc && EOF != rc) {
00543
00544 if (!inet_aton(ip, &tempaddr)) {
00545 debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip);
00546 continue;
00547 }
00548 debug(LOG_DEBUG, "Read incoming traffic for %s: Bytes=%llu", ip, counter);
00549 LOCK_CLIENT_LIST();
00550 if ((p1 = client_list_find_by_ip(ip))) {
00551 if ((p1->counters.incoming - p1->counters.incoming_history) < counter) {
00552 p1->counters.incoming = p1->counters.incoming_history + counter;
00553 debug(LOG_DEBUG, "%s - Updated counter.incoming to %llu bytes", ip, counter);
00554 }
00555 } else {
00556 debug(LOG_ERR, "Could not find %s in client list", ip);
00557 }
00558 UNLOCK_CLIENT_LIST();
00559 }
00560 }
00561 pclose(output);
00562
00563 return 1;
00564 }