X-Git-Url: https://git.archive.openwrt.org/?p=project%2Fluci.git;a=blobdiff_plain;f=contrib%2Ffwd%2Fsrc%2Ffwd_rules.c;h=e6604911a73b6c59b03bc1189e5b1d35627cb65d;hp=9c233417ef6af47aafdeca9c8aeabd89fe3729ef;hb=0f791a7fb6a67cf30d91775e4ae768679e14d610;hpb=2e9ac3b3420350737aa37d01c0418bede10ab401 diff --git a/contrib/fwd/src/fwd_rules.c b/contrib/fwd/src/fwd_rules.c index 9c233417e..e6604911a 100644 --- a/contrib/fwd/src/fwd_rules.c +++ b/contrib/fwd/src/fwd_rules.c @@ -20,498 +20,758 @@ #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, ...) + +/* -P */ +static void fwd_r_set_policy( + struct iptc_handle *h, const char *chain, const char *policy +) { + iptc_set_policy(chain, policy, NULL, h); +} + +/* -N */ +static void fwd_r_new_chain(struct iptc_handle *h, const char *chain) { - int len = 0; - char buf[256]; buf[0] = 0; + iptc_create_chain(chain, h); +} - va_list ap; - va_start(ap, fmt); - len = vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); +/* -A -j */ +static void fwd_r_jump_chain( + struct iptc_handle *h, const char *chain1, const char *chain2 +) { + struct fwd_xt_rule *r; - if( len > 0 ) + if( (r = fwd_xt_init_rule(h)) != NULL ) { - r->buf = realloc(r->buf, r->len + len + 1); - memcpy(&r->buf[r->len], buf, len); - r->buf[r->len + len] = 0; - r->len += len; + fwd_xt_get_target(r, chain2); + fwd_xt_exec_rule(r, chain1); } } -static struct fwd_ipt_rulebuf * fwd_ipt_init(const char *table) +/* -A -m state --state INVALID -j DROP */ +static void fwd_r_drop_invalid(struct iptc_handle *h, const char *chain) { - struct fwd_ipt_rulebuf *r; + struct fwd_xt_rule *r; + struct xtables_match *m; - if( (r = fwd_alloc_ptr(struct fwd_ipt_rulebuf)) != NULL ) + if( (r = fwd_xt_init_rule(h)) != NULL ) { - fwd_ipt_rule_append(r, IPT " -t %s", table); - return r; + 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_exec_rule(r, chain); + } } - - return NULL; } -static void fwd_ipt_add_srcport( - struct fwd_ipt_rulebuf *r, struct fwd_portrange *p -) { - if( p != NULL ) +/* -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; + + if( (r = fwd_xt_init_rule(h)) != NULL ) { - if( p->min < p->max ) - fwd_ipt_rule_append(r, " --sport %u:%u", p->min, p->max); - else - fwd_ipt_rule_append(r, " --sport %u", p->min); + 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_exec_rule(r, chain); + } } } -static void fwd_ipt_add_destport( - struct fwd_ipt_rulebuf *r, struct fwd_portrange *p -) { - if( p != NULL ) +/* -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; + + n.ifname = "lo"; + + if( (r = fwd_xt_init_rule(h)) != NULL ) { - if( p->min < p->max ) - fwd_ipt_rule_append(r, " --dport %u:%u", p->min, p->max); - else - fwd_ipt_rule_append(r, " --dport %u", p->min); + fwd_xt_parse_in(r, &n, 0); + fwd_xt_get_target(r, "ACCEPT"); + fwd_xt_exec_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_exec_rule(r, "OUTPUT"); } } -static void fwd_ipt_add_proto( - struct fwd_ipt_rulebuf *r, struct fwd_proto *p -) { - if( p != NULL ) +/* 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 ) { - switch( p->type ) + /* -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 ) { - case FWD_PR_TCPUDP: - fwd_ipt_rule_append(r, " -p tcp -p udp"); - break; + fwd_xt_parse_match(r, m, "--syn"); + } - case FWD_PR_TCP: - fwd_ipt_rule_append(r, " -p tcp"); - break; + /* -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); - case FWD_PR_UDP: - fwd_ipt_rule_append(r, " -p udp"); - break; + sprintf(buf, "%i", def->syn_burst); + fwd_xt_parse_match(r, m, "--limit-burst", buf); + } - case FWD_PR_ICMP: - fwd_ipt_rule_append(r, " -p icmp"); - break; + /* -j RETURN; -A syn_flood */ + fwd_xt_get_target(r, "RETURN"); + fwd_xt_exec_rule(r, "syn_flood"); + } - case FWD_PR_ALL: - fwd_ipt_rule_append(r, " -p all"); - break; + /* 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"); + } - case FWD_PR_CUSTOM: - fwd_ipt_rule_append(r, " -p %u", p->proto); - break; + /* 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_exec_rule(r, "INPUT"); } } -static void fwd_ipt_add_srcaddr( - struct fwd_ipt_rulebuf *r, struct fwd_cidr *c -) { - if( c != NULL ) +/* 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 ) { - if( c->prefix < 32 ) - fwd_ipt_rule_append(r, " -s %s/%u", - inet_ntoa(c->addr), c->prefix); - else - fwd_ipt_rule_append(r, " -s %s", inet_ntoa(c->addr)); + /* -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_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"); + } + + /* -A handle_reject */ + fwd_xt_exec_rule(r, "handle_reject"); } } -static void fwd_ipt_add_destaddr( - struct fwd_ipt_rulebuf *r, struct fwd_cidr *c +/* 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_reject */ + fwd_xt_get_target(r, "DROP"); + fwd_xt_exec_rule(r, "handle_reject"); + } +} + +/* 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_exec_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_list *n, struct fwd_network_list *n2 ) { - if( c != NULL ) + struct xtables_match *m; + char buf[256]; + + if( (m = fwd_xt_get_match(r, "comment")) != NULL ) { - if( c->prefix < 32 ) - fwd_ipt_rule_append(r, " -d %s/%u", - inet_ntoa(c->addr), c->prefix); + if( (n != NULL) && (n2 != NULL) ) + snprintf(buf, sizeof(buf), "%s:%s src:%s dest:%s", + t, z->name, n->name, n2->name); + else if( (n == NULL) && (n2 != NULL) ) + snprintf(buf, sizeof(buf), "%s:%s dest:%s", t, z->name, n2->name); else - fwd_ipt_rule_append(r, " -d %s", inet_ntoa(c->addr)); + snprintf(buf, sizeof(buf), "%s:%s src:%s", t, z->name, n->name); + + fwd_xt_parse_match(r, m, "--comment", buf); } } -static void fwd_ipt_add_srcmac( - struct fwd_ipt_rulebuf *r, struct fwd_mac *m +/* add --sport (if applicable) */ +static void fwd_r_add_sport( + struct fwd_xt_rule *r, struct fwd_portrange *p ) { - if( m != NULL ) + 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)) ) { - fwd_ipt_rule_append(r, - " -m mac --mac-source %02x:%02x:%02x:%02x:%02x:%02x", - m->mac[0], m->mac[1], m->mac[2], - m->mac[3], m->mac[4], m->mac[5]); + /* 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); + } } } -static void fwd_ipt_add_icmptype( - struct fwd_ipt_rulebuf *r, struct fwd_icmptype *i +/* add --dport (if applicable) */ +static void fwd_r_add_dport( + struct fwd_xt_rule *r, struct fwd_portrange *p ) { - if( i != NULL ) + 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)) ) { - if( i->name ) - fwd_ipt_rule_append(r, " --icmp-type %s", i->name); - else if( i->code > -1 ) - fwd_ipt_rule_append(r, " --icmp-type %u/%u", i->type, i->code); - else - fwd_ipt_rule_append(r, " --icmp-type %u", i->type); + /* 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); + } } } -static void fwd_ipt_add_dnat_target( - struct fwd_ipt_rulebuf *r, struct fwd_cidr *c, struct fwd_portrange *p +/* add --icmp-type (of applicable) */ +static void fwd_r_add_icmptype( + struct fwd_xt_rule *r, struct fwd_icmptype *i ) { - if( c != NULL ) + 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) ) { - fwd_ipt_rule_append(r, " -j DNAT --to-destination %s", - inet_ntoa(c->addr)); + /* 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); - if( (p != NULL) && (p->min < p->max) ) - fwd_ipt_rule_append(r, ":%u-%u", p->min, p->max); - else if( p != NULL ) - fwd_ipt_rule_append(r, ":%u", p->min); + fwd_xt_parse_match(r, m, "--icmp-type", buf); + } } } -static void fwd_ipt_exec(struct fwd_ipt_rulebuf *r) -{ - if( r->len ) - printf("%s\n", r->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]; - fwd_free_ptr(r->buf); - fwd_free_ptr(r); -} + 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]); -static const char * fwd_str_policy(enum fwd_policy pol) -{ - return (pol == FWD_P_ACCEPT ? "ACCEPT" : "DROP"); + fwd_xt_parse_match(r, m, "--mac-source", buf); + } + } } -static const char * fwd_str_target(enum fwd_policy pol) -{ +/* add policy target */ +static void fwd_r_add_policytarget( + struct fwd_xt_rule *r, enum fwd_policy pol +) { switch(pol) { case FWD_P_ACCEPT: - return "ACCEPT"; + fwd_xt_get_target(r, "handle_accept"); + break; case FWD_P_REJECT: - return "REJECT"; + fwd_xt_get_target(r, "handle_reject"); + break; - default: - return "DROP"; + 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]; - return "DROP"; + 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); + } + } } 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_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)); + 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_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"); + 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_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"); + 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_ipt_exec_format("filter", " -A INPUT -i lo -j ACCEPT"); - fwd_ipt_exec_format("filter", " -A OUTPUT -o lo -j ACCEPT"); + fwd_r_accept_lo(h_filter); /* syn flood protection */ if( def->syn_flood ) { - fwd_ipt_exec_format("filter", " -N syn_flood"); - - 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); - - fwd_ipt_exec_format("filter", " -A syn_flood -j DROP"); - fwd_ipt_exec_format("filter", " -A INPUT -p tcp --syn -j syn_flood"); + fwd_r_add_synflood(h_filter, def); } - /* 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"); + /* 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); } -static void fwd_ipt_zone_create(struct fwd_data *d) -{ - struct fwd_zone *z = &d->section.zone; - - if( !strcmp(z->name, "loopback") ) - return; - - 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); - - 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)); - 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)); - - if( z->output != FWD_P_UNSPEC ) - fwd_ipt_exec_format("filter", " -A output -j zone_%s_%s", - z->name, fwd_str_target(z->output)); - - 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); - - if( z->masq ) - fwd_ipt_exec_format("nat", " -A POSTROUTING -j zone_%s_nat", - z->name); - - if( z->mtu_fix ) - fwd_ipt_exec_format("filter", " -A FORWARD -j zone_%s_MSSFIX", - z->name); -} - -static void fwd_ipt_forwarding_create(struct fwd_data *d) +void fwd_ipt_build_ruleset(struct fwd_handle *h) { - struct fwd_forwarding *f = &d->section.forwarding; - struct fwd_ipt_rulebuf *b; + struct fwd_data *e; - b = fwd_ipt_init("filter"); + fwd_xt_init(); - 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"); + for( e = h->conf; e; e = e->next ) + { + switch(e->type) + { + case FWD_S_DEFAULTS: + printf("\n## DEFAULTS\n"); + fwd_ipt_defaults_create(e); + break; - if( f->dest ) - fwd_ipt_add_format(b, " -j zone_%s_ACCEPT", f->dest->name); - else - fwd_ipt_add_format(b, " -j ACCEPT"); + case FWD_S_INCLUDE: + printf("\n## INCLUDE %s\n", e->section.include.path); + break; - fwd_ipt_exec(b); + case FWD_S_ZONE: + case FWD_S_FORWARD: + case FWD_S_REDIRECT: + case FWD_S_RULE: + /* Make gcc happy */ + break; + } + } } -static void fwd_ipt_redirect_create(struct fwd_data *d) -{ - struct fwd_redirect *r = &d->section.redirect; - struct fwd_ipt_rulebuf *b; - - 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); -} -static void fwd_ipt_rule_create(struct fwd_data *d) +static struct fwd_zone * +fwd_lookup_zone(struct fwd_handle *h, const char *net) { - struct fwd_rule *r = &d->section.rule; - struct fwd_ipt_rulebuf *b; - - b = fwd_ipt_init("filter"); - - 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); -} + struct fwd_data *e; + struct fwd_network_list *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_list * -fwd_lookup_network(struct fwd_network_list *n, const char *net) +fwd_lookup_network(struct fwd_zone *z, const char *net) { - struct fwd_network_list *e; + struct fwd_network_list *n; - if( n != NULL ) - for( e = n; e; e = e->next ) - if( !strcmp(e->name, net) ) - return e; + for( n = z->networks; n; n = n->next ) + if( !strcmp(n->name, net) ) + return n; return NULL; } static struct fwd_addr_list * -fwd_lookup_addr(struct fwd_addr_list *a, const char *ifname) +fwd_lookup_addr(struct fwd_handle *h, struct fwd_network_list *n) { - struct fwd_addr_list *e; + struct fwd_addr_list *a; - if( a != NULL ) - for( e = a; e; e = e->next ) - if( !strcmp(e->ifname, ifname) ) - return e; + if( n != NULL ) + for( a = h->addrs; a; a = a->next ) + if( !strcmp(a->ifname, n->ifname) ) + return a; return NULL; } - -void fwd_ipt_build_ruleset(struct fwd_handle *h) +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_addr_list *a, *a2; + struct fwd_network_list *n, *n2; + struct fwd_proto p; - for( e = h->conf; e; e = e->next ) - { - switch(e->type) - { - case FWD_S_DEFAULTS: - printf("\n## DEFAULTS\n"); - fwd_ipt_defaults_create(e); - break; + struct fwd_xt_rule *x; + struct xtables_match *m; + struct xtables_target *t; - case FWD_S_ZONE: - printf("\n## ZONE %s\n", e->section.zone.name); - fwd_ipt_zone_create(e); - break; + struct iptc_handle *h_filter, *h_nat; - 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; + if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) ) + fwd_fatal("Unable to obtain libiptc handle"); - 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; + if( !(z = fwd_lookup_zone(h, net)) ) + return; - case FWD_S_INCLUDE: - printf("\n## INCLUDE %s\n", e->section.include.path); - break; - } - } -} + if( !(n = fwd_lookup_network(z, net)) ) + return; -void fwd_ipt_addif(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; + if( !(a = fwd_lookup_addr(h, n)) ) + return; - for( e = h->conf; e; e = e->next ) + printf("\n\n#\n# addif(%s)\n#\n", net); + + /* Build masquerading rule */ + if( z->masq ) { - if( (e->type != FWD_S_ZONE) || - !(n = fwd_lookup_network(e->section.zone.networks, net)) || - !(a = fwd_lookup_addr(h->addrs, n->ifname)) ) - continue; + printf("\n# Net %s (%s) - masq\n", n->name, n->ifname); - z = &e->section.zone; + 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, NULL, n); /* -m comment ... */ + fwd_xt_exec_rule(x, "zonemasq"); /* -A zonemasq */ + } + } + + /* Build MSS fix rule */ + if( z->mtu_fix ) + { + printf("\n# Net %s (%s) - mtu_fix\n", n->name, n->ifname); - printf("\n## NETWORK %s (%s - %s/%u)\n", - n->name, n->ifname, - inet_ntoa(a->ipaddr.v4), a->prefix - ); + 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 */ - fwd_ipt_exec_format("filter", " -A input -i %s -j zone_%s", - n->ifname, z->name); + /* -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"); - 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); + /* -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"); - fwd_ipt_exec_format("filter", " -I zone_%s_ACCEPT 1 -o %s -j ACCEPT", - z->name, n->ifname); + /* -m comment ... */ + fwd_r_add_comment(x, "mssfix", z, NULL, n); - fwd_ipt_exec_format("filter", " -I zone_%s_DROP 1 -o %s -j DROP", - z->name, n->ifname); + /* -A mssfix */ + fwd_xt_exec_rule(x, "mssfix"); + } + } - fwd_ipt_exec_format("filter", " -I zone_%s_REJECT 1 -o %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); + + 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, n2); /* -m comment ... */ + fwd_xt_exec_rule(x, "zones"); /* -A zones */ + } + } + } - fwd_ipt_exec_format("filter", " -I zone_%s_ACCEPT 1 -i %s -j ACCEPT", - 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 */ + 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, n2); /* -m comment ... */ + fwd_xt_exec_rule(x, "forwardings"); /* -A forwardings */ + } + } + } - fwd_ipt_exec_format("filter", " -I zone_%s_DROP 1 -i %s -j DROP", - z->name, n->ifname); + /* 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); - fwd_ipt_exec_format("filter", " -I zone_%s_REJECT 1 -i %s -j reject", - z->name, n->ifname); + /* 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->ipaddr, 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, NULL); /* -m comment ... */ + fwd_xt_exec_rule(x, "redirects"); /* -A redirects */ + } - fwd_ipt_exec_format("filter", - " -I zone_%s_nat 1 -t nat -o %s -j MASQUERADE", - z->name, n->ifname); + /* 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, NULL); /* -m comment ... */ + fwd_xt_exec_rule(x, "redirects"); /* -A redirects */ + } - fwd_ipt_exec_format("filter", - " -I PREROUTING 1 -t nat -i %s -j zone_%s_prerouting", - n->ifname, z->name); + /* 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, NULL); /* -m comment ... */ + fwd_xt_exec_rule(x, "loopback"); /* -A loopback */ + } + } + } - 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); + + 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, n2); /* -m comment ... */ + fwd_xt_exec_rule(x, "rules"); /* -A rules */ + } + } + } - 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); + + 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, NULL); /* -m comment ... */ + fwd_xt_exec_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); }