X-Git-Url: http://git.archive.openwrt.org/?p=project%2Ffirewall3.git;a=blobdiff_plain;f=iptables.c;h=d8482399dbaa85f611f6720aaae1d29727b0bf17;hp=2a0d0ee29f453dba28025a269c917e76f9f7bb2c;hb=a4d98aea373e04f3fdc3c492c1688ba52ce490a9;hpb=c5c87e46994635c11b75d01129a57ba42570fa03 diff --git a/iptables.c b/iptables.c index 2a0d0ee..d848239 100644 --- a/iptables.c +++ b/iptables.c @@ -16,25 +16,110 @@ * 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 { @@ -252,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; @@ -263,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")) - 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 @@ -283,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) @@ -299,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); @@ -326,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); @@ -497,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"; @@ -529,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; } @@ -624,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; } @@ -992,8 +1045,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) { @@ -1458,6 +1511,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, ...) { @@ -1469,8 +1550,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; @@ -1485,25 +1570,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"); + status = setjmp(fw3_ipt_error_jmp); - if (!em) - { - warn("fw3_ipt_rule_append(): Can't find match '%s'", "id"); - goto free; - } - - 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) @@ -1531,6 +1608,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')) {