From 54f0b072a03fded1070ce228676d93e574ccac09 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Fri, 5 Apr 2013 16:02:31 +0200 Subject: [PATCH] Add support for fwmark matches and targets --- defaults.c | 4 ++++ options.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ options.h | 37 ++++++++++++++++++++++++++----------- redirects.c | 4 ++++ rules.c | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 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, @@ -1098,6 +1137,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, ...) { 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) -- 2.30.2