firewall: Flush managed chains
authorDaniel Wagner <daniel.wagner@bmw-carit.de>
Tue, 19 Mar 2013 12:46:31 +0000 (13:46 +0100)
committerPatrik Flykt <patrik.flykt@linux.intel.com>
Mon, 25 Mar 2013 11:17:58 +0000 (13:17 +0200)
ConnMan maintains its own chain per builtin chain. The managed
chain have a prefix 'connman-' and one rule in the corresponding
builtin chain which jumps uncoditional to the managed chain.

In case ConnMan crashed we need to cleanup first.

src/firewall.c

index e8b7e20..47a5c9d 100644 (file)
 #include <config.h>
 #endif
 
+#include <xtables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
 #include "connman.h"
 
+#define CHAIN_PREFIX "connman-"
+
+static const char *builtin_chains[] = {
+       [NF_IP_PRE_ROUTING]     = "PREROUTING",
+       [NF_IP_LOCAL_IN]        = "INPUT",
+       [NF_IP_FORWARD]         = "FORWARD",
+       [NF_IP_LOCAL_OUT]       = "OUTPUT",
+       [NF_IP_POST_ROUTING]    = "POSTROUTING",
+};
+
+static int chain_to_index(const char *chain_name)
+{
+       if (!g_strcmp0(builtin_chains[NF_IP_PRE_ROUTING], chain_name))
+               return NF_IP_PRE_ROUTING;
+       if (!g_strcmp0(builtin_chains[NF_IP_LOCAL_IN], chain_name))
+               return NF_IP_LOCAL_IN;
+       if (!g_strcmp0(builtin_chains[NF_IP_FORWARD], chain_name))
+               return NF_IP_FORWARD;
+       if (!g_strcmp0(builtin_chains[NF_IP_LOCAL_OUT], chain_name))
+               return NF_IP_LOCAL_OUT;
+       if (!g_strcmp0(builtin_chains[NF_IP_POST_ROUTING], chain_name))
+               return NF_IP_POST_ROUTING;
+
+       return -1;
+}
+
+static int managed_chain_to_index(const char *chain_name)
+{
+       if (g_str_has_prefix(chain_name, CHAIN_PREFIX) == FALSE)
+               return -1;
+
+       return chain_to_index(chain_name + strlen(CHAIN_PREFIX));
+}
+
+static void iterate_chains_cb(const char *chain_name, void *user_data)
+{
+       GSList **chains = user_data;
+       int id;
+
+       id = managed_chain_to_index(chain_name);
+       if (id < 0)
+               return;
+
+       *chains = g_slist_prepend(*chains, GINT_TO_POINTER(id));
+}
+
+static void flush_table(const char *table_name)
+{
+       GSList *chains = NULL, *list;
+       char *rule, *managed_chain;
+       int id, err;
+
+       __connman_iptables_iterate_chains(table_name, iterate_chains_cb,
+                                               &chains);
+
+       for (list = chains; list != NULL; list = list->next) {
+               id = GPOINTER_TO_INT(list->data);
+
+               managed_chain = g_strdup_printf("%s%s", CHAIN_PREFIX,
+                                               builtin_chains[id]);
+
+               rule = g_strdup_printf("-j %s", managed_chain);
+               err = __connman_iptables_delete(table_name,
+                                               builtin_chains[id], rule);
+               if (err < 0) {
+                       connman_warn("Failed to delete jump rule '%s': %s",
+                               rule, strerror(-err));
+               }
+               g_free(rule);
+
+               err = __connman_iptables_flush_chain(table_name, managed_chain);
+               if (err < 0) {
+                       connman_warn("Failed to flush chain '%s': %s",
+                               managed_chain, strerror(-err));
+               }
+               err = __connman_iptables_delete_chain(table_name, managed_chain);
+               if (err < 0) {
+                       connman_warn("Failed to delete chain '%s': %s",
+                               managed_chain, strerror(-err));
+               }
+
+               g_free(managed_chain);
+       }
+
+       err = __connman_iptables_commit(table_name);
+       if (err < 0) {
+               connman_warn("Failed to flush table '%s': %s",
+                       table_name, strerror(-err));
+       }
+
+       g_slist_free(chains);
+}
+
+static void flush_all_tables(void)
+{
+       /* Flush the tables ConnMan might have modified */
+
+       flush_table("filter");
+       flush_table("mangle");
+       flush_table("nat");
+}
+
 int __connman_firewall_init(void)
 {
        DBG("");
 
+       flush_all_tables();
+
        return 0;
 }