Browse Source

Add support for DSCP matches and target

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Jo-Philipp Wich 5 years ago
parent
commit
12a7cf9db1
5 changed files with 126 additions and 18 deletions
  1. 14 0
      iptables.c
  2. 2 0
      iptables.h
  3. 59 0
      options.c
  4. 22 11
      options.h
  5. 29 7
      rules.c

+ 14 - 0
iptables.c

@@ -1140,6 +1140,20 @@ fw3_ipt_rule_mark(struct fw3_ipt_rule *r, struct fw3_mark *mark)
 	fw3_ipt_rule_addarg(r, mark->invert, "--mark", buf);
 }
 
+void
+fw3_ipt_rule_dscp(struct fw3_ipt_rule *r, struct fw3_dscp *dscp)
+{
+	char buf[sizeof("0xFF\0")];
+
+	if (!dscp || !dscp->set)
+		return;
+
+	sprintf(buf, "0x%x", dscp->dscp);
+
+	fw3_ipt_rule_addarg(r, false, "-m", "dscp");
+	fw3_ipt_rule_addarg(r, dscp->invert, "--dscp", buf);
+}
+
 void
 fw3_ipt_rule_comment(struct fw3_ipt_rule *r, const char *fmt, ...)
 {

+ 2 - 0
iptables.h

@@ -93,6 +93,8 @@ void fw3_ipt_rule_time(struct fw3_ipt_rule *r, struct fw3_time *time);
 
 void fw3_ipt_rule_mark(struct fw3_ipt_rule *r, struct fw3_mark *mark);
 
+void fw3_ipt_rule_dscp(struct fw3_ipt_rule *r, struct fw3_dscp *dscp);
+
 void fw3_ipt_rule_comment(struct fw3_ipt_rule *r, const char *fmt, ...);
 
 void fw3_ipt_rule_extra(struct fw3_ipt_rule *r, const char *extra);

+ 59 - 0
options.c

@@ -77,6 +77,7 @@ const char *fw3_flag_names[__FW3_FLAG_MAX] = {
 	"NOTRACK",
 	"HELPER",
 	"MARK",
+	"DSCP",
 	"DNAT",
 	"SNAT",
 	"MASQUERADE",
@@ -135,6 +136,31 @@ static const char *reflection_sources[] = {
 	"external",
 };
 
+static const struct { const char *name; uint8_t dscp; } dscp_classes[] = {
+	{ "CS0",  0x00 },
+	{ "CS1",  0x08 },
+	{ "CS2",  0x10 },
+	{ "CS3",  0x18 },
+	{ "CS4",  0x20 },
+	{ "CS5",  0x28 },
+	{ "CS6",  0x30 },
+	{ "CS7",  0x38 },
+	{ "BE",   0x00 },
+	{ "AF11", 0x0a },
+	{ "AF12", 0x0c },
+	{ "AF13", 0x0e },
+	{ "AF21", 0x12 },
+	{ "AF22", 0x14 },
+	{ "AF23", 0x16 },
+	{ "AF31", 0x1a },
+	{ "AF32", 0x1c },
+	{ "AF33", 0x1e },
+	{ "AF41", 0x22 },
+	{ "AF42", 0x24 },
+	{ "AF43", 0x26 },
+	{ "EF",   0x2e }
+};
+
 
 bool
 fw3_parse_bool(void *ptr, const char *val, bool is_list)
@@ -858,6 +884,39 @@ fw3_parse_mark(void *ptr, const char *val, bool is_list)
 	return true;
 }
 
+bool
+fw3_parse_dscp(void *ptr, const char *val, bool is_list)
+{
+	uint32_t n;
+	char *e;
+	struct fw3_dscp *d = ptr;
+
+	if (*val == '!')
+	{
+		d->invert = true;
+		while (isspace(*++val));
+	}
+
+	for (n = 0; n < sizeof(dscp_classes) / sizeof(dscp_classes[0]); n++)
+	{
+		if (strcmp(dscp_classes[n].name, val))
+			continue;
+
+		d->set = true;
+		d->dscp = dscp_classes[n].dscp;
+		return true;
+	}
+
+	n = strtoul(val, &e, 0);
+
+	if (e == val || *e || n > 0x3F)
+		return false;
+
+	d->set = true;
+	d->dscp = n;
+	return true;
+}
+
 bool
 fw3_parse_setmatch(void *ptr, const char *val, bool is_list)
 {

+ 22 - 11
options.h

@@ -73,17 +73,18 @@ enum fw3_flag
 	FW3_FLAG_NOTRACK       = 9,
 	FW3_FLAG_HELPER        = 10,
 	FW3_FLAG_MARK          = 11,
-	FW3_FLAG_DNAT          = 12,
-	FW3_FLAG_SNAT          = 13,
-	FW3_FLAG_MASQUERADE    = 14,
-	FW3_FLAG_SRC_ACCEPT    = 15,
-	FW3_FLAG_SRC_REJECT    = 16,
-	FW3_FLAG_SRC_DROP      = 17,
-	FW3_FLAG_CUSTOM_CHAINS = 18,
-	FW3_FLAG_SYN_FLOOD     = 19,
-	FW3_FLAG_MTU_FIX       = 20,
-	FW3_FLAG_DROP_INVALID  = 21,
-	FW3_FLAG_HOTPLUG       = 22,
+	FW3_FLAG_DSCP          = 12,
+	FW3_FLAG_DNAT          = 13,
+	FW3_FLAG_SNAT          = 14,
+	FW3_FLAG_MASQUERADE    = 15,
+	FW3_FLAG_SRC_ACCEPT    = 16,
+	FW3_FLAG_SRC_REJECT    = 17,
+	FW3_FLAG_SRC_DROP      = 18,
+	FW3_FLAG_CUSTOM_CHAINS = 19,
+	FW3_FLAG_SYN_FLOOD     = 20,
+	FW3_FLAG_MTU_FIX       = 21,
+	FW3_FLAG_DROP_INVALID  = 22,
+	FW3_FLAG_HOTPLUG       = 23,
 
 	__FW3_FLAG_MAX
 };
@@ -268,6 +269,13 @@ struct fw3_mark
 	uint32_t mask;
 };
 
+struct fw3_dscp
+{
+	bool set;
+	bool invert;
+	uint8_t dscp;
+};
+
 struct fw3_cthelpermatch
 {
 	struct list_head list;
@@ -382,10 +390,12 @@ struct fw3_rule
 	struct fw3_limit limit;
 	struct fw3_time time;
 	struct fw3_mark mark;
+	struct fw3_dscp dscp;
 
 	enum fw3_flag target;
 	struct fw3_mark set_mark;
 	struct fw3_mark set_xmark;
+	struct fw3_dscp set_dscp;
 	struct fw3_cthelpermatch set_helper;
 
 	const char *extra;
@@ -613,6 +623,7 @@ 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);
+bool fw3_parse_dscp(void *ptr, const char *val, bool is_list);
 bool fw3_parse_setmatch(void *ptr, const char *val, bool is_list);
 bool fw3_parse_direction(void *ptr, const char *val, bool is_list);
 bool fw3_parse_cthelper(void *ptr, const char *val, bool is_list);

+ 29 - 7
rules.c

@@ -62,6 +62,9 @@ const struct fw3_option fw3_rule_opts[] = {
 	FW3_OPT("set_mark",            mark,      rule,     set_mark),
 	FW3_OPT("set_xmark",           mark,      rule,     set_xmark),
 
+	FW3_OPT("dscp",                dscp,      rule,     dscp),
+	FW3_OPT("set_dscp",            dscp,      rule,     set_dscp),
+
 	FW3_OPT("target",              target,    rule,     target),
 
 	{ }
@@ -156,19 +159,28 @@ check_rule(struct fw3_state *state, struct fw3_rule *r, struct uci_element *e)
 	    r->target == FW3_FLAG_MARK)
 	{
 		warn_section("rule", r, e, "is set to target MARK but specifies neither "
-		                "'set_mark' nor 'set_xmark' option");
+		                           "'set_mark' nor 'set_xmark' option");
 		return false;
 	}
 
-	if (r->_dest && r->target == FW3_FLAG_MARK)
+	if (!r->set_dscp.set && r->target == FW3_FLAG_DSCP)
 	{
-		warn_section("rule", r, e, "must not specify 'dest' for MARK target");
+		warn_section("rule", r, e, "is set to target DSCP but specifies no "
+		                           "'set_dscp' option");
 		return false;
 	}
 
-	if (r->set_mark.invert || r->set_xmark.invert)
+	if (r->_dest && (r->target == FW3_FLAG_MARK || r->target == FW3_FLAG_DSCP))
 	{
-		warn_section("rule", r, e, "must not have inverted 'set_mark' or 'set_xmark'");
+		warn_section("rule", r, e, "must not specify 'dest' for %s target",
+		             fw3_flag_names[r->target]);
+		return false;
+	}
+
+	if (r->set_mark.invert || r->set_xmark.invert || r->set_dscp.invert)
+	{
+		warn_section("rule", r, e, "must not have inverted 'set_mark', "
+		                           "'set_xmark' or 'set_dscp'");
 		return false;
 	}
 
@@ -202,7 +214,7 @@ check_rule(struct fw3_state *state, struct fw3_rule *r, struct uci_element *e)
 		warn_section("rule", r, e, "has no target specified, defaulting to REJECT");
 		r->target = FW3_FLAG_REJECT;
 	}
-	else if (r->target > FW3_FLAG_MARK)
+	else if (r->target > FW3_FLAG_DSCP)
 	{
 		warn_section("rule", r, e, "has invalid target specified, defaulting to REJECT");
 		r->target = FW3_FLAG_REJECT;
@@ -297,7 +309,8 @@ append_chain(struct fw3_ipt_rule *r, struct fw3_rule *rule)
 	{
 		snprintf(chain, sizeof(chain), "zone_%s_helper", rule->src.name);
 	}
-	else if (rule->target == FW3_FLAG_MARK && (rule->_src || rule->src.any))
+	else if ((rule->target == FW3_FLAG_MARK || rule->target == FW3_FLAG_DSCP) &&
+	         (rule->_src || rule->src.any))
 	{
 		snprintf(chain, sizeof(chain), "PREROUTING");
 	}
@@ -353,6 +366,13 @@ static void set_target(struct fw3_ipt_rule *r, struct fw3_rule *rule)
 		fw3_ipt_rule_addarg(r, false, name, buf);
 		return;
 
+	case FW3_FLAG_DSCP:
+		sprintf(buf, "0x%x", rule->set_dscp.dscp);
+
+		fw3_ipt_rule_target(r, "DSCP");
+		fw3_ipt_rule_addarg(r, false, "--set-dscp", buf);
+		return;
+
 	case FW3_FLAG_NOTRACK:
 		fw3_ipt_rule_target(r, "CT");
 		fw3_ipt_rule_addarg(r, false, "--notrack", NULL);
@@ -461,6 +481,7 @@ print_rule(struct fw3_ipt_handle *handle, struct fw3_state *state,
 	fw3_ipt_rule_limit(r, &rule->limit);
 	fw3_ipt_rule_time(r, &rule->time);
 	fw3_ipt_rule_mark(r, &rule->mark);
+	fw3_ipt_rule_dscp(r, &rule->dscp);
 	set_target(r, rule);
 	fw3_ipt_rule_extra(r, rule->extra);
 	set_comment(r, rule->name, num);
@@ -492,6 +513,7 @@ expand_rule(struct fw3_ipt_handle *handle, struct fw3_state *state,
 	if ((rule->target == FW3_FLAG_NOTRACK && handle->table != FW3_TABLE_RAW) ||
 	    (rule->target == FW3_FLAG_HELPER && handle->table != FW3_TABLE_RAW)  ||
 	    (rule->target == FW3_FLAG_MARK && handle->table != FW3_TABLE_MANGLE) ||
+	    (rule->target == FW3_FLAG_DSCP && handle->table != FW3_TABLE_MANGLE) ||
 		(rule->target < FW3_FLAG_NOTRACK && handle->table != FW3_TABLE_FILTER))
 		return;