X-Git-Url: http://git.archive.openwrt.org/?p=project%2Ffirewall3.git;a=blobdiff_plain;f=zones.c;h=2aa74738ebcddb23263bfb8f172b975030f3b7e4;hp=a4458fe5f7ea96b0248bb1ed70f7c459f56317a4;hb=0e5dd73076c3dc23a6971784640dd7e36f99b6d5;hpb=6818f758fe8b0de9eae45adf4bae91a312cc8f0c diff --git a/zones.c b/zones.c index a4458fe..2aa7473 100644 --- a/zones.c +++ b/zones.c @@ -66,6 +66,7 @@ const struct fw3_option fw3_zone_opts[] = { FW3_OPT("output", target, zone, policy_output), FW3_OPT("masq", bool, zone, masq), + FW3_OPT("masq_allow_invalid", bool, zone, masq_allow_invalid), FW3_LIST("masq_src", network, zone, masq_src), FW3_LIST("masq_dest", network, zone, masq_dest), @@ -73,7 +74,6 @@ const struct fw3_option fw3_zone_opts[] = { FW3_OPT("extra_src", string, zone, extra_src), FW3_OPT("extra_dest", string, zone, extra_dest), - FW3_OPT("conntrack", bool, zone, conntrack), FW3_OPT("mtu_fix", bool, zone, mtu_fix), FW3_OPT("custom_chains", bool, zone, custom_chains), @@ -171,7 +171,8 @@ fw3_load_zones(struct fw3_state *state, struct uci_package *p) if (!zone) continue; - fw3_parse_options(zone, fw3_zone_opts, s); + if (!fw3_parse_options(zone, fw3_zone_opts, s)) + warn_elem(e, "has invalid options"); if (!zone->enabled) { @@ -216,23 +217,22 @@ fw3_load_zones(struct fw3_state *state, struct uci_package *p) if (zone->masq) { - setbit(zone->flags[0], FW3_FLAG_SNAT); - zone->conntrack = true; + fw3_setbit(zone->flags[0], FW3_FLAG_SNAT); } if (zone->custom_chains) { - setbit(zone->flags[0], FW3_FLAG_SNAT); - setbit(zone->flags[0], FW3_FLAG_DNAT); + fw3_setbit(zone->flags[0], FW3_FLAG_SNAT); + fw3_setbit(zone->flags[0], FW3_FLAG_DNAT); } - setbit(zone->flags[0], fw3_to_src_target(zone->policy_input)); - setbit(zone->flags[0], zone->policy_forward); - setbit(zone->flags[0], zone->policy_output); + fw3_setbit(zone->flags[0], fw3_to_src_target(zone->policy_input)); + fw3_setbit(zone->flags[0], zone->policy_forward); + fw3_setbit(zone->flags[0], zone->policy_output); - setbit(zone->flags[1], fw3_to_src_target(zone->policy_input)); - setbit(zone->flags[1], zone->policy_forward); - setbit(zone->flags[1], zone->policy_output); + fw3_setbit(zone->flags[1], fw3_to_src_target(zone->policy_input)); + fw3_setbit(zone->flags[1], zone->policy_forward); + fw3_setbit(zone->flags[1], zone->policy_output); list_add_tail(&zone->list, &state->zones); } @@ -268,9 +268,6 @@ print_zone_chain(struct fw3_ipt_handle *handle, struct fw3_state *state, if (zone->custom_chains) set(zone->flags, handle->family, FW3_FLAG_CUSTOM_CHAINS); - if (!zone->conntrack && !state->defaults.drop_invalid) - set(zone->flags, handle->family, FW3_FLAG_NOTRACK); - for (c = zone_chains; c->format; c++) { /* don't touch user chains on selective stop */ @@ -284,7 +281,7 @@ print_zone_chain(struct fw3_ipt_handle *handle, struct fw3_state *state, continue; if (c->flag && - !hasbit(zone->flags[handle->family == FW3_FAMILY_V6], c->flag)) + !fw3_hasbit(zone->flags[handle->family == FW3_FAMILY_V6], c->flag)) continue; fw3_ipt_create_chain(handle, c->format, zone->name); @@ -359,14 +356,20 @@ print_interface_rule(struct fw3_ipt_handle *handle, struct fw3_state *state, if (has(zone->flags, handle->family, t)) { + if (t == FW3_FLAG_ACCEPT && + zone->masq && !zone->masq_allow_invalid) + { + r = fw3_ipt_rule_create(handle, NULL, NULL, dev, NULL, sub); + fw3_ipt_rule_extra(r, "-m conntrack --ctstate INVALID"); + fw3_ipt_rule_comment(r, "Prevent NAT leakage"); + fw3_ipt_rule_target(r, fw3_flag_names[FW3_FLAG_DROP]); + fw3_ipt_rule_replace(r, "zone_%s_dest_%s", zone->name, + fw3_flag_names[t]); + } + r = fw3_ipt_rule_create(handle, NULL, NULL, dev, NULL, sub); fw3_ipt_rule_target(r, jump_target(t)); fw3_ipt_rule_extra(r, zone->extra_dest); - - if (t == FW3_FLAG_ACCEPT && !state->defaults.drop_invalid) - fw3_ipt_rule_extra(r, - "-m conntrack --ctstate NEW,UNTRACKED"); - fw3_ipt_rule_replace(r, "zone_%s_dest_%s", zone->name, fw3_flag_names[t]); } @@ -466,11 +469,29 @@ print_interface_rules(struct fw3_ipt_handle *handle, struct fw3_state *state, } } +static struct fw3_address * +next_addr(struct fw3_address *addr, struct list_head *list, + enum fw3_family family, bool invert) +{ + struct list_head *p; + struct fw3_address *rv; + + for (p = addr ? addr->list.next : list->next; p != list; p = p->next) + { + rv = list_entry(p, struct fw3_address, list); + + if (fw3_is_family(rv, family) && rv->invert == invert) + return rv; + } + + return NULL; +} + static void print_zone_rule(struct fw3_ipt_handle *handle, struct fw3_state *state, bool reload, struct fw3_zone *zone) { - bool disable_notrack = state->defaults.drop_invalid; + bool first_src, first_dest; struct fw3_address *msrc; struct fw3_address *mdest; struct fw3_ipt_rule *r; @@ -552,31 +573,55 @@ print_zone_rule(struct fw3_ipt_handle *handle, struct fw3_state *state, case FW3_TABLE_NAT: if (zone->masq && handle->family == FW3_FAMILY_V4) { - fw3_foreach(msrc, &zone->masq_src) - fw3_foreach(mdest, &zone->masq_dest) + /* for any negated masq_src ip, emit -s addr -j RETURN rules */ + for (msrc = NULL; + (msrc = next_addr(msrc, &zone->masq_src, + handle->family, true)) != NULL; ) { - if (!fw3_is_family(msrc, handle->family) || - !fw3_is_family(mdest, handle->family)) - continue; + msrc->invert = false; + r = fw3_ipt_rule_new(handle); + fw3_ipt_rule_src_dest(r, msrc, NULL); + fw3_ipt_rule_target(r, "RETURN"); + fw3_ipt_rule_append(r, "zone_%s_postrouting", zone->name); + msrc->invert = true; + } + /* for any negated masq_dest ip, emit -d addr -j RETURN rules */ + for (mdest = NULL; + (mdest = next_addr(mdest, &zone->masq_dest, + handle->family, true)) != NULL; ) + { + mdest->invert = false; r = fw3_ipt_rule_new(handle); - fw3_ipt_rule_src_dest(r, msrc, mdest); - fw3_ipt_rule_target(r, "MASQUERADE"); + fw3_ipt_rule_src_dest(r, NULL, mdest); + fw3_ipt_rule_target(r, "RETURN"); fw3_ipt_rule_append(r, "zone_%s_postrouting", zone->name); + mdest->invert = true; } - } - break; - case FW3_TABLE_RAW: - if (!zone->conntrack && !disable_notrack) - { - r = fw3_ipt_rule_new(handle); - fw3_ipt_rule_target(r, "CT"); - fw3_ipt_rule_addarg(r, false, "--notrack", NULL); - fw3_ipt_rule_append(r, "zone_%s_notrack", zone->name); + /* emit masquerading entries for non-negated addresses + and ensure that both src and dest loops run at least once, + even if there are no relevant addresses */ + for (first_src = true, msrc = NULL; + (msrc = next_addr(msrc, &zone->masq_src, + handle->family, false)) || first_src; + first_src = false) + { + for (first_dest = true, mdest = NULL; + (mdest = next_addr(mdest, &zone->masq_dest, + handle->family, false)) || first_dest; + first_dest = false) + { + r = fw3_ipt_rule_new(handle); + fw3_ipt_rule_src_dest(r, msrc, mdest); + fw3_ipt_rule_target(r, "MASQUERADE"); + fw3_ipt_rule_append(r, "zone_%s_postrouting", zone->name); + } + } } break; + case FW3_TABLE_RAW: case FW3_TABLE_MANGLE: break; } @@ -655,15 +700,15 @@ fw3_hotplug_zones(struct fw3_state *state, bool add) list_for_each_entry(z, &state->zones, list) { - if (add != hasbit(z->flags[0], FW3_FLAG_HOTPLUG)) + if (add != fw3_hasbit(z->flags[0], FW3_FLAG_HOTPLUG)) { list_for_each_entry(d, &z->devices, list) fw3_hotplug(add, z, d); if (add) - setbit(z->flags[0], FW3_FLAG_HOTPLUG); + fw3_setbit(z->flags[0], FW3_FLAG_HOTPLUG); else - delbit(z->flags[0], FW3_FLAG_HOTPLUG); + fw3_delbit(z->flags[0], FW3_FLAG_HOTPLUG); } } }