X-Git-Url: http://git.archive.openwrt.org/?p=project%2Ffirewall3.git;a=blobdiff_plain;f=iptables.c;h=f8d4d46ec7717fca1f38f77c23092342b576e3c6;hp=95fc0d45835d565217d8caad63dc4486a92c426b;hb=HEAD;hpb=dd013720b42d6df91176dc9e87f815dcd5d69519 diff --git a/iptables.c b/iptables.c index 95fc0d4..f8d4d46 100644 --- a/iptables.c +++ b/iptables.c @@ -16,19 +16,97 @@ * 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 @@ -38,6 +116,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 @@ -258,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; @@ -269,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 @@ -289,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) @@ -305,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); @@ -332,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); @@ -503,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"; @@ -535,36 +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; - const char *pfx = (h->family == FW3_FAMILY_V6) ? "libip6t" : "libipt"; - - xext.retain = true; - - 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); - } - - xext.retain = false; - - return !!lib; -} - 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; } @@ -630,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; } @@ -979,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; @@ -998,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) { @@ -1366,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 @@ -1390,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; @@ -1464,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, ...) { @@ -1475,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; @@ -1491,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; - } + 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) @@ -1537,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')) {