/*
* firewall3 - 3rd OpenWrt UCI firewall implementation
*
- * Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
+ * Copyright (C) 2013 Jo-Philipp Wich <jo@mein.io>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
{ FW3_FAMILY_##f, FW3_TABLE_##tbl, FW3_FLAG_##def, fmt }
static const struct fw3_chain_spec default_chains[] = {
- //C(ANY, FILTER, UNSPEC, "delegate_input"),
- //C(ANY, FILTER, UNSPEC, "delegate_output"),
- //C(ANY, FILTER, UNSPEC, "delegate_forward"),
C(ANY, FILTER, UNSPEC, "reject"),
C(ANY, FILTER, CUSTOM_CHAINS, "input_rule"),
C(ANY, FILTER, CUSTOM_CHAINS, "output_rule"),
C(ANY, FILTER, CUSTOM_CHAINS, "forwarding_rule"),
C(ANY, FILTER, SYN_FLOOD, "syn_flood"),
- //C(V4, NAT, UNSPEC, "delegate_prerouting"),
- //C(V4, NAT, UNSPEC, "delegate_postrouting"),
C(V4, NAT, CUSTOM_CHAINS, "prerouting_rule"),
C(V4, NAT, CUSTOM_CHAINS, "postrouting_rule"),
- //C(ANY, MANGLE, UNSPEC, "mssfix"),
- //C(ANY, MANGLE, UNSPEC, "fwmark"),
-
- //C(ANY, RAW, UNSPEC, "delegate_notrack"),
-
{ }
};
FW3_OPT("output", target, defaults, policy_output),
FW3_OPT("drop_invalid", bool, defaults, drop_invalid),
+ FW3_OPT("tcp_reject_code", reject_code, defaults, tcp_reject_code),
+ FW3_OPT("any_reject_code", reject_code, defaults, any_reject_code),
FW3_OPT("syn_flood", bool, defaults, syn_flood),
FW3_OPT("synflood_protect", bool, defaults, syn_flood),
FW3_OPT("accept_redirects", bool, defaults, accept_redirects),
FW3_OPT("accept_source_route", bool, defaults, accept_source_route),
+ FW3_OPT("auto_helper", bool, defaults, auto_helper),
FW3_OPT("custom_chains", bool, defaults, custom_chains),
FW3_OPT("disable_ipv6", bool, defaults, disable_ipv6),
+ FW3_OPT("flow_offloading", bool, defaults, flow_offloading),
+ FW3_OPT("flow_offloading_hw", bool, defaults, flow_offloading_hw),
FW3_OPT("__flags_v4", int, defaults, flags[0]),
FW3_OPT("__flags_v6", int, defaults, flags[1]),
}
}
+static void
+check_target(struct uci_element *e, bool *available, const char *target, const bool ipv6)
+{
+ const bool b = fw3_has_target(ipv6, target);
+ if (!b)
+ {
+ warn_elem(e, "requires unavailable target extension %s, disabling", target);
+ }
+ *available = b;
+}
+
+static void
+check_any_reject_code(struct uci_element *e, enum fw3_reject_code *any_reject_code)
+{
+ if (*any_reject_code == FW3_REJECT_CODE_TCP_RESET) {
+ warn_elem(e, "tcp-reset not valid for any_reject_code, defaulting to port-unreach");
+ *any_reject_code = FW3_REJECT_CODE_PORT_UNREACH;
+ }
+}
+
+static const char*
+get_reject_code(enum fw3_family family, enum fw3_reject_code reject_code)
+{
+ switch (reject_code) {
+ case FW3_REJECT_CODE_TCP_RESET:
+ return "tcp-reset";
+ case FW3_REJECT_CODE_PORT_UNREACH:
+ return "port-unreach";
+ case FW3_REJECT_CODE_ADM_PROHIBITED:
+ return family == FW3_FAMILY_V6 ? "adm-prohibited": "admin-prohib";
+ default:
+ return "unknown";
+ }
+}
+
void
fw3_load_defaults(struct fw3_state *state, struct uci_package *p)
{
struct uci_element *e;
struct fw3_defaults *defs = &state->defaults;
+ bool flow_offload_avaliable = false;
bool seen = false;
+ defs->tcp_reject_code = FW3_REJECT_CODE_TCP_RESET;
+ defs->any_reject_code = FW3_REJECT_CODE_PORT_UNREACH;
defs->syn_flood_rate.rate = 25;
defs->syn_flood_rate.burst = 50;
defs->tcp_syncookies = true;
defs->tcp_window_scaling = true;
defs->custom_chains = true;
+ defs->auto_helper = true;
uci_foreach_element(&p->sections, e)
{
continue;
}
- fw3_parse_options(&state->defaults, fw3_flag_opts, s);
+ if(!fw3_parse_options(&state->defaults, fw3_flag_opts, s))
+ warn_elem(e, "has invalid options");
check_policy(e, &defs->policy_input, "input");
check_policy(e, &defs->policy_output, "output");
check_policy(e, &defs->policy_forward, "forward");
+
+ check_any_reject_code(e, &defs->any_reject_code);
+
+ /* exists in both ipv4 and ipv6, if at all, so only check ipv4 */
+ check_target(e, &flow_offload_avaliable, "FLOWOFFLOAD", false);
+
+ if (!flow_offload_avaliable)
+ defs->flow_offloading = false;
}
}
for (c = default_chains; c->format; c++)
{
- /* don't touch user chains on selective stop */
- if (reload && c->flag == FW3_FLAG_CUSTOM_CHAINS)
- continue;
-
if (!fw3_is_family(c, handle->family))
continue;
continue;
if (c->flag &&
- !hasbit(defs->flags[handle->family == FW3_FAMILY_V6], c->flag))
+ !fw3_hasbit(defs->flags[handle->family == FW3_FAMILY_V6], c->flag))
continue;
- fw3_ipt_create_chain(handle, c->format);
+ fw3_ipt_create_chain(handle, reload, c->format);
}
set(defs->flags, handle->family, handle->table);
}
-
-struct toplevel_rule {
- enum fw3_table table;
- const char *chain;
- const char *target;
-};
-
void
fw3_print_default_head_rules(struct fw3_ipt_handle *handle,
struct fw3_state *state, bool reload)
{
int i;
struct fw3_defaults *defs = &state->defaults;
- struct fw3_device lodev = { .set = true };
+ struct fw3_device lodev = { .set = true, .name = "lo" };
struct fw3_protocol tcp = { .protocol = 6 };
struct fw3_ipt_rule *r;
- //struct toplevel_rule *tr;
const char *chains[] = {
"INPUT", "input",
"FORWARD", "forwarding",
};
- //struct toplevel_rule rules[] = {
- // { FW3_TABLE_FILTER, "INPUT", "delegate_input" },
- // { FW3_TABLE_FILTER, "OUTPUT", "delegate_output" },
- // { FW3_TABLE_FILTER, "FORWARD", "delegate_forward" },
- //
- // { FW3_TABLE_NAT, "PREROUTING", "delegate_prerouting" },
- // { FW3_TABLE_NAT, "POSTROUTING", "delegate_postrouting" },
- //
- // { FW3_TABLE_MANGLE, "FORWARD", "mssfix" },
- // { FW3_TABLE_MANGLE, "PREROUTING", "fwmark" },
- //
- // { FW3_TABLE_RAW, "PREROUTING", "delegate_notrack" },
- //
- // { 0, NULL },
- //};
- //
- //for (tr = rules; tr->chain; tr++)
- //{
- // if (tr->table != handle->table)
- // continue;
- //
- // r = fw3_ipt_rule_new(handle);
- // fw3_ipt_rule_target(r, tr->target);
- // fw3_ipt_rule_replace(r, tr->chain);
- //}
-
switch (handle->table)
{
case FW3_TABLE_FILTER:
- sprintf(lodev.name, "lo");
-
r = fw3_ipt_rule_create(handle, NULL, &lodev, NULL, NULL, NULL);
fw3_ipt_rule_target(r, "ACCEPT");
fw3_ipt_rule_append(r, "INPUT");
for (i = 0; i < ARRAY_SIZE(chains); i += 2)
{
r = fw3_ipt_rule_new(handle);
- fw3_ipt_rule_comment(r, "user chain for %s", chains[i+1]);
+ fw3_ipt_rule_comment(r, "Custom %s rule chain", chains[i+1]);
fw3_ipt_rule_target(r, "%s_rule", chains[i+1]);
fw3_ipt_rule_append(r, chains[i]);
}
}
+ if (defs->flow_offloading)
+ {
+ r = fw3_ipt_rule_new(handle);
+ fw3_ipt_rule_comment(r, "Traffic offloading");
+ fw3_ipt_rule_extra(r, "-m conntrack --ctstate RELATED,ESTABLISHED");
+ fw3_ipt_rule_target(r, "FLOWOFFLOAD");
+ if (defs->flow_offloading_hw)
+ fw3_ipt_rule_addarg(r, false, "--hw", NULL);
+ fw3_ipt_rule_append(r, "FORWARD");
+ }
+
for (i = 0; i < ARRAY_SIZE(chains); i += 2)
{
r = fw3_ipt_rule_new(handle);
r = fw3_ipt_rule_create(handle, &tcp, NULL, NULL, NULL, NULL);
fw3_ipt_rule_target(r, "REJECT");
- fw3_ipt_rule_addarg(r, false, "--reject-with", "tcp-reset");
+ fw3_ipt_rule_addarg(r, false, "--reject-with", get_reject_code(handle->family, defs->tcp_reject_code));
fw3_ipt_rule_append(r, "reject");
r = fw3_ipt_rule_new(handle);
fw3_ipt_rule_target(r, "REJECT");
- fw3_ipt_rule_addarg(r, false, "--reject-with", "port-unreach");
+ fw3_ipt_rule_addarg(r, false, "--reject-with", get_reject_code(handle->family, defs->any_reject_code));
fw3_ipt_rule_append(r, "reject");
break;
if (defs->custom_chains)
{
r = fw3_ipt_rule_new(handle);
- fw3_ipt_rule_comment(r, "user chain for prerouting");
+ fw3_ipt_rule_comment(r, "Custom prerouting rule chain");
fw3_ipt_rule_target(r, "prerouting_rule");
fw3_ipt_rule_append(r, "PREROUTING");
r = fw3_ipt_rule_new(handle);
- fw3_ipt_rule_comment(r, "user chain for postrouting");
+ fw3_ipt_rule_comment(r, "Custom postrouting rule chain");
fw3_ipt_rule_target(r, "postrouting_rule");
fw3_ipt_rule_append(r, "POSTROUTING");
}
set_default(const char *name, int set)
{
FILE *f;
- char path[sizeof("/proc/sys/net/ipv4/tcp_window_scaling\0")];
+ char path[sizeof("/proc/sys/net/ipv4/tcp_window_scaling")];
snprintf(path, sizeof(path), "/proc/sys/net/ipv4/tcp_%s", name);
- info(" * Set tcp_%s to %s", name, set ? "on" : "off", name);
+ info(" * Set tcp_%s to %s", name, set ? "on" : "off");
if (!(f = fopen(path, "w")))
{
fw3_ipt_delete_id_rules(handle, "PREROUTING");
fw3_ipt_delete_id_rules(handle, "POSTROUTING");
+ /* first flush all the rules ... */
for (c = default_chains; c->format; c++)
{
/* don't touch user chains on selective stop */
continue;
fw3_ipt_flush_chain(handle, c->format);
+ }
- /* keep certain basic chains that do not depend on any settings to
- avoid purging unrelated user rules pointing to them */
- if (reload && !c->flag)
+ /* ... then remove the chains */
+ for (c = default_chains; c->format; c++)
+ {
+ if (!fw3_is_family(c, handle->family))
+ continue;
+
+ if (c->table != handle->table)
+ continue;
+
+ if (c->flag && !has(defs->flags, handle->family, c->flag))
continue;
- fw3_ipt_delete_chain(handle, c->format);
+ fw3_ipt_delete_chain(handle, reload, c->format);
}
del(defs->flags, handle->family, handle->table);