/* * fwd - OpenWrt firewall daemon - iptables rule set * * Copyright (C) 2009 Jo-Philipp Wich * * The fwd program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * The fwd program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with the fwd program. If not, see http://www.gnu.org/licenses/. */ #include "fwd.h" #include "fwd_addr.h" #include "fwd_rules.h" #include "fwd_xtables.h" /* -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) { iptc_create_chain(chain, h); } /* -A -j */ static void fwd_r_jump_chain( struct iptc_handle *h, const char *chain1, const char *chain2 ) { struct fwd_xt_rule *r; if( (r = fwd_xt_init_rule(h)) != NULL ) { fwd_xt_get_target(r, chain2); fwd_xt_append_rule(r, chain1); } } /* -A -m state --state INVALID -j DROP */ static void fwd_r_drop_invalid(struct iptc_handle *h, const char *chain) { struct fwd_xt_rule *r; struct xtables_match *m; if( (r = fwd_xt_init_rule(h)) != NULL ) { if( (m = fwd_xt_get_match(r, "state")) != NULL ) { fwd_xt_parse_match(r, m, "--state", "INVALID"); fwd_xt_get_target(r, "DROP"); fwd_xt_append_rule(r, chain); } } } /* -A -m state --state RELATED,ESTABLISHED -j ACCEPT */ static void fwd_r_accept_related(struct iptc_handle *h, const char *chain) { struct fwd_xt_rule *r; struct xtables_match *m; if( (r = fwd_xt_init_rule(h)) != NULL ) { if( (m = fwd_xt_get_match(r, "state")) != NULL ) { fwd_xt_parse_match(r, m, "--state", "RELATED,ESTABLISHED"); fwd_xt_get_target(r, "ACCEPT"); fwd_xt_append_rule(r, chain); } } } /* -A INPUT -i lo -j ACCEPT; -A OUTPUT -o lo -j ACCEPT */ static void fwd_r_accept_lo(struct iptc_handle *h) { struct fwd_network_list n; struct fwd_xt_rule *r; n.ifname = "lo"; if( (r = fwd_xt_init_rule(h)) != NULL ) { fwd_xt_parse_in(r, &n, 0); fwd_xt_get_target(r, "ACCEPT"); fwd_xt_append_rule(r, "INPUT"); } if( (r = fwd_xt_init_rule(h)) != NULL ) { fwd_xt_parse_out(r, &n, 0); fwd_xt_get_target(r, "ACCEPT"); fwd_xt_append_rule(r, "OUTPUT"); } } /* build syn_flood chain and jump rule */ static void fwd_r_add_synflood(struct iptc_handle *h, struct fwd_defaults *def) { struct fwd_proto p; struct fwd_xt_rule *r; struct xtables_match *m; char buf[32]; /* -N syn_flood */ fwd_r_new_chain(h, "syn_flood"); /* return rule */ if( (r = fwd_xt_init_rule(h)) != NULL ) { /* -p tcp */ p.type = FWD_PR_TCP; fwd_xt_parse_proto(r, &p, 0); /* -m tcp --syn */ if( (m = fwd_xt_get_match(r, "tcp")) != NULL ) { fwd_xt_parse_match(r, m, "--syn"); } /* -m limit --limit x/second --limit-burst y */ if( (m = fwd_xt_get_match(r, "limit")) != NULL ) { sprintf(buf, "%i/second", def->syn_rate); fwd_xt_parse_match(r, m, "--limit", buf); sprintf(buf, "%i", def->syn_burst); fwd_xt_parse_match(r, m, "--limit-burst", buf); } /* -j RETURN; -A syn_flood */ fwd_xt_get_target(r, "RETURN"); fwd_xt_append_rule(r, "syn_flood"); } /* drop rule */ if( (r = fwd_xt_init_rule(h)) != NULL ) { /* -j DROP; -A syn_flood */ fwd_xt_get_target(r, "DROP"); fwd_xt_append_rule(r, "syn_flood"); } /* jump to syn_flood rule */ if( (r = fwd_xt_init_rule(h)) != NULL ) { /* -p tcp */ p.type = FWD_PR_TCP; fwd_xt_parse_proto(r, &p, 0); /* -m tcp --syn */ if( (m = fwd_xt_get_match(r, "tcp")) != NULL ) { fwd_xt_parse_match(r, m, "--syn"); } /* -j syn_flood; -A INPUT */ fwd_xt_get_target(r, "syn_flood"); fwd_xt_append_rule(r, "INPUT"); } } /* build reject target chain */ static void fwd_r_handle_reject(struct iptc_handle *h) { struct fwd_proto p; struct fwd_xt_rule *r; struct xtables_target *t; /* -N handle_reject */ fwd_r_new_chain(h, "handle_reject"); /* tcp reject rule */ if( (r = fwd_xt_init_rule(h)) != NULL ) { /* -p tcp */ p.type = FWD_PR_TCP; fwd_xt_parse_proto(r, &p, 0); /* -j REJECT --reject-with tcp-reset */ if( (t = fwd_xt_get_target(r, "REJECT")) != NULL ) { fwd_xt_parse_target(r, t, "--reject-with", "tcp-reset"); } /* -A handle_reject */ fwd_xt_append_rule(r, "handle_reject"); } /* common reject rule */ if( (r = fwd_xt_init_rule(h)) != NULL ) { /* -j REJECT --reject-with icmp-port-unreachable */ if( (t = fwd_xt_get_target(r, "REJECT")) != NULL ) { fwd_xt_parse_target(r, t, "--reject-with", "icmp-port-unreachable"); } /* -A handle_reject */ fwd_xt_append_rule(r, "handle_reject"); } } /* build drop target chain */ static void fwd_r_handle_drop(struct iptc_handle *h) { struct fwd_xt_rule *r; /* -N handle_drop */ fwd_r_new_chain(h, "handle_drop"); /* common drop rule */ if( (r = fwd_xt_init_rule(h)) != NULL ) { /* -j DROP; -A handle_drop */ fwd_xt_get_target(r, "DROP"); fwd_xt_append_rule(r, "handle_drop"); } } /* build accept target chain */ static void fwd_r_handle_accept(struct iptc_handle *h) { struct fwd_xt_rule *r; /* -N handle_accept */ fwd_r_new_chain(h, "handle_accept"); /* common accept rule */ if( (r = fwd_xt_init_rule(h)) != NULL ) { /* -j ACCEPT; -A handle_accept */ fwd_xt_get_target(r, "ACCEPT"); fwd_xt_append_rule(r, "handle_accept"); } } /* add comment match */ static void fwd_r_add_comment( struct fwd_xt_rule *r, const char *t, struct fwd_zone *z, struct fwd_network_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); } } } /* parse comment string and look for match */ static int fwd_r_cmp(const char *what, const char *cmt, const char *cmp) { char *match; if( (match = strstr(cmt, what)) == NULL ) return 0; match += strlen(what); if( strncmp(match, cmp, strlen(cmp)) != 0 ) return 0; if( (match[strlen(cmp)] != ' ') && (match[strlen(cmp)] != '\0') ) return 0; return 1; } static void fwd_ipt_defaults_create(struct fwd_data *d) { struct fwd_defaults *def = &d->section.defaults; struct iptc_handle *h_filter, *h_nat; if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) ) fwd_fatal("Unable to obtain libiptc handle"); /* policies */ fwd_r_set_policy(h_filter, "INPUT", def->input == FWD_P_ACCEPT ? "ACCEPT" : "DROP"); fwd_r_set_policy(h_filter, "OUTPUT", def->output == FWD_P_ACCEPT ? "ACCEPT" : "DROP"); fwd_r_set_policy(h_filter, "FORWARD", def->forward == FWD_P_ACCEPT ? "ACCEPT" : "DROP"); /* invalid state drop */ if( def->drop_invalid ) { fwd_r_drop_invalid(h_filter, "INPUT"); fwd_r_drop_invalid(h_filter, "OUTPUT"); fwd_r_drop_invalid(h_filter, "FORWARD"); } /* default accept related */ fwd_r_accept_related(h_filter, "INPUT"); fwd_r_accept_related(h_filter, "OUTPUT"); fwd_r_accept_related(h_filter, "FORWARD"); /* default accept on lo */ fwd_r_accept_lo(h_filter); /* syn flood protection */ if( def->syn_flood ) { fwd_r_add_synflood(h_filter, def); } /* rule container chains */ fwd_r_new_chain(h_filter, "mssfix"); fwd_r_new_chain(h_filter, "zones"); fwd_r_new_chain(h_filter, "rules"); fwd_r_new_chain(h_filter, "redirects"); fwd_r_new_chain(h_filter, "forwardings"); fwd_r_jump_chain(h_filter, "INPUT", "rules"); fwd_r_jump_chain(h_filter, "FORWARD", "mssfix"); fwd_r_jump_chain(h_filter, "FORWARD", "zones"); fwd_r_jump_chain(h_filter, "FORWARD", "rules"); fwd_r_jump_chain(h_filter, "FORWARD", "redirects"); fwd_r_jump_chain(h_filter, "FORWARD", "forwardings"); fwd_r_new_chain(h_nat, "zonemasq"); fwd_r_new_chain(h_nat, "redirects"); fwd_r_new_chain(h_nat, "loopback"); fwd_r_jump_chain(h_nat, "POSTROUTING", "zonemasq"); fwd_r_jump_chain(h_nat, "PREROUTING", "redirects"); fwd_r_jump_chain(h_nat, "POSTROUTING", "loopback"); /* standard drop, accept, reject chain */ fwd_r_handle_drop(h_filter); fwd_r_handle_accept(h_filter); fwd_r_handle_reject(h_filter); if( !iptc_commit(h_nat) ) fwd_fatal("Cannot commit nat table: %s", iptc_strerror(errno)); if( !iptc_commit(h_filter) ) fwd_fatal("Cannot commit filter table: %s", iptc_strerror(errno)); iptc_free(h_nat); iptc_free(h_filter); } void fwd_ipt_build_ruleset(struct fwd_handle *h) { struct fwd_data *e; fwd_xt_init(); for( e = h->conf; e; e = e->next ) { switch(e->type) { case FWD_S_DEFAULTS: printf("\n## DEFAULTS\n"); fwd_ipt_defaults_create(e); break; case FWD_S_INCLUDE: printf("\n## INCLUDE %s\n", e->section.include.path); break; case FWD_S_ZONE: case FWD_S_FORWARD: case FWD_S_REDIRECT: case FWD_S_RULE: /* Make gcc happy */ break; } } } static struct fwd_zone * fwd_lookup_zone(struct fwd_handle *h, const char *net) { struct fwd_data *e; struct fwd_network_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_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; } static struct fwd_addr_list * fwd_lookup_addr(struct fwd_handle *h, struct fwd_network_list *n) { struct fwd_addr_list *a; if( n != NULL ) for( a = h->addrs; a; a = a->next ) if( !strcmp(a->ifname, n->ifname) ) return a; return NULL; } void fwd_ipt_addif(struct fwd_handle *h, const char *net) { struct fwd_data *e; struct fwd_zone *z; struct fwd_rule *c; struct fwd_redirect *r; struct fwd_forwarding *f; struct fwd_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; if( !(n = fwd_lookup_network(z, net)) ) return; if( !(a = fwd_lookup_addr(h, n)) ) return; printf("\n\n#\n# addif(%s)\n#\n", net); /* Build masquerading rule */ if( z->masq ) { printf("\n# Net %s (%s) - masq\n", n->name, n->ifname); 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_append_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); 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_append_rule(x, "mssfix"); } } /* 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_append_rule(x, "zones"); /* -A zones */ } } } /* Build inter-zone forwarding rules */ for( e = z->forwardings; e && (f = &e->section.forwarding); e = e->next ) { for( n2 = f->dest->networks; n2; n2 = n2->next ) { 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_append_rule(x, "forwardings"); /* -A forwardings */ } } } /* 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 */ 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_append_rule(x, "redirects"); /* -A redirects */ } /* Forward */ if( (x = fwd_xt_init_rule(h_filter)) != NULL ) { fwd_xt_parse_in(x, n, 0); /* -i ... */ fwd_xt_parse_src(x, r->src_ip, 0); /* -s ... */ fwd_xt_parse_dest(x, r->dest_ip, 0); /* -d ... */ fwd_xt_parse_proto(x, r->proto, 0); /* -p ... */ fwd_r_add_srcmac(x, r->src_mac); /* -m mac --mac-source ... */ fwd_r_add_sport(x, r->src_port); /* --sport ... */ fwd_r_add_dport(x, r->dest_port); /* --dport ... */ fwd_r_add_policytarget(x, FWD_P_ACCEPT); /* -j handle_accept */ fwd_r_add_comment(x, "redir", z, n, NULL); /* -m comment ... */ fwd_xt_append_rule(x, "redirects"); /* -A redirects */ } /* Add loopback rule if neither src_ip nor src_mac are defined */ if( !r->src_ip && !r->src_mac ) { if( (x = fwd_xt_init_rule(h_nat)) != NULL ) { fwd_xt_parse_in(x, n, 1); /* -i ! ... */ fwd_xt_parse_dest(x, r->dest_ip, 0); /* -d ... */ fwd_xt_parse_proto(x, r->proto, 0); /* -p ... */ fwd_r_add_sport(x, r->src_port); /* --sport ... */ fwd_r_add_dport(x, r->src_dport); /* --dport ... */ fwd_xt_get_target(x, "MASQUERADE"); /* -j MASQUERADE */ fwd_r_add_comment(x, "redir", z, n, NULL); /* -m comment ... */ fwd_xt_append_rule(x, "loopback"); /* -A loopback */ } } } /* Build rules */ for( e = z->rules; e && (c = &e->section.rule); e = e->next ) { /* Has destination, add forward rule for each network in target zone */ if( c->dest ) { for( n2 = c->dest->networks; n2; n2 = n2->next ) { 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_append_rule(x, "rules"); /* -A rules */ } } } /* 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_append_rule(x, "rules"); /* -A rules */ } } } if( !iptc_commit(h_nat) ) fwd_fatal("Cannot commit nat table: %s", iptc_strerror(errno)); if( !iptc_commit(h_filter) ) fwd_fatal("Cannot commit filter table: %s", iptc_strerror(errno)); iptc_free(h_nat); iptc_free(h_filter); } static void fwd_ipt_delif_table(struct iptc_handle *h, const char *net) { struct xt_entry_match *m; struct ipt_entry *e; const char *chain, *comment; size_t off = 0, num = 0; /* iterate chains */ for( chain = iptc_first_chain(h); chain; chain = iptc_next_chain(h) ) { /* iterate rules */ for( e = iptc_first_rule(chain, h), num = 0; e; e = iptc_next_rule(e, h), num++ ) { repeat_rule: /* skip entries w/o matches */ if( ! e->target_offset ) continue; /* iterate matches */ for( off = sizeof(struct ipt_entry); off < e->target_offset; off += m->u.match_size ) { m = (void *)e + off; /* yay */ if( ! strcmp(m->u.user.name, "comment") ) { /* better use struct_xt_comment_info but well... */ comment = (void *)m + sizeof(struct xt_entry_match); if( fwd_r_cmp("src:", comment, net) ) { e = iptc_next_rule(e, h); iptc_delete_num_entry(chain, num, h); if( e != NULL ) goto repeat_rule; else break; } } } } } } void fwd_ipt_delif(struct fwd_handle *h, const char *net) { struct iptc_handle *h_filter, *h_nat; if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) ) fwd_fatal("Unable to obtain libiptc handle"); printf("\n\n#\n# delif(%s)\n#\n", net); /* delete network related rules */ fwd_ipt_delif_table(h_nat, net); fwd_ipt_delif_table(h_filter, net); if( !iptc_commit(h_nat) ) fwd_fatal("Cannot commit nat table: %s", iptc_strerror(errno)); if( !iptc_commit(h_filter) ) fwd_fatal("Cannot commit filter table: %s", iptc_strerror(errno)); iptc_free(h_nat); iptc_free(h_filter); } static void fwd_ipt_clear_ruleset_table(struct iptc_handle *h) { const char *chain; /* pass 1: flush all chains */ for( chain = iptc_first_chain(h); chain; chain = iptc_next_chain(h) ) { iptc_flush_entries(chain, h); } /* pass 2: remove user defined chains */ for( chain = iptc_first_chain(h); chain; chain = iptc_next_chain(h) ) { if( ! iptc_builtin(chain, h) ) iptc_delete_chain(chain, h); } } void fwd_ipt_clear_ruleset(struct fwd_handle *h) { struct iptc_handle *h_filter, *h_nat; if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) ) fwd_fatal("Unable to obtain libiptc handle"); /* flush tables */ fwd_ipt_clear_ruleset_table(h_nat); fwd_ipt_clear_ruleset_table(h_filter); /* revert policies */ fwd_r_set_policy(h_filter, "INPUT", "ACCEPT"); fwd_r_set_policy(h_filter, "OUTPUT", "ACCEPT"); fwd_r_set_policy(h_filter, "FORWARD", "ACCEPT"); if( !iptc_commit(h_nat) ) fwd_fatal("Cannot commit nat table: %s", iptc_strerror(errno)); if( !iptc_commit(h_filter) ) fwd_fatal("Cannot commit filter table: %s", iptc_strerror(errno)); iptc_free(h_nat); iptc_free(h_filter); }