#include "zones.h"
#include "ubus.h"
+#include "helpers.h"
#define C(f, tbl, tgt, fmt) \
C(V4, NAT, SNAT, "zone_%s_postrouting"),
C(V4, NAT, DNAT, "zone_%s_prerouting"),
+ C(ANY, RAW, HELPER, "zone_%s_helper"),
C(ANY, RAW, NOTRACK, "zone_%s_notrack"),
C(ANY, FILTER, CUSTOM_CHAINS, "input_%s_rule"),
{ }
};
+enum fw3_zone_logmask {
+ FW3_ZONE_LOG_FILTER = (1 << 0),
+ FW3_ZONE_LOG_MANGLE = (1 << 1),
+};
+
const struct fw3_option fw3_zone_opts[] = {
FW3_OPT("enabled", bool, zone, enabled),
FW3_OPT("mtu_fix", bool, zone, mtu_fix),
FW3_OPT("custom_chains", bool, zone, custom_chains),
- FW3_OPT("log", bool, zone, log),
+ FW3_OPT("log", int, zone, log),
FW3_OPT("log_limit", limit, zone, log_limit),
+ FW3_OPT("auto_helper", bool, zone, auto_helper),
+ FW3_LIST("helper", cthelper, zone, cthelpers),
+
FW3_OPT("__flags_v4", int, zone, flags[0]),
FW3_OPT("__flags_v6", int, zone, flags[1]),
}
}
+static bool
+check_masq_addrs(struct list_head *head)
+{
+ struct fw3_address *addr;
+ int n_addr = 0, n_failed = 0;
+
+ list_for_each_entry(addr, head, list)
+ {
+ if (addr->invert)
+ continue;
+
+ n_addr++;
+
+ if (!addr->set && addr->resolved)
+ n_failed++;
+ }
+
+ return (n_addr == 0 || n_failed < n_addr);
+}
+
static void
resolve_networks(struct uci_element *e, struct fw3_zone *zone)
{
}
}
+static void
+resolve_cthelpers(struct fw3_state *s, struct uci_element *e, struct fw3_zone *zone)
+{
+ struct fw3_cthelpermatch *match;
+
+ if (list_empty(&zone->cthelpers))
+ {
+ if (!zone->masq && zone->auto_helper)
+ {
+ fw3_setbit(zone->flags[0], FW3_FLAG_HELPER);
+ fw3_setbit(zone->flags[1], FW3_FLAG_HELPER);
+ }
+
+ return;
+ }
+
+ list_for_each_entry(match, &zone->cthelpers, list)
+ {
+ if (match->invert)
+ {
+ warn_elem(e, "must not use a negated helper match");
+ continue;
+ }
+
+ match->ptr = fw3_lookup_cthelper(s, match->name);
+
+ if (!match->ptr)
+ {
+ warn_elem(e, "refers to not existing helper '%s'", match->name);
+ continue;
+ }
+
+ if (fw3_is_family(match->ptr, FW3_FAMILY_V4))
+ fw3_setbit(zone->flags[0], FW3_FLAG_HELPER);
+
+ if (fw3_is_family(match->ptr, FW3_FAMILY_V6))
+ fw3_setbit(zone->flags[1], FW3_FLAG_HELPER);
+ }
+}
+
struct fw3_zone *
fw3_alloc_zone(void)
{
INIT_LIST_HEAD(&zone->subnets);
INIT_LIST_HEAD(&zone->masq_src);
INIT_LIST_HEAD(&zone->masq_dest);
+ INIT_LIST_HEAD(&zone->cthelpers);
INIT_LIST_HEAD(&zone->old_addrs);
zone->enabled = true;
+ zone->auto_helper = true;
zone->custom_chains = true;
zone->log_limit.rate = 10;
if (!defs->custom_chains && zone->custom_chains)
zone->custom_chains = false;
+ if (!defs->auto_helper && zone->auto_helper)
+ zone->auto_helper = false;
+
if (!zone->name || !*zone->name)
{
warn_elem(e, "has no name - ignoring");
warn_elem(e, "has no device, network, subnet or extra options");
}
+ if (!check_masq_addrs(&zone->masq_src))
+ {
+ warn_elem(e, "has unresolved masq_src, disabling masq");
+ zone->masq = false;
+ }
+
+ if (!check_masq_addrs(&zone->masq_dest))
+ {
+ warn_elem(e, "has unresolved masq_dest, disabling masq");
+ zone->masq = false;
+ }
+
check_policy(e, &zone->policy_input, defs->policy_input, "input");
check_policy(e, &zone->policy_output, defs->policy_output, "output");
check_policy(e, &zone->policy_forward, defs->policy_forward, "forward");
fw3_setbit(zone->flags[0], FW3_FLAG_DNAT);
}
+ resolve_cthelpers(state, e, zone);
+
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);
if (!fw3_is_family(zone, handle->family))
return;
- info(" * Zone '%s'", zone->name);
-
set(zone->flags, handle->family, handle->table);
if (zone->custom_chains)
{
if (zone->mtu_fix)
{
- if (zone->log)
+ if (zone->log & FW3_ZONE_LOG_MANGLE)
{
snprintf(buf, sizeof(buf) - 1, "MSSFIX(%s): ", zone->name);
}
else if (handle->table == FW3_TABLE_RAW)
{
+ if (has(zone->flags, handle->family, FW3_FLAG_HELPER))
+ {
+ r = fw3_ipt_rule_create(handle, NULL, dev, NULL, sub, NULL);
+ fw3_ipt_rule_comment(r, "%s CT helper assignment", zone->name);
+ fw3_ipt_rule_target(r, "zone_%s_helper", zone->name);
+ fw3_ipt_rule_extra(r, zone->extra_src);
+ fw3_ipt_rule_replace(r, "PREROUTING");
+ }
+
if (has(zone->flags, handle->family, FW3_FLAG_NOTRACK))
{
r = fw3_ipt_rule_create(handle, NULL, dev, NULL, sub, NULL);
+ fw3_ipt_rule_comment(r, "%s CT bypass", zone->name);
fw3_ipt_rule_target(r, "zone_%s_notrack", zone->name);
fw3_ipt_rule_extra(r, zone->extra_src);
fw3_ipt_rule_replace(r, "PREROUTING");
{
rv = list_entry(p, struct fw3_address, list);
- if (fw3_is_family(rv, family) && rv->invert == invert)
+ if (fw3_is_family(rv, family) && rv->set && rv->invert == invert)
return rv;
}
if (!fw3_is_family(zone, handle->family))
return;
+ info(" * Zone '%s'", zone->name);
+
switch (handle->table)
{
case FW3_TABLE_FILTER:
fw3_flag_names[zone->policy_output]);
fw3_ipt_rule_append(r, "zone_%s_output", zone->name);
- if (zone->log)
+ if (zone->log & FW3_ZONE_LOG_FILTER)
{
for (t = FW3_FLAG_REJECT; t <= FW3_FLAG_DROP; t++)
{
break;
case FW3_TABLE_RAW:
+ fw3_print_cthelpers(handle, state, zone);
+ break;
+
case FW3_TABLE_MANGLE:
break;
}