Drop iptables-restore and create rules through libiptc and libxtables
authorJo-Philipp Wich <jow@openwrt.org>
Tue, 14 May 2013 22:04:33 +0000 (00:04 +0200)
committerJo-Philipp Wich <jow@openwrt.org>
Fri, 17 May 2013 12:36:29 +0000 (14:36 +0200)
18 files changed:
CMakeLists.txt
defaults.c
defaults.h
forwards.c
forwards.h
iptables.c
iptables.h
main.c
options.c
options.h
redirects.c
redirects.h
rules.c
rules.h
utils.c
utils.h
zones.c
zones.h

index 50b1c3f43ba6d806ffdc137879963ef99460eb06..e5d2dc3ebb65bdf1449f96d7cb8ce27339dac9d3 100644 (file)
@@ -11,7 +11,7 @@ IF(APPLE)
 ENDIF()
 
 ADD_EXECUTABLE(firewall3 main.c options.c defaults.c zones.c forwards.c rules.c redirects.c utils.c ubus.c ipsets.c includes.c iptables.c)
-TARGET_LINK_LIBRARIES(firewall3 uci ubox ubus ip4tc ip6tc)
+TARGET_LINK_LIBRARIES(firewall3 uci ubox ubus ip4tc ip6tc xtables m ${CMAKE_SOURCE_DIR}/libext.a ${CMAKE_SOURCE_DIR}/libext4.a ${CMAKE_SOURCE_DIR}/libext6.a)
 
 SET(CMAKE_INSTALL_PREFIX /usr)
 
index 20c57d6ad81c0996fbf5472ad3f210aa86d96725..3ed6cfaad9b62615149f1b441e7c19d8e115dd88 100644 (file)
@@ -45,22 +45,6 @@ static const struct fw3_rule_spec default_chains[] = {
        { }
 };
 
-static const struct fw3_rule_spec toplevel_rules[] = {
-       C(ANY, FILTER, UNSPEC,        "INPUT -j delegate_input"),
-       C(ANY, FILTER, UNSPEC,        "OUTPUT -j delegate_output"),
-       C(ANY, FILTER, UNSPEC,        "FORWARD -j delegate_forward"),
-
-       C(V4,  NAT,    UNSPEC,        "PREROUTING -j delegate_prerouting"),
-       C(V4,  NAT,    UNSPEC,        "POSTROUTING -j delegate_postrouting"),
-
-       C(ANY, MANGLE, UNSPEC,        "FORWARD -j mssfix"),
-       C(ANY, MANGLE, UNSPEC,        "PREROUTING -j fwmark"),
-
-       C(ANY, RAW,    UNSPEC,        "PREROUTING -j notrack"),
-
-       { }
-};
-
 const struct fw3_option fw3_flag_opts[] = {
        FW3_OPT("input",               target,   defaults, policy_input),
        FW3_OPT("forward",             target,   defaults, policy_forward),
@@ -142,110 +126,186 @@ fw3_load_defaults(struct fw3_state *state, struct uci_package *p)
 }
 
 void
-fw3_print_default_chains(struct fw3_state *state, enum fw3_family family,
-                         enum fw3_table table, bool reload)
+fw3_print_default_chains(struct fw3_ipt_handle *handle, struct fw3_state *state,
+                         bool reload)
 {
-       bool rv;
        struct fw3_defaults *defs = &state->defaults;
-       uint32_t custom_mask = ~0;
+       const struct fw3_rule_spec *c;
 
 #define policy(t) \
-       ((t == FW3_FLAG_REJECT) ? "DROP" : fw3_flag_names[t])
+       ((t == FW3_FLAG_REJECT) ? FW3_FLAG_DROP : t)
 
-       if (family == FW3_FAMILY_V6 && defs->disable_ipv6)
+       if (handle->family == FW3_FAMILY_V6 && defs->disable_ipv6)
                return;
 
-       if (table == FW3_TABLE_FILTER)
+       if (handle->table == FW3_TABLE_FILTER)
        {
-               fw3_pr(":INPUT %s [0:0]\n", policy(defs->policy_input));
-               fw3_pr(":FORWARD %s [0:0]\n", policy(defs->policy_forward));
-               fw3_pr(":OUTPUT %s [0:0]\n", policy(defs->policy_output));
+               fw3_ipt_set_policy(handle, "INPUT",   policy(defs->policy_input));
+               fw3_ipt_set_policy(handle, "OUTPUT",  policy(defs->policy_output));
+               fw3_ipt_set_policy(handle, "FORWARD", policy(defs->policy_forward));
        }
 
-       /* Don't touch user chains on reload */
-       if (reload)
-               delbit(custom_mask, FW3_FLAG_CUSTOM_CHAINS);
-
        if (defs->custom_chains)
-               set(defs->flags, family, FW3_FLAG_CUSTOM_CHAINS);
+               set(defs->flags, handle->family, FW3_FLAG_CUSTOM_CHAINS);
 
        if (defs->syn_flood)
-               set(defs->flags, family, FW3_FLAG_SYN_FLOOD);
+               set(defs->flags, handle->family, FW3_FLAG_SYN_FLOOD);
+
+       for (c = default_chains; c->format; c++)
+       {
+               /* don't touch user chains on selective stop */
+               if (reload && c->flag == FW3_FLAG_CUSTOM_CHAINS)
+                       continue;
+
+               if (!fw3_is_family(c, handle->family))
+                       continue;
+
+               if (c->table != handle->table)
+                       continue;
 
-       rv = fw3_pr_rulespec(table, family, defs->flags, custom_mask,
-                            default_chains, ":%s - [0:0]\n");
+               if (c->flag &&
+                   !hasbit(defs->flags[handle->family == FW3_FAMILY_V6], c->flag))
+                       continue;
+
+               fw3_ipt_create_chain(handle, c->format);
+       }
 
-       if (rv)
-               set(defs->flags, family, table);
+       set(defs->flags, handle->family, handle->table);
 }
 
+
+struct toplevel_rule {
+       enum fw3_table table;
+       const char *chain;
+       const char *target;
+};
+
 void
-fw3_print_default_head_rules(struct fw3_state *state, enum fw3_family family,
-                             enum fw3_table table, bool reload)
+fw3_print_default_head_rules(struct fw3_ipt_handle *handle,
+                             struct fw3_state *state, bool reload)
 {
        int i;
        struct fw3_defaults *defs = &state->defaults;
+       struct fw3_device lodev = { .set = true };
+       struct fw3_protocol tcp = { .protocol = 6 };
+       struct fw3_ipt_rule *r;
+       struct toplevel_rule *tr;
+
        const char *chains[] = {
-               "input", "input",
-               "output", "output",
-               "forward", "forwarding",
+               "delegate_input", "input",
+               "delegate_output", "output",
+               "delegate_forward", "forwarding",
        };
 
-       fw3_pr_rulespec(table, family, NULL, 0, toplevel_rules, "-A %s\n");
+       struct toplevel_rule rules[] = {
+               { FW3_TABLE_FILTER, "INPUT",       "delegate_input" },
+               { FW3_TABLE_FILTER, "OUTPUT",      "delegate_output" },
+               { FW3_TABLE_FILTER, "FORWARD",     "delegate_forward" },
+
+               { FW3_TABLE_NAT,    "PREROUTING",  "delegate_prerouting" },
+               { FW3_TABLE_NAT,    "POSTROUTING", "delegate_postrouting" },
+
+               { FW3_TABLE_MANGLE, "FORWARD",     "mssfix" },
+               { FW3_TABLE_MANGLE, "PREROUTING",  "fwmark" },
+
+               { FW3_TABLE_RAW,    "PREROUTING",  "notrack" },
+
+               { 0, NULL },
+       };
 
-       switch (table)
+       for (tr = rules; tr->chain; tr++)
+       {
+               if (tr->table != handle->table)
+                       continue;
+
+               r = fw3_ipt_rule_new(handle);
+               fw3_ipt_rule_target(r, tr->target);
+               fw3_ipt_rule_append(r, tr->chain);
+       }
+
+       switch (handle->table)
        {
        case FW3_TABLE_FILTER:
-               fw3_pr("-A delegate_input -i lo -j ACCEPT\n");
-               fw3_pr("-A delegate_output -o lo -j ACCEPT\n");
+
+               sprintf(lodev.name, "lo");
+
+               r = fw3_ipt_rule_create(handle, NULL, &lodev, NULL, NULL, NULL);
+               fw3_ipt_rule_target(r, "ACCEPT");
+               fw3_ipt_rule_append(r, "delegate_input");
+
+               r = fw3_ipt_rule_create(handle, NULL, NULL, &lodev, NULL, NULL);
+               fw3_ipt_rule_target(r, "ACCEPT");
+               fw3_ipt_rule_append(r, "delegate_output");
 
                if (defs->custom_chains)
                {
                        for (i = 0; i < ARRAY_SIZE(chains); i += 2)
                        {
-                               fw3_pr("-A delegate_%s -m comment "
-                                      "--comment \"user chain for %s\" -j %s_rule\n",
-                                          chains[i], chains[i+1], chains[i+1]);
+                               r = fw3_ipt_rule_new(handle);
+                               fw3_ipt_rule_comment(r, "user chain for %s", chains[i+1]);
+                               fw3_ipt_rule_target(r, chains[i+1]);
+                               fw3_ipt_rule_append(r, chains[i]);
                        }
                }
 
                for (i = 0; i < ARRAY_SIZE(chains); i += 2)
                {
-                       fw3_pr("-A delegate_%s -m conntrack --ctstate RELATED,ESTABLISHED "
-                              "-j ACCEPT\n", chains[i]);
+                       r = fw3_ipt_rule_new(handle);
+                       fw3_ipt_rule_extra(r, "-m conntrack --ctstate RELATED,ESTABLISHED");
+                       fw3_ipt_rule_target(r, "ACCEPT");
+                       fw3_ipt_rule_append(r, chains[i]);
 
                        if (defs->drop_invalid)
                        {
-                               fw3_pr("-A delegate_%s -m conntrack --ctstate INVALID -j DROP\n",
-                                      chains[i]);
+                               r = fw3_ipt_rule_new(handle);
+                               fw3_ipt_rule_extra(r, "-m conntrack --ctstate INVALID");
+                               fw3_ipt_rule_target(r, "DROP");
+                               fw3_ipt_rule_append(r, chains[i]);
                        }
                }
 
                if (defs->syn_flood)
                {
-                       fw3_pr("-A syn_flood -p tcp --syn");
-                       fw3_format_limit(&defs->syn_flood_rate);
-                       fw3_pr(" -j RETURN\n");
-
-                       fw3_pr("-A syn_flood -j DROP\n");
-                       fw3_pr("-A delegate_input -p tcp --syn -j syn_flood\n");
+                       r = fw3_ipt_rule_create(handle, &tcp, NULL, NULL, NULL, NULL);
+                       fw3_ipt_rule_extra(r, "--syn");
+                       fw3_ipt_rule_limit(r, &defs->syn_flood_rate);
+                       fw3_ipt_rule_target(r, "RETURN");
+                       fw3_ipt_rule_append(r, "syn_flood");
+
+                       r = fw3_ipt_rule_new(handle);
+                       fw3_ipt_rule_target(r, "DROP");
+                       fw3_ipt_rule_append(r, "syn_flood");
+
+                       r = fw3_ipt_rule_create(handle, &tcp, NULL, NULL, NULL, NULL);
+                       fw3_ipt_rule_extra(r, "--syn");
+                       fw3_ipt_rule_target(r, "syn_flood");
+                       fw3_ipt_rule_append(r, "delegate_input");
                }
 
-               fw3_pr("-A reject -p tcp -j REJECT --reject-with tcp-reset\n");
-               fw3_pr("-A reject -j REJECT --reject-with port-unreach\n");
+               r = fw3_ipt_rule_create(handle, &tcp, NULL, NULL, NULL, NULL);
+               fw3_ipt_rule_target(r, "REJECT");
+               fw3_ipt_rule_addarg(r, false, "--reject-with", "tcp-reset");
+               fw3_ipt_rule_append(r, "reject");
+
+               r = fw3_ipt_rule_new(handle);
+               fw3_ipt_rule_target(r, "REJECT");
+               fw3_ipt_rule_addarg(r, false, "--reject-with", "port-unreach");
+               fw3_ipt_rule_append(r, "reject");
 
                break;
 
        case FW3_TABLE_NAT:
                if (defs->custom_chains)
                {
-                       fw3_pr("-A delegate_prerouting "
-                              "-m comment --comment \"user chain for prerouting\" "
-                              "-j prerouting_rule\n");
-
-                       fw3_pr("-A delegate_postrouting "
-                              "-m comment --comment \"user chain for postrouting\" "
-                              "-j postrouting_rule\n");
+                       r = fw3_ipt_rule_new(handle);
+                       fw3_ipt_rule_comment(r, "user chain for prerouting");
+                       fw3_ipt_rule_target(r, "prerouting_rule");
+                       fw3_ipt_rule_append(r, "delegate_prerouting");
+
+                       r = fw3_ipt_rule_new(handle);
+                       fw3_ipt_rule_comment(r, "user chain for postrouting");
+                       fw3_ipt_rule_target(r, "postrouting_rule");
+                       fw3_ipt_rule_append(r, "delegate_postrouting");
                }
                break;
 
@@ -255,22 +315,47 @@ fw3_print_default_head_rules(struct fw3_state *state, enum fw3_family family,
 }
 
 void
-fw3_print_default_tail_rules(struct fw3_state *state, enum fw3_family family,
-                             enum fw3_table table, bool reload)
+fw3_print_default_tail_rules(struct fw3_ipt_handle *handle,
+                             struct fw3_state *state, bool reload)
 {
        struct fw3_defaults *defs = &state->defaults;
+       struct fw3_ipt_rule *r;
 
-       if (table != FW3_TABLE_FILTER)
+       if (handle->table != FW3_TABLE_FILTER)
                return;
 
        if (defs->policy_input == FW3_FLAG_REJECT)
-               fw3_pr("-A delegate_input -j reject\n");
+       {
+               r = fw3_ipt_rule_new(handle);
+
+               if (!r)
+                       return;
+
+               fw3_ipt_rule_target(r, "reject");
+               fw3_ipt_rule_append(r, "delegate_input");
+       }
 
        if (defs->policy_output == FW3_FLAG_REJECT)
-               fw3_pr("-A delegate_output -j reject\n");
+       {
+               r = fw3_ipt_rule_new(handle);
+
+               if (!r)
+                       return;
+
+               fw3_ipt_rule_target(r, "reject");
+               fw3_ipt_rule_append(r, "delegate_output");
+       }
 
        if (defs->policy_forward == FW3_FLAG_REJECT)
-               fw3_pr("-A delegate_forward -j reject\n");
+       {
+               r = fw3_ipt_rule_new(handle);
+
+               if (!r)
+                       return;
+
+               fw3_ipt_rule_target(r, "reject");
+               fw3_ipt_rule_append(r, "delegate_forward");
+       }
 }
 
 static void
@@ -305,16 +390,24 @@ void
 fw3_flush_rules(struct fw3_ipt_handle *handle, struct fw3_state *state,
                 bool reload)
 {
+       enum fw3_flag policy = reload ? FW3_FLAG_DROP : FW3_FLAG_ACCEPT;
        struct fw3_defaults *defs = &state->defaults;
        const struct fw3_rule_spec *c;
 
        if (!has(defs->flags, handle->family, handle->table))
                return;
 
+       if (handle->table == FW3_TABLE_FILTER)
+       {
+               fw3_ipt_set_policy(handle, "INPUT",   policy);
+               fw3_ipt_set_policy(handle, "OUTPUT",  policy);
+               fw3_ipt_set_policy(handle, "FORWARD", policy);
+       }
+
        for (c = default_chains; c->format; c++)
        {
                /* don't touch user chains on selective stop */
-               if (reload && hasbit(c->flag, FW3_FLAG_CUSTOM_CHAINS))
+               if (reload && c->flag == FW3_FLAG_CUSTOM_CHAINS)
                        continue;
 
                if (!fw3_is_family(c, handle->family))
@@ -323,7 +416,10 @@ fw3_flush_rules(struct fw3_ipt_handle *handle, struct fw3_state *state,
                if (c->table != handle->table)
                        continue;
 
-               fw3_ipt_set_policy(handle, reload ? FW3_FLAG_DROP : FW3_FLAG_ACCEPT);
+               if (c->flag &&
+                   !hasbit(defs->flags[handle->family == FW3_FAMILY_V6], c->flag))
+                       continue;
+
                fw3_ipt_delete_rules(handle, c->format);
                fw3_ipt_delete_chain(handle, c->format);
        }
@@ -334,6 +430,12 @@ fw3_flush_rules(struct fw3_ipt_handle *handle, struct fw3_state *state,
 void
 fw3_flush_all(struct fw3_ipt_handle *handle)
 {
-       fw3_ipt_set_policy(handle, FW3_FLAG_ACCEPT);
+       if (handle->table == FW3_TABLE_FILTER)
+       {
+               fw3_ipt_set_policy(handle, "INPUT",   FW3_FLAG_ACCEPT);
+               fw3_ipt_set_policy(handle, "OUTPUT",  FW3_FLAG_ACCEPT);
+               fw3_ipt_set_policy(handle, "FORWARD", FW3_FLAG_ACCEPT);
+       }
+
        fw3_ipt_flush(handle);
 }
index a89a36e5c700c2d9186c964c553f5d2398d3f9ae..649e32913068dc3536a0548237dfcd7d099251b5 100644 (file)
@@ -26,16 +26,14 @@ extern const struct fw3_option fw3_flag_opts[];
 
 void fw3_load_defaults(struct fw3_state *state, struct uci_package *p);
 
-void fw3_print_default_chains(struct fw3_state *state, enum fw3_family family,
-                              enum fw3_table table, bool reload);
+void fw3_print_default_chains(struct fw3_ipt_handle *handle,
+                              struct fw3_state *state, bool reload);
 
-void fw3_print_default_head_rules(struct fw3_state *state,
-                                  enum fw3_family family, enum fw3_table table,
-                                  bool reload);
+void fw3_print_default_head_rules(struct fw3_ipt_handle *handle,
+                                  struct fw3_state *state, bool reload);
 
-void fw3_print_default_tail_rules(struct fw3_state *state,
-                                  enum fw3_family family, enum fw3_table table,
-                                  bool reload);
+void fw3_print_default_tail_rules(struct fw3_ipt_handle *handle,
+                                  struct fw3_state *state, bool reload);
 
 void fw3_set_defaults(struct fw3_state *state);
 
index 6ea0497698a3a84349668fe375fadb882a8d5251..c7e7ba1874fb2fe2cc51a8682d4fd8c51027f4e5 100644 (file)
@@ -106,32 +106,32 @@ fw3_load_forwards(struct fw3_state *state, struct uci_package *p)
 
 
 static void
-print_chain(struct fw3_forward *forward)
+append_chain(struct fw3_ipt_rule *r, struct fw3_forward *forward)
 {
        if (forward->src.any || !forward->src.set)
-               fw3_pr("-A delegate_forward");
+               fw3_ipt_rule_append(r, "delegate_forward");
        else
-               fw3_pr("-A zone_%s_forward", forward->src.name);
+               fw3_ipt_rule_append(r, "zone_%s_forward", forward->src.name);
 }
 
-static void print_target(struct fw3_forward *forward)
+static void set_target(struct fw3_ipt_rule *r, struct fw3_forward *forward)
 {
        if (forward->dest.any || !forward->dest.set)
-               fw3_pr(" -j ACCEPT\n");
+               fw3_ipt_rule_target(r, "ACCEPT");
        else
-               fw3_pr(" -j zone_%s_dest_ACCEPT\n", forward->dest.name);
+               fw3_ipt_rule_target(r, "zone_%s_dest_ACCEPT", forward->dest.name);
 }
 
 static void
-print_forward(struct fw3_forward *forward, enum fw3_family family,
-              enum fw3_table table)
+print_forward(struct fw3_ipt_handle *handle, struct fw3_forward *forward)
 {
        const char *s, *d;
+       struct fw3_ipt_rule *r;
 
-       if (table != FW3_TABLE_FILTER)
+       if (handle->table != FW3_TABLE_FILTER)
                return;
 
-       if (!fw3_is_family(forward, family))
+       if (!fw3_is_family(forward, handle->family))
                return;
 
        s = forward->_src  ? forward->_src->name  : "*";
@@ -139,24 +139,24 @@ print_forward(struct fw3_forward *forward, enum fw3_family family,
 
        info("   * Forward '%s' -> '%s'", s, d);
 
-       if (!fw3_is_family(forward->_src, family) ||
-           !fw3_is_family(forward->_dest, family))
+       if (!fw3_is_family(forward->_src, handle->family) ||
+           !fw3_is_family(forward->_dest, handle->family))
        {
                info("     ! Skipping due to different family of zone");
                return;
        }
 
-       print_chain(forward);
-       fw3_format_comment("forwarding ", s, "->", d);
-       print_target(forward);
+       r = fw3_ipt_rule_new(handle);
+       fw3_ipt_rule_comment(r, "forwarding %s -> %s", s, d);
+       set_target(r, forward);
+       append_chain(r, forward);
 }
 
 void
-fw3_print_forwards(struct fw3_state *state, enum fw3_family family,
-                   enum fw3_table table)
+fw3_print_forwards(struct fw3_ipt_handle *handle, struct fw3_state *state)
 {
        struct fw3_forward *forward;
 
        list_for_each_entry(forward, &state->forwards, list)
-               print_forward(forward, family, table);
+               print_forward(handle, forward);
 }
index b8784bcfafd22080fc8cc26514699b9dd48c3f96..d299718a04e852a8d0b79821a71c36cf4c21de8b 100644 (file)
 #include "options.h"
 #include "zones.h"
 #include "utils.h"
+#include "iptables.h"
 
 extern const struct fw3_option fw3_forward_opts[];
 
 void fw3_load_forwards(struct fw3_state *state, struct uci_package *p);
-void fw3_print_forwards(struct fw3_state *state, enum fw3_family family,
-                        enum fw3_table table);
+void fw3_print_forwards(struct fw3_ipt_handle *handle, struct fw3_state *state);
 
 #define fw3_free_forward(forward) \
        fw3_free_object(forward, fw3_forward_opts)
index f5f4952bf129817bab48fa3fe72254be35bbe317..9c5f80a067b1e92d1b0a80e5ff5657cbae84153b 100644 (file)
 #include "iptables.h"
 
 
+static struct option base_opts[] = {
+       { .name = "match",  .has_arg = 1, .val = 'm' },
+       { .name = "jump",   .has_arg = 1, .val = 'j' },
+       { .name = "append", .has_arg = 1, .val = 'A' },
+       { NULL }
+};
+
+static struct xtables_globals xtg = {
+       .option_offset = 0,
+       .program_version = "4",
+       .orig_opts = base_opts,
+};
+
+static struct xtables_globals xtg6 = {
+       .option_offset = 0,
+       .program_version = "6",
+       .orig_opts = base_opts,
+};
+
+/* Required by certain extensions like SNAT and DNAT */
+int kernel_version;
+
+void
+get_kernel_version(void)
+{
+       static struct utsname uts;
+       int x = 0, y = 0, z = 0;
+
+       if (uname(&uts) == -1)
+               sprintf(uts.release, "3.0.0");
+
+       sscanf(uts.release, "%d.%d.%d", &x, &y, &z);
+       kernel_version = LINUX_VERSION(x, y, z);
+}
+
 struct fw3_ipt_handle *
 fw3_ipt_open(enum fw3_family family, enum fw3_table table)
 {
        struct fw3_ipt_handle *h;
 
-       h = malloc(sizeof(*h));
+       h = fw3_alloc(sizeof(*h));
 
-       if (!h)
-               return NULL;
+       xtables_init();
 
        if (family == FW3_FAMILY_V6)
        {
                h->family = FW3_FAMILY_V6;
                h->table  = table;
                h->handle = ip6tc_init(fw3_flag_names[table]);
+
+               xtables_set_params(&xtg6);
+               xtables_set_nfproto(NFPROTO_IPV6);
        }
        else
        {
                h->family = FW3_FAMILY_V4;
                h->table  = table;
                h->handle = iptc_init(fw3_flag_names[table]);
+
+               xtables_set_params(&xtg);
+               xtables_set_nfproto(NFPROTO_IPV4);
        }
 
        if (!h->handle)
@@ -48,30 +88,38 @@ fw3_ipt_open(enum fw3_family family, enum fw3_table table)
                return NULL;
        }
 
+       xtables_pending_matches = NULL;
+       xtables_pending_targets = NULL;
+
+       xtables_matches = NULL;
+       xtables_targets = NULL;
+
+       init_extensions();
+       init_extensions4();
+       init_extensions6();
+
        return h;
 }
 
-void fw3_ipt_set_policy(struct fw3_ipt_handle *h, enum fw3_flag policy)
+void
+fw3_ipt_set_policy(struct fw3_ipt_handle *h, const char *chain,
+                   enum fw3_flag policy)
 {
-       if (h->table != FW3_TABLE_FILTER)
-               return;
-
        if (h->family == FW3_FAMILY_V6)
-       {
-               ip6tc_set_policy("INPUT", fw3_flag_names[policy], NULL, h->handle);
-               ip6tc_set_policy("OUTPUT", fw3_flag_names[policy], NULL, h->handle);
-               ip6tc_set_policy("FORWARD", fw3_flag_names[policy], NULL, h->handle);
-       }
+               ip6tc_set_policy(chain, fw3_flag_names[policy], NULL, h->handle);
        else
-       {
-               iptc_set_policy("INPUT", fw3_flag_names[policy], NULL, h->handle);
-               iptc_set_policy("OUTPUT", fw3_flag_names[policy], NULL, h->handle);
-               iptc_set_policy("FORWARD", fw3_flag_names[policy], NULL, h->handle);
-       }
+               iptc_set_policy(chain, fw3_flag_names[policy], NULL, h->handle);
 }
 
-void fw3_ipt_delete_chain(struct fw3_ipt_handle *h, const char *chain)
+void
+fw3_ipt_delete_chain(struct fw3_ipt_handle *h, const char *chain)
 {
+       if (fw3_pr_debug)
+       {
+               printf("-F %s\n", chain);
+               printf("-X %s\n", chain);
+       }
+
        if (h->family == FW3_FAMILY_V6)
        {
                if (ip6tc_flush_entries(chain, h->handle))
@@ -84,7 +132,8 @@ void fw3_ipt_delete_chain(struct fw3_ipt_handle *h, const char *chain)
        }
 }
 
-void fw3_ipt_delete_rules(struct fw3_ipt_handle *h, const char *target)
+void
+fw3_ipt_delete_rules(struct fw3_ipt_handle *h, const char *target)
 {
        unsigned int num;
        const struct ipt_entry *e;
@@ -110,6 +159,9 @@ void fw3_ipt_delete_rules(struct fw3_ipt_handle *h, const char *target)
 
                                        if (*t && !strcmp(t, target))
                                        {
+                                               if (fw3_pr_debug)
+                                                       printf("-D %s %u\n", chain, num + 1);
+
                                                ip6tc_delete_num_entry(chain, num, h->handle);
                                                found = true;
                                                break;
@@ -135,6 +187,9 @@ void fw3_ipt_delete_rules(struct fw3_ipt_handle *h, const char *target)
 
                                        if (*t && !strcmp(t, target))
                                        {
+                                               if (fw3_pr_debug)
+                                                       printf("-D %s %u\n", chain, num + 1);
+
                                                iptc_delete_num_entry(chain, num, h->handle);
                                                found = true;
                                                break;
@@ -145,7 +200,8 @@ void fw3_ipt_delete_rules(struct fw3_ipt_handle *h, const char *target)
        }
 }
 
-void fw3_ipt_flush(struct fw3_ipt_handle *h)
+void
+fw3_ipt_flush(struct fw3_ipt_handle *h)
 {
        const char *chain;
 
@@ -183,12 +239,1022 @@ void fw3_ipt_flush(struct fw3_ipt_handle *h)
        }
 }
 
-void fw3_ipt_commit(struct fw3_ipt_handle *h)
+void
+fw3_ipt_commit(struct fw3_ipt_handle *h)
 {
+       int rv;
+
        if (h->family == FW3_FAMILY_V6)
-               ip6tc_commit(h->handle);
+       {
+               rv = ip6tc_commit(h->handle);
+               if (!rv)
+                       fprintf(stderr, "ip6tc_commit(): %s\n", ip6tc_strerror(errno));
+       }
        else
-               iptc_commit(h->handle);
+       {
+               rv = iptc_commit(h->handle);
+               if (!rv)
+                       fprintf(stderr, "iptc_commit(): %s\n", iptc_strerror(errno));
+       }
 
        free(h);
 }
+
+struct fw3_ipt_rule *
+fw3_ipt_rule_new(struct fw3_ipt_handle *h)
+{
+       struct fw3_ipt_rule *r;
+
+       r = fw3_alloc(sizeof(*r));
+
+       r->h = h;
+       r->argv = fw3_alloc(sizeof(char *));
+       r->argv[r->argc++] = "fw3";
+
+       return r;
+}
+
+
+static bool
+is_chain(struct fw3_ipt_handle *h, const char *name)
+{
+       if (h->family == FW3_FAMILY_V6)
+               return ip6tc_is_chain(name, h->handle);
+       else
+               return iptc_is_chain(name, h->handle);
+}
+
+static char *
+get_protoname(struct fw3_ipt_rule *r)
+{
+       const struct xtables_pprot *pp;
+
+       if (r->protocol)
+               for (pp = xtables_chain_protos; pp->name; pp++)
+                       if (pp->num == r->protocol)
+                               return (char *)pp->name;
+
+       return NULL;
+}
+
+static struct xtables_match *
+find_match(struct fw3_ipt_rule *r, const char *name)
+{
+       return xtables_find_match(name, XTF_TRY_LOAD, &r->matches);
+}
+
+static void
+init_match(struct fw3_ipt_rule *r, struct xtables_match *m, bool no_clone)
+{
+       size_t s;
+       struct xtables_globals *g;
+
+       if (!m)
+               return;
+
+       s = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size;
+
+       m->m = fw3_alloc(s);
+       strcpy(m->m->u.user.name, m->real_name ? m->real_name : m->name);
+       m->m->u.user.revision = m->revision;
+       m->m->u.match_size = s;
+
+       /* free previous userspace data */
+       if (m->udata_size)
+       {
+               free(m->udata);
+               m->udata = fw3_alloc(m->udata_size);
+       }
+
+       if (m->init)
+               m->init(m->m);
+
+       /* don't merge options if no_clone is set and this match is a clone */
+       if (no_clone && (m == m->next))
+               return;
+
+       /* merge option table */
+       g = (r->h->family == FW3_FAMILY_V6) ? &xtg6 : &xtg;
+
+       if (m->x6_options)
+               g->opts = xtables_options_xfrm(g->orig_opts, g->opts,
+                                                                          m->x6_options, &m->option_offset);
+
+       if (m->extra_opts)
+               g->opts = xtables_merge_options(g->orig_opts, g->opts,
+                                                                               m->extra_opts, &m->option_offset);
+}
+
+static bool
+need_protomatch(struct fw3_ipt_rule *r, const char *pname)
+{
+       if (!pname)
+               return false;
+
+       if (!xtables_find_match(pname, XTF_DONT_LOAD, NULL))
+               return true;
+
+       return !r->protocol_loaded;
+}
+
+static struct xtables_match *
+load_protomatch(struct fw3_ipt_rule *r)
+{
+       const char *pname = get_protoname(r);
+
+       if (!need_protomatch(r, pname))
+               return NULL;
+
+       return find_match(r, pname);
+}
+
+static struct xtables_target *
+get_target(struct fw3_ipt_rule *r, const char *name)
+{
+       size_t s;
+       struct xtables_target *t;
+       struct xtables_globals *g;
+
+       bool chain = is_chain(r->h, name);
+
+       if (chain)
+               t = xtables_find_target(XT_STANDARD_TARGET, XTF_LOAD_MUST_SUCCEED);
+       else
+               t = xtables_find_target(name, XTF_TRY_LOAD);
+
+       if (!t)
+               return NULL;
+
+       s = XT_ALIGN(sizeof(struct xt_entry_target)) + t->size;
+       t->t = fw3_alloc(s);
+
+       if (!t->real_name)
+               strcpy(t->t->u.user.name, name);
+       else
+               strcpy(t->t->u.user.name, t->real_name);
+
+       t->t->u.user.revision = t->revision;
+       t->t->u.target_size = s;
+
+       if (t->udata_size)
+       {
+               free(t->udata);
+               t->udata = fw3_alloc(t->udata_size);
+       }
+
+       if (t->init)
+               t->init(t->t);
+
+       /* merge option table */
+       g = (r->h->family == FW3_FAMILY_V6) ? &xtg6 : &xtg;
+
+       if (t->x6_options)
+               g->opts = xtables_options_xfrm(g->orig_opts, g->opts,
+                                              t->x6_options, &t->option_offset);
+       else
+               g->opts = xtables_merge_options(g->orig_opts, g->opts,
+                                               t->extra_opts, &t->option_offset);
+
+       r->target = t;
+
+       return t;
+}
+
+void
+fw3_ipt_rule_proto(struct fw3_ipt_rule *r, struct fw3_protocol *proto)
+{
+       uint32_t pr;
+
+       if (!proto || proto->any)
+               return;
+
+       pr = proto->protocol;
+
+       if (r->h->family == FW3_FAMILY_V6)
+       {
+               if (pr == 1)
+                       pr = 58;
+
+               r->e6.ipv6.proto = pr;
+               r->e6.ipv6.flags |= IP6T_F_PROTO;
+
+               if (proto->invert)
+                       r->e6.ipv6.invflags |= XT_INV_PROTO;
+       }
+       else
+       {
+               r->e.ip.proto = pr;
+
+               if (proto->invert)
+                       r->e.ip.invflags |= XT_INV_PROTO;
+       }
+
+       r->protocol = pr;
+}
+
+void
+fw3_ipt_rule_in_out(struct fw3_ipt_rule *r,
+                    struct fw3_device *in, struct fw3_device *out)
+{
+       if (r->h->family == FW3_FAMILY_V6)
+       {
+               if (in && !in->any)
+               {
+                       xtables_parse_interface(in->name, r->e6.ipv6.iniface,
+                                                         r->e6.ipv6.iniface_mask);
+
+                       if (in->invert)
+                               r->e6.ipv6.invflags |= IP6T_INV_VIA_IN;
+               }
+
+               if (out && !out->any)
+               {
+                       xtables_parse_interface(out->name, r->e6.ipv6.outiface,
+                                                          r->e6.ipv6.outiface_mask);
+
+                       if (out->invert)
+                               r->e6.ipv6.invflags |= IP6T_INV_VIA_OUT;
+               }
+       }
+       else
+       {
+               if (in && !in->any)
+               {
+                       xtables_parse_interface(in->name, r->e.ip.iniface,
+                                                         r->e.ip.iniface_mask);
+
+                       if (in->invert)
+                               r->e.ip.invflags |= IPT_INV_VIA_IN;
+               }
+
+               if (out && !out->any)
+               {
+                       xtables_parse_interface(out->name, r->e.ip.outiface,
+                                                          r->e.ip.outiface_mask);
+
+                       if (out->invert)
+                               r->e.ip.invflags |= IPT_INV_VIA_OUT;
+               }
+       }
+}
+
+
+static void
+ip4prefix2mask(int prefix, struct in_addr *mask)
+{
+       mask->s_addr = htonl(~((1 << (32 - prefix)) - 1));
+}
+
+static void
+ip6prefix2mask(int prefix, struct in6_addr *mask)
+{
+       char *p = (char *)mask;
+
+       if (prefix > 0)
+       {
+               memset(p, 0xff, prefix / 8);
+               memset(p + (prefix / 8) + 1, 0, (128 - prefix) / 8);
+               p[prefix / 8] = 0xff << (8 - (prefix & 7));
+       }
+       else
+       {
+               memset(mask, 0, sizeof(*mask));
+       }
+}
+
+void
+fw3_ipt_rule_src_dest(struct fw3_ipt_rule *r,
+                      struct fw3_address *src, struct fw3_address *dest)
+{
+       int i;
+
+       if ((src && src->range) || (dest && dest->range))
+       {
+               fw3_ipt_rule_addarg(r, false, "-m", "iprange");
+       }
+
+       if (src && src->set)
+       {
+               if (src->range)
+               {
+                       fw3_ipt_rule_addarg(r, src->invert, "--src-range",
+                                           fw3_address_to_string(src, false));
+               }
+               else if (r->h->family == FW3_FAMILY_V6)
+               {
+                       r->e6.ipv6.src = src->address.v6;
+                       ip6prefix2mask(src->mask, &r->e6.ipv6.smsk);
+
+                       for (i = 0; i < 4; i++)
+                               r->e6.ipv6.src.s6_addr32[i] &= r->e6.ipv6.smsk.s6_addr32[i];
+
+                       if (src->invert)
+                               r->e6.ipv6.invflags |= IP6T_INV_SRCIP;
+               }
+               else
+               {
+                       r->e.ip.src = src->address.v4;
+                       ip4prefix2mask(src->mask, &r->e.ip.smsk);
+
+                       r->e.ip.src.s_addr &= r->e.ip.smsk.s_addr;
+
+                       if (src->invert)
+                               r->e.ip.invflags |= IPT_INV_SRCIP;
+               }
+       }
+
+       if (dest && dest->set)
+       {
+               if (dest->range)
+               {
+                       fw3_ipt_rule_addarg(r, dest->invert, "--dst-range",
+                                           fw3_address_to_string(dest, false));
+               }
+               else if (r->h->family == FW3_FAMILY_V6)
+               {
+                       r->e6.ipv6.dst = dest->address.v6;
+                       ip6prefix2mask(dest->mask, &r->e6.ipv6.dmsk);
+
+                       for (i = 0; i < 4; i++)
+                               r->e6.ipv6.dst.s6_addr32[i] &= r->e6.ipv6.dmsk.s6_addr32[i];
+
+                       if (dest->invert)
+                               r->e6.ipv6.invflags |= IP6T_INV_DSTIP;
+               }
+               else
+               {
+                       r->e.ip.dst = dest->address.v4;
+                       ip4prefix2mask(dest->mask, &r->e.ip.dmsk);
+
+                       r->e.ip.dst.s_addr &= r->e.ip.dmsk.s_addr;
+
+                       if (dest->invert)
+                               r->e.ip.invflags |= IPT_INV_DSTIP;
+               }
+       }
+}
+
+void
+fw3_ipt_rule_sport_dport(struct fw3_ipt_rule *r,
+                         struct fw3_port *sp, struct fw3_port *dp)
+{
+       char buf[sizeof("65535:65535\0")];
+
+       if ((!sp || !sp->set) && (!dp || !dp->set))
+               return;
+
+       if (!get_protoname(r))
+               return;
+
+       if (sp && sp->set)
+       {
+               if (sp->port_min == sp->port_max)
+                       sprintf(buf, "%u", sp->port_min);
+               else
+                       sprintf(buf, "%u:%u", sp->port_min, sp->port_max);
+
+               fw3_ipt_rule_addarg(r, sp->invert, "--sport", buf);
+       }
+
+       if (dp && dp->set)
+       {
+               if (dp->port_min == dp->port_max)
+                       sprintf(buf, "%u", dp->port_min);
+               else
+                       sprintf(buf, "%u:%u", dp->port_min, dp->port_max);
+
+               fw3_ipt_rule_addarg(r, dp->invert, "--dport", buf);
+       }
+}
+
+void
+fw3_ipt_rule_mac(struct fw3_ipt_rule *r, struct fw3_mac *mac)
+{
+       if (!mac)
+               return;
+
+       fw3_ipt_rule_addarg(r, false, "-m", "mac");
+       fw3_ipt_rule_addarg(r, mac->invert, "--mac-source", ether_ntoa(&mac->mac));
+}
+
+void
+fw3_ipt_rule_icmptype(struct fw3_ipt_rule *r, struct fw3_icmptype *icmp)
+{
+       char buf[sizeof("255/255\0")];
+
+       if (!icmp)
+               return;
+
+       if (r->h->family == FW3_FAMILY_V6)
+       {
+               if (icmp->code6_min == 0 && icmp->code6_max == 0xFF)
+                       sprintf(buf, "%u", icmp->type6);
+               else
+                       sprintf(buf, "%u/%u", icmp->type6, icmp->code6_min);
+
+               fw3_ipt_rule_addarg(r, icmp->invert, "--icmpv6-type", buf);
+       }
+       else
+       {
+               if (icmp->code_min == 0 && icmp->code_max == 0xFF)
+                       sprintf(buf, "%u", icmp->type);
+               else
+                       sprintf(buf, "%u/%u", icmp->type, icmp->code_min);
+
+               fw3_ipt_rule_addarg(r, icmp->invert, "--icmp-type", buf);
+       }
+}
+
+void
+fw3_ipt_rule_limit(struct fw3_ipt_rule *r, struct fw3_limit *limit)
+{
+       char buf[sizeof("-4294967296/second\0")];
+
+       if (!limit || limit->rate <= 0)
+               return;
+
+       fw3_ipt_rule_addarg(r, false, "-m", "limit");
+
+       sprintf(buf, "%u/%s", limit->rate, fw3_limit_units[limit->unit]);
+       fw3_ipt_rule_addarg(r, limit->invert, "--limit", buf);
+
+       if (limit->burst > 0)
+       {
+               sprintf(buf, "%u", limit->burst);
+               fw3_ipt_rule_addarg(r, limit->invert, "--limit-burst", buf);
+       }
+}
+
+void
+fw3_ipt_rule_ipset(struct fw3_ipt_rule *r, struct fw3_ipset *ipset,
+                   bool invert)
+{
+       char buf[sizeof("dst,dst,dst\0")];
+       char *p = buf;
+
+       struct fw3_ipset_datatype *type;
+
+       if (!ipset)
+               return;
+
+       list_for_each_entry(type, &ipset->datatypes, list)
+       {
+               if (p > buf)
+                       *p++ = ',';
+
+               p += sprintf(p, "%s", type->dest ? "dst" : "src");
+       }
+
+       fw3_ipt_rule_addarg(r, false, "-m", "set");
+
+       fw3_ipt_rule_addarg(r, invert, "--match-set",
+                           ipset->external ? ipset->external : ipset->name);
+
+       fw3_ipt_rule_addarg(r, false, buf, NULL);
+}
+
+void
+fw3_ipt_rule_time(struct fw3_ipt_rule *r, struct fw3_time *time)
+{
+       int i;
+       struct tm empty = { 0 };
+
+       char buf[84]; /* sizeof("1,2,3,...,30,31\0") */
+       char *p;
+
+       bool d1 = memcmp(&time->datestart, &empty, sizeof(empty));
+       bool d2 = memcmp(&time->datestop, &empty, sizeof(empty));
+
+       if (!d1 && !d2 && !time->timestart && !time->timestop &&
+           !(time->monthdays & 0xFFFFFFFE) && !(time->weekdays & 0xFE))
+       {
+               return;
+       }
+
+       fw3_ipt_rule_addarg(r, false, "-m", "time");
+
+       if (time->utc)
+               fw3_ipt_rule_addarg(r, false, "--utc", NULL);
+
+       if (d1)
+       {
+               strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &time->datestart);
+               fw3_ipt_rule_addarg(r, false, "--datestart", buf);
+       }
+
+       if (d2)
+       {
+               strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &time->datestop);
+               fw3_ipt_rule_addarg(r, false, "--datestop", buf);
+       }
+
+       if (time->timestart)
+       {
+               sprintf(buf, "%02d:%02d:%02d",
+                       time->timestart / 3600,
+                       time->timestart % 3600 / 60,
+                       time->timestart % 60);
+
+               fw3_ipt_rule_addarg(r, false, "--timestart", buf);
+       }
+
+       if (time->timestop)
+       {
+               sprintf(buf, "%02d:%02d:%02d",
+                       time->timestop / 3600,
+                       time->timestop % 3600 / 60,
+                       time->timestop % 60);
+
+               fw3_ipt_rule_addarg(r, false, "--timestop", buf);
+       }
+
+       if (time->monthdays & 0xFFFFFFFE)
+       {
+               for (i = 1, p = buf; i < 32; i++)
+               {
+                       if (hasbit(time->monthdays, i))
+                       {
+                               if (p > buf)
+                                       *p++ = ',';
+
+                               p += sprintf(p, "%u", i);
+                       }
+               }
+
+               fw3_ipt_rule_addarg(r, hasbit(time->monthdays, 0), "--monthdays", buf);
+       }
+
+       if (time->weekdays & 0xFE)
+       {
+               for (i = 1, p = buf; i < 8; i++)
+               {
+                       if (hasbit(time->weekdays, i))
+                       {
+                               if (p > buf)
+                                       *p++ = ',';
+
+                               p += sprintf(p, "%u", i);
+                       }
+               }
+
+               fw3_ipt_rule_addarg(r, hasbit(time->weekdays, 0), "--weekdays", buf);
+       }
+}
+
+void
+fw3_ipt_rule_mark(struct fw3_ipt_rule *r, struct fw3_mark *mark)
+{
+       char buf[sizeof("0xFFFFFFFF/0xFFFFFFFF\0")];
+
+       if (!mark || !mark->set)
+               return;
+
+       if (mark->mask < 0xFFFFFFFF)
+               sprintf(buf, "0x%x/0x%x", mark->mark, mark->mask);
+       else
+               sprintf(buf, "0x%x", mark->mark);
+
+       fw3_ipt_rule_addarg(r, false, "-m", "mark");
+       fw3_ipt_rule_addarg(r, mark->invert, "--mark", buf);
+}
+
+void
+fw3_ipt_rule_comment(struct fw3_ipt_rule *r, const char *fmt, ...)
+{
+       va_list ap;
+       char buf[256];
+
+       if (!fmt || !*fmt)
+               return;
+
+       va_start(ap, fmt);
+       vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
+       va_end(ap);
+
+       fw3_ipt_rule_addarg(r, false, "-m", "comment");
+       fw3_ipt_rule_addarg(r, false, "--comment", buf);
+}
+
+void
+fw3_ipt_rule_extra(struct fw3_ipt_rule *r, const char *extra)
+{
+       char *p, **tmp, *s;
+
+       if (!extra || !*extra)
+               return;
+
+       s = fw3_strdup(extra);
+
+       for (p = strtok(s, " \t"); p; p = strtok(NULL, " \t"))
+       {
+               tmp = realloc(r->argv, (r->argc + 1) * sizeof(*r->argv));
+
+               if (!tmp)
+                       break;
+
+               r->argv = tmp;
+               r->argv[r->argc++] = fw3_strdup(p);
+       }
+
+       free(s);
+}
+
+static void
+rule_print6(struct ip6t_entry *e)
+{
+       char buf[INET6_ADDRSTRLEN];
+       char *pname;
+
+       if (e->ipv6.flags & IP6T_F_PROTO)
+       {
+               if (e->ipv6.flags & XT_INV_PROTO)
+                       printf(" !");
+
+               pname = get_protoname(container_of(e, struct fw3_ipt_rule, e6));
+
+               if (pname)
+                       printf(" -p %s", pname);
+               else
+                       printf(" -p %u", e->ipv6.proto);
+       }
+
+       if (e->ipv6.iniface[0])
+       {
+               if (e->ipv6.flags & IP6T_INV_VIA_IN)
+                       printf(" !");
+
+               printf(" -i %s", e->ipv6.iniface);
+       }
+
+       if (e->ipv6.outiface[0])
+       {
+               if (e->ipv6.flags & IP6T_INV_VIA_OUT)
+                       printf(" !");
+
+               printf(" -o %s", e->ipv6.outiface);
+       }
+
+       if (memcmp(&e->ipv6.src, &in6addr_any, sizeof(struct in6_addr)))
+       {
+               if (e->ipv6.flags & IP6T_INV_SRCIP)
+                       printf(" !");
+
+               printf(" -s %s/%u", inet_ntop(AF_INET6, &e->ipv6.src, buf, sizeof(buf)),
+                                   xtables_ip6mask_to_cidr(&e->ipv6.smsk));
+       }
+
+       if (memcmp(&e->ipv6.dst, &in6addr_any, sizeof(struct in6_addr)))
+       {
+               if (e->ipv6.flags & IP6T_INV_DSTIP)
+                       printf(" !");
+
+               printf(" -d %s/%u", inet_ntop(AF_INET6, &e->ipv6.dst, buf, sizeof(buf)),
+                                   xtables_ip6mask_to_cidr(&e->ipv6.dmsk));
+       }
+}
+
+static void
+rule_print4(struct ipt_entry *e)
+{
+       struct in_addr in_zero = { 0 };
+       char buf[sizeof("255.255.255.255\0")];
+       char *pname;
+
+       if (e->ip.proto)
+       {
+               if (e->ip.flags & XT_INV_PROTO)
+                       printf(" !");
+
+               pname = get_protoname(container_of(e, struct fw3_ipt_rule, e));
+
+               if (pname)
+                       printf(" -p %s", pname);
+               else
+                       printf(" -p %u", e->ip.proto);
+       }
+
+       if (e->ip.iniface[0])
+       {
+               if (e->ip.flags & IPT_INV_VIA_IN)
+                       printf(" !");
+
+               printf(" -i %s", e->ip.iniface);
+       }
+
+       if (e->ip.outiface[0])
+       {
+               if (e->ip.flags & IPT_INV_VIA_OUT)
+                       printf(" !");
+
+               printf(" -o %s", e->ip.outiface);
+       }
+
+       if (memcmp(&e->ip.src, &in_zero, sizeof(struct in_addr)))
+       {
+               if (e->ip.flags & IPT_INV_SRCIP)
+                       printf(" !");
+
+               printf(" -s %s/%u", inet_ntop(AF_INET, &e->ip.src, buf, sizeof(buf)),
+                                   xtables_ipmask_to_cidr(&e->ip.smsk));
+       }
+
+       if (memcmp(&e->ip.dst, &in_zero, sizeof(struct in_addr)))
+       {
+               if (e->ip.flags & IPT_INV_DSTIP)
+                       printf(" !");
+
+               printf(" -d %s/%u", inet_ntop(AF_INET, &e->ip.dst, buf, sizeof(buf)),
+                                   xtables_ipmask_to_cidr(&e->ip.dmsk));
+       }
+}
+
+static void
+rule_print(struct fw3_ipt_rule *r, const char *chain)
+{
+       struct xtables_rule_match *rm;
+       struct xtables_match *m;
+       struct xtables_target *t;
+
+       printf("-A %s", chain);
+
+       if (r->h->family == FW3_FAMILY_V6)
+               rule_print6(&r->e6);
+       else
+               rule_print4(&r->e);
+
+       for (rm = r->matches; rm; rm = rm->next)
+       {
+               m = rm->match;
+               printf(" -m %s", m->alias ? m->alias(m->m) : m->m->u.user.name);
+
+               if (m->save)
+                       m->save(&r->e.ip, m->m);
+       }
+
+       if (r->target)
+       {
+               t = r->target;
+               printf(" -j %s", t->alias ? t->alias(t->t) : t->t->u.user.name);
+
+               if (t->save)
+                       t->save(&r->e.ip, t->t);
+       }
+
+       printf("\n");
+}
+
+static bool
+parse_option(struct fw3_ipt_rule *r, int optc, bool inv)
+{
+       struct xtables_rule_match *m;
+       struct xtables_match *em;
+
+       /* is a target option */
+       if (r->target && (r->target->parse || r->target->x6_parse) &&
+               optc >= r->target->option_offset &&
+               optc < (r->target->option_offset + 256))
+       {
+               xtables_option_tpcall(optc, r->argv, inv, r->target, &r->e);
+               return false;
+       }
+
+       /* try to dispatch argument to one of the match parsers */
+       for (m = r->matches; m; m = m->next)
+       {
+               em = m->match;
+
+               if (m->completed || (!em->parse && !em->x6_parse))
+                       continue;
+
+               if (optc < em->option_offset ||
+                       optc >= (em->option_offset + 256))
+                       continue;
+
+               xtables_option_mpcall(optc, r->argv, inv, em, &r->e);
+               return false;
+       }
+
+       /* unhandled option, might belong to a protocol match */
+       if ((em = load_protomatch(r)) != NULL)
+       {
+               init_match(r, em, false);
+
+               r->protocol_loaded = true;
+               optind--;
+
+               return true;
+       }
+
+       if (optc == ':')
+               fprintf(stderr, "parse_option(): option '%s' needs argument\n",
+                       r->argv[optind-1]);
+
+       if (optc == '?')
+               fprintf(stderr, "parse_option(): unknown option '%s'\n",
+                       r->argv[optind-1]);
+
+       return false;
+}
+
+void
+fw3_ipt_rule_addarg(struct fw3_ipt_rule *r, bool inv,
+                    const char *k, const char *v)
+{
+       int n;
+       char **tmp;
+
+       if (!k)
+               return;
+
+       n = inv + !!k + !!v;
+       tmp = realloc(r->argv, (r->argc + n) * sizeof(*tmp));
+
+       if (!tmp)
+               return;
+
+       r->argv = tmp;
+
+       if (inv)
+               r->argv[r->argc++] = fw3_strdup("!");
+
+       r->argv[r->argc++] = fw3_strdup(k);
+
+       if (v)
+               r->argv[r->argc++] = fw3_strdup(v);
+}
+
+void
+fw3_ipt_rule_append(struct fw3_ipt_rule *r, const char *fmt, ...)
+{
+       size_t s;
+       struct xtables_rule_match *m;
+       struct xtables_match *em;
+       struct xtables_target *et;
+       struct xtables_globals *g;
+       struct ipt_entry *e;
+       struct ip6t_entry *e6;
+
+       int i, optc;
+       bool inv = false;
+       char buf[32];
+       va_list ap;
+
+       va_start(ap, fmt);
+       vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
+       va_end(ap);
+
+       g = (r->h->family == FW3_FAMILY_V6) ? &xtg6 : &xtg;
+       g->opts = g->orig_opts;
+
+       optind = 0;
+       opterr = 0;
+
+       while ((optc = getopt_long(r->argc, r->argv, "m:j:", g->opts, NULL)) != -1)
+       {
+               switch (optc)
+               {
+               case 'm':
+                       em = find_match(r, optarg);
+
+                       if (!em)
+                       {
+                               fprintf(stderr, "fw3_ipt_rule_append(): Can't find match '%s'\n", optarg);
+                               return;
+                       }
+
+                       init_match(r, em, true);
+                       break;
+
+               case 'j':
+                       et = get_target(r, optarg);
+
+                       if (!et)
+                       {
+                               fprintf(stderr, "fw3_ipt_rule_append(): Can't find target '%s'\n", optarg);
+                               return;
+                       }
+
+                       break;
+
+               case 1:
+                       if ((optarg[0] == '!') && (optarg[1] == '\0'))
+                       {
+                               inv = true;
+                               continue;
+                       }
+
+                       fprintf(stderr, "fw3_ipt_rule_append(): Bad argument '%s'\n", optarg);
+                       return;
+
+               default:
+                       if (parse_option(r, optc, inv))
+                               continue;
+                       break;
+               }
+
+               inv = false;
+       }
+
+       for (m = r->matches; m; m = m->next)
+               xtables_option_mfcall(m->match);
+
+       if (r->target)
+               xtables_option_tfcall(r->target);
+
+       if (fw3_pr_debug)
+               rule_print(r, buf);
+
+       if (r->h->family == FW3_FAMILY_V6)
+       {
+               s = XT_ALIGN(sizeof(struct ip6t_entry));
+
+               for (m = r->matches; m; m = m->next)
+                       s += m->match->m->u.match_size;
+
+               e6 = fw3_alloc(s + r->target->t->u.target_size);
+
+               memcpy(e6, &r->e6, sizeof(struct ip6t_entry));
+
+               e6->target_offset = s;
+               e6->next_offset = s + r->target->t->u.target_size;
+
+               s = 0;
+
+               for (m = r->matches; m; m = m->next)
+               {
+                       memcpy(e6->elems + s, m->match->m, m->match->m->u.match_size);
+                       s += m->match->m->u.match_size;
+               }
+
+               memcpy(e6->elems + s, r->target->t, r->target->t->u.target_size);
+               ip6tc_append_entry(buf, e6, r->h->handle);
+               free(e6);
+       }
+       else
+       {
+               s = XT_ALIGN(sizeof(struct ipt_entry));
+
+               for (m = r->matches; m; m = m->next)
+                       s += m->match->m->u.match_size;
+
+               e = fw3_alloc(s + r->target->t->u.target_size);
+
+               memcpy(e, &r->e, sizeof(struct ipt_entry));
+
+               e->target_offset = s;
+               e->next_offset = s + r->target->t->u.target_size;
+
+               s = 0;
+
+               for (m = r->matches; m; m = m->next)
+               {
+                       memcpy(e->elems + s, m->match->m, m->match->m->u.match_size);
+                       s += m->match->m->u.match_size;
+               }
+
+               memcpy(e->elems + s, r->target->t, r->target->t->u.target_size);
+
+               if (!iptc_append_entry(buf, e, r->h->handle))
+                       fprintf(stderr, "iptc_append_entry(): %s\n", iptc_strerror(errno));
+
+               free(e);
+       }
+
+       for (i = 1; i < r->argc; i++)
+               free(r->argv[i]);
+
+       free(r->argv);
+
+       xtables_rule_matches_free(&r->matches);
+
+       free(r->target->t);
+       free(r);
+
+       /* reset all targets and matches */
+       for (em = xtables_matches; em; em = em->next)
+               em->mflags = 0;
+
+       for (et = xtables_targets; et; et = et->next)
+       {
+               et->tflags = 0;
+               et->used = 0;
+       }
+
+       xtables_free_opts(1);
+}
+
+struct fw3_ipt_rule *
+fw3_ipt_rule_create(struct fw3_ipt_handle *handle, struct fw3_protocol *proto,
+                    struct fw3_device *in, struct fw3_device *out,
+                    struct fw3_address *src, struct fw3_address *dest)
+{
+       struct fw3_ipt_rule *r;
+
+       r = fw3_ipt_rule_new(handle);
+
+       fw3_ipt_rule_proto(r, proto);
+       fw3_ipt_rule_in_out(r, in, out);
+       fw3_ipt_rule_src_dest(r, src, dest);
+
+       return r;
+}
index d809c1da43b4ea5573019698e9d8a74a2b4d43ee..31d32682badd762a89b89e09ee1a5dd3d8bec932 100644 (file)
 
 #include <libiptc/libiptc.h>
 #include <libiptc/libip6tc.h>
+#include <xtables.h>
+
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/utsname.h>
 
 #include "options.h"
 
 
+extern struct xtables_match *xtables_pending_matches;
+extern struct xtables_target *xtables_pending_targets;
+
+/* libext.a interface */
+void init_extensions(void);
+void init_extensions4(void);
+void init_extensions6(void);
+
+/* Required by certain extensions like SNAT and DNAT */
+extern int kernel_version;
+void get_kernel_version(void);
+
 struct fw3_ipt_handle {
        enum fw3_family family;
        enum fw3_table table;
        struct xtc_handle *handle;
 };
 
-struct fw3_ipt_handle *fw3_ipt_open(enum fw3_family family, enum fw3_table table);
+struct fw3_ipt_rule {
+       struct fw3_ipt_handle *h;
+
+       union {
+               struct ipt_entry e;
+               struct ip6t_entry e6;
+       };
+
+       struct xtables_rule_match *matches;
+       struct xtables_target *target;
+
+       int argc;
+       char **argv;
+
+       uint32_t protocol;
+       bool protocol_loaded;
+};
+
+struct fw3_ipt_handle *fw3_ipt_open(enum fw3_family family,
+                                    enum fw3_table table);
+
+void fw3_ipt_set_policy(struct fw3_ipt_handle *h, const char *chain,
+                        enum fw3_flag policy);
 
-void fw3_ipt_set_policy(struct fw3_ipt_handle *h, enum fw3_flag policy);
 void fw3_ipt_delete_chain(struct fw3_ipt_handle *h, const char *chain);
 void fw3_ipt_delete_rules(struct fw3_ipt_handle *h, const char *target);
+
+static inline void
+fw3_ipt_create_chain(struct fw3_ipt_handle *h, const char *fmt, ...)
+{
+       char buf[32];
+       va_list ap;
+
+       va_start(ap, fmt);
+       vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
+       va_end(ap);
+
+       if (fw3_pr_debug)
+               printf("-N %s\n", buf);
+
+       iptc_create_chain(buf, h->handle);
+}
+
 void fw3_ipt_flush(struct fw3_ipt_handle *h);
 
 void fw3_ipt_commit(struct fw3_ipt_handle *h);
 
+struct fw3_ipt_rule *fw3_ipt_rule_new(struct fw3_ipt_handle *h);
+
+void fw3_ipt_rule_proto(struct fw3_ipt_rule *r, struct fw3_protocol *proto);
+
+void fw3_ipt_rule_in_out(struct fw3_ipt_rule *r,
+                         struct fw3_device *in, struct fw3_device *out);
+
+void fw3_ipt_rule_src_dest(struct fw3_ipt_rule *r,
+                           struct fw3_address *src, struct fw3_address *dest);
+
+void fw3_ipt_rule_sport_dport(struct fw3_ipt_rule *r,
+                              struct fw3_port *sp, struct fw3_port *dp);
+
+void fw3_ipt_rule_mac(struct fw3_ipt_rule *r, struct fw3_mac *mac);
+
+void fw3_ipt_rule_icmptype(struct fw3_ipt_rule *r, struct fw3_icmptype *icmp);
+
+void fw3_ipt_rule_limit(struct fw3_ipt_rule *r, struct fw3_limit *limit);
+
+void fw3_ipt_rule_ipset(struct fw3_ipt_rule *r, struct fw3_ipset *ipset,
+                        bool invert);
+
+void fw3_ipt_rule_time(struct fw3_ipt_rule *r, struct fw3_time *time);
+
+void fw3_ipt_rule_mark(struct fw3_ipt_rule *r, struct fw3_mark *mark);
+
+void fw3_ipt_rule_comment(struct fw3_ipt_rule *r, const char *fmt, ...);
+
+void fw3_ipt_rule_extra(struct fw3_ipt_rule *r, const char *extra);
+
+void fw3_ipt_rule_addarg(struct fw3_ipt_rule *r, bool inv,
+                         const char *k, const char *v);
+
+struct fw3_ipt_rule * fw3_ipt_rule_create(struct fw3_ipt_handle *handle,
+                                          struct fw3_protocol *proto,
+                                          struct fw3_device *in,
+                                          struct fw3_device *out,
+                                          struct fw3_address *src,
+                                          struct fw3_address *dest);
+
+void fw3_ipt_rule_append(struct fw3_ipt_rule *r, const char *fmt, ...);
+
+static inline void
+fw3_ipt_rule_target(struct fw3_ipt_rule *r, const char *fmt, ...)
+{
+       va_list ap;
+       char buf[32];
+
+       va_start(ap, fmt);
+       vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
+       va_end(ap);
+
+       fw3_ipt_rule_addarg(r, false, "-j", buf);
+}
+
 #endif
diff --git a/main.c b/main.c
index 09de78260f1fdb78cd72ae741506cdc3d468e286..a2b80be4444c1eb90719f5fcaa6fb2cb1ff020ce 100644 (file)
--- a/main.c
+++ b/main.c
@@ -139,25 +139,6 @@ free_state(struct fw3_state *state)
 }
 
 
-static bool
-restore_pipe(enum fw3_family family, bool silent)
-{
-       const char *cmd;
-
-       cmd = (family == FW3_FAMILY_V4) ? "iptables-restore" : "ip6tables-restore";
-
-       if (print_rules)
-               return fw3_stdout_pipe();
-
-       if (!fw3_command_pipe(silent, cmd, "--lenient", "--noflush"))
-       {
-               warn("Unable to execute %s", cmd);
-               return false;
-       }
-
-       return true;
-}
-
 static bool
 family_running(enum fw3_family family)
 {
@@ -261,6 +242,7 @@ start(void)
        int rv = 1;
        enum fw3_family family;
        enum fw3_table table;
+       struct fw3_ipt_handle *handle;
 
        if (!print_rules)
        {
@@ -285,32 +267,31 @@ start(void)
                        continue;
                }
 
-               if (!restore_pipe(family, false))
-                       continue;
-
                for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
                {
                        if (!fw3_has_table(family == FW3_FAMILY_V6, fw3_flag_names[table]))
                                continue;
 
+                       if (!(handle = fw3_ipt_open(family, table)))
+                               continue;
+
                        info(" * Populating %s %s table",
                             fw3_flag_names[family], fw3_flag_names[table]);
 
-                       fw3_pr("*%s\n", fw3_flag_names[table]);
-                       fw3_print_default_chains(cfg_state, family, table, false);
-                       fw3_print_zone_chains(cfg_state, family, table, false);
-                       fw3_print_default_head_rules(cfg_state, family, table, false);
-                       fw3_print_rules(cfg_state, family, table);
-                       fw3_print_redirects(cfg_state, family, table);
-                       fw3_print_forwards(cfg_state, family, table);
-                       fw3_print_zone_rules(cfg_state, family, table, false);
-                       fw3_print_default_tail_rules(cfg_state, family, table, false);
-                       fw3_pr("COMMIT\n");
+                       fw3_print_default_chains(handle, cfg_state, false);
+                       fw3_print_zone_chains(handle, cfg_state, false);
+                       fw3_print_default_head_rules(handle, cfg_state, false);
+                       fw3_print_rules(handle, cfg_state);
+                       fw3_print_redirects(handle, cfg_state);
+                       fw3_print_forwards(handle, cfg_state);
+                       fw3_print_zone_rules(handle, cfg_state, false);
+                       fw3_print_default_tail_rules(handle, cfg_state, false);
+
+                       fw3_ipt_commit(handle);
                }
 
-               fw3_print_includes(cfg_state, family, false);
+               //fw3_print_includes(cfg_state, family, false);
 
-               fw3_command_close();
                family_set(run_state, family, true);
                family_set(cfg_state, family, true);
 
@@ -373,41 +354,38 @@ reload(void)
                family_set(cfg_state, family, false);
 
 start:
-               if (!restore_pipe(family, true))
-                       continue;
-
                if (family == FW3_FAMILY_V6 && cfg_state->defaults.disable_ipv6)
-                       goto skip;
+                       continue;
 
                for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
                {
                        if (!fw3_has_table(family == FW3_FAMILY_V6, fw3_flag_names[table]))
                                continue;
 
+                       if (!(handle = fw3_ipt_open(family, table)))
+                               continue;
+
                        info(" * Populating %s %s table",
                             fw3_flag_names[family], fw3_flag_names[table]);
 
-                       fw3_pr("*%s\n", fw3_flag_names[table]);
-                       fw3_print_default_chains(cfg_state, family, table, true);
-                       fw3_print_zone_chains(cfg_state, family, table, true);
-                       fw3_print_default_head_rules(cfg_state, family, table, true);
-                       fw3_print_rules(cfg_state, family, table);
-                       fw3_print_redirects(cfg_state, family, table);
-                       fw3_print_forwards(cfg_state, family, table);
-                       fw3_print_zone_rules(cfg_state, family, table, true);
-                       fw3_print_default_tail_rules(cfg_state, family, table, true);
-                       fw3_pr("COMMIT\n");
+                       fw3_print_default_chains(handle, cfg_state, true);
+                       fw3_print_zone_chains(handle, cfg_state, true);
+                       fw3_print_default_head_rules(handle, cfg_state, true);
+                       fw3_print_rules(handle, cfg_state);
+                       fw3_print_redirects(handle, cfg_state);
+                       fw3_print_forwards(handle, cfg_state);
+                       fw3_print_zone_rules(handle, cfg_state, true);
+                       fw3_print_default_tail_rules(handle, cfg_state, true);
+
+                       fw3_ipt_commit(handle);
                }
 
-               fw3_print_includes(cfg_state, family, true);
+               //fw3_print_includes(cfg_state, family, true);
 
                family_set(run_state, family, true);
                family_set(cfg_state, family, true);
 
                rv = 0;
-
-skip:
-               fw3_command_close();
        }
 
        if (!rv)
index 3d30c57c5f86ae736d64c3490ef141971cdc7c6f..0cd90680efa707e930ab0276eb2d6b582e9d15bf 100644 (file)
--- a/options.c
+++ b/options.c
@@ -84,7 +84,7 @@ const char *fw3_flag_names[__FW3_FLAG_MAX] = {
        "DROP",
 };
 
-static const char *limit_units[] = {
+const char *fw3_limit_units[__FW3_LIMIT_UNIT_MAX] = {
        "second",
        "minute",
        "hour",
@@ -191,7 +191,7 @@ fw3_parse_limit(void *ptr, const char *val, bool is_list)
        if (!strlen(e))
                return false;
 
-       if (!parse_enum(&u, e, limit_units, 0, FW3_LIMIT_UNIT_DAY))
+       if (!parse_enum(&u, e, fw3_limit_units, 0, FW3_LIMIT_UNIT_DAY))
                return false;
 
        limit->rate = n;
@@ -893,16 +893,6 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
 }
 
 
-void
-fw3_format_in_out(struct fw3_device *in, struct fw3_device *out)
-{
-       if (in && !in->any)
-               fw3_pr(" %s-i %s", in->invert ? "! " : "", in->name);
-
-       if (out && !out->any)
-               fw3_pr(" %s-o %s", out->invert ? "! " : "", out->name);
-}
-
 const char *
 fw3_address_to_string(struct fw3_address *address, bool allow_invert)
 {
@@ -1040,7 +1030,7 @@ fw3_format_limit(struct fw3_limit *limit)
        {
                fw3_pr(" -m limit %s--limit %u/%s",
                       limit->invert ? "! " : "",
-                      limit->rate, limit_units[limit->unit]);
+                      limit->rate, fw3_limit_units[limit->unit]);
 
                if (limit->burst > 0)
                        fw3_pr(" --limit-burst %u", limit->burst);
index 0a22cb689bd845180bec0e2663731ff538bf6640..f6168f55830b3068b2430d83a081bd6edd83e3fa 100644 (file)
--- a/options.h
+++ b/options.h
@@ -92,8 +92,13 @@ enum fw3_limit_unit
        FW3_LIMIT_UNIT_MINUTE = 1,
        FW3_LIMIT_UNIT_HOUR   = 2,
        FW3_LIMIT_UNIT_DAY    = 3,
+
+       __FW3_LIMIT_UNIT_MAX
 };
 
+extern const char *fw3_limit_units[__FW3_LIMIT_UNIT_MAX];
+
+
 enum fw3_ipset_method
 {
        FW3_IPSET_METHOD_UNSPEC = 0,
index 3c0ffada64fc8978a3aa7ff90766db652f9b295f..aec47fdf46db19ae4feeeb5ade2858655bddb346 100644 (file)
@@ -259,84 +259,207 @@ fw3_load_redirects(struct fw3_state *state, struct uci_package *p)
 }
 
 static void
-print_chain_nat(struct fw3_redirect *redir)
+append_chain_nat(struct fw3_ipt_rule *r, struct fw3_redirect *redir)
 {
        if (redir->target == FW3_FLAG_DNAT)
-               fw3_pr("-A zone_%s_prerouting", redir->src.name);
+               fw3_ipt_rule_append(r, "zone_%s_prerouting", redir->src.name);
        else
-               fw3_pr("-A zone_%s_postrouting", redir->dest.name);
+               fw3_ipt_rule_append(r, "zone_%s_postrouting", redir->dest.name);
 }
 
 static void
-print_snat_dnat(enum fw3_flag target,
-                struct fw3_address *addr, struct fw3_port *port)
+set_snat_dnat(struct fw3_ipt_rule *r, enum fw3_flag target,
+              struct fw3_address *addr, struct fw3_port *port)
 {
-       char s[sizeof("255.255.255.255 ")];
+       char buf[sizeof("255.255.255.255:65535-65535\0")];
 
-       if (target == FW3_FLAG_DNAT)
-               fw3_pr(" -j DNAT --to-destination ");
-       else
-               fw3_pr(" -j SNAT --to-source ");
+       buf[0] = '\0';
 
        if (addr && addr->set)
        {
-               inet_ntop(AF_INET, &addr->address.v4, s, sizeof(s));
-               fw3_pr(s);
+               inet_ntop(AF_INET, &addr->address.v4, buf, sizeof(buf));
        }
 
        if (port && port->set)
        {
                if (port->port_min == port->port_max)
-                       fw3_pr(":%u", port->port_min);
+                       sprintf(buf + strlen(buf), ":%u", port->port_min);
                else
-                       fw3_pr(":%u-%u", port->port_min, port->port_max);
+                       sprintf(buf + strlen(buf), ":%u-%u",
+                               port->port_min, port->port_max);
        }
 
-       fw3_pr("\n");
+       if (target == FW3_FLAG_DNAT)
+       {
+               fw3_ipt_rule_target(r, "DNAT");
+               fw3_ipt_rule_addarg(r, false, "--to-destination", buf);
+       }
+       else
+       {
+               fw3_ipt_rule_target(r, "SNAT");
+               fw3_ipt_rule_addarg(r, false, "--to-source", buf);
+       }
 }
 
 static void
-print_target_nat(struct fw3_redirect *redir)
+set_target_nat(struct fw3_ipt_rule *r, struct fw3_redirect *redir)
 {
        if (redir->target == FW3_FLAG_DNAT)
-               print_snat_dnat(redir->target, &redir->ip_redir, &redir->port_redir);
+               set_snat_dnat(r, redir->target, &redir->ip_redir, &redir->port_redir);
        else
-               print_snat_dnat(redir->target, &redir->ip_dest, &redir->port_dest);
+               set_snat_dnat(r, redir->target, &redir->ip_dest, &redir->port_dest);
 }
 
 static void
-print_chain_filter(struct fw3_redirect *redir)
+append_chain_filter(struct fw3_ipt_rule *r, struct fw3_redirect *redir)
 {
        if (redir->target == FW3_FLAG_DNAT)
        {
                /* XXX: check for local ip */
                if (!redir->ip_redir.set)
-                       fw3_pr("-A zone_%s_input", redir->src.name);
+                       fw3_ipt_rule_append(r, "zone_%s_input", redir->src.name);
                else
-                       fw3_pr("-A zone_%s_forward", redir->src.name);
+                       fw3_ipt_rule_append(r, "zone_%s_forward", redir->src.name);
        }
        else
        {
                if (redir->src.set && !redir->src.any)
-                       fw3_pr("-A zone_%s_forward", redir->src.name);
+                       fw3_ipt_rule_append(r, "zone_%s_forward", redir->src.name);
                else
-                       fw3_pr("-A delegate_forward");
+                       fw3_ipt_rule_append(r, "delegate_forward");
        }
 }
 
 static void
-print_target_filter(struct fw3_redirect *redir)
+set_target_filter(struct fw3_ipt_rule *r, struct fw3_redirect *redir)
 {
        /* XXX: check for local ip */
        if (redir->target == FW3_FLAG_DNAT && !redir->ip_redir.set)
-               fw3_pr(" -m conntrack --ctstate DNAT -j ACCEPT\n");
+               fw3_ipt_rule_extra(r, "-m conntrack --ctstate DNAT");
+
+       fw3_ipt_rule_target(r, "ACCEPT");
+}
+
+static void
+set_comment(struct fw3_ipt_rule *r, const char *name, int num, bool ref)
+{
+       if (name)
+       {
+               if (ref)
+                       fw3_ipt_rule_comment(r, "%s (reflection)", name);
+               else
+                       fw3_ipt_rule_comment(r, name);
+       }
        else
-               fw3_pr(" -j ACCEPT\n");
+       {
+               if (ref)
+                       fw3_ipt_rule_comment(r, "@redirect[%u] (reflection)", num);
+               else
+                       fw3_ipt_rule_comment(r, "@redirect[%u]", num);
+       }
+}
+
+static void
+print_redirect(struct fw3_ipt_handle *h, struct fw3_state *state,
+               struct fw3_redirect *redir, int num,
+               struct fw3_protocol *proto, struct fw3_mac *mac)
+{
+       struct fw3_ipt_rule *r;
+       struct fw3_address *src, *dst;
+       struct fw3_port *spt, *dpt;
+
+       switch (h->table)
+       {
+       case FW3_TABLE_NAT:
+               src = &redir->ip_src;
+               dst = &redir->ip_dest;
+               spt = &redir->port_src;
+               dpt = &redir->port_dest;
+
+               if (redir->target == FW3_FLAG_SNAT)
+               {
+                       dst = &redir->ip_redir;
+                       dpt = &redir->port_redir;
+               }
+
+               r = fw3_ipt_rule_create(h, proto, NULL, NULL, src, dst);
+               fw3_ipt_rule_sport_dport(r, spt, dpt);
+               fw3_ipt_rule_mac(r, mac);
+               fw3_ipt_rule_ipset(r, redir->_ipset, redir->ipset.invert);
+               fw3_ipt_rule_time(r, &redir->time);
+               fw3_ipt_rule_mark(r, &redir->mark);
+               set_target_nat(r, redir);
+               fw3_ipt_rule_extra(r, redir->extra);
+               set_comment(r, redir->name, num, false);
+               append_chain_nat(r, redir);
+               break;
+
+       case FW3_TABLE_FILTER:
+               src = &redir->ip_src;
+               dst = &redir->ip_redir;
+               spt = &redir->port_src;
+               dpt = &redir->port_redir;
+
+               r = fw3_ipt_rule_create(h, proto, NULL, NULL, src, dst);
+               fw3_ipt_rule_sport_dport(r, spt, dpt);
+               fw3_ipt_rule_mac(r, mac);
+               fw3_ipt_rule_ipset(r, redir->_ipset, redir->ipset.invert);
+               fw3_ipt_rule_time(r, &redir->time);
+               fw3_ipt_rule_mark(r, &redir->mark);
+               set_target_filter(r, redir);
+               fw3_ipt_rule_extra(r, redir->extra);
+               set_comment(r, redir->name, num, false);
+               append_chain_filter(r, redir);
+               break;
+
+       default:
+               break;
+       }
 }
 
 static void
-print_redirect(struct fw3_state *state, enum fw3_family family,
-               enum fw3_table table, struct fw3_redirect *redir, int num)
+print_reflection(struct fw3_ipt_handle *h, struct fw3_state *state,
+                 struct fw3_redirect *redir, int num,
+                 struct fw3_protocol *proto, struct fw3_address *ra,
+                 struct fw3_address *ia, struct fw3_address *ea)
+{
+       struct fw3_ipt_rule *r;
+
+       switch (h->table)
+       {
+       case FW3_TABLE_NAT:
+               r = fw3_ipt_rule_create(h, proto, NULL, NULL, ia, ea);
+               fw3_ipt_rule_sport_dport(r, NULL, &redir->port_dest);
+               fw3_ipt_rule_time(r, &redir->time);
+               set_comment(r, redir->name, num, true);
+               set_snat_dnat(r, FW3_FLAG_DNAT, &redir->ip_redir, &redir->port_redir);
+               fw3_ipt_rule_append(r, "zone_%s_prerouting", redir->dest.name);
+
+               r = fw3_ipt_rule_create(h, proto, NULL, NULL, ia, &redir->ip_redir);
+               fw3_ipt_rule_sport_dport(r, NULL, &redir->port_redir);
+               fw3_ipt_rule_time(r, &redir->time);
+               set_comment(r, redir->name, num, true);
+               set_snat_dnat(r, FW3_FLAG_SNAT, ra, NULL);
+               fw3_ipt_rule_append(r, "zone_%s_postrouting", redir->dest.name);
+               break;
+
+       case FW3_TABLE_FILTER:
+               r = fw3_ipt_rule_create(h, proto, NULL, NULL, ia, &redir->ip_redir);
+               fw3_ipt_rule_sport_dport(r, NULL, &redir->port_redir);
+               fw3_ipt_rule_time(r, &redir->time);
+               set_comment(r, redir->name, num, true);
+               fw3_ipt_rule_target(r, "zone_%s_dest_ACCEPT", redir->dest.name);
+               fw3_ipt_rule_append(r, "zone_%s_forward", redir->dest.name);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static void
+expand_redirect(struct fw3_ipt_handle *handle, struct fw3_state *state,
+                struct fw3_redirect *redir, int num)
 {
        struct list_head *ext_addrs, *int_addrs;
        struct fw3_address *ext_addr, *int_addr, ref_addr;
@@ -349,16 +472,16 @@ print_redirect(struct fw3_state *state, enum fw3_family family,
        else
                info("   * Redirect #%u", num);
 
-       if (!fw3_is_family(redir->_src, family) ||
-               !fw3_is_family(redir->_dest, family))
+       if (!fw3_is_family(redir->_src, handle->family) ||
+               !fw3_is_family(redir->_dest, handle->family))
        {
                info("     ! Skipping due to different family of zone");
                return;
        }
 
-       if (!fw3_is_family(&redir->ip_src, family) ||
-           !fw3_is_family(&redir->ip_dest, family) ||
-               !fw3_is_family(&redir->ip_redir, family))
+       if (!fw3_is_family(&redir->ip_src, handle->family) ||
+           !fw3_is_family(&redir->ip_dest, handle->family) ||
+               !fw3_is_family(&redir->ip_redir, handle->family))
        {
                info("     ! Skipping due to different family of ip address");
                return;
@@ -366,7 +489,7 @@ print_redirect(struct fw3_state *state, enum fw3_family family,
 
        if (redir->_ipset)
        {
-               if (!fw3_is_family(redir->_ipset, family))
+               if (!fw3_is_family(redir->_ipset, handle->family))
                {
                        info("     ! Skipping due to different family in ipset");
                        return;
@@ -380,51 +503,12 @@ print_redirect(struct fw3_state *state, enum fw3_family family,
                        return;
                }
 
-               set(redir->_ipset->flags, family, family);
+               set(redir->_ipset->flags, handle->family, handle->family);
        }
 
        fw3_foreach(proto, &redir->proto)
        fw3_foreach(mac, &redir->mac_src)
-       {
-               if (table == FW3_TABLE_NAT)
-               {
-                       print_chain_nat(redir);
-                       fw3_format_ipset(redir->_ipset, redir->ipset.invert);
-                       fw3_format_protocol(proto, family);
-
-                       if (redir->target == FW3_FLAG_DNAT)
-                       {
-                               fw3_format_src_dest(&redir->ip_src, &redir->ip_dest);
-                               fw3_format_sport_dport(&redir->port_src, &redir->port_dest);
-                       }
-                       else
-                       {
-                               fw3_format_src_dest(&redir->ip_src, &redir->ip_redir);
-                               fw3_format_sport_dport(&redir->port_src, &redir->port_redir);
-                       }
-
-                       fw3_format_mac(mac);
-                       fw3_format_time(&redir->time);
-                       fw3_format_mark(&redir->mark);
-                       fw3_format_extra(redir->extra);
-                       fw3_format_comment(redir->name);
-                       print_target_nat(redir);
-               }
-               else if (table == FW3_TABLE_FILTER)
-               {
-                       print_chain_filter(redir);
-                       fw3_format_ipset(redir->_ipset, redir->ipset.invert);
-                       fw3_format_protocol(proto, family);
-                       fw3_format_src_dest(&redir->ip_src, &redir->ip_redir);
-                       fw3_format_sport_dport(&redir->port_src, &redir->port_redir);
-                       fw3_format_mac(mac);
-                       fw3_format_time(&redir->time);
-                       fw3_format_mark(&redir->mark);
-                       fw3_format_extra(redir->extra);
-                       fw3_format_comment(redir->name);
-                       print_target_filter(redir);
-               }
-       }
+               print_redirect(handle, state, redir, num, proto, mac);
 
        /* reflection rules */
        if (redir->target != FW3_FLAG_DNAT || !redir->reflection)
@@ -451,8 +535,8 @@ print_redirect(struct fw3_state *state, enum fw3_family family,
                        fw3_foreach(int_addr, int_addrs)
                        fw3_foreach(proto, &redir->proto)
                        {
-                               if (!fw3_is_family(int_addr, family) ||
-                                   !fw3_is_family(ext_addr, family))
+                               if (!fw3_is_family(int_addr, handle->family) ||
+                                   !fw3_is_family(ext_addr, handle->family))
                                        continue;
 
                                if (!proto || (proto->protocol != 6 && proto->protocol != 17))
@@ -466,35 +550,8 @@ print_redirect(struct fw3_state *state, enum fw3_family family,
                                ref_addr.mask = 32;
                                ext_addr->mask = 32;
 
-                               if (table == FW3_TABLE_NAT)
-                               {
-                                       fw3_pr("-A zone_%s_prerouting", redir->dest.name);
-                                       fw3_format_protocol(proto, family);
-                                       fw3_format_src_dest(int_addr, ext_addr);
-                                       fw3_format_sport_dport(NULL, &redir->port_dest);
-                                       fw3_format_time(&redir->time);
-                                       fw3_format_comment(redir->name, " (reflection)");
-                                       print_snat_dnat(FW3_FLAG_DNAT,
-                                                       &redir->ip_redir, &redir->port_redir);
-
-                                       fw3_pr("-A zone_%s_postrouting", redir->dest.name);
-                                       fw3_format_protocol(proto, family);
-                                       fw3_format_src_dest(int_addr, &redir->ip_redir);
-                                       fw3_format_sport_dport(NULL, &redir->port_redir);
-                                       fw3_format_time(&redir->time);
-                                       fw3_format_comment(redir->name, " (reflection)");
-                                       print_snat_dnat(FW3_FLAG_SNAT, &ref_addr, NULL);
-                               }
-                               else if (table == FW3_TABLE_FILTER)
-                               {
-                                       fw3_pr("-A zone_%s_forward", redir->dest.name);
-                                       fw3_format_protocol(proto, family);
-                                       fw3_format_src_dest(int_addr, &redir->ip_redir);
-                                       fw3_format_sport_dport(NULL, &redir->port_redir);
-                                       fw3_format_time(&redir->time);
-                                       fw3_format_comment(redir->name, " (reflection)");
-                                       fw3_pr(" -j zone_%s_dest_ACCEPT\n", redir->dest.name);
-                               }
+                               print_reflection(handle, state, redir, num, proto,
+                                                                &ref_addr, int_addr, ext_addr);
                        }
 
                        fw3_ubus_address_free(int_addrs);
@@ -505,18 +562,17 @@ print_redirect(struct fw3_state *state, enum fw3_family family,
 }
 
 void
-fw3_print_redirects(struct fw3_state *state, enum fw3_family family,
-                    enum fw3_table table)
+fw3_print_redirects(struct fw3_ipt_handle *handle, struct fw3_state *state)
 {
        int num = 0;
        struct fw3_redirect *redir;
 
-       if (family == FW3_FAMILY_V6)
+       if (handle->family == FW3_FAMILY_V6)
                return;
 
-       if (table != FW3_TABLE_FILTER && table != FW3_TABLE_NAT)
+       if (handle->table != FW3_TABLE_FILTER && handle->table != FW3_TABLE_NAT)
                return;
 
        list_for_each_entry(redir, &state->redirects, list)
-               print_redirect(state, family, table, redir, num++);
+               expand_redirect(handle, state, redir, num++);
 }
index 14f90bb6d01748554b16c94d2a83a75619995078..b7001a431101255cb9b8cc8ea5ffc57bb2a3c785 100644 (file)
 #include "zones.h"
 #include "ipsets.h"
 #include "ubus.h"
+#include "iptables.h"
 
 extern const struct fw3_option fw3_redirect_opts[];
 
 void fw3_load_redirects(struct fw3_state *state, struct uci_package *p);
-void fw3_print_redirects(struct fw3_state *state, enum fw3_family family,
-                         enum fw3_table table);
+void fw3_print_redirects(struct fw3_ipt_handle *handle,
+                         struct fw3_state *state);
 
 #define fw3_free_redirect(redir) \
        fw3_free_object(redir, fw3_redirect_opts)
diff --git a/rules.c b/rules.c
index 7f748ebb043fb96028d3598fc5f93c94ace3d137..53268e29d3cebd7c5d36e3dce0cba1d188901afb 100644 (file)
--- a/rules.c
+++ b/rules.c
@@ -208,19 +208,19 @@ fw3_load_rules(struct fw3_state *state, struct uci_package *p)
 
 
 static void
-print_chain(struct fw3_rule *rule)
+append_chain(struct fw3_ipt_rule *r, struct fw3_rule *rule)
 {
-       char chain[256];
+       char chain[32];
 
-       sprintf(chain, "delegate_output");
+       snprintf(chain, sizeof(chain), "delegate_output");
 
        if (rule->target == FW3_FLAG_NOTRACK)
        {
-               sprintf(chain, "zone_%s_notrack", rule->src.name);
+               snprintf(chain, sizeof(chain), "zone_%s_notrack", rule->src.name);
        }
        else if (rule->target == FW3_FLAG_MARK)
        {
-               sprintf(chain, "fwmark");
+               snprintf(chain, sizeof(chain), "fwmark");
        }
        else
        {
@@ -229,98 +229,103 @@ print_chain(struct fw3_rule *rule)
                        if (!rule->src.any)
                        {
                                if (rule->dest.set)
-                                       sprintf(chain, "zone_%s_forward", rule->src.name);
+                                       snprintf(chain, sizeof(chain), "zone_%s_forward",
+                                                rule->src.name);
                                else
-                                       sprintf(chain, "zone_%s_input", rule->src.name);
+                                       snprintf(chain, sizeof(chain), "zone_%s_input",
+                                                rule->src.name);
                        }
                        else
                        {
                                if (rule->dest.set)
-                                       sprintf(chain, "delegate_forward");
+                                       snprintf(chain, sizeof(chain), "delegate_forward");
                                else
-                                       sprintf(chain, "delegate_input");
+                                       snprintf(chain, sizeof(chain), "delegate_input");
                        }
                }
 
                if (rule->dest.set && !rule->src.set)
-                       sprintf(chain, "zone_%s_output", rule->dest.name);
+                       snprintf(chain, sizeof(chain), "zone_%s_output", rule->dest.name);
        }
 
-       fw3_pr("-A %s", chain);
+       fw3_ipt_rule_append(r, chain);
 }
 
-static void print_target(struct fw3_rule *rule)
+static void set_target(struct fw3_ipt_rule *r, struct fw3_rule *rule)
 {
-       const char *target;
+       const char *name;
+       struct fw3_mark *mark;
+       char buf[sizeof("0xFFFFFFFF/0xFFFFFFFF\0")];
 
        switch(rule->target)
        {
        case FW3_FLAG_MARK:
-               if (rule->set_mark.set)
-                       fw3_pr(" -j MARK --set-mark 0x%x/0x%x\n",
-                              rule->set_mark.mark, rule->set_mark.mask);
-               else
-                       fw3_pr(" -j MARK --set-xmark 0x%x/0x%x\n",
-                              rule->set_xmark.mark, rule->set_xmark.mask);
+               name = rule->set_mark.set ? "--set-mark" : "--set-xmark";
+               mark = rule->set_mark.set ? &rule->set_mark : &rule->set_xmark;
+               sprintf(buf, "0x%x/0x%x", mark->mark, mark->mask);
+
+               fw3_ipt_rule_target(r, "MARK");
+               fw3_ipt_rule_addarg(r, false, name, buf);
                return;
 
        case FW3_FLAG_ACCEPT:
        case FW3_FLAG_DROP:
        case FW3_FLAG_NOTRACK:
-               target = fw3_flag_names[rule->target];
+               name = fw3_flag_names[rule->target];
                break;
 
        default:
-               target = fw3_flag_names[FW3_FLAG_REJECT];
+               name = fw3_flag_names[FW3_FLAG_REJECT];
                break;
        }
 
        if (rule->dest.set && !rule->dest.any)
-               fw3_pr(" -j zone_%s_dest_%s\n", rule->dest.name, target);
+               fw3_ipt_rule_target(r, "zone_%s_dest_%s", rule->dest.name, name);
        else if (rule->target == FW3_FLAG_REJECT)
-               fw3_pr(" -j reject\n");
+               fw3_ipt_rule_target(r, "reject");
        else
-               fw3_pr(" -j %s\n", target);
+               fw3_ipt_rule_target(r, name);
 }
 
 static void
-print_rule(struct fw3_state *state, enum fw3_family family,
-           enum fw3_table table, struct fw3_rule *rule,
-           struct fw3_protocol *proto,
+print_rule(struct fw3_ipt_handle *handle, struct fw3_state *state,
+           struct fw3_rule *rule, struct fw3_protocol *proto,
            struct fw3_address *sip, struct fw3_address *dip,
            struct fw3_port *sport, struct fw3_port *dport,
            struct fw3_mac *mac, struct fw3_icmptype *icmptype)
 {
-       if (!fw3_is_family(sip, family) || !fw3_is_family(dip, family))
+       struct fw3_ipt_rule *r;
+
+       if (!fw3_is_family(sip, handle->family) ||
+           !fw3_is_family(dip, handle->family))
        {
                info("     ! Skipping due to different family of ip address");
                return;
        }
 
-       if (proto->protocol == 58 && family == FW3_FAMILY_V4)
+       if (proto->protocol == 58 && handle->family == FW3_FAMILY_V4)
        {
                info("     ! Skipping due to different family of protocol");
                return;
        }
 
-       print_chain(rule);
-       fw3_format_ipset(rule->_ipset, rule->ipset.invert);
-       fw3_format_protocol(proto, family);
-       fw3_format_src_dest(sip, dip);
-       fw3_format_sport_dport(sport, dport);
-       fw3_format_icmptype(icmptype, family);
-       fw3_format_mac(mac);
-       fw3_format_limit(&rule->limit);
-       fw3_format_time(&rule->time);
-       fw3_format_mark(&rule->mark);
-       fw3_format_extra(rule->extra);
-       fw3_format_comment(rule->name);
-       print_target(rule);
+       r = fw3_ipt_rule_create(handle, proto, NULL, NULL, sip, dip);
+       fw3_ipt_rule_sport_dport(r, sport, dport);
+       fw3_ipt_rule_icmptype(r, icmptype);
+       fw3_ipt_rule_mac(r, mac);
+       fw3_ipt_rule_ipset(r, rule->_ipset, rule->ipset.invert);
+       fw3_ipt_rule_limit(r, &rule->limit);
+       fw3_ipt_rule_time(r, &rule->time);
+       fw3_ipt_rule_mark(r, &rule->mark);
+       set_target(r, rule);
+       fw3_ipt_rule_extra(r, rule->extra);
+       fw3_ipt_rule_comment(r, rule->name);
+       append_chain(r, rule);
 }
 
 static void
-expand_rule(struct fw3_state *state, enum fw3_family family,
-            enum fw3_table table, struct fw3_rule *rule, int num)
+expand_rule(struct fw3_ipt_handle *handle, struct fw3_state *state,
+            struct fw3_rule *rule, int num)
 {
        struct fw3_protocol *proto;
        struct fw3_address *sip;
@@ -337,12 +342,12 @@ expand_rule(struct fw3_state *state, enum fw3_family family,
        struct list_head empty;
        INIT_LIST_HEAD(&empty);
 
-       if (!fw3_is_family(rule, family))
+       if (!fw3_is_family(rule, handle->family))
                return;
 
-       if ((rule->target == FW3_FLAG_NOTRACK && table != FW3_TABLE_RAW) ||
-           (rule->target == FW3_FLAG_MARK && table != FW3_TABLE_MANGLE) ||
-               (rule->target < FW3_FLAG_NOTRACK && table != FW3_TABLE_FILTER))
+       if ((rule->target == FW3_FLAG_NOTRACK && handle->table != FW3_TABLE_RAW) ||
+           (rule->target == FW3_FLAG_MARK && handle->table != FW3_TABLE_MANGLE) ||
+               (rule->target < FW3_FLAG_NOTRACK && handle->table != FW3_TABLE_FILTER))
                return;
 
        if (rule->name)
@@ -350,8 +355,8 @@ expand_rule(struct fw3_state *state, enum fw3_family family,
        else
                info("   * Rule #%u", num);
 
-       if (!fw3_is_family(rule->_src, family) ||
-           !fw3_is_family(rule->_dest, family))
+       if (!fw3_is_family(rule->_src, handle->family) ||
+           !fw3_is_family(rule->_dest, handle->family))
        {
                info("     ! Skipping due to different family of zone");
                return;
@@ -359,7 +364,7 @@ expand_rule(struct fw3_state *state, enum fw3_family family,
 
        if (rule->_ipset)
        {
-               if (!fw3_is_family(rule->_ipset, family))
+               if (!fw3_is_family(rule->_ipset, handle->family))
                {
                        info("     ! Skipping due to different family in ipset");
                        return;
@@ -373,7 +378,7 @@ expand_rule(struct fw3_state *state, enum fw3_family family,
                        return;
                }
 
-               set(rule->_ipset->flags, family, family);
+               set(rule->_ipset->flags, handle->family, handle->family);
        }
 
        list_for_each_entry(proto, &rule->proto, list)
@@ -398,18 +403,17 @@ expand_rule(struct fw3_state *state, enum fw3_family family,
                fw3_foreach(dport, dports)
                fw3_foreach(mac, &rule->mac_src)
                fw3_foreach(icmptype, icmptypes)
-                       print_rule(state, family, table, rule, proto, sip, dip,
+                       print_rule(handle, state, rule, proto, sip, dip,
                                   sport, dport, mac, icmptype);
        }
 }
 
 void
-fw3_print_rules(struct fw3_state *state, enum fw3_family family,
-                enum fw3_table table)
+fw3_print_rules(struct fw3_ipt_handle *handle, struct fw3_state *state)
 {
        int num = 0;
        struct fw3_rule *rule;
 
        list_for_each_entry(rule, &state->rules, list)
-               expand_rule(state, family, table, rule, num++);
+               expand_rule(handle, state, rule, num++);
 }
diff --git a/rules.h b/rules.h
index 44a40f21cfe794709fba5fd86c048ffc2899929c..6d332fc61e5ca3002a49a70bc79a9f0335936994 100644 (file)
--- a/rules.h
+++ b/rules.h
 #include "zones.h"
 #include "ipsets.h"
 #include "utils.h"
+#include "iptables.h"
 
 extern const struct fw3_option fw3_rule_opts[];
 
 void fw3_load_rules(struct fw3_state *state, struct uci_package *p);
-void fw3_print_rules(struct fw3_state *state, enum fw3_family family,
-                     enum fw3_table table);
+void fw3_print_rules(struct fw3_ipt_handle *handle, struct fw3_state *state);
 
 #define fw3_free_rule(rule) \
        fw3_free_object(rule, fw3_rule_opts)
diff --git a/utils.c b/utils.c
index fc8c201c7b7958dffb3fbc39f1b628f821d056cd..19c0eda2e2e7fffa139fa0e580ed780fb94379cc 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -132,6 +132,32 @@ info(const char* format, ...)
        fprintf(stderr, "\n");
 }
 
+void *
+fw3_alloc(size_t size)
+{
+       void *mem;
+
+       mem = calloc(1, size);
+
+       if (!mem)
+               error("Out of memory while allocating %d bytes", size);
+
+       return mem;
+}
+
+char *
+fw3_strdup(const char *s)
+{
+       char *ns;
+
+       ns = strdup(s);
+
+       if (!ns)
+               error("Out of memory while duplicating string '%s'", s);
+
+       return ns;
+}
+
 const char *
 fw3_find_command(const char *cmd)
 {
diff --git a/utils.h b/utils.h
index 3573e14857b0cdc0cc240af3aa89779d99808c39..ea6a10598adc3ca02309e0d244c960d61c1bde80 100644 (file)
--- a/utils.h
+++ b/utils.h
@@ -69,6 +69,9 @@ void info(const char *format, ...);
                 (1<<FW3_TABLE_MANGLE)|(1<<FW3_TABLE_RAW))))
 
 
+void * fw3_alloc(size_t size);
+char * fw3_strdup(const char *s);
+
 const char * fw3_find_command(const char *cmd);
 
 bool fw3_stdout_pipe(void);
diff --git a/zones.c b/zones.c
index 1fd785bb15972fd1bc2f3c58bdd8afcd0950f04f..11ec56979aaceec7c1f1d43c332bf65724d5651e 100644 (file)
--- a/zones.c
+++ b/zones.c
        { FW3_FAMILY_##f, FW3_TABLE_##tbl, FW3_FLAG_##tgt, fmt }
 
 static const struct fw3_rule_spec zone_chains[] = {
-       C(ANY, FILTER, UNSPEC,        "zone_%1$s_input"),
-       C(ANY, FILTER, UNSPEC,        "zone_%1$s_output"),
-       C(ANY, FILTER, UNSPEC,        "zone_%1$s_forward"),
+       C(ANY, FILTER, UNSPEC,        "zone_%s_input"),
+       C(ANY, FILTER, UNSPEC,        "zone_%s_output"),
+       C(ANY, FILTER, UNSPEC,        "zone_%s_forward"),
 
-       C(ANY, FILTER, SRC_ACCEPT,    "zone_%1$s_src_ACCEPT"),
-       C(ANY, FILTER, SRC_REJECT,    "zone_%1$s_src_REJECT"),
-       C(ANY, FILTER, SRC_DROP,      "zone_%1$s_src_DROP"),
+       C(ANY, FILTER, SRC_ACCEPT,    "zone_%s_src_ACCEPT"),
+       C(ANY, FILTER, SRC_REJECT,    "zone_%s_src_REJECT"),
+       C(ANY, FILTER, SRC_DROP,      "zone_%s_src_DROP"),
 
-       C(ANY, FILTER, ACCEPT,        "zone_%1$s_dest_ACCEPT"),
-       C(ANY, FILTER, REJECT,        "zone_%1$s_dest_REJECT"),
-       C(ANY, FILTER, DROP,          "zone_%1$s_dest_DROP"),
+       C(ANY, FILTER, ACCEPT,        "zone_%s_dest_ACCEPT"),
+       C(ANY, FILTER, REJECT,        "zone_%s_dest_REJECT"),
+       C(ANY, FILTER, DROP,          "zone_%s_dest_DROP"),
 
-       C(V4,  NAT,    SNAT,          "zone_%1$s_postrouting"),
-       C(V4,  NAT,    DNAT,          "zone_%1$s_prerouting"),
+       C(V4,  NAT,    SNAT,          "zone_%s_postrouting"),
+       C(V4,  NAT,    DNAT,          "zone_%s_prerouting"),
 
-       C(ANY, FILTER, CUSTOM_CHAINS, "input_%1$s_rule"),
-       C(ANY, FILTER, CUSTOM_CHAINS, "output_%1$s_rule"),
-       C(ANY, FILTER, CUSTOM_CHAINS, "forwarding_%1$s_rule"),
+       C(ANY, FILTER, CUSTOM_CHAINS, "input_%s_rule"),
+       C(ANY, FILTER, CUSTOM_CHAINS, "output_%s_rule"),
+       C(ANY, FILTER, CUSTOM_CHAINS, "forwarding_%s_rule"),
 
-       C(V4,  NAT,    CUSTOM_CHAINS, "prerouting_%1$s_rule"),
-       C(V4,  NAT,    CUSTOM_CHAINS, "postrouting_%1$s_rule"),
-
-       { }
-};
-
-
-#define R(dir1, dir2) \
-       "zone_%1$s_" #dir1 " -m comment --comment \"user chain for %1$s " \
-       #dir2 "\" -j " #dir2 "_%1$s_rule"
-
-static const struct fw3_rule_spec zone_rules[] = {
-       C(ANY, FILTER, CUSTOM_CHAINS, R(input, input)),
-       C(ANY, FILTER, CUSTOM_CHAINS, R(output, output)),
-       C(ANY, FILTER, CUSTOM_CHAINS, R(forward, forwarding)),
-
-       C(V4,  NAT,    CUSTOM_CHAINS, R(prerouting, prerouting)),
-       C(V4,  NAT,    CUSTOM_CHAINS, R(postrouting, postrouting)),
+       C(V4,  NAT,    CUSTOM_CHAINS, "prerouting_%s_rule"),
+       C(V4,  NAT,    CUSTOM_CHAINS, "postrouting_%s_rule"),
 
        { }
 };
@@ -243,154 +227,207 @@ fw3_load_zones(struct fw3_state *state, struct uci_package *p)
 
 
 static void
-print_zone_chain(struct fw3_state *state, enum fw3_family family,
-                 enum fw3_table table, bool reload, struct fw3_zone *zone)
+print_zone_chain(struct fw3_ipt_handle *handle, struct fw3_state *state,
+                 bool reload, struct fw3_zone *zone)
 {
-       bool c, r;
-       uint32_t custom_mask = ~0;
+       int i;
+       struct fw3_ipt_rule *r;
+       const struct fw3_rule_spec *c;
+
+       const char *flt_chains[] = {
+               "input",   "input",
+               "output",  "output",
+               "forward", "forwarding",
+       };
 
-       if (!fw3_is_family(zone, family))
+       const char *nat_chains[] = {
+               "prerouting",  "prerouting",
+               "postrouting", "postrouting",
+       };
+
+       if (!fw3_is_family(zone, handle->family))
                return;
 
-       set(zone->flags, family, table);
+       info("   * Zone '%s'", zone->name);
 
-       /* Don't touch user chains on reload */
-       if (reload)
-               delbit(custom_mask, FW3_FLAG_CUSTOM_CHAINS);
+       set(zone->flags, handle->family, handle->table);
 
        if (zone->custom_chains)
-               set(zone->flags, family, FW3_FLAG_CUSTOM_CHAINS);
+               set(zone->flags, handle->family, FW3_FLAG_CUSTOM_CHAINS);
 
        if (!zone->conntrack && !state->defaults.drop_invalid)
-               set(zone->flags, family, FW3_FLAG_NOTRACK);
+               set(zone->flags, handle->family, FW3_FLAG_NOTRACK);
 
-       c = fw3_pr_rulespec(table, family, zone->flags, custom_mask, zone_chains,
-                           ":%s - [0:0]\n", zone->name);
+       for (c = zone_chains; c->format; c++)
+       {
+               /* don't touch user chains on selective stop */
+               if (reload && c->flag == FW3_FLAG_CUSTOM_CHAINS)
+                       continue;
 
-       r = fw3_pr_rulespec(table, family, zone->flags, 0, zone_rules,
-                           "-A %s\n", zone->name);
+               if (!fw3_is_family(c, handle->family))
+                       continue;
 
-       if (c || r)
-       {
-               info("   * Zone '%s'", zone->name);
+               if (c->table != handle->table)
+                       continue;
 
-               set(zone->flags, family, table);
+               if (c->flag &&
+                   !hasbit(zone->flags[handle->family == FW3_FAMILY_V6], c->flag))
+                       continue;
+
+               fw3_ipt_create_chain(handle, c->format, zone->name);
        }
+
+       if (zone->custom_chains)
+       {
+               if (handle->table == FW3_TABLE_FILTER)
+               {
+                       for (i = 0; i < sizeof(flt_chains)/sizeof(flt_chains[0]); i += 2)
+                       {
+                               r = fw3_ipt_rule_new(handle);
+                               fw3_ipt_rule_comment(r, "user chain for %s", flt_chains[i+1]);
+                               fw3_ipt_rule_target(r, "%s_%s_rule", flt_chains[i+1], zone->name);
+                               fw3_ipt_rule_append(r, "zone_%s_%s", zone->name, flt_chains[i]);
+                       }
+               }
+               else if (handle->table == FW3_TABLE_NAT)
+               {
+                       for (i = 0; i < sizeof(nat_chains)/sizeof(nat_chains[0]); i += 2)
+                       {
+                               r = fw3_ipt_rule_new(handle);
+                               fw3_ipt_rule_comment(r, "user chain for %s", nat_chains[i+1]);
+                               fw3_ipt_rule_target(r, "%s_%s_rule", nat_chains[i+1], zone->name);
+                               fw3_ipt_rule_append(r, "zone_%s_%s", zone->name, nat_chains[i]);
+                       }
+               }
+       }
+
+       set(zone->flags, handle->family, handle->table);
 }
 
 static void
-print_interface_rule(struct fw3_state *state, enum fw3_family family,
-                     enum fw3_table table, bool reload, struct fw3_zone *zone,
+print_interface_rule(struct fw3_ipt_handle *handle, struct fw3_state *state,
+                                        bool reload, struct fw3_zone *zone,
                      struct fw3_device *dev, struct fw3_address *sub)
 {
        bool disable_notrack = state->defaults.drop_invalid;
-
+       struct fw3_protocol tcp = { .protocol = 6 };
+       struct fw3_ipt_rule *r;
        enum fw3_flag t;
 
+       char buf[32];
+
+       int i;
+
+       const char *chains[] = {
+               "input",
+               "output",
+               "forward",
+       };
+
 #define jump_target(t) \
        ((t == FW3_FLAG_REJECT) ? "reject" : fw3_flag_names[t])
 
-       if (table == FW3_TABLE_FILTER)
+       if (handle->table == FW3_TABLE_FILTER)
        {
                for (t = FW3_FLAG_ACCEPT; t <= FW3_FLAG_DROP; t++)
                {
-                       if (has(zone->flags, family, fw3_to_src_target(t)))
+                       if (has(zone->flags, handle->family, fw3_to_src_target(t)))
                        {
-                               fw3_pr("-A zone_%s_src_%s", zone->name, fw3_flag_names[t]);
-                               fw3_format_in_out(dev, NULL);
-                               fw3_format_src_dest(sub, NULL);
-                               fw3_format_extra(zone->extra_src);
-                               fw3_pr(" -j %s\n", jump_target(t));
+                               r = fw3_ipt_rule_create(handle, NULL, dev, NULL, sub, NULL);
+                               fw3_ipt_rule_target(r, jump_target(t));
+                               fw3_ipt_rule_extra(r, zone->extra_src);
+                               fw3_ipt_rule_append(r, "zone_%s_src_%s", zone->name,
+                                                   fw3_flag_names[t]);
                        }
 
-                       if (has(zone->flags, family, t))
+                       if (has(zone->flags, handle->family, t))
                        {
-                               fw3_pr("-A zone_%s_dest_%s", zone->name, fw3_flag_names[t]);
-                               fw3_format_in_out(NULL, dev);
-                               fw3_format_src_dest(NULL, sub);
-                               fw3_format_extra(zone->extra_dest);
-                               fw3_pr(" -j %s\n", jump_target(t));
+                               r = fw3_ipt_rule_create(handle, NULL, NULL, dev, NULL, sub);
+                               fw3_ipt_rule_target(r, jump_target(t));
+                               fw3_ipt_rule_extra(r, zone->extra_dest);
+                               fw3_ipt_rule_append(r, "zone_%s_dest_%s", zone->name,
+                                                   fw3_flag_names[t]);
                        }
                }
 
-               fw3_pr("-A delegate_input");
-               fw3_format_in_out(dev, NULL);
-               fw3_format_src_dest(sub, NULL);
-               fw3_format_extra(zone->extra_src);
-               fw3_pr(" -j zone_%s_input\n", zone->name);
-
-               fw3_pr("-A delegate_forward");
-               fw3_format_in_out(dev, NULL);
-               fw3_format_src_dest(sub, NULL);
-               fw3_format_extra(zone->extra_src);
-               fw3_pr(" -j zone_%s_forward\n", zone->name);
-
-               fw3_pr("-A delegate_output");
-               fw3_format_in_out(NULL, dev);
-               fw3_format_src_dest(NULL, sub);
-               fw3_format_extra(zone->extra_dest);
-               fw3_pr(" -j zone_%s_output\n", zone->name);
+               for (i = 0; i < sizeof(chains)/sizeof(chains[0]); i++)
+               {
+                       if (*chains[i] == 'o')
+                               r = fw3_ipt_rule_create(handle, NULL, NULL, dev, NULL, sub);
+                       else
+                               r = fw3_ipt_rule_create(handle, NULL, dev, NULL, sub, NULL);
+
+                       fw3_ipt_rule_target(r, "zone_%s_%s", zone->name, chains[i]);
+
+                       if (*chains[i] == 'o')
+                               fw3_ipt_rule_extra(r, zone->extra_dest);
+                       else
+                               fw3_ipt_rule_extra(r, zone->extra_src);
+
+                       fw3_ipt_rule_append(r, "delegate_%s", chains[i]);
+               }
        }
-       else if (table == FW3_TABLE_NAT)
+       else if (handle->table == FW3_TABLE_NAT)
        {
-               if (has(zone->flags, family, FW3_FLAG_DNAT))
+               if (has(zone->flags, handle->family, FW3_FLAG_DNAT))
                {
-                       fw3_pr("-A delegate_prerouting");
-                       fw3_format_in_out(dev, NULL);
-                       fw3_format_src_dest(sub, NULL);
-                       fw3_format_extra(zone->extra_src);
-                       fw3_pr(" -j zone_%s_prerouting\n", zone->name);
+                       r = fw3_ipt_rule_create(handle, NULL, dev, NULL, sub, NULL);
+                       fw3_ipt_rule_target(r, "zone_%s_prerouting", zone->name);
+                       fw3_ipt_rule_extra(r, zone->extra_src);
+                       fw3_ipt_rule_append(r, "delegate_prerouting");
                }
 
-               if (has(zone->flags, family, FW3_FLAG_SNAT))
+               if (has(zone->flags, handle->family, FW3_FLAG_SNAT))
                {
-                       fw3_pr("-A delegate_postrouting");
-                       fw3_format_in_out(NULL, dev);
-                       fw3_format_src_dest(NULL, sub);
-                       fw3_format_extra(zone->extra_dest);
-                       fw3_pr(" -j zone_%s_postrouting\n", zone->name);
+                       r = fw3_ipt_rule_create(handle, NULL, NULL, dev, NULL, sub);
+                       fw3_ipt_rule_target(r, "zone_%s_postrouting", zone->name);
+                       fw3_ipt_rule_extra(r, zone->extra_dest);
+                       fw3_ipt_rule_append(r, "delegate_postrouting");
                }
        }
-       else if (table == FW3_TABLE_MANGLE)
+       else if (handle->table == FW3_TABLE_MANGLE)
        {
                if (zone->mtu_fix)
                {
                        if (zone->log)
                        {
-                               fw3_pr("-A mssfix");
-                               fw3_format_in_out(NULL, dev);
-                               fw3_format_src_dest(NULL, sub);
-                               fw3_pr(" -p tcp --tcp-flags SYN,RST SYN");
-                               fw3_format_limit(&zone->log_limit);
-                               fw3_format_comment(zone->name, " (mtu_fix logging)");
-                               fw3_pr(" -j LOG --log-prefix \"MSSFIX(%s): \"\n", zone->name);
+                               snprintf(buf, sizeof(buf) - 1, "MSSFIX(%s): ", zone->name);
+
+                               r = fw3_ipt_rule_create(handle, &tcp, NULL, dev, NULL, sub);
+                               fw3_ipt_rule_addarg(r, false, "--tcp-flags", "SYN,RST");
+                               fw3_ipt_rule_addarg(r, false, "SYN", NULL);
+                               fw3_ipt_rule_limit(r, &zone->log_limit);
+                               fw3_ipt_rule_comment(r, "%s (mtu_fix logging)", zone->name);
+                               fw3_ipt_rule_target(r, "LOG");
+                               fw3_ipt_rule_addarg(r, false, "--log-prefix", buf);
+                               fw3_ipt_rule_append(r, "mssfix");
                        }
 
-                       fw3_pr("-A mssfix");
-                       fw3_format_in_out(NULL, dev);
-                       fw3_format_src_dest(NULL, sub);
-                       fw3_pr(" -p tcp --tcp-flags SYN,RST SYN");
-                       fw3_format_comment(zone->name, " (mtu_fix)");
-                       fw3_pr(" -j TCPMSS --clamp-mss-to-pmtu\n");
+                       r = fw3_ipt_rule_create(handle, &tcp, NULL, dev, NULL, sub);
+                       fw3_ipt_rule_addarg(r, false, "--tcp-flags", "SYN,RST");
+                       fw3_ipt_rule_addarg(r, false, "SYN", NULL);
+                       fw3_ipt_rule_comment(r, "%s (mtu_fix)", zone->name);
+                       fw3_ipt_rule_target(r, "TCPMSS");
+                       fw3_ipt_rule_addarg(r, false, "--clamp-mss-to-pmtu", NULL);
+                       fw3_ipt_rule_append(r, "mssfix");
                }
        }
-       else if (table == FW3_TABLE_RAW)
+       else if (handle->table == FW3_TABLE_RAW)
        {
                if (!zone->conntrack && !disable_notrack)
                {
-                       fw3_pr("-A notrack");
-                       fw3_format_in_out(dev, NULL);
-                       fw3_format_src_dest(sub, NULL);
-                       fw3_format_extra(zone->extra_src);
-                       fw3_format_comment(zone->name, " (notrack)");
-                       fw3_pr(" -j CT --notrack\n", zone->name);
+                       r = fw3_ipt_rule_create(handle, NULL, dev, NULL, sub, NULL);
+                       fw3_ipt_rule_target(r, "CT");
+                       fw3_ipt_rule_addarg(r, false, "--notrack", NULL);
+                       fw3_ipt_rule_extra(r, zone->extra_src);
+                       fw3_ipt_rule_append(r, "notrack");
                }
        }
 }
 
 static void
-print_interface_rules(struct fw3_state *state, enum fw3_family family,
-                      enum fw3_table table, bool reload, struct fw3_zone *zone)
+print_interface_rules(struct fw3_ipt_handle *handle, struct fw3_state *state,
+                      bool reload, struct fw3_zone *zone)
 {
        struct fw3_device *dev;
        struct fw3_address *sub;
@@ -398,76 +435,97 @@ print_interface_rules(struct fw3_state *state, enum fw3_family family,
        fw3_foreach(dev, &zone->devices)
        fw3_foreach(sub, &zone->subnets)
        {
-               if (!fw3_is_family(sub, family))
+               if (!fw3_is_family(sub, handle->family))
                        continue;
 
                if (!dev && !sub)
                        continue;
 
-               print_interface_rule(state, family, table, reload, zone, dev, sub);
+               print_interface_rule(handle, state, reload, zone, dev, sub);
        }
 }
 
 static void
-print_zone_rule(struct fw3_state *state, enum fw3_family family,
-                enum fw3_table table, bool reload, struct fw3_zone *zone)
+print_zone_rule(struct fw3_ipt_handle *handle, struct fw3_state *state,
+                bool reload, struct fw3_zone *zone)
 {
        struct fw3_address *msrc;
        struct fw3_address *mdest;
+       struct fw3_ipt_rule *r;
 
        enum fw3_flag t;
+       char buf[32];
 
-       if (!fw3_is_family(zone, family))
+       if (!fw3_is_family(zone, handle->family))
                return;
 
-       switch (table)
+       switch (handle->table)
        {
        case FW3_TABLE_FILTER:
-               fw3_pr("-A zone_%s_input -j zone_%s_src_%s\n",
-                          zone->name, zone->name, fw3_flag_names[zone->policy_input]);
+               r = fw3_ipt_rule_new(handle);
+               fw3_ipt_rule_target(r, "zone_%s_src_%s", zone->name,
+                                    fw3_flag_names[zone->policy_input]);
+               fw3_ipt_rule_append(r, "zone_%s_input", zone->name);
 
-               fw3_pr("-A zone_%s_forward -j zone_%s_dest_%s\n",
-                          zone->name, zone->name, fw3_flag_names[zone->policy_forward]);
+               r = fw3_ipt_rule_new(handle);
+               fw3_ipt_rule_target(r, "zone_%s_dest_%s", zone->name,
+                                    fw3_flag_names[zone->policy_forward]);
+               fw3_ipt_rule_append(r, "zone_%s_forward", zone->name);
 
-               fw3_pr("-A zone_%s_output -j zone_%s_dest_%s\n",
-                          zone->name, zone->name, fw3_flag_names[zone->policy_output]);
+               r = fw3_ipt_rule_new(handle);
+               fw3_ipt_rule_target(r, "zone_%s_dest_%s", zone->name,
+                                    fw3_flag_names[zone->policy_output]);
+               fw3_ipt_rule_append(r, "zone_%s_output", zone->name);
 
                if (zone->log)
                {
                        for (t = FW3_FLAG_REJECT; t <= FW3_FLAG_DROP; t++)
                        {
-                               if (has(zone->flags, family, fw3_to_src_target(t)))
+                               if (has(zone->flags, handle->family, fw3_to_src_target(t)))
                                {
-                                       fw3_pr("-A zone_%s_src_%s", zone->name, fw3_flag_names[t]);
-                                       fw3_format_limit(&zone->log_limit);
-                                       fw3_pr(" -j LOG --log-prefix \"%s(src %s)\"\n",
-                                                  fw3_flag_names[t], zone->name);
+                                       r = fw3_ipt_rule_new(handle);
+
+                                       snprintf(buf, sizeof(buf) - 1, "%s(src %s)",
+                                                fw3_flag_names[t], zone->name);
+
+                                       fw3_ipt_rule_limit(r, &zone->log_limit);
+                                       fw3_ipt_rule_target(r, "LOG");
+                                       fw3_ipt_rule_addarg(r, false, "--log-prefix", buf);
+                                       fw3_ipt_rule_append(r, "zone_%s_src_%s",
+                                                           zone->name, fw3_flag_names[t]);
                                }
 
-                               if (has(zone->flags, family, t))
+                               if (has(zone->flags, handle->family, t))
                                {
-                                       fw3_pr("-A zone_%s_dest_%s", zone->name, fw3_flag_names[t]);
-                                       fw3_format_limit(&zone->log_limit);
-                                       fw3_pr(" -j LOG --log-prefix \"%s(dest %s)\"\n",
-                                                  fw3_flag_names[t], zone->name);
+                                       r = fw3_ipt_rule_new(handle);
+
+                                       snprintf(buf, sizeof(buf) - 1, "%s(dest %s)",
+                                                fw3_flag_names[t], zone->name);
+
+                                       fw3_ipt_rule_limit(r, &zone->log_limit);
+                                       fw3_ipt_rule_target(r, "LOG");
+                                       fw3_ipt_rule_addarg(r, false, "--log-prefix", buf);
+                                       fw3_ipt_rule_append(r, "zone_%s_dest_%s",
+                                                           zone->name, fw3_flag_names[t]);
                                }
                        }
                }
                break;
 
        case FW3_TABLE_NAT:
-               if (zone->masq && family == FW3_FAMILY_V4)
+               if (zone->masq && handle->family == FW3_FAMILY_V4)
                {
                        fw3_foreach(msrc, &zone->masq_src)
                        fw3_foreach(mdest, &zone->masq_dest)
                        {
-                               if (!fw3_is_family(msrc, family) ||
-                                   !fw3_is_family(mdest, family))
+                               if (!fw3_is_family(msrc, handle->family) ||
+                                   !fw3_is_family(mdest, handle->family))
                                        continue;
 
-                               fw3_pr("-A zone_%s_postrouting", zone->name);
-                               fw3_format_src_dest(msrc, mdest);
-                               fw3_pr(" -j MASQUERADE\n");
+                               r = fw3_ipt_rule_new(handle);
+                               fw3_ipt_rule_src_dest(r, msrc, mdest);
+                               fw3_ipt_rule_target(r, "MASQUERADE");
+                               fw3_ipt_rule_append(r, "zone_%s_postrouting", zone->name);
                        }
                }
                break;
@@ -477,27 +535,27 @@ print_zone_rule(struct fw3_state *state, enum fw3_family family,
                break;
        }
 
-       print_interface_rules(state, family, table, reload, zone);
+       print_interface_rules(handle, state, reload, zone);
 }
 
 void
-fw3_print_zone_chains(struct fw3_state *state, enum fw3_family family,
-                      enum fw3_table table, bool reload)
+fw3_print_zone_chains(struct fw3_ipt_handle *handle, struct fw3_state *state,
+                      bool reload)
 {
        struct fw3_zone *zone;
 
        list_for_each_entry(zone, &state->zones, list)
-               print_zone_chain(state, family, table, reload, zone);
+               print_zone_chain(handle, state, reload, zone);
 }
 
 void
-fw3_print_zone_rules(struct fw3_state *state, enum fw3_family family,
-                     enum fw3_table table, bool reload)
+fw3_print_zone_rules(struct fw3_ipt_handle *handle, struct fw3_state *state,
+                     bool reload)
 {
        struct fw3_zone *zone;
 
        list_for_each_entry(zone, &state->zones, list)
-               print_zone_rule(state, family, table, reload, zone);
+               print_zone_rule(handle, state, reload, zone);
 }
 
 void
diff --git a/zones.h b/zones.h
index 353f08926f7e9634ab23d8885bfd93e17c1e9f78..b78aa32ece58043e02db9c18fe4a1e94a1eaf9c4 100644 (file)
--- a/zones.h
+++ b/zones.h
@@ -28,11 +28,11 @@ struct fw3_zone * fw3_alloc_zone(void);
 
 void fw3_load_zones(struct fw3_state *state, struct uci_package *p);
 
-void fw3_print_zone_chains(struct fw3_state *state, enum fw3_family family,
-                           enum fw3_table table, bool reload);
+void fw3_print_zone_chains(struct fw3_ipt_handle *handle,
+                           struct fw3_state *state, bool reload);
 
-void fw3_print_zone_rules(struct fw3_state *state, enum fw3_family family,
-                          enum fw3_table table, bool reload);
+void fw3_print_zone_rules(struct fw3_ipt_handle *handle,
+                          struct fw3_state *state, bool reload);
 
 void fw3_flush_zones(struct fw3_ipt_handle *handle, struct fw3_state *state,
                      bool reload);