X-Git-Url: http://git.openwrt.org/?a=blobdiff_plain;f=iptables.c;h=d03d1dd2933e8000712a0696c4e0d60fa6142347;hb=HEAD;hp=a27da142acaa11640ebc5b7111628c1640681d83;hpb=410cff5e62db45e8415bf25bf50395b4e7e22482;p=project%2Ffirewall3.git diff --git a/iptables.c b/iptables.c index a27da14..d03d1dd 100644 --- a/iptables.c +++ b/iptables.c @@ -1,7 +1,7 @@ /* * firewall3 - 3rd OpenWrt UCI firewall implementation * - * Copyright (C) 2013 Jo-Philipp Wich + * Copyright (C) 2013 Jo-Philipp Wich * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,27 +16,124 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define _GNU_SOURCE /* RTLD_NEXT */ + +/* include userspace headers */ +#include +#include +#include +#include +#include +#include +#include + +/* prevent indirect inclusion of kernel headers */ +#define _LINUX_IF_H +#define _LINUX_IN_H +#define _LINUX_IN6_H + +/* prevent libiptc from including kernel headers */ +#define _FWCHAINS_KERNEL_HEADERS_H + +/* finally include libiptc and xtables */ +#include +#include +#include + +#include + +#include "options.h" + +/* xtables interface */ +#if (XTABLES_VERSION_CODE >= 10) +# include "xtables-10.h" +#elif (XTABLES_VERSION_CODE == 5) +# include "xtables-5.h" +#else +# error "Unsupported xtables version" +#endif + #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; + + union { + struct ipt_entry e; + struct ip6t_entry e6; + }; + + struct xtables_rule_match *matches; + struct xtables_target *target; + + int argc; + char **argv; + + uint32_t protocol; + bool protocol_loaded; +}; 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 }; 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 }; +static struct { + bool retain; + int mcount, tcount; + struct xtables_match **matches; + struct xtables_target **targets; + void (*register_match)(struct xtables_match *); + void (*register_target)(struct xtables_target *); +} xext; + + /* Required by certain extensions like SNAT and DNAT */ int kernel_version = 0; @@ -44,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; } @@ -66,12 +162,18 @@ static void fw3_init_extensions(void) struct fw3_ipt_handle * fw3_ipt_open(enum fw3_family family, enum fw3_table table) { + int i; struct fw3_ipt_handle *h; h = fw3_alloc(sizeof(*h)); 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 @@ -96,12 +198,21 @@ 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; } fw3_xt_reset(); fw3_init_extensions(); + if (xext.register_match) + for (i = 0; i < xext.mcount; i++) + xext.register_match(xext.matches[i]); + + if (xext.register_target) + for (i = 0; i < xext.tcount; i++) + xext.register_target(xext.targets[i]); + return h; } @@ -217,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) @@ -233,10 +396,9 @@ fw3_ipt_delete_chain(struct fw3_ipt_handle *h, const char *chain) iptc_delete_chain(chain, h->handle); } -static int -get_rule_id(const void *base, unsigned int start, unsigned int end) +static bool +has_rule_tag(const void *base, unsigned int start, unsigned int end) { - uint32_t id; unsigned int i; const struct xt_entry_match *em; @@ -244,18 +406,14 @@ get_rule_id(const void *base, unsigned int start, unsigned int end) { em = base + i; - if (strcmp(em->u.user.name, "id")) - continue; - - memcpy(&id, em->data, sizeof(id)); - - if ((id & FW3_ID_MASK) != FW3_ID_MAGIC) + if (strcmp(em->u.user.name, "comment")) continue; - return (id & ~FW3_ID_MASK); + if (!memcmp(em->data, "!fw3", 4)) + return true; } - return -1; + return false; } void @@ -264,7 +422,6 @@ fw3_ipt_delete_id_rules(struct fw3_ipt_handle *h, const char *chain) unsigned int num; const struct ipt_entry *e; bool found; - int id; #ifndef DISABLE_IPV6 if (h->family == FW3_FAMILY_V6) @@ -280,9 +437,7 @@ fw3_ipt_delete_id_rules(struct fw3_ipt_handle *h, const char *chain) e6 != NULL; num++, e6 = ip6tc_next_rule(e6, h->handle)) { - id = get_rule_id(e6, sizeof(*e6), e6->target_offset); - - if (id >= 0) + if (has_rule_tag(e6, sizeof(*e6), e6->target_offset)) { if (fw3_pr_debug) debug(h, "-D %s %u\n", chain, num + 1); @@ -307,9 +462,7 @@ fw3_ipt_delete_id_rules(struct fw3_ipt_handle *h, const char *chain) e != NULL; num++, e = iptc_next_rule(e, h->handle)) { - id = get_rule_id(e, sizeof(*e), e->target_offset); - - if (id >= 0) + if (has_rule_tag(e, sizeof(*e), e->target_offset)) { if (fw3_pr_debug) debug(h, "-D %s %u\n", chain, num + 1); @@ -323,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 @@ -412,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; } @@ -435,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; } @@ -467,17 +629,7 @@ fw3_ipt_commit(struct fw3_ipt_handle *h) void fw3_ipt_close(struct fw3_ipt_handle *h) { - if (h->libv) - { - while (h->libc > 0) - { - h->libc--; - dlclose(h->libv[h->libc]); - } - - free(h->libv); - } - + fw3_unlock_path(&xt_lock_fd, XT_LOCK_NAME); free(h); } @@ -489,7 +641,6 @@ fw3_ipt_rule_new(struct fw3_ipt_handle *h) r = fw3_alloc(sizeof(*r)); r->h = h; - r->id = 0; r->argv = fw3_alloc(sizeof(char *)); r->argv[r->argc++] = "fw3"; @@ -497,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) { @@ -521,43 +661,14 @@ get_protoname(struct fw3_ipt_rule *r) return NULL; } -static bool -load_extension(struct fw3_ipt_handle *h, const char *name) -{ - char path[256]; - void *lib, **tmp; - const char *pfx = (h->family == FW3_FAMILY_V6) ? "libip6t" : "libipt"; - - snprintf(path, sizeof(path), "/usr/lib/iptables/libxt_%s.so", name); - if (!(lib = dlopen(path, RTLD_NOW))) - { - snprintf(path, sizeof(path), "/usr/lib/iptables/%s_%s.so", pfx, name); - lib = dlopen(path, RTLD_NOW); - } - - if (!lib) - return false; - - tmp = realloc(h->libv, sizeof(lib) * (h->libc + 1)); - - if (!tmp) - return false; - - h->libv = tmp; - h->libv[h->libc++] = lib; - - return true; -} - static struct xtables_match * find_match(struct fw3_ipt_rule *r, const char *name) { struct xtables_match *m; - m = xtables_find_match(name, XTF_DONT_LOAD, &r->matches); - - if (!m && load_extension(r->h, name)) - m = xtables_find_match(name, XTF_DONT_LOAD, &r->matches); + xext.retain = true; + m = xtables_find_match(name, XTF_TRY_LOAD, &r->matches); + xext.retain = false; return m; } @@ -598,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; } @@ -623,13 +740,14 @@ find_target(struct fw3_ipt_rule *r, const char *name) { struct xtables_target *t; - if (is_chain(r->h, name)) - return xtables_find_target(XT_STANDARD_TARGET, XTF_LOAD_MUST_SUCCEED); + xext.retain = true; - t = xtables_find_target(name, XTF_DONT_LOAD); + if (is_chain(r->h, name)) + t = xtables_find_target(XT_STANDARD_TARGET, XTF_TRY_LOAD); + else + t = xtables_find_target(name, XTF_TRY_LOAD); - if (!t && load_extension(r->h, name)) - t = xtables_find_target(name, XTF_DONT_LOAD); + xext.retain = false; return t; } @@ -832,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; @@ -843,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); } @@ -853,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); } @@ -864,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); } } @@ -874,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); @@ -890,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; @@ -899,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); } @@ -909,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); } @@ -920,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); } } @@ -940,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; @@ -956,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++; } @@ -971,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)) { @@ -991,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) { @@ -1008,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); @@ -1018,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); @@ -1028,54 +1173,92 @@ 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 (hasbit(time->monthdays, 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); - p += sprintf(p, "%u", i); + if (len < 0 || len >= rem) + break; + + rem -= len; + p += len; } } - fw3_ipt_rule_addarg(r, hasbit(time->monthdays, 0), "--monthdays", buf); + fw3_ipt_rule_addarg(r, fw3_hasbit(time->monthdays, 0), "--monthdays", buf); } if (time->weekdays & 0xFE) { - for (i = 1, p = buf; i < 8; i++) + for (i = 1, p = buf, rem = sizeof(buf); i < 8; i++) { - if (hasbit(time->weekdays, i)) + if (fw3_hasbit(time->weekdays, 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; } } - fw3_ipt_rule_addarg(r, hasbit(time->weekdays, 0), "--weekdays", buf); + fw3_ipt_rule_addarg(r, fw3_hasbit(time->weekdays, 0), "--weekdays", buf); } } 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, ...) { @@ -1086,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"); @@ -1126,7 +1309,7 @@ rule_print6(struct ip6t_entry *e) if (e->ipv6.flags & IP6T_F_PROTO) { - if (e->ipv6.flags & XT_INV_PROTO) + if (e->ipv6.invflags & XT_INV_PROTO) printf(" !"); pname = get_protoname(container_of(e, struct fw3_ipt_rule, e6)); @@ -1139,7 +1322,7 @@ rule_print6(struct ip6t_entry *e) if (e->ipv6.iniface[0]) { - if (e->ipv6.flags & IP6T_INV_VIA_IN) + if (e->ipv6.invflags & IP6T_INV_VIA_IN) printf(" !"); printf(" -i %s", e->ipv6.iniface); @@ -1147,7 +1330,7 @@ rule_print6(struct ip6t_entry *e) if (e->ipv6.outiface[0]) { - if (e->ipv6.flags & IP6T_INV_VIA_OUT) + if (e->ipv6.invflags & IP6T_INV_VIA_OUT) printf(" !"); printf(" -o %s", e->ipv6.outiface); @@ -1155,7 +1338,7 @@ rule_print6(struct ip6t_entry *e) if (memcmp(&e->ipv6.src, &in6addr_any, sizeof(struct in6_addr))) { - if (e->ipv6.flags & IP6T_INV_SRCIP) + if (e->ipv6.invflags & IP6T_INV_SRCIP) printf(" !"); printf(" -s %s/%s", @@ -1165,7 +1348,7 @@ rule_print6(struct ip6t_entry *e) if (memcmp(&e->ipv6.dst, &in6addr_any, sizeof(struct in6_addr))) { - if (e->ipv6.flags & IP6T_INV_DSTIP) + if (e->ipv6.invflags & IP6T_INV_DSTIP) printf(" !"); printf(" -d %s/%s", @@ -1179,12 +1362,12 @@ 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) { - if (e->ip.flags & XT_INV_PROTO) + if (e->ip.invflags & XT_INV_PROTO) printf(" !"); pname = get_protoname(container_of(e, struct fw3_ipt_rule, e)); @@ -1197,7 +1380,7 @@ rule_print4(struct ipt_entry *e) if (e->ip.iniface[0]) { - if (e->ip.flags & IPT_INV_VIA_IN) + if (e->ip.invflags & IPT_INV_VIA_IN) printf(" !"); printf(" -i %s", e->ip.iniface); @@ -1205,7 +1388,7 @@ rule_print4(struct ipt_entry *e) if (e->ip.outiface[0]) { - if (e->ip.flags & IPT_INV_VIA_OUT) + if (e->ip.invflags & IPT_INV_VIA_OUT) printf(" !"); printf(" -o %s", e->ip.outiface); @@ -1213,7 +1396,7 @@ rule_print4(struct ipt_entry *e) if (memcmp(&e->ip.src, &in_zero, sizeof(struct in_addr))) { - if (e->ip.flags & IPT_INV_SRCIP) + if (e->ip.invflags & IPT_INV_SRCIP) printf(" !"); printf(" -s %s/%s", @@ -1223,7 +1406,7 @@ rule_print4(struct ipt_entry *e) if (memcmp(&e->ip.dst, &in_zero, sizeof(struct in_addr))) { - if (e->ip.flags & IPT_INV_DSTIP) + if (e->ip.invflags & IPT_INV_DSTIP) printf(" !"); printf(" -d %s/%s", @@ -1359,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 @@ -1383,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; @@ -1457,6 +1640,34 @@ rule_build(struct fw3_ipt_rule *r) } } +static void +set_rule_tag(struct fw3_ipt_rule *r) +{ + int i; + char *p, **tmp; + const char *tag = "!fw3"; + + for (i = 0; i < r->argc; i++) + if (!strcmp(r->argv[i], "--comment") && (i + 1) < r->argc) + if (asprintf(&p, "%s: %s", tag, r->argv[i + 1]) > 0) + { + free(r->argv[i + 1]); + r->argv[i + 1] = p; + return; + } + + tmp = realloc(r->argv, (r->argc + 4) * sizeof(*r->argv)); + + if (tmp) + { + r->argv = tmp; + r->argv[r->argc++] = fw3_strdup("-m"); + r->argv[r->argc++] = fw3_strdup("comment"); + r->argv[r->argc++] = fw3_strdup("--comment"); + r->argv[r->argc++] = fw3_strdup(tag); + } +} + void __fw3_ipt_rule_append(struct fw3_ipt_rule *r, bool repl, const char *fmt, ...) { @@ -1468,8 +1679,12 @@ __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; - uint32_t id; bool inv = false; char buf[32]; va_list ap; @@ -1484,25 +1699,17 @@ __fw3_ipt_rule_append(struct fw3_ipt_rule *r, bool repl, const char *fmt, ...) optind = 0; opterr = 0; - if (r->id >= 0) - { - em = find_match(r, "id"); - - if (!em) - { - warn("fw3_ipt_rule_append(): Can't find match '%s'", "id"); - goto free; - } + status = setjmp(fw3_ipt_error_jmp); - init_match(r, em, true); - - id = FW3_ID_MAGIC | (r->id & ~FW3_ID_MASK); - memcpy(em->m->data, &id, sizeof(id)); - - em->mflags = 1; + if (status > 0) + { + info(" ! Skipping due to previous exception (code %u)", status); + goto free; } - while ((optc = getopt_long(r->argc, r->argv, "-:m:j:", g->opts, + set_rule_tag(r); + + while ((optc = getopt_long(r->argc, r->argv, "-:m:j:i:o:s:d:", g->opts, NULL)) != -1) { switch (optc) @@ -1530,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')) { @@ -1642,3 +1877,63 @@ fw3_ipt_rule_create(struct fw3_ipt_handle *handle, struct fw3_protocol *proto, return r; } + +void +xtables_register_match(struct xtables_match *me) +{ + int i; + static struct xtables_match **tmp; + + if (!xext.register_match) + xext.register_match = dlsym(RTLD_NEXT, "xtables_register_match"); + + if (!xext.register_match) + return; + + xext.register_match(me); + + if (xext.retain) + { + for (i = 0; i < xext.mcount; i++) + if (xext.matches[i] == me) + return; + + tmp = realloc(xext.matches, sizeof(me) * (xext.mcount + 1)); + + if (!tmp) + return; + + xext.matches = tmp; + xext.matches[xext.mcount++] = me; + } +} + +void +xtables_register_target(struct xtables_target *me) +{ + int i; + static struct xtables_target **tmp; + + if (!xext.register_target) + xext.register_target = dlsym(RTLD_NEXT, "xtables_register_target"); + + if (!xext.register_target) + return; + + xext.register_target(me); + + if (xext.retain) + { + for (i = 0; i < xext.tcount; i++) + if (xext.targets[i] == me) + return; + + tmp = realloc(xext.targets, sizeof(me) * (xext.tcount + 1)); + + if (!tmp) + return; + + xext.targets = tmp; + xext.targets[xext.tcount++] = me; + } +}