X-Git-Url: http://git.openwrt.org/?p=project%2Ffirewall3.git;a=blobdiff_plain;f=iptables.c;h=d8482399dbaa85f611f6720aaae1d29727b0bf17;hp=fc22d1aae7bcb2e7ca763ab53a19d6b1eb42eff7;hb=HEAD;hpb=010723ef8af18add1e592a55092d4b0e1c5e1efe diff --git a/iptables.c b/iptables.c index fc22d1a..d03d1dd 100644 --- a/iptables.c +++ b/iptables.c @@ -16,19 +16,99 @@ * 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 @@ -38,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 @@ -60,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; } @@ -89,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 @@ -113,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; } @@ -242,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) @@ -258,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; @@ -269,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 @@ -289,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) @@ -305,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); @@ -332,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); @@ -348,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 @@ -437,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; } @@ -460,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; } @@ -492,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); } @@ -503,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"; @@ -511,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) { @@ -535,36 +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; - 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; } @@ -605,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; } @@ -630,20 +740,14 @@ find_target(struct fw3_ipt_rule *r, const char *name) { struct xtables_target *t; - if (is_chain(r->h, name)) { - t = xtables_find_target(XT_STANDARD_TARGET, XTF_DONT_LOAD); - - if (t) - return t; - - load_extension(r->h, "standard"); - 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; } @@ -846,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; @@ -857,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); } @@ -867,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); } @@ -878,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); } } @@ -888,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); @@ -904,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; @@ -913,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); } @@ -923,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); } @@ -934,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); } } @@ -954,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; @@ -970,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++; } @@ -985,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)) { @@ -1005,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) { @@ -1022,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); @@ -1032,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); @@ -1042,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; } } @@ -1058,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--; + } + + len = snprintf(p, rem, "%u", i); - p += sprintf(p, "%u", i); + if (len < 0 || len >= rem) + break; + + rem -= len; + p += len; } } @@ -1076,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, ...) { @@ -1100,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"); @@ -1193,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) @@ -1373,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 @@ -1397,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; @@ -1471,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, ...) { @@ -1482,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; @@ -1498,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; - } - - init_match(r, em, true); - - id = FW3_ID_MAGIC | (r->id & ~FW3_ID_MASK); - memcpy(em->m->data, &id, sizeof(id)); + status = setjmp(fw3_ipt_error_jmp); - 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) @@ -1544,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')) {