Use libiptc to clear current ruleset
authorJo-Philipp Wich <jow@openwrt.org>
Mon, 13 May 2013 17:47:12 +0000 (19:47 +0200)
committerJo-Philipp Wich <jow@openwrt.org>
Mon, 13 May 2013 18:56:18 +0000 (20:56 +0200)
CMakeLists.txt
defaults.c
defaults.h
iptables.c [new file with mode: 0644]
iptables.h [new file with mode: 0644]
main.c
zones.c
zones.h

index 01d2c7c43cc10795373f5337abd4f7180f34cf04..50b1c3f43ba6d806ffdc137879963ef99460eb06 100644 (file)
@@ -10,8 +10,8 @@ IF(APPLE)
   LINK_DIRECTORIES(/opt/local/lib)
 ENDIF()
 
-ADD_EXECUTABLE(firewall3 main.c options.c defaults.c zones.c forwards.c rules.c redirects.c utils.c ubus.c ipsets.c includes.c)
-TARGET_LINK_LIBRARIES(firewall3 uci ubox ubus)
+ADD_EXECUTABLE(firewall3 main.c options.c defaults.c zones.c forwards.c rules.c redirects.c utils.c ubus.c ipsets.c includes.c iptables.c)
+TARGET_LINK_LIBRARIES(firewall3 uci ubox ubus ip4tc ip6tc)
 
 SET(CMAKE_INSTALL_PREFIX /usr)
 
index f87ac92d0e2420b59b04304b006f54f4d19e0b7f..20c57d6ad81c0996fbf5472ad3f210aa86d96725 100644 (file)
@@ -301,55 +301,39 @@ fw3_set_defaults(struct fw3_state *state)
        set_default("window_scaling", state->defaults.tcp_window_scaling);
 }
 
-static void
-reset_policy(enum fw3_table table, enum fw3_flag policy)
-{
-       if (table != FW3_TABLE_FILTER)
-               return;
-
-       fw3_pr(":INPUT %s [0:0]\n", fw3_flag_names[policy]);
-       fw3_pr(":OUTPUT %s [0:0]\n", fw3_flag_names[policy]);
-       fw3_pr(":FORWARD %s [0:0]\n", fw3_flag_names[policy]);
-}
-
 void
-fw3_flush_rules(struct fw3_state *state, enum fw3_family family,
-                enum fw3_table table, bool reload, bool pass2)
+fw3_flush_rules(struct fw3_ipt_handle *handle, struct fw3_state *state,
+                bool reload)
 {
        struct fw3_defaults *defs = &state->defaults;
-       uint32_t custom_mask = ~0;
+       const struct fw3_rule_spec *c;
 
-       if (!has(defs->flags, family, table))
+       if (!has(defs->flags, handle->family, handle->table))
                return;
 
-       /* don't touch user chains on selective stop */
-       if (reload)
-               delbit(custom_mask, FW3_FLAG_CUSTOM_CHAINS);
-
-       if (!pass2)
+       for (c = default_chains; c->format; c++)
        {
-               reset_policy(table, reload ? FW3_FLAG_DROP : FW3_FLAG_ACCEPT);
+               /* don't touch user chains on selective stop */
+               if (reload && hasbit(c->flag, FW3_FLAG_CUSTOM_CHAINS))
+                       continue;
 
-               fw3_pr_rulespec(table, family, defs->flags, custom_mask,
-                               toplevel_rules, "-D %s\n");
+               if (!fw3_is_family(c, handle->family))
+                       continue;
 
-               fw3_pr_rulespec(table, family, defs->flags, custom_mask,
-                               default_chains, "-F %s\n");
-       }
-       else
-       {
-               fw3_pr_rulespec(table, family, defs->flags, custom_mask,
-                               default_chains, "-X %s\n");
+               if (c->table != handle->table)
+                       continue;
 
-               del(defs->flags, family, table);
+               fw3_ipt_set_policy(handle, reload ? FW3_FLAG_DROP : FW3_FLAG_ACCEPT);
+               fw3_ipt_delete_rules(handle, c->format);
+               fw3_ipt_delete_chain(handle, c->format);
        }
+
+       del(defs->flags, handle->family, handle->table);
 }
 
 void
-fw3_flush_all(enum fw3_table table)
+fw3_flush_all(struct fw3_ipt_handle *handle)
 {
-       reset_policy(table, FW3_FLAG_ACCEPT);
-
-       fw3_pr("-F\n");
-       fw3_pr("-X\n");
+       fw3_ipt_set_policy(handle, FW3_FLAG_ACCEPT);
+       fw3_ipt_flush(handle);
 }
index 1c1a6a0455c5797fa86df3a1a9e910bcc143e372..a89a36e5c700c2d9186c964c553f5d2398d3f9ae 100644 (file)
@@ -20,6 +20,7 @@
 #define __FW3_DEFAULTS_H
 
 #include "options.h"
+#include "iptables.h"
 
 extern const struct fw3_option fw3_flag_opts[];
 
@@ -38,9 +39,9 @@ void fw3_print_default_tail_rules(struct fw3_state *state,
 
 void fw3_set_defaults(struct fw3_state *state);
 
-void fw3_flush_rules(struct fw3_state *state, enum fw3_family family,
-                     enum fw3_table table, bool reload, bool pass2);
+void fw3_flush_rules(struct fw3_ipt_handle *handle, struct fw3_state *state,
+                     bool reload);
 
-void fw3_flush_all(enum fw3_table table);
+void fw3_flush_all(struct fw3_ipt_handle *handle);
 
 #endif
diff --git a/iptables.c b/iptables.c
new file mode 100644 (file)
index 0000000..f5f4952
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * firewall3 - 3rd OpenWrt UCI firewall implementation
+ *
+ *   Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "iptables.h"
+
+
+struct fw3_ipt_handle *
+fw3_ipt_open(enum fw3_family family, enum fw3_table table)
+{
+       struct fw3_ipt_handle *h;
+
+       h = malloc(sizeof(*h));
+
+       if (!h)
+               return NULL;
+
+       if (family == FW3_FAMILY_V6)
+       {
+               h->family = FW3_FAMILY_V6;
+               h->table  = table;
+               h->handle = ip6tc_init(fw3_flag_names[table]);
+       }
+       else
+       {
+               h->family = FW3_FAMILY_V4;
+               h->table  = table;
+               h->handle = iptc_init(fw3_flag_names[table]);
+       }
+
+       if (!h->handle)
+       {
+               free(h);
+               return NULL;
+       }
+
+       return h;
+}
+
+void fw3_ipt_set_policy(struct fw3_ipt_handle *h, enum fw3_flag policy)
+{
+       if (h->table != FW3_TABLE_FILTER)
+               return;
+
+       if (h->family == FW3_FAMILY_V6)
+       {
+               ip6tc_set_policy("INPUT", fw3_flag_names[policy], NULL, h->handle);
+               ip6tc_set_policy("OUTPUT", fw3_flag_names[policy], NULL, h->handle);
+               ip6tc_set_policy("FORWARD", fw3_flag_names[policy], NULL, h->handle);
+       }
+       else
+       {
+               iptc_set_policy("INPUT", fw3_flag_names[policy], NULL, h->handle);
+               iptc_set_policy("OUTPUT", fw3_flag_names[policy], NULL, h->handle);
+               iptc_set_policy("FORWARD", fw3_flag_names[policy], NULL, h->handle);
+       }
+}
+
+void fw3_ipt_delete_chain(struct fw3_ipt_handle *h, const char *chain)
+{
+       if (h->family == FW3_FAMILY_V6)
+       {
+               if (ip6tc_flush_entries(chain, h->handle))
+                       ip6tc_delete_chain(chain, h->handle);
+       }
+       else
+       {
+               if (iptc_flush_entries(chain, h->handle))
+                       iptc_delete_chain(chain, h->handle);
+       }
+}
+
+void fw3_ipt_delete_rules(struct fw3_ipt_handle *h, const char *target)
+{
+       unsigned int num;
+       const struct ipt_entry *e;
+       const struct ip6t_entry *e6;
+       const char *chain;
+       const char *t;
+       bool found;
+
+       if (h->family == FW3_FAMILY_V6)
+       {
+               for (chain = ip6tc_first_chain(h->handle);
+                    chain != NULL;
+                    chain = ip6tc_next_chain(h->handle))
+               {
+                       do {
+                               found = false;
+
+                               for (num = 0, e6 = ip6tc_first_rule(chain, h->handle);
+                                        e6 != NULL;
+                                        num++, e6 = ip6tc_next_rule(e6, h->handle))
+                               {
+                                       t = ip6tc_get_target(e6, h->handle);
+
+                                       if (*t && !strcmp(t, target))
+                                       {
+                                               ip6tc_delete_num_entry(chain, num, h->handle);
+                                               found = true;
+                                               break;
+                                       }
+                               }
+                       } while (found);
+               }
+       }
+       else
+       {
+               for (chain = iptc_first_chain(h->handle);
+                    chain != NULL;
+                    chain = iptc_next_chain(h->handle))
+               {
+                       do {
+                               found = false;
+
+                               for (num = 0, e = iptc_first_rule(chain, h->handle);
+                                    e != NULL;
+                                        num++, e = iptc_next_rule(e, h->handle))
+                               {
+                                       t = iptc_get_target(e, h->handle);
+
+                                       if (*t && !strcmp(t, target))
+                                       {
+                                               iptc_delete_num_entry(chain, num, h->handle);
+                                               found = true;
+                                               break;
+                                       }
+                               }
+                       } while (found);
+               }
+       }
+}
+
+void fw3_ipt_flush(struct fw3_ipt_handle *h)
+{
+       const char *chain;
+
+       if (h->family == FW3_FAMILY_V6)
+       {
+               for (chain = ip6tc_first_chain(h->handle);
+                    chain != NULL;
+                    chain = ip6tc_next_chain(h->handle))
+               {
+                       ip6tc_flush_entries(chain, h->handle);
+               }
+
+               for (chain = ip6tc_first_chain(h->handle);
+                    chain != NULL;
+                    chain = ip6tc_next_chain(h->handle))
+               {
+                       ip6tc_delete_chain(chain, h->handle);
+               }
+       }
+       else
+       {
+               for (chain = iptc_first_chain(h->handle);
+                    chain != NULL;
+                    chain = iptc_next_chain(h->handle))
+               {
+                       iptc_flush_entries(chain, h->handle);
+               }
+
+               for (chain = iptc_first_chain(h->handle);
+                    chain != NULL;
+                    chain = iptc_next_chain(h->handle))
+               {
+                       iptc_delete_chain(chain, h->handle);
+               }
+       }
+}
+
+void fw3_ipt_commit(struct fw3_ipt_handle *h)
+{
+       if (h->family == FW3_FAMILY_V6)
+               ip6tc_commit(h->handle);
+       else
+               iptc_commit(h->handle);
+
+       free(h);
+}
diff --git a/iptables.h b/iptables.h
new file mode 100644 (file)
index 0000000..d809c1d
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * firewall3 - 3rd OpenWrt UCI firewall implementation
+ *
+ *   Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __FW3_IPTABLES_H
+#define __FW3_IPTABLES_H
+
+#include <libiptc/libiptc.h>
+#include <libiptc/libip6tc.h>
+
+#include "options.h"
+
+
+struct fw3_ipt_handle {
+       enum fw3_family family;
+       enum fw3_table table;
+       struct xtc_handle *handle;
+};
+
+struct fw3_ipt_handle *fw3_ipt_open(enum fw3_family family, enum fw3_table table);
+
+void fw3_ipt_set_policy(struct fw3_ipt_handle *h, enum fw3_flag policy);
+void fw3_ipt_delete_chain(struct fw3_ipt_handle *h, const char *chain);
+void fw3_ipt_delete_rules(struct fw3_ipt_handle *h, const char *target);
+void fw3_ipt_flush(struct fw3_ipt_handle *h);
+
+void fw3_ipt_commit(struct fw3_ipt_handle *h);
+
+#endif
diff --git a/main.c b/main.c
index a0c8a873fc84464f485b4071883b96f428e36da0..09de78260f1fdb78cd72ae741506cdc3d468e286 100644 (file)
--- a/main.c
+++ b/main.c
@@ -28,6 +28,7 @@
 #include "ipsets.h"
 #include "includes.h"
 #include "ubus.h"
+#include "iptables.h"
 
 
 static bool print_rules = false;
@@ -183,6 +184,7 @@ stop(bool complete)
        int rv = 1;
        enum fw3_family family;
        enum fw3_table table;
+       struct fw3_ipt_handle *handle;
 
        if (!complete && !run_state)
        {
@@ -200,38 +202,30 @@ stop(bool complete)
                if (!complete && !family_running(family))
                        continue;
 
-               if (!restore_pipe(family, true))
-                       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;
+
                        info(" * %sing %s %s table", complete ? "Flush" : "Clear",
                             fw3_flag_names[family], fw3_flag_names[table]);
 
-                       fw3_pr("*%s\n", fw3_flag_names[table]);
-
                        if (complete)
                        {
-                               fw3_flush_all(table);
+                               fw3_flush_all(handle);
                        }
                        else if (run_state)
                        {
-                               /* pass 1 */
-                               fw3_flush_rules(run_state, family, table, false, false);
-                               fw3_flush_zones(run_state, family, table, false, false);
-
-                               /* pass 2 */
-                               fw3_flush_rules(run_state, family, table, false, true);
-                               fw3_flush_zones(run_state, family, table, false, true);
+                               fw3_flush_rules(handle, run_state, false);
+                               fw3_flush_zones(handle, run_state, false);
                        }
 
-                       fw3_pr("COMMIT\n");
+                       fw3_ipt_commit(handle);
                }
 
-               fw3_command_close();
                family_set(run_state, family, false);
                family_set(cfg_state, family, false);
 
@@ -345,15 +339,13 @@ reload(void)
        int rv = 1;
        enum fw3_family family;
        enum fw3_table table;
+       struct fw3_ipt_handle *handle;
 
        if (!print_rules && run_state)
                fw3_hotplug_zones(run_state, false);
 
        for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++)
        {
-               if (!restore_pipe(family, true))
-                       continue;
-
                if (!family_running(family))
                        goto start;
 
@@ -362,29 +354,28 @@ reload(void)
                        if (!fw3_has_table(family == FW3_FAMILY_V6, fw3_flag_names[table]))
                                continue;
 
+                       if (!(handle = fw3_ipt_open(family, table)))
+                               continue;
+
                        info(" * Clearing %s %s table",
                             fw3_flag_names[family], fw3_flag_names[table]);
 
-                       fw3_pr("*%s\n", fw3_flag_names[table]);
-
                        if (run_state)
                        {
-                               /* pass 1 */
-                               fw3_flush_rules(run_state, family, table, true, false);
-                               fw3_flush_zones(run_state, family, table, true, false);
-
-                               /* pass 2 */
-                               fw3_flush_rules(run_state, family, table, true, true);
-                               fw3_flush_zones(run_state, family, table, true, true);
+                               fw3_flush_rules(handle, run_state, true);
+                               fw3_flush_zones(handle, run_state, true);
                        }
 
-                       fw3_pr("COMMIT\n");
+                       fw3_ipt_commit(handle);
                }
 
                family_set(run_state, family, false);
                family_set(cfg_state, family, false);
 
 start:
+               if (!restore_pipe(family, true))
+                       continue;
+
                if (family == FW3_FAMILY_V6 && cfg_state->defaults.disable_ipv6)
                        goto skip;
 
diff --git a/zones.c b/zones.c
index b0fcaee265f4bb40f143a2a5e185a9e88180e126..1fd785bb15972fd1bc2f3c58bdd8afcd0950f04f 100644 (file)
--- a/zones.c
+++ b/zones.c
@@ -501,26 +501,36 @@ fw3_print_zone_rules(struct fw3_state *state, enum fw3_family family,
 }
 
 void
-fw3_flush_zones(struct fw3_state *state, enum fw3_family family,
-                enum fw3_table table, bool reload, bool pass2)
+fw3_flush_zones(struct fw3_ipt_handle *handle, struct fw3_state *state,
+                bool reload)
 {
        struct fw3_zone *z, *tmp;
-       uint32_t custom_mask = ~0;
-
-       /* don't touch user chains on selective stop */
-       if (reload)
-               delbit(custom_mask, FW3_FLAG_CUSTOM_CHAINS);
+       const struct fw3_rule_spec *c;
+       char chain[32];
 
        list_for_each_entry_safe(z, tmp, &state->zones, list)
        {
-               if (!has(z->flags, family, table))
+               if (!has(z->flags, handle->family, handle->table))
                        continue;
 
-               fw3_pr_rulespec(table, family, z->flags, custom_mask, zone_chains,
-                               pass2 ? "-X %s\n" : "-F %s\n", z->name);
+               for (c = zone_chains; c->format; c++)
+               {
+                       /* don't touch user chains on selective stop */
+                       if (reload && hasbit(c->flag, FW3_FLAG_CUSTOM_CHAINS))
+                               continue;
+
+                       if (!fw3_is_family(c, handle->family))
+                               continue;
+
+                       if (c->table != handle->table)
+                               continue;
+
+                       snprintf(chain, sizeof(chain), c->format, z->name);
+                       fw3_ipt_delete_rules(handle, chain);
+                       fw3_ipt_delete_chain(handle, chain);
+               }
 
-               if (pass2)
-                       del(z->flags, family, table);
+               del(z->flags, handle->family, handle->table);
        }
 }
 
diff --git a/zones.h b/zones.h
index dd449a6fa5a39b5b20c655abfebf500691c40ef0..353f08926f7e9634ab23d8885bfd93e17c1e9f78 100644 (file)
--- a/zones.h
+++ b/zones.h
@@ -20,6 +20,7 @@
 #define __FW3_ZONES_H
 
 #include "options.h"
+#include "iptables.h"
 
 extern const struct fw3_option fw3_zone_opts[];
 
@@ -33,8 +34,8 @@ void fw3_print_zone_chains(struct fw3_state *state, enum fw3_family family,
 void fw3_print_zone_rules(struct fw3_state *state, enum fw3_family family,
                           enum fw3_table table, bool reload);
 
-void fw3_flush_zones(struct fw3_state *state, enum fw3_family family,
-                     enum fw3_table table, bool reload, bool pass2);
+void fw3_flush_zones(struct fw3_ipt_handle *handle, struct fw3_state *state,
+                     bool reload);
 
 void fw3_hotplug_zones(struct fw3_state *state, bool add);