diff options
-rw-r--r-- | contrib/fwd/src/Makefile | 2 | ||||
-rw-r--r-- | contrib/fwd/src/fwd.h | 8 | ||||
-rw-r--r-- | contrib/fwd/src/fwd_addr.c | 4 | ||||
-rw-r--r-- | contrib/fwd/src/fwd_addr.h | 6 | ||||
-rw-r--r-- | contrib/fwd/src/fwd_config.c | 101 | ||||
-rw-r--r-- | contrib/fwd/src/fwd_rules.c | 569 |
6 files changed, 363 insertions, 327 deletions
diff --git a/contrib/fwd/src/Makefile b/contrib/fwd/src/Makefile index 89efd7b065..c147c67060 100644 --- a/contrib/fwd/src/Makefile +++ b/contrib/fwd/src/Makefile @@ -1,4 +1,4 @@ -CFLAGS := -g -Wall -I./uci -I./iptables-1.4.5/include +CFLAGS := -ggdb3 -O0 -Wall -I./uci -I./iptables-1.4.5/include LDFLAGS := -luci -liptc -lxtables -ldl -L./iptables-1.4.5/libiptc/.libs -L./iptables-1.4.5/.libs -Wl,--export-dynamic fwd: diff --git a/contrib/fwd/src/fwd.h b/contrib/fwd/src/fwd.h index c93c0aff90..0228daf7b6 100644 --- a/contrib/fwd/src/fwd.h +++ b/contrib/fwd/src/fwd.h @@ -24,6 +24,7 @@ #include <unistd.h> #include <stdarg.h> #include <stdlib.h> +#include <getopt.h> #include <netinet/in.h> #if 0 @@ -36,7 +37,7 @@ enum fwd_policy { FWD_P_UNSPEC = 0, FWD_P_DROP = 1, FWD_P_REJECT = 2, - FWD_P_ACCEPT = 3 + FWD_P_ACCEPT = 3 }; enum fwd_stype { @@ -103,6 +104,9 @@ struct fwd_defaults { struct fwd_zone { char *name; struct fwd_network_list *networks; + struct fwd_data *forwardings; + struct fwd_data *redirects; + struct fwd_data *rules; enum fwd_policy input; enum fwd_policy forward; enum fwd_policy output; @@ -127,6 +131,7 @@ struct fwd_redirect { struct fwd_cidr *dest_ip; struct fwd_portrange *dest_port; struct fwd_proto *proto; + int clone; /* true if rule is cloned (tcpudp -> tcp + udp) */ }; struct fwd_rule { @@ -140,6 +145,7 @@ struct fwd_rule { struct fwd_proto *proto; struct fwd_icmptype *icmp_type; enum fwd_policy target; + int clone; /* true if rule is cloned (tcpudp -> tcp + udp) */ }; struct fwd_include { diff --git a/contrib/fwd/src/fwd_addr.c b/contrib/fwd/src/fwd_addr.c index df5d8e7c2a..fd277e9e0f 100644 --- a/contrib/fwd/src/fwd_addr.c +++ b/contrib/fwd/src/fwd_addr.c @@ -95,8 +95,8 @@ struct fwd_addr_list * fwd_get_addrs(int fd, int family) { if( rtatp->rta_type == IFA_ADDRESS ) { - memcpy(&entry->ipaddr, (char *) RTA_DATA(rtatp), rtatp->rta_len); - entry->prefix = rtmp->ifa_prefixlen; + memcpy(&entry->ipaddr.addr, (char *) RTA_DATA(rtatp), rtatp->rta_len); + entry->ipaddr.prefix = rtmp->ifa_prefixlen; entry->family = family; } else if( rtatp->rta_type == IFA_LABEL) diff --git a/contrib/fwd/src/fwd_addr.h b/contrib/fwd/src/fwd_addr.h index 1a28f64641..44465705af 100644 --- a/contrib/fwd/src/fwd_addr.h +++ b/contrib/fwd/src/fwd_addr.h @@ -33,11 +33,7 @@ struct fwd_addr_list { char label[IFNAMSIZ]; int family; int index; - unsigned int prefix; - union { - struct in_addr v4; - struct in6_addr v6; - } ipaddr; + struct fwd_cidr ipaddr; struct fwd_addr_list *next; }; diff --git a/contrib/fwd/src/fwd_config.c b/contrib/fwd/src/fwd_config.c index 11fd458325..a77965cf5a 100644 --- a/contrib/fwd/src/fwd_config.c +++ b/contrib/fwd/src/fwd_config.c @@ -163,11 +163,17 @@ fwd_read_mac(struct uci_context *uci, const char *s, const char *o, struct fwd_m { if( (*m = fwd_alloc_ptr(struct fwd_mac)) != NULL ) { + unsigned int i1, i2, i3, i4, i5, i6; + if( sscanf(val, "%2x:%2x:%2x:%2x:%2x:%2x", - (unsigned int *)&(*m)->mac[0], (unsigned int *)&(*m)->mac[1], - (unsigned int *)&(*m)->mac[2], (unsigned int *)&(*m)->mac[3], - (unsigned int *)&(*m)->mac[4], (unsigned int *)&(*m)->mac[5]) == 6 + &i1, &i2, &i3, &i4, &i5, &i6) == 6 ) { + (*m)->mac[0] = (unsigned char)i1; + (*m)->mac[1] = (unsigned char)i2; + (*m)->mac[2] = (unsigned char)i3; + (*m)->mac[3] = (unsigned char)i4; + (*m)->mac[4] = (unsigned char)i5; + (*m)->mac[5] = (unsigned char)i6; return 0; } } @@ -470,17 +476,14 @@ static void fwd_read_forwards_cb( struct fwd_zone *zsrc = NULL; struct fwd_zone *zdest = NULL; - if( (src = fwd_read_string(uci, s, "src")) != NULL ) - { - if( !(zsrc = fwd_lookup_zone(cv->head, src)) ) - fwd_read_error("section '%s' references unknown src zone '%s'!", s, src); - } - - if( (dest = fwd_read_string(uci, s, "dest")) != NULL ) - { - if( !(zdest = fwd_lookup_zone(cv->head, dest)) ) - fwd_read_error("section '%s' references unknown dest zone '%s'!", s, dest); - } + if( !(src = fwd_read_string(uci, s, "src")) ) + fwd_read_error("section '%s' is missing 'src' option!", s); + else if( !(zsrc = fwd_lookup_zone(cv->head, src)) ) + fwd_read_error("section '%s' references unknown src zone '%s'!", s, src); + else if( !(dest = fwd_read_string(uci, s, "dest")) ) + fwd_read_error("section '%s' is missing 'dest' option!", s); + else if( !(zdest = fwd_lookup_zone(cv->head, dest)) ) + fwd_read_error("section '%s' references unknown dest zone '%s'!", s, dest); if( (dtn = fwd_alloc_ptr(struct fwd_data)) != NULL ) { @@ -490,8 +493,17 @@ static void fwd_read_forwards_cb( dtn->section.forwarding.masq = fwd_read_bool(uci, s, "masq", 0); dtn->type = FWD_S_FORWARD; - dtn->next = cv->cursor; - cv->cursor = dtn; + + if( zsrc ) + { + dtn->next = zsrc->forwardings; + zsrc->forwardings = dtn; + } + else + { + dtn->next = cv->cursor; + cv->cursor = dtn; + } } else { @@ -560,8 +572,8 @@ static void fwd_read_redirects_cb( dtn->section.redirect.dest_port = dest_port; dtn->type = FWD_S_REDIRECT; - dtn->next = cv->cursor; - cv->cursor = dtn; + dtn->next = zsrc->redirects; + zsrc->redirects = dtn; if( (proto != NULL) && (proto->type == FWD_PR_TCPUDP) ) { @@ -582,10 +594,11 @@ static void fwd_read_redirects_cb( dtn2->section.redirect.src_dport = src_dport; dtn2->section.redirect.dest_ip = dest_ip; dtn2->section.redirect.dest_port = dest_port; + dtn2->section.redirect.clone = 1; dtn2->type = FWD_S_REDIRECT; - dtn2->next = cv->cursor; - cv->cursor = dtn2; + dtn2->next = zsrc->redirects; + zsrc->redirects = dtn2; } } else @@ -665,8 +678,8 @@ static void fwd_read_rules_cb( dtn->section.rule.target = fwd_read_policy(uci, s, "target"); dtn->type = FWD_S_RULE; - dtn->next = cv->cursor; - cv->cursor = dtn; + dtn->next = zsrc->rules; + zsrc->rules = dtn; if( (proto != NULL) && (proto->type == FWD_PR_TCPUDP) ) { @@ -688,10 +701,11 @@ static void fwd_read_rules_cb( dtn2->section.rule.dest_ip = dest_ip; dtn2->section.rule.dest_port = dest_port; dtn2->section.rule.target = dtn->section.rule.target; + dtn2->section.rule.clone = 1; dtn2->type = FWD_S_RULE; - dtn2->next = cv->cursor; - cv->cursor = dtn2; + dtn2->next = zsrc->rules; + zsrc->rules = dtn2; } } else @@ -868,26 +882,39 @@ void fwd_free_config(struct fwd_data *h) case FWD_S_ZONE: fwd_free_ptr(h->section.zone.name); fwd_free_networks(h->section.zone.networks); + fwd_free_config(h->section.zone.rules); + fwd_free_config(h->section.zone.redirects); + fwd_free_config(h->section.zone.forwardings); break; case FWD_S_REDIRECT: - fwd_free_ptr(h->section.redirect.src_ip); - fwd_free_ptr(h->section.redirect.src_mac); - fwd_free_ptr(h->section.redirect.src_port); - fwd_free_ptr(h->section.redirect.src_dport); - fwd_free_ptr(h->section.redirect.dest_ip); - fwd_free_ptr(h->section.redirect.dest_port); + /* Clone rules share all pointers except proto. + Prevent a double-free here */ + if( ! h->section.redirect.clone ) + { + fwd_free_ptr(h->section.redirect.src_ip); + fwd_free_ptr(h->section.redirect.src_mac); + fwd_free_ptr(h->section.redirect.src_port); + fwd_free_ptr(h->section.redirect.src_dport); + fwd_free_ptr(h->section.redirect.dest_ip); + fwd_free_ptr(h->section.redirect.dest_port); + } fwd_free_ptr(h->section.redirect.proto); break; case FWD_S_RULE: - fwd_free_ptr(h->section.rule.src_ip); - fwd_free_ptr(h->section.rule.src_mac); - fwd_free_ptr(h->section.rule.src_port); - fwd_free_ptr(h->section.rule.dest_ip); - fwd_free_ptr(h->section.rule.dest_port); + /* Clone rules share all pointers except proto. + Prevent a double-free here */ + if( ! h->section.rule.clone ) + { + fwd_free_ptr(h->section.rule.src_ip); + fwd_free_ptr(h->section.rule.src_mac); + fwd_free_ptr(h->section.rule.src_port); + fwd_free_ptr(h->section.rule.dest_ip); + fwd_free_ptr(h->section.rule.dest_port); + fwd_free_ptr(h->section.rule.icmp_type); + } fwd_free_ptr(h->section.rule.proto); - fwd_free_ptr(h->section.rule.icmp_type); break; case FWD_S_DEFAULTS: @@ -896,7 +923,7 @@ void fwd_free_config(struct fwd_data *h) break; } - free(h); + fwd_free_ptr(h); h = e; } diff --git a/contrib/fwd/src/fwd_rules.c b/contrib/fwd/src/fwd_rules.c index c3d4ebbe53..e6604911a7 100644 --- a/contrib/fwd/src/fwd_rules.c +++ b/contrib/fwd/src/fwd_rules.c @@ -22,199 +22,6 @@ #include "fwd_rules.h" #include "fwd_xtables.h" -static void -fwd_ipt_rule_append(struct fwd_ipt_rulebuf *r, const char *fmt, ...) -{ - int len = 0; - char buf[256]; buf[0] = 0; - - va_list ap; - va_start(ap, fmt); - len = vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - - if( len > 0 ) - { - 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; - } -} - -static struct fwd_ipt_rulebuf * fwd_ipt_init(const char *table) -{ - struct fwd_ipt_rulebuf *r; - - if( (r = fwd_alloc_ptr(struct fwd_ipt_rulebuf)) != NULL ) - { - fwd_ipt_rule_append(r, IPT " -t %s", table); - return r; - } - - return NULL; -} - -static void fwd_ipt_add_srcport( - struct fwd_ipt_rulebuf *r, struct fwd_portrange *p -) { - if( p != 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); - } -} - -static void fwd_ipt_add_destport( - struct fwd_ipt_rulebuf *r, struct fwd_portrange *p -) { - if( p != 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); - } -} - -static void fwd_ipt_add_proto( - struct fwd_ipt_rulebuf *r, struct fwd_proto *p -) { - if( p != NULL ) - { - switch( p->type ) - { - case FWD_PR_TCPUDP: - fwd_ipt_rule_append(r, " -p tcp -p udp"); - break; - - case FWD_PR_TCP: - fwd_ipt_rule_append(r, " -p tcp"); - break; - - case FWD_PR_UDP: - fwd_ipt_rule_append(r, " -p udp"); - break; - - case FWD_PR_ICMP: - fwd_ipt_rule_append(r, " -p icmp"); - break; - - case FWD_PR_ALL: - fwd_ipt_rule_append(r, " -p all"); - break; - - case FWD_PR_CUSTOM: - fwd_ipt_rule_append(r, " -p %u", p->proto); - break; - } - } -} - -static void fwd_ipt_add_srcaddr( - struct fwd_ipt_rulebuf *r, struct fwd_cidr *c -) { - if( c != 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)); - } -} - -static void fwd_ipt_add_destaddr( - struct fwd_ipt_rulebuf *r, struct fwd_cidr *c -) { - if( c != NULL ) - { - if( c->prefix < 32 ) - fwd_ipt_rule_append(r, " -d %s/%u", - inet_ntoa(c->addr), c->prefix); - else - fwd_ipt_rule_append(r, " -d %s", inet_ntoa(c->addr)); - } -} - -static void fwd_ipt_add_srcmac( - struct fwd_ipt_rulebuf *r, struct fwd_mac *m -) { - if( m != NULL ) - { - 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]); - } -} - -static void fwd_ipt_add_icmptype( - struct fwd_ipt_rulebuf *r, struct fwd_icmptype *i -) { - if( i != NULL ) - { - 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); - } -} - -static void fwd_ipt_add_dnat_target( - struct fwd_ipt_rulebuf *r, struct fwd_cidr *c, struct fwd_portrange *p -) { - if( c != NULL ) - { - fwd_ipt_rule_append(r, " -j DNAT --to-destination %s", - inet_ntoa(c->addr)); - - 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); - } -} - -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 ) - printf("%s\n", r->buf); - - fwd_free_ptr(r->buf); - fwd_free_ptr(r); -} /* -P <chain> <policy> */ static void fwd_r_set_policy( @@ -252,7 +59,7 @@ static void fwd_r_drop_invalid(struct iptc_handle *h, const char *chain) { if( (m = fwd_xt_get_match(r, "state")) != NULL ) { - fwd_xt_parse_match(r, m, "--state", "INVALID", 0); + fwd_xt_parse_match(r, m, "--state", "INVALID"); fwd_xt_get_target(r, "DROP"); fwd_xt_exec_rule(r, chain); } @@ -269,7 +76,7 @@ static void fwd_r_accept_related(struct iptc_handle *h, const char *chain) { if( (m = fwd_xt_get_match(r, "state")) != NULL ) { - fwd_xt_parse_match(r, m, "--state", "RELATED,ESTABLISHED", 0); + fwd_xt_parse_match(r, m, "--state", "RELATED,ESTABLISHED"); fwd_xt_get_target(r, "ACCEPT"); fwd_xt_exec_rule(r, chain); } @@ -320,17 +127,17 @@ static void fwd_r_add_synflood(struct iptc_handle *h, struct fwd_defaults *def) /* -m tcp --syn */ if( (m = fwd_xt_get_match(r, "tcp")) != NULL ) { - fwd_xt_parse_match(r, m, "--syn", NULL, 0); + 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, 0); + fwd_xt_parse_match(r, m, "--limit", buf); sprintf(buf, "%i", def->syn_burst); - fwd_xt_parse_match(r, m, "--limit-burst", buf, 0); + fwd_xt_parse_match(r, m, "--limit-burst", buf); } /* -j RETURN; -A syn_flood */ @@ -356,7 +163,7 @@ static void fwd_r_add_synflood(struct iptc_handle *h, struct fwd_defaults *def) /* -m tcp --syn */ if( (m = fwd_xt_get_match(r, "tcp")) != NULL ) { - fwd_xt_parse_match(r, m, "--syn", NULL, 0); + fwd_xt_parse_match(r, m, "--syn"); } /* -j syn_flood; -A INPUT */ @@ -385,7 +192,7 @@ static void fwd_r_handle_reject(struct iptc_handle *h) /* -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); + fwd_xt_parse_target(r, t, "--reject-with", "tcp-reset"); } /* -A handle_reject */ @@ -399,7 +206,7 @@ static void fwd_r_handle_reject(struct iptc_handle *h) if( (t = fwd_xt_get_target(r, "REJECT")) != NULL ) { fwd_xt_parse_target(r, t, "--reject-with", - "icmp-port-unreachable", 0); + "icmp-port-unreachable"); } /* -A handle_reject */ @@ -441,6 +248,155 @@ static void fwd_r_handle_accept(struct iptc_handle *h) } } +/* 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 +) { + struct xtables_match *m; + char buf[256]; + + if( (m = fwd_xt_get_match(r, "comment")) != NULL ) + { + 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 + snprintf(buf, sizeof(buf), "%s:%s src:%s", t, z->name, n->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); + } + } +} + static void fwd_ipt_defaults_create(struct fwd_data *d) { @@ -494,9 +450,10 @@ static void fwd_ipt_defaults_create(struct fwd_data *d) 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", "redirects"); + fwd_r_jump_chain(h_nat, "POSTROUTING", "loopback"); /* standard drop, accept, reject chain */ fwd_r_handle_drop(h_filter); @@ -589,12 +546,22 @@ 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; + 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; @@ -612,10 +579,13 @@ void fwd_ipt_addif(struct fwd_handle *h, const char *net) { printf("\n# Net %s (%s) - masq\n", n->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); + 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 */ @@ -623,12 +593,26 @@ void fwd_ipt_addif(struct fwd_handle *h, const char *net) { 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); + 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, NULL, n); + + /* -A mssfix */ + fwd_xt_exec_rule(x, "mssfix"); + } } /* Build intra-zone forwarding rules */ @@ -641,12 +625,14 @@ void fwd_ipt_addif(struct fwd_handle *h, const char *net) 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); + 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 */ + } } } @@ -661,12 +647,14 @@ void fwd_ipt_addif(struct fwd_handle *h, const char *net) 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); + 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 */ + } } } @@ -677,43 +665,49 @@ void fwd_ipt_addif(struct fwd_handle *h, const char *net) 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); + 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 */ + } /* 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); + 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 */ + } /* 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); + 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 */ + } } } @@ -730,19 +724,21 @@ void fwd_ipt_addif(struct fwd_handle *h, const char *net) 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); + 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 */ + } } } @@ -752,19 +748,30 @@ void fwd_ipt_addif(struct fwd_handle *h, const char *net) 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); + 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); } |