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
00210
00211
00212
00213
00214
00215
00216 iptables_do_command("-t mangle -N " TABLE_WIFIDOG_TRUSTED);
00217 iptables_do_command("-t mangle -N " TABLE_WIFIDOG_OUTGOING);
00218 iptables_do_command("-t mangle -N " TABLE_WIFIDOG_INCOMING);
00219
00220
00221 iptables_do_command("-t mangle -I PREROUTING 1 -i %s -j " TABLE_WIFIDOG_OUTGOING, gw_interface);
00222 iptables_do_command("-t mangle -I PREROUTING 1 -i %s -j " TABLE_WIFIDOG_TRUSTED, gw_interface);
00223 iptables_do_command("-t mangle -I POSTROUTING 1 -o %s -j " TABLE_WIFIDOG_INCOMING, gw_interface);
00224
00225 for (p = config->trustedmaclist; p != NULL; p = p->next)
00226 iptables_do_command("-t mangle -A " TABLE_WIFIDOG_TRUSTED " -m mac --mac-source %s -j MARK --set-mark %d", p->mac, FW_MARK_KNOWN);
00227
00228
00229
00230
00231
00232
00233
00234
00235 iptables_do_command("-t nat -N " TABLE_WIFIDOG_OUTGOING);
00236 iptables_do_command("-t nat -N " TABLE_WIFIDOG_WIFI_TO_ROUTER);
00237 iptables_do_command("-t nat -N " TABLE_WIFIDOG_WIFI_TO_INTERNET);
00238 iptables_do_command("-t nat -N " TABLE_WIFIDOG_GLOBAL);
00239 iptables_do_command("-t nat -N " TABLE_WIFIDOG_UNKNOWN);
00240 iptables_do_command("-t nat -N " TABLE_WIFIDOG_AUTHSERVERS);
00241
00242
00243 iptables_do_command("-t nat -A PREROUTING -i %s -j " TABLE_WIFIDOG_OUTGOING, gw_interface);
00244
00245 iptables_do_command("-t nat -A " TABLE_WIFIDOG_OUTGOING " -d %s -j " TABLE_WIFIDOG_WIFI_TO_ROUTER, gw_address);
00246 iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_ROUTER " -j ACCEPT");
00247
00248 iptables_do_command("-t nat -A " TABLE_WIFIDOG_OUTGOING " -j " TABLE_WIFIDOG_WIFI_TO_INTERNET);
00249 iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j ACCEPT", FW_MARK_KNOWN);
00250 iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j ACCEPT", FW_MARK_PROBATION);
00251 iptables_do_command("-t nat -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_UNKNOWN);
00252
00253 iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -j " TABLE_WIFIDOG_AUTHSERVERS);
00254 iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -j " TABLE_WIFIDOG_GLOBAL);
00255 iptables_do_command("-t nat -A " TABLE_WIFIDOG_UNKNOWN " -p tcp --dport 80 -j REDIRECT --to-ports %d", gw_port);
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265 iptables_do_command("-t filter -N " TABLE_WIFIDOG_WIFI_TO_INTERNET);
00266 iptables_do_command("-t filter -N " TABLE_WIFIDOG_AUTHSERVERS);
00267 iptables_do_command("-t filter -N " TABLE_WIFIDOG_LOCKED);
00268 iptables_do_command("-t filter -N " TABLE_WIFIDOG_GLOBAL);
00269 iptables_do_command("-t filter -N " TABLE_WIFIDOG_VALIDATE);
00270 iptables_do_command("-t filter -N " TABLE_WIFIDOG_KNOWN);
00271 iptables_do_command("-t filter -N " TABLE_WIFIDOG_UNKNOWN);
00272
00273
00274
00275
00276 iptables_do_command("-t filter -I FORWARD -i %s -j " TABLE_WIFIDOG_WIFI_TO_INTERNET, gw_interface);
00277
00278
00279 iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m state --state INVALID -j DROP");
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289 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);
00290
00291 iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_AUTHSERVERS);
00292 iptables_fw_set_authservers();
00293
00294 iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j " TABLE_WIFIDOG_LOCKED, FW_MARK_LOCKED);
00295 iptables_load_ruleset("filter", "locked-users", TABLE_WIFIDOG_LOCKED);
00296
00297 iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_GLOBAL);
00298 iptables_load_ruleset("filter", "global", TABLE_WIFIDOG_GLOBAL);
00299 iptables_load_ruleset("nat", "global", TABLE_WIFIDOG_GLOBAL);
00300
00301 iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j " TABLE_WIFIDOG_VALIDATE, FW_MARK_PROBATION);
00302 iptables_load_ruleset("filter", "validating-users", TABLE_WIFIDOG_VALIDATE);
00303
00304 iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -m mark --mark 0x%u -j " TABLE_WIFIDOG_KNOWN, FW_MARK_KNOWN);
00305 iptables_load_ruleset("filter", "known-users", TABLE_WIFIDOG_KNOWN);
00306
00307 iptables_do_command("-t filter -A " TABLE_WIFIDOG_WIFI_TO_INTERNET " -j " TABLE_WIFIDOG_UNKNOWN);
00308 iptables_load_ruleset("filter", "unknown-users", TABLE_WIFIDOG_UNKNOWN);
00309 iptables_do_command("-t filter -A " TABLE_WIFIDOG_UNKNOWN " -j REJECT --reject-with icmp-port-unreachable");
00310
00311 free(gw_interface);
00312 free(gw_address);
00313
00314 return 1;
00315 }
00316
00321 int
00322 iptables_fw_destroy(void)
00323 {
00324 fw_quiet = 1;
00325
00326 debug(LOG_DEBUG, "Destroying our iptables entries");
00327
00328
00329
00330
00331
00332
00333 debug(LOG_DEBUG, "Destroying chains in the MANGLE table");
00334 iptables_fw_destroy_mention("mangle", "PREROUTING", TABLE_WIFIDOG_TRUSTED);
00335 iptables_fw_destroy_mention("mangle", "PREROUTING", TABLE_WIFIDOG_OUTGOING);
00336 iptables_fw_destroy_mention("mangle", "POSTROUTING", TABLE_WIFIDOG_INCOMING);
00337 iptables_do_command("-t mangle -F " TABLE_WIFIDOG_TRUSTED);
00338 iptables_do_command("-t mangle -F " TABLE_WIFIDOG_OUTGOING);
00339 iptables_do_command("-t mangle -F " TABLE_WIFIDOG_INCOMING);
00340 iptables_do_command("-t mangle -X " TABLE_WIFIDOG_TRUSTED);
00341 iptables_do_command("-t mangle -X " TABLE_WIFIDOG_OUTGOING);
00342 iptables_do_command("-t mangle -X " TABLE_WIFIDOG_INCOMING);
00343
00344
00345
00346
00347
00348
00349 debug(LOG_DEBUG, "Destroying chains in the NAT table");
00350 iptables_fw_destroy_mention("nat", "PREROUTING", TABLE_WIFIDOG_OUTGOING);
00351 iptables_do_command("-t nat -F " TABLE_WIFIDOG_AUTHSERVERS);
00352 iptables_do_command("-t nat -F " TABLE_WIFIDOG_OUTGOING);
00353 iptables_do_command("-t nat -F " TABLE_WIFIDOG_WIFI_TO_ROUTER);
00354 iptables_do_command("-t nat -F " TABLE_WIFIDOG_WIFI_TO_INTERNET);
00355 iptables_do_command("-t nat -F " TABLE_WIFIDOG_GLOBAL);
00356 iptables_do_command("-t nat -F " TABLE_WIFIDOG_UNKNOWN);
00357 iptables_do_command("-t nat -X " TABLE_WIFIDOG_AUTHSERVERS);
00358 iptables_do_command("-t nat -X " TABLE_WIFIDOG_OUTGOING);
00359 iptables_do_command("-t nat -X " TABLE_WIFIDOG_WIFI_TO_ROUTER);
00360 iptables_do_command("-t nat -X " TABLE_WIFIDOG_WIFI_TO_INTERNET);
00361 iptables_do_command("-t nat -X " TABLE_WIFIDOG_GLOBAL);
00362 iptables_do_command("-t nat -X " TABLE_WIFIDOG_UNKNOWN);
00363
00364
00365
00366
00367
00368
00369 debug(LOG_DEBUG, "Destroying chains in the FILTER table");
00370 iptables_fw_destroy_mention("filter", "FORWARD", TABLE_WIFIDOG_WIFI_TO_INTERNET);
00371 iptables_do_command("-t filter -F " TABLE_WIFIDOG_WIFI_TO_INTERNET);
00372 iptables_do_command("-t filter -F " TABLE_WIFIDOG_AUTHSERVERS);
00373 iptables_do_command("-t filter -F " TABLE_WIFIDOG_LOCKED);
00374 iptables_do_command("-t filter -F " TABLE_WIFIDOG_GLOBAL);
00375 iptables_do_command("-t filter -F " TABLE_WIFIDOG_VALIDATE);
00376 iptables_do_command("-t filter -F " TABLE_WIFIDOG_KNOWN);
00377 iptables_do_command("-t filter -F " TABLE_WIFIDOG_UNKNOWN);
00378 iptables_do_command("-t filter -X " TABLE_WIFIDOG_WIFI_TO_INTERNET);
00379 iptables_do_command("-t filter -X " TABLE_WIFIDOG_AUTHSERVERS);
00380 iptables_do_command("-t filter -X " TABLE_WIFIDOG_LOCKED);
00381 iptables_do_command("-t filter -X " TABLE_WIFIDOG_GLOBAL);
00382 iptables_do_command("-t filter -X " TABLE_WIFIDOG_VALIDATE);
00383 iptables_do_command("-t filter -X " TABLE_WIFIDOG_KNOWN);
00384 iptables_do_command("-t filter -X " TABLE_WIFIDOG_UNKNOWN);
00385
00386 return 1;
00387 }
00388
00389
00390
00391
00392
00393
00394
00395 int
00396 iptables_fw_destroy_mention(
00397 char * table,
00398 char * chain,
00399 char * mention
00400 ) {
00401 FILE *p = NULL;
00402 char *command = NULL;
00403 char *command2 = NULL;
00404 char line[MAX_BUF];
00405 char rulenum[10];
00406 int deleted = 0;
00407
00408 debug(LOG_DEBUG, "Attempting to destroy all mention of %s from %s.%s", mention, table, chain);
00409
00410 safe_asprintf(&command, "iptables -t %s -L %s -n --line-numbers -v", table, chain);
00411
00412 if ((p = popen(command, "r"))) {
00413
00414 while (!feof(p) && fgetc(p) != '\n');
00415 while (!feof(p) && fgetc(p) != '\n');
00416
00417 while (fgets(line, sizeof(line), p)) {
00418
00419 if (strstr(line, mention)) {
00420
00421 if (sscanf(line, "%9[0-9]", rulenum) == 1) {
00422
00423 debug(LOG_DEBUG, "Deleting rule %s from %s.%s because it mentions %s", rulenum, table, chain, mention);
00424 safe_asprintf(&command2, "-t %s -D %s %s", table, chain, rulenum);
00425 iptables_do_command(command2);
00426 free(command2);
00427 deleted = 1;
00428
00429 break;
00430 }
00431 }
00432 }
00433 pclose(p);
00434 }
00435
00436 free(command);
00437
00438 if (deleted) {
00439
00440 iptables_fw_destroy_mention(table, chain, mention);
00441 }
00442
00443 return (deleted);
00444 }
00445
00447 int
00448 iptables_fw_access(fw_access_t type, char *ip, char *mac, int tag)
00449 {
00450 int rc;
00451
00452 fw_quiet = 0;
00453
00454 switch(type) {
00455 case FW_ACCESS_ALLOW:
00456 iptables_do_command("-t mangle -A " TABLE_WIFIDOG_OUTGOING " -s %s -m mac --mac-source %s -j MARK --set-mark %d", ip, mac, tag);
00457 rc = iptables_do_command("-t mangle -A " TABLE_WIFIDOG_INCOMING " -d %s -j ACCEPT", ip);
00458 break;
00459 case FW_ACCESS_DENY:
00460 iptables_do_command("-t mangle -D " TABLE_WIFIDOG_OUTGOING " -s %s -m mac --mac-source %s -j MARK --set-mark %d", ip, mac, tag);
00461 rc = iptables_do_command("-t mangle -D " TABLE_WIFIDOG_INCOMING " -d %s -j DROP", ip);
00462 break;
00463 default:
00464 rc = -1;
00465 break;
00466 }
00467
00468 return rc;
00469 }
00470
00472 int
00473 iptables_fw_counters_update(void)
00474 {
00475 FILE *output;
00476 char *script,
00477 ip[16],
00478 rc;
00479 unsigned long long int counter;
00480 t_client *p1;
00481 struct in_addr tempaddr;
00482
00483
00484 safe_asprintf(&script, "%s %s", "iptables", "-v -n -x -t mangle -L " TABLE_WIFIDOG_OUTGOING);
00485 output = popen(script, "r");
00486 free(script);
00487 if (!output) {
00488 debug(LOG_ERR, "popen(): %s", strerror(errno));
00489 return -1;
00490 }
00491
00492
00493 while (('\n' != fgetc(output)) && !feof(output))
00494 ;
00495 while (('\n' != fgetc(output)) && !feof(output))
00496 ;
00497 while (output && !(feof(output))) {
00498 rc = fscanf(output, "%*s %llu %*s %*s %*s %*s %*s %15[0-9.] %*s %*s %*s %*s %*s 0x%*u", &counter, ip);
00499 if (2 == rc && EOF != rc) {
00500
00501 if (!inet_aton(ip, &tempaddr)) {
00502 debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip);
00503 continue;
00504 }
00505 debug(LOG_DEBUG, "Outgoing %s Bytes=%llu", ip, counter);
00506 LOCK_CLIENT_LIST();
00507 if ((p1 = client_list_find_by_ip(ip))) {
00508 if ((p1->counters.outgoing - p1->counters.outgoing_history) < counter) {
00509 p1->counters.outgoing = p1->counters.outgoing_history + counter;
00510 p1->counters.last_updated = time(NULL);
00511 debug(LOG_DEBUG, "%s - Updated counter.outgoing to %llu bytes", ip, counter);
00512 }
00513 } else {
00514 debug(LOG_ERR, "Could not find %s in client list", ip);
00515 }
00516 UNLOCK_CLIENT_LIST();
00517 }
00518 }
00519 pclose(output);
00520
00521
00522 safe_asprintf(&script, "%s %s", "iptables", "-v -n -x -t mangle -L " TABLE_WIFIDOG_INCOMING);
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 %*s %15[0-9.]", &counter, ip);
00537 if (2 == rc && EOF != rc) {
00538
00539 if (!inet_aton(ip, &tempaddr)) {
00540 debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip);
00541 continue;
00542 }
00543 debug(LOG_DEBUG, "Incoming %s Bytes=%llu", ip, counter);
00544 LOCK_CLIENT_LIST();
00545 if ((p1 = client_list_find_by_ip(ip))) {
00546 if ((p1->counters.incoming - p1->counters.incoming_history) < counter) {
00547 p1->counters.incoming = p1->counters.incoming_history + counter;
00548 debug(LOG_DEBUG, "%s - Updated counter.incoming to %llu bytes", ip, counter);
00549 }
00550 } else {
00551 debug(LOG_ERR, "Could not find %s in client list", ip);
00552 }
00553 UNLOCK_CLIENT_LIST();
00554 }
00555 }
00556 pclose(output);
00557
00558 return 1;
00559 }