summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--defaults.c4
-rw-r--r--options.c51
-rw-r--r--options.h37
-rw-r--r--redirects.c4
-rw-r--r--rules.c48
5 files changed, 130 insertions, 14 deletions
diff --git a/defaults.c b/defaults.c
index 10b1163..b5a94e6 100644
--- a/defaults.c
+++ b/defaults.c
@@ -38,6 +38,8 @@ static const struct fw3_rule_spec default_chains[] = {
C(V4, NAT, CUSTOM_CHAINS, "postrouting_rule"),
C(ANY, MANGLE, UNSPEC, "mssfix"),
+ C(ANY, MANGLE, UNSPEC, "fwmark"),
+
C(ANY, RAW, UNSPEC, "notrack"),
{ }
@@ -52,6 +54,8 @@ static const struct fw3_rule_spec toplevel_rules[] = {
C(V4, NAT, UNSPEC, "POSTROUTING -j delegate_postrouting"),
C(ANY, MANGLE, UNSPEC, "FORWARD -j mssfix"),
+ C(ANY, MANGLE, UNSPEC, "PREROUTING -j fwmark"),
+
C(ANY, RAW, UNSPEC, "PREROUTING -j notrack"),
{ }
diff --git a/options.c b/options.c
index 031de83..1f561d3 100644
--- a/options.c
+++ b/options.c
@@ -75,6 +75,7 @@ const char *fw3_flag_names[__FW3_FLAG_MAX] = {
"REJECT",
"DROP",
"NOTRACK",
+ "MARK",
"DNAT",
"SNAT",
@@ -754,6 +755,44 @@ fw3_parse_reflection_source(void *ptr, const char *val, bool is_list)
FW3_REFLECTION_INTERNAL, FW3_REFLECTION_EXTERNAL);
}
+bool
+fw3_parse_mark(void *ptr, const char *val, bool is_list)
+{
+ uint32_t n;
+ char *s, *e;
+ struct fw3_mark *m = ptr;
+
+ if (*val == '!')
+ {
+ m->invert = true;
+ while (isspace(*++val));
+ }
+
+ if ((s = strchr(val, '/')) != NULL)
+ *s++ = 0;
+
+ n = strtoul(val, &e, 0);
+
+ if (e == val || *e)
+ return false;
+
+ m->mark = n;
+ m->mask = 0xFFFFFFFF;
+
+ if (s)
+ {
+ n = strtoul(s, &e, 0);
+
+ if (e == s || *e)
+ return false;
+
+ m->mask = n;
+ }
+
+ m->set = true;
+ return true;
+}
+
void
fw3_parse_options(void *s, const struct fw3_option *opts,
@@ -1099,6 +1138,18 @@ fw3_format_time(struct fw3_time *time)
}
void
+fw3_format_mark(struct fw3_mark *mark)
+{
+ if (!mark->set)
+ return;
+
+ fw3_pr(" -m mark %s--mark 0x%x", mark->invert ? "! " : "", mark->mark);
+
+ if (mark->mask < 0xFFFFFFFF)
+ fw3_pr("/0x%x", mark->mask);
+}
+
+void
__fw3_format_comment(const char *comment, ...)
{
va_list ap;
diff --git a/options.h b/options.h
index dd86d05..3fb7a9c 100644
--- a/options.h
+++ b/options.h
@@ -68,17 +68,18 @@ enum fw3_flag
FW3_FLAG_REJECT = 7,
FW3_FLAG_DROP = 8,
FW3_FLAG_NOTRACK = 9,
- FW3_FLAG_DNAT = 10,
- FW3_FLAG_SNAT = 11,
- FW3_FLAG_SRC_ACCEPT = 12,
- FW3_FLAG_SRC_REJECT = 13,
- FW3_FLAG_SRC_DROP = 14,
- FW3_FLAG_CUSTOM_CHAINS = 15,
- FW3_FLAG_SYN_FLOOD = 16,
- FW3_FLAG_MTU_FIX = 17,
- FW3_FLAG_DROP_INVALID = 18,
- FW3_FLAG_HOTPLUG = 19,
- FW3_FLAG_DELETED = 20,
+ FW3_FLAG_MARK = 10,
+ FW3_FLAG_DNAT = 11,
+ FW3_FLAG_SNAT = 12,
+ FW3_FLAG_SRC_ACCEPT = 13,
+ FW3_FLAG_SRC_REJECT = 14,
+ FW3_FLAG_SRC_DROP = 15,
+ FW3_FLAG_CUSTOM_CHAINS = 16,
+ FW3_FLAG_SYN_FLOOD = 17,
+ FW3_FLAG_MTU_FIX = 18,
+ FW3_FLAG_DROP_INVALID = 19,
+ FW3_FLAG_HOTPLUG = 20,
+ FW3_FLAG_DELETED = 21,
__FW3_FLAG_MAX
};
@@ -224,6 +225,14 @@ struct fw3_time
uint8_t weekdays; /* bit 0 is invert + 1 .. 7 */
};
+struct fw3_mark
+{
+ bool set;
+ bool invert;
+ uint32_t mark;
+ uint32_t mask;
+};
+
struct fw3_defaults
{
enum fw3_flag policy_input;
@@ -319,8 +328,11 @@ struct fw3_rule
struct fw3_limit limit;
struct fw3_time time;
+ struct fw3_mark mark;
enum fw3_flag target;
+ struct fw3_mark set_mark;
+ struct fw3_mark set_xmark;
const char *extra;
};
@@ -356,6 +368,7 @@ struct fw3_redirect
struct fw3_port port_redir;
struct fw3_time time;
+ struct fw3_mark mark;
enum fw3_flag target;
@@ -480,6 +493,7 @@ bool fw3_parse_date(void *ptr, const char *val, bool is_list);
bool fw3_parse_time(void *ptr, const char *val, bool is_list);
bool fw3_parse_weekdays(void *ptr, const char *val, bool is_list);
bool fw3_parse_monthdays(void *ptr, const char *val, bool is_list);
+bool fw3_parse_mark(void *ptr, const char *val, bool is_list);
void fw3_parse_options(void *s, const struct fw3_option *opts,
struct uci_section *section);
@@ -493,6 +507,7 @@ void fw3_format_icmptype(struct fw3_icmptype *icmp, enum fw3_family family);
void fw3_format_limit(struct fw3_limit *limit);
void fw3_format_ipset(struct fw3_ipset *ipset, bool invert);
void fw3_format_time(struct fw3_time *time);
+void fw3_format_mark(struct fw3_mark *mark);
void __fw3_format_comment(const char *comment, ...);
#define fw3_format_comment(...) __fw3_format_comment(__VA_ARGS__, NULL)
diff --git a/redirects.c b/redirects.c
index 7817e9b..0a13d85 100644
--- a/redirects.c
+++ b/redirects.c
@@ -52,6 +52,8 @@ const struct fw3_option fw3_redirect_opts[] = {
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),
@@ -395,6 +397,7 @@ print_redirect(struct fw3_state *state, 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);
@@ -408,6 +411,7 @@ print_redirect(struct fw3_state *state, enum fw3_family family,
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);
diff --git a/rules.c b/rules.c
index 1037d2f..287ad90 100644
--- a/rules.c
+++ b/rules.c
@@ -53,6 +53,10 @@ const struct fw3_option fw3_rule_opts[] = {
FW3_OPT("weekdays", weekdays, rule, time.weekdays),
FW3_OPT("monthdays", monthdays, rule, time.monthdays),
+ FW3_OPT("mark", mark, rule, mark),
+ FW3_OPT("set_mark", mark, rule, set_mark),
+ FW3_OPT("set_xmark", mark, rule, set_xmark),
+
FW3_OPT("target", target, rule, target),
{ }
@@ -144,6 +148,29 @@ fw3_load_rules(struct fw3_state *state, struct uci_package *p)
continue;
}
+ if (!rule->set_mark.set && !rule->set_xmark.set &&
+ rule->target == FW3_FLAG_MARK)
+ {
+ warn_elem(e, "is set to target MARK but specifies neither "
+ "'set_mark' nor 'set_xmark' option");
+ fw3_free_rule(rule);
+ continue;
+ }
+
+ if (rule->_dest && rule->target == FW3_FLAG_MARK)
+ {
+ warn_elem(e, "must not specify 'dest' for MARK target");
+ fw3_free_rule(rule);
+ continue;
+ }
+
+ if (rule->set_mark.invert || rule->set_xmark.invert)
+ {
+ warn_elem(e, "must not have inverted 'set_mark' or 'set_xmark'");
+ fw3_free_rule(rule);
+ continue;
+ }
+
if (!rule->_src && !rule->_dest && !rule->src.any && !rule->dest.any)
{
warn_elem(e, "has neither a source nor a destination zone assigned "
@@ -161,7 +188,7 @@ fw3_load_rules(struct fw3_state *state, struct uci_package *p)
warn_elem(e, "has no target specified, defaulting to REJECT");
rule->target = FW3_FLAG_REJECT;
}
- else if (rule->target > FW3_FLAG_NOTRACK)
+ else if (rule->target > FW3_FLAG_MARK)
{
warn_elem(e, "has invalid target specified, defaulting to REJECT");
rule->target = FW3_FLAG_REJECT;
@@ -191,6 +218,10 @@ print_chain(struct fw3_rule *rule)
{
sprintf(chain, "zone_%s_notrack", rule->src.name);
}
+ else if (rule->target == FW3_FLAG_MARK)
+ {
+ sprintf(chain, "fwmark");
+ }
else
{
if (rule->src.set)
@@ -224,6 +255,15 @@ static void print_target(struct fw3_rule *rule)
switch(rule->target)
{
+ case FW3_FLAG_MARK:
+ if (rule->set_mark.set)
+ fw3_pr(" -j MARK --set-mark 0x%x/0x%x\n",
+ rule->set_mark.mark, rule->set_mark.mask);
+ else
+ fw3_pr(" -j MARK --set-xmark 0x%x/0x%x\n",
+ rule->set_xmark.mark, rule->set_xmark.mask);
+ return;
+
case FW3_FLAG_ACCEPT:
case FW3_FLAG_DROP:
case FW3_FLAG_NOTRACK:
@@ -272,6 +312,7 @@ print_rule(struct fw3_state *state, enum fw3_family family,
fw3_format_mac(mac);
fw3_format_limit(&rule->limit);
fw3_format_time(&rule->time);
+ fw3_format_mark(&rule->mark);
fw3_format_extra(rule->extra);
fw3_format_comment(rule->name);
print_target(rule);
@@ -299,8 +340,9 @@ expand_rule(struct fw3_state *state, enum fw3_family family,
if (!fw3_is_family(rule, family))
return;
- if ((table == FW3_TABLE_RAW && rule->target != FW3_FLAG_NOTRACK) ||
- (table != FW3_TABLE_FILTER))
+ if ((rule->target == FW3_FLAG_NOTRACK && table != FW3_TABLE_RAW) ||
+ (rule->target == FW3_FLAG_MARK && table != FW3_TABLE_MANGLE) ||
+ (rule->target < FW3_FLAG_NOTRACK && table != FW3_TABLE_FILTER))
return;
if (rule->name)