Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 19 Aug 2021 10:08:24 GMT
From:      Kristof Provost <kp@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 0a7d1fc6f632 - main - pf: implement set-tos for IPv6
Message-ID:  <202108191008.17JA8OnT031466@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=0a7d1fc6f6324e62458e72546cc06ac8c76c494b

commit 0a7d1fc6f6324e62458e72546cc06ac8c76c494b
Author:     Samuel Robinette <samrobinette95@gmail.com>
AuthorDate: 2021-08-15 18:26:41 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2021-08-19 08:07:56 +0000

    pf: implement set-tos for IPv6
    
    Extend the existing set-tos keyword to also be able to set traffic class
    on IPv6 traffic.
    Add tests for this as well.
    
    Reviewed by:    kp
    Differential Revision:  https://reviews.freebsd.org/D31564
---
 sys/netpfil/pf/pf_norm.c             | 12 +++--
 tests/sys/netpfil/common/pft_ping.py | 29 +++++++++++-
 tests/sys/netpfil/pf/set_tos.sh      | 88 ++++++++++++++++++++++++++++++++++++
 3 files changed, 125 insertions(+), 4 deletions(-)

diff --git a/sys/netpfil/pf/pf_norm.c b/sys/netpfil/pf/pf_norm.c
index e9674d21ec5a..796d445607e7 100644
--- a/sys/netpfil/pf/pf_norm.c
+++ b/sys/netpfil/pf/pf_norm.c
@@ -157,7 +157,7 @@ static int	pf_reassemble(struct mbuf **, struct ip *, int, u_short *);
 #ifdef INET6
 static int	pf_reassemble6(struct mbuf **, struct ip6_hdr *,
 		    struct ip6_frag *, uint16_t, uint16_t, u_short *);
-static void	pf_scrub_ip6(struct mbuf **, uint8_t);
+static void	pf_scrub_ip6(struct mbuf **, uint32_t, uint8_t, uint8_t);
 #endif	/* INET6 */
 
 #define	DPFPRINTF(x) do {				\
@@ -1283,7 +1283,7 @@ pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kkif *kif,
 	if (sizeof(struct ip6_hdr) + plen > m->m_pkthdr.len)
 		goto shortpkt;
 
-	pf_scrub_ip6(&m, r->min_ttl);
+	pf_scrub_ip6(&m, r->rule_flag, r->min_ttl, r->set_tos);
 
 	return (PF_PASS);
 
@@ -2032,7 +2032,7 @@ pf_scrub_ip(struct mbuf **m0, u_int32_t flags, u_int8_t min_ttl, u_int8_t tos)
 
 #ifdef INET6
 static void
-pf_scrub_ip6(struct mbuf **m0, u_int8_t min_ttl)
+pf_scrub_ip6(struct mbuf **m0, u_int32_t flags, u_int8_t min_ttl, u_int8_t tos)
 {
 	struct mbuf		*m = *m0;
 	struct ip6_hdr		*h = mtod(m, struct ip6_hdr *);
@@ -2040,5 +2040,11 @@ pf_scrub_ip6(struct mbuf **m0, u_int8_t min_ttl)
 	/* Enforce a minimum ttl, may cause endless packet loops */
 	if (min_ttl && h->ip6_hlim < min_ttl)
 		h->ip6_hlim = min_ttl;
+
+	/* Enforce tos. Set traffic class bits */
+	if (flags & PFRULE_SET_TOS) {
+		h->ip6_flow &= IPV6_FLOWLABEL_MASK | IPV6_VERSION_MASK;
+		h->ip6_flow |= htonl((tos | IPV6_ECN(h)) << 20);
+	}
 }
 #endif
diff --git a/tests/sys/netpfil/common/pft_ping.py b/tests/sys/netpfil/common/pft_ping.py
index 9cc7c5d5c5c0..9ed6a00cab34 100644
--- a/tests/sys/netpfil/common/pft_ping.py
+++ b/tests/sys/netpfil/common/pft_ping.py
@@ -115,6 +115,14 @@ def check_ping6_request(args, packet):
 	if icmp.data != PAYLOAD_MAGIC:
 		return False
 
+	# Wait to check expectations until we've established this is the packet we
+	# sent.
+	if args.expect_tc:
+		if ip.tc != int(args.expect_tc[0]):
+			print("Unexpected traffic class value %d, expected %d" \
+				% (ip.tc, int(args.expect_tc[0])))
+			return False
+
 	return True
 
 def check_ping_reply(args, packet):
@@ -147,6 +155,12 @@ def check_ping4_reply(args, packet):
 	if raw.load != PAYLOAD_MAGIC:
 		return False
 
+	if args.expect_tos:
+		if ip.tos != int(args.expect_tos[0]):
+			print("Unexpected ToS value %d, expected %d" \
+				% (ip.tos, int(args.expect_tos[0])))
+			return False
+
 	return True
 
 def check_ping6_reply(args, packet):
@@ -170,6 +184,12 @@ def check_ping6_reply(args, packet):
 		print("data mismatch")
 		return False
 
+	if args.expect_tc:
+		if ip.tc != int(args.expect_tc[0]):
+			print("Unexpected traffic class value %d, expected %d" \
+				% (ip.tc, int(args.expect_tc[0])))
+			return False
+
 	return True
 
 def ping(send_if, dst_ip, args):
@@ -192,8 +212,11 @@ def ping6(send_if, dst_ip, args):
 	ip6 = sp.IPv6(dst=dst_ip)
 	icmp = sp.ICMPv6EchoRequest(data=sp.raw(PAYLOAD_MAGIC))
 
+	if args.send_tc:
+		ip6.tc = int(args.send_tc[0])
+
 	if args.fromaddr:
-		ip.src = args.fromaddr[0]
+		ip6.src = args.fromaddr[0]
 
 	req = ether / ip6 / icmp
 	sp.sendp(req, iface=send_if, verbose=False)
@@ -274,10 +297,14 @@ def main():
 	# Packet settings
 	parser.add_argument('--send-tos', nargs=1,
 		help='Set the ToS value for the transmitted packet')
+	parser.add_argument('--send-tc', nargs=1,
+		help='Set the traffic class value for the transmitted packet')
 
 	# Expectations
 	parser.add_argument('--expect-tos', nargs=1,
 		help='The expected ToS value in the received packet')
+	parser.add_argument('--expect-tc', nargs=1,
+		help='The expected traffic class value in the received packet')
 
 	args = parser.parse_args()
 
diff --git a/tests/sys/netpfil/pf/set_tos.sh b/tests/sys/netpfil/pf/set_tos.sh
index 55d0059aa133..2dbca54a1ee9 100644
--- a/tests/sys/netpfil/pf/set_tos.sh
+++ b/tests/sys/netpfil/pf/set_tos.sh
@@ -4,6 +4,8 @@
 #
 # Copyright (c) 2017 Kristof Provost <kp@FreeBSD.org>
 #
+# Copyright (c) 2021 Samuel Robinette
+#
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
 # are met:
@@ -114,7 +116,93 @@ v4_cleanup()
 	pft_cleanup
 }
 
+atf_test_case "v6" "cleanup"
+v6_head()
+{
+	atf_set descr 'set-tos6 test'
+	atf_set require.user root
+
+	# We need scapy to be installed for out test scripts to work
+	atf_set require.progs scapy
+}
+
+v6_body()
+{
+	pft_init
+
+	epair=$(vnet_mkepair)
+	ifconfig ${epair}a inet6 add 2001:db8:192::1
+	vnet_mkjail alcatraz ${epair}b
+	jexec alcatraz ifconfig ${epair}b inet6 add 2001:db8:192::2
+
+	route -6 add 2001:db8:192::2 2001:db8:192::1
+	jexec alcatraz route -6 add 2001:db8:192::1 2001:db8:192::2
+
+	jexec alcatraz pfctl -e
+
+	# No change is done if not requested
+	pft_set_rules alcatraz "scrub out proto ipv6-icmp"
+	atf_check -s exit:1 -o ignore -e ignore ${common_dir}/pft_ping.py \
+		--ip6 \
+		--sendif ${epair}a \
+		--to 2001:db8:192::2 \
+		--replyif ${epair}a \
+		--expect-tc 42
+
+	# The requested ToS is set
+	pft_set_rules alcatraz "scrub out proto ipv6-icmp set-tos 42"
+	atf_check -s exit:0 -o ignore -e ignore ${common_dir}/pft_ping.py \
+		--ip6 \
+		--sendif ${epair}a \
+		--to 2001:db8:192::2 \
+		--replyif ${epair}a \
+		--expect-tc 42
+
+	# ToS is not changed if the scrub rule does not match
+	pft_set_rules alcatraz "scrub out from 2001:db8:192::3 set-tos 42"
+	atf_check -s exit:1 -o ignore -e ignore ${common_dir}/pft_ping.py \
+		--ip6 \
+		--sendif ${epair}a \
+		--to 2001:db8:192::2 \
+		--replyif ${epair}a \
+		--expect-tc 42
+
+	# Multiple scrub rules match as expected
+	pft_set_rules alcatraz "scrub out from 2001:db8:192::3 set-tos 13" \
+		"scrub out proto ipv6-icmp set-tos 14"
+	atf_check -s exit:0 -o ignore -e ignore ${common_dir}/pft_ping.py \
+		--ip6 \
+		--sendif ${epair}a \
+		--to 2001:db8:192::2 \
+		--replyif ${epair}a \
+		--expect-tc 14
+
+	# And this works even if the packet already has ToS values set
+	atf_check -s exit:0 -o ignore -e ignore ${common_dir}/pft_ping.py \
+		--ip6 \
+		--sendif ${epair}a \
+		--to 2001:db8:192::2 \
+		--replyif ${epair}a \
+		--send-tc 42 \
+		--expect-tc 14
+
+	# ToS values are unmolested if the packets do not match a scrub rule
+	pft_set_rules alcatraz "scrub out from 2001:db8:192::3 set-tos 13"
+	atf_check -s exit:0 -o ignore -e ignore ${common_dir}/pft_ping.py \
+		--ip6 \
+		--sendif ${epair}a \
+		--to 2001:db8:192::2 \
+		--replyif ${epair}a \
+		--expect-tc 0
+}
+
+v6_cleanup()
+{
+	pft_cleanup
+}
+
 atf_init_test_cases()
 {
 	atf_add_test_case "v4"
+	atf_add_test_case "v6"
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202108191008.17JA8OnT031466>