X-Git-Url: http://git.openwrt.org/?p=project%2Ffirewall3.git;a=blobdiff_plain;f=iptables.c;h=d8482399dbaa85f611f6720aaae1d29727b0bf17;hp=e9f4ca7d59573189c8aa433fb322712b39f2bdb7;hb=HEAD;hpb=bd40ba4584141ce34f3d5c42841abafccad06bdd diff --git a/iptables.c b/iptables.c index e9f4ca7..d03d1dd 100644 --- a/iptables.c +++ b/iptables.c @@ -40,10 +40,12 @@ #include #include +#include + #include "options.h" /* xtables interface */ -#if (XTABLES_VERSION_CODE == 10 || XTABLES_VERSION_CODE == 11) +#if (XTABLES_VERSION_CODE >= 10) # include "xtables-10.h" #elif (XTABLES_VERSION_CODE == 5) # include "xtables-5.h" @@ -53,6 +55,8 @@ #include "iptables.h" +#define XT_LOCK_NAME "/var/run/xtables.lock" +static int xt_lock_fd = -1; struct fw3_ipt_rule { struct fw3_ipt_handle *h; @@ -73,15 +77,38 @@ struct fw3_ipt_rule { }; static struct option base_opts[] = { - { .name = "match", .has_arg = 1, .val = 'm' }, - { .name = "jump", .has_arg = 1, .val = 'j' }, + { .name = "match", .has_arg = 1, .val = 'm' }, + { .name = "jump", .has_arg = 1, .val = 'j' }, + { .name = "in-interface", .has_arg = 1, .val = 'i' }, + { .name = "out-interface", .has_arg = 1, .val = 'o' }, + { .name = "source", .has_arg = 1, .val = 's' }, + { .name = "destination", .has_arg = 1, .val = 'd' }, { NULL } }; + +static jmp_buf fw3_ipt_error_jmp; + +static __attribute__((noreturn)) +void fw3_ipt_error_handler(enum xtables_exittype status, + const char *fmt, ...) +{ + va_list args; + + fprintf(stderr, " ! Exception: "); + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + + longjmp(fw3_ipt_error_jmp, status); +} + static struct xtables_globals xtg = { .option_offset = 0, .program_version = "4", .orig_opts = base_opts, + .exit_err = fw3_ipt_error_handler, #if XTABLES_VERSION_CODE > 10 .compat_rev = xtables_compatible_revision, #endif @@ -91,6 +118,7 @@ static struct xtables_globals xtg6 = { .option_offset = 0, .program_version = "6", .orig_opts = base_opts, + .exit_err = fw3_ipt_error_handler, #if XTABLES_VERSION_CODE > 10 .compat_rev = xtables_compatible_revision, #endif @@ -113,12 +141,11 @@ void get_kernel_version(void) { static struct utsname uts; - int x = 0, y = 0, z = 0; + int x = 3, y = 0, z = 0; - if (uname(&uts) == -1) - sprintf(uts.release, "3.0.0"); + if (uname(&uts) != -1) + sscanf(uts.release, "%d.%d.%d", &x, &y, &z); - sscanf(uts.release, "%d.%d.%d", &x, &y, &z); kernel_version = 0x10000 * x + 0x100 * y + z; } @@ -142,6 +169,11 @@ fw3_ipt_open(enum fw3_family family, enum fw3_table table) xtables_init(); + while (!fw3_lock_path(&xt_lock_fd, XT_LOCK_NAME)) { + warn("Currently busy xtables.lock - wait 1 second"); + sleep(1); + } + if (family == FW3_FAMILY_V6) { #ifndef DISABLE_IPV6 @@ -166,6 +198,7 @@ fw3_ipt_open(enum fw3_family family, enum fw3_table table) if (!h->handle) { free(h); + fw3_unlock_path(&xt_lock_fd, XT_LOCK_NAME); return NULL; } @@ -295,9 +328,61 @@ delete_rules(struct fw3_ipt_handle *h, const char *target) } } +static bool +is_referenced(struct fw3_ipt_handle *h, const char *target) +{ + const struct ipt_entry *e; + const char *chain; + const char *t; + +#ifndef DISABLE_IPV6 + if (h->family == FW3_FAMILY_V6) + { + for (chain = ip6tc_first_chain(h->handle); + chain != NULL; + chain = ip6tc_next_chain(h->handle)) + { + const struct ip6t_entry *e6; + for (e6 = ip6tc_first_rule(chain, h->handle); + e6 != NULL; + e6 = ip6tc_next_rule(e6, h->handle)) + { + t = ip6tc_get_target(e6, h->handle); + + if (*t && !strcmp(t, target)) + return true; + } + } + } + else +#endif + { + for (chain = iptc_first_chain(h->handle); + chain != NULL; + chain = iptc_next_chain(h->handle)) + { + for (e = iptc_first_rule(chain, h->handle); + e != NULL; + e = iptc_next_rule(e, h->handle)) + { + t = iptc_get_target(e, h->handle); + + if (*t && !strcmp(t, target)) + return true; + } + } + } + + return false; +} + void -fw3_ipt_delete_chain(struct fw3_ipt_handle *h, const char *chain) +fw3_ipt_delete_chain(struct fw3_ipt_handle *h, bool if_unused, + const char *chain) { + if (if_unused && is_referenced(h, chain)) + return; + delete_rules(h, chain); if (fw3_pr_debug) @@ -391,20 +476,29 @@ fw3_ipt_delete_id_rules(struct fw3_ipt_handle *h, const char *chain) } } -void -fw3_ipt_create_chain(struct fw3_ipt_handle *h, const char *fmt, ...) + +static bool +is_chain(struct fw3_ipt_handle *h, const char *name) { - char buf[32]; - va_list ap; +#ifndef DISABLE_IPV6 + if (h->family == FW3_FAMILY_V6) + return ip6tc_is_chain(name, h->handle); + else +#endif + return iptc_is_chain(name, h->handle); +} - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf) - 1, fmt, ap); - va_end(ap); +void +fw3_ipt_create_chain(struct fw3_ipt_handle *h, bool ignore_existing, + const char *chain) +{ + if (ignore_existing && is_chain(h, chain)) + return; if (fw3_pr_debug) - debug(h, "-N %s\n", buf); + debug(h, "-N %s\n", chain); - iptc_create_chain(buf, h->handle); + iptc_create_chain(chain, h->handle); } void @@ -480,7 +574,7 @@ fw3_ipt_gc(struct fw3_ipt_handle *h) if (!chain_is_empty(h, chain)) continue; - fw3_ipt_delete_chain(h, chain); + fw3_ipt_delete_chain(h, false, chain); found = true; break; } @@ -503,7 +597,7 @@ fw3_ipt_gc(struct fw3_ipt_handle *h) warn("D=%s\n", chain); - fw3_ipt_delete_chain(h, chain); + fw3_ipt_delete_chain(h, false, chain); found = true; break; } @@ -535,6 +629,7 @@ fw3_ipt_commit(struct fw3_ipt_handle *h) void fw3_ipt_close(struct fw3_ipt_handle *h) { + fw3_unlock_path(&xt_lock_fd, XT_LOCK_NAME); free(h); } @@ -553,17 +648,6 @@ fw3_ipt_rule_new(struct fw3_ipt_handle *h) } -static bool -is_chain(struct fw3_ipt_handle *h, const char *name) -{ -#ifndef DISABLE_IPV6 - if (h->family == FW3_FAMILY_V6) - return ip6tc_is_chain(name, h->handle); - else -#endif - return iptc_is_chain(name, h->handle); -} - static char * get_protoname(struct fw3_ipt_rule *r) { @@ -625,12 +709,18 @@ init_match(struct fw3_ipt_rule *r, struct xtables_match *m, bool no_clone) static bool need_protomatch(struct fw3_ipt_rule *r, const char *pname) { + struct xtables_match *match; + if (!pname) return false; - if (!xtables_find_match(pname, XTF_DONT_LOAD, NULL)) + match = xtables_find_match(pname, XTF_DONT_LOAD, NULL); + if (!match) return true; + /* Free any kind of clone from xtables_find_match */ + if (match == match->next) + free(match); return !r->protocol_loaded; } @@ -860,7 +950,7 @@ void fw3_ipt_rule_sport_dport(struct fw3_ipt_rule *r, struct fw3_port *sp, struct fw3_port *dp) { - char buf[sizeof("65535:65535\0")]; + char buf[sizeof("65535:65535")]; if ((!sp || !sp->set) && (!dp || !dp->set)) return; @@ -871,9 +961,9 @@ fw3_ipt_rule_sport_dport(struct fw3_ipt_rule *r, if (sp && sp->set) { if (sp->port_min == sp->port_max) - sprintf(buf, "%u", sp->port_min); + snprintf(buf, sizeof(buf), "%u", sp->port_min); else - sprintf(buf, "%u:%u", sp->port_min, sp->port_max); + snprintf(buf, sizeof(buf), "%u:%u", sp->port_min, sp->port_max); fw3_ipt_rule_addarg(r, sp->invert, "--sport", buf); } @@ -881,9 +971,9 @@ fw3_ipt_rule_sport_dport(struct fw3_ipt_rule *r, if (dp && dp->set) { if (dp->port_min == dp->port_max) - sprintf(buf, "%u", dp->port_min); + snprintf(buf, sizeof(buf), "%u", dp->port_min); else - sprintf(buf, "%u:%u", dp->port_min, dp->port_max); + snprintf(buf, sizeof(buf), "%u:%u", dp->port_min, dp->port_max); fw3_ipt_rule_addarg(r, dp->invert, "--dport", buf); } @@ -892,9 +982,10 @@ fw3_ipt_rule_sport_dport(struct fw3_ipt_rule *r, void fw3_ipt_rule_device(struct fw3_ipt_rule *r, const char *device, bool out) { + struct fw3_device dev = { .any = false }; + if (device) { - struct fw3_device dev = { .any = false }; - strncpy(dev.name, device, sizeof(dev.name) - 1); + snprintf(dev.name, sizeof(dev.name), "%s", device); fw3_ipt_rule_in_out(r, (out) ? NULL : &dev, (out) ? &dev : NULL); } } @@ -902,14 +993,14 @@ fw3_ipt_rule_device(struct fw3_ipt_rule *r, const char *device, bool out) void fw3_ipt_rule_mac(struct fw3_ipt_rule *r, struct fw3_mac *mac) { - char buf[sizeof("ff:ff:ff:ff:ff:ff\0")]; + char buf[sizeof("ff:ff:ff:ff:ff:ff")]; uint8_t *addr = mac->mac.ether_addr_octet; if (!mac) return; - sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); fw3_ipt_rule_addarg(r, false, "-m", "mac"); fw3_ipt_rule_addarg(r, mac->invert, "--mac-source", buf); @@ -918,7 +1009,7 @@ fw3_ipt_rule_mac(struct fw3_ipt_rule *r, struct fw3_mac *mac) void fw3_ipt_rule_icmptype(struct fw3_ipt_rule *r, struct fw3_icmptype *icmp) { - char buf[sizeof("255/255\0")]; + char buf[sizeof("255/255")]; if (!icmp) return; @@ -927,9 +1018,9 @@ fw3_ipt_rule_icmptype(struct fw3_ipt_rule *r, struct fw3_icmptype *icmp) if (r->h->family == FW3_FAMILY_V6) { if (icmp->code6_min == 0 && icmp->code6_max == 0xFF) - sprintf(buf, "%u", icmp->type6); + snprintf(buf, sizeof(buf), "%u", icmp->type6); else - sprintf(buf, "%u/%u", icmp->type6, icmp->code6_min); + snprintf(buf, sizeof(buf), "%u/%u", icmp->type6, icmp->code6_min); fw3_ipt_rule_addarg(r, icmp->invert, "--icmpv6-type", buf); } @@ -937,9 +1028,9 @@ fw3_ipt_rule_icmptype(struct fw3_ipt_rule *r, struct fw3_icmptype *icmp) #endif { if (icmp->code_min == 0 && icmp->code_max == 0xFF) - sprintf(buf, "%u", icmp->type); + snprintf(buf, sizeof(buf), "%u", icmp->type); else - sprintf(buf, "%u/%u", icmp->type, icmp->code_min); + snprintf(buf, sizeof(buf), "%u/%u", icmp->type, icmp->code_min); fw3_ipt_rule_addarg(r, icmp->invert, "--icmp-type", buf); } @@ -948,19 +1039,19 @@ fw3_ipt_rule_icmptype(struct fw3_ipt_rule *r, struct fw3_icmptype *icmp) void fw3_ipt_rule_limit(struct fw3_ipt_rule *r, struct fw3_limit *limit) { - char buf[sizeof("-4294967296/second\0")]; + char buf[sizeof("-4294967296/second")]; if (!limit || limit->rate <= 0) return; fw3_ipt_rule_addarg(r, false, "-m", "limit"); - sprintf(buf, "%u/%s", limit->rate, fw3_limit_units[limit->unit]); + snprintf(buf, sizeof(buf), "%u/%s", limit->rate, fw3_limit_units[limit->unit]); fw3_ipt_rule_addarg(r, limit->invert, "--limit", buf); if (limit->burst > 0) { - sprintf(buf, "%u", limit->burst); + snprintf(buf, sizeof(buf), "%u", limit->burst); fw3_ipt_rule_addarg(r, limit->invert, "--limit-burst", buf); } } @@ -968,9 +1059,10 @@ fw3_ipt_rule_limit(struct fw3_ipt_rule *r, struct fw3_limit *limit) void fw3_ipt_rule_ipset(struct fw3_ipt_rule *r, struct fw3_setmatch *match) { - char buf[sizeof("dst,dst,dst\0")]; + char buf[sizeof("dst,dst,dst")]; char *p = buf; - int i = 0; + int i = 0, len; + size_t rem = sizeof(buf); struct fw3_ipset *set; struct fw3_ipset_datatype *type; @@ -984,10 +1076,23 @@ fw3_ipt_rule_ipset(struct fw3_ipt_rule *r, struct fw3_setmatch *match) if (i >= 3) break; - if (p > buf) + if (p > buf) { + if (rem <= 1) + break; + *p++ = ','; + *p = 0; + rem--; + } + + len = snprintf(p, rem, "%s", match->dir[i] ? match->dir[i] : type->dir); + + if (len < 0 || len >= rem) + break; + + rem -= len; + p += len; - p += sprintf(p, "%s", match->dir[i] ? match->dir[i] : type->dir); i++; } @@ -999,18 +1104,30 @@ fw3_ipt_rule_ipset(struct fw3_ipt_rule *r, struct fw3_setmatch *match) fw3_ipt_rule_addarg(r, false, buf, NULL); } +void +fw3_ipt_rule_helper(struct fw3_ipt_rule *r, struct fw3_cthelpermatch *match) +{ + if (!match || !match->set || !match->ptr) + return; + + fw3_ipt_rule_addarg(r, false, "-m", "helper"); + fw3_ipt_rule_addarg(r, match->invert, "--helper", match->ptr->name); +} + void fw3_ipt_rule_time(struct fw3_ipt_rule *r, struct fw3_time *time) { - int i; + int i, len; struct tm empty = { 0 }; - char buf[84]; /* sizeof("1,2,3,...,30,31\0") */ + char buf[84]; /* sizeof("1,2,3,...,30,31") */ char *p; bool d1 = memcmp(&time->datestart, &empty, sizeof(empty)); bool d2 = memcmp(&time->datestop, &empty, sizeof(empty)); + size_t rem; + if (!d1 && !d2 && !time->timestart && !time->timestop && !(time->monthdays & 0xFFFFFFFE) && !(time->weekdays & 0xFE)) { @@ -1019,8 +1136,8 @@ fw3_ipt_rule_time(struct fw3_ipt_rule *r, struct fw3_time *time) fw3_ipt_rule_addarg(r, false, "-m", "time"); - if (time->utc) - fw3_ipt_rule_addarg(r, false, "--utc", NULL); + if (!time->utc) + fw3_ipt_rule_addarg(r, false, "--kerneltz", NULL); if (d1) { @@ -1036,7 +1153,7 @@ fw3_ipt_rule_time(struct fw3_ipt_rule *r, struct fw3_time *time) if (time->timestart) { - sprintf(buf, "%02d:%02d:%02d", + snprintf(buf, sizeof(buf), "%02d:%02d:%02d", time->timestart / 3600, time->timestart % 3600 / 60, time->timestart % 60); @@ -1046,7 +1163,7 @@ fw3_ipt_rule_time(struct fw3_ipt_rule *r, struct fw3_time *time) if (time->timestop) { - sprintf(buf, "%02d:%02d:%02d", + snprintf(buf, sizeof(buf), "%02d:%02d:%02d", time->timestop / 3600, time->timestop % 3600 / 60, time->timestop % 60); @@ -1056,14 +1173,26 @@ fw3_ipt_rule_time(struct fw3_ipt_rule *r, struct fw3_time *time) if (time->monthdays & 0xFFFFFFFE) { - for (i = 1, p = buf; i < 32; i++) + for (i = 1, p = buf, rem = sizeof(buf); i < 32; i++) { if (fw3_hasbit(time->monthdays, i)) { - if (p > buf) + if (p > buf) { + if (rem <= 1) + break; + *p++ = ','; + *p = 0; + rem--; + } + + len = snprintf(p, rem, "%u", i); + + if (len < 0 || len >= rem) + break; - p += sprintf(p, "%u", i); + rem -= len; + p += len; } } @@ -1072,14 +1201,26 @@ fw3_ipt_rule_time(struct fw3_ipt_rule *r, struct fw3_time *time) if (time->weekdays & 0xFE) { - for (i = 1, p = buf; i < 8; i++) + for (i = 1, p = buf, rem = sizeof(buf); i < 8; i++) { if (fw3_hasbit(time->weekdays, i)) { - if (p > buf) + if (p > buf) { + if (rem <= 1) + break; + *p++ = ','; + *p = 0; + rem--; + } - p += sprintf(p, "%u", i); + len = snprintf(p, rem, "%u", i); + + if (len < 0 || len >= rem) + break; + + rem -= len; + p += len; } } @@ -1090,20 +1231,34 @@ fw3_ipt_rule_time(struct fw3_ipt_rule *r, struct fw3_time *time) void fw3_ipt_rule_mark(struct fw3_ipt_rule *r, struct fw3_mark *mark) { - char buf[sizeof("0xFFFFFFFF/0xFFFFFFFF\0")]; + char buf[sizeof("0xFFFFFFFF/0xFFFFFFFF")]; if (!mark || !mark->set) return; if (mark->mask < 0xFFFFFFFF) - sprintf(buf, "0x%x/0x%x", mark->mark, mark->mask); + snprintf(buf, sizeof(buf), "0x%x/0x%x", mark->mark, mark->mask); else - sprintf(buf, "0x%x", mark->mark); + snprintf(buf, sizeof(buf), "0x%x", mark->mark); fw3_ipt_rule_addarg(r, false, "-m", "mark"); fw3_ipt_rule_addarg(r, mark->invert, "--mark", buf); } +void +fw3_ipt_rule_dscp(struct fw3_ipt_rule *r, struct fw3_dscp *dscp) +{ + char buf[sizeof("0xFF")]; + + if (!dscp || !dscp->set) + return; + + snprintf(buf, sizeof(buf), "0x%x", dscp->dscp); + + fw3_ipt_rule_addarg(r, false, "-m", "dscp"); + fw3_ipt_rule_addarg(r, dscp->invert, "--dscp", buf); +} + void fw3_ipt_rule_comment(struct fw3_ipt_rule *r, const char *fmt, ...) { @@ -1114,7 +1269,7 @@ fw3_ipt_rule_comment(struct fw3_ipt_rule *r, const char *fmt, ...) return; va_start(ap, fmt); - vsnprintf(buf, sizeof(buf) - 1, fmt, ap); + vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); fw3_ipt_rule_addarg(r, false, "-m", "comment"); @@ -1207,7 +1362,7 @@ static void rule_print4(struct ipt_entry *e) { struct in_addr in_zero = { 0 }; - char buf1[sizeof("255.255.255.255\0")], buf2[sizeof("255.255.255.255\0")]; + char buf1[sizeof("255.255.255.255")], buf2[sizeof("255.255.255.255")]; char *pname; if (e->ip.proto) @@ -1387,7 +1542,7 @@ rule_mask(struct fw3_ipt_rule *r) p += SZ(ip6t_entry_match) + m->match->size; } - memset(p, 0xFF, SZ(ip6t_entry_target) + (r->target) ? r->target->userspacesize : 0); + memset(p, 0xFF, SZ(ip6t_entry_target) + (r->target ? r->target->userspacesize : 0)); } else #endif @@ -1411,7 +1566,7 @@ rule_mask(struct fw3_ipt_rule *r) p += SZ(ipt_entry_match) + m->match->size; } - memset(p, 0xFF, SZ(ipt_entry_target) + (r->target) ? r->target->userspacesize : 0); + memset(p, 0xFF, SZ(ipt_entry_target) + (r->target ? r->target->userspacesize : 0)); } return mask; @@ -1524,6 +1679,11 @@ __fw3_ipt_rule_append(struct fw3_ipt_rule *r, bool repl, const char *fmt, ...) struct xtables_target *et; struct xtables_globals *g; + struct fw3_device dev; + struct fw3_address addr; + + enum xtables_exittype status; + int i, optc; bool inv = false; char buf[32]; @@ -1539,9 +1699,17 @@ __fw3_ipt_rule_append(struct fw3_ipt_rule *r, bool repl, const char *fmt, ...) optind = 0; opterr = 0; + status = setjmp(fw3_ipt_error_jmp); + + if (status > 0) + { + info(" ! Skipping due to previous exception (code %u)", status); + goto free; + } + set_rule_tag(r); - while ((optc = getopt_long(r->argc, r->argv, "-:m:j:", g->opts, + while ((optc = getopt_long(r->argc, r->argv, "-:m:j:i:o:s:d:", g->opts, NULL)) != -1) { switch (optc) @@ -1569,6 +1737,34 @@ __fw3_ipt_rule_append(struct fw3_ipt_rule *r, bool repl, const char *fmt, ...) break; + case 'i': + case 'o': + if (!fw3_parse_device(&dev, optarg, false) || + dev.any || dev.invert || *dev.network) + { + warn("fw3_ipt_rule_append(): Bad argument '%s'", optarg); + goto free; + } + + dev.invert = inv; + fw3_ipt_rule_in_out(r, (optc == 'i') ? &dev : NULL, + (optc == 'o') ? &dev : NULL); + break; + + case 's': + case 'd': + if (!fw3_parse_address(&addr, optarg, false) || + addr.range || addr.invert) + { + warn("fw3_ipt_rule_append(): Bad argument '%s'", optarg); + goto free; + } + + addr.invert = inv; + fw3_ipt_rule_src_dest(r, (optc == 's') ? &addr : NULL, + (optc == 'd') ? &addr : NULL); + break; + case 1: if ((optarg[0] == '!') && (optarg[1] == '\0')) {