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