From ea1e5c25c1c4c8c82b51c0440d033944ccb4e2e2 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Mon, 18 Feb 2013 02:54:15 +0100 Subject: [PATCH] selectively delete chains in filter and nat tables --- defaults.c | 262 ++++++++++++++++++++++++++++++++++++------------------------ defaults.h | 13 ++- forwards.c | 2 +- ipsets.c | 31 ++----- ipsets.h | 3 +- main.c | 50 +++++++----- options.h | 23 ++++-- redirects.c | 10 +-- rules.c | 2 +- utils.c | 102 +++++++++++++++++++---- utils.h | 19 +++++ zones.c | 158 ++++++++++++++++++++++-------------- zones.h | 3 + 13 files changed, 436 insertions(+), 242 deletions(-) diff --git a/defaults.c b/defaults.c index 498e5d5..1a25eaf 100644 --- a/defaults.c +++ b/defaults.c @@ -19,6 +19,47 @@ #include "defaults.h" +#define C(f, tbl, def, name) \ + { FW3_FAMILY_##f, FW3_TABLE_##tbl, FW3_DEFAULT_##def, name } + +struct chain { + enum fw3_family family; + enum fw3_table table; + enum fw3_default flag; + const char *name; +}; + +static const struct chain default_chains[] = { + C(ANY, FILTER, UNSPEC, "delegate_input"), + C(ANY, FILTER, UNSPEC, "delegate_output"), + C(ANY, FILTER, UNSPEC, "delegate_forward"), + C(ANY, FILTER, CUSTOM_CHAINS, "input_rule"), + C(ANY, FILTER, CUSTOM_CHAINS, "output_rule"), + C(ANY, FILTER, CUSTOM_CHAINS, "forwarding_rule"), + C(ANY, FILTER, UNSPEC, "reject"), + C(ANY, FILTER, SYN_FLOOD, "syn_flood"), + + 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, RAW, UNSPEC, "notrack"), +}; + +static const struct chain toplevel_rules[] = { + C(ANY, FILTER, UNSPEC, "INPUT -j delegate_input"), + C(ANY, FILTER, UNSPEC, "OUTPUT -j delegate_output"), + C(ANY, FILTER, UNSPEC, "FORWARD -j delegate_forward"), + + C(V4, NAT, UNSPEC, "PREROUTING -j delegate_prerouting"), + C(V4, NAT, UNSPEC, "POSTROUTING -j delegate_postrouting"), + + C(ANY, MANGLE, UNSPEC, "FORWARD -j mssfix"), + C(ANY, RAW, UNSPEC, "PREROUTING -j notrack"), +}; + static struct fw3_option default_opts[] = { FW3_OPT("input", target, defaults, policy_input), FW3_OPT("forward", target, defaults, policy_forward), @@ -44,6 +85,33 @@ static struct fw3_option default_opts[] = { }; +static bool +print_chains(enum fw3_table table, enum fw3_family family, + const char *fmt, uint8_t flags, + const struct chain *chains, int n) +{ + bool rv = false; + const struct chain *c; + + for (c = chains; n > 0; c++, n--) + { + if (!fw3_is_family(c, family)) + continue; + + if (c->table != table) + continue; + + if ((c->flag != FW3_DEFAULT_UNSPEC) && !(flags & (1 << c->flag))) + continue; + + fw3_pr(fmt, c->name); + + rv = true; + } + + return rv; +} + static void check_policy(struct uci_element *e, enum fw3_target *pol, const char *name) { @@ -93,6 +161,12 @@ fw3_load_defaults(struct fw3_state *state, struct uci_package *p) check_policy(e, &defs->policy_input, "input"); check_policy(e, &defs->policy_output, "output"); check_policy(e, &defs->policy_forward, "forward"); + + if (defs->custom_chains) + defs->has_flag |= (1 << FW3_DEFAULT_CUSTOM_CHAINS); + + if (defs->syn_flood) + defs->has_flag |= (1 << FW3_DEFAULT_SYN_FLOOD); } } @@ -111,72 +185,53 @@ fw3_print_default_chains(enum fw3_table table, enum fw3_family family, "(bug)", }; - switch (table) + if (table == FW3_TABLE_FILTER) { - case FW3_TABLE_FILTER: fw3_pr(":INPUT %s [0:0]\n", policy[defs->policy_input]); fw3_pr(":FORWARD %s [0:0]\n", policy[defs->policy_forward]); fw3_pr(":OUTPUT %s [0:0]\n", policy[defs->policy_output]); - - if (defs->custom_chains) - { - fw3_pr(":input_rule - [0:0]\n"); - fw3_pr(":output_rule - [0:0]\n"); - fw3_pr(":forwarding_rule - [0:0]\n"); - } - - fw3_pr(":delegate_input - [0:0]\n"); - fw3_pr(":delegate_output - [0:0]\n"); - fw3_pr(":delegate_forward - [0:0]\n"); - fw3_pr(":reject - [0:0]\n"); - fw3_pr(":syn_flood - [0:0]\n"); - break; - - case FW3_TABLE_NAT: - if (defs->custom_chains) - { - fw3_pr(":prerouting_rule - [0:0]\n"); - fw3_pr(":postrouting_rule - [0:0]\n"); - } - break; - - case FW3_TABLE_MANGLE: - fw3_pr(":mssfix - [0:0]\n"); - break; - - case FW3_TABLE_RAW: - if (!defs->drop_invalid) - fw3_pr(":notrack - [0:0]\n"); - break; } + + print_chains(table, family, ":%s - [0:0]\n", defs->has_flag, + default_chains, ARRAY_SIZE(default_chains)); } void -fw3_print_default_rules(enum fw3_table table, enum fw3_family family, - struct fw3_state *state) +fw3_print_default_head_rules(enum fw3_table table, enum fw3_family family, + struct fw3_state *state) { int i; struct fw3_defaults *defs = &state->defaults; const char *chains[] = { - "INPUT", - "OUTPUT", - "FORWARD", + "input", + "output", + "forward", }; + print_chains(table, family, "-A %s\n", 0, + toplevel_rules, ARRAY_SIZE(toplevel_rules)); + switch (table) { case FW3_TABLE_FILTER: - fw3_pr("-A INPUT -i lo -j ACCEPT\n"); - fw3_pr("-A OUTPUT -o lo -j ACCEPT\n"); + fw3_pr("-A delegate_input -i lo -j ACCEPT\n"); + fw3_pr("-A delegate_output -o lo -j ACCEPT\n"); + + if (defs->custom_chains) + { + fw3_pr("-A delegate_input -j input_rule\n"); + fw3_pr("-A delegate_output -j output_rule\n"); + fw3_pr("-A delegate_forward -j forwarding_rule\n"); + } for (i = 0; i < ARRAY_SIZE(chains); i++) { - fw3_pr("-A %s -m conntrack --ctstate RELATED,ESTABLISHED " + fw3_pr("-A delegate_%s -m conntrack --ctstate RELATED,ESTABLISHED " "-j ACCEPT\n", chains[i]); if (defs->drop_invalid) { - fw3_pr("-A %s -m conntrack --ctstate INVALID -j DROP\n", + fw3_pr("-A delegate_%s -m conntrack --ctstate INVALID -j DROP\n", chains[i]); } } @@ -188,96 +243,91 @@ fw3_print_default_rules(enum fw3_table table, enum fw3_family family, fw3_pr(" -j RETURN\n"); fw3_pr("-A syn_flood -j DROP\n"); - fw3_pr("-A INPUT -p tcp --syn -j syn_flood\n"); - } - - if (defs->custom_chains) - { - fw3_pr("-A INPUT -j input_rule\n"); - fw3_pr("-A OUTPUT -j output_rule\n"); - fw3_pr("-A FORWARD -j forwarding_rule\n"); + fw3_pr("-A delegate_input -p tcp --syn -j syn_flood\n"); } - fw3_pr("-A INPUT -j delegate_input\n"); - fw3_pr("-A OUTPUT -j delegate_output\n"); - fw3_pr("-A FORWARD -j delegate_forward\n"); - fw3_pr("-A reject -p tcp -j REJECT --reject-with tcp-reset\n"); fw3_pr("-A reject -j REJECT --reject-with port-unreach\n"); - if (defs->policy_input == FW3_TARGET_REJECT) - fw3_pr("-A INPUT -j reject\n"); - - if (defs->policy_output == FW3_TARGET_REJECT) - fw3_pr("-A OUTPUT -j reject\n"); - - if (defs->policy_forward == FW3_TARGET_REJECT) - fw3_pr("-A FORWARD -j reject\n"); - break; case FW3_TABLE_NAT: if (defs->custom_chains) { - fw3_pr("-A PREROUTING -j prerouting_rule\n"); - fw3_pr("-A POSTROUTING -j postrouting_rule\n"); + fw3_pr("-A delegate_prerouting -j prerouting_rule\n"); + fw3_pr("-A delegate_postrouting -j postrouting_rule\n"); } break; - case FW3_TABLE_MANGLE: - fw3_pr("-A FORWARD -j mssfix\n"); - break; - - case FW3_TABLE_RAW: - if (!defs->drop_invalid) - fw3_pr("-A PREROUTING -j notrack\n"); + default: break; } } void -fw3_print_flush_rules(enum fw3_table table, enum fw3_family family, - struct fw3_state *state, bool complete) +fw3_print_default_tail_rules(enum fw3_table table, enum fw3_family family, + struct fw3_state *state) { - switch (table) - { - case FW3_TABLE_FILTER: - fw3_pr(":INPUT ACCEPT [0:0]\n"); - fw3_pr(":OUTPUT ACCEPT [0:0]\n"); - fw3_pr(":FORWARD ACCEPT [0:0]\n"); - /* fall through */ + struct fw3_defaults *defs = &state->defaults; - case FW3_TABLE_NAT: - fw3_pr("-F\n"); - fw3_pr("-X\n"); - break; + if (table != FW3_TABLE_FILTER) + return; - case FW3_TABLE_MANGLE: - if (complete) - { - fw3_pr("-F\n"); - fw3_pr("-X\n"); - } - else - { - fw3_pr("-D FORWARD -j mssfix\n"); - fw3_pr("-F mssfix\n"); - fw3_pr("-X mssfix\n"); - } - break; + if (defs->policy_input == FW3_TARGET_REJECT) + fw3_pr("-A delegate_input -j reject\n"); + + if (defs->policy_output == FW3_TARGET_REJECT) + fw3_pr("-A delegate_output -j reject\n"); + + if (defs->policy_forward == FW3_TARGET_REJECT) + fw3_pr("-A delegate_forward -j reject\n"); +} + +static void +reset_policy(enum fw3_table table) +{ + if (table != FW3_TABLE_FILTER) + return; + + fw3_pr(":INPUT ACCEPT [0:0]\n"); + fw3_pr(":OUTPUT ACCEPT [0:0]\n"); + fw3_pr(":FORWARD ACCEPT [0:0]\n"); +} + +void +fw3_flush_rules(enum fw3_table table, enum fw3_family family, + bool pass2, struct list_head *statefile) +{ + struct fw3_statefile_entry *e; - case FW3_TABLE_RAW: - if (complete) + list_for_each_entry(e, statefile, list) + { + if (e->type != FW3_TYPE_DEFAULTS) + continue; + + if (!pass2) { - fw3_pr("-F\n"); - fw3_pr("-X\n"); + reset_policy(table); + + print_chains(table, family, "-D %s\n", e->flags[0], + toplevel_rules, ARRAY_SIZE(toplevel_rules)); + + print_chains(table, family, "-F %s\n", e->flags[0], + default_chains, ARRAY_SIZE(default_chains)); } else { - fw3_pr("-D PREROUTING -j notrack\n"); - fw3_pr("-F notrack\n"); - fw3_pr("-X notrack\n"); + print_chains(table, family, "-X %s\n", e->flags[0], + default_chains, ARRAY_SIZE(default_chains)); } - break; } } + +void +fw3_flush_all(enum fw3_table table) +{ + reset_policy(table); + + fw3_pr("-F\n"); + fw3_pr("-X\n"); +} diff --git a/defaults.h b/defaults.h index 10ac68c..17f9ba9 100644 --- a/defaults.h +++ b/defaults.h @@ -26,10 +26,15 @@ void fw3_load_defaults(struct fw3_state *state, struct uci_package *p); void fw3_print_default_chains(enum fw3_table table, enum fw3_family family, struct fw3_state *state); -void fw3_print_default_rules(enum fw3_table table, enum fw3_family family, - struct fw3_state *state); +void fw3_print_default_head_rules(enum fw3_table table, enum fw3_family family, + struct fw3_state *state); -void fw3_print_flush_rules(enum fw3_table table, enum fw3_family family, - struct fw3_state *state, bool complete); +void fw3_print_default_tail_rules(enum fw3_table table, enum fw3_family family, + struct fw3_state *state); + +void fw3_flush_rules(enum fw3_table table, enum fw3_family family, + bool pass2, struct list_head *statefile); + +void fw3_flush_all(enum fw3_table table); #endif diff --git a/forwards.c b/forwards.c index c212c8c..d3750b5 100644 --- a/forwards.c +++ b/forwards.c @@ -76,7 +76,7 @@ fw3_load_forwards(struct fw3_state *state, struct uci_package *p) if (forward->_dest) { - forward->_dest->has_dest_target[FW3_TARGET_ACCEPT] = true; + forward->_dest->has_dest_target |= (1 << FW3_TARGET_ACCEPT); if (forward->_src && (forward->_src->conntrack || forward->_dest->conntrack)) diff --git a/ipsets.c b/ipsets.c index ca0bd29..215be73 100644 --- a/ipsets.c +++ b/ipsets.c @@ -351,39 +351,22 @@ fw3_create_ipsets(struct fw3_state *state) } void -fw3_destroy_ipsets(struct fw3_state *state) +fw3_destroy_ipsets(struct list_head *statefile) { - FILE *sf; - - char *p; - char line[128]; - - sf = fopen(FW3_STATEFILE, "r"); - - if (!sf) - return; + struct fw3_statefile_entry *e; info("Destroying ipsets ..."); - while (fgets(line, sizeof(line), sf)) + list_for_each_entry(e, statefile, list) { - if (strncmp(line, "ipset ", 6)) - continue; - - p = strtok(line+6, " \t\n"); - - if (!p || !strlen(p)) + if (e->type != FW3_TYPE_IPSET) continue; - info(" * %s", p); + info(" * %s", e->name); - fw3_pr("flush %s\n", p); - fw3_pr("destroy %s\n", p); + fw3_pr("flush %s\n", e->name); + fw3_pr("destroy %s\n", e->name); } - - fw3_pr("quit\n"); - - fclose(sf); } void diff --git a/ipsets.h b/ipsets.h index 5ad6d99..49c6e66 100644 --- a/ipsets.h +++ b/ipsets.h @@ -40,7 +40,8 @@ struct fw3_ipset_settype { void fw3_load_ipsets(struct fw3_state *state, struct uci_package *p); void fw3_create_ipsets(struct fw3_state *state); -void fw3_destroy_ipsets(struct fw3_state *state); + +void fw3_destroy_ipsets(struct list_head *statefile); void fw3_free_ipset(struct fw3_ipset *ipset); diff --git a/main.c b/main.c index 79324a4..fdb901a 100644 --- a/main.c +++ b/main.c @@ -125,11 +125,13 @@ restore_pipe(enum fw3_family family, bool silent) } static int -stop(struct fw3_state *state, bool complete) +stop(struct fw3_state *state, bool complete, bool ipsets) { enum fw3_family family; enum fw3_table table; + struct list_head *statefile = fw3_read_state(); + const char *tables[] = { "filter", "nat", @@ -153,24 +155,37 @@ stop(struct fw3_state *state, bool complete) complete ? "Flush" : "Clear", tables[table]); fw3_pr("*%s\n", tables[table]); - fw3_print_flush_rules(table, family, state, complete); + + if (complete) + { + fw3_flush_all(table); + } + else + { + /* pass 1 */ + fw3_flush_rules(table, family, false, statefile); + fw3_flush_zones(table, family, false, statefile); + + /* pass 2 */ + fw3_flush_rules(table, family, true, statefile); + fw3_flush_zones(table, family, true, statefile); + } + fw3_pr("COMMIT\n"); } fw3_command_close(); } - return 0; -} + if (ipsets && fw3_command_pipe(false, "ipset", "-exist", "-")) + { + fw3_destroy_ipsets(statefile); + fw3_command_close(); + } -static void -destroy_ipsets(struct fw3_state *state) -{ - if (!fw3_command_pipe(false, "ipset", "-exist", "-")) - return; + fw3_free_state(statefile); - fw3_destroy_ipsets(state); - fw3_command_close(); + return 0; } static int @@ -209,11 +224,12 @@ start(struct fw3_state *state) fw3_pr("*%s\n", tables[table]); fw3_print_default_chains(table, family, state); fw3_print_zone_chains(table, family, state); - fw3_print_default_rules(table, family, state); + fw3_print_default_head_rules(table, family, state); fw3_print_rules(table, family, state); fw3_print_redirects(table, family, state); fw3_print_forwards(table, family, state); fw3_print_zone_rules(table, family, state); + fw3_print_default_tail_rules(table, family, state); fw3_pr("COMMIT\n"); } @@ -355,17 +371,13 @@ int main(int argc, char **argv) goto out; } - rv = stop(state, false); - - destroy_ipsets(state); + rv = stop(state, false, true); fw3_remove_state(); } else if (!strcmp(argv[optind], "flush")) { - rv = stop(state, true); - - destroy_ipsets(state); + rv = stop(state, true, true); if (fw3_has_state()) fw3_remove_state(); @@ -374,7 +386,7 @@ int main(int argc, char **argv) { if (fw3_has_state()) { - stop(state, false); + stop(state, false, false); fw3_remove_state(); } diff --git a/options.h b/options.h index 0d9fb99..ee2c008 100644 --- a/options.h +++ b/options.h @@ -46,10 +46,10 @@ enum fw3_table { - FW3_TABLE_FILTER, - FW3_TABLE_NAT, - FW3_TABLE_MANGLE, - FW3_TABLE_RAW, + FW3_TABLE_FILTER = 0, + FW3_TABLE_NAT = 1, + FW3_TABLE_MANGLE = 2, + FW3_TABLE_RAW = 3, }; enum fw3_family @@ -70,6 +70,15 @@ enum fw3_target FW3_TARGET_SNAT = 6, }; +enum fw3_default +{ + FW3_DEFAULT_UNSPEC = 0, + FW3_DEFAULT_CUSTOM_CHAINS = 1, + FW3_DEFAULT_SYN_FLOOD = 2, + FW3_DEFAULT_MTU_FIX = 3, + FW3_DEFAULT_DROP_INVALID = 4, +}; + enum fw3_limit_unit { FW3_LIMIT_UNIT_SECOND = 0, @@ -200,6 +209,8 @@ struct fw3_defaults bool custom_chains; bool disable_ipv6; + + uint8_t has_flag; }; struct fw3_zone @@ -233,8 +244,8 @@ struct fw3_zone bool custom_chains; - bool has_src_target[FW3_TARGET_SNAT + 1]; - bool has_dest_target[FW3_TARGET_SNAT + 1]; + uint8_t has_src_target; + uint8_t has_dest_target; }; struct fw3_rule diff --git a/redirects.c b/redirects.c index 2bf2c37..1fc81f0 100644 --- a/redirects.c +++ b/redirects.c @@ -133,16 +133,16 @@ fw3_load_redirects(struct fw3_state *state, struct uci_package *p) warn_elem(e, "has no source specified"); else { - redir->_src->has_dest_target[redir->target] = true; + redir->_src->has_dest_target |= (1 << redir->target); redir->_src->conntrack = true; valid = true; } if (redir->reflection && redir->_dest && redir->_src->masq) { - redir->_dest->has_dest_target[FW3_TARGET_ACCEPT] = true; - redir->_dest->has_dest_target[FW3_TARGET_DNAT] = true; - redir->_dest->has_dest_target[FW3_TARGET_SNAT] = true; + redir->_dest->has_dest_target |= (1 << FW3_TARGET_ACCEPT); + redir->_dest->has_dest_target |= (1 << FW3_TARGET_DNAT); + redir->_dest->has_dest_target |= (1 << FW3_TARGET_SNAT); } } else @@ -155,7 +155,7 @@ fw3_load_redirects(struct fw3_state *state, struct uci_package *p) warn_elem(e, "has no src_dip option specified"); else { - redir->_dest->has_dest_target[redir->target] = true; + redir->_dest->has_dest_target |= (1 << redir->target); redir->_dest->conntrack = true; valid = true; } diff --git a/rules.c b/rules.c index 3ad2a6a..12c04c9 100644 --- a/rules.c +++ b/rules.c @@ -142,7 +142,7 @@ fw3_load_rules(struct fw3_state *state, struct uci_package *p) } if (rule->_dest) - rule->_dest->has_dest_target[rule->target] = true; + rule->_dest->has_dest_target |= (1 << rule->target); list_add_tail(&rule->list, &state->rules); continue; diff --git a/utils.c b/utils.c index a5d0082..4691fe1 100644 --- a/utils.c +++ b/utils.c @@ -332,17 +332,93 @@ fw3_unlock(void) } -bool fw3_has_state(void) +bool +fw3_has_state(void) { struct stat s; return !stat(FW3_STATEFILE, &s); } -void fw3_write_state(void *state) +struct list_head * +fw3_read_state(void) +{ + FILE *sf; + + int n; + char line[128]; + const char *p; + + struct list_head *state; + struct fw3_statefile_entry *entry; + + state = malloc(sizeof(*state)); + + if (!state) + return NULL; + + INIT_LIST_HEAD(state); + + sf = fopen(FW3_STATEFILE, "r"); + + if (!sf) + { + warn("Cannot open state %s: %s", FW3_STATEFILE, strerror(errno)); + free(state); + + return NULL; + } + + while (fgets(line, sizeof(line), sf)) + { + entry = malloc(sizeof(*entry)); + + if (!entry) + continue; + + memset(entry, 0, sizeof(*entry)); + + p = strtok(line, " \t\n"); + + if (!p) + continue; + + entry->type = strtoul(p, NULL, 10); + + p = strtok(NULL, " \t\n"); + + if (!p) + continue; + + entry->name = strdup(p); + + for (n = 0, p = strtok(NULL, " \t\n"); + n < ARRAY_SIZE(entry->flags) && p != NULL; + n++, p = strtok(NULL, " \t\n")) + { + entry->flags[n] = strtoul(p, NULL, 10); + } + + list_add_tail(&entry->list, state); + } + + fclose(sf); + + return state; +} + +void +fw3_free_state(struct list_head *statefile) +{ + fw3_free_list(statefile); + free(statefile); +} + +void +fw3_write_state(void *state) { FILE *sf; - int n, val; struct fw3_state *s = state; + struct fw3_defaults *d = &s->defaults; struct fw3_zone *z; struct fw3_ipset *i; @@ -354,19 +430,12 @@ void fw3_write_state(void *state) return; } + fprintf(sf, "%u - %u\n", FW3_TYPE_DEFAULTS, d->has_flag); + list_for_each_entry(z, &s->zones, list) { - for (n = FW3_TARGET_ACCEPT, val = 0; n <= FW3_TARGET_SNAT; n++) - if (z->has_src_target[n]) - val |= (1 << n); - - fprintf(sf, "zone %s %u", z->name, val); - - for (n = FW3_TARGET_ACCEPT, val = 0; n <= FW3_TARGET_SNAT; n++) - if (z->has_dest_target[n]) - val |= (1 << n); - - fprintf(sf, " %u\n", val); + fprintf(sf, "%u %s %u %u\n", FW3_TYPE_ZONE, + z->name, z->has_src_target, z->has_dest_target); } list_for_each_entry(i, &s->ipsets, list) @@ -374,13 +443,14 @@ void fw3_write_state(void *state) if (i->external && *i->external) continue; - fprintf(sf, "ipset %s\n", i->name); + fprintf(sf, "%u %s\n", FW3_TYPE_IPSET, i->name); } fclose(sf); } -void fw3_remove_state(void) +void +fw3_remove_state(void) { if (unlink(FW3_STATEFILE)) warn("Unable to remove state %s: %s", FW3_STATEFILE, strerror(errno)); diff --git a/utils.h b/utils.h index 90d7c9a..2178b5a 100644 --- a/utils.h +++ b/utils.h @@ -79,4 +79,23 @@ bool fw3_has_state(void); void fw3_write_state(void *state); void fw3_remove_state(void); + +enum fw3_statefile_type +{ + FW3_TYPE_DEFAULTS = 0, + FW3_TYPE_ZONE = 1, + FW3_TYPE_IPSET = 2, +}; + +struct fw3_statefile_entry +{ + struct list_head list; + enum fw3_statefile_type type; + const char *name; + uint32_t flags[2]; +}; + +struct list_head * fw3_read_state(void); +void fw3_free_state(struct list_head *statefile); + #endif diff --git a/zones.c b/zones.c index 2820348..3ab17bf 100644 --- a/zones.c +++ b/zones.c @@ -20,6 +20,37 @@ #include "ubus.h" +#define C(f, tbl, tgt, name) \ + { FW3_FAMILY_##f, FW3_TABLE_##tbl, FW3_TARGET_##tgt, name } + +struct chain { + enum fw3_family family; + enum fw3_table table; + enum fw3_target target; + const char *name; +}; + +static const struct chain src_chains[] = { + C(ANY, FILTER, UNSPEC, "zone_%s_input"), + C(ANY, FILTER, UNSPEC, "zone_%s_output"), + C(ANY, FILTER, UNSPEC, "zone_%s_forward"), + + C(ANY, FILTER, ACCEPT, "zone_%s_src_ACCEPT"), + C(ANY, FILTER, REJECT, "zone_%s_src_REJECT"), + C(ANY, FILTER, DROP, "zone_%s_src_DROP"), +}; + +static const struct chain dst_chains[] = { + C(ANY, FILTER, ACCEPT, "zone_%s_dest_ACCEPT"), + C(ANY, FILTER, REJECT, "zone_%s_dest_REJECT"), + C(ANY, FILTER, DROP, "zone_%s_dest_DROP"), + + C(V4, NAT, SNAT, "zone_%s_postrouting"), + C(V4, NAT, DNAT, "zone_%s_prerouting"), + + C(ANY, RAW, NOTRACK, "zone_%s_notrack"), +}; + static struct fw3_option zone_opts[] = { FW3_OPT("name", string, zone, name), @@ -48,6 +79,35 @@ static struct fw3_option zone_opts[] = { }; +static bool +print_chains(enum fw3_table table, enum fw3_family family, + const char *fmt, const char *name, uint8_t targets, + const struct chain *chains, int n) +{ + bool rv = false; + char cn[128] = { 0 }; + const struct chain *c; + + for (c = chains; n > 0; c++, n--) + { + if (!fw3_is_family(c, family)) + continue; + + if (c->table != table) + continue; + + if ((c->target != FW3_TARGET_UNSPEC) && !(targets & (1 << c->target))) + continue; + + snprintf(cn, sizeof(cn), c->name, name); + fw3_pr(fmt, cn); + + rv = true; + } + + return rv; +} + static void check_policy(struct uci_element *e, enum fw3_target *pol, enum fw3_target def, const char *name) @@ -141,13 +201,13 @@ fw3_load_zones(struct fw3_state *state, struct uci_package *p) if (zone->masq) { - zone->has_dest_target[FW3_TARGET_SNAT] = true; + zone->has_dest_target |= (1 << FW3_TARGET_SNAT); zone->conntrack = true; } - zone->has_src_target[zone->policy_input] = true; - zone->has_dest_target[zone->policy_output] = true; - zone->has_dest_target[zone->policy_forward] = true; + zone->has_src_target |= (1 << zone->policy_input); + zone->has_dest_target |= (1 << zone->policy_output); + zone->has_dest_target |= (1 << zone->policy_forward); list_add_tail(&zone->list, &state->zones); } @@ -158,60 +218,22 @@ static void print_zone_chain(enum fw3_table table, enum fw3_family family, struct fw3_zone *zone, bool disable_notrack) { - enum fw3_target t; - const char *targets[] = { - "(bug)", - "ACCEPT", - "REJECT", - "DROP", - }; + bool s, d; if (!fw3_is_family(zone, family)) return; - switch (table) - { - case FW3_TABLE_FILTER: - info(" * Zone '%s'", zone->name); - - for (t = FW3_TARGET_ACCEPT; t <= FW3_TARGET_DROP; t++) - { - if (zone->has_src_target[t]) - fw3_pr(":zone_%s_src_%s - [0:0]\n", zone->name, targets[t]); - - if (zone->has_dest_target[t]) - fw3_pr(":zone_%s_dest_%s - [0:0]\n", zone->name, targets[t]); - } - - fw3_pr(":zone_%s_forward - [0:0]\n", zone->name); - fw3_pr(":zone_%s_input - [0:0]\n", zone->name); - fw3_pr(":zone_%s_output - [0:0]\n", zone->name); - break; + if (!zone->conntrack && !disable_notrack) + zone->has_dest_target |= (1 << FW3_TARGET_NOTRACK); - case FW3_TABLE_NAT: - if (family == FW3_FAMILY_V4) - { - info(" * Zone '%s'", zone->name); - - if (zone->has_dest_target[FW3_TARGET_SNAT]) - fw3_pr(":zone_%s_postrouting - [0:0]\n", zone->name); - - if (zone->has_dest_target[FW3_TARGET_DNAT]) - fw3_pr(":zone_%s_prerouting - [0:0]\n", zone->name); - } - break; + s = print_chains(table, family, ":%s - [0:0]\n", zone->name, + zone->has_src_target, src_chains, ARRAY_SIZE(src_chains)); - case FW3_TABLE_RAW: - if (!zone->conntrack && !disable_notrack) - { - info(" * Zone '%s'", zone->name); - fw3_pr(":zone_%s_notrack - [0:0]\n", zone->name); - } - break; + d = print_chains(table, family, ":%s - [0:0]\n", zone->name, + zone->has_dest_target, dst_chains, ARRAY_SIZE(dst_chains)); - case FW3_TABLE_MANGLE: - break; - } + if (s || d) + info(" * Zone '%s'", zone->name); } static void @@ -231,7 +253,7 @@ print_interface_rule(enum fw3_table table, enum fw3_family family, { for (t = FW3_TARGET_ACCEPT; t <= FW3_TARGET_DROP; t++) { - if (zone->has_src_target[t]) + if (zone->has_src_target & (1 << t)) { fw3_pr("-A zone_%s_src_%s", zone->name, targets[t*2]); fw3_format_in_out(dev, NULL); @@ -240,7 +262,7 @@ print_interface_rule(enum fw3_table table, enum fw3_family family, fw3_pr(" -j %s\n", targets[t*2+1]); } - if (zone->has_dest_target[t]) + if (zone->has_dest_target & (1 << t)) { fw3_pr("-A zone_%s_dest_%s", zone->name, targets[t*2]); fw3_format_in_out(NULL, dev); @@ -270,18 +292,18 @@ print_interface_rule(enum fw3_table table, enum fw3_family family, } else if (table == FW3_TABLE_NAT) { - if (zone->has_dest_target[FW3_TARGET_DNAT]) + if (zone->has_dest_target & (1 << FW3_TARGET_DNAT)) { - fw3_pr("-A PREROUTING"); + fw3_pr("-A delegate_prerouting"); fw3_format_in_out(dev, NULL); fw3_format_src_dest(sub, NULL); fw3_format_extra(zone->extra_src); fw3_pr(" -j zone_%s_prerouting\n", zone->name); } - if (zone->has_dest_target[FW3_TARGET_SNAT]) + if (zone->has_dest_target & (1 << FW3_TARGET_SNAT)) { - fw3_pr("-A POSTROUTING"); + fw3_pr("-A delegate_postrouting"); fw3_format_in_out(NULL, dev); fw3_format_src_dest(NULL, sub); fw3_format_extra(zone->extra_dest); @@ -382,7 +404,7 @@ print_zone_rule(enum fw3_table table, enum fw3_family family, { for (t = FW3_TARGET_REJECT; t <= FW3_TARGET_DROP; t++) { - if (zone->has_src_target[t]) + if (zone->has_src_target & (1 << t)) { fw3_pr("-A zone_%s_src_%s", zone->name, targets[t]); fw3_format_limit(&zone->log_limit); @@ -390,7 +412,7 @@ print_zone_rule(enum fw3_table table, enum fw3_family family, targets[t], zone->name); } - if (zone->has_dest_target[t]) + if (zone->has_dest_target & (1 << t)) { fw3_pr("-A zone_%s_dest_%s", zone->name, targets[t]); fw3_format_limit(&zone->log_limit); @@ -442,6 +464,24 @@ fw3_print_zone_rules(enum fw3_table table, enum fw3_family family, print_zone_rule(table, family, zone, state->defaults.drop_invalid); } +void +fw3_flush_zones(enum fw3_table table, enum fw3_family family, + bool pass2, struct list_head *statefile) +{ + struct fw3_statefile_entry *e; + + list_for_each_entry(e, statefile, list) + { + if (e->type != FW3_TYPE_ZONE) + continue; + + print_chains(table, family, pass2 ? "-X %s\n" : "-F %s\n", + e->name, e->flags[0], src_chains, ARRAY_SIZE(src_chains)); + + print_chains(table, family, pass2 ? "-X %s\n" : "-F %s\n", + e->name, e->flags[1], dst_chains, ARRAY_SIZE(dst_chains)); + } +} struct fw3_zone * fw3_lookup_zone(struct fw3_state *state, const char *name) diff --git a/zones.h b/zones.h index 8537af7..57e42df 100644 --- a/zones.h +++ b/zones.h @@ -29,6 +29,9 @@ void fw3_print_zone_chains(enum fw3_table table, enum fw3_family family, void fw3_print_zone_rules(enum fw3_table table, enum fw3_family family, struct fw3_state *state); +void fw3_flush_zones(enum fw3_table table, enum fw3_family family, + bool pass2, struct list_head *statefile); + struct fw3_zone * fw3_lookup_zone(struct fw3_state *state, const char *name); void fw3_free_zone(struct fw3_zone *zone); -- 2.11.0