From 410cff5e62db45e8415bf25bf50395b4e7e22482 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Sun, 24 Jan 2016 17:43:30 +0100 Subject: [PATCH] Use xt_id match to track own rules Instead of relying on the delegate_* chains to isolate own toplevel rules from user supplied ones, use the xt_id match to attach a magic value to fw3 rules which allows selective cleanup regardless of the container chain. Also add an experimental "fw3 gc" call to garbage collect empty chains. Signed-off-by: Jo-Philipp Wich --- defaults.c | 96 +++++++++++++++-------------- forwards.c | 2 +- iptables.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++++ iptables.h | 9 +++ main.c | 37 ++++++++++++ rules.c | 10 ++-- snats.c | 2 +- zones.c | 20 +++---- 8 files changed, 287 insertions(+), 62 deletions(-) diff --git a/defaults.c b/defaults.c index 396cbf7..ccd320c 100644 --- a/defaults.c +++ b/defaults.c @@ -23,24 +23,24 @@ { FW3_FAMILY_##f, FW3_TABLE_##tbl, FW3_FLAG_##def, fmt } static const struct fw3_chain_spec default_chains[] = { - C(ANY, FILTER, UNSPEC, "delegate_input"), - C(ANY, FILTER, UNSPEC, "delegate_output"), - C(ANY, FILTER, UNSPEC, "delegate_forward"), + //C(ANY, FILTER, UNSPEC, "delegate_input"), + //C(ANY, FILTER, UNSPEC, "delegate_output"), + //C(ANY, FILTER, UNSPEC, "delegate_forward"), C(ANY, FILTER, UNSPEC, "reject"), C(ANY, FILTER, CUSTOM_CHAINS, "input_rule"), C(ANY, FILTER, CUSTOM_CHAINS, "output_rule"), C(ANY, FILTER, CUSTOM_CHAINS, "forwarding_rule"), C(ANY, FILTER, SYN_FLOOD, "syn_flood"), - C(V4, NAT, UNSPEC, "delegate_prerouting"), - C(V4, NAT, UNSPEC, "delegate_postrouting"), + //C(V4, NAT, UNSPEC, "delegate_prerouting"), + //C(V4, NAT, UNSPEC, "delegate_postrouting"), C(V4, NAT, CUSTOM_CHAINS, "prerouting_rule"), C(V4, NAT, CUSTOM_CHAINS, "postrouting_rule"), - C(ANY, MANGLE, UNSPEC, "mssfix"), - C(ANY, MANGLE, UNSPEC, "fwmark"), + //C(ANY, MANGLE, UNSPEC, "mssfix"), + //C(ANY, MANGLE, UNSPEC, "fwmark"), - C(ANY, RAW, UNSPEC, "delegate_notrack"), + //C(ANY, RAW, UNSPEC, "delegate_notrack"), { } }; @@ -189,39 +189,39 @@ fw3_print_default_head_rules(struct fw3_ipt_handle *handle, struct fw3_device lodev = { .set = true }; struct fw3_protocol tcp = { .protocol = 6 }; struct fw3_ipt_rule *r; - struct toplevel_rule *tr; + //struct toplevel_rule *tr; const char *chains[] = { - "delegate_input", "input", - "delegate_output", "output", - "delegate_forward", "forwarding", + "INPUT", "input", + "OUTPUT", "output", + "FORWARD", "forwarding", }; - struct toplevel_rule rules[] = { - { FW3_TABLE_FILTER, "INPUT", "delegate_input" }, - { FW3_TABLE_FILTER, "OUTPUT", "delegate_output" }, - { FW3_TABLE_FILTER, "FORWARD", "delegate_forward" }, - - { FW3_TABLE_NAT, "PREROUTING", "delegate_prerouting" }, - { FW3_TABLE_NAT, "POSTROUTING", "delegate_postrouting" }, - - { FW3_TABLE_MANGLE, "FORWARD", "mssfix" }, - { FW3_TABLE_MANGLE, "PREROUTING", "fwmark" }, - - { FW3_TABLE_RAW, "PREROUTING", "delegate_notrack" }, - - { 0, NULL }, - }; - - for (tr = rules; tr->chain; tr++) - { - if (tr->table != handle->table) - continue; - - r = fw3_ipt_rule_new(handle); - fw3_ipt_rule_target(r, tr->target); - fw3_ipt_rule_replace(r, tr->chain); - } + //struct toplevel_rule rules[] = { + // { FW3_TABLE_FILTER, "INPUT", "delegate_input" }, + // { FW3_TABLE_FILTER, "OUTPUT", "delegate_output" }, + // { FW3_TABLE_FILTER, "FORWARD", "delegate_forward" }, + // + // { FW3_TABLE_NAT, "PREROUTING", "delegate_prerouting" }, + // { FW3_TABLE_NAT, "POSTROUTING", "delegate_postrouting" }, + // + // { FW3_TABLE_MANGLE, "FORWARD", "mssfix" }, + // { FW3_TABLE_MANGLE, "PREROUTING", "fwmark" }, + // + // { FW3_TABLE_RAW, "PREROUTING", "delegate_notrack" }, + // + // { 0, NULL }, + //}; + // + //for (tr = rules; tr->chain; tr++) + //{ + // if (tr->table != handle->table) + // continue; + // + // r = fw3_ipt_rule_new(handle); + // fw3_ipt_rule_target(r, tr->target); + // fw3_ipt_rule_replace(r, tr->chain); + //} switch (handle->table) { @@ -231,11 +231,11 @@ fw3_print_default_head_rules(struct fw3_ipt_handle *handle, r = fw3_ipt_rule_create(handle, NULL, &lodev, NULL, NULL, NULL); fw3_ipt_rule_target(r, "ACCEPT"); - fw3_ipt_rule_append(r, "delegate_input"); + fw3_ipt_rule_append(r, "INPUT"); r = fw3_ipt_rule_create(handle, NULL, NULL, &lodev, NULL, NULL); fw3_ipt_rule_target(r, "ACCEPT"); - fw3_ipt_rule_append(r, "delegate_output"); + fw3_ipt_rule_append(r, "OUTPUT"); if (defs->custom_chains) { @@ -279,7 +279,7 @@ fw3_print_default_head_rules(struct fw3_ipt_handle *handle, r = fw3_ipt_rule_create(handle, &tcp, NULL, NULL, NULL, NULL); fw3_ipt_rule_extra(r, "--syn"); fw3_ipt_rule_target(r, "syn_flood"); - fw3_ipt_rule_append(r, "delegate_input"); + fw3_ipt_rule_append(r, "INPUT"); } r = fw3_ipt_rule_create(handle, &tcp, NULL, NULL, NULL, NULL); @@ -300,12 +300,12 @@ fw3_print_default_head_rules(struct fw3_ipt_handle *handle, r = fw3_ipt_rule_new(handle); fw3_ipt_rule_comment(r, "user chain for prerouting"); fw3_ipt_rule_target(r, "prerouting_rule"); - fw3_ipt_rule_append(r, "delegate_prerouting"); + fw3_ipt_rule_append(r, "PREROUTING"); r = fw3_ipt_rule_new(handle); fw3_ipt_rule_comment(r, "user chain for postrouting"); fw3_ipt_rule_target(r, "postrouting_rule"); - fw3_ipt_rule_append(r, "delegate_postrouting"); + fw3_ipt_rule_append(r, "POSTROUTING"); } break; @@ -332,7 +332,7 @@ fw3_print_default_tail_rules(struct fw3_ipt_handle *handle, return; fw3_ipt_rule_target(r, "reject"); - fw3_ipt_rule_append(r, "delegate_input"); + fw3_ipt_rule_append(r, "INPUT"); } if (defs->policy_output == FW3_FLAG_REJECT) @@ -343,7 +343,7 @@ fw3_print_default_tail_rules(struct fw3_ipt_handle *handle, return; fw3_ipt_rule_target(r, "reject"); - fw3_ipt_rule_append(r, "delegate_output"); + fw3_ipt_rule_append(r, "OUTPUT"); } if (defs->policy_forward == FW3_FLAG_REJECT) @@ -354,7 +354,7 @@ fw3_print_default_tail_rules(struct fw3_ipt_handle *handle, return; fw3_ipt_rule_target(r, "reject"); - fw3_ipt_rule_append(r, "delegate_forward"); + fw3_ipt_rule_append(r, "FORWARD"); } } @@ -404,6 +404,12 @@ fw3_flush_rules(struct fw3_ipt_handle *handle, struct fw3_state *state, fw3_ipt_set_policy(handle, "FORWARD", policy); } + fw3_ipt_delete_id_rules(handle, "INPUT"); + fw3_ipt_delete_id_rules(handle, "OUTPUT"); + fw3_ipt_delete_id_rules(handle, "FORWARD"); + fw3_ipt_delete_id_rules(handle, "PREROUTING"); + fw3_ipt_delete_id_rules(handle, "POSTROUTING"); + for (c = default_chains; c->format; c++) { /* don't touch user chains on selective stop */ diff --git a/forwards.c b/forwards.c index e27e4ee..24b8e4d 100644 --- a/forwards.c +++ b/forwards.c @@ -106,7 +106,7 @@ static void append_chain(struct fw3_ipt_rule *r, struct fw3_forward *forward) { if (forward->src.any || !forward->src.set) - fw3_ipt_rule_append(r, "delegate_forward"); + fw3_ipt_rule_append(r, "FORWARD"); else fw3_ipt_rule_append(r, "zone_%s_forward", forward->src.name); } diff --git a/iptables.c b/iptables.c index 0f41fb0..a27da14 100644 --- a/iptables.c +++ b/iptables.c @@ -233,6 +233,96 @@ 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) +{ + uint32_t id; + unsigned int i; + const struct xt_entry_match *em; + + for (i = start; i < end; i += em->u.match_size) + { + 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) + continue; + + return (id & ~FW3_ID_MASK); + } + + return -1; +} + +void +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) + { + if (!ip6tc_is_chain(chain, h->handle)) + return; + + do { + found = false; + + const struct ip6t_entry *e6; + for (num = 0, e6 = ip6tc_first_rule(chain, h->handle); + e6 != NULL; + num++, e6 = ip6tc_next_rule(e6, h->handle)) + { + id = get_rule_id(e6, sizeof(*e6), e6->target_offset); + + if (id >= 0) + { + if (fw3_pr_debug) + debug(h, "-D %s %u\n", chain, num + 1); + + ip6tc_delete_num_entry(chain, num, h->handle); + found = true; + break; + } + } + } while (found); + } + else +#endif + { + if (!iptc_is_chain(chain, h->handle)) + return; + + do { + found = false; + + for (num = 0, e = iptc_first_rule(chain, h->handle); + e != NULL; + num++, e = iptc_next_rule(e, h->handle)) + { + id = get_rule_id(e, sizeof(*e), e->target_offset); + + if (id >= 0) + { + if (fw3_pr_debug) + debug(h, "-D %s %u\n", chain, num + 1); + + iptc_delete_num_entry(chain, num, h->handle); + found = true; + break; + } + } + } while (found); + } +} + void fw3_ipt_create_chain(struct fw3_ipt_handle *h, const char *fmt, ...) { @@ -290,6 +380,69 @@ fw3_ipt_flush(struct fw3_ipt_handle *h) } } +static bool +chain_is_empty(struct fw3_ipt_handle *h, const char *chain) +{ +#ifndef DISABLE_IPV6 + if (h->family == FW3_FAMILY_V6) + return (!ip6tc_builtin(chain, h->handle) && + !ip6tc_first_rule(chain, h->handle)); +#endif + + return (!iptc_builtin(chain, h->handle) && + !iptc_first_rule(chain, h->handle)); +} + +void +fw3_ipt_gc(struct fw3_ipt_handle *h) +{ + const char *chain; + bool found; + +#ifndef DISABLE_IPV6 + if (h->family == FW3_FAMILY_V6) + { + do { + found = false; + + for (chain = ip6tc_first_chain(h->handle); + chain != NULL; + chain = ip6tc_next_chain(h->handle)) + { + if (!chain_is_empty(h, chain)) + continue; + + fw3_ipt_delete_chain(h, chain); + found = true; + break; + } + } while(found); + } + else +#endif + { + do { + found = false; + + for (chain = iptc_first_chain(h->handle); + chain != NULL; + chain = iptc_next_chain(h->handle)) + { + warn("C=%s\n", chain); + + if (!chain_is_empty(h, chain)) + continue; + + warn("D=%s\n", chain); + + fw3_ipt_delete_chain(h, chain); + found = true; + break; + } + } while (found); + } +} + void fw3_ipt_commit(struct fw3_ipt_handle *h) { @@ -336,6 +489,7 @@ 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"; @@ -1315,6 +1469,7 @@ __fw3_ipt_rule_append(struct fw3_ipt_rule *r, bool repl, const char *fmt, ...) struct xtables_globals *g; int i, optc; + uint32_t id; bool inv = false; char buf[32]; va_list ap; @@ -1329,6 +1484,24 @@ __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)); + + em->mflags = 1; + } + while ((optc = getopt_long(r->argc, r->argv, "-:m:j:", g->opts, NULL)) != -1) { diff --git a/iptables.h b/iptables.h index fabefa8..a6d1024 100644 --- a/iptables.h +++ b/iptables.h @@ -30,6 +30,9 @@ #include "options.h" +#define FW3_ID_MAGIC 0x66773300 /* 'f' 'w' '3' */ +#define FW3_ID_MASK 0xffffff00 + /* xtables interface */ #if (XTABLES_VERSION_CODE == 10) # include "xtables-10.h" @@ -68,6 +71,8 @@ struct fw3_ipt_rule { struct xtables_rule_match *matches; struct xtables_target *target; + int id; + int argc; char **argv; @@ -85,10 +90,14 @@ void fw3_ipt_set_policy(struct fw3_ipt_handle *h, const char *chain, void fw3_ipt_flush_chain(struct fw3_ipt_handle *h, const char *chain); void fw3_ipt_delete_chain(struct fw3_ipt_handle *h, const char *chain); +void 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, ...); void fw3_ipt_flush(struct fw3_ipt_handle *h); +void fw3_ipt_gc(struct fw3_ipt_handle *h); + void fw3_ipt_commit(struct fw3_ipt_handle *h); void fw3_ipt_close(struct fw3_ipt_handle *h); diff --git a/main.c b/main.c index 71463ae..b953020 100644 --- a/main.c +++ b/main.c @@ -400,6 +400,35 @@ start: return rv; } +static int +gc(void) +{ + enum fw3_family family; + enum fw3_table table; + struct fw3_ipt_handle *handle; + + for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++) + { + if (family == FW3_FAMILY_V6 && cfg_state->defaults.disable_ipv6) + continue; + + for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++) + { + if (!fw3_has_table(family == FW3_FAMILY_V6, fw3_flag_names[table])) + continue; + + if (!(handle = fw3_ipt_open(family, table))) + continue; + + fw3_ipt_gc(handle); + fw3_ipt_commit(handle); + fw3_ipt_close(handle); + } + } + + return 0; +} + static int lookup_network(const char *net) { @@ -591,6 +620,14 @@ int main(int argc, char **argv) fw3_unlock(); } } + else if (!strcmp(argv[optind], "gc")) + { + if (fw3_lock()) + { + rv = gc(); + fw3_unlock(); + } + } else if (!strcmp(argv[optind], "network") && (optind + 1) < argc) { rv = lookup_network(argv[optind + 1]); diff --git a/rules.c b/rules.c index a5f3fa9..756c78d 100644 --- a/rules.c +++ b/rules.c @@ -264,7 +264,7 @@ append_chain(struct fw3_ipt_rule *r, struct fw3_rule *rule) { char chain[32]; - snprintf(chain, sizeof(chain), "delegate_output"); + snprintf(chain, sizeof(chain), "OUTPUT"); if (rule->target == FW3_FLAG_NOTRACK) { @@ -272,7 +272,7 @@ append_chain(struct fw3_ipt_rule *r, struct fw3_rule *rule) } else if (rule->target == FW3_FLAG_MARK) { - snprintf(chain, sizeof(chain), "fwmark"); + snprintf(chain, sizeof(chain), "PREROUTING"); } else { @@ -290,16 +290,16 @@ append_chain(struct fw3_ipt_rule *r, struct fw3_rule *rule) else { if (rule->dest.set) - snprintf(chain, sizeof(chain), "delegate_forward"); + snprintf(chain, sizeof(chain), "FORWARD"); else - snprintf(chain, sizeof(chain), "delegate_input"); + snprintf(chain, sizeof(chain), "INPUT"); } } if (rule->dest.set && !rule->src.set) { if (rule->dest.any) - snprintf(chain, sizeof(chain), "delegate_output"); + snprintf(chain, sizeof(chain), "OUTPUT"); else snprintf(chain, sizeof(chain), "zone_%s_output", rule->dest.name); diff --git a/snats.c b/snats.c index 0f7d851..75b0fa0 100644 --- a/snats.c +++ b/snats.c @@ -265,7 +265,7 @@ append_chain(struct fw3_ipt_rule *r, struct fw3_snat *snat) if (snat->_src) fw3_ipt_rule_append(r, "zone_%s_postrouting", snat->src.name); else - fw3_ipt_rule_append(r, "delegate_postrouting"); + fw3_ipt_rule_append(r, "POSTROUTING"); } static void diff --git a/zones.c b/zones.c index 2ddd7b4..88133e2 100644 --- a/zones.c +++ b/zones.c @@ -331,9 +331,9 @@ print_interface_rule(struct fw3_ipt_handle *handle, struct fw3_state *state, int i; const char *chains[] = { - "input", - "output", - "forward", + "input", "INPUT", + "output", "OUTPUT", + "forward", "FORWARD", }; #define jump_target(t) \ @@ -362,7 +362,7 @@ print_interface_rule(struct fw3_ipt_handle *handle, struct fw3_state *state, } } - for (i = 0; i < sizeof(chains)/sizeof(chains[0]); i++) + for (i = 0; i < sizeof(chains)/sizeof(chains[0]); i += 2) { if (*chains[i] == 'o') r = fw3_ipt_rule_create(handle, NULL, NULL, dev, NULL, sub); @@ -376,7 +376,7 @@ print_interface_rule(struct fw3_ipt_handle *handle, struct fw3_state *state, else fw3_ipt_rule_extra(r, zone->extra_src); - fw3_ipt_rule_replace(r, "delegate_%s", chains[i]); + fw3_ipt_rule_replace(r, chains[i + 1]); } } else if (handle->table == FW3_TABLE_NAT) @@ -386,7 +386,7 @@ print_interface_rule(struct fw3_ipt_handle *handle, struct fw3_state *state, r = fw3_ipt_rule_create(handle, NULL, dev, NULL, sub, NULL); fw3_ipt_rule_target(r, "zone_%s_prerouting", zone->name); fw3_ipt_rule_extra(r, zone->extra_src); - fw3_ipt_rule_replace(r, "delegate_prerouting"); + fw3_ipt_rule_replace(r, "PREROUTING"); } if (has(zone->flags, handle->family, FW3_FLAG_SNAT)) @@ -394,7 +394,7 @@ print_interface_rule(struct fw3_ipt_handle *handle, struct fw3_state *state, r = fw3_ipt_rule_create(handle, NULL, NULL, dev, NULL, sub); fw3_ipt_rule_target(r, "zone_%s_postrouting", zone->name); fw3_ipt_rule_extra(r, zone->extra_dest); - fw3_ipt_rule_replace(r, "delegate_postrouting"); + fw3_ipt_rule_replace(r, "POSTROUTING"); } } else if (handle->table == FW3_TABLE_MANGLE) @@ -412,7 +412,7 @@ print_interface_rule(struct fw3_ipt_handle *handle, struct fw3_state *state, fw3_ipt_rule_comment(r, "%s (mtu_fix logging)", zone->name); fw3_ipt_rule_target(r, "LOG"); fw3_ipt_rule_addarg(r, false, "--log-prefix", buf); - fw3_ipt_rule_replace(r, "mssfix"); + fw3_ipt_rule_replace(r, "FORWARD"); } r = fw3_ipt_rule_create(handle, &tcp, NULL, dev, NULL, sub); @@ -421,7 +421,7 @@ print_interface_rule(struct fw3_ipt_handle *handle, struct fw3_state *state, fw3_ipt_rule_comment(r, "%s (mtu_fix)", zone->name); fw3_ipt_rule_target(r, "TCPMSS"); fw3_ipt_rule_addarg(r, false, "--clamp-mss-to-pmtu", NULL); - fw3_ipt_rule_replace(r, "mssfix"); + fw3_ipt_rule_replace(r, "FORWARD"); } } else if (handle->table == FW3_TABLE_RAW) @@ -431,7 +431,7 @@ print_interface_rule(struct fw3_ipt_handle *handle, struct fw3_state *state, r = fw3_ipt_rule_create(handle, NULL, dev, NULL, sub, NULL); fw3_ipt_rule_target(r, "zone_%s_notrack", zone->name); fw3_ipt_rule_extra(r, zone->extra_src); - fw3_ipt_rule_replace(r, "delegate_notrack"); + fw3_ipt_rule_replace(r, "PREROUTING"); } } } -- 2.30.2