[Midnightbsd-cvs] src [9405] trunk: add ipfw support for setting/matching diffserv codepoints (DSCP).
laffer1 at midnightbsd.org
laffer1 at midnightbsd.org
Sat Mar 4 16:36:45 EST 2017
Revision: 9405
http://svnweb.midnightbsd.org/src/?rev=9405
Author: laffer1
Date: 2017-03-04 16:36:44 -0500 (Sat, 04 Mar 2017)
Log Message:
-----------
add ipfw support for setting/matching diffserv codepoints (DSCP).
Setting DSCP support is done via O_SETDSCP which works for both IPv4 and IPv6 packets.
Modified Paths:
--------------
trunk/sbin/ipfw/ipfw.8
trunk/sbin/ipfw/ipfw2.c
trunk/sbin/ipfw/ipfw2.h
trunk/sys/netinet/ip_fw.h
trunk/sys/netpfil/ipfw/ip_fw2.c
trunk/sys/netpfil/ipfw/ip_fw_log.c
trunk/sys/netpfil/ipfw/ip_fw_sockopt.c
Modified: trunk/sbin/ipfw/ipfw.8
===================================================================
--- trunk/sbin/ipfw/ipfw.8 2017-03-04 21:35:16 UTC (rev 9404)
+++ trunk/sbin/ipfw/ipfw.8 2017-03-04 21:36:44 UTC (rev 9405)
@@ -948,6 +948,61 @@
It is possible to use the
.Cm tablearg
keyword with a setfib. If tablearg value is not within compiled FIB range packet fib is set to 0.
+.It Cm setdscp Ar DSCP | number | tablearg
+Set specified DiffServ codepoint for an IPv4/IPv6 packet.
+Processing continues at the next rule.
+Supported values are:
+.Pp
+.Cm CS0
+.Pq Dv 000000 ,
+.Cm CS1
+.Pq Dv 001000 ,
+.Cm CS2
+.Pq Dv 010000 ,
+.Cm CS3
+.Pq Dv 011000 ,
+.Cm CS4
+.Pq Dv 100000 ,
+.Cm CS5
+.Pq Dv 101000 ,
+.Cm CS6
+.Pq Dv 110000 ,
+.Cm CS7
+.Pq Dv 111000 ,
+.Cm AF11
+.Pq Dv 001010 ,
+.Cm AF12
+.Pq Dv 001100 ,
+.Cm AF13
+.Pq Dv 001110 ,
+.Cm AF21
+.Pq Dv 010010 ,
+.Cm AF22
+.Pq Dv 010100 ,
+.Cm AF23
+.Pq Dv 010110 ,
+.Cm AF31
+.Pq Dv 011010 ,
+.Cm AF32
+.Pq Dv 011100 ,
+.Cm AF33
+.Pq Dv 011110 ,
+.Cm AF41
+.Pq Dv 100010 ,
+.Cm AF42
+.Pq Dv 100100 ,
+.Cm AF43
+.Pq Dv 100110 ,
+.Cm EF
+.Pq Dv 101110 ,
+.Cm BE
+.Pq Dv 000000 .
+Additionally, DSCP value can be specified by number (0..64).
+It is also possible to use the
+.Cm tablearg
+keyword with setdscp.
+If the tablearg value is not within the 0..64 range, lower 6 bits of supplied
+value are used.
.It Cm reass
Queue and reassemble ip fragments.
If the packet is not fragmented, counters are updated and processing continues with the next rule.
@@ -1436,6 +1491,17 @@
The absence of a particular type may be denoted
with a
.Ql \&! .
+.It Cm dscp spec Ns Op , Ns Ar spec
+Matches IPv4/IPv6 packets whose
+.Cm DS
+field value is contained in
+.Ar spec
+mask.
+Multiple values can be specified via
+the comma separated list.
+Value can be one of keywords used in
+.Cm setdscp
+action or exact number.
.It Cm ipttl Ar ttl-list
Matches IPv4 packets whose time to live is included in
.Ar ttl-list ,
@@ -2944,6 +3010,23 @@
but coming in on
.Li fxp1
would be dropped.
+.Pp
+The
+.Cm setdscp
+option could be used to (re)mark user traffic,
+by adding the following to the appropriate place in ruleset:
+.Pp
+.Dl "ipfw add setdscp be ip from any to any dscp af11,af21"
+.Pp
+This rule drops all incoming packets that appear to be coming from another
+directly connected system but on the wrong interface.
+For example, a packet with a source address of
+.Li 192.168.0.0/24 ,
+configured on
+.Li fxp0 ,
+but coming in on
+.Li fxp1
+would be dropped.
.Ss DYNAMIC RULES
In order to protect a site from flood attacks involving fake
TCP packets, it is safer to use dynamic rules:
Modified: trunk/sbin/ipfw/ipfw2.c
===================================================================
--- trunk/sbin/ipfw/ipfw2.c 2017-03-04 21:35:16 UTC (rev 9404)
+++ trunk/sbin/ipfw/ipfw2.c 2017-03-04 21:36:44 UTC (rev 9405)
@@ -167,6 +167,32 @@
{ NULL, 0 }
};
+static struct _s_x f_ipdscp[] = {
+ { "af11", IPTOS_DSCP_AF11 >> 2 }, /* 001010 */
+ { "af12", IPTOS_DSCP_AF12 >> 2 }, /* 001100 */
+ { "af13", IPTOS_DSCP_AF13 >> 2 }, /* 001110 */
+ { "af21", IPTOS_DSCP_AF21 >> 2 }, /* 010010 */
+ { "af22", IPTOS_DSCP_AF22 >> 2 }, /* 010100 */
+ { "af23", IPTOS_DSCP_AF23 >> 2 }, /* 010110 */
+ { "af31", IPTOS_DSCP_AF31 >> 2 }, /* 011010 */
+ { "af32", IPTOS_DSCP_AF32 >> 2 }, /* 011100 */
+ { "af33", IPTOS_DSCP_AF33 >> 2 }, /* 011110 */
+ { "af41", IPTOS_DSCP_AF41 >> 2 }, /* 100010 */
+ { "af42", IPTOS_DSCP_AF42 >> 2 }, /* 100100 */
+ { "af43", IPTOS_DSCP_AF43 >> 2 }, /* 100110 */
+ { "be", IPTOS_DSCP_CS0 >> 2 }, /* 000000 */
+ { "ef", IPTOS_DSCP_EF >> 2 }, /* 101110 */
+ { "cs0", IPTOS_DSCP_CS0 >> 2 }, /* 000000 */
+ { "cs1", IPTOS_DSCP_CS1 >> 2 }, /* 001000 */
+ { "cs2", IPTOS_DSCP_CS2 >> 2 }, /* 010000 */
+ { "cs3", IPTOS_DSCP_CS3 >> 2 }, /* 011000 */
+ { "cs4", IPTOS_DSCP_CS4 >> 2 }, /* 100000 */
+ { "cs5", IPTOS_DSCP_CS5 >> 2 }, /* 101000 */
+ { "cs6", IPTOS_DSCP_CS6 >> 2 }, /* 110000 */
+ { "cs7", IPTOS_DSCP_CS7 >> 2 }, /* 100000 */
+ { NULL, 0 }
+};
+
static struct _s_x limit_masks[] = {
{"all", DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT},
{"src-addr", DYN_SRC_ADDR},
@@ -237,6 +263,7 @@
{ "nat", TOK_NAT },
{ "reass", TOK_REASS },
{ "setfib", TOK_SETFIB },
+ { "setdscp", TOK_SETDSCP },
{ "call", TOK_CALL },
{ "return", TOK_RETURN },
{ NULL, 0 } /* terminator */
@@ -714,6 +741,51 @@
return (i);
}
+/*
+ * Fill the body of the command with the list of DiffServ codepoints.
+ */
+static void
+fill_dscp(ipfw_insn *cmd, char *av, int cblen)
+{
+ uint32_t *low, *high;
+ char *s = av, *a;
+ int code;
+
+ cmd->opcode = O_DSCP;
+ cmd->len |= F_INSN_SIZE(ipfw_insn_u32) + 1;
+
+ CHECK_CMDLEN;
+
+ low = (uint32_t *)(cmd + 1);
+ high = low + 1;
+
+ *low = 0;
+ *high = 0;
+
+ while (s != NULL) {
+ a = strchr(s, ',');
+
+ if (a != NULL)
+ *a++ = '\0';
+
+ if (isalpha(*s)) {
+ if ((code = match_token(f_ipdscp, s)) == -1)
+ errx(EX_DATAERR, "Unknown DSCP code");
+ } else {
+ code = strtoul(s, NULL, 10);
+ if (code < 0 || code > 63)
+ errx(EX_DATAERR, "Invalid DSCP value");
+ }
+
+ if (code > 32)
+ *high |= 1 << (code - 32);
+ else
+ *low |= 1 << code;
+
+ s = a;
+ }
+}
+
static struct _s_x icmpcodes[] = {
{ "net", ICMP_UNREACH_NET },
{ "host", ICMP_UNREACH_HOST },
@@ -972,6 +1044,32 @@
}
}
+static void
+print_dscp(ipfw_insn_u32 *cmd)
+{
+ int i, c;
+ uint32_t *v;
+ char sep= ' ';
+ const char *code;
+
+ printf(" dscp");
+ i = 0;
+ c = 0;
+ v = cmd->d;
+ while (i < 64) {
+ if (*v & (1 << i)) {
+ if ((code = match_value(f_ipdscp, i)) != NULL)
+ printf("%c%s", sep, code);
+ else
+ printf("%c%d", sep, i);
+ sep = ',';
+ }
+
+ if ((++i % 32) == 0)
+ v++;
+ }
+}
+
/*
* show_ipfw() prints the body of an ipfw rule.
* Because the standard rule has at least proto src_ip dst_ip, we use
@@ -1204,6 +1302,17 @@
PRINT_UINT_ARG("setfib ", cmd->arg1);
break;
+ case O_SETDSCP:
+ {
+ const char *code;
+
+ if ((code = match_value(f_ipdscp, cmd->arg1)) != NULL)
+ printf("setdscp %s", code);
+ else
+ PRINT_UINT_ARG("setdscp ", cmd->arg1);
+ }
+ break;
+
case O_REASS:
printf("reass");
break;
@@ -1499,6 +1608,10 @@
printf(" ipprecedence %u", (cmd->arg1) >> 5 );
break;
+ case O_DSCP:
+ print_dscp((ipfw_insn_u32 *)cmd);
+ break;
+
case O_IPLEN:
if (F_LEN(cmd) == 1)
printf(" iplen %u", cmd->arg1 );
@@ -3035,6 +3148,24 @@
break;
}
+ case TOK_SETDSCP:
+ {
+ int code;
+
+ action->opcode = O_SETDSCP;
+ NEED1("missing DSCP code");
+ if (_substrcmp(*av, "tablearg") == 0) {
+ action->arg1 = IP_FW_TABLEARG;
+ } else if (isalpha(*av[0])) {
+ if ((code = match_token(f_ipdscp, *av)) == -1)
+ errx(EX_DATAERR, "Unknown DSCP code");
+ action->arg1 = code;
+ } else
+ action->arg1 = strtoul(*av, NULL, 10);
+ av++;
+ break;
+ }
+
case TOK_REASS:
action->opcode = O_REASS;
break;
@@ -3447,6 +3578,12 @@
av++;
break;
+ case TOK_DSCP:
+ NEED1("missing DSCP code");
+ fill_dscp(cmd, *av, cblen);
+ av++;
+ break;
+
case TOK_IPOPTS:
NEED1("missing argument for ipoptions");
fill_flags(cmd, O_IPOPT, f_ipopts, *av);
Modified: trunk/sbin/ipfw/ipfw2.h
===================================================================
--- trunk/sbin/ipfw/ipfw2.h 2017-03-04 21:35:16 UTC (rev 9404)
+++ trunk/sbin/ipfw/ipfw2.h 2017-03-04 21:36:44 UTC (rev 9405)
@@ -203,6 +203,7 @@
TOK_SETFIB,
TOK_LOOKUP,
TOK_SOCKARG,
+ TOK_SETDSCP,
};
/*
* the following macro returns an error message if we run out of
Modified: trunk/sys/netinet/ip_fw.h
===================================================================
--- trunk/sys/netinet/ip_fw.h 2017-03-04 21:35:16 UTC (rev 9404)
+++ trunk/sys/netinet/ip_fw.h 2017-03-04 21:36:44 UTC (rev 9405)
@@ -219,6 +219,9 @@
O_FORWARD_IP6, /* fwd sockaddr_in6 */
+ O_DSCP, /* 2 u32 = DSCP mask */
+ O_SETDSCP, /* arg1=DSCP value */
+
O_LAST_OPCODE /* not an opcode! */
};
Modified: trunk/sys/netpfil/ipfw/ip_fw2.c
===================================================================
--- trunk/sys/netpfil/ipfw/ip_fw2.c 2017-03-04 21:35:16 UTC (rev 9404)
+++ trunk/sys/netpfil/ipfw/ip_fw2.c 2017-03-04 21:36:44 UTC (rev 9405)
@@ -1658,6 +1658,32 @@
flags_match(cmd, ip->ip_tos));
break;
+ case O_DSCP:
+ {
+ uint32_t *p;
+ uint16_t x;
+
+ p = ((ipfw_insn_u32 *)cmd)->d;
+
+ if (is_ipv4)
+ x = ip->ip_tos >> 2;
+ else if (is_ipv6) {
+ uint8_t *v;
+ v = &((struct ip6_hdr *)ip)->ip6_vfc;
+ x = (*v & 0x0F) << 2;
+ v++;
+ x |= *v >> 6;
+ } else
+ break;
+
+ /* DSCP bitmask is stored as low_u32 high_u32 */
+ if (x > 32)
+ match = *(p + 1) & (1 << (x - 32));
+ else
+ match = *p & (1 << x);
+ }
+ break;
+
case O_TCPDATALEN:
if (proto == IPPROTO_TCP && offset == 0) {
struct tcphdr *tcp;
@@ -2340,6 +2366,32 @@
break;
}
+ case O_SETDSCP: {
+ uint16_t code;
+
+ code = IP_FW_ARG_TABLEARG(cmd->arg1) & 0x3F;
+ l = 0; /* exit inner loop */
+ if (is_ipv4) {
+ uint16_t a;
+
+ a = ip->ip_tos;
+ ip->ip_tos = (code << 2) | (ip->ip_tos & 0x03);
+ a += ntohs(ip->ip_sum) - ip->ip_tos;
+ ip->ip_sum = htons(a);
+ } else if (is_ipv6) {
+ uint8_t *v;
+
+ v = &((struct ip6_hdr *)ip)->ip6_vfc;
+ *v = (*v & 0xF0) | (code >> 2);
+ v++;
+ *v = (*v & 0x3F) | ((code & 0x03) << 6);
+ } else
+ break;
+
+ IPFW_INC_RULE_COUNTER(f, pktlen);
+ break;
+ }
+
case O_NAT:
if (!IPFW_NAT_LOADED) {
retval = IP_FW_DENY;
Modified: trunk/sys/netpfil/ipfw/ip_fw_log.c
===================================================================
--- trunk/sys/netpfil/ipfw/ip_fw_log.c 2017-03-04 21:35:16 UTC (rev 9404)
+++ trunk/sys/netpfil/ipfw/ip_fw_log.c 2017-03-04 21:36:44 UTC (rev 9405)
@@ -209,12 +209,10 @@
altq->qid);
cmd += F_LEN(cmd);
}
- if (cmd->opcode == O_PROB)
+ if (cmd->opcode == O_PROB || cmd->opcode == O_TAG ||
+ cmd->opcode == O_SETDSCP)
cmd += F_LEN(cmd);
- if (cmd->opcode == O_TAG)
- cmd += F_LEN(cmd);
-
action = action2;
switch (cmd->opcode) {
case O_DENY:
Modified: trunk/sys/netpfil/ipfw/ip_fw_sockopt.c
===================================================================
--- trunk/sys/netpfil/ipfw/ip_fw_sockopt.c 2017-03-04 21:35:16 UTC (rev 9404)
+++ trunk/sys/netpfil/ipfw/ip_fw_sockopt.c 2017-03-04 21:36:44 UTC (rev 9405)
@@ -681,6 +681,11 @@
goto bad_size;
break;
+ case O_DSCP:
+ if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1)
+ goto bad_size;
+ break;
+
case O_MAC_TYPE:
case O_IP_SRCPORT:
case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */
@@ -741,6 +746,7 @@
case O_ACCEPT:
case O_DENY:
case O_REJECT:
+ case O_SETDSCP:
#ifdef INET6
case O_UNREACH6:
#endif
More information about the Midnightbsd-cvs
mailing list