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