xref: /freebsd/tests/sys/netinet6/frag6/frag6_20.py (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
1619456bbSBjoern A. Zeeb#!/usr/bin/env python
2619456bbSBjoern A. Zeeb#-
3619456bbSBjoern A. Zeeb# SPDX-License-Identifier: BSD-2-Clause
4619456bbSBjoern A. Zeeb#
5619456bbSBjoern A. Zeeb# Copyright (c) 2019 Netflix, Inc.
6619456bbSBjoern A. Zeeb#
7619456bbSBjoern A. Zeeb# Redistribution and use in source and binary forms, with or without
8619456bbSBjoern A. Zeeb# modification, are permitted provided that the following conditions
9619456bbSBjoern A. Zeeb# are met:
10619456bbSBjoern A. Zeeb# 1. Redistributions of source code must retain the above copyright
11619456bbSBjoern A. Zeeb#    notice, this list of conditions and the following disclaimer.
12619456bbSBjoern A. Zeeb# 2. Redistributions in binary form must reproduce the above copyright
13619456bbSBjoern A. Zeeb#    notice, this list of conditions and the following disclaimer in the
14619456bbSBjoern A. Zeeb#    documentation and/or other materials provided with the distribution.
15619456bbSBjoern A. Zeeb#
16619456bbSBjoern A. Zeeb# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17619456bbSBjoern A. Zeeb# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18619456bbSBjoern A. Zeeb# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19619456bbSBjoern A. Zeeb# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20619456bbSBjoern A. Zeeb# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21619456bbSBjoern A. Zeeb# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22619456bbSBjoern A. Zeeb# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23619456bbSBjoern A. Zeeb# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24619456bbSBjoern A. Zeeb# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25619456bbSBjoern A. Zeeb# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26619456bbSBjoern A. Zeeb# SUCH DAMAGE.
27619456bbSBjoern A. Zeeb#
28619456bbSBjoern A. Zeeb#
29619456bbSBjoern A. Zeeb
30619456bbSBjoern A. Zeebimport argparse
31a26e895fSKristof Provostimport logging
32a26e895fSKristof Provostlogging.getLogger("scapy").setLevel(logging.CRITICAL)
33619456bbSBjoern A. Zeebimport scapy.all as sp
34619456bbSBjoern A. Zeebimport socket
35619456bbSBjoern A. Zeebimport sys
36619456bbSBjoern A. Zeebfrom sniffer import Sniffer
37619456bbSBjoern A. Zeebfrom time import sleep
38619456bbSBjoern A. Zeeb
39619456bbSBjoern A. Zeebdef check_icmp6_error(args, packet):
40619456bbSBjoern A. Zeeb	ip6 = packet.getlayer(sp.IPv6)
41619456bbSBjoern A. Zeeb	if not ip6:
42619456bbSBjoern A. Zeeb		return False
43619456bbSBjoern A. Zeeb	oip6 = sp.IPv6(src=args.src[0], dst=args.to[0])
44619456bbSBjoern A. Zeeb	if ip6.dst != oip6.src:
45619456bbSBjoern A. Zeeb		return False
46619456bbSBjoern A. Zeeb	icmp6 = packet.getlayer(sp.ICMPv6TimeExceeded)
47619456bbSBjoern A. Zeeb	if not icmp6:
48619456bbSBjoern A. Zeeb		return False
49619456bbSBjoern A. Zeeb	# ICMP6_TIME_EXCEED_REASSEMBLY 1
50619456bbSBjoern A. Zeeb	if icmp6.code != 1:
51619456bbSBjoern A. Zeeb		return False
52619456bbSBjoern A. Zeeb	# Should we check the payload as well?
53619456bbSBjoern A. Zeeb	# We are running in a very isolated environment and nothing else
54619456bbSBjoern A. Zeeb	# should trigger an ICMPv6 Time Exceeded / Frag reassembly so leave it.
55619456bbSBjoern A. Zeeb	#icmp6.display()
56619456bbSBjoern A. Zeeb	return True
57619456bbSBjoern A. Zeeb
58619456bbSBjoern A. Zeeb
59619456bbSBjoern A. Zeebdef main():
60619456bbSBjoern A. Zeeb	parser = argparse.ArgumentParser("frag6.py",
61619456bbSBjoern A. Zeeb		description="IPv6 fragementation test tool")
62619456bbSBjoern A. Zeeb	parser.add_argument('--sendif', nargs=1,
63619456bbSBjoern A. Zeeb		required=True,
64619456bbSBjoern A. Zeeb		help='The interface through which the packet will be sent')
65619456bbSBjoern A. Zeeb	parser.add_argument('--recvif', nargs=1,
66619456bbSBjoern A. Zeeb		required=True,
67619456bbSBjoern A. Zeeb		help='The interface on which to check for the packet')
68619456bbSBjoern A. Zeeb	parser.add_argument('--src', nargs=1,
69619456bbSBjoern A. Zeeb		required=True,
70619456bbSBjoern A. Zeeb		help='The source IP address')
71619456bbSBjoern A. Zeeb	parser.add_argument('--to', nargs=1,
72619456bbSBjoern A. Zeeb		required=True,
73619456bbSBjoern A. Zeeb		help='The destination IP address')
74619456bbSBjoern A. Zeeb	parser.add_argument('--debug',
75619456bbSBjoern A. Zeeb		required=False, action='store_true',
76619456bbSBjoern A. Zeeb		help='Enable test debugging')
77619456bbSBjoern A. Zeeb
78619456bbSBjoern A. Zeeb	args = parser.parse_args()
79619456bbSBjoern A. Zeeb
80619456bbSBjoern A. Zeeb
81619456bbSBjoern A. Zeeb	# Start sniffing on recvif
82619456bbSBjoern A. Zeeb	sniffer = Sniffer(args, check_icmp6_error)
83619456bbSBjoern A. Zeeb
84619456bbSBjoern A. Zeeb
85619456bbSBjoern A. Zeeb	########################################################################
86619456bbSBjoern A. Zeeb	#
87619456bbSBjoern A. Zeeb	# Send a proper first fragment (off=0) and a second fragment which
88619456bbSBjoern A. Zeeb	# just fits the 64k.  The re-send the first fragment with an extra
89619456bbSBjoern A. Zeeb	# unfragmentable part making the 64k to exceed the limit.
90619456bbSBjoern A. Zeeb	# This is to make sure we don't allow to update meta-data for a
91619456bbSBjoern A. Zeeb	# 1st fragmented packet should a second arrive but given the
92619456bbSBjoern A. Zeeb	# fragmentable part is an exact duplicate only that fragment
93619456bbSBjoern A. Zeeb	# will be silently discarded.
94619456bbSBjoern A. Zeeb	#
95619456bbSBjoern A. Zeeb	# A:  Reassembly failure, timeout after
96619456bbSBjoern A. Zeeb	# R:  ICMPv6 time exceeded / statistics for the duplicate
97619456bbSBjoern A. Zeeb	#
98619456bbSBjoern A. Zeeb	data = "6" * 8
99619456bbSBjoern A. Zeeb	ip6f00 = \
100619456bbSBjoern A. Zeeb		sp.Ether() / \
101619456bbSBjoern A. Zeeb		sp.IPv6(src=args.src[0], dst=args.to[0]) / \
102619456bbSBjoern A. Zeeb		sp.IPv6ExtHdrFragment(offset=0, m=1, id=20) / \
103619456bbSBjoern A. Zeeb		sp.UDP(dport=3456, sport=6543) / \
104619456bbSBjoern A. Zeeb		data
105619456bbSBjoern A. Zeeb	data = "6" * 15
106619456bbSBjoern A. Zeeb	ip6f01 = \
107619456bbSBjoern A. Zeeb		sp.Ether() / \
108619456bbSBjoern A. Zeeb		sp.IPv6(src=args.src[0], dst=args.to[0]) / \
109619456bbSBjoern A. Zeeb		sp.IPv6ExtHdrFragment(offset=0x1ffc, m=0, id=20) / \
110619456bbSBjoern A. Zeeb		sp.UDP(dport=3456, sport=6543) / \
111619456bbSBjoern A. Zeeb		data
112619456bbSBjoern A. Zeeb	data = "6" * 8
113619456bbSBjoern A. Zeeb	ip6f02 = \
114619456bbSBjoern A. Zeeb		sp.Ether() / \
115619456bbSBjoern A. Zeeb		sp.IPv6(src=args.src[0], dst=args.to[0]) / \
116619456bbSBjoern A. Zeeb		sp.IPv6ExtHdrDestOpt(options = \
117619456bbSBjoern A. Zeeb		    sp.PadN(optdata="\x00\x00\x00\x00\x00\x00")) / \
118619456bbSBjoern A. Zeeb		sp.IPv6ExtHdrFragment(offset=0, m=1, id=20) / \
119619456bbSBjoern A. Zeeb		sp.UDP(dport=3456, sport=6543) / \
120619456bbSBjoern A. Zeeb		data
121619456bbSBjoern A. Zeeb	if args.debug :
122619456bbSBjoern A. Zeeb		ip6f00.display()
123619456bbSBjoern A. Zeeb		ip6f01.display()
124619456bbSBjoern A. Zeeb		ip6f02.display()
125619456bbSBjoern A. Zeeb	sp.sendp(ip6f00, iface=args.sendif[0], verbose=False)
126619456bbSBjoern A. Zeeb	sp.sendp(ip6f01, iface=args.sendif[0], verbose=False)
127619456bbSBjoern A. Zeeb	sp.sendp(ip6f02, iface=args.sendif[0], verbose=False)
128619456bbSBjoern A. Zeeb
129*e32221a1SAlexander V. Chernikov	sleep(3)
130619456bbSBjoern A. Zeeb	sniffer.setEnd()
131619456bbSBjoern A. Zeeb	sniffer.join()
132619456bbSBjoern A. Zeeb	if not sniffer.foundCorrectPacket:
133619456bbSBjoern A. Zeeb		sys.exit(1)
134619456bbSBjoern A. Zeeb
135619456bbSBjoern A. Zeeb	sys.exit(0)
136619456bbSBjoern A. Zeeb
137619456bbSBjoern A. Zeebif __name__ == '__main__':
138619456bbSBjoern A. Zeeb	main()
139