X-Git-Url: http://git.archive.openwrt.org/?p=project%2Ffirewall3.git;a=blobdiff_plain;f=iptables.c;h=f8d4d46ec7717fca1f38f77c23092342b576e3c6;hp=e54ea53f2c39d48cf5e0ab3234e5c36e5d2cfbe8;hb=b45e162eca2c6e913318c4552643aae2a973ae3a;hpb=18f4c6fda6afb912f53ded3112b1f270ddf5ff6c diff --git a/iptables.c b/iptables.c index e54ea53..f8d4d46 100644 --- a/iptables.c +++ b/iptables.c @@ -16,27 +16,122 @@ * 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" +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; @@ -66,6 +161,7 @@ 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)); @@ -102,6 +198,14 @@ fw3_ipt_open(enum fw3_family family, enum fw3_table table) 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; } @@ -233,10 +337,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 +347,14 @@ get_rule_id(const void *base, unsigned int start, unsigned int end) { em = base + i; - if (strcmp(em->u.user.name, "id")) + if (strcmp(em->u.user.name, "comment")) continue; - memcpy(&id, em->data, sizeof(id)); - - if ((id & FW3_ID_MASK) != FW3_ID_MAGIC) - continue; - - return (id & ~FW3_ID_MASK); + if (!memcmp(em->data, "!fw3", 4)) + return true; } - return -1; + return false; } void @@ -264,7 +363,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 +378,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 +403,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); @@ -467,17 +561,6 @@ 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); - } - free(h); } @@ -489,7 +572,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"; @@ -521,43 +603,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; } @@ -623,13 +676,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; } @@ -972,6 +1026,16 @@ fw3_ipt_rule_ipset(struct fw3_ipt_rule *r, struct fw3_setmatch *match) } 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; @@ -991,8 +1055,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) { @@ -1359,7 +1423,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 +1447,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 +1521,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 +1560,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 +1580,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; - } - - init_match(r, em, true); + status = setjmp(fw3_ipt_error_jmp); - 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 +1618,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 +1758,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; + } +}