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>