contrib: remove abandonned projects
[project/luci.git] / contrib / fwd / src / fwd_rules.c
diff --git a/contrib/fwd/src/fwd_rules.c b/contrib/fwd/src/fwd_rules.c
deleted file mode 100644 (file)
index b960e62..0000000
+++ /dev/null
@@ -1,886 +0,0 @@
-/*
- * fwd - OpenWrt firewall daemon - iptables rule set
- *
- *   Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
- *
- * The fwd program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * The fwd program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with the fwd program. If not, see http://www.gnu.org/licenses/.
- */
-
-
-#include "fwd.h"
-#include "fwd_addr.h"
-#include "fwd_rules.h"
-#include "fwd_xtables.h"
-#include "fwd_utils.h"
-
-
-/* -P <chain> <policy> */
-static void fwd_r_set_policy(
-       struct iptc_handle *h, const char *chain, const char *policy
-) {
-       iptc_set_policy(chain, policy, NULL, h);
-}
-
-/* -N <chain> */
-static void fwd_r_new_chain(struct iptc_handle *h, const char *chain)
-{
-       iptc_create_chain(chain, h);
-}
-
-/* -A <chain1> -j <chain2> */
-static void fwd_r_jump_chain(
-       struct iptc_handle *h, const char *chain1, const char *chain2
-) {
-       struct fwd_xt_rule *r;
-
-       if( (r = fwd_xt_init_rule(h)) != NULL )
-       {
-               fwd_xt_get_target(r, chain2);
-               fwd_xt_append_rule(r, chain1);
-       }
-}
-
-/* -A <chain> -m state --state INVALID -j DROP */
-static void fwd_r_drop_invalid(struct iptc_handle *h, const char *chain)
-{
-       struct fwd_xt_rule *r;
-       struct xtables_match *m;
-
-       if( (r = fwd_xt_init_rule(h)) != NULL )
-       {
-               if( (m = fwd_xt_get_match(r, "state")) != NULL )
-               {
-                       fwd_xt_parse_match(r, m, "--state", "INVALID");
-                       fwd_xt_get_target(r, "DROP");
-                       fwd_xt_append_rule(r, chain);
-               }
-       }
-}
-
-/* -A <chain> -m state --state RELATED,ESTABLISHED -j ACCEPT */
-static void fwd_r_accept_related(struct iptc_handle *h, const char *chain)
-{
-       struct fwd_xt_rule *r;
-       struct xtables_match *m;
-
-       if( (r = fwd_xt_init_rule(h)) != NULL )
-       {
-               if( (m = fwd_xt_get_match(r, "state")) != NULL )
-               {
-                       fwd_xt_parse_match(r, m, "--state", "RELATED,ESTABLISHED");
-                       fwd_xt_get_target(r, "ACCEPT");
-                       fwd_xt_append_rule(r, chain);
-               }
-       }
-}
-
-/* -A INPUT -i lo -j ACCEPT; -A OUTPUT -o lo -j ACCEPT */
-static void fwd_r_accept_lo(struct iptc_handle *h)
-{
-       struct fwd_network n;
-       struct fwd_xt_rule *r;
-
-       n.ifname = "lo";
-
-       if( (r = fwd_xt_init_rule(h)) != NULL )
-       {
-               fwd_xt_parse_in(r, &n, 0);
-               fwd_xt_get_target(r, "ACCEPT");
-               fwd_xt_append_rule(r, "INPUT");
-       }
-
-       if( (r = fwd_xt_init_rule(h)) != NULL )
-       {
-               fwd_xt_parse_out(r, &n, 0);
-               fwd_xt_get_target(r, "ACCEPT");
-               fwd_xt_append_rule(r, "OUTPUT");
-       }
-}
-
-/* build syn_flood chain and jump rule */
-static void fwd_r_add_synflood(struct iptc_handle *h, struct fwd_defaults *def)
-{
-       struct fwd_proto p;
-       struct fwd_xt_rule *r;
-       struct xtables_match *m;
-       char buf[32];
-
-       /* -N syn_flood */
-       fwd_r_new_chain(h, "syn_flood");
-
-       /* return rule */
-       if( (r = fwd_xt_init_rule(h)) != NULL )
-       {
-               /* -p tcp */
-               p.type = FWD_PR_TCP;
-               fwd_xt_parse_proto(r, &p, 0);
-
-               /* -m tcp --syn */
-               if( (m = fwd_xt_get_match(r, "tcp")) != NULL )
-               {
-                       fwd_xt_parse_match(r, m, "--syn");
-               }
-
-               /* -m limit --limit x/second --limit-burst y */
-               if( (m = fwd_xt_get_match(r, "limit")) != NULL )
-               {
-                       sprintf(buf, "%i/second", def->syn_rate);
-                       fwd_xt_parse_match(r, m, "--limit", buf);
-
-                       sprintf(buf, "%i", def->syn_burst);
-                       fwd_xt_parse_match(r, m, "--limit-burst", buf);
-               }
-
-               /* -j RETURN; -A syn_flood */
-               fwd_xt_get_target(r, "RETURN");
-               fwd_xt_append_rule(r, "syn_flood");
-       }
-
-       /* drop rule */
-       if( (r = fwd_xt_init_rule(h)) != NULL )
-       {       
-               /* -j DROP; -A syn_flood */
-               fwd_xt_get_target(r, "DROP");
-               fwd_xt_append_rule(r, "syn_flood");
-       }
-
-       /* jump to syn_flood rule */
-       if( (r = fwd_xt_init_rule(h)) != NULL )
-       {       
-               /* -p tcp */
-               p.type = FWD_PR_TCP;
-               fwd_xt_parse_proto(r, &p, 0);
-
-               /* -m tcp --syn */
-               if( (m = fwd_xt_get_match(r, "tcp")) != NULL )
-               {
-                       fwd_xt_parse_match(r, m, "--syn");
-               }
-
-               /* -j syn_flood; -A INPUT */
-               fwd_xt_get_target(r, "syn_flood");
-               fwd_xt_append_rule(r, "INPUT");
-       }
-}
-
-/* build reject target chain */
-static void fwd_r_handle_reject(struct iptc_handle *h)
-{
-       struct fwd_proto p;
-       struct fwd_xt_rule *r;
-       struct xtables_target *t;
-
-       /* -N handle_reject */
-       fwd_r_new_chain(h, "handle_reject");
-
-       /* tcp reject rule */
-       if( (r = fwd_xt_init_rule(h)) != NULL )
-       {
-               /* -p tcp */
-               p.type = FWD_PR_TCP;
-               fwd_xt_parse_proto(r, &p, 0);
-
-               /* -j REJECT --reject-with tcp-reset */
-               if( (t = fwd_xt_get_target(r, "REJECT")) != NULL )
-               {
-                       fwd_xt_parse_target(r, t, "--reject-with", "tcp-reset");
-               }
-
-               /* -A handle_reject */
-               fwd_xt_append_rule(r, "handle_reject");
-       }
-
-       /* common reject rule */
-       if( (r = fwd_xt_init_rule(h)) != NULL )
-       {
-               /* -j REJECT --reject-with icmp-port-unreachable */
-               if( (t = fwd_xt_get_target(r, "REJECT")) != NULL )
-               {
-                       fwd_xt_parse_target(r, t, "--reject-with",
-                               "icmp-port-unreachable");
-               }
-
-               /* -A handle_reject */
-               fwd_xt_append_rule(r, "handle_reject");
-       }
-}
-
-/* build drop target chain */
-static void fwd_r_handle_drop(struct iptc_handle *h)
-{
-       struct fwd_xt_rule *r;
-
-       /* -N handle_drop */
-       fwd_r_new_chain(h, "handle_drop");
-
-       /* common drop rule */
-       if( (r = fwd_xt_init_rule(h)) != NULL )
-       {
-               /* -j DROP; -A handle_drop */
-               fwd_xt_get_target(r, "DROP");
-               fwd_xt_append_rule(r, "handle_drop");
-       }
-}
-
-/* build accept target chain */
-static void fwd_r_handle_accept(struct iptc_handle *h)
-{
-       struct fwd_xt_rule *r;
-
-       /* -N handle_accept */
-       fwd_r_new_chain(h, "handle_accept");
-
-       /* common accept rule */
-       if( (r = fwd_xt_init_rule(h)) != NULL )
-       {
-               /* -j ACCEPT; -A handle_accept */
-               fwd_xt_get_target(r, "ACCEPT");
-               fwd_xt_append_rule(r, "handle_accept");
-       }
-}
-
-/* add comment match */
-static void fwd_r_add_comment(
-       struct fwd_xt_rule *r, const char *t, struct fwd_zone *z,
-       struct fwd_network *n
-) {
-       struct xtables_match *m;
-       char buf[256];
-
-       if( (m = fwd_xt_get_match(r, "comment")) != NULL )
-       {
-               snprintf(buf, sizeof(buf), "%s:net=%s zone=%s", t, n->name, z->name);
-               fwd_xt_parse_match(r, m, "--comment", buf);
-       }
-}
-
-/* add --sport (if applicable) */
-static void fwd_r_add_sport(
-       struct fwd_xt_rule *r, struct fwd_portrange *p
-) {
-       int proto = r->entry->ip.proto;
-       char buf[12];
-       struct xtables_match *m;
-
-       /* have portrange and proto is tcp or udp ... */
-       if( (p != NULL) && ((proto == 6) || (proto == 17)) )
-       {
-               /* get match ... */
-               if( (m = fwd_xt_get_match(r, (proto == 6) ? "tcp" : "udp")) != NULL )
-               {
-                       snprintf(buf, sizeof(buf), "%u:%u", p->min, p->max);
-                       fwd_xt_parse_match(r, m, "--sport", buf);
-               }
-       }
-}
-
-/* add --dport (if applicable) */
-static void fwd_r_add_dport(
-       struct fwd_xt_rule *r, struct fwd_portrange *p
-) {
-       int proto = r->entry->ip.proto;
-       char buf[12];
-       struct xtables_match *m;
-
-       /* have portrange and proto is tcp or udp ... */
-       if( (p != NULL) && ((proto == 6) || (proto == 17)) )
-       {
-               /* get match ... */
-               if( (m = fwd_xt_get_match(r, (proto == 6) ? "tcp" : "udp")) != NULL )
-               {
-                       snprintf(buf, sizeof(buf), "%u:%u", p->min, p->max);
-                       fwd_xt_parse_match(r, m, "--dport", buf);
-               }
-       }
-}
-
-/* add --icmp-type (of applicable) */
-static void fwd_r_add_icmptype(
-       struct fwd_xt_rule *r, struct fwd_icmptype *i
-) {
-       int proto = r->entry->ip.proto;
-       struct xtables_match *m;
-       char buf[32];
-
-       /* have icmp-type and proto is icmp ... */
-       if( (i != NULL) && (proto == 1) )
-       {
-               /* get match ... */
-               if( (m = fwd_xt_get_match(r, "icmp")) != NULL )
-               {
-                       if( i->name[0] )
-                               snprintf(buf, sizeof(buf), "%s", i->name);
-                       else
-                               snprintf(buf, sizeof(buf), "%u/%u", i->type, i->code);
-
-                       fwd_xt_parse_match(r, m, "--icmp-type", buf);
-               }
-       }
-}
-
-/* add -m mac --mac-source ... */
-static void fwd_r_add_srcmac(
-       struct fwd_xt_rule *r, struct fwd_mac *mac
-) {
-       struct xtables_match *m;
-       char buf[18];
-
-       if( mac != NULL )
-       {
-               if( (m = fwd_xt_get_match(r, "mac")) != NULL )
-               {
-                       snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
-                               mac->mac[0], mac->mac[1], mac->mac[2],
-                               mac->mac[3], mac->mac[4], mac->mac[5]);
-
-                       fwd_xt_parse_match(r, m, "--mac-source", buf);
-               }
-       }
-}
-
-/* add policy target */
-static void fwd_r_add_policytarget(
-       struct fwd_xt_rule *r, enum fwd_policy pol
-) {
-       switch(pol)
-       {
-               case FWD_P_ACCEPT:
-                       fwd_xt_get_target(r, "handle_accept");
-                       break;
-
-               case FWD_P_REJECT:
-                       fwd_xt_get_target(r, "handle_reject");
-                       break;
-
-               case FWD_P_DROP:
-               case FWD_P_UNSPEC:
-                       fwd_xt_get_target(r, "handle_drop");
-                       break;
-       }
-}
-
-/* add dnat target */
-static void fwd_r_add_dnattarget(
-       struct fwd_xt_rule *r, struct fwd_cidr *c, struct fwd_portrange *p
-) {
-       struct xtables_target *t;
-       char buf[32];
-
-       if( c != NULL )
-       {
-               if( (t = fwd_xt_get_target(r, "DNAT")) != NULL )
-               {
-                       if( p != NULL )
-                               snprintf(buf, sizeof(buf), "%s:%u-%u",
-                                       inet_ntoa(c->addr), p->min, p->max);
-                       else
-                               snprintf(buf, sizeof(buf), "%s", inet_ntoa(c->addr));
-
-                       fwd_xt_parse_target(r, t, "--to-destination", buf);
-               }
-       }
-}
-
-/* parse comment string and look for match */
-static int fwd_r_cmp(const char *what, const char *cmt, const char *cmp)
-{
-       char *match;
-
-       if( (match = strstr(cmt, what)) == NULL )
-               return 0;
-
-       match += strlen(what);
-
-       if( strncmp(match, cmp, strlen(cmp)) != 0 )
-               return 0;
-
-       if( (match[strlen(cmp)] != ' ') && (match[strlen(cmp)] != '\0') )
-               return 0;
-
-       return 1;
-}
-
-
-static void fwd_ipt_defaults_create(struct fwd_data *d)
-{
-       struct fwd_defaults *def = &d->section.defaults;
-       struct iptc_handle *h_filter, *h_nat;
-
-       if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) )
-               fwd_fatal("Unable to obtain libiptc handle");
-
-       /* policies */
-       fwd_r_set_policy(h_filter, "INPUT",
-               def->input == FWD_P_ACCEPT ? "ACCEPT" : "DROP");
-       fwd_r_set_policy(h_filter, "OUTPUT",
-               def->output == FWD_P_ACCEPT ? "ACCEPT" : "DROP");
-       fwd_r_set_policy(h_filter, "FORWARD",
-               def->forward == FWD_P_ACCEPT ? "ACCEPT" : "DROP");
-
-       /* invalid state drop */
-       if( def->drop_invalid )
-       {
-               fwd_r_drop_invalid(h_filter, "INPUT");
-               fwd_r_drop_invalid(h_filter, "OUTPUT");
-               fwd_r_drop_invalid(h_filter, "FORWARD");
-       }
-
-       /* default accept related */
-       fwd_r_accept_related(h_filter, "INPUT");
-       fwd_r_accept_related(h_filter, "OUTPUT");
-       fwd_r_accept_related(h_filter, "FORWARD");
-
-       /* default accept on lo */
-       fwd_r_accept_lo(h_filter);
-
-       /* syn flood protection */
-       if( def->syn_flood )
-       {
-               fwd_r_add_synflood(h_filter, def);
-       }
-
-       /* rule container chains */
-       fwd_r_new_chain(h_filter, "mssfix");
-       fwd_r_new_chain(h_filter, "zones");
-       fwd_r_new_chain(h_filter, "rules");
-       fwd_r_new_chain(h_filter, "redirects");
-       fwd_r_new_chain(h_filter, "forwardings");
-       fwd_r_jump_chain(h_filter, "INPUT", "rules");
-       fwd_r_jump_chain(h_filter, "FORWARD", "mssfix");
-       fwd_r_jump_chain(h_filter, "FORWARD", "zones");
-       fwd_r_jump_chain(h_filter, "FORWARD", "rules");
-       fwd_r_jump_chain(h_filter, "FORWARD", "redirects");
-       fwd_r_jump_chain(h_filter, "FORWARD", "forwardings");
-       fwd_r_new_chain(h_nat, "zonemasq");
-       fwd_r_new_chain(h_nat, "redirects");
-       fwd_r_new_chain(h_nat, "loopback");
-       fwd_r_jump_chain(h_nat, "POSTROUTING", "zonemasq");
-       fwd_r_jump_chain(h_nat, "PREROUTING", "redirects");
-       fwd_r_jump_chain(h_nat, "POSTROUTING", "loopback");
-
-       /* standard drop, accept, reject chain */
-       fwd_r_handle_drop(h_filter);
-       fwd_r_handle_accept(h_filter);
-       fwd_r_handle_reject(h_filter);
-
-
-       if( !iptc_commit(h_nat) )
-               fwd_fatal("Cannot commit nat table: %s", iptc_strerror(errno));
-
-       if( !iptc_commit(h_filter) )
-               fwd_fatal("Cannot commit filter table: %s", iptc_strerror(errno));
-
-       iptc_free(h_nat);
-       iptc_free(h_filter);
-}
-
-
-void fwd_ipt_build_ruleset(struct fwd_handle *h)
-{
-       struct fwd_data *e;
-
-       fwd_xt_init();
-
-       for( e = h->conf; e; e = e->next )
-       {
-               switch(e->type)
-               {
-                       case FWD_S_DEFAULTS:
-                               fwd_log_info("Loading defaults");
-                               fwd_ipt_defaults_create(e);
-                               break;
-
-                       case FWD_S_INCLUDE:
-                               fwd_log_info("Loading include: %s",
-                                       e->section.include.path);
-                               break;
-
-                       case FWD_S_ZONE:
-                       case FWD_S_FORWARD:
-                       case FWD_S_REDIRECT:
-                       case FWD_S_RULE:
-                               /* Make gcc happy */
-                               break;
-               }
-       }
-}
-
-
-static struct fwd_zone *
-fwd_lookup_zone(struct fwd_handle *h, const char *net)
-{
-       struct fwd_data *e;
-       struct fwd_network *n;
-
-       for( e = h->conf; e; e = e->next )
-               if( e->type == FWD_S_ZONE )
-                       for( n = e->section.zone.networks; n; n = n->next )
-                               if( !strcmp(n->name, net) )
-                                       return &e->section.zone;
-
-       return NULL;
-}
-
-static struct fwd_network *
-fwd_lookup_network(struct fwd_zone *z, const char *net)
-{
-       struct fwd_network *n;
-
-       for( n = z->networks; n; n = n->next )
-               if( !strcmp(n->name, net) )
-                       return n;
-
-       return NULL;
-}
-
-void fwd_ipt_addif(struct fwd_handle *h, const char *net)
-{
-       struct fwd_data *e;
-       struct fwd_zone *z;
-       struct fwd_rule *c;
-       struct fwd_redirect *r;
-       struct fwd_forwarding *f;
-       struct fwd_cidr *a, *a2;
-       struct fwd_network *n, *n2;
-       struct fwd_proto p;
-
-       struct fwd_xt_rule *x;
-       struct xtables_match *m;
-       struct xtables_target *t;
-
-       struct iptc_handle *h_filter, *h_nat;
-
-       if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) )
-               fwd_fatal("Unable to obtain libiptc handle");
-
-
-       if( !(z = fwd_lookup_zone(h, net)) )
-               return;
-
-       if( !(n = fwd_lookup_network(z, net)) )
-               return;
-
-       if( !(a = n->addr) || fwd_empty_cidr(a) )
-               return;
-
-
-       fwd_log_info("Adding network %s (interface %s)",
-               n->name, n->ifname);
-
-       /* Build masquerading rule */
-       if( z->masq )
-       {
-               if( (x = fwd_xt_init_rule(h_nat)) != NULL )
-               {
-                       fwd_xt_parse_out(x, n, 0);                              /* -o ... */
-                       fwd_xt_get_target(x, "MASQUERADE");             /* -j MASQUERADE */
-                       fwd_r_add_comment(x, "masq", z, n);             /* -m comment ... */
-                       fwd_xt_append_rule(x, "zonemasq");              /* -A zonemasq */
-               }
-       }
-
-       /* Build MSS fix rule */
-       if( z->mtu_fix )
-       {
-               if( (x = fwd_xt_init_rule(h_filter)) != NULL )
-               {
-                       p.type = FWD_PR_TCP;
-                       fwd_xt_parse_out(x, n, 0);                                      /* -o ... */
-                       fwd_xt_parse_proto(x, &p, 0);                           /* -p tcp */
-
-                       /* -m tcp --tcp-flags SYN,RST SYN */
-                       if( (m = fwd_xt_get_match(x, "tcp")) != NULL )
-                               fwd_xt_parse_match(x, m, "--tcp-flags", "SYN,RST", "SYN");
-
-                       /* -j TCPMSS --clamp-mss-to-pmtu */
-                       if( (t = fwd_xt_get_target(x, "TCPMSS")) != NULL )
-                               fwd_xt_parse_target(x, t, "--clamp-mss-to-pmtu");
-
-                       /* -m comment ... */
-                       fwd_r_add_comment(x, "mssfix", z, n);
-
-                       /* -A mssfix */
-                       fwd_xt_append_rule(x, "mssfix");
-               }
-       }
-
-       /* Build intra-zone forwarding rules */
-       for( n2 = z->networks; n2; n2 = n2->next )
-       {
-               if( (a2 = n2->addr) != NULL )
-               {
-                       if( (x = fwd_xt_init_rule(h_filter)) != NULL )
-                       {
-                               fwd_xt_parse_in(x, n, 0);                               /* -i ... */
-                               fwd_xt_parse_out(x, n2, 0);                             /* -o ... */
-                               fwd_r_add_policytarget(x, z->forward);  /* -j handle_... */
-                               fwd_r_add_comment(x, "zone", z, n);             /* -m comment ... */
-                               fwd_xt_append_rule(x, "zones");                 /* -A zones */
-                       }
-               }
-       }
-
-       /* Build inter-zone forwarding rules */
-       for( e = z->forwardings; e && (f = &e->section.forwarding); e = e->next )
-       {
-               for( n2 = f->dest->networks; n2; n2 = n2->next )
-               {
-                       /* Build forwarding rule */
-                       if( (x = fwd_xt_init_rule(h_filter)) != NULL )
-                       {
-                               fwd_xt_parse_in(x, n, 0);                                       /* -i ... */
-                               fwd_xt_parse_out(x, n2, 0);                                     /* -o ... */
-                               fwd_r_add_policytarget(x, FWD_P_ACCEPT);        /* -j handle_... */
-                               fwd_r_add_comment(x, "forward", z, n);          /* -m comment ... */
-                               fwd_xt_append_rule(x, "forwardings");           /* -A forwardings */
-                       }
-               }
-       }
-
-       /* Build DNAT rules */
-       for( e = z->redirects; e && (r = &e->section.redirect); e = e->next )
-       {
-               /* DNAT */
-               if( (x = fwd_xt_init_rule(h_nat)) != NULL )
-               {
-                       fwd_xt_parse_in(x, n, 0);                                       /* -i ... */
-                       fwd_xt_parse_src(x, r->src_ip, 0);                      /* -s ... */
-                       fwd_xt_parse_dest(x, a, 0);                                     /* -d ... */
-                       fwd_xt_parse_proto(x, r->proto, 0);                     /* -p ... */
-                       fwd_r_add_sport(x, r->src_port);                        /* --sport ... */
-                       fwd_r_add_dport(x, r->src_dport);                       /* --dport ... */
-                       fwd_r_add_srcmac(x, r->src_mac);                        /* -m mac --mac-source ... */
-                       fwd_r_add_dnattarget(x, r->dest_ip, r->dest_port);      /* -j DNAT ... */
-                       fwd_r_add_comment(x, "redir", z, n);            /* -m comment ... */
-                       fwd_xt_append_rule(x, "redirects");                     /* -A redirects */
-               }
-
-               /* Forward */
-               if( (x = fwd_xt_init_rule(h_filter)) != NULL )
-               {
-                       fwd_xt_parse_in(x, n, 0);                                       /* -i ... */
-                       fwd_xt_parse_src(x, r->src_ip, 0);                      /* -s ... */
-                       fwd_xt_parse_dest(x, r->dest_ip, 0);            /* -d ... */
-                       fwd_xt_parse_proto(x, r->proto, 0);                     /* -p ... */
-                       fwd_r_add_srcmac(x, r->src_mac);                        /* -m mac --mac-source ... */
-                       fwd_r_add_sport(x, r->src_port);                        /* --sport ... */
-                       fwd_r_add_dport(x, r->dest_port);                       /* --dport ... */
-                       fwd_r_add_policytarget(x, FWD_P_ACCEPT);        /* -j handle_accept */
-                       fwd_r_add_comment(x, "redir", z, n);            /* -m comment ... */
-                       fwd_xt_append_rule(x, "redirects");                     /* -A redirects */
-               }
-
-               /* Add loopback rule if neither src_ip nor src_mac are defined */
-               if( !r->src_ip && !r->src_mac )
-               {
-                       if( (x = fwd_xt_init_rule(h_nat)) != NULL )
-                       {
-                               fwd_xt_parse_in(x, n, 1);                               /* -i ! ... */
-                               fwd_xt_parse_dest(x, r->dest_ip, 0);    /* -d ... */
-                               fwd_xt_parse_proto(x, r->proto, 0);             /* -p ... */
-                               fwd_r_add_sport(x, r->src_port);                /* --sport ... */
-                               fwd_r_add_dport(x, r->src_dport);               /* --dport ... */
-                               fwd_xt_get_target(x, "MASQUERADE");             /* -j MASQUERADE */
-                               fwd_r_add_comment(x, "redir", z, n);    /* -m comment ... */
-                               fwd_xt_append_rule(x, "loopback");              /* -A loopback */
-                       }
-               }
-       }
-
-       /* Build rules */
-       for( e = z->rules; e && (c = &e->section.rule); e = e->next )
-       {
-               /* Has destination, add forward rule for each network in target zone */
-               if( c->dest )
-               {
-                       for( n2 = c->dest->networks; n2; n2 = n2->next )
-                       {
-                               if( (x = fwd_xt_init_rule(h_filter)) != NULL )
-                               {
-                                       fwd_xt_parse_in(x, n, 0);                               /* -i ... */
-                                       fwd_xt_parse_out(x, n2, 0);                             /* -o ... */
-                                       fwd_xt_parse_src(x, c->src_ip, 0);              /* -s ... */
-                                       fwd_xt_parse_dest(x, c->dest_ip, 0);    /* -d ... */
-                                       fwd_xt_parse_proto(x, c->proto, 0);             /* -p ... */
-                                       fwd_r_add_icmptype(x, c->icmp_type);    /* --icmp-type ... */
-                                       fwd_r_add_srcmac(x, c->src_mac);                /* --mac-source ... */
-                                       fwd_r_add_sport(x, c->src_port);                /* --sport ... */
-                                       fwd_r_add_dport(x, c->dest_port);               /* --dport ... */
-                                       fwd_r_add_policytarget(x, c->target);   /* -j handle_... */
-                                       fwd_r_add_comment(x, "rule", z, n);             /* -m comment ... */
-                                       fwd_xt_append_rule(x, "rules");                 /* -A rules */
-                               }
-                       }
-               }
-
-               /* No destination specified, treat it as input rule */
-               else
-               {
-                       if( (x = fwd_xt_init_rule(h_filter)) != NULL )
-                       {
-                               fwd_xt_parse_in(x, n, 0);                               /* -i ... */
-                               fwd_xt_parse_src(x, c->src_ip, 0);              /* -s ... */
-                               fwd_xt_parse_dest(x, c->dest_ip, 0);    /* -d ... */
-                               fwd_xt_parse_proto(x, c->proto, 0);             /* -p ... */
-                               fwd_r_add_icmptype(x, c->icmp_type);    /* --icmp-type ... */
-                               fwd_r_add_srcmac(x, c->src_mac);                /* --mac-source ... */
-                               fwd_r_add_sport(x, c->src_port);                /* --sport ... */
-                               fwd_r_add_dport(x, c->dest_port);               /* --dport ... */
-                               fwd_r_add_policytarget(x, c->target);   /* -j handle_... */
-                               fwd_r_add_comment(x, "rule", z, n);             /* -m comment ... */
-                               fwd_xt_append_rule(x, "rules");                 /* -A rules */
-                       }
-               }
-       }
-
-       if( !iptc_commit(h_nat) )
-               fwd_fatal("Cannot commit nat table: %s", iptc_strerror(errno));
-
-       if( !iptc_commit(h_filter) )
-               fwd_fatal("Cannot commit filter table: %s", iptc_strerror(errno));
-
-       iptc_free(h_nat);
-       iptc_free(h_filter);
-}
-
-
-static void fwd_ipt_delif_table(struct iptc_handle *h, const char *net)
-{
-       const struct xt_entry_match *m;
-       const struct ipt_entry *e;
-       const char *chain, *comment;
-       size_t off = 0, num = 0;
-
-       /* iterate chains */
-       for( chain = iptc_first_chain(h); chain;
-            chain = iptc_next_chain(h)
-       ) {
-               /* iterate rules */
-               for( e = iptc_first_rule(chain, h), num = 0; e;
-                    e = iptc_next_rule(e, h), num++
-               ) {
-                       repeat_rule:
-
-                       /* skip entries w/o matches */
-                       if( ! e->target_offset )
-                               continue;
-
-                       /* iterate matches */
-                       for( off = sizeof(struct ipt_entry);
-                            off < e->target_offset;
-                            off += m->u.match_size
-                       ) {
-                               m = (void *)e + off;
-
-                               /* yay */
-                               if( ! strcmp(m->u.user.name, "comment") )
-                               {
-                                       /* better use struct_xt_comment_info but well... */
-                                       comment = (void *)m + sizeof(struct xt_entry_match);
-
-                                       if( fwd_r_cmp("net=", comment, net) )
-                                       {
-                                               e = iptc_next_rule(e, h);
-                                               iptc_delete_num_entry(chain, num, h);
-
-                                               if( e != NULL )
-                                                       goto repeat_rule;
-                                               else
-                                                       break;
-                                       }
-                               }
-                       }
-               }
-       }
-}
-
-void fwd_ipt_delif(struct fwd_handle *h, const char *net)
-{
-       struct iptc_handle *h_filter, *h_nat;
-
-       if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) )
-               fwd_fatal("Unable to obtain libiptc handle");
-
-
-       fwd_log_info("Removing network %s", net);
-
-       /* delete network related rules */
-       fwd_ipt_delif_table(h_nat, net);
-       fwd_ipt_delif_table(h_filter, net);
-
-
-       if( !iptc_commit(h_nat) )
-               fwd_fatal("Cannot commit nat table: %s", iptc_strerror(errno));
-
-       if( !iptc_commit(h_filter) )
-               fwd_fatal("Cannot commit filter table: %s", iptc_strerror(errno));
-
-       iptc_free(h_nat);
-       iptc_free(h_filter);
-}
-
-void fwd_ipt_chgif(struct fwd_handle *h, const char *net)
-{
-       /* XXX: should alter rules in-place, tbd */
-       fwd_ipt_delif(h, net);
-       fwd_ipt_addif(h, net);
-}
-
-
-static void fwd_ipt_clear_ruleset_table(struct iptc_handle *h)
-{
-       const char *chain;
-
-       /* pass 1: flush all chains */
-       for( chain = iptc_first_chain(h); chain;
-            chain = iptc_next_chain(h)
-       ) {
-               iptc_flush_entries(chain, h);
-       }
-
-       /* pass 2: remove user defined chains */
-       for( chain = iptc_first_chain(h); chain;
-            chain = iptc_next_chain(h)
-       ) {
-               if( ! iptc_builtin(chain, h) )
-                       iptc_delete_chain(chain, h);
-       }
-}
-
-void fwd_ipt_clear_ruleset(struct fwd_handle *h)
-{
-       struct iptc_handle *h_filter, *h_nat;
-
-       if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) )
-               fwd_fatal("Unable to obtain libiptc handle");
-
-       /* flush tables */
-       fwd_ipt_clear_ruleset_table(h_nat);
-       fwd_ipt_clear_ruleset_table(h_filter);
-
-       /* revert policies */
-       fwd_r_set_policy(h_filter, "INPUT", "ACCEPT");
-       fwd_r_set_policy(h_filter, "OUTPUT", "ACCEPT");
-       fwd_r_set_policy(h_filter, "FORWARD", "ACCEPT");        
-
-
-       if( !iptc_commit(h_nat) )
-               fwd_fatal("Cannot commit nat table: %s", iptc_strerror(errno));
-
-       if( !iptc_commit(h_filter) )
-               fwd_fatal("Cannot commit filter table: %s", iptc_strerror(errno));
-
-       iptc_free(h_nat);
-       iptc_free(h_filter);
-}
-