summaryrefslogtreecommitdiff
path: root/src/firewall.c
diff options
context:
space:
mode:
authorDaniel Wagner <daniel.wagner@bmw-carit.de>2013-03-19 13:46:32 +0100
committerPatrik Flykt <patrik.flykt@linux.intel.com>2013-03-25 13:17:58 +0200
commit8d9d64c7f2deda60e668bd74c09dfd4b16cfa0d2 (patch)
treeadab483ab7708ee9dbb9f243d6fe3242f8006dbc /src/firewall.c
parenta6b73c60cf555ea6e02daca913f08bfa0b48b723 (diff)
downloadconnman-8d9d64c7f2deda60e668bd74c09dfd4b16cfa0d2.tar.gz
connman-8d9d64c7f2deda60e668bd74c09dfd4b16cfa0d2.tar.bz2
connman-8d9d64c7f2deda60e668bd74c09dfd4b16cfa0d2.zip
firewall: Add firewall API
The main idea behind this API is to collect several iptables rules together and enable or disable in one go. For this a context is created via __connman_firewall_create() and the rules added to this context via __connman_firewall_add_rule(). In order to append all rules __connman_firewall_enable() has to be called. To remove all rules associated with one context __connman_firewall_disable() has to be used. If something goes awry the code tries to get back to the initial state.
Diffstat (limited to 'src/firewall.c')
-rw-r--r--src/firewall.c128
1 files changed, 128 insertions, 0 deletions
diff --git a/src/firewall.c b/src/firewall.c
index 47a5c9d9..c44ddc12 100644
--- a/src/firewall.c
+++ b/src/firewall.c
@@ -38,6 +38,16 @@ static const char *builtin_chains[] = {
[NF_IP_POST_ROUTING] = "POSTROUTING",
};
+struct fw_rule {
+ char *table;
+ char *chain;
+ char *rule_spec;
+};
+
+struct firewall_context {
+ GList *rules;
+};
+
static int chain_to_index(const char *chain_name)
{
if (!g_strcmp0(builtin_chains[NF_IP_PRE_ROUTING], chain_name))
@@ -62,6 +72,124 @@ static int managed_chain_to_index(const char *chain_name)
return chain_to_index(chain_name + strlen(CHAIN_PREFIX));
}
+static void cleanup_fw_rule(gpointer user_data)
+{
+ struct fw_rule *rule = user_data;
+
+ g_free(rule->rule_spec);
+ g_free(rule->chain);
+ g_free(rule->table);
+ g_free(rule);
+}
+
+struct firewall_context *__connman_firewall_create(void)
+{
+ struct firewall_context *ctx;
+
+ ctx = g_new0(struct firewall_context, 1);
+
+ return ctx;
+}
+
+void __connman_firewall_destroy(struct firewall_context *ctx)
+{
+ g_list_free_full(ctx->rules, cleanup_fw_rule);
+ g_free(ctx);
+}
+
+int __connman_firewall_add_rule(struct firewall_context *ctx,
+ const char *table,
+ const char *chain,
+ const char *rule_fmt, ...)
+{
+ va_list args;
+ char *rule_spec;
+ struct fw_rule *rule;
+
+ va_start(args, rule_fmt);
+
+ rule_spec = g_strdup_vprintf(rule_fmt, args);
+
+ va_end(args);
+
+ rule = g_new0(struct fw_rule, 1);
+
+ rule->table = g_strdup(table);
+ rule->chain = g_strdup(chain);
+ rule->rule_spec = rule_spec;
+
+ ctx->rules = g_list_append(ctx->rules, rule);
+
+ return 0;
+}
+
+static int firewall_disable(GList *rules)
+{
+ struct fw_rule *rule;
+ GList *list;
+ int err;
+
+ for (list = rules; list != NULL; list = g_list_previous(list)) {
+ rule = list->data;
+
+ err = __connman_iptables_delete(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_enable(struct firewall_context *ctx)
+{
+ struct fw_rule *rule;
+ GList *list;
+ int err;
+
+ for (list = g_list_first(ctx->rules); list != NULL;
+ list = g_list_next(list)) {
+ rule = list->data;
+
+ DBG("%s %s %s", rule->table, rule->chain, rule->rule_spec);
+
+ err = __connman_iptables_append(rule->table,
+ rule->chain,
+ rule->rule_spec);
+ if (err < 0)
+ goto err;
+
+ err = __connman_iptables_commit(rule->table);
+ if (err < 0)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ connman_warn("Failed to install iptables rules: %s", strerror(-err));
+
+ firewall_disable(g_list_previous(list));
+
+ return err;
+}
+
+int __connman_firewall_disable(struct firewall_context *ctx)
+{
+ return firewall_disable(g_list_last(ctx->rules));
+}
+
static void iterate_chains_cb(const char *chain_name, void *user_data)
{
GSList **chains = user_data;