diff options
Diffstat (limited to 'src/firewall.c')
-rw-r--r-- | src/firewall.c | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/src/firewall.c b/src/firewall.c index e8b7e207..47a5c9d9 100644 --- a/src/firewall.c +++ b/src/firewall.c @@ -23,12 +23,119 @@ #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; } |