From: Jo-Philipp Wich Date: Tue, 15 Dec 2009 11:21:42 +0000 (+0000) Subject: contrib/fwd: simplify ruleset, initial xtables integration X-Git-Tag: 0.10.0~896 X-Git-Url: http://git.openwrt.org/?p=project%2Fluci.git;a=commitdiff_plain;h=7001c02a38ce75eac28efea6ac0a415133dba535;hp=3e97fcfe4b82e1c547234de2002275fa49933136 contrib/fwd: simplify ruleset, initial xtables integration --- diff --git a/contrib/fwd/src/fwd_rules.c b/contrib/fwd/src/fwd_rules.c index 9c233417ef..c3d4ebbe53 100644 --- a/contrib/fwd/src/fwd_rules.c +++ b/contrib/fwd/src/fwd_rules.c @@ -20,6 +20,7 @@ #include "fwd.h" #include "fwd_addr.h" #include "fwd_rules.h" +#include "fwd_xtables.h" static void fwd_ipt_rule_append(struct fwd_ipt_rulebuf *r, const char *fmt, ...) @@ -179,6 +180,33 @@ static void fwd_ipt_add_dnat_target( } } +static void fwd_ipt_add_policy_target( + struct fwd_ipt_rulebuf *r, enum fwd_policy p +) { + fwd_ipt_rule_append(r, " -j %s", + (p == FWD_P_ACCEPT) + ? "handle_accept" + : (p == FWD_P_REJECT) + ? "handle_reject" + : "handle_drop" + ); +} + +static void fwd_ipt_add_comment( + struct fwd_ipt_rulebuf *r, const char *t, struct fwd_zone *z, + struct fwd_network_list *n, struct fwd_network_list *n2 +) { + if( (n != NULL) && (n2 != NULL) ) + fwd_ipt_add_format(r, " -m comment --comment '%s:%s src:%s dest:%s'", + t, z->name, n->name, n2->name); + else if( (n == NULL) && (n2 != NULL) ) + fwd_ipt_add_format(r, " -m comment --comment '%s:%s dest:%s'", + t, z->name, n2->name); + else + fwd_ipt_add_format(r, " -m comment --comment '%s:%s src:%s'", + t, z->name, n->name); +} + static void fwd_ipt_exec(struct fwd_ipt_rulebuf *r) { if( r->len ) @@ -188,223 +216,302 @@ static void fwd_ipt_exec(struct fwd_ipt_rulebuf *r) fwd_free_ptr(r); } -static const char * fwd_str_policy(enum fwd_policy pol) -{ - return (pol == FWD_P_ACCEPT ? "ACCEPT" : "DROP"); +/* -P */ +static void fwd_r_set_policy( + struct iptc_handle *h, const char *chain, const char *policy +) { + iptc_set_policy(chain, policy, NULL, h); } -static const char * fwd_str_target(enum fwd_policy pol) +/* -N */ +static void fwd_r_new_chain(struct iptc_handle *h, const char *chain) { - switch(pol) - { - case FWD_P_ACCEPT: - return "ACCEPT"; + iptc_create_chain(chain, h); +} - case FWD_P_REJECT: - return "REJECT"; +/* -A -j */ +static void fwd_r_jump_chain( + struct iptc_handle *h, const char *chain1, const char *chain2 +) { + struct fwd_xt_rule *r; - default: - return "DROP"; + if( (r = fwd_xt_init_rule(h)) != NULL ) + { + fwd_xt_get_target(r, chain2); + fwd_xt_exec_rule(r, chain1); } - - return "DROP"; } - -static void fwd_ipt_defaults_create(struct fwd_data *d) +/* -A -m state --state INVALID -j DROP */ +static void fwd_r_drop_invalid(struct iptc_handle *h, const char *chain) { - struct fwd_defaults *def = &d->section.defaults; - - /* policies */ - fwd_ipt_exec_format("filter", " -P INPUT %s", fwd_str_policy(def->input)); - fwd_ipt_exec_format("filter", " -P OUTPUT %s", fwd_str_policy(def->output)); - fwd_ipt_exec_format("filter", " -P FORWARD %s", fwd_str_policy(def->forward)); + struct fwd_xt_rule *r; + struct xtables_match *m; - /* invalid state drop */ - if( def->drop_invalid ) + if( (r = fwd_xt_init_rule(h)) != NULL ) { - fwd_ipt_exec_format("filter", " -A INPUT --state INVALID -j DROP"); - fwd_ipt_exec_format("filter", " -A OUTPUT --state INVALID -j DROP"); - fwd_ipt_exec_format("filter", " -A FORWARD --state INVALID -j DROP"); + if( (m = fwd_xt_get_match(r, "state")) != NULL ) + { + fwd_xt_parse_match(r, m, "--state", "INVALID", 0); + fwd_xt_get_target(r, "DROP"); + fwd_xt_exec_rule(r, chain); + } } +} - /* default accept related */ - fwd_ipt_exec_format("filter", " -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT"); - fwd_ipt_exec_format("filter", " -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT"); - fwd_ipt_exec_format("filter", " -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT"); - - /* default accept on lo */ - fwd_ipt_exec_format("filter", " -A INPUT -i lo -j ACCEPT"); - fwd_ipt_exec_format("filter", " -A OUTPUT -o lo -j ACCEPT"); +/* -A -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; - /* syn flood protection */ - if( def->syn_flood ) + if( (r = fwd_xt_init_rule(h)) != NULL ) { - fwd_ipt_exec_format("filter", " -N syn_flood"); + if( (m = fwd_xt_get_match(r, "state")) != NULL ) + { + fwd_xt_parse_match(r, m, "--state", "RELATED,ESTABLISHED", 0); + fwd_xt_get_target(r, "ACCEPT"); + fwd_xt_exec_rule(r, chain); + } + } +} - fwd_ipt_exec_format("filter", - " -A syn_flood -p tcp --syn -m limit --limit %i/second" - " --limit-burst %i -j RETURN", - def->syn_rate, def->syn_burst); +/* -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_list n; + struct fwd_xt_rule *r; - fwd_ipt_exec_format("filter", " -A syn_flood -j DROP"); - fwd_ipt_exec_format("filter", " -A INPUT -p tcp --syn -j syn_flood"); + 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_exec_rule(r, "INPUT"); } - /* standard input/output/forward chain */ - fwd_ipt_exec_format("filter", " -N input"); - fwd_ipt_exec_format("filter", " -N output"); - fwd_ipt_exec_format("filter", " -N forward"); - fwd_ipt_exec_format("filter", " -A INPUT -j input"); - fwd_ipt_exec_format("filter", " -A OUTPUT -j output"); - fwd_ipt_exec_format("filter", " -A FORWARD -j forward"); - - /* standard reject chain */ - fwd_ipt_exec_format("filter", " -N reject"); - fwd_ipt_exec_format("filter", " -A reject -p tcp -j REJECT --reject-with tcp-reset"); - fwd_ipt_exec_format("filter", " -A reject -j REJECT --reject-with icmp-port-unreachable"); + if( (r = fwd_xt_init_rule(h)) != NULL ) + { + fwd_xt_parse_out(r, &n, 0); + fwd_xt_get_target(r, "ACCEPT"); + fwd_xt_exec_rule(r, "OUTPUT"); + } } -static void fwd_ipt_zone_create(struct fwd_data *d) +/* build syn_flood chain and jump rule */ +static void fwd_r_add_synflood(struct iptc_handle *h, struct fwd_defaults *def) { - struct fwd_zone *z = &d->section.zone; + struct fwd_proto p; + struct fwd_xt_rule *r; + struct xtables_match *m; + char buf[32]; - if( !strcmp(z->name, "loopback") ) - return; + /* -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); - fwd_ipt_exec_format("filter", " -N zone_%s", z->name); - fwd_ipt_exec_format("filter", " -N zone_%s_forward", z->name); - fwd_ipt_exec_format("filter", " -N zone_%s_ACCEPT", z->name); - fwd_ipt_exec_format("filter", " -N zone_%s_REJECT", z->name); - fwd_ipt_exec_format("filter", " -N zone_%s_DROP", z->name); - fwd_ipt_exec_format("filter", " -N zone_%s_MSSFIX", z->name); + /* -m tcp --syn */ + if( (m = fwd_xt_get_match(r, "tcp")) != NULL ) + { + fwd_xt_parse_match(r, m, "--syn", NULL, 0); + } - if( z->forward != FWD_P_UNSPEC ) - fwd_ipt_exec_format("filter", " -A zone_%s_forward -j zone_%s_%s", - z->name, z->name, fwd_str_target(z->forward)); + /* -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, 0); - if( z->input != FWD_P_UNSPEC ) - fwd_ipt_exec_format("filter", " -A zone_%s -j zone_%s_%s", - z->name, z->name, fwd_str_target(z->input)); + sprintf(buf, "%i", def->syn_burst); + fwd_xt_parse_match(r, m, "--limit-burst", buf, 0); + } - if( z->output != FWD_P_UNSPEC ) - fwd_ipt_exec_format("filter", " -A output -j zone_%s_%s", - z->name, fwd_str_target(z->output)); + /* -j RETURN; -A syn_flood */ + fwd_xt_get_target(r, "RETURN"); + fwd_xt_exec_rule(r, "syn_flood"); + } - fwd_ipt_exec_format("nat", " -N zone_%s_nat", z->name); - fwd_ipt_exec_format("nat", " -N zone_%s_prerouting", z->name); - fwd_ipt_exec_format("raw", " -N zone_%s_notrack", z->name); + /* drop rule */ + if( (r = fwd_xt_init_rule(h)) != NULL ) + { + /* -j DROP; -A syn_flood */ + fwd_xt_get_target(r, "DROP"); + fwd_xt_exec_rule(r, "syn_flood"); + } - if( z->masq ) - fwd_ipt_exec_format("nat", " -A POSTROUTING -j zone_%s_nat", - z->name); + /* 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); - if( z->mtu_fix ) - fwd_ipt_exec_format("filter", " -A FORWARD -j zone_%s_MSSFIX", - z->name); + /* -m tcp --syn */ + if( (m = fwd_xt_get_match(r, "tcp")) != NULL ) + { + fwd_xt_parse_match(r, m, "--syn", NULL, 0); + } + + /* -j syn_flood; -A INPUT */ + fwd_xt_get_target(r, "syn_flood"); + fwd_xt_exec_rule(r, "INPUT"); + } } -static void fwd_ipt_forwarding_create(struct fwd_data *d) +/* build reject target chain */ +static void fwd_r_handle_reject(struct iptc_handle *h) { - struct fwd_forwarding *f = &d->section.forwarding; - struct fwd_ipt_rulebuf *b; + struct fwd_proto p; + struct fwd_xt_rule *r; + struct xtables_target *t; - b = fwd_ipt_init("filter"); + /* -N handle_reject */ + fwd_r_new_chain(h, "handle_reject"); - if( f->src ) - fwd_ipt_add_format(b, " -I zone_%s_forward 1", f->src->name); - else - fwd_ipt_add_format(b, " -I forward 1"); + /* 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); - if( f->dest ) - fwd_ipt_add_format(b, " -j zone_%s_ACCEPT", f->dest->name); - else - fwd_ipt_add_format(b, " -j ACCEPT"); + /* -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", 0); + } + + /* -A handle_reject */ + fwd_xt_exec_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", 0); + } - fwd_ipt_exec(b); + /* -A handle_reject */ + fwd_xt_exec_rule(r, "handle_reject"); + } } -static void fwd_ipt_redirect_create(struct fwd_data *d) +/* build drop target chain */ +static void fwd_r_handle_drop(struct iptc_handle *h) { - struct fwd_redirect *r = &d->section.redirect; - struct fwd_ipt_rulebuf *b; + struct fwd_xt_rule *r; + + /* -N handle_drop */ + fwd_r_new_chain(h, "handle_drop"); - b = fwd_ipt_init("nat"); - fwd_ipt_add_format(b, " -A zone_%s_prerouting", r->src->name); - fwd_ipt_add_proto(b, r->proto); - fwd_ipt_add_srcaddr(b, r->src_ip); - fwd_ipt_add_srcport(b, r->src_port); - fwd_ipt_add_destport(b, r->src_dport); - fwd_ipt_add_srcmac(b, r->src_mac); - fwd_ipt_add_dnat_target(b, r->dest_ip, r->dest_port); - fwd_ipt_exec(b); - - b = fwd_ipt_init("nat"); - fwd_ipt_add_format(b, " -I zone_%s_forward 1", r->src->name); - fwd_ipt_add_proto(b, r->proto); - fwd_ipt_add_srcmac(b, r->src_mac); - fwd_ipt_add_srcaddr(b, r->src_ip); - fwd_ipt_add_srcport(b, r->src_port); - fwd_ipt_add_destaddr(b, r->dest_ip); - fwd_ipt_add_destport(b, r->dest_port); - fwd_ipt_add_format(b, " -j ACCEPT"); - fwd_ipt_exec(b); + /* common drop rule */ + if( (r = fwd_xt_init_rule(h)) != NULL ) + { + /* -j DROP; -A handle_reject */ + fwd_xt_get_target(r, "DROP"); + fwd_xt_exec_rule(r, "handle_reject"); + } } -static void fwd_ipt_rule_create(struct fwd_data *d) +/* build accept target chain */ +static void fwd_r_handle_accept(struct iptc_handle *h) { - struct fwd_rule *r = &d->section.rule; - struct fwd_ipt_rulebuf *b; + struct fwd_xt_rule *r; - b = fwd_ipt_init("filter"); + /* -N handle_accept */ + fwd_r_new_chain(h, "handle_accept"); - if( r->dest ) - fwd_ipt_add_format(b, " -A zone_%s_forward", r->src->name); - else - fwd_ipt_add_format(b, " -A zone_%s", r->src->name); - - fwd_ipt_add_proto(b, r->proto); - fwd_ipt_add_icmptype(b, r->icmp_type); - fwd_ipt_add_srcmac(b, r->src_mac); - fwd_ipt_add_srcaddr(b, r->src_ip); - fwd_ipt_add_srcport(b, r->src_port); - fwd_ipt_add_destaddr(b, r->dest_ip); - fwd_ipt_add_destport(b, r->dest_port); - - if( r->dest ) - fwd_ipt_add_format(b, " -j zone_%s_%s", - r->dest->name, fwd_str_target(r->target)); - else - fwd_ipt_add_format(b, " -j %s", fwd_str_target(r->target)); - - fwd_ipt_exec(b); + /* common accept rule */ + if( (r = fwd_xt_init_rule(h)) != NULL ) + { + /* -j ACCEPT; -A handle_accept */ + fwd_xt_get_target(r, "ACCEPT"); + fwd_xt_exec_rule(r, "handle_accept"); + } } -static struct fwd_network_list * -fwd_lookup_network(struct fwd_network_list *n, const char *net) +static void fwd_ipt_defaults_create(struct fwd_data *d) { - struct fwd_network_list *e; + struct fwd_defaults *def = &d->section.defaults; + struct iptc_handle *h_filter, *h_nat; - if( n != NULL ) - for( e = n; e; e = e->next ) - if( !strcmp(e->name, net) ) - return e; + if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) ) + fwd_fatal("Unable to obtain libiptc handle"); - return NULL; -} + /* 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"); -static struct fwd_addr_list * -fwd_lookup_addr(struct fwd_addr_list *a, const char *ifname) -{ - struct fwd_addr_list *e; + /* 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"); + } - if( a != NULL ) - for( e = a; e; e = e->next ) - if( !strcmp(e->ifname, ifname) ) - return e; + /* default accept related */ + fwd_r_accept_related(h_filter, "INPUT"); + fwd_r_accept_related(h_filter, "OUTPUT"); + fwd_r_accept_related(h_filter, "FORWARD"); - return NULL; + /* 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_jump_chain(h_nat, "POSTROUTING", "zonemasq"); + fwd_r_jump_chain(h_nat, "PREROUTING", "redirects"); + fwd_r_jump_chain(h_nat, "POSTROUTING", "redirects"); + + /* 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); } @@ -412,6 +519,8 @@ 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) @@ -421,97 +530,241 @@ void fwd_ipt_build_ruleset(struct fwd_handle *h) fwd_ipt_defaults_create(e); break; - case FWD_S_ZONE: - printf("\n## ZONE %s\n", e->section.zone.name); - fwd_ipt_zone_create(e); + case FWD_S_INCLUDE: + printf("\n## INCLUDE %s\n", e->section.include.path); break; + case FWD_S_ZONE: case FWD_S_FORWARD: - printf("\n## FORWARD %s -> %s\n", - e->section.forwarding.src - ? e->section.forwarding.src->name : "(all)", - e->section.forwarding.dest - ? e->section.forwarding.dest->name : "(all)"); - fwd_ipt_forwarding_create(e); - break; - case FWD_S_REDIRECT: - printf("\n## REDIRECT %s\n", e->section.forwarding.src->name); - fwd_ipt_redirect_create(e); - break; - case FWD_S_RULE: - printf("\n## RULE %s\n", e->section.rule.src->name); - fwd_ipt_rule_create(e); - break; - - case FWD_S_INCLUDE: - printf("\n## INCLUDE %s\n", e->section.include.path); + /* Make gcc happy */ break; } } } -void fwd_ipt_addif(struct fwd_handle *h, const char *net) + +static struct fwd_zone * +fwd_lookup_zone(struct fwd_handle *h, const char *net) { struct fwd_data *e; - struct fwd_zone *z; - struct fwd_addr_list *a; struct fwd_network_list *n; for( e = h->conf; e; e = e->next ) - { - if( (e->type != FWD_S_ZONE) || - !(n = fwd_lookup_network(e->section.zone.networks, net)) || - !(a = fwd_lookup_addr(h->addrs, n->ifname)) ) - continue; + 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_list * +fwd_lookup_network(struct fwd_zone *z, const char *net) +{ + struct fwd_network_list *n; + + for( n = z->networks; n; n = n->next ) + if( !strcmp(n->name, net) ) + return n; + + return NULL; +} - z = &e->section.zone; +static struct fwd_addr_list * +fwd_lookup_addr(struct fwd_handle *h, struct fwd_network_list *n) +{ + struct fwd_addr_list *a; - printf("\n## NETWORK %s (%s - %s/%u)\n", - n->name, n->ifname, - inet_ntoa(a->ipaddr.v4), a->prefix - ); + if( n != NULL ) + for( a = h->addrs; a; a = a->next ) + if( !strcmp(a->ifname, n->ifname) ) + return a; - fwd_ipt_exec_format("filter", " -A input -i %s -j zone_%s", - n->ifname, z->name); + return NULL; +} - fwd_ipt_exec_format("filter", - " -I zone_%s_MSSFIX 1 -o %s -p tcp --tcp-flags SYN,RST SYN" - " -j TCPMSS --clamp-mss-to-pmtu", - z->name, n->ifname); +void fwd_ipt_addif(struct fwd_handle *h, const char *net) +{ + struct fwd_data *e; + struct fwd_zone *z; + struct fwd_ipt_rulebuf *b; + struct fwd_rule *c; + struct fwd_redirect *r; + struct fwd_forwarding *f; + struct fwd_addr_list *a, *a2; + struct fwd_network_list *n, *n2; + + if( !(z = fwd_lookup_zone(h, net)) ) + return; + + if( !(n = fwd_lookup_network(z, net)) ) + return; - fwd_ipt_exec_format("filter", " -I zone_%s_ACCEPT 1 -o %s -j ACCEPT", - z->name, n->ifname); + if( !(a = fwd_lookup_addr(h, n)) ) + return; - fwd_ipt_exec_format("filter", " -I zone_%s_DROP 1 -o %s -j DROP", - z->name, n->ifname); + printf("\n\n#\n# addif(%s)\n#\n", net); - fwd_ipt_exec_format("filter", " -I zone_%s_REJECT 1 -o %s -j reject", - z->name, n->ifname); + /* Build masquerading rule */ + if( z->masq ) + { + printf("\n# Net %s (%s) - masq\n", n->name, n->ifname); - fwd_ipt_exec_format("filter", " -I zone_%s_ACCEPT 1 -i %s -j ACCEPT", - z->name, n->ifname); + b = fwd_ipt_init("nat"); + fwd_ipt_add_format(b, " -A zonemasq -o %s -j MASQUERADE", n->ifname); + fwd_ipt_add_comment(b, "masq", z, NULL, n); + fwd_ipt_exec(b); + } - fwd_ipt_exec_format("filter", " -I zone_%s_DROP 1 -i %s -j DROP", - z->name, n->ifname); + /* Build MSS fix rule */ + if( z->mtu_fix ) + { + printf("\n# Net %s (%s) - mtu_fix\n", n->name, n->ifname); + + b = fwd_ipt_init("filter"); + fwd_ipt_add_format(b, + " -A mssfix -o %s -p tcp --tcp-flags SYN,RST SYN" + " -j TCPMSS --clamp-mss-to-pmtu", n->ifname); + fwd_ipt_add_comment(b, "mssfix", z, NULL, n); + fwd_ipt_exec(b); + } - fwd_ipt_exec_format("filter", " -I zone_%s_REJECT 1 -i %s -j reject", - z->name, n->ifname); + /* Build intra-zone forwarding rules */ + for( n2 = z->networks; n2; n2 = n2->next ) + { + if( (a2 = fwd_lookup_addr(h, n2)) != NULL ) + { + printf("\n# Net %s (%s) - intra-zone-forwarding" + " Z:%s N:%s I:%s -> Z:%s N:%s I:%s\n", + n->name, n->ifname, z->name, n->name, n->ifname, + z->name, n2->name, n2->ifname); + + b = fwd_ipt_init("filter"); + fwd_ipt_add_format(b, " -A zones -i %s -o %s", + n->ifname, n2->ifname); + fwd_ipt_add_policy_target(b, z->forward); + fwd_ipt_add_comment(b, "zone", z, n, n2); + fwd_ipt_exec(b); + } + } - fwd_ipt_exec_format("filter", - " -I zone_%s_nat 1 -t nat -o %s -j MASQUERADE", - z->name, n->ifname); + /* 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 ) + { + printf("\n# Net %s (%s) - inter-zone-forwarding" + " Z:%s N:%s I:%s -> Z:%s N:%s I:%s\n", + n->name, n->ifname, z->name, n->name, n->ifname, + f->dest->name, n2->name, n2->ifname); + + /* Build forwarding rule */ + b = fwd_ipt_init("filter"); + fwd_ipt_add_format(b, " -A forwardings -i %s -o %s", + n->ifname, n2->ifname); + fwd_ipt_add_policy_target(b, FWD_P_ACCEPT); + fwd_ipt_add_comment(b, "forward", z, n, n2); + fwd_ipt_exec(b); + } + } - fwd_ipt_exec_format("filter", - " -I PREROUTING 1 -t nat -i %s -j zone_%s_prerouting", - n->ifname, z->name); + /* Build DNAT rules */ + for( e = z->redirects; e && (r = &e->section.redirect); e = e->next ) + { + printf("\n# Net %s (%s) - redirect Z:%s N:%s I:%s\n", + n->name, n->ifname, z->name, n->name, n->ifname); + + /* DNAT */ + b = fwd_ipt_init("nat"); + fwd_ipt_add_format(b, " -A redirects -i %s -d %s", + n->ifname, inet_ntoa(a->ipaddr.v4)); + fwd_ipt_add_proto(b, r->proto); + fwd_ipt_add_srcaddr(b, r->src_ip); + fwd_ipt_add_srcport(b, r->src_port); + fwd_ipt_add_destport(b, r->src_dport); + fwd_ipt_add_srcmac(b, r->src_mac); + fwd_ipt_add_dnat_target(b, r->dest_ip, r->dest_port); + fwd_ipt_add_comment(b, "redir", z, n, NULL); + fwd_ipt_exec(b); + + /* Forward */ + b = fwd_ipt_init("filter"); + fwd_ipt_add_format(b, " -A redirects -i %s", n->ifname); + fwd_ipt_add_proto(b, r->proto); + fwd_ipt_add_srcmac(b, r->src_mac); + fwd_ipt_add_srcaddr(b, r->src_ip); + fwd_ipt_add_srcport(b, r->src_port); + fwd_ipt_add_destaddr(b, r->dest_ip); + fwd_ipt_add_destport(b, r->dest_port); + fwd_ipt_add_policy_target(b, FWD_P_ACCEPT); + fwd_ipt_add_comment(b, "redir", z, n, NULL); + fwd_ipt_exec(b); + + /* Add loopback rule if neither src_ip nor src_mac are defined */ + if( !r->src_ip && !r->src_mac ) + { + b = fwd_ipt_init("nat"); + fwd_ipt_add_format(b, " -A redirects -i ! %s -d %s", + n->ifname, inet_ntoa(r->dest_ip->addr)); + fwd_ipt_add_proto(b, r->proto); + fwd_ipt_add_srcport(b, r->src_port); + fwd_ipt_add_destport(b, r->src_dport); + fwd_ipt_add_format(b, " -j MASQUERADE"); + fwd_ipt_add_comment(b, "redir", z, n, NULL); + fwd_ipt_exec(b); + } + } - fwd_ipt_exec_format("filter", " -A forward -i %s -j zone_%s_forward", - n->ifname, z->name); + /* 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 ) + { + printf("\n# Net %s (%s) - rule+dest" + " Z:%s N:%s I:%s -> Z:%s N:%s I:%s\n", + n->name, n->ifname, z->name, n->name, n->ifname, + f->dest->name, n2->name, n2->ifname); + + b = fwd_ipt_init("filter"); + fwd_ipt_add_format(b, " -A rules -i %s -o %s", + n->ifname, n2->ifname); + fwd_ipt_add_proto(b, c->proto); + fwd_ipt_add_icmptype(b, c->icmp_type); + fwd_ipt_add_srcmac(b, c->src_mac); + fwd_ipt_add_srcaddr(b, c->src_ip); + fwd_ipt_add_srcport(b, c->src_port); + fwd_ipt_add_destaddr(b, c->dest_ip); + fwd_ipt_add_destport(b, c->dest_port); + fwd_ipt_add_policy_target(b, c->target); + fwd_ipt_add_comment(b, "rule", z, n, n2); + fwd_ipt_exec(b); + } + } - fwd_ipt_exec_format("raw", " -I PREROUTING 1 -i %s -j zone_%s_notrack", - n->ifname, z->name); + /* No destination specified, treat it as input rule */ + else + { + printf("\n# Net %s (%s) - rule Z:%s N:%s I:%s\n", + n->name, n->ifname, z->name, n->name, n->ifname); + + b = fwd_ipt_init("filter"); + fwd_ipt_add_format(b, " -A rules -i %s", n->ifname); + fwd_ipt_add_proto(b, c->proto); + fwd_ipt_add_icmptype(b, c->icmp_type); + fwd_ipt_add_srcmac(b, c->src_mac); + fwd_ipt_add_srcaddr(b, c->src_ip); + fwd_ipt_add_srcport(b, c->src_port); + fwd_ipt_add_destaddr(b, c->dest_ip); + fwd_ipt_add_destport(b, c->dest_port); + fwd_ipt_add_policy_target(b, c->target); + fwd_ipt_add_comment(b, "rule", z, n, n2); + fwd_ipt_exec(b); + } } }