summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2020-06-02 19:37:09 +0200
committerJo-Philipp Wich <jo@mein.io>2020-06-02 20:37:29 +0200
commit23cc543f4f7ca636400707161e7e8355b6ecd856 (patch)
tree1d5f704234a649b6acf17cc71aa0db4f6dff0a2a
parent9d7f49df47ad40a95ea0a37b9dcf423ee07819a7 (diff)
downloadfirewall3-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.c23
-rw-r--r--iptables.c87
-rw-r--r--iptables.h6
-rw-r--r--zones.c25
4 files changed, 106 insertions, 35 deletions
diff --git a/defaults.c b/defaults.c
index 60a4c81..6c3ec9d 100644
--- a/defaults.c
+++ b/defaults.c
@@ -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);
diff --git a/iptables.c b/iptables.c
index 559fe7d..7ad1d22 100644
--- a/iptables.c
+++ b/iptables.c
@@ -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)
{
diff --git a/iptables.h b/iptables.h
index fb4a899..402baf2 100644
--- a/iptables.h
+++ b/iptables.h
@@ -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);
diff --git a/zones.c b/zones.c
index 01fb706..d915bfd 100644
--- a/zones.c
+++ b/zones.c
@@ -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);