#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 <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)
{
- 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 <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( 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 <chain> -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 <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( 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);
}