From owner-dev-commits-src-main@freebsd.org Thu Aug 19 10:08:24 2021 Return-Path: Delivered-To: dev-commits-src-main@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id CD30466256A; Thu, 19 Aug 2021 10:08:24 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Gr0pJ5BdHz4Yc7; Thu, 19 Aug 2021 10:08:24 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 9A40623854; Thu, 19 Aug 2021 10:08:24 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 17JA8OSG031467; Thu, 19 Aug 2021 10:08:24 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 17JA8OnT031466; Thu, 19 Aug 2021 10:08:24 GMT (envelope-from git) Date: Thu, 19 Aug 2021 10:08:24 GMT Message-Id: <202108191008.17JA8OnT031466@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kristof Provost Subject: git: 0a7d1fc6f632 - main - pf: implement set-tos for IPv6 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kp X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 0a7d1fc6f6324e62458e72546cc06ac8c76c494b Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-main@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commit messages for the main branch of the src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 19 Aug 2021 10:08:24 -0000 The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=0a7d1fc6f6324e62458e72546cc06ac8c76c494b commit 0a7d1fc6f6324e62458e72546cc06ac8c76c494b Author: Samuel Robinette AuthorDate: 2021-08-15 18:26:41 +0000 Commit: Kristof Provost 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 # +# 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" }