X-Git-Url: http://git.archive.openwrt.org/?p=project%2Ffirewall3.git;a=blobdiff_plain;f=redirects.c;h=3c0ffada64fc8978a3aa7ff90766db652f9b295f;hp=da149713fb3dfebece93a444e9872c69b0947db6;hb=78e134ba7cdc473e7cdf0422b863579ac700ac13;hpb=1ccbcc2642e5cfeed375cf56130ab6ecaad35052 diff --git a/redirects.c b/redirects.c index da14971..3c0ffad 100644 --- a/redirects.c +++ b/redirects.c @@ -19,35 +19,96 @@ #include "redirects.h" -static struct fw3_option redirect_opts[] = { - FW3_OPT("name", string, redirect, name), - FW3_OPT("family", family, redirect, family), +const struct fw3_option fw3_redirect_opts[] = { + FW3_OPT("enabled", bool, redirect, enabled), - FW3_OPT("src", device, redirect, src), - FW3_OPT("dest", device, redirect, dest), + FW3_OPT("name", string, redirect, name), + FW3_OPT("family", family, redirect, family), - FW3_OPT("ipset", device, redirect, ipset), + FW3_OPT("src", device, redirect, src), + FW3_OPT("dest", device, redirect, dest), - FW3_LIST("proto", protocol, redirect, proto), + FW3_OPT("ipset", device, redirect, ipset), - FW3_OPT("src_ip", address, redirect, ip_src), - FW3_LIST("src_mac", mac, redirect, mac_src), - FW3_OPT("src_port", port, redirect, port_src), + FW3_LIST("proto", protocol, redirect, proto), - FW3_OPT("src_dip", address, redirect, ip_dest), - FW3_OPT("src_dport", port, redirect, port_dest), + FW3_OPT("src_ip", address, redirect, ip_src), + FW3_LIST("src_mac", mac, redirect, mac_src), + FW3_OPT("src_port", port, redirect, port_src), - FW3_OPT("dest_ip", address, redirect, ip_redir), - FW3_OPT("dest_port", port, redirect, port_redir), + FW3_OPT("src_dip", address, redirect, ip_dest), + FW3_OPT("src_dport", port, redirect, port_dest), - FW3_OPT("extra", string, redirect, extra), + FW3_OPT("dest_ip", address, redirect, ip_redir), + FW3_OPT("dest_port", port, redirect, port_redir), - FW3_OPT("reflection", bool, redirect, reflection), + FW3_OPT("extra", string, redirect, extra), - FW3_OPT("target", target, redirect, target), + FW3_OPT("utc_time", bool, redirect, time.utc), + FW3_OPT("start_date", date, redirect, time.datestart), + FW3_OPT("stop_date", date, redirect, time.datestop), + FW3_OPT("start_time", time, redirect, time.timestart), + FW3_OPT("stop_time", time, redirect, time.timestop), + FW3_OPT("weekdays", weekdays, redirect, time.weekdays), + FW3_OPT("monthdays", monthdays, redirect, time.monthdays), + + FW3_OPT("mark", mark, redirect, mark), + + FW3_OPT("reflection", bool, redirect, reflection), + FW3_OPT("reflection_src", reflection_source, + redirect, reflection_src), + + FW3_OPT("target", target, redirect, target), + + { } }; +static bool +check_families(struct uci_element *e, struct fw3_redirect *r) +{ + if (r->family == FW3_FAMILY_ANY) + return true; + + if (r->_src && r->_src->family && r->_src->family != r->family) + { + warn_elem(e, "refers to source zone with different family"); + return false; + } + + if (r->_dest && r->_dest->family && r->_dest->family != r->family) + { + warn_elem(e, "refers to destination zone with different family"); + return false; + } + + if (r->_ipset && r->_ipset->family && r->_ipset->family != r->family) + { + warn_elem(e, "refers to ipset with different family"); + return false; + } + + if (r->ip_src.family && r->ip_src.family != r->family) + { + warn_elem(e, "uses source ip with different family"); + return false; + } + + if (r->ip_dest.family && r->ip_dest.family != r->family) + { + warn_elem(e, "uses destination ip with different family"); + return false; + } + + if (r->ip_redir.family && r->ip_redir.family != r->family) + { + warn_elem(e, "uses redirect ip with different family"); + return false; + } + + return true; +} + void fw3_load_redirects(struct fw3_state *state, struct uci_package *p) { @@ -55,7 +116,7 @@ fw3_load_redirects(struct fw3_state *state, struct uci_package *p) struct uci_element *e; struct fw3_redirect *redir; - bool valid = false; + bool valid; INIT_LIST_HEAD(&state->redirects); @@ -76,9 +137,18 @@ fw3_load_redirects(struct fw3_state *state, struct uci_package *p) INIT_LIST_HEAD(&redir->proto); INIT_LIST_HEAD(&redir->mac_src); + redir->enabled = true; redir->reflection = true; - fw3_parse_options(redir, redirect_opts, ARRAY_SIZE(redirect_opts), s); + valid = false; + + fw3_parse_options(redir, fw3_redirect_opts, s); + + if (!redir->enabled) + { + fw3_free_redirect(redir); + continue; + } if (redir->src.invert) { @@ -109,23 +179,29 @@ fw3_load_redirects(struct fw3_state *state, struct uci_package *p) else if (redir->ipset.set && !redir->ipset.any && !(redir->_ipset = fw3_lookup_ipset(state, redir->ipset.name))) { - warn_elem(e, "refers to not declared ipset '%s'", redir->ipset.name); + warn_elem(e, "refers to unknown ipset '%s'", redir->ipset.name); + fw3_free_redirect(redir); + continue; + } + + if (!check_families(e, redir)) + { fw3_free_redirect(redir); continue; } - if (redir->target == FW3_TARGET_UNSPEC) + if (redir->target == FW3_FLAG_UNSPEC) { warn_elem(e, "has no target specified, defaulting to DNAT"); - redir->target = FW3_TARGET_DNAT; + redir->target = FW3_FLAG_DNAT; } - else if (redir->target < FW3_TARGET_DNAT) + else if (redir->target < FW3_FLAG_DNAT) { warn_elem(e, "has invalid target specified, defaulting to DNAT"); - redir->target = FW3_TARGET_DNAT; + redir->target = FW3_FLAG_DNAT; } - if (redir->target == FW3_TARGET_DNAT) + if (redir->target == FW3_FLAG_DNAT) { if (redir->src.any) warn_elem(e, "must not have source '*' for DNAT target"); @@ -133,16 +209,16 @@ fw3_load_redirects(struct fw3_state *state, struct uci_package *p) warn_elem(e, "has no source specified"); else { - setbit(redir->_src->dst_flags, redir->target); + set(redir->_src->flags, FW3_FAMILY_V4, redir->target); redir->_src->conntrack = true; valid = true; } if (redir->reflection && redir->_dest && redir->_src->masq) { - setbit(redir->_dest->dst_flags, FW3_TARGET_ACCEPT); - setbit(redir->_dest->dst_flags, FW3_TARGET_DNAT); - setbit(redir->_dest->dst_flags, FW3_TARGET_SNAT); + set(redir->_dest->flags, FW3_FAMILY_V4, FW3_FLAG_ACCEPT); + set(redir->_dest->flags, FW3_FAMILY_V4, FW3_FLAG_DNAT); + set(redir->_dest->flags, FW3_FAMILY_V4, FW3_FLAG_SNAT); } } else @@ -153,14 +229,22 @@ fw3_load_redirects(struct fw3_state *state, struct uci_package *p) warn_elem(e, "has no destination specified"); else if (!redir->ip_dest.set) warn_elem(e, "has no src_dip option specified"); + else if (!list_empty(&redir->mac_src)) + warn_elem(e, "must not use 'src_mac' option for SNAT target"); else { - setbit(redir->_dest->dst_flags, redir->target); + set(redir->_dest->flags, FW3_FAMILY_V4, redir->target); redir->_dest->conntrack = true; valid = true; } } + if (list_empty(&redir->proto)) + { + warn_elem(e, "does not specify a protocol, assuming TCP+UDP"); + fw3_parse_protocol(&redir->proto, "tcpudp", true); + } + if (!valid) { fw3_free_redirect(redir); @@ -177,27 +261,28 @@ fw3_load_redirects(struct fw3_state *state, struct uci_package *p) static void print_chain_nat(struct fw3_redirect *redir) { - if (redir->target == FW3_TARGET_DNAT) + if (redir->target == FW3_FLAG_DNAT) fw3_pr("-A zone_%s_prerouting", redir->src.name); else fw3_pr("-A zone_%s_postrouting", redir->dest.name); } static void -print_snat_dnat(enum fw3_target target, +print_snat_dnat(enum fw3_flag target, struct fw3_address *addr, struct fw3_port *port) { - const char *t; char s[sizeof("255.255.255.255 ")]; - if (target == FW3_TARGET_DNAT) - t = "DNAT --to-destination"; + if (target == FW3_FLAG_DNAT) + fw3_pr(" -j DNAT --to-destination "); else - t = "SNAT --to-source"; + fw3_pr(" -j SNAT --to-source "); - inet_ntop(AF_INET, &addr->address.v4, s, sizeof(s)); - - fw3_pr(" -j %s %s", t, s); + if (addr && addr->set) + { + inet_ntop(AF_INET, &addr->address.v4, s, sizeof(s)); + fw3_pr(s); + } if (port && port->set) { @@ -213,7 +298,7 @@ print_snat_dnat(enum fw3_target target, static void print_target_nat(struct fw3_redirect *redir) { - if (redir->target == FW3_TARGET_DNAT) + if (redir->target == FW3_FLAG_DNAT) print_snat_dnat(redir->target, &redir->ip_redir, &redir->port_redir); else print_snat_dnat(redir->target, &redir->ip_dest, &redir->port_dest); @@ -222,7 +307,7 @@ print_target_nat(struct fw3_redirect *redir) static void print_chain_filter(struct fw3_redirect *redir) { - if (redir->target == FW3_TARGET_DNAT) + if (redir->target == FW3_FLAG_DNAT) { /* XXX: check for local ip */ if (!redir->ip_redir.set) @@ -243,37 +328,71 @@ static void print_target_filter(struct fw3_redirect *redir) { /* XXX: check for local ip */ - if (redir->target == FW3_TARGET_DNAT && !redir->ip_redir.set) + if (redir->target == FW3_FLAG_DNAT && !redir->ip_redir.set) fw3_pr(" -m conntrack --ctstate DNAT -j ACCEPT\n"); else fw3_pr(" -j ACCEPT\n"); } static void -print_redirect(enum fw3_table table, enum fw3_family family, - struct fw3_redirect *redir, int num) +print_redirect(struct fw3_state *state, enum fw3_family family, + enum fw3_table table, struct fw3_redirect *redir, int num) { struct list_head *ext_addrs, *int_addrs; - struct fw3_address *ext_addr, *int_addr; + struct fw3_address *ext_addr, *int_addr, ref_addr; struct fw3_device *ext_net, *int_net; struct fw3_protocol *proto; struct fw3_mac *mac; + if (redir->name) + info(" * Redirect '%s'", redir->name); + else + info(" * Redirect #%u", num); + + if (!fw3_is_family(redir->_src, family) || + !fw3_is_family(redir->_dest, family)) + { + info(" ! Skipping due to different family of zone"); + return; + } + + if (!fw3_is_family(&redir->ip_src, family) || + !fw3_is_family(&redir->ip_dest, family) || + !fw3_is_family(&redir->ip_redir, family)) + { + info(" ! Skipping due to different family of ip address"); + return; + } + + if (redir->_ipset) + { + if (!fw3_is_family(redir->_ipset, family)) + { + info(" ! Skipping due to different family in ipset"); + return; + } + + if (!fw3_check_ipset(redir->_ipset)) + { + info(" ! Skipping due to missing ipset '%s'", + redir->_ipset->external ? + redir->_ipset->external : redir->_ipset->name); + return; + } + + set(redir->_ipset->flags, family, family); + } + fw3_foreach(proto, &redir->proto) fw3_foreach(mac, &redir->mac_src) { if (table == FW3_TABLE_NAT) { - if (redir->name) - info(" * Redirect '%s'", redir->name); - else - info(" * Redirect #%u", num); - print_chain_nat(redir); fw3_format_ipset(redir->_ipset, redir->ipset.invert); fw3_format_protocol(proto, family); - if (redir->target == FW3_TARGET_DNAT) + if (redir->target == FW3_FLAG_DNAT) { fw3_format_src_dest(&redir->ip_src, &redir->ip_dest); fw3_format_sport_dport(&redir->port_src, &redir->port_dest); @@ -285,23 +404,22 @@ print_redirect(enum fw3_table table, enum fw3_family family, } fw3_format_mac(mac); + fw3_format_time(&redir->time); + fw3_format_mark(&redir->mark); fw3_format_extra(redir->extra); fw3_format_comment(redir->name); print_target_nat(redir); } else if (table == FW3_TABLE_FILTER) { - if (redir->name) - info(" * Redirect '%s'", redir->name); - else - info(" * Redirect #%u", num); - print_chain_filter(redir); fw3_format_ipset(redir->_ipset, redir->ipset.invert); fw3_format_protocol(proto, family); fw3_format_src_dest(&redir->ip_src, &redir->ip_redir); fw3_format_sport_dport(&redir->port_src, &redir->port_redir); fw3_format_mac(mac); + fw3_format_time(&redir->time); + fw3_format_mark(&redir->mark); fw3_format_extra(redir->extra); fw3_format_comment(redir->name); print_target_filter(redir); @@ -309,7 +427,7 @@ print_redirect(enum fw3_table table, enum fw3_family family, } /* reflection rules */ - if (redir->target != FW3_TARGET_DNAT || !redir->reflection) + if (redir->target != FW3_FLAG_DNAT || !redir->reflection) return; if (!redir->_dest || !redir->_src->masq) @@ -340,6 +458,12 @@ print_redirect(enum fw3_table table, enum fw3_family family, if (!proto || (proto->protocol != 6 && proto->protocol != 17)) continue; + if (redir->reflection_src == FW3_REFLECTION_INTERNAL) + ref_addr = *int_addr; + else + ref_addr = *ext_addr; + + ref_addr.mask = 32; ext_addr->mask = 32; if (table == FW3_TABLE_NAT) @@ -348,16 +472,18 @@ print_redirect(enum fw3_table table, enum fw3_family family, fw3_format_protocol(proto, family); fw3_format_src_dest(int_addr, ext_addr); fw3_format_sport_dport(NULL, &redir->port_dest); + fw3_format_time(&redir->time); fw3_format_comment(redir->name, " (reflection)"); - print_snat_dnat(FW3_TARGET_DNAT, + print_snat_dnat(FW3_FLAG_DNAT, &redir->ip_redir, &redir->port_redir); fw3_pr("-A zone_%s_postrouting", redir->dest.name); fw3_format_protocol(proto, family); fw3_format_src_dest(int_addr, &redir->ip_redir); fw3_format_sport_dport(NULL, &redir->port_redir); + fw3_format_time(&redir->time); fw3_format_comment(redir->name, " (reflection)"); - print_snat_dnat(FW3_TARGET_SNAT, ext_addr, NULL); + print_snat_dnat(FW3_FLAG_SNAT, &ref_addr, NULL); } else if (table == FW3_TABLE_FILTER) { @@ -365,6 +491,7 @@ print_redirect(enum fw3_table table, enum fw3_family family, fw3_format_protocol(proto, family); fw3_format_src_dest(int_addr, &redir->ip_redir); fw3_format_sport_dport(NULL, &redir->port_redir); + fw3_format_time(&redir->time); fw3_format_comment(redir->name, " (reflection)"); fw3_pr(" -j zone_%s_dest_ACCEPT\n", redir->dest.name); } @@ -378,8 +505,8 @@ print_redirect(enum fw3_table table, enum fw3_family family, } void -fw3_print_redirects(enum fw3_table table, enum fw3_family family, - struct fw3_state *state) +fw3_print_redirects(struct fw3_state *state, enum fw3_family family, + enum fw3_table table) { int num = 0; struct fw3_redirect *redir; @@ -387,14 +514,9 @@ fw3_print_redirects(enum fw3_table table, enum fw3_family family, if (family == FW3_FAMILY_V6) return; - list_for_each_entry(redir, &state->redirects, list) - print_redirect(table, family, redir, num++); -} + if (table != FW3_TABLE_FILTER && table != FW3_TABLE_NAT) + return; -void -fw3_free_redirect(struct fw3_redirect *redir) -{ - fw3_free_list(&redir->proto); - fw3_free_list(&redir->mac_src); - free(redir); + list_for_each_entry(redir, &state->redirects, list) + print_redirect(state, family, table, redir, num++); }