We like to add and remove rules while the filewall is up and running.
For example we need to insert per Session rule in the global
NAT table. That could also be implemented destroying the whole table
and recreate it when need but that is quite an overhead.

Instead of taking down the whole table down we add an API to
add and remove new rules during runtime.
---
 src/connman.h         |   3 ++
 src/firewall.c        | 112 +++++++++++++++++++++++++++++++++++++++-----------
 tools/iptables-unit.c |  39 +++++++++++++++---
 3 files changed, 126 insertions(+), 28 deletions(-)

diff --git a/src/connman.h b/src/connman.h
index 29151af..654b8fa 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -989,6 +989,9 @@ int __connman_firewall_add_rule(struct firewall_context 
*ctx,
                                const char *table,
                                const char *chain,
                                const char *rule_fmt, ...);
+int __connman_firewall_remove_rule(struct firewall_context *ctx, int id);
+int __connman_firewall_enable_rule(struct firewall_context *ctx, int id);
+int __connman_firewall_disable_rule(struct firewall_context *ctx, int id);
 int __connman_firewall_enable(struct firewall_context *ctx);
 int __connman_firewall_disable(struct firewall_context *ctx);
 bool __connman_firewall_is_up(void);
diff --git a/src/firewall.c b/src/firewall.c
index 90c3d3c..c25d086 100644
--- a/src/firewall.c
+++ b/src/firewall.c
@@ -46,6 +46,7 @@ struct connman_managed_table {
 };
 
 struct fw_rule {
+       int id;
        char *table;
        char *chain;
        char *rule_spec;
@@ -58,6 +59,7 @@ struct firewall_context {
 static GSList *managed_tables;
 
 static bool firewall_is_up;
+static unsigned int firewall_rule_id;
 
 static int chain_to_index(const char *chain_name)
 {
@@ -284,38 +286,109 @@ int __connman_firewall_add_rule(struct firewall_context 
*ctx,
 
        rule = g_new0(struct fw_rule, 1);
 
+       rule->id = firewall_rule_id++;
        rule->table = g_strdup(table);
        rule->chain = g_strdup(chain);
        rule->rule_spec = rule_spec;
 
        ctx->rules = g_list_append(ctx->rules, rule);
+       return rule->id;
+}
+
+static int firewall_enable_rule(struct fw_rule *rule)
+{
+       int err;
+
+       DBG("%s %s %s", rule->table, rule->chain, rule->rule_spec);
+
+       err = insert_managed_rule(rule->table, rule->chain, rule->rule_spec);
+       if (err < 0)
+               return err;
+
+       return  __connman_iptables_commit(rule->table);
+}
+
+static int firewall_disable_rule(struct fw_rule *rule)
+{
+       int err;
+
+       err = delete_managed_rule(rule->table, rule->chain, rule->rule_spec);
+       if (err < 0) {
+               connman_error("Cannot remove previously installed "
+                       "iptables rules: %s", strerror(-err));
+               return err;
+       }
+
+       err = __connman_iptables_commit(rule->table);
+       if (err < 0) {
+               connman_error("Cannot remove previously installed "
+                       "iptables rules: %s", strerror(-err));
+               return err;
+       }
 
        return 0;
 }
 
+
+int __connman_firewall_remove_rule(struct firewall_context *ctx, int id)
+{
+       struct fw_rule *rule;
+       GList *list;
+
+       for (list = ctx->rules; list; list = list->next) {
+               rule = list->data;
+               if (rule->id != id)
+                       continue;
+
+               ctx->rules = g_list_remove(ctx->rules, rule);
+               cleanup_fw_rule(rule);
+               return 0;
+       }
+
+       return -ENOENT;
+}
+
+int __connman_firewall_enable_rule(struct firewall_context *ctx, int id)
+{
+       struct fw_rule *rule;
+       GList *list;
+
+       for (list = ctx->rules; list; list = list->next) {
+               rule = list->data;
+               if (rule->id != id)
+                       continue;
+
+               return firewall_enable_rule(rule);
+       }
+
+       return -ENOENT;
+}
+
+int __connman_firewall_disable_rule(struct firewall_context *ctx, int id)
+{
+       struct fw_rule *rule;
+       GList *list;
+
+       for (list = ctx->rules; list; list = list->next) {
+               rule = list->data;
+               if (rule->id != id)
+                       continue;
+
+               return firewall_disable_rule(rule);
+       }
+
+       return -ENOENT;
+}
+
 static int firewall_disable(GList *rules)
 {
        struct fw_rule *rule;
        GList *list;
-       int err;
 
        for (list = rules; list; list = g_list_previous(list)) {
                rule = list->data;
 
-               err = delete_managed_rule(rule->table,
-                                               rule->chain, rule->rule_spec);
-               if (err < 0) {
-                       connman_error("Cannot remove previously installed "
-                               "iptables rules: %s", strerror(-err));
-                       return err;
-               }
-
-               err = __connman_iptables_commit(rule->table);
-               if (err < 0) {
-                       connman_error("Cannot remove previously installed "
-                               "iptables rules: %s", strerror(-err));
-                       return err;
-               }
+               return firewall_disable_rule(rule);
        }
 
        return 0;
@@ -331,14 +404,7 @@ int __connman_firewall_enable(struct firewall_context *ctx)
                        list = g_list_next(list)) {
                rule = list->data;
 
-               DBG("%s %s %s", rule->table, rule->chain, rule->rule_spec);
-
-               err = insert_managed_rule(rule->table,
-                                               rule->chain, rule->rule_spec);
-               if (err < 0)
-                       goto err;
-
-               err = __connman_iptables_commit(rule->table);
+               err = firewall_enable_rule(rule);
                if (err < 0)
                        goto err;
        }
diff --git a/tools/iptables-unit.c b/tools/iptables-unit.c
index 7e427e2..58f53ae 100644
--- a/tools/iptables-unit.c
+++ b/tools/iptables-unit.c
@@ -24,6 +24,7 @@
 #endif
 
 #include <glib.h>
+#include <errno.h>
 
 #include "../src/connman.h"
 
@@ -412,7 +413,7 @@ static void test_firewall_basic0(void)
 
        err = __connman_firewall_add_rule(ctx, "filter", "INPUT",
                                        "-m mark --mark 999 -j LOG");
-       g_assert(err == 0);
+       g_assert(err >= 0);
 
        err = __connman_firewall_enable(ctx);
        g_assert(err == 0);
@@ -441,11 +442,11 @@ static void test_firewall_basic1(void)
 
        err = __connman_firewall_add_rule(ctx, "filter", "INPUT",
                                        "-m mark --mark 999 -j LOG");
-       g_assert(err == 0);
+       g_assert(err >= 0);
 
        err = __connman_firewall_add_rule(ctx, "filter", "OUTPUT",
                                        "-m mark --mark 999 -j LOG");
-       g_assert(err == 0);
+       g_assert(err >= 0);
 
        err = __connman_firewall_enable(ctx);
        g_assert(err == 0);
@@ -466,11 +467,11 @@ static void test_firewall_basic2(void)
 
        err = __connman_firewall_add_rule(ctx, "mangle", "INPUT",
                                        "-j CONNMARK --restore-mark");
-       g_assert(err == 0);
+       g_assert(err >= 0);
 
        err = __connman_firewall_add_rule(ctx, "mangle", "POSTROUTING",
                                        "-j CONNMARK --save-mark");
-       g_assert(err == 0);
+       g_assert(err >= 0);
 
        err = __connman_firewall_enable(ctx);
        g_assert(err == 0);
@@ -481,6 +482,33 @@ static void test_firewall_basic2(void)
        __connman_firewall_destroy(ctx);
 }
 
+static void test_firewall_basic3(void)
+{
+       struct firewall_context *ctx;
+       int err, id;
+
+       ctx = __connman_firewall_create();
+       g_assert(ctx);
+
+       id = __connman_firewall_add_rule(ctx, "mangle", "INPUT",
+                                       "-j CONNMARK --restore-mark");
+       g_assert(id >= 0);
+
+       err = __connman_firewall_enable_rule(ctx, id);
+       g_assert(err == 0);
+
+       err = __connman_firewall_disable_rule(ctx, id);
+       g_assert(err == 0);
+
+       err = __connman_firewall_remove_rule(ctx, id);
+       g_assert(err == 0);
+
+       err = __connman_firewall_disable(ctx);
+       g_assert(err == 0);
+
+       __connman_firewall_destroy(ctx);
+}
+
 static gchar *option_debug = NULL;
 
 static bool parse_debug(const char *key, const char *value,
@@ -543,6 +571,7 @@ int main(int argc, char *argv[])
        g_test_add_func("/firewall/basic0", test_firewall_basic0);
        g_test_add_func("/firewall/basic1", test_firewall_basic1);
        g_test_add_func("/firewall/basic2", test_firewall_basic2);
+       g_test_add_func("/firewall/basic3", test_firewall_basic3);
 
        err = g_test_run();
 
-- 
2.4.3

_______________________________________________
connman mailing list
connman@connman.net
https://lists.connman.net/mailman/listinfo/connman

Reply via email to