ipfw: fix IPv6 flow label matching
* do not require just only ip6 proto for flow-id opcode in ipfw(8). ipv6-icmp, tcp, udp should be fine too. * fix off-by-one bug leading to out-of-bounds read. * apply IPV6_FLOWLABEL_MASK before comparison in flow6id_match(), so flow-id opcode will match a specified flow label. No need to take protocol version and traffic class into account. * add the test to verify that opcode is working correctly. Reviewed by: pouria Obtained from: Yandex LLC MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D56869
This commit is contained in:
committed by
Andrey V. Elsukov
parent
e26b5e0749
commit
3d39eadcde
@@ -63,6 +63,7 @@ def prepare_ipv6(send_params):
|
||||
dst_address = send_params.get('dst_address')
|
||||
hlim = send_params.get('hlim')
|
||||
tc = send_params.get('tc')
|
||||
fl = send_params.get('fl')
|
||||
ip6 = sp.IPv6(dst=dst_address)
|
||||
if src_address:
|
||||
ip6.src = src_address
|
||||
@@ -70,6 +71,8 @@ def prepare_ipv6(send_params):
|
||||
ip6.hlim = hlim
|
||||
if tc:
|
||||
ip6.tc = tc
|
||||
if fl:
|
||||
ip6.fl = fl
|
||||
return ip6
|
||||
|
||||
|
||||
@@ -224,6 +227,7 @@ def check_ipv6(expect_params, packet):
|
||||
flags = expect_params.get('flags')
|
||||
hlim = expect_params.get('hlim')
|
||||
tc = expect_params.get('tc')
|
||||
fl = expect_params.get('fl')
|
||||
ip6 = packet.getlayer(sp.IPv6)
|
||||
if not ip6:
|
||||
LOGGER.debug('Packet is not IPv6!')
|
||||
@@ -245,6 +249,9 @@ def check_ipv6(expect_params, packet):
|
||||
if tc and ip6.tc != tc:
|
||||
LOGGER.debug(f'Wrong TC value {ip6.tc}, expected {tc}')
|
||||
return False
|
||||
if fl and ip6.fl != fl:
|
||||
LOGGER.debug(f'Wrong Flow Label value {ip6.fl}, expected {fl}')
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@@ -635,6 +642,8 @@ def parse_args():
|
||||
help='ICMP Echo Request payload size')
|
||||
parser_send.add_argument('--send-tc', type=int,
|
||||
help='IPv6 Traffic Class or IPv4 DiffServ / ToS')
|
||||
parser_send.add_argument('--send-fl', type=int,
|
||||
help='IPv6 Flow label')
|
||||
parser_send.add_argument('--send-tcpopt-unaligned', action='store_true',
|
||||
help='Include unaligned TCP options')
|
||||
parser_send.add_argument('--send-nop', action='store_true',
|
||||
@@ -652,6 +661,8 @@ def parse_args():
|
||||
help='TCP sequence number')
|
||||
parser_expect.add_argument('--expect-tc', type=int,
|
||||
help='IPv6 Traffic Class or IPv4 DiffServ / ToS')
|
||||
parser_expect.add_argument('--expect-fl', type=int,
|
||||
help='IPv6 Flow Label')
|
||||
|
||||
parser.add_argument('-v', '--verbose', action='store_true',
|
||||
help=('Enable verbose logging. Apart of potentially useful information '
|
||||
@@ -673,7 +684,7 @@ def main():
|
||||
send_params = {}
|
||||
expect_params = {}
|
||||
for param_name in (
|
||||
'flags', 'hlim', 'length', 'mss', 'seq', 'tc', 'frag_length',
|
||||
'flags', 'hlim', 'length', 'mss', 'seq', 'tc', 'fl', 'frag_length',
|
||||
'sport', 'dport',
|
||||
):
|
||||
param_arg = vars(args).get(f'send_{param_name}')
|
||||
|
||||
@@ -4,6 +4,7 @@ TESTSDIR= ${TESTSBASE}/sys/netpfil/ipfw
|
||||
|
||||
ATF_TESTS_SH+= fwd \
|
||||
divert \
|
||||
ipv6-flow-id \
|
||||
log \
|
||||
lookup \
|
||||
table
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
#
|
||||
# Copyright (c) 2026 Boris Lytochkin
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
|
||||
common_dir="$(atf_get_srcdir)/../common"
|
||||
. ${common_dir}/utils.subr
|
||||
|
||||
NC="nc -w 1 -dnN"
|
||||
|
||||
setup_network_v6()
|
||||
{
|
||||
epair="$1"
|
||||
|
||||
ifconfig ${epair}a inet6 2001:db8:42::1/64 up no_dad -ifdisabled
|
||||
|
||||
vnet_mkjail alcatraz ${epair}b
|
||||
|
||||
ifconfig -j alcatraz ${epair}b inet6 2001:db8:42::2/64 up no_dad -ifdisabled
|
||||
|
||||
jexec alcatraz /usr/sbin/inetd -p /dev/null $(atf_get_srcdir)/lookup_inetd.conf
|
||||
|
||||
# Sanity checks
|
||||
atf_check -s exit:0 -o ignore ping6 -i .1 -c 3 -s 1200 2001:db8:42::2
|
||||
atf_check -o "inline:GOOD 82\n" ${NC} 2001:db8:42::2 82
|
||||
}
|
||||
|
||||
atf_test_case "ipv6fl" "cleanup"
|
||||
|
||||
ipv6fl_head()
|
||||
{
|
||||
atf_set descr 'flow-id test'
|
||||
atf_set require.user root
|
||||
atf_set require.progs python3 scapy
|
||||
}
|
||||
|
||||
ipv6fl_body()
|
||||
{
|
||||
|
||||
firewall_init "ipfw"
|
||||
|
||||
epair=$(vnet_mkepair)
|
||||
|
||||
setup_network_v6 ${epair}
|
||||
|
||||
# Check if the firewall is able to match exact IPv6 flow label
|
||||
firewall_config "alcatraz" ipfw ipfw \
|
||||
"ipfw -q add 100 allow ip6 from any to any flow-id 0xbaad" \
|
||||
"ipfw -q add 200 deny ipv6-icmp from any to any icmp6types 128 in"
|
||||
|
||||
# Check Flow Label matches
|
||||
atf_check -s exit:0 ${common_dir}/pft_ping.py \
|
||||
--sendif ${epair}a \
|
||||
--fromaddr 2001:db8:42::1 \
|
||||
--to 2001:db8:42::2 \
|
||||
--send-fl $((0xbaad)) \
|
||||
--replyif ${epair}a
|
||||
|
||||
# Check Flow Label mismatch
|
||||
atf_check -s exit:1 ${common_dir}/pft_ping.py \
|
||||
--sendif ${epair}a \
|
||||
--fromaddr 2001:db8:42::1 \
|
||||
--to 2001:db8:42::2 \
|
||||
--send-fl $((0xf001)) \
|
||||
--replyif ${epair}a
|
||||
|
||||
}
|
||||
|
||||
ipv6fl_cleanup()
|
||||
{
|
||||
firewall_cleanup $1
|
||||
}
|
||||
|
||||
atf_init_test_cases()
|
||||
{
|
||||
atf_add_test_case "ipv6fl"
|
||||
}
|
||||
Reference in New Issue
Block a user