Hi Wagi, On ma, 2015-07-27 at 14:47 +0200, Daniel Wagner wrote: > We like to add and remove rules while the filewall is up and running.
filewall -> firewall > 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; > +} __connman_firewall_remove_rule() and __connman_firewall_enable_rule() and __connman_firewall_disable_rule() are looking quite similar, perhaps some refactoring could be done here? > + > +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(); > Cheers, Jukka _______________________________________________ connman mailing list connman@connman.net https://lists.connman.net/mailman/listinfo/connman