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