Add support for DSCP matches and target
authorJo-Philipp Wich <jo@mein.io>
Fri, 3 Aug 2018 20:29:59 +0000 (22:29 +0200)
committerJo-Philipp Wich <jo@mein.io>
Fri, 3 Aug 2018 20:29:59 +0000 (22:29 +0200)
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
iptables.c
iptables.h
options.c
options.h
rules.c

index adf64c05c4311ed75135cdb9c927da75ae4553c4..a095621dc30873a2cb068d2ace6e59bc0d111e97 100644 (file)
@@ -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, ...)
 {
index 8ec7add695cbdfc012cc9b3d4e8cd1ba2e42a653..fb4a899a8fa8d6ce6b9ba425772fa07943ed3b05 100644 (file)
@@ -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);
index c85bafd4d9123a66ba9c7dc46e4bf339f5d753c5..5184346d2d40b51abd7c98b4c875bf2c57cd2d00 100644 (file)
--- a/options.c
+++ b/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)
 {
index 0b73a8433e9c0480b87a715d2ecb3bd52576a63f..a75cfa3536714c919f9243176ad1f844870ffa0f 100644 (file)
--- a/options.h
+++ b/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);
diff --git a/rules.c b/rules.c
index 5e1d5f3a6385fe084f53d9e4feae8659c4afe2ac..5af8bfd952623d625b538f4968e7180ef6407225 100644 (file)
--- a/rules.c
+++ b/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;