diff options
author | Jo-Philipp Wich <jo@mein.io> | 2020-06-02 19:37:09 +0200 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2020-06-02 20:37:29 +0200 |
commit | 23cc543f4f7ca636400707161e7e8355b6ecd856 (patch) | |
tree | 1d5f704234a649b6acf17cc71aa0db4f6dff0a2a | |
parent | 9d7f49df47ad40a95ea0a37b9dcf423ee07819a7 (diff) | |
download | firewall3-23cc543f4f7ca636400707161e7e8355b6ecd856.tar.gz |
improve reload logic
- Purge chains in two phases, first flush rules, then delete chains
- Create missing zone user chains during reload
- Keep used chains on reload to avoid removing user rules
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r-- | defaults.c | 23 | ||||
-rw-r--r-- | iptables.c | 87 | ||||
-rw-r--r-- | iptables.h | 6 | ||||
-rw-r--r-- | zones.c | 25 |
4 files changed, 106 insertions, 35 deletions
@@ -196,10 +196,6 @@ fw3_print_default_chains(struct fw3_ipt_handle *handle, struct fw3_state *state, for (c = default_chains; c->format; c++) { - /* don't touch user chains on selective stop */ - if (reload && c->flag == FW3_FLAG_CUSTOM_CHAINS) - continue; - if (!fw3_is_family(c, handle->family)) continue; @@ -210,7 +206,7 @@ fw3_print_default_chains(struct fw3_ipt_handle *handle, struct fw3_state *state, !fw3_hasbit(defs->flags[handle->family == FW3_FAMILY_V6], c->flag)) continue; - fw3_ipt_create_chain(handle, c->format); + fw3_ipt_create_chain(handle, reload, c->format); } set(defs->flags, handle->family, handle->table); @@ -430,6 +426,7 @@ fw3_flush_rules(struct fw3_ipt_handle *handle, struct fw3_state *state, fw3_ipt_delete_id_rules(handle, "PREROUTING"); fw3_ipt_delete_id_rules(handle, "POSTROUTING"); + /* first flush all the rules ... */ for (c = default_chains; c->format; c++) { /* don't touch user chains on selective stop */ @@ -446,13 +443,21 @@ fw3_flush_rules(struct fw3_ipt_handle *handle, struct fw3_state *state, continue; fw3_ipt_flush_chain(handle, c->format); + } + + /* ... then remove the chains */ + for (c = default_chains; c->format; c++) + { + if (!fw3_is_family(c, handle->family)) + continue; - /* keep certain basic chains that do not depend on any settings to - avoid purging unrelated user rules pointing to them */ - if (reload && !c->flag) + if (c->table != handle->table) + continue; + + if (c->flag && !has(defs->flags, handle->family, c->flag)) continue; - fw3_ipt_delete_chain(handle, c->format); + fw3_ipt_delete_chain(handle, reload, c->format); } del(defs->flags, handle->family, handle->table); @@ -329,9 +329,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) @@ -425,8 +477,21 @@ fw3_ipt_delete_id_rules(struct fw3_ipt_handle *h, const char *chain) } } + +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); +} + void -fw3_ipt_create_chain(struct fw3_ipt_handle *h, const char *fmt, ...) +fw3_ipt_create_chain(struct fw3_ipt_handle *h, bool ignore_existing, + const char *fmt, ...) { char buf[32]; va_list ap; @@ -435,6 +500,9 @@ fw3_ipt_create_chain(struct fw3_ipt_handle *h, const char *fmt, ...) vsnprintf(buf, sizeof(buf) - 1, fmt, ap); va_end(ap); + if (ignore_existing && is_chain(h, buf)) + return; + if (fw3_pr_debug) debug(h, "-N %s\n", buf); @@ -514,7 +582,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; } @@ -537,7 +605,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; } @@ -588,17 +656,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) { @@ -50,11 +50,13 @@ 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_chain(struct fw3_ipt_handle *h, bool if_unused, + 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_create_chain(struct fw3_ipt_handle *h, bool ignore_existing, + const char *fmt, ...); void fw3_ipt_flush(struct fw3_ipt_handle *h); @@ -356,10 +356,6 @@ print_zone_chain(struct fw3_ipt_handle *handle, struct fw3_state *state, for (c = zone_chains; c->format; c++) { - /* don't touch user chains on selective stop */ - if (reload && c->flag == FW3_FLAG_CUSTOM_CHAINS) - continue; - if (!fw3_is_family(c, handle->family)) continue; @@ -370,7 +366,7 @@ print_zone_chain(struct fw3_ipt_handle *handle, struct fw3_state *state, !fw3_hasbit(zone->flags[handle->family == FW3_FAMILY_V6], c->flag)) continue; - fw3_ipt_create_chain(handle, c->format, zone->name); + fw3_ipt_create_chain(handle, reload, c->format, zone->name); } if (zone->custom_chains) @@ -763,6 +759,7 @@ fw3_flush_zones(struct fw3_ipt_handle *handle, struct fw3_state *state, if (!has(z->flags, handle->family, handle->table)) continue; + /* first flush all rules ... */ for (c = zone_chains; c->format; c++) { /* don't touch user chains on selective stop */ @@ -780,13 +777,23 @@ fw3_flush_zones(struct fw3_ipt_handle *handle, struct fw3_state *state, snprintf(chain, sizeof(chain), c->format, z->name); fw3_ipt_flush_chain(handle, chain); + } + + /* ... then remove the chains */ + for (c = zone_chains; c->format; c++) + { + if (!fw3_is_family(c, handle->family)) + continue; - /* keep certain basic chains that do not depend on any settings to - avoid purging unrelated user rules pointing to them */ - if (reload && !c->flag) + if (c->table != handle->table) continue; - fw3_ipt_delete_chain(handle, chain); + if (c->flag && !has(z->flags, handle->family, c->flag)) + continue; + + snprintf(chain, sizeof(chain), c->format, z->name); + + fw3_ipt_delete_chain(handle, reload, chain); } del(z->flags, handle->family, handle->table); |