xref: /illumos-gate/usr/src/test/os-tests/tests/minttl/minttl.c (revision e82490700e19f1b8a2cef6102f4726144d281988)
1*e8249070SRobert Mustacchi /*
2*e8249070SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*e8249070SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*e8249070SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*e8249070SRobert Mustacchi  * 1.0 of the CDDL.
6*e8249070SRobert Mustacchi  *
7*e8249070SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*e8249070SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*e8249070SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*e8249070SRobert Mustacchi  */
11*e8249070SRobert Mustacchi 
12*e8249070SRobert Mustacchi /*
13*e8249070SRobert Mustacchi  * Copyright 2024 Oxide Computer Company
14*e8249070SRobert Mustacchi  */
15*e8249070SRobert Mustacchi 
16*e8249070SRobert Mustacchi /*
17*e8249070SRobert Mustacchi  * Basic set of tests for IP_MINTTL and IPV6_MINHOPCOUNT. The main design of
18*e8249070SRobert Mustacchi  * this is to spin up connections on localhost that walk through different
19*e8249070SRobert Mustacchi  * socket types and confirm that we can use the corresponding socket option and
20*e8249070SRobert Mustacchi  * that we receive traffic when the TTL is set and not otherwise.
21*e8249070SRobert Mustacchi  */
22*e8249070SRobert Mustacchi 
23*e8249070SRobert Mustacchi #include <err.h>
24*e8249070SRobert Mustacchi #include <port.h>
25*e8249070SRobert Mustacchi #include <stdlib.h>
26*e8249070SRobert Mustacchi #include <sys/types.h>
27*e8249070SRobert Mustacchi #include <sys/socket.h>
28*e8249070SRobert Mustacchi #include <netinet/in.h>
29*e8249070SRobert Mustacchi #include <netinet/sctp.h>
30*e8249070SRobert Mustacchi #include <arpa/inet.h>
31*e8249070SRobert Mustacchi #include <sys/sysmacros.h>
32*e8249070SRobert Mustacchi #include <stdbool.h>
33*e8249070SRobert Mustacchi #include <unistd.h>
34*e8249070SRobert Mustacchi #include <string.h>
35*e8249070SRobert Mustacchi #include <errno.h>
36*e8249070SRobert Mustacchi #include <sys/debug.h>
37*e8249070SRobert Mustacchi 
38*e8249070SRobert Mustacchi /*
39*e8249070SRobert Mustacchi  * The IP protocols 0xfd-0xfe are reserved for experiments. This is the safest
40*e8249070SRobert Mustacchi  * IP protocol for us to use then in our testing for raw sockets.
41*e8249070SRobert Mustacchi  */
42*e8249070SRobert Mustacchi #define	TTL_IPPROTO_EXP	0xfd
43*e8249070SRobert Mustacchi 
44*e8249070SRobert Mustacchi static hrtime_t tt_sock_to = MSEC2NSEC(100); /* ms in ns */
45*e8249070SRobert Mustacchi static const uint32_t tt_msg = 0x7777;
46*e8249070SRobert Mustacchi 
47*e8249070SRobert Mustacchi typedef enum {
48*e8249070SRobert Mustacchi 	TTL_SENDRECV,
49*e8249070SRobert Mustacchi 	TTL_NOCONNECT,
50*e8249070SRobert Mustacchi 	TTL_NODATA
51*e8249070SRobert Mustacchi } ttl_pass_t;
52*e8249070SRobert Mustacchi 
53*e8249070SRobert Mustacchi typedef struct {
54*e8249070SRobert Mustacchi 	const char *tt_desc;
55*e8249070SRobert Mustacchi 	int tt_domain;
56*e8249070SRobert Mustacchi 	int tt_type;
57*e8249070SRobert Mustacchi 	int tt_ttl;
58*e8249070SRobert Mustacchi 	int tt_proto;
59*e8249070SRobert Mustacchi 	int tt_minttl;
60*e8249070SRobert Mustacchi 	ttl_pass_t tt_pass;
61*e8249070SRobert Mustacchi } ttl_test_t;
62*e8249070SRobert Mustacchi 
63*e8249070SRobert Mustacchi static const ttl_test_t ttl_tests[] = {
64*e8249070SRobert Mustacchi 	{
65*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 TCP TTL/MIN: unset/0",
66*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
67*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
68*e8249070SRobert Mustacchi 		.tt_ttl = 0,
69*e8249070SRobert Mustacchi 		.tt_minttl = 0,
70*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
71*e8249070SRobert Mustacchi 	}, {
72*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 TCP TTL/MIN: 200/100",
73*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
74*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
75*e8249070SRobert Mustacchi 		.tt_ttl = 200,
76*e8249070SRobert Mustacchi 		.tt_minttl = 100,
77*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
78*e8249070SRobert Mustacchi 	}, {
79*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 TCP TTL/MIN: 255/255",
80*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
81*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
82*e8249070SRobert Mustacchi 		.tt_ttl = 255,
83*e8249070SRobert Mustacchi 		.tt_minttl = 255,
84*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
85*e8249070SRobert Mustacchi 	}, {
86*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 TCP TTL/MIN: 23/169",
87*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
88*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
89*e8249070SRobert Mustacchi 		.tt_ttl = 23,
90*e8249070SRobert Mustacchi 		.tt_minttl = 169,
91*e8249070SRobert Mustacchi 		.tt_pass = TTL_NOCONNECT
92*e8249070SRobert Mustacchi 	}, {
93*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 TCP TTL/MIN: 254/255",
94*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
95*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
96*e8249070SRobert Mustacchi 		.tt_ttl = 254,
97*e8249070SRobert Mustacchi 		.tt_minttl = 255,
98*e8249070SRobert Mustacchi 		.tt_pass = TTL_NOCONNECT
99*e8249070SRobert Mustacchi 	}, {
100*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 UDP TTL/MIN: unset/0",
101*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
102*e8249070SRobert Mustacchi 		.tt_type = SOCK_DGRAM,
103*e8249070SRobert Mustacchi 		.tt_ttl = 0,
104*e8249070SRobert Mustacchi 		.tt_minttl = 0,
105*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
106*e8249070SRobert Mustacchi 	}, {
107*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 UDP TTL/MIN: 200/100",
108*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
109*e8249070SRobert Mustacchi 		.tt_type = SOCK_DGRAM,
110*e8249070SRobert Mustacchi 		.tt_ttl = 200,
111*e8249070SRobert Mustacchi 		.tt_minttl = 100,
112*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
113*e8249070SRobert Mustacchi 	}, {
114*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 UDP TTL/MIN: 255/255",
115*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
116*e8249070SRobert Mustacchi 		.tt_type = SOCK_DGRAM,
117*e8249070SRobert Mustacchi 		.tt_ttl = 255,
118*e8249070SRobert Mustacchi 		.tt_minttl = 255,
119*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
120*e8249070SRobert Mustacchi 	}, {
121*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 UDP TTL/MIN: 23/169",
122*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
123*e8249070SRobert Mustacchi 		.tt_type = SOCK_DGRAM,
124*e8249070SRobert Mustacchi 		.tt_ttl = 23,
125*e8249070SRobert Mustacchi 		.tt_minttl = 169,
126*e8249070SRobert Mustacchi 		.tt_pass = TTL_NODATA
127*e8249070SRobert Mustacchi 	}, {
128*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 UDP TTL/MIN: 254/255",
129*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
130*e8249070SRobert Mustacchi 		.tt_type = SOCK_DGRAM,
131*e8249070SRobert Mustacchi 		.tt_ttl = 254,
132*e8249070SRobert Mustacchi 		.tt_minttl = 255,
133*e8249070SRobert Mustacchi 		.tt_pass = TTL_NODATA
134*e8249070SRobert Mustacchi 	}, {
135*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 SCTP TTL/MIN: unset/0",
136*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
137*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
138*e8249070SRobert Mustacchi 		.tt_proto = IPPROTO_SCTP,
139*e8249070SRobert Mustacchi 		.tt_ttl = 0,
140*e8249070SRobert Mustacchi 		.tt_minttl = 0,
141*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
142*e8249070SRobert Mustacchi 	}, {
143*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 SCTP TTL/MIN: 200/100",
144*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
145*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
146*e8249070SRobert Mustacchi 		.tt_proto = IPPROTO_SCTP,
147*e8249070SRobert Mustacchi 		.tt_ttl = 200,
148*e8249070SRobert Mustacchi 		.tt_minttl = 100,
149*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
150*e8249070SRobert Mustacchi 	}, {
151*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 SCTP TTL/MIN: 255/255",
152*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
153*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
154*e8249070SRobert Mustacchi 		.tt_proto = IPPROTO_SCTP,
155*e8249070SRobert Mustacchi 		.tt_ttl = 255,
156*e8249070SRobert Mustacchi 		.tt_minttl = 255,
157*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
158*e8249070SRobert Mustacchi 	}, {
159*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 SCTP TTL/MIN: 23/169",
160*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
161*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
162*e8249070SRobert Mustacchi 		.tt_proto = IPPROTO_SCTP,
163*e8249070SRobert Mustacchi 		.tt_ttl = 23,
164*e8249070SRobert Mustacchi 		.tt_minttl = 169,
165*e8249070SRobert Mustacchi 		.tt_pass = TTL_NOCONNECT
166*e8249070SRobert Mustacchi 	}, {
167*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 SCTP TTL/MIN: 254/255",
168*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
169*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
170*e8249070SRobert Mustacchi 		.tt_proto = IPPROTO_SCTP,
171*e8249070SRobert Mustacchi 		.tt_ttl = 254,
172*e8249070SRobert Mustacchi 		.tt_minttl = 255,
173*e8249070SRobert Mustacchi 		.tt_pass = TTL_NOCONNECT
174*e8249070SRobert Mustacchi 	}, {
175*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 RAW (0xfd) TTL/MIN: unset/0",
176*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
177*e8249070SRobert Mustacchi 		.tt_type = SOCK_RAW,
178*e8249070SRobert Mustacchi 		.tt_proto = TTL_IPPROTO_EXP,
179*e8249070SRobert Mustacchi 		.tt_ttl = 0,
180*e8249070SRobert Mustacchi 		.tt_minttl = 0,
181*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
182*e8249070SRobert Mustacchi 	}, {
183*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 RAW (0xfd) TTL/MIN: 200/100",
184*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
185*e8249070SRobert Mustacchi 		.tt_type = SOCK_RAW,
186*e8249070SRobert Mustacchi 		.tt_proto = TTL_IPPROTO_EXP,
187*e8249070SRobert Mustacchi 		.tt_ttl = 200,
188*e8249070SRobert Mustacchi 		.tt_minttl = 100,
189*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
190*e8249070SRobert Mustacchi 	}, {
191*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 RAW (0xfd) TTL/MIN: 255/255",
192*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
193*e8249070SRobert Mustacchi 		.tt_type = SOCK_RAW,
194*e8249070SRobert Mustacchi 		.tt_proto = TTL_IPPROTO_EXP,
195*e8249070SRobert Mustacchi 		.tt_ttl = 255,
196*e8249070SRobert Mustacchi 		.tt_minttl = 255,
197*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
198*e8249070SRobert Mustacchi 	}, {
199*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 RAW (0xfd) TTL/MIN: 23/169",
200*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
201*e8249070SRobert Mustacchi 		.tt_type = SOCK_RAW,
202*e8249070SRobert Mustacchi 		.tt_proto = TTL_IPPROTO_EXP,
203*e8249070SRobert Mustacchi 		.tt_ttl = 23,
204*e8249070SRobert Mustacchi 		.tt_minttl = 169,
205*e8249070SRobert Mustacchi 		.tt_pass = TTL_NODATA
206*e8249070SRobert Mustacchi 	}, {
207*e8249070SRobert Mustacchi 		.tt_desc = "IPv4 RAW (0xfd) TTL/MIN: 254/255",
208*e8249070SRobert Mustacchi 		.tt_domain = PF_INET,
209*e8249070SRobert Mustacchi 		.tt_type = SOCK_RAW,
210*e8249070SRobert Mustacchi 		.tt_proto = TTL_IPPROTO_EXP,
211*e8249070SRobert Mustacchi 		.tt_ttl = 254,
212*e8249070SRobert Mustacchi 		.tt_minttl = 255,
213*e8249070SRobert Mustacchi 		.tt_pass = TTL_NODATA
214*e8249070SRobert Mustacchi 	}, {
215*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 TCP TTL/MIN: unset/0",
216*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
217*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
218*e8249070SRobert Mustacchi 		.tt_ttl = 0,
219*e8249070SRobert Mustacchi 		.tt_minttl = 0,
220*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
221*e8249070SRobert Mustacchi 	}, {
222*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 TCP TTL/MIN: 200/100",
223*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
224*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
225*e8249070SRobert Mustacchi 		.tt_ttl = 200,
226*e8249070SRobert Mustacchi 		.tt_minttl = 100,
227*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
228*e8249070SRobert Mustacchi 	}, {
229*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 TCP TTL/MIN: 255/255",
230*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
231*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
232*e8249070SRobert Mustacchi 		.tt_ttl = 255,
233*e8249070SRobert Mustacchi 		.tt_minttl = 255,
234*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
235*e8249070SRobert Mustacchi 	}, {
236*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 CTP TTL/MIN: 23/169",
237*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
238*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
239*e8249070SRobert Mustacchi 		.tt_ttl = 23,
240*e8249070SRobert Mustacchi 		.tt_minttl = 169,
241*e8249070SRobert Mustacchi 		.tt_pass = TTL_NOCONNECT
242*e8249070SRobert Mustacchi 	}, {
243*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 CTP TTL/MIN: 254/255",
244*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
245*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
246*e8249070SRobert Mustacchi 		.tt_ttl = 254,
247*e8249070SRobert Mustacchi 		.tt_minttl = 255,
248*e8249070SRobert Mustacchi 		.tt_pass = TTL_NOCONNECT
249*e8249070SRobert Mustacchi 	}, {
250*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 UDP TTL/MIN: unset/0",
251*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
252*e8249070SRobert Mustacchi 		.tt_type = SOCK_DGRAM,
253*e8249070SRobert Mustacchi 		.tt_ttl = 0,
254*e8249070SRobert Mustacchi 		.tt_minttl = 0,
255*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
256*e8249070SRobert Mustacchi 	}, {
257*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 UDP TTL/MIN: 200/100",
258*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
259*e8249070SRobert Mustacchi 		.tt_type = SOCK_DGRAM,
260*e8249070SRobert Mustacchi 		.tt_ttl = 200,
261*e8249070SRobert Mustacchi 		.tt_minttl = 100,
262*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
263*e8249070SRobert Mustacchi 	}, {
264*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 UDP TTL/MIN: 255/255",
265*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
266*e8249070SRobert Mustacchi 		.tt_type = SOCK_DGRAM,
267*e8249070SRobert Mustacchi 		.tt_ttl = 255,
268*e8249070SRobert Mustacchi 		.tt_minttl = 255,
269*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
270*e8249070SRobert Mustacchi 	}, {
271*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 UDP TTL/MIN: 23/169",
272*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
273*e8249070SRobert Mustacchi 		.tt_type = SOCK_DGRAM,
274*e8249070SRobert Mustacchi 		.tt_ttl = 23,
275*e8249070SRobert Mustacchi 		.tt_minttl = 169,
276*e8249070SRobert Mustacchi 		.tt_pass = TTL_NODATA
277*e8249070SRobert Mustacchi 	}, {
278*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 UDP TTL/MIN: 254/255",
279*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
280*e8249070SRobert Mustacchi 		.tt_type = SOCK_DGRAM,
281*e8249070SRobert Mustacchi 		.tt_ttl = 254,
282*e8249070SRobert Mustacchi 		.tt_minttl = 255,
283*e8249070SRobert Mustacchi 		.tt_pass = TTL_NODATA
284*e8249070SRobert Mustacchi 	}, {
285*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 SCTP TTL/MIN: unset/0",
286*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
287*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
288*e8249070SRobert Mustacchi 		.tt_proto = IPPROTO_SCTP,
289*e8249070SRobert Mustacchi 		.tt_ttl = 0,
290*e8249070SRobert Mustacchi 		.tt_minttl = 0,
291*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
292*e8249070SRobert Mustacchi 	}, {
293*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 SCTP TTL/MIN: 200/100",
294*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
295*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
296*e8249070SRobert Mustacchi 		.tt_proto = IPPROTO_SCTP,
297*e8249070SRobert Mustacchi 		.tt_ttl = 200,
298*e8249070SRobert Mustacchi 		.tt_minttl = 100,
299*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
300*e8249070SRobert Mustacchi 	}, {
301*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 SCTP TTL/MIN: 255/255",
302*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
303*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
304*e8249070SRobert Mustacchi 		.tt_proto = IPPROTO_SCTP,
305*e8249070SRobert Mustacchi 		.tt_ttl = 255,
306*e8249070SRobert Mustacchi 		.tt_minttl = 255,
307*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
308*e8249070SRobert Mustacchi 	}, {
309*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 SCTP TTL/MIN: 23/169",
310*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
311*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
312*e8249070SRobert Mustacchi 		.tt_proto = IPPROTO_SCTP,
313*e8249070SRobert Mustacchi 		.tt_ttl = 23,
314*e8249070SRobert Mustacchi 		.tt_minttl = 169,
315*e8249070SRobert Mustacchi 		.tt_pass = TTL_NOCONNECT
316*e8249070SRobert Mustacchi 	}, {
317*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 SCTP TTL/MIN: 254/255",
318*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
319*e8249070SRobert Mustacchi 		.tt_type = SOCK_STREAM,
320*e8249070SRobert Mustacchi 		.tt_proto = IPPROTO_SCTP,
321*e8249070SRobert Mustacchi 		.tt_ttl = 254,
322*e8249070SRobert Mustacchi 		.tt_minttl = 255,
323*e8249070SRobert Mustacchi 		.tt_pass = TTL_NOCONNECT
324*e8249070SRobert Mustacchi 	}, {
325*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 RAW (0xfd) TTL/MIN: unset/0",
326*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
327*e8249070SRobert Mustacchi 		.tt_type = SOCK_RAW,
328*e8249070SRobert Mustacchi 		.tt_proto = TTL_IPPROTO_EXP,
329*e8249070SRobert Mustacchi 		.tt_ttl = 0,
330*e8249070SRobert Mustacchi 		.tt_minttl = 0,
331*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
332*e8249070SRobert Mustacchi 	}, {
333*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 RAW (0xfd) TTL/MIN: 200/100",
334*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
335*e8249070SRobert Mustacchi 		.tt_type = SOCK_RAW,
336*e8249070SRobert Mustacchi 		.tt_proto = TTL_IPPROTO_EXP,
337*e8249070SRobert Mustacchi 		.tt_ttl = 200,
338*e8249070SRobert Mustacchi 		.tt_minttl = 100,
339*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
340*e8249070SRobert Mustacchi 	}, {
341*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 RAW (0xfd) TTL/MIN: 255/255",
342*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
343*e8249070SRobert Mustacchi 		.tt_type = SOCK_RAW,
344*e8249070SRobert Mustacchi 		.tt_proto = TTL_IPPROTO_EXP,
345*e8249070SRobert Mustacchi 		.tt_ttl = 255,
346*e8249070SRobert Mustacchi 		.tt_minttl = 255,
347*e8249070SRobert Mustacchi 		.tt_pass = TTL_SENDRECV
348*e8249070SRobert Mustacchi 	}, {
349*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 RAW (0xfd) TTL/MIN: 23/169",
350*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
351*e8249070SRobert Mustacchi 		.tt_type = SOCK_RAW,
352*e8249070SRobert Mustacchi 		.tt_proto = TTL_IPPROTO_EXP,
353*e8249070SRobert Mustacchi 		.tt_ttl = 23,
354*e8249070SRobert Mustacchi 		.tt_minttl = 169,
355*e8249070SRobert Mustacchi 		.tt_pass = TTL_NODATA
356*e8249070SRobert Mustacchi 	}, {
357*e8249070SRobert Mustacchi 		.tt_desc = "IPv6 RAW (0xfd) TTL/MIN: 254/255",
358*e8249070SRobert Mustacchi 		.tt_domain = PF_INET6,
359*e8249070SRobert Mustacchi 		.tt_type = SOCK_RAW,
360*e8249070SRobert Mustacchi 		.tt_proto = TTL_IPPROTO_EXP,
361*e8249070SRobert Mustacchi 		.tt_ttl = 254,
362*e8249070SRobert Mustacchi 		.tt_minttl = 255,
363*e8249070SRobert Mustacchi 		.tt_pass = TTL_NODATA
364*e8249070SRobert Mustacchi 	}
365*e8249070SRobert Mustacchi };
366*e8249070SRobert Mustacchi 
367*e8249070SRobert Mustacchi static bool
ttl_bind_dest(const ttl_test_t * test,int sock,struct sockaddr_storage * dst)368*e8249070SRobert Mustacchi ttl_bind_dest(const ttl_test_t *test, int sock, struct sockaddr_storage *dst)
369*e8249070SRobert Mustacchi {
370*e8249070SRobert Mustacchi 	socklen_t len;
371*e8249070SRobert Mustacchi 	struct sockaddr_storage addr;
372*e8249070SRobert Mustacchi 
373*e8249070SRobert Mustacchi 	(void) memset(&addr, 0, sizeof (struct sockaddr_storage));
374*e8249070SRobert Mustacchi 
375*e8249070SRobert Mustacchi 	if (test->tt_domain == PF_INET) {
376*e8249070SRobert Mustacchi 		struct sockaddr_in *in = (struct sockaddr_in *)&addr;
377*e8249070SRobert Mustacchi 		in->sin_family = AF_INET;
378*e8249070SRobert Mustacchi 		in->sin_port = htons(0);
379*e8249070SRobert Mustacchi 		if (inet_pton(AF_INET, "127.0.0.1", &in->sin_addr) != 1) {
380*e8249070SRobert Mustacchi 			warnx("TEST FAILED: %s: failed to convert 127.0.0.1 "
381*e8249070SRobert Mustacchi 			    "to an IPv4 address", test->tt_desc);
382*e8249070SRobert Mustacchi 			return (false);
383*e8249070SRobert Mustacchi 		}
384*e8249070SRobert Mustacchi 		len = sizeof (struct sockaddr_in);
385*e8249070SRobert Mustacchi 	} else {
386*e8249070SRobert Mustacchi 		struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr;
387*e8249070SRobert Mustacchi 		in6->sin6_family = AF_INET6;
388*e8249070SRobert Mustacchi 		in6->sin6_port = htons(0);
389*e8249070SRobert Mustacchi 		if (inet_pton(AF_INET6, "::1", &in6->sin6_addr) != 1) {
390*e8249070SRobert Mustacchi 			warnx("TEST FAILED: %s: failed to convert ::1 "
391*e8249070SRobert Mustacchi 			    "to an IPv6 address", test->tt_desc);
392*e8249070SRobert Mustacchi 			return (false);
393*e8249070SRobert Mustacchi 		}
394*e8249070SRobert Mustacchi 		len = sizeof (struct sockaddr_in6);
395*e8249070SRobert Mustacchi 	}
396*e8249070SRobert Mustacchi 
397*e8249070SRobert Mustacchi 	if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
398*e8249070SRobert Mustacchi 		warn("TEST FAILED: %s: failed to bind listen socket",
399*e8249070SRobert Mustacchi 		    test->tt_desc);
400*e8249070SRobert Mustacchi 		return (false);
401*e8249070SRobert Mustacchi 	}
402*e8249070SRobert Mustacchi 
403*e8249070SRobert Mustacchi 	len = sizeof (struct sockaddr_storage);
404*e8249070SRobert Mustacchi 	if (getsockname(sock, (struct sockaddr *)dst, &len) != 0) {
405*e8249070SRobert Mustacchi 		warn("TEST FAILED: %s: failed to retrieve socket address ",
406*e8249070SRobert Mustacchi 		    test->tt_desc);
407*e8249070SRobert Mustacchi 		return (false);
408*e8249070SRobert Mustacchi 	}
409*e8249070SRobert Mustacchi 
410*e8249070SRobert Mustacchi 	return (true);
411*e8249070SRobert Mustacchi }
412*e8249070SRobert Mustacchi 
413*e8249070SRobert Mustacchi /*
414*e8249070SRobert Mustacchi  * Our job is to attempt to connect to the other end with our current settings.
415*e8249070SRobert Mustacchi  * This may not work, so we use our port to get things ready just in case.
416*e8249070SRobert Mustacchi  */
417*e8249070SRobert Mustacchi static bool
ttl_connect(const ttl_test_t * test,int port,int src,int dst,int * cfd,const struct sockaddr * addr)418*e8249070SRobert Mustacchi ttl_connect(const ttl_test_t *test, int port, int src, int dst, int *cfd,
419*e8249070SRobert Mustacchi     const struct sockaddr *addr)
420*e8249070SRobert Mustacchi {
421*e8249070SRobert Mustacchi 	struct timespec to = { .tv_nsec = tt_sock_to };
422*e8249070SRobert Mustacchi 	int namelen = test->tt_domain == PF_INET ? sizeof (struct sockaddr_in) :
423*e8249070SRobert Mustacchi 	    sizeof (struct sockaddr_in6);
424*e8249070SRobert Mustacchi 	int conn;
425*e8249070SRobert Mustacchi 	port_event_t pe;
426*e8249070SRobert Mustacchi 
427*e8249070SRobert Mustacchi 	if (listen(dst, 5) != 0) {
428*e8249070SRobert Mustacchi 		warn("TEST FAILED: %s: failed to listen", test->tt_desc);
429*e8249070SRobert Mustacchi 		return (false);
430*e8249070SRobert Mustacchi 	}
431*e8249070SRobert Mustacchi 
432*e8249070SRobert Mustacchi 	if (connect(src, addr, namelen) != 0 && errno != EINPROGRESS) {
433*e8249070SRobert Mustacchi 		warn("TEST FAILED: %s: failed to connect", test->tt_desc);
434*e8249070SRobert Mustacchi 		return (false);
435*e8249070SRobert Mustacchi 	}
436*e8249070SRobert Mustacchi 
437*e8249070SRobert Mustacchi 	if (port_associate(port, PORT_SOURCE_FD, src, POLLOUT, NULL) != 0) {
438*e8249070SRobert Mustacchi 		err(EXIT_FAILURE, "INTERNAL TEST FAILURE: %s: could not port "
439*e8249070SRobert Mustacchi 		    "associate to watch connect", test->tt_desc);
440*e8249070SRobert Mustacchi 	}
441*e8249070SRobert Mustacchi 
442*e8249070SRobert Mustacchi 	if (port_get(port, &pe, &to) != 0) {
443*e8249070SRobert Mustacchi 		if (test->tt_pass == TTL_NOCONNECT) {
444*e8249070SRobert Mustacchi 			(void) printf("TEST PASSED: %s: correctly failed to "
445*e8249070SRobert Mustacchi 			    "connect\n", test->tt_desc);
446*e8249070SRobert Mustacchi 			return (true);
447*e8249070SRobert Mustacchi 		} else {
448*e8249070SRobert Mustacchi 			warn("TEST FAILED: %s: timed out waiting to connect",
449*e8249070SRobert Mustacchi 			    test->tt_desc);
450*e8249070SRobert Mustacchi 			return (false);
451*e8249070SRobert Mustacchi 		}
452*e8249070SRobert Mustacchi 	}
453*e8249070SRobert Mustacchi 
454*e8249070SRobert Mustacchi 	if ((pe.portev_events & POLLOUT) == 0) {
455*e8249070SRobert Mustacchi 		warnx("TEST FAILED: %s: connect port event doesn't contain "
456*e8249070SRobert Mustacchi 		    "POLLOUT, found 0x%x", test->tt_desc, pe.portev_events);
457*e8249070SRobert Mustacchi 		return (false);
458*e8249070SRobert Mustacchi 	}
459*e8249070SRobert Mustacchi 
460*e8249070SRobert Mustacchi 	/*
461*e8249070SRobert Mustacchi 	 * Now make sure the listen socket is ready.
462*e8249070SRobert Mustacchi 	 */
463*e8249070SRobert Mustacchi 	if (port_associate(port, PORT_SOURCE_FD, dst, POLLIN, NULL) != 0) {
464*e8249070SRobert Mustacchi 		err(EXIT_FAILURE, "INTERNAL TEST FAILURE: %s: could not port "
465*e8249070SRobert Mustacchi 		    "associate to watch accept", test->tt_desc);
466*e8249070SRobert Mustacchi 	}
467*e8249070SRobert Mustacchi 
468*e8249070SRobert Mustacchi 	if (port_get(port, &pe, &to) != 0) {
469*e8249070SRobert Mustacchi 		warn("TEST FAILED: %s: timed out waiting to accept",
470*e8249070SRobert Mustacchi 		    test->tt_desc);
471*e8249070SRobert Mustacchi 		return (false);
472*e8249070SRobert Mustacchi 	}
473*e8249070SRobert Mustacchi 
474*e8249070SRobert Mustacchi 	if ((pe.portev_events & POLLIN) == 0) {
475*e8249070SRobert Mustacchi 		warnx("TEST FAILED: %s: accept port event doesn't contain "
476*e8249070SRobert Mustacchi 		    "POLLIN, found 0x%x", test->tt_desc, pe.portev_events);
477*e8249070SRobert Mustacchi 		return (false);
478*e8249070SRobert Mustacchi 	}
479*e8249070SRobert Mustacchi 
480*e8249070SRobert Mustacchi 	conn = accept4(dst, NULL, NULL, SOCK_NONBLOCK);
481*e8249070SRobert Mustacchi 	if (conn < 0) {
482*e8249070SRobert Mustacchi 		warn("TEST FAILED: %s: failed to get client connection",
483*e8249070SRobert Mustacchi 		    test->tt_desc);
484*e8249070SRobert Mustacchi 		return (false);
485*e8249070SRobert Mustacchi 	}
486*e8249070SRobert Mustacchi 
487*e8249070SRobert Mustacchi 	if (test->tt_pass != TTL_SENDRECV) {
488*e8249070SRobert Mustacchi 		warnx("TEST FAILED: %s: expected connect to fail, but passed",
489*e8249070SRobert Mustacchi 		    test->tt_desc);
490*e8249070SRobert Mustacchi 		return (false);
491*e8249070SRobert Mustacchi 	}
492*e8249070SRobert Mustacchi 
493*e8249070SRobert Mustacchi 	*cfd = conn;
494*e8249070SRobert Mustacchi 	return (true);
495*e8249070SRobert Mustacchi }
496*e8249070SRobert Mustacchi 
497*e8249070SRobert Mustacchi static bool
ttl_check_ancil(const ttl_test_t * test,const struct msghdr * msg)498*e8249070SRobert Mustacchi ttl_check_ancil(const ttl_test_t *test, const struct msghdr *msg)
499*e8249070SRobert Mustacchi {
500*e8249070SRobert Mustacchi 	int level, ttlopt;
501*e8249070SRobert Mustacchi 
502*e8249070SRobert Mustacchi 	if (test->tt_domain == PF_INET) {
503*e8249070SRobert Mustacchi 		level = IPPROTO_IP;
504*e8249070SRobert Mustacchi 		ttlopt = IP_RECVTTL;
505*e8249070SRobert Mustacchi 	} else {
506*e8249070SRobert Mustacchi 		level = IPPROTO_IPV6;
507*e8249070SRobert Mustacchi 		ttlopt = IPV6_HOPLIMIT;
508*e8249070SRobert Mustacchi 	}
509*e8249070SRobert Mustacchi 
510*e8249070SRobert Mustacchi 	if (msg->msg_controllen != CMSG_SPACE(sizeof (int))) {
511*e8249070SRobert Mustacchi 		warnx("TEST FAILED: %s: expected %u bytes of ancillary "
512*e8249070SRobert Mustacchi 		    "data, found %u", test->tt_desc, CMSG_SPACE(sizeof (int)),
513*e8249070SRobert Mustacchi 		    msg->msg_controllen);
514*e8249070SRobert Mustacchi 		return (false);
515*e8249070SRobert Mustacchi 	}
516*e8249070SRobert Mustacchi 
517*e8249070SRobert Mustacchi 	for (const struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
518*e8249070SRobert Mustacchi 	    cmsg = CMSG_NXTHDR(msg, cmsg)) {
519*e8249070SRobert Mustacchi 		int val;
520*e8249070SRobert Mustacchi 
521*e8249070SRobert Mustacchi 		if (cmsg->cmsg_level != level || cmsg->cmsg_type != ttlopt)
522*e8249070SRobert Mustacchi 			continue;
523*e8249070SRobert Mustacchi 		(void) memcpy(&val, CMSG_DATA(cmsg), sizeof (int));
524*e8249070SRobert Mustacchi 		if (test->tt_ttl != 0 && val != test->tt_ttl) {
525*e8249070SRobert Mustacchi 			warnx("TEST FAILED: %s: TTL/HLIM mismatch: expected "
526*e8249070SRobert Mustacchi 			    "0x%x, found 0x%x", test->tt_desc, test->tt_ttl,
527*e8249070SRobert Mustacchi 			    val);
528*e8249070SRobert Mustacchi 			return (false);
529*e8249070SRobert Mustacchi 		}
530*e8249070SRobert Mustacchi 
531*e8249070SRobert Mustacchi 		(void) printf("TEST PASSED: %s: TTL/HLIM is correct\n",
532*e8249070SRobert Mustacchi 		    test->tt_desc);
533*e8249070SRobert Mustacchi 		return (true);
534*e8249070SRobert Mustacchi 	}
535*e8249070SRobert Mustacchi 
536*e8249070SRobert Mustacchi 	warnx("TEST FAILED: %s: failed to find TTL/HLIM in ancillary options",
537*e8249070SRobert Mustacchi 	    test->tt_desc);
538*e8249070SRobert Mustacchi 	return (false);
539*e8249070SRobert Mustacchi }
540*e8249070SRobert Mustacchi 
541*e8249070SRobert Mustacchi /*
542*e8249070SRobert Mustacchi  * Attempt to send data with the TTLs set up appropriately. This might fail,
543*e8249070SRobert Mustacchi  * hence our port_associate dance and unfortunately regrettable timeout.
544*e8249070SRobert Mustacchi  */
545*e8249070SRobert Mustacchi static bool
ttl_sendrecv(const ttl_test_t * test,int port,int src,int dst,struct sockaddr * addr)546*e8249070SRobert Mustacchi ttl_sendrecv(const ttl_test_t *test, int port, int src, int dst,
547*e8249070SRobert Mustacchi     struct sockaddr *addr)
548*e8249070SRobert Mustacchi {
549*e8249070SRobert Mustacchi 	struct timespec to = { .tv_nsec = tt_sock_to };
550*e8249070SRobert Mustacchi 	int namelen = test->tt_domain == PF_INET ? sizeof (struct sockaddr_in) :
551*e8249070SRobert Mustacchi 	    sizeof (struct sockaddr_in6);
552*e8249070SRobert Mustacchi 	uint8_t ancil[CMSG_SPACE(sizeof (int)) * 2];
553*e8249070SRobert Mustacchi 	port_event_t pe;
554*e8249070SRobert Mustacchi 	struct msghdr msg;
555*e8249070SRobert Mustacchi 	uint32_t data;
556*e8249070SRobert Mustacchi 	struct iovec iov;
557*e8249070SRobert Mustacchi 	ssize_t sret;
558*e8249070SRobert Mustacchi 
559*e8249070SRobert Mustacchi 	if (sendto(src, &tt_msg, sizeof (tt_msg), MSG_NOSIGNAL, addr,
560*e8249070SRobert Mustacchi 	    namelen) != sizeof (tt_msg)) {
561*e8249070SRobert Mustacchi 		warn("TEST FAILED: %s: failed to write message to socket",
562*e8249070SRobert Mustacchi 		    test->tt_desc);
563*e8249070SRobert Mustacchi 	}
564*e8249070SRobert Mustacchi 
565*e8249070SRobert Mustacchi 	if (port_associate(port, PORT_SOURCE_FD, dst, POLLIN, NULL) != 0) {
566*e8249070SRobert Mustacchi 		err(EXIT_FAILURE, "INTERNAL TEST FAILURE: %s: could not port "
567*e8249070SRobert Mustacchi 		    "associate to watch recv", test->tt_desc);
568*e8249070SRobert Mustacchi 	}
569*e8249070SRobert Mustacchi 
570*e8249070SRobert Mustacchi 	if (port_get(port, &pe, &to) != 0) {
571*e8249070SRobert Mustacchi 		if (test->tt_pass == TTL_NODATA) {
572*e8249070SRobert Mustacchi 			(void) printf("TEST PASSED: %s: timed out waiting "
573*e8249070SRobert Mustacchi 			    "for data\n", test->tt_desc);
574*e8249070SRobert Mustacchi 			return (true);
575*e8249070SRobert Mustacchi 		} else {
576*e8249070SRobert Mustacchi 			warn("TEST FAILED: %s: timed out waiting to recv",
577*e8249070SRobert Mustacchi 			    test->tt_desc);
578*e8249070SRobert Mustacchi 			return (false);
579*e8249070SRobert Mustacchi 		}
580*e8249070SRobert Mustacchi 	}
581*e8249070SRobert Mustacchi 
582*e8249070SRobert Mustacchi 	if ((pe.portev_events & POLLIN) == 0) {
583*e8249070SRobert Mustacchi 		warnx("TEST FAILED: %s: receive port event doesn't contain "
584*e8249070SRobert Mustacchi 		    "POLLIN, found 0x%x", test->tt_desc, pe.portev_events);
585*e8249070SRobert Mustacchi 		return (false);
586*e8249070SRobert Mustacchi 	}
587*e8249070SRobert Mustacchi 
588*e8249070SRobert Mustacchi 	(void) memset(&msg, 0, sizeof (msg));
589*e8249070SRobert Mustacchi 	iov.iov_base = (void *)&data;
590*e8249070SRobert Mustacchi 	iov.iov_len = sizeof (data);
591*e8249070SRobert Mustacchi 	msg.msg_iov = &iov;
592*e8249070SRobert Mustacchi 	msg.msg_iovlen = 1;
593*e8249070SRobert Mustacchi 	msg.msg_control = ancil;
594*e8249070SRobert Mustacchi 	msg.msg_controllen = sizeof (ancil);
595*e8249070SRobert Mustacchi 
596*e8249070SRobert Mustacchi 	sret = recvmsg(dst, &msg, MSG_DONTWAIT);
597*e8249070SRobert Mustacchi 	if (sret != (ssize_t)sizeof (data)) {
598*e8249070SRobert Mustacchi 		warnx("TEST FAILED: %s: failed to receive data: %zx",
599*e8249070SRobert Mustacchi 		    test->tt_desc, sret);
600*e8249070SRobert Mustacchi 		return (false);
601*e8249070SRobert Mustacchi 	}
602*e8249070SRobert Mustacchi 
603*e8249070SRobert Mustacchi 	if (test->tt_pass != TTL_SENDRECV) {
604*e8249070SRobert Mustacchi 		warnx("TEST FAILED: %s: found data, despite expecting not to",
605*e8249070SRobert Mustacchi 		    test->tt_desc);
606*e8249070SRobert Mustacchi 		return (false);
607*e8249070SRobert Mustacchi 	}
608*e8249070SRobert Mustacchi 
609*e8249070SRobert Mustacchi 	/*
610*e8249070SRobert Mustacchi 	 * We skip testing the data on raw sockets so we can ignore having to
611*e8249070SRobert Mustacchi 	 * parse the IPv4 or IPv6 headers.
612*e8249070SRobert Mustacchi 	 */
613*e8249070SRobert Mustacchi 	if (data != tt_msg && test->tt_type != SOCK_RAW) {
614*e8249070SRobert Mustacchi 		warnx("TEST FAILED: %s: data mismatch: expected 0x%x, found "
615*e8249070SRobert Mustacchi 		    "0x%x", test->tt_desc, tt_msg, data);
616*e8249070SRobert Mustacchi 		return (false);
617*e8249070SRobert Mustacchi 	}
618*e8249070SRobert Mustacchi 
619*e8249070SRobert Mustacchi 	if (test->tt_type == SOCK_DGRAM && !ttl_check_ancil(test, &msg)) {
620*e8249070SRobert Mustacchi 		return (false);
621*e8249070SRobert Mustacchi 	}
622*e8249070SRobert Mustacchi 
623*e8249070SRobert Mustacchi 	(void) printf("TEST PASSED: %s: Successfully received data\n",
624*e8249070SRobert Mustacchi 	    test->tt_desc);
625*e8249070SRobert Mustacchi 	return (true);
626*e8249070SRobert Mustacchi }
627*e8249070SRobert Mustacchi 
628*e8249070SRobert Mustacchi static bool
ttl_test_one(const ttl_test_t * test)629*e8249070SRobert Mustacchi ttl_test_one(const ttl_test_t *test)
630*e8249070SRobert Mustacchi {
631*e8249070SRobert Mustacchi 	int src = -1, dst = -1, cfd = -1, port = -1, tdst;
632*e8249070SRobert Mustacchi 	int level, ttlopt, minttlopt, recvopt, en = 1;
633*e8249070SRobert Mustacchi 	bool ret = true;
634*e8249070SRobert Mustacchi 	struct sockaddr_storage dst_addr;
635*e8249070SRobert Mustacchi 
636*e8249070SRobert Mustacchi 	if ((port = port_create()) < 0) {
637*e8249070SRobert Mustacchi 		err(EXIT_FAILURE, "TEST FAILED: failed to create event port");
638*e8249070SRobert Mustacchi 	}
639*e8249070SRobert Mustacchi 
640*e8249070SRobert Mustacchi 	src = socket(test->tt_domain, test->tt_type | SOCK_NONBLOCK,
641*e8249070SRobert Mustacchi 	    test->tt_proto);
642*e8249070SRobert Mustacchi 	if (src < 0) {
643*e8249070SRobert Mustacchi 		warn("TEST FAILED: %s: failed to create source socket",
644*e8249070SRobert Mustacchi 		    test->tt_desc);
645*e8249070SRobert Mustacchi 		ret = false;
646*e8249070SRobert Mustacchi 		goto cleanup;
647*e8249070SRobert Mustacchi 	}
648*e8249070SRobert Mustacchi 
649*e8249070SRobert Mustacchi 	dst = socket(test->tt_domain, test->tt_type | SOCK_NONBLOCK,
650*e8249070SRobert Mustacchi 	    test->tt_proto);
651*e8249070SRobert Mustacchi 	if (dst < 0) {
652*e8249070SRobert Mustacchi 		warn("TEST FAILED: %s: failed to create destination socket",
653*e8249070SRobert Mustacchi 		    test->tt_desc);
654*e8249070SRobert Mustacchi 		ret = false;
655*e8249070SRobert Mustacchi 		goto cleanup;
656*e8249070SRobert Mustacchi 	}
657*e8249070SRobert Mustacchi 
658*e8249070SRobert Mustacchi 	if (!ttl_bind_dest(test, dst, &dst_addr)) {
659*e8249070SRobert Mustacchi 		ret = false;
660*e8249070SRobert Mustacchi 		goto cleanup;
661*e8249070SRobert Mustacchi 	}
662*e8249070SRobert Mustacchi 
663*e8249070SRobert Mustacchi 	if (test->tt_domain == PF_INET) {
664*e8249070SRobert Mustacchi 		level = IPPROTO_IP;
665*e8249070SRobert Mustacchi 		ttlopt = IP_TTL;
666*e8249070SRobert Mustacchi 		minttlopt = IP_MINTTL;
667*e8249070SRobert Mustacchi 		recvopt = IP_RECVTTL;
668*e8249070SRobert Mustacchi 	} else {
669*e8249070SRobert Mustacchi 		level = IPPROTO_IPV6;
670*e8249070SRobert Mustacchi 		ttlopt = IPV6_UNICAST_HOPS;
671*e8249070SRobert Mustacchi 		minttlopt = IPV6_MINHOPCOUNT;
672*e8249070SRobert Mustacchi 		recvopt = IPV6_RECVHOPLIMIT;
673*e8249070SRobert Mustacchi 	}
674*e8249070SRobert Mustacchi 
675*e8249070SRobert Mustacchi 	if (test->tt_ttl > 0 && setsockopt(src, level, ttlopt, &test->tt_ttl,
676*e8249070SRobert Mustacchi 	    sizeof (int)) != 0) {
677*e8249070SRobert Mustacchi 		warn("TEST FAILED: %s: failed to set TTL/HLIM to %d",
678*e8249070SRobert Mustacchi 		    test->tt_desc, test->tt_ttl);
679*e8249070SRobert Mustacchi 		ret = false;
680*e8249070SRobert Mustacchi 		goto cleanup;
681*e8249070SRobert Mustacchi 	}
682*e8249070SRobert Mustacchi 
683*e8249070SRobert Mustacchi 	if (setsockopt(dst, level, minttlopt, &test->tt_minttl,
684*e8249070SRobert Mustacchi 	    sizeof (int)) != 0) {
685*e8249070SRobert Mustacchi 		warn("TEST FAILED: %s: failed to set min TTL/HLIM to %d",
686*e8249070SRobert Mustacchi 		    test->tt_desc, test->tt_minttl);
687*e8249070SRobert Mustacchi 		ret = false;
688*e8249070SRobert Mustacchi 		goto cleanup;
689*e8249070SRobert Mustacchi 	}
690*e8249070SRobert Mustacchi 
691*e8249070SRobert Mustacchi 	if (test->tt_type == SOCK_DGRAM && setsockopt(dst, level, recvopt, &en,
692*e8249070SRobert Mustacchi 	    sizeof (int)) != 0) {
693*e8249070SRobert Mustacchi 		warn("TEST FAILED: %s failed to enable receiving the TTL",
694*e8249070SRobert Mustacchi 		    test->tt_desc);
695*e8249070SRobert Mustacchi 		ret = false;
696*e8249070SRobert Mustacchi 		goto cleanup;
697*e8249070SRobert Mustacchi 	}
698*e8249070SRobert Mustacchi 
699*e8249070SRobert Mustacchi 	if (test->tt_type != SOCK_DGRAM && test->tt_type != SOCK_RAW) {
700*e8249070SRobert Mustacchi 		if (!ttl_connect(test, port, src, dst, &cfd,
701*e8249070SRobert Mustacchi 		    (struct sockaddr *)&dst_addr)) {
702*e8249070SRobert Mustacchi 			ret = false;
703*e8249070SRobert Mustacchi 			goto cleanup;
704*e8249070SRobert Mustacchi 		}
705*e8249070SRobert Mustacchi 		if (test->tt_pass != TTL_SENDRECV) {
706*e8249070SRobert Mustacchi 			goto cleanup;
707*e8249070SRobert Mustacchi 		}
708*e8249070SRobert Mustacchi 		tdst = cfd;
709*e8249070SRobert Mustacchi 	} else {
710*e8249070SRobert Mustacchi 		tdst = dst;
711*e8249070SRobert Mustacchi 	}
712*e8249070SRobert Mustacchi 
713*e8249070SRobert Mustacchi 	if (!ttl_sendrecv(test, port, src, tdst,
714*e8249070SRobert Mustacchi 	    (struct sockaddr *)&dst_addr)) {
715*e8249070SRobert Mustacchi 		ret = false;
716*e8249070SRobert Mustacchi 		goto cleanup;
717*e8249070SRobert Mustacchi 	}
718*e8249070SRobert Mustacchi 
719*e8249070SRobert Mustacchi cleanup:
720*e8249070SRobert Mustacchi 	if (port > -1)
721*e8249070SRobert Mustacchi 		(void) close(port);
722*e8249070SRobert Mustacchi 	if (src > -1)
723*e8249070SRobert Mustacchi 		(void) close(src);
724*e8249070SRobert Mustacchi 	if (dst > -1)
725*e8249070SRobert Mustacchi 		(void) close(dst);
726*e8249070SRobert Mustacchi 	if (cfd > -1)
727*e8249070SRobert Mustacchi 		(void) close(cfd);
728*e8249070SRobert Mustacchi 	return (ret);
729*e8249070SRobert Mustacchi }
730*e8249070SRobert Mustacchi 
731*e8249070SRobert Mustacchi int
main(void)732*e8249070SRobert Mustacchi main(void)
733*e8249070SRobert Mustacchi {
734*e8249070SRobert Mustacchi 	int ret = EXIT_SUCCESS;
735*e8249070SRobert Mustacchi 
736*e8249070SRobert Mustacchi 	for (size_t i = 0; i < ARRAY_SIZE(ttl_tests); i++) {
737*e8249070SRobert Mustacchi 		if (!ttl_test_one(&ttl_tests[i])) {
738*e8249070SRobert Mustacchi 			ret = EXIT_FAILURE;
739*e8249070SRobert Mustacchi 		}
740*e8249070SRobert Mustacchi 	}
741*e8249070SRobert Mustacchi 
742*e8249070SRobert Mustacchi 	if (ret == EXIT_SUCCESS) {
743*e8249070SRobert Mustacchi 		(void) printf("All tests passed successfully\n");
744*e8249070SRobert Mustacchi 	}
745*e8249070SRobert Mustacchi 
746*e8249070SRobert Mustacchi 	return (ret);
747*e8249070SRobert Mustacchi }
748