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