xref: /freebsd/usr.sbin/traceroute/tests/traceroute_test.sh (revision 24e4dcf4ba5e9dedcf89efd358ea3e1fe5867020)
1# SPDX-License-Identifier: ISC
2#
3# Copyright (c) 2025 Lexi Winter
4#
5# Permission to use, copy, modify, and distribute this software for any
6# purpose with or without fee is hereby granted, provided that the above
7# copyright notice and this permission notice appear in all copies.
8#
9# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
17# We are missing tests for the following flags:
18#
19# -a (turn on ASN lookups)
20# -A (specify ASN lookup server)
21# -d (enable SO_DEBUG)
22# -D (print the diff between our packet and the quote in the ICMP error)
23# -E (detect ECN bleaching)
24# -n (or rather, we enable -n by default and don't test without it)
25# -S (print per-hop packet loss)
26# -v (verbose output)
27# -w (how long to wait for an error response)
28# -x (toggle IP checksums)
29# -z (how long to wait between each probe)
30
31. $(atf_get_srcdir)/../../sys/common/vnet.subr
32
33# These are the default flags we use for most test cases:
34# - only send a single probe packet to reduce the risk of kernel ICMP
35#   rate-limiting breaking the test.
36# - only trace up to 5 hops and only wait 1 second for a response so the test
37#   fails quicker if something goes wrong.
38# - disable DNS resolution as we don't usually care about this.
39TR_FLAGS="-w 1 -q 1 -m 5 -n"
40
41# The prefix our test networks are in.
42TEST_PREFIX="192.0.2.0/24"
43
44# The IPv4 addresses of the first link net between trsrc and trrtr.
45LINK_TRSRC_TRSRC="192.0.2.5"
46LINK_TRSRC_TRRTR="192.0.2.6"
47LINK_TRSRC_PREFIXLEN="30"
48
49# The IPv4 addresses of the second link net between trsrc and trrtr.
50LINK_TRSRC2_TRSRC="192.0.2.13"
51LINK_TRSRC2_TRRTR="192.0.2.14"
52LINK_TRSRC2_PREFIXLEN="30"
53
54# The IPv4 addresses of the link net between trdst and trrtr.
55LINK_TRDST_TRDST="192.0.2.9"
56LINK_TRDST_TRRTR="192.0.2.10"
57LINK_TRDST_PREFIXLEN="30"
58
59# This is an address inside $TEST_PREFIX which is not routed anywhere.
60UNREACHABLE_ADDR="192.0.2.255"
61
62setup_network()
63{
64	# Create 3 jails: one to be the source host, one to be the router,
65	# and one to be the destination host.
66
67	vnet_init
68
69	# src jail
70	epsrc=$(vnet_mkepair)
71	epsrc2=$(vnet_mkepair)
72	vnet_mkjail trsrc ${epsrc}a ${epsrc2}a
73
74	# dst jail
75	epdst=$(vnet_mkepair)
76	vnet_mkjail trdst ${epdst}a
77
78	# router jail
79	vnet_mkjail trrtr ${epsrc}b ${epsrc2}b ${epdst}b
80
81	# Configure IPv4 addresses and routes on each jail.
82
83	# trsrc
84	jexec trsrc ifconfig ${epsrc}a inet \
85	    ${LINK_TRSRC_TRSRC}/${LINK_TRSRC_PREFIXLEN}
86	jexec trrtr ifconfig ${epsrc}b inet \
87	    ${LINK_TRSRC_TRRTR}/${LINK_TRSRC_PREFIXLEN}
88	jexec trsrc route add -inet ${TEST_PREFIX} ${LINK_TRSRC_TRRTR}
89
90	# trsrc2
91	jexec trsrc ifconfig ${epsrc2}a inet \
92	    ${LINK_TRSRC2_TRSRC}/${LINK_TRSRC2_PREFIXLEN}
93	jexec trrtr ifconfig ${epsrc2}b inet \
94	    ${LINK_TRSRC2_TRRTR}/${LINK_TRSRC2_PREFIXLEN}
95
96	# trdst
97	jexec trdst ifconfig ${epdst}a inet \
98	    ${LINK_TRDST_TRDST}/${LINK_TRDST_PREFIXLEN}
99	jexec trrtr ifconfig ${epdst}b inet \
100	    ${LINK_TRDST_TRRTR}/${LINK_TRDST_PREFIXLEN}
101	jexec trdst route add -inet ${TEST_PREFIX} ${LINK_TRDST_TRRTR}
102
103	# The router jail (only) needs IP forwarding enabled.
104	jexec trrtr sysctl net.inet.ip.forwarding=1
105}
106
107##
108#
109# start_tcpdump, stop_tcpdump: used to capture packets during the test so we
110# can verify we actually sent the expected packets.
111
112start_tcpdump()
113{
114	# Run tcpdump on trrtr, either on the given interface or on
115	# ${epsrc}b, which is trsrc's default route interface.
116
117	interface="$1"
118	if [ -z "$interface" ]; then
119		interface="${epsrc}b"
120	fi
121
122	rm -f "${PWD}/traceroute.pcap"
123
124	jexec trrtr daemon -p "${PWD}/tcpdump.pid" \
125	    tcpdump --immediate-mode -w "${PWD}/traceroute.pcap" -nv \
126	    -i $interface
127
128	# Give tcpdump time to start
129	sleep 1
130}
131
132stop_tcpdump()
133{
134	# Sleep to give tcpdump a chance to finish flushing
135	jexec trrtr kill -USR2 $(cat "${PWD}/tcpdump.pid")
136	sleep 1
137	jexec trrtr kill $(cat "${PWD}/tcpdump.pid")
138
139	# Format the packet capture and merge continued lines (starting with
140	# whitespace) into a single line; this makes it easier to match in
141	# atf_check.  Append a blank line since the N command exits on EOF.
142	(tcpdump -nv -r "${PWD}/traceroute.pcap"; echo) | \
143	    sed -E -e :a -e N -e 's/\n +/ /' -e ta -e P -e D \
144	    > tcpdump.output
145}
146
147##
148# test: ipv4_basic
149#
150
151atf_test_case "ipv4_basic" "cleanup"
152ipv4_basic_head()
153{
154	atf_set descr "Basic IPv4 traceroute across a router"
155	atf_set require.user root
156}
157
158ipv4_basic_body()
159{
160	setup_network
161
162	# Use a more detailed set of regexp here than the rest of the tests to
163	# make sure the basic output format is correct.
164	atf_check -s exit:0					\
165	    -e match:"^traceroute to ${LINK_TRDST_TRDST} \\(${LINK_TRDST_TRDST}\\), 5 hops max, 40 byte packets$" \
166	    -o match:"^ 1  ${LINK_TRSRC_TRRTR}  [0-9.]+ ms$"	\
167	    -o match:"^ 2  ${LINK_TRDST_TRDST}  [0-9.]+ ms$"	\
168	    -o not-match:"^ 3"					\
169	    jexec trsrc traceroute $TR_FLAGS ${LINK_TRDST_TRDST}
170}
171
172ipv4_basic_cleanup()
173{
174	vnet_cleanup
175}
176
177##
178# test: ipv4_icmp
179#
180
181atf_test_case "ipv4_icmp" "cleanup"
182ipv4_icmp_head()
183{
184	atf_set descr "Basic IPv4 ICMP traceroute across a router"
185	atf_set require.user root
186}
187
188ipv4_icmp_body()
189{
190	setup_network
191
192	# -I and -Picmp should mean the same thing, so test both.
193
194	for icmp_flag in -Picmp -I; do
195		start_tcpdump
196
197		atf_check -s exit:0					\
198		    -e match:"^traceroute to ${LINK_TRDST_TRDST}"	\
199		    -o match:"^ 1  ${LINK_TRSRC_TRRTR}"			\
200		    -o match:"^ 2  ${LINK_TRDST_TRDST}"			\
201		    -o not-match:"^ 3"					\
202		    jexec trsrc traceroute $TR_FLAGS $icmp_flag		\
203		    ${LINK_TRDST_TRDST}
204
205		stop_tcpdump
206
207		atf_check -s exit:0 -e ignore 				\
208		    -o match:"IP \\(tos 0x0, ttl 1, .*, proto ICMP.*\\).* ${LINK_TRSRC_TRSRC} > ${LINK_TRDST_TRDST}: ICMP echo request" \
209		    -o match:"IP \\(tos 0x0, ttl 2, .*, proto ICMP.*\\).* ${LINK_TRSRC_TRSRC} > ${LINK_TRDST_TRDST}: ICMP echo request" \
210		    cat tcpdump.output
211	done
212}
213
214ipv4_icmp_cleanup()
215{
216	vnet_cleanup
217}
218
219##
220# test: ipv4_udp
221#
222
223atf_test_case "ipv4_udp" "cleanup"
224ipv4_udp_head()
225{
226	atf_set descr "IPv4 UDP traceroute"
227	atf_set require.user root
228}
229
230ipv4_udp_body()
231{
232	setup_network
233
234	start_tcpdump
235
236	atf_check -s exit:0					\
237	    -e match:"^traceroute to ${LINK_TRDST_TRDST}"	\
238	    -o match:"^ 1  ${LINK_TRSRC_TRRTR}"			\
239	    -o match:"^ 2  ${LINK_TRDST_TRDST}"			\
240	    -o not-match:"^ 3"					\
241	    jexec trsrc traceroute $TR_FLAGS -Pudp ${LINK_TRDST_TRDST}
242
243	stop_tcpdump
244
245	atf_check -s exit:0 -e ignore 				\
246	    -o match:"IP \\(tos 0x0, ttl 1, .*, proto UDP .*\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.33435: UDP" \
247	    -o match:"IP \\(tos 0x0, ttl 2, .*, proto UDP .*\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.33436: UDP" \
248	    cat tcpdump.output
249
250	# Test with -e, the destination port should not increment.
251
252	start_tcpdump
253
254	atf_check -s exit:0					\
255	    -e match:"^traceroute to ${LINK_TRDST_TRDST}"	\
256	    -o match:"^ 1  ${LINK_TRSRC_TRRTR}"			\
257	    -o match:"^ 2  ${LINK_TRDST_TRDST}"			\
258	    -o not-match:"^ 3"					\
259	    jexec trsrc traceroute $TR_FLAGS -Pudp -e -p 40000 ${LINK_TRDST_TRDST}
260
261	stop_tcpdump
262
263	atf_check -s exit:0 -e ignore 				\
264	    -o match:"IP \\(tos 0x0, ttl 1, .*, proto UDP .*\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.40000: UDP" \
265	    -o match:"IP \\(tos 0x0, ttl 2, .*, proto UDP .*\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.40000: UDP" \
266	    cat tcpdump.output
267}
268
269ipv4_udp_cleanup()
270{
271	vnet_cleanup
272}
273
274##
275# test: ipv4_sctp
276#
277
278atf_test_case "ipv4_sctp" "cleanup"
279ipv4_sctp_head()
280{
281	atf_set descr "IPv4 SCTP traceroute"
282	atf_set require.user root
283}
284
285ipv4_sctp_body()
286{
287	setup_network
288
289	# For the default packet size, we should sent a SHUTDOWN ACK packet.
290
291	start_tcpdump
292
293	atf_check -s exit:0					\
294	    -e match:"^traceroute to ${LINK_TRDST_TRDST}"	\
295	    -o match:"^ 1  ${LINK_TRSRC_TRRTR}"			\
296	    jexec trsrc traceroute $TR_FLAGS -Psctp ${LINK_TRDST_TRDST}
297
298	stop_tcpdump
299	atf_check -s exit:0 -e ignore 				\
300	    -o match:"IP \\(tos 0x0, ttl 1, .*, proto SCTP.*\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.33435: sctp \(1\) \[SHUTDOWN ACK\]" \
301	    -o match:"IP \\(tos 0x0, ttl 2, .*, proto SCTP.*\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.33436: sctp \(1\) \[SHUTDOWN ACK\]" \
302	    cat tcpdump.output
303
304	# For a larger packet size we should send INIT packets.
305
306	start_tcpdump
307
308	atf_check -s exit:0					\
309	    -e match:"^traceroute to ${LINK_TRDST_TRDST}"	\
310	    -o match:"^ 1  ${LINK_TRSRC_TRRTR}"			\
311	    jexec trsrc traceroute $TR_FLAGS -Psctp ${LINK_TRDST_TRDST} 128
312
313	stop_tcpdump
314	atf_check -s exit:0 -e ignore 				\
315	    -o match:"IP \\(tos 0x0, ttl 1, .*, proto SCTP.*\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.33435: sctp \(1\) \[INIT\]" \
316	    -o match:"IP \\(tos 0x0, ttl 2, .*, proto SCTP.*\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.33436: sctp \(1\) \[INIT\]" \
317	    cat tcpdump.output
318
319	# Test with -e, the destination port should not increment.
320
321	start_tcpdump
322
323	atf_check -s exit:0					\
324	    -e match:"^traceroute to ${LINK_TRDST_TRDST}"	\
325	    -o match:"^ 1  ${LINK_TRSRC_TRRTR}"			\
326	    jexec trsrc traceroute $TR_FLAGS -Psctp -e -p 40000 ${LINK_TRDST_TRDST}
327
328	stop_tcpdump
329	atf_check -s exit:0 -e ignore 				\
330	    -o match:"IP \\(tos 0x0, ttl 1, .*, proto SCTP.*\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.40000: sctp \(1\) \[SHUTDOWN ACK\]" \
331	    -o match:"IP \\(tos 0x0, ttl 2, .*, proto SCTP.*\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.40000: sctp \(1\) \[SHUTDOWN ACK\]" \
332	    cat tcpdump.output
333}
334
335ipv4_sctp_cleanup()
336{
337	vnet_cleanup
338}
339
340##
341# test: ipv4_tcp
342#
343
344atf_test_case "ipv4_tcp" "cleanup"
345ipv4_tcp_head()
346{
347	atf_set descr "IPv4 TCP traceroute"
348	atf_set require.user root
349}
350
351ipv4_tcp_body()
352{
353	setup_network
354
355	start_tcpdump
356
357	# We expect the second hop to be a failure since traceroute doesn't
358	# know how to capture the RST packet.
359	atf_check -s exit:0					\
360	    -e match:"^traceroute to ${LINK_TRDST_TRDST}"	\
361	    -o match:"^ 1  ${LINK_TRSRC_TRRTR}"			\
362	    -o match:"^ 2  \\*"					\
363	    jexec trsrc traceroute $TR_FLAGS -Ptcp ${LINK_TRDST_TRDST}
364
365	stop_tcpdump
366	atf_check -s exit:0 -e ignore 				\
367	    -o match:"IP \\(tos 0x0, ttl 1, .*, proto TCP.*\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.33435: Flags \[S\]" \
368	    -o match:"IP \\(tos 0x0, ttl 2, .*, proto TCP.*\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.33436: Flags \[S\]" \
369	    cat tcpdump.output
370
371	# Test with -e, the destination port should not increment.
372	start_tcpdump
373
374	atf_check -s exit:0					\
375	    -e match:"^traceroute to ${LINK_TRDST_TRDST}"	\
376	    -o match:"^ 1  ${LINK_TRSRC_TRRTR}"			\
377	    -o match:"^ 2  \\*"					\
378	    jexec trsrc traceroute $TR_FLAGS -Ptcp -e -p 40000 ${LINK_TRDST_TRDST}
379
380	stop_tcpdump
381	atf_check -s exit:0 -e ignore 				\
382	    -o match:"IP \\(tos 0x0, ttl 1, .*, proto TCP.*\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.40000: Flags \[S\]" \
383	    -o match:"IP \\(tos 0x0, ttl 2, .*, proto TCP.*\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.40000: Flags \[S\]" \
384	    cat tcpdump.output
385}
386
387ipv4_tcp_cleanup()
388{
389	vnet_cleanup
390}
391
392##
393# test: ipv4_srcaddr
394#
395
396atf_test_case "ipv4_srcaddr" "cleanup"
397ipv4_srcaddr_head()
398{
399	atf_set descr "IPv4 traceroute with explicit source address"
400	atf_set require.user root
401}
402
403ipv4_srcaddr_body()
404{
405	setup_network
406
407	start_tcpdump
408
409	atf_check -s exit:0				\
410	    -e match:"^traceroute to ${LINK_TRDST_TRDST} \\($LINK_TRDST_TRDST\\) from ${LINK_TRSRC2_TRSRC}" \
411	    -o match:"^ 1  ${LINK_TRSRC2_TRRTR}"	\
412	    -o match:"^ 2  ${LINK_TRDST_TRDST}"		\
413	    -o not-match:"^ 3"				\
414	    jexec trsrc traceroute $TR_FLAGS		\
415	        -s ${LINK_TRSRC2_TRSRC} ${LINK_TRDST_TRDST}
416
417	stop_tcpdump
418	atf_check -s exit:0 -e ignore 				\
419	    -o match:"IP \\(tos 0x0, ttl 1, .*, proto UDP.*\\).* ${LINK_TRSRC2_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.33435: UDP" \
420	    -o match:"IP \\(tos 0x0, ttl 2, .*, proto UDP.*\\).* ${LINK_TRSRC2_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.33436: UDP" \
421	    cat tcpdump.output
422}
423
424ipv4_srcaddr_cleanup()
425{
426	vnet_cleanup
427}
428
429##
430# test: ipv4_srcinterface
431#
432
433atf_test_case "ipv4_srcinterface" "cleanup"
434ipv4_srcinterface_head()
435{
436	atf_set descr "IPv4 traceroute with explicit source interface"
437	atf_set require.user root
438}
439
440ipv4_srcinterface_body()
441{
442	setup_network
443
444	start_tcpdump
445
446	# Unlike -s, traceroute doesn't print 'from ...' when using -i.
447	atf_check -s exit:0					\
448	    -e match:"^traceroute to ${LINK_TRDST_TRDST}"	\
449	    -o match:"^ 1  ${LINK_TRSRC2_TRRTR}"		\
450	    -o match:"^ 2  ${LINK_TRDST_TRDST}"			\
451	    -o not-match:"^ 3"					\
452	    jexec trsrc traceroute $TR_FLAGS			\
453	        -i ${epsrc2}a ${LINK_TRDST_TRDST}
454
455	stop_tcpdump
456	atf_check -s exit:0 -e ignore 				\
457	    -o match:"IP \\(tos 0x0, ttl 1, .*, proto UDP.*\\).* ${LINK_TRSRC2_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.33435: UDP" \
458	    -o match:"IP \\(tos 0x0, ttl 2, .*, proto UDP.*\\).* ${LINK_TRSRC2_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.33436: UDP" \
459	    cat tcpdump.output
460}
461
462ipv4_srcinterface_cleanup()
463{
464	vnet_cleanup
465}
466
467##
468# test: ipv4_maxhops
469#
470
471atf_test_case "ipv4_maxhops" "cleanup"
472ipv4_maxhops_head()
473{
474	atf_set descr "IPv4 traceroute with -m"
475	atf_set require.user root
476}
477
478ipv4_maxhops_body()
479{
480	setup_network
481
482	atf_check -s exit:0					\
483	    -e match:"^traceroute to ${LINK_TRDST_TRDST}"	\
484	    -o match:"^ 1  ${LINK_TRSRC_TRRTR}"			\
485	    -o not-match:"^ 2"					\
486	    jexec trsrc traceroute -w1 -q1 -m1 ${LINK_TRDST_TRDST}
487}
488
489ipv4_maxhops_cleanup()
490{
491	vnet_cleanup
492}
493
494##
495# test: ipv4_unreachable
496#
497
498atf_test_case "ipv4_unreachable" "cleanup"
499ipv4_unreachable_head()
500{
501	atf_set descr "IPv4 traceroute to an unreachable destination"
502	atf_set require.user root
503}
504
505ipv4_unreachable_body()
506{
507	setup_network
508
509	atf_check -s exit:0					\
510	    -e match:"^traceroute to ${UNREACHABLE_ADDR}"	\
511	    -o match:"^ 1  ${LINK_TRSRC_TRRTR}"			\
512	    -o match:"^ 2  ${LINK_TRSRC_TRRTR}  [0-9.]+ ms !H"	\
513	    -o not-match:"^ 3"					\
514	    jexec trsrc traceroute $TR_FLAGS $UNREACHABLE_ADDR
515}
516
517ipv4_unreachable_cleanup()
518{
519	vnet_cleanup
520}
521
522##
523# test: ipv4_hugepacket
524#
525
526atf_test_case "ipv4_hugepacket" "cleanup"
527ipv4_hugepacket_head()
528{
529	atf_set descr "IPv4 traceroute with a huge packet"
530	atf_set require.user root
531}
532
533ipv4_hugepacket_body()
534{
535	setup_network
536
537	# We expect this to fail since we specified -F (don't fragment) and the
538	# 2000-byte packet is too large to fit through our tiny epair.  Make
539	# sure traceroute reports the error.
540	atf_check -s exit:0					\
541	    -e match:"^traceroute to ${LINK_TRDST_TRDST} \\(${LINK_TRDST_TRDST}\\), 5 hops max, 2000 byte packets$" \
542	    -o match:"^ 1 traceroute: wrote ${LINK_TRDST_TRDST} 2000 chars, ret=-1" \
543	    -e match:"^traceroute: sendto: Message too long"	\
544	    jexec trsrc traceroute -F $TR_FLAGS ${LINK_TRDST_TRDST} 2000
545}
546
547ipv4_hugepacket_cleanup()
548{
549	vnet_cleanup
550}
551
552##
553# test: ipv4_firsthop
554#
555
556atf_test_case "ipv4_firsthop" "cleanup"
557ipv4_firsthop_head()
558{
559	atf_set descr "IPv4 traceroute with one hop skipped"
560	atf_set require.user root
561}
562
563ipv4_firsthop_body()
564{
565	setup_network
566
567	# -f 2 means we skip the first hop.  For backward compatibility, -M is
568	# the same as -f, so test that too.
569
570	for flag in -f2 -M2; do
571		start_tcpdump
572
573		atf_check -s exit:0					\
574		    -e match:"^traceroute to ${LINK_TRDST_TRDST}"	\
575		    -o not-match:"^ 1"					\
576		    -o match:"^ 2  ${LINK_TRDST_TRDST}"			\
577		    -o not-match:"^ 3"					\
578		    jexec trsrc traceroute $flag $TR_FLAGS ${LINK_TRDST_TRDST}
579
580		stop_tcpdump
581		atf_check -s exit:0 -e ignore 				\
582		    -o not-match:"^..:..:..\....... IP \\(tos 0x0, ttl 1, .*, proto UDP.*\\)" \
583		    -o match:"IP \\(tos 0x0, ttl 2, .*, proto UDP.*\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.33435: UDP" \
584		    cat tcpdump.output
585	done
586}
587
588ipv4_firsthop_cleanup()
589{
590	vnet_cleanup
591}
592
593##
594# test: ipv4_nprobes
595#
596
597atf_test_case "ipv4_nprobes" "cleanup"
598ipv4_nprobes_head()
599{
600	atf_set descr "IPv4 traceroute with varying number of probes"
601	atf_set require.user root
602}
603
604ipv4_nprobes_body()
605{
606	setup_network
607
608	# By default we should send 3 probes.
609	atf_check -s exit:0 -e ignore				\
610	    -o match:"^ 1  ${LINK_TRSRC_TRRTR} \(${LINK_TRSRC_TRRTR}\)(  [0-9.]+ ms){3}$" \
611	    jexec trsrc traceroute -w1 -m1 ${LINK_TRDST_TRDST}
612
613	# Also test 1 and 2 (below the default) and 5 (above the default)
614	for nprobes in 1 2 5; do
615		atf_check -s exit:0 -e ignore				\
616		    -o match:"^ 1  ${LINK_TRSRC_TRRTR} \(${LINK_TRSRC_TRRTR}\)(  [0-9.]+ ms){$nprobes}$" \
617		    jexec trsrc traceroute -q$nprobes -w1 -m1 ${LINK_TRDST_TRDST}
618	    done
619}
620
621ipv4_nprobes_cleanup()
622{
623	vnet_cleanup
624}
625
626##
627# test: ipv4_baseport
628#
629
630atf_test_case "ipv4_baseport" "cleanup"
631ipv4_baseport_head()
632{
633	atf_set descr "IPv4 traceroute with non-default base port"
634	atf_set require.user root
635}
636
637ipv4_baseport_body()
638{
639	setup_network
640
641	start_tcpdump
642
643	atf_check -s exit:0					\
644	    -e match:"^traceroute to ${LINK_TRDST_TRDST}"	\
645	    -o match:"^ 1  ${LINK_TRSRC_TRRTR}"			\
646	    -o match:"^ 2  ${LINK_TRDST_TRDST}"			\
647	    -o not-match:"^ 3"					\
648	    jexec trsrc traceroute $TR_FLAGS -p 40000		\
649	    ${LINK_TRDST_TRDST}
650
651	stop_tcpdump
652
653	atf_check -s exit:0 -e ignore 				\
654	    -o match:"IP \\(tos 0x0, ttl 1, .*, proto UDP.*\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.40001: UDP" \
655	    -o match:"IP \\(tos 0x0, ttl 2, .*, proto UDP.*\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.40002: UDP" \
656	    cat tcpdump.output
657}
658
659ipv4_baseport_cleanup()
660{
661	vnet_cleanup
662}
663
664##
665# test: ipv4_gre
666#
667
668atf_test_case "ipv4_gre" "cleanup"
669ipv4_gre_head()
670{
671	atf_set descr "IPv4 GRE traceroute"
672	atf_set require.user root
673}
674
675ipv4_gre_body()
676{
677	setup_network
678
679	start_tcpdump
680
681	# We expect the second hop to be a failure since the remote host will
682	# ignore the GRE packet.
683	atf_check -s exit:0					\
684	    -e match:"^traceroute to ${LINK_TRDST_TRDST}"	\
685	    -o match:"^ 1  ${LINK_TRSRC_TRRTR}"			\
686	    -o match:"^ 2  \\*"					\
687	    jexec trsrc traceroute $TR_FLAGS -Pgre ${LINK_TRDST_TRDST}
688
689	stop_tcpdump
690	atf_check -s exit:0 -e ignore 				\
691	    -o match:"IP \\(tos 0x0, ttl 1, .*, proto GRE .*\\).* ${LINK_TRSRC_TRSRC} > ${LINK_TRDST_TRDST}: GREv1" \
692	    -o match:"IP \\(tos 0x0, ttl 2, .*, proto GRE .*\\).* ${LINK_TRSRC_TRSRC} > ${LINK_TRDST_TRDST}: GREv1" \
693	    cat tcpdump.output
694}
695
696ipv4_gre_cleanup()
697{
698	vnet_cleanup
699}
700
701##
702# test: ipv4_udplite
703#
704
705atf_test_case "ipv4_udplite" "cleanup"
706ipv4_udplite_head()
707{
708	atf_set descr "IPv4 UDP-Lite traceroute"
709	atf_set require.user root
710}
711
712ipv4_udplite_body()
713{
714	setup_network
715
716	start_tcpdump
717
718	atf_check -s exit:0					\
719	    -e match:"^traceroute to ${LINK_TRDST_TRDST}"	\
720	    -o match:"^ 1  ${LINK_TRSRC_TRRTR}"			\
721	    -o match:"^ 2  ${LINK_TRDST_TRDST}"			\
722	    -o not-match:"^ 3"					\
723	    jexec trsrc traceroute $TR_FLAGS -Pudplite ${LINK_TRDST_TRDST}
724
725	stop_tcpdump
726	atf_check -s exit:0 -e ignore 				\
727	    -o match:"IP \\(tos 0x0, ttl 1, .*, proto unknown \(136\), .*\\).* ${LINK_TRSRC_TRSRC} > ${LINK_TRDST_TRDST}:  ip-proto-136" \
728	    -o match:"IP \\(tos 0x0, ttl 2, .*, proto unknown \(136\), .*\\).* ${LINK_TRSRC_TRSRC} > ${LINK_TRDST_TRDST}:  ip-proto-136" \
729	    cat tcpdump.output
730}
731
732ipv4_udplite_cleanup()
733{
734	vnet_cleanup
735}
736
737##
738# test: ipv4_iptos
739#
740
741atf_test_case "ipv4_iptos" "cleanup"
742ipv4_iptos_head()
743{
744	atf_set descr "IPv4 traceroute with explicit ToS"
745	atf_set require.user root
746}
747
748ipv4_iptos_body()
749{
750	setup_network
751
752	start_tcpdump
753
754	atf_check -s exit:0					\
755	    -e match:"^traceroute to ${LINK_TRDST_TRDST}"	\
756	    -o match:"^ 1  ${LINK_TRSRC_TRRTR}"			\
757	    -o match:"^ 2  ${LINK_TRDST_TRDST}"			\
758	    -o not-match:"^ 3"					\
759	    jexec trsrc traceroute $TR_FLAGS -t 4 ${LINK_TRDST_TRDST}
760
761	stop_tcpdump
762	atf_check -s exit:0 -e ignore 				\
763	    -o match:"IP \\(tos 0x4, ttl 1, .*, proto UDP .*\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.33435: UDP" \
764	    -o match:"IP \\(tos 0x4, ttl 2, .*, proto UDP .*\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRDST_TRDST}.33436: UDP" \
765	    cat tcpdump.output
766}
767
768ipv4_iptos_cleanup()
769{
770	vnet_cleanup
771}
772
773##
774# test: ipv4_srcroute
775#
776
777atf_test_case "ipv4_srcroute" "cleanup"
778ipv4_srcroute_head()
779{
780	atf_set descr "IPv4 traceroute with explicit source routing"
781	atf_set require.user root
782}
783
784ipv4_srcroute_body()
785{
786	setup_network
787	jexec trsrc sysctl net.inet.ip.sourceroute=1
788	jexec trsrc sysctl net.inet.ip.accept_sourceroute=1
789	jexec trrtr sysctl net.inet.ip.sourceroute=1
790
791	start_tcpdump
792
793	# As we don't enable source routing on trdst, we should get an ICMP
794	# source routing failed error (!S).
795	atf_check -s exit:0					\
796	    -e match:"^traceroute to ${LINK_TRDST_TRDST}"	\
797	    -o match:"^ 1  ${LINK_TRSRC_TRRTR}"			\
798	    -o match:"^ 2  ${LINK_TRDST_TRDST}  [0-9.]+ ms !S"	\
799	    -o not-match:"^ 3"					\
800	    jexec trsrc traceroute $TR_FLAGS			\
801	        -g ${LINK_TRSRC_TRRTR} ${LINK_TRDST_TRDST}
802
803	stop_tcpdump
804	atf_check -s exit:0 -e ignore 				\
805	    -o match:"IP \\(tos 0x0, ttl 1, .*, proto UDP .*, options \\(NOP,LSRR ${LINK_TRDST_TRDST}\\)\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRSRC_TRRTR}.33435: UDP" \
806	    -o match:"IP \\(tos 0x0, ttl 2, .*, proto UDP .*, options \\(NOP,LSRR ${LINK_TRDST_TRDST}\\)\\).* ${LINK_TRSRC_TRSRC}.[0-9]+ > ${LINK_TRSRC_TRRTR}.33436: UDP" \
807	    cat tcpdump.output
808}
809
810ipv4_srcroute_cleanup()
811{
812	vnet_cleanup
813}
814
815##
816# test: ipv4_dontroute
817#
818
819atf_test_case "ipv4_dontroute" "cleanup"
820ipv4_dontroute_head()
821{
822	atf_set descr "IPv4 traceroute with -r"
823	atf_set require.user root
824}
825
826ipv4_dontroute_body()
827{
828	setup_network
829
830	# This one should work as trrtr is directly connected.
831
832	atf_check -s exit:0					\
833	    -e match:"^traceroute to ${LINK_TRSRC_TRRTR}"	\
834	    -o match:"^ 1  ${LINK_TRSRC_TRRTR}  [0-9.]+ ms$"	\
835	    -o not-match:"^ 2"					\
836	    jexec trsrc traceroute -r $TR_FLAGS ${LINK_TRSRC_TRRTR}
837
838	# This one should fail.
839
840	atf_check -s exit:0					\
841	    -e match:"^traceroute to ${LINK_TRDST_TRDST}"	\
842	    -o match:"^ 1 traceroute: wrote ${LINK_TRDST_TRDST} 40 chars, ret=-1" \
843	    jexec trsrc traceroute -r $TR_FLAGS ${LINK_TRDST_TRDST}
844}
845
846ipv4_dontroute_cleanup()
847{
848	vnet_cleanup
849}
850
851##
852# test case declarations
853
854atf_init_test_cases()
855{
856	atf_add_test_case ipv4_basic
857	atf_add_test_case ipv4_udp
858	atf_add_test_case ipv4_icmp
859	atf_add_test_case ipv4_tcp
860	atf_add_test_case ipv4_sctp
861	atf_add_test_case ipv4_gre
862	atf_add_test_case ipv4_udplite
863	atf_add_test_case ipv4_srcaddr
864	atf_add_test_case ipv4_srcinterface
865	atf_add_test_case ipv4_maxhops
866	atf_add_test_case ipv4_unreachable
867	atf_add_test_case ipv4_hugepacket
868	atf_add_test_case ipv4_firsthop
869	atf_add_test_case ipv4_nprobes
870	atf_add_test_case ipv4_baseport
871	atf_add_test_case ipv4_iptos
872	atf_add_test_case ipv4_srcroute
873	atf_add_test_case ipv4_dontroute
874}
875