summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJo-Philipp Wich <jow@openwrt.org>2016-01-24 17:43:30 +0100
committerJo-Philipp Wich <jow@openwrt.org>2016-01-24 17:56:02 +0100
commit410cff5e62db45e8415bf25bf50395b4e7e22482 (patch)
treeef74994935fa4efd86e970d9fed16b6baa57e925
parent18a503d0125aebc3a8d62dad1c02e6bb1da92eb6 (diff)
downloadfirewall3-410cff5e62db45e8415bf25bf50395b4e7e22482.tar.gz
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 <jow@openwrt.org>
-rw-r--r--defaults.c96
-rw-r--r--forwards.c2
-rw-r--r--iptables.c173
-rw-r--r--iptables.h9
-rw-r--r--main.c37
-rw-r--r--rules.c10
-rw-r--r--snats.c2
-rw-r--r--zones.c20
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
@@ -401,6 +401,35 @@ start:
}
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)
{
struct fw3_zone *z;
@@ -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");
}
}
}