xref: /freebsd/tools/regression/netinet/ipsockopt/ipsockopt.c (revision 00e13b1d679d242d6db62cab43303efe327afdbc)
1f1f6501dSRobert Watson /*-
2f1f6501dSRobert Watson  * Copyright (c) 2004 Robert N. M. Watson
3f1f6501dSRobert Watson  * All rights reserved.
4f1f6501dSRobert Watson  *
5f1f6501dSRobert Watson  * Redistribution and use in source and binary forms, with or without
6f1f6501dSRobert Watson  * modification, are permitted provided that the following conditions
7f1f6501dSRobert Watson  * are met:
8f1f6501dSRobert Watson  * 1. Redistributions of source code must retain the above copyright
9f1f6501dSRobert Watson  *    notice, this list of conditions and the following disclaimer.
10f1f6501dSRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
11f1f6501dSRobert Watson  *    notice, this list of conditions and the following disclaimer in the
12f1f6501dSRobert Watson  *    documentation and/or other materials provided with the distribution.
13f1f6501dSRobert Watson  *
14f1f6501dSRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15f1f6501dSRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16f1f6501dSRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17f1f6501dSRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18f1f6501dSRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19f1f6501dSRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20f1f6501dSRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21f1f6501dSRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22f1f6501dSRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23f1f6501dSRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24f1f6501dSRobert Watson  * SUCH DAMAGE.
25f1f6501dSRobert Watson  *
26f1f6501dSRobert Watson  * $FreeBSD$
27f1f6501dSRobert Watson  */
28f1f6501dSRobert Watson 
29f1f6501dSRobert Watson #include <sys/types.h>
30f1f6501dSRobert Watson #include <sys/socket.h>
31f1f6501dSRobert Watson 
32f1f6501dSRobert Watson #include <netinet/in.h>
33f1f6501dSRobert Watson #include <netinet/in_systm.h>
34f1f6501dSRobert Watson #include <netinet/ip.h>
35f1f6501dSRobert Watson 
36f1f6501dSRobert Watson #include <err.h>
37f1f6501dSRobert Watson #include <errno.h>
38f1f6501dSRobert Watson #include <stdio.h>
39f1f6501dSRobert Watson #include <stdlib.h>
40f1f6501dSRobert Watson #include <string.h>
41f1f6501dSRobert Watson #include <unistd.h>
42f1f6501dSRobert Watson 
43f1f6501dSRobert Watson /*
44f1f6501dSRobert Watson  * The test tool exercises IP-level socket options by interrogating the
45f1f6501dSRobert Watson  * getsockopt()/setsockopt() APIs.  It does not currently test that the
46f1f6501dSRobert Watson  * intended semantics of each option are implemented (i.e., that setting IP
47f1f6501dSRobert Watson  * options on the socket results in packets with the desired IP options in
48f1f6501dSRobert Watson  * it).
49f1f6501dSRobert Watson  */
50f1f6501dSRobert Watson 
51f1f6501dSRobert Watson /*
52cdeeed7aSRobert Watson  * get_socket() is a wrapper function that returns a socket of the specified
53cdeeed7aSRobert Watson  * type, and created with or without restored root privilege (if running
54cdeeed7aSRobert Watson  * with a real uid of root and an effective uid of some other user).  This
55cdeeed7aSRobert Watson  * us to test whether the same rights are granted using a socket with a
56cdeeed7aSRobert Watson  * privileged cached credential vs. a socket with a regular credential.
57cdeeed7aSRobert Watson  */
58cdeeed7aSRobert Watson #define	PRIV_ASIS	0
59cdeeed7aSRobert Watson #define	PRIV_GETROOT	1
60cdeeed7aSRobert Watson static int
61cdeeed7aSRobert Watson get_socket_unpriv(int type)
62cdeeed7aSRobert Watson {
63cdeeed7aSRobert Watson 
64cdeeed7aSRobert Watson 	return (socket(PF_INET, type, 0));
65cdeeed7aSRobert Watson }
66cdeeed7aSRobert Watson 
67cdeeed7aSRobert Watson static int
68cdeeed7aSRobert Watson get_socket_priv(int type)
69cdeeed7aSRobert Watson {
70cdeeed7aSRobert Watson 	uid_t olduid;
71cdeeed7aSRobert Watson 	int sock;
72cdeeed7aSRobert Watson 
73cdeeed7aSRobert Watson 	if (getuid() != 0)
74cdeeed7aSRobert Watson 		errx(-1, "get_sock_priv: running without real uid 0");
75cdeeed7aSRobert Watson 
76cdeeed7aSRobert Watson 	olduid = geteuid();
77cdeeed7aSRobert Watson 	if (seteuid(0) < 0)
78cdeeed7aSRobert Watson 		err(-1, "get_sock_priv: seteuid(0)");
79cdeeed7aSRobert Watson 
80cdeeed7aSRobert Watson 	sock = socket(PF_INET, type, 0);
81cdeeed7aSRobert Watson 
82cdeeed7aSRobert Watson 	if (seteuid(olduid) < 0)
83cdeeed7aSRobert Watson 		err(-1, "get_sock_priv: seteuid(%d)", olduid);
84cdeeed7aSRobert Watson 
85cdeeed7aSRobert Watson 	return (sock);
86cdeeed7aSRobert Watson }
87cdeeed7aSRobert Watson 
88cdeeed7aSRobert Watson static int
89cdeeed7aSRobert Watson get_socket(int type, int priv)
90cdeeed7aSRobert Watson {
91cdeeed7aSRobert Watson 
92cdeeed7aSRobert Watson 	if (priv)
93cdeeed7aSRobert Watson 		return (get_socket_priv(type));
94cdeeed7aSRobert Watson 	else
95cdeeed7aSRobert Watson 		return (get_socket_unpriv(type));
96cdeeed7aSRobert Watson }
97cdeeed7aSRobert Watson 
98cdeeed7aSRobert Watson /*
99f1f6501dSRobert Watson  * Exercise the IP_OPTIONS socket option.  Confirm the following properties:
100f1f6501dSRobert Watson  *
101f1f6501dSRobert Watson  * - That there is no initial set of options (length returned is 0).
102f1f6501dSRobert Watson  * - That if we set a specific set of options, we can read it back.
103f1f6501dSRobert Watson  * - That if we then reset the options, they go away.
104f1f6501dSRobert Watson  *
105f1f6501dSRobert Watson  * Use a UDP socket for this.
106f1f6501dSRobert Watson  */
107f1f6501dSRobert Watson static void
108cdeeed7aSRobert Watson test_ip_options(int sock, const char *socktypename)
109f1f6501dSRobert Watson {
110f1f6501dSRobert Watson 	u_int32_t new_options, test_options[2];
111f1f6501dSRobert Watson 	socklen_t len;
112f1f6501dSRobert Watson 
113f1f6501dSRobert Watson 	/*
114f1f6501dSRobert Watson 	 * Start off by confirming the default IP options on a socket are to
115f1f6501dSRobert Watson 	 * have no options set.
116f1f6501dSRobert Watson 	 */
117f1f6501dSRobert Watson 	len = sizeof(test_options);
118f1f6501dSRobert Watson 	if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
119cdeeed7aSRobert Watson 		err(-1, "test_ip_options(%s): initial getsockopt()",
120cdeeed7aSRobert Watson 		    socktypename);
121f1f6501dSRobert Watson 
122f1f6501dSRobert Watson 	if (len != 0)
123cdeeed7aSRobert Watson 		errx(-1, "test_ip_options(%s): initial getsockopt() returned "
124cdeeed7aSRobert Watson 		    "%d bytes", socktypename, len);
125f1f6501dSRobert Watson 
126f1f6501dSRobert Watson #define	TEST_MAGIC	0xc34e4212
127f1f6501dSRobert Watson #define	NEW_OPTIONS	htonl(IPOPT_EOL | (IPOPT_NOP << 8) | (IPOPT_NOP << 16) \
128f1f6501dSRobert Watson 			 | (IPOPT_NOP << 24))
129f1f6501dSRobert Watson 
130f1f6501dSRobert Watson 	/*
131f1f6501dSRobert Watson 	 * Write some new options into the socket.
132f1f6501dSRobert Watson 	 */
133f1f6501dSRobert Watson 	new_options = NEW_OPTIONS;
134f1f6501dSRobert Watson 	if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, &new_options,
135f1f6501dSRobert Watson 	    sizeof(new_options)) < 0)
136cdeeed7aSRobert Watson 		err(-1, "test_ip_options(%s): setsockopt(NOP|NOP|NOP|EOL)",
137cdeeed7aSRobert Watson 		    socktypename);
138f1f6501dSRobert Watson 
139f1f6501dSRobert Watson 	/*
140f1f6501dSRobert Watson 	 * Store some random cruft in a local variable and retrieve the
141f1f6501dSRobert Watson 	 * options to make sure they set.  Note that we pass in an array
142f1f6501dSRobert Watson 	 * of u_int32_t's so that if whatever ended up in the option was
143f1f6501dSRobert Watson 	 * larger than what we put in, we find out about it here.
144f1f6501dSRobert Watson 	 */
145f1f6501dSRobert Watson 	test_options[0] = TEST_MAGIC;
146f1f6501dSRobert Watson 	test_options[1] = TEST_MAGIC;
147f1f6501dSRobert Watson 	len = sizeof(test_options);
148f1f6501dSRobert Watson 	if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
149cdeeed7aSRobert Watson 		err(-1, "test_ip_options(%s): getsockopt() after set",
150cdeeed7aSRobert Watson 		    socktypename);
151f1f6501dSRobert Watson 
152f1f6501dSRobert Watson 	/*
153f1f6501dSRobert Watson 	 * Getting the right amount back is important.
154f1f6501dSRobert Watson 	 */
155f1f6501dSRobert Watson 	if (len != sizeof(new_options))
156cdeeed7aSRobert Watson 		errx(-1, "test_ip_options(%s): getsockopt() after set "
157cdeeed7aSRobert Watson 		    "returned %d bytes of data", socktypename, len);
158f1f6501dSRobert Watson 
159f1f6501dSRobert Watson 	/*
160f1f6501dSRobert Watson 	 * One posible failure mode is that the call succeeds but neglects to
161f1f6501dSRobert Watson 	 * copy out the data.
162f1f6501dSRobert Watson  	 */
163f1f6501dSRobert Watson 	if (test_options[0] == TEST_MAGIC)
164cdeeed7aSRobert Watson 		errx(-1, "test_ip_options(%s): getsockopt() after set didn't "
165cdeeed7aSRobert Watson 		    "return data", socktypename);
166f1f6501dSRobert Watson 
167f1f6501dSRobert Watson 	/*
168f1f6501dSRobert Watson 	 * Make sure we get back what we wrote on.
169f1f6501dSRobert Watson 	 */
170f1f6501dSRobert Watson 	if (new_options != test_options[0])
171cdeeed7aSRobert Watson 		errx(-1, "test_ip_options(%s): getsockopt() after set "
172cdeeed7aSRobert Watson 		    "returned wrong options (%08x, %08x)", socktypename,
173cdeeed7aSRobert Watson 		    new_options, test_options[0]);
174f1f6501dSRobert Watson 
175f1f6501dSRobert Watson 	/*
176f1f6501dSRobert Watson 	 * Now we reset the value to make sure clearing works.
177f1f6501dSRobert Watson 	 */
178f1f6501dSRobert Watson 	if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, NULL, 0) < 0)
179cdeeed7aSRobert Watson 		err(-1, "test_ip_options(%s): setsockopt() to reset",
180cdeeed7aSRobert Watson 		    socktypename);
181f1f6501dSRobert Watson 
182f1f6501dSRobert Watson 	/*
183f1f6501dSRobert Watson 	 * Make sure it was really cleared.
184f1f6501dSRobert Watson 	 */
185f1f6501dSRobert Watson 	test_options[0] = TEST_MAGIC;
186f1f6501dSRobert Watson 	test_options[1] = TEST_MAGIC;
187f1f6501dSRobert Watson 	len = sizeof(test_options);
188f1f6501dSRobert Watson 	if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
189cdeeed7aSRobert Watson 		err(-1, "test_ip_options(%s): getsockopt() after reset",
190cdeeed7aSRobert Watson 		    socktypename);
191f1f6501dSRobert Watson 
192f1f6501dSRobert Watson 	if (len != 0)
193cdeeed7aSRobert Watson 		errx(-1, "test_ip_options(%s): getsockopt() after reset "
194cdeeed7aSRobert Watson 		    "returned %d bytes", socktypename, len);
195f1f6501dSRobert Watson }
196f1f6501dSRobert Watson 
197f1f6501dSRobert Watson /*
198f1f6501dSRobert Watson  * This test checks the behavior of the IP_HDRINCL socket option, which
199f1f6501dSRobert Watson  * allows users with privilege to specify the full header on an IP raw
200f1f6501dSRobert Watson  * socket.  We test that the option can only be used with raw IP sockets, not
201f1f6501dSRobert Watson  * with UDP or TCP sockets.  We also confirm that the raw socket is only
202f1f6501dSRobert Watson  * available to a privileged user (subject to the UID when called).  We
203f1f6501dSRobert Watson  * confirm that it defaults to off
204cdeeed7aSRobert Watson  *
205cdeeed7aSRobert Watson  * Unlike other tests, doesn't use caller-provided socket.  Probably should
206cdeeed7aSRobert Watson  * be fixed.
207f1f6501dSRobert Watson  */
208f1f6501dSRobert Watson static void
209f1f6501dSRobert Watson test_ip_hdrincl(void)
210f1f6501dSRobert Watson {
211f1f6501dSRobert Watson 	int flag[2], sock;
212f1f6501dSRobert Watson 	socklen_t len;
213f1f6501dSRobert Watson 
214f1f6501dSRobert Watson 	/*
215f1f6501dSRobert Watson 	 * Try to receive or set the IP_HDRINCL flag on a TCP socket.
216f1f6501dSRobert Watson 	 */
217f1f6501dSRobert Watson 	sock = socket(PF_INET, SOCK_STREAM, 0);
218cdeeed7aSRobert Watson 	if (sock == -1)
219cdeeed7aSRobert Watson 		err(-1, "test_ip_hdrincl(): socket(SOCK_STREAM)");
220f1f6501dSRobert Watson 
221f1f6501dSRobert Watson 	flag[0] = -1;
222f1f6501dSRobert Watson 	len = sizeof(flag[0]);
223cdeeed7aSRobert Watson 	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0)
224cdeeed7aSRobert Watson 		err(-1, "test_ip_hdrincl(): initial getsockopt(IP_HDRINCL)");
225f1f6501dSRobert Watson 
226cdeeed7aSRobert Watson 	if (errno != ENOPROTOOPT)
227cdeeed7aSRobert Watson 		errx(-1, "test_ip_hdrincl(): initial getsockopt(IP_HDRINC) "
228cdeeed7aSRobert Watson 		    "returned %d (%s) not ENOPROTOOPT", errno,
229cdeeed7aSRobert Watson 		    strerror(errno));
230f1f6501dSRobert Watson 
231f1f6501dSRobert Watson 	flag[0] = 1;
232f1f6501dSRobert Watson 	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
233cdeeed7aSRobert Watson 	    == 0)
234cdeeed7aSRobert Watson 		err(-1,"test_ip_hdrincl(): setsockopt(IP_HDRINCL) on TCP "
235cdeeed7aSRobert Watson 		    "succeeded\n");
236f1f6501dSRobert Watson 
237cdeeed7aSRobert Watson 	if (errno != ENOPROTOOPT)
238cdeeed7aSRobert Watson 		errx(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on TCP "
239cdeeed7aSRobert Watson 		    "returned %d (%s) not ENOPROTOOPT\n", errno,
240cdeeed7aSRobert Watson 		    strerror(errno));
241f1f6501dSRobert Watson 
242f1f6501dSRobert Watson 	close(sock);
243f1f6501dSRobert Watson 
244f1f6501dSRobert Watson 	/*
245f1f6501dSRobert Watson 	 * Try to receive or set the IP_HDRINCL flag on a UDP socket.
246f1f6501dSRobert Watson 	 */
247f1f6501dSRobert Watson 	sock = socket(PF_INET, SOCK_DGRAM, 0);
248cdeeed7aSRobert Watson 	if (sock == -1)
249cdeeed7aSRobert Watson 		err(-1, "test_ip_hdrincl(): socket(SOCK_DGRAM");
250f1f6501dSRobert Watson 
251f1f6501dSRobert Watson 	flag[0] = -1;
252f1f6501dSRobert Watson 	len = sizeof(flag[0]);
253cdeeed7aSRobert Watson 	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0)
254cdeeed7aSRobert Watson 		err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on UDP "
255cdeeed7aSRobert Watson 		    "succeeded\n");
256f1f6501dSRobert Watson 
257cdeeed7aSRobert Watson 	if (errno != ENOPROTOOPT)
258cdeeed7aSRobert Watson 		errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on UDP "
259cdeeed7aSRobert Watson 		    "returned %d (%s) not ENOPROTOOPT\n", errno,
260cdeeed7aSRobert Watson 		    strerror(errno));
261f1f6501dSRobert Watson 
262f1f6501dSRobert Watson 	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
263cdeeed7aSRobert Watson 	    == 0)
264cdeeed7aSRobert Watson 		err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on UDP "
265cdeeed7aSRobert Watson 		    "succeeded\n");
266f1f6501dSRobert Watson 
267cdeeed7aSRobert Watson 	if (errno != ENOPROTOOPT)
268cdeeed7aSRobert Watson 		errx(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on UDP "
269cdeeed7aSRobert Watson 		    "returned %d (%s) not ENOPROTOOPT\n", errno,
270cdeeed7aSRobert Watson 		    strerror(errno));
271f1f6501dSRobert Watson 
272f1f6501dSRobert Watson 	close(sock);
273f1f6501dSRobert Watson 
274f1f6501dSRobert Watson 	/*
275f1f6501dSRobert Watson 	 * Now try on a raw socket.  Access ontrol should prevent non-root
276f1f6501dSRobert Watson 	 * users from creating the raw socket, so check that here based on
277f1f6501dSRobert Watson 	 * geteuid().  If we're non-root, we just return assuming the socket
278f1f6501dSRobert Watson 	 * create fails since the remainder of the tests apply only on a raw
279f1f6501dSRobert Watson 	 * socket.
280f1f6501dSRobert Watson 	 */
281f1f6501dSRobert Watson 	sock = socket(PF_INET, SOCK_RAW, 0);
282f1f6501dSRobert Watson 	if (geteuid() != 0) {
283f1f6501dSRobert Watson 		if (sock != -1)
284f1f6501dSRobert Watson 			errx(-1, "test_ip_hdrincl: created raw socket as "
285f1f6501dSRobert Watson 			    "uid %d", geteuid());
286f1f6501dSRobert Watson 		return;
287f1f6501dSRobert Watson 	}
288cdeeed7aSRobert Watson 	if (sock == -1)
289cdeeed7aSRobert Watson 		err(-1, "test_ip_hdrincl(): socket(PF_INET, SOCK_RAW)");
290f1f6501dSRobert Watson 
291f1f6501dSRobert Watson 	/*
292f1f6501dSRobert Watson 	 * Make sure the initial value of the flag is 0 (disabled).
293f1f6501dSRobert Watson 	 */
294f1f6501dSRobert Watson 	flag[0] = -1;
295f1f6501dSRobert Watson 	flag[1] = -1;
296f1f6501dSRobert Watson 	len = sizeof(flag);
297cdeeed7aSRobert Watson 	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)
298cdeeed7aSRobert Watson 		err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on raw "
299cdeeed7aSRobert Watson 		    "socket");
300f1f6501dSRobert Watson 
301cdeeed7aSRobert Watson 	if (len != sizeof(flag[0]))
302cdeeed7aSRobert Watson 		errx(-1, "test_ip_hdrincl(): %d bytes returned on "
303f1f6501dSRobert Watson 		    "initial get\n", len);
304f1f6501dSRobert Watson 
305cdeeed7aSRobert Watson 	if (flag[0] != 0)
306cdeeed7aSRobert Watson 		errx(-1, "test_ip_hdrincl(): initial flag value of %d\n",
307f1f6501dSRobert Watson 		    flag[0]);
308f1f6501dSRobert Watson 
309f1f6501dSRobert Watson 	/*
310f1f6501dSRobert Watson 	 * Enable the IP_HDRINCL flag.
311f1f6501dSRobert Watson 	 */
312f1f6501dSRobert Watson 	flag[0] = 1;
313f1f6501dSRobert Watson 	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
314cdeeed7aSRobert Watson 	    < 0)
315cdeeed7aSRobert Watson 		err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL, 1)");
316f1f6501dSRobert Watson 
317f1f6501dSRobert Watson 	/*
318f1f6501dSRobert Watson 	 * Check that the IP_HDRINCL flag was set.
319f1f6501dSRobert Watson 	 */
320f1f6501dSRobert Watson 	flag[0] = -1;
321f1f6501dSRobert Watson 	flag[1] = -1;
322f1f6501dSRobert Watson 	len = sizeof(flag);
323cdeeed7aSRobert Watson 	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)
324cdeeed7aSRobert Watson 		err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) after "
325cdeeed7aSRobert Watson 		    "set");
326f1f6501dSRobert Watson 
327cdeeed7aSRobert Watson 	if (flag[0] == 0)
328cdeeed7aSRobert Watson 		errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) "
329f1f6501dSRobert Watson 		    "after set had flag of %d\n", flag[0]);
330f1f6501dSRobert Watson 
331f1f6501dSRobert Watson #define	HISTORICAL_INP_HDRINCL	8
332cdeeed7aSRobert Watson 	if (flag[0] != HISTORICAL_INP_HDRINCL)
333cdeeed7aSRobert Watson 		warnx("test_ip_hdrincl(): WARNING: getsockopt(IP_H"
334f1f6501dSRobert Watson 		    "DRINCL) after set had non-historical value of %d\n",
335f1f6501dSRobert Watson 		    flag[0]);
336f1f6501dSRobert Watson 
337f1f6501dSRobert Watson 	/*
338f1f6501dSRobert Watson 	 * Reset the IP_HDRINCL flag to 0.
339f1f6501dSRobert Watson 	 */
340f1f6501dSRobert Watson 	flag[0] = 0;
341f1f6501dSRobert Watson 	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
342cdeeed7aSRobert Watson 	    < 0)
343cdeeed7aSRobert Watson 		err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL, 0)");
344f1f6501dSRobert Watson 
345f1f6501dSRobert Watson 	/*
346f1f6501dSRobert Watson 	 * Check that the IP_HDRINCL flag was reset to 0.
347f1f6501dSRobert Watson 	 */
348f1f6501dSRobert Watson 	flag[0] = -1;
349f1f6501dSRobert Watson 	flag[1] = -1;
350f1f6501dSRobert Watson 	len = sizeof(flag);
351cdeeed7aSRobert Watson 	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)
352cdeeed7aSRobert Watson 		err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) after "
353cdeeed7aSRobert Watson 		    "reset");
354f1f6501dSRobert Watson 
355cdeeed7aSRobert Watson 	if (flag[0] != 0)
356cdeeed7aSRobert Watson 		errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) "
357f1f6501dSRobert Watson 		    "after set had flag of %d\n", flag[0]);
358f1f6501dSRobert Watson 
359f1f6501dSRobert Watson 	close(sock);
360f1f6501dSRobert Watson }
361f1f6501dSRobert Watson 
362f1f6501dSRobert Watson /*
363f1f6501dSRobert Watson  * As with other non-int or larger sized socket options, the IP_TOS and
364f1f6501dSRobert Watson  * IP_TTL fields in kernel is stored as an 8-bit value, reflecting the IP
365f1f6501dSRobert Watson  * header fields, but useful I/O to the field occurs using 32-bit integers.
366f1f6501dSRobert Watson  * The FreeBSD kernel will permit writes from variables at least an int in
367f1f6501dSRobert Watson  * size (and ignore additional bytes), and will permit a read to buffers 1
368f1f6501dSRobert Watson  * byte or larger (but depending on endianness, may truncate out useful
369f1f6501dSRobert Watson  * values if the caller provides less room).
370f1f6501dSRobert Watson  *
371f1f6501dSRobert Watson  * Given the limitations of the API, use a UDP socket to confirm that the
372f1f6501dSRobert Watson  * following are true:
373f1f6501dSRobert Watson  *
374f1f6501dSRobert Watson  * - We can read the IP_TOS/IP_TTL options.
375f1f6501dSRobert Watson  * - The initial value of the TOS option is 0, TTL is 64.
376f1f6501dSRobert Watson  * - That if we provide more than 32 bits of storage, we get back only 32
377f1f6501dSRobert Watson  *   bits of data.
378f1f6501dSRobert Watson  * - When we set it to a non-zero value expressible with a u_char, we can
379f1f6501dSRobert Watson  *   read that value back.
380f1f6501dSRobert Watson  * - When we reset it back to zero, we can read it as 0.
381f1f6501dSRobert Watson  * - When we set it to a value >255, the value is truncated to something less
382f1f6501dSRobert Watson  *   than 255.
383f1f6501dSRobert Watson  */
384f1f6501dSRobert Watson static void
385cdeeed7aSRobert Watson test_ip_uchar(int sock, const char *socktypename, int option,
386cdeeed7aSRobert Watson     const char *optionname, int initial)
387f1f6501dSRobert Watson {
388cdeeed7aSRobert Watson 	int val[2];
389f1f6501dSRobert Watson 	socklen_t len;
390f1f6501dSRobert Watson 
391f1f6501dSRobert Watson 	/*
392f1f6501dSRobert Watson 	 * Check that the initial value is 0, and that the size is one
393f1f6501dSRobert Watson 	 * u_char;
394f1f6501dSRobert Watson 	 */
395f1f6501dSRobert Watson 	val[0] = -1;
396f1f6501dSRobert Watson 	val[1] = -1;
397f1f6501dSRobert Watson 	len = sizeof(val);
398f1f6501dSRobert Watson 	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
399cdeeed7aSRobert Watson 		err(-1, "test_ip_uchar(%s, %s): initial getsockopt()",
400cdeeed7aSRobert Watson 		    socktypename, optionname);
401f1f6501dSRobert Watson 
402f1f6501dSRobert Watson 	if (len != sizeof(val[0]))
403cdeeed7aSRobert Watson 		errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() "
404cdeeed7aSRobert Watson 		    "returned %d bytes", socktypename, optionname, len);
405f1f6501dSRobert Watson 
406f1f6501dSRobert Watson 	if (val[0] == -1)
407cdeeed7aSRobert Watson 		errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() didn't "
408cdeeed7aSRobert Watson 		    "return data", socktypename, optionname);
409f1f6501dSRobert Watson 
410f1f6501dSRobert Watson 	if (val[0] != initial)
411cdeeed7aSRobert Watson 		errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() "
412cdeeed7aSRobert Watson 		    "returned value of %d, not %d", socktypename, optionname,
413cdeeed7aSRobert Watson 		    val[0], initial);
414f1f6501dSRobert Watson 
415f1f6501dSRobert Watson 	/*
416f1f6501dSRobert Watson 	 * Set the field to a valid value.
417f1f6501dSRobert Watson 	 */
418f1f6501dSRobert Watson 	val[0] = 128;
419f1f6501dSRobert Watson 	val[1] = -1;
420f1f6501dSRobert Watson 	if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0)
421cdeeed7aSRobert Watson 		err(-1, "test_ip_uchar(%s, %s): setsockopt(128)",
422cdeeed7aSRobert Watson 		    socktypename, optionname);
423f1f6501dSRobert Watson 
424f1f6501dSRobert Watson 	/*
425f1f6501dSRobert Watson 	 * Check that when we read back the field, we get the same value.
426f1f6501dSRobert Watson 	 */
427f1f6501dSRobert Watson 	val[0] = -1;
428f1f6501dSRobert Watson 	val[1] = -1;
429f1f6501dSRobert Watson 	len = sizeof(val);
430f1f6501dSRobert Watson 	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
431cdeeed7aSRobert Watson 		err(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
432cdeeed7aSRobert Watson 		    "128", socktypename, optionname);
433f1f6501dSRobert Watson 
434f1f6501dSRobert Watson 	if (len != sizeof(val[0]))
435cdeeed7aSRobert Watson 		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
436cdeeed7aSRobert Watson 		    "128 returned %d bytes", socktypename, optionname, len);
437f1f6501dSRobert Watson 
438f1f6501dSRobert Watson 	if (val[0] == -1)
439cdeeed7aSRobert Watson 		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
440cdeeed7aSRobert Watson 		    "128 didn't return data", socktypename, optionname);
441f1f6501dSRobert Watson 
442f1f6501dSRobert Watson 	if (val[0] != 128)
443cdeeed7aSRobert Watson 		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
444cdeeed7aSRobert Watson 		    "128 returned %d", socktypename, optionname, val[0]);
445f1f6501dSRobert Watson 
446f1f6501dSRobert Watson 	/*
447f1f6501dSRobert Watson 	 * Reset the value to 0, check that it was reset.
448f1f6501dSRobert Watson 	 */
449f1f6501dSRobert Watson 	val[0] = 0;
450f1f6501dSRobert Watson 	val[1] = 0;
451f1f6501dSRobert Watson 	if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0)
452cdeeed7aSRobert Watson 		err(-1, "test_ip_uchar(%s, %s): setsockopt() to reset from "
453cdeeed7aSRobert Watson 		    "128", socktypename, optionname);
454f1f6501dSRobert Watson 
455f1f6501dSRobert Watson 	if (len != sizeof(val[0]))
456cdeeed7aSRobert Watson 		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "
457cdeeed7aSRobert Watson 		   "from 128 returned %d bytes", socktypename, optionname,
458cdeeed7aSRobert Watson 		    len);
459f1f6501dSRobert Watson 
460f1f6501dSRobert Watson 	if (val[0] == -1)
461cdeeed7aSRobert Watson 		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "
462cdeeed7aSRobert Watson 		    "from 128 didn't return data", socktypename, optionname);
463f1f6501dSRobert Watson 
464f1f6501dSRobert Watson 	if (val[0] != 0)
465cdeeed7aSRobert Watson 		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "
466cdeeed7aSRobert Watson 		    "from 128 returned %d", socktypename, optionname,
467cdeeed7aSRobert Watson 		    val[0]);
468f1f6501dSRobert Watson 
469f1f6501dSRobert Watson 	/*
470f1f6501dSRobert Watson 	 * Set the value to something out of range and check that it comes
471f1f6501dSRobert Watson 	 * back truncated, or that we get EINVAL back.  Traditional u_char
472f1f6501dSRobert Watson 	 * IP socket options truncate, but newer ones (such as multicast
473f1f6501dSRobert Watson 	 * socket options) will return EINVAL.
474f1f6501dSRobert Watson 	 */
475f1f6501dSRobert Watson 	val[0] = 32000;
476f1f6501dSRobert Watson 	val[1] = -1;
477f1f6501dSRobert Watson 	if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0) {
478f1f6501dSRobert Watson 		/*
479f1f6501dSRobert Watson 		 * EINVAL is a fine outcome, no need to run the truncation
480f1f6501dSRobert Watson 		 * tests.
481f1f6501dSRobert Watson 		 */
482cdeeed7aSRobert Watson 		if (errno == EINVAL)
483f1f6501dSRobert Watson 			return;
484cdeeed7aSRobert Watson 		err(-1, "test_ip_uchar(%s, %s): getsockopt(32000)",
485cdeeed7aSRobert Watson 		    socktypename, optionname);
486f1f6501dSRobert Watson 	}
487f1f6501dSRobert Watson 
488f1f6501dSRobert Watson 	val[0] = -1;
489f1f6501dSRobert Watson 	val[1] = -1;
490f1f6501dSRobert Watson 	len = sizeof(val);
491f1f6501dSRobert Watson 	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
492cdeeed7aSRobert Watson 		err(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
493cdeeed7aSRobert Watson 		    "32000", socktypename, optionname);
494f1f6501dSRobert Watson 
495f1f6501dSRobert Watson 	if (len != sizeof(val[0]))
496cdeeed7aSRobert Watson 		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
497cdeeed7aSRobert Watson 		    "32000 returned %d bytes", socktypename, optionname,
498cdeeed7aSRobert Watson 		    len);
499f1f6501dSRobert Watson 
500f1f6501dSRobert Watson 	if (val[0] == -1)
501cdeeed7aSRobert Watson 		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
502cdeeed7aSRobert Watson 		    "32000 didn't return data", socktypename, optionname);
503f1f6501dSRobert Watson 
504f1f6501dSRobert Watson 	if (val[0] == 32000)
505cdeeed7aSRobert Watson 		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
506cdeeed7aSRobert Watson 		    "32000 returned 32000: failed to truncate", socktypename,
507cdeeed7aSRobert Watson 		    optionname);
508f1f6501dSRobert Watson }
509f1f6501dSRobert Watson 
510f1f6501dSRobert Watson /*
511f1f6501dSRobert Watson  * Generic test for a boolean socket option.  Caller provides the option
512f1f6501dSRobert Watson  * number, string name, expected default (initial) value, and whether or not
513f1f6501dSRobert Watson  * the option is root-only.  For each option, test:
514f1f6501dSRobert Watson  *
515f1f6501dSRobert Watson  * - That we can read the option.
516f1f6501dSRobert Watson  * - That the initial value is as expected.
517f1f6501dSRobert Watson  * - That we can modify the value.
518f1f6501dSRobert Watson  * - That on modification, the new value can be read back.
519f1f6501dSRobert Watson  * - That we can reset the value.
520f1f6501dSRobert Watson  * - that on reset, the new value can be read back.
521f1f6501dSRobert Watson  */
522f1f6501dSRobert Watson #define	BOOLEAN_ANYONE		1
523f1f6501dSRobert Watson #define	BOOLEAN_ROOTONLY	1
524f1f6501dSRobert Watson static void
525cdeeed7aSRobert Watson test_ip_boolean(int sock, const char *socktypename, int option,
526cdeeed7aSRobert Watson     char *optionname, int initial, int rootonly)
527f1f6501dSRobert Watson {
528cdeeed7aSRobert Watson 	int newvalue, val[2];
529f1f6501dSRobert Watson 	socklen_t len;
530f1f6501dSRobert Watson 
531f1f6501dSRobert Watson 	/*
532f1f6501dSRobert Watson 	 * The default for a boolean might be true or false.  If it's false,
533f1f6501dSRobert Watson 	 * we will try setting it to true (but using a non-1 value of true).
534f1f6501dSRobert Watson 	 * If it's true, we'll set it to false.
535f1f6501dSRobert Watson 	 */
536f1f6501dSRobert Watson 	if (initial == 0)
537f1f6501dSRobert Watson 		newvalue = 0xff;
538f1f6501dSRobert Watson 	else
539f1f6501dSRobert Watson 		newvalue = 0;
540f1f6501dSRobert Watson 
541f1f6501dSRobert Watson 	val[0] = -1;
542f1f6501dSRobert Watson 	val[1] = -1;
543f1f6501dSRobert Watson 	len = sizeof(val);
544f1f6501dSRobert Watson 	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
545f1f6501dSRobert Watson 		err(-1, "test_ip_boolean: initial getsockopt()");
546f1f6501dSRobert Watson 
547f1f6501dSRobert Watson 	if (len != sizeof(val[0]))
548cdeeed7aSRobert Watson 		errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "
549cdeeed7aSRobert Watson 		    "returned %d bytes", socktypename, optionname, len);
550f1f6501dSRobert Watson 
551f1f6501dSRobert Watson 	if (val[0] == -1)
552cdeeed7aSRobert Watson 		errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "
553cdeeed7aSRobert Watson 		    "didn't return data", socktypename, optionname);
554f1f6501dSRobert Watson 
555f1f6501dSRobert Watson 	if (val[0] != initial)
556cdeeed7aSRobert Watson 		errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "
557cdeeed7aSRobert Watson 		    "returned %d (expected %d)", socktypename, optionname,
558cdeeed7aSRobert Watson 		    val[0], initial);
559f1f6501dSRobert Watson 
560f1f6501dSRobert Watson 	/*
561f1f6501dSRobert Watson 	 * Set the socket option to a new non-default value.
562f1f6501dSRobert Watson 	 */
563f1f6501dSRobert Watson 	if (setsockopt(sock, IPPROTO_IP, option, &newvalue, sizeof(newvalue))
564f1f6501dSRobert Watson 	    < 0)
565cdeeed7aSRobert Watson 		err(-1, "test_ip_boolean(%s, %s): setsockopt() to %d",
566cdeeed7aSRobert Watson 		    socktypename, optionname, newvalue);
567f1f6501dSRobert Watson 
568f1f6501dSRobert Watson 	/*
569f1f6501dSRobert Watson 	 * Read the value back and see if it is not the default (note: will
570f1f6501dSRobert Watson 	 * not be what we set it to, as we set it to 0xff above).
571f1f6501dSRobert Watson 	 */
572f1f6501dSRobert Watson 	val[0] = -1;
573f1f6501dSRobert Watson 	val[1] = -1;
574f1f6501dSRobert Watson 	len = sizeof(val);
575f1f6501dSRobert Watson 	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
576cdeeed7aSRobert Watson 		err(-1, "test_ip_boolean(%s, %s): getsockopt() after set to "
577cdeeed7aSRobert Watson 		    "%d", socktypename, optionname, newvalue);
578f1f6501dSRobert Watson 
579f1f6501dSRobert Watson 	if (len != sizeof(val[0]))
580cdeeed7aSRobert Watson 		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "
581cdeeed7aSRobert Watson 		    "to %d returned %d bytes", socktypename, optionname,
582cdeeed7aSRobert Watson 		    newvalue, len);
583f1f6501dSRobert Watson 
584f1f6501dSRobert Watson 	if (val[0] == -1)
585cdeeed7aSRobert Watson 		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "
586cdeeed7aSRobert Watson 		    "to %d didn't return data", socktypename, optionname,
587cdeeed7aSRobert Watson 		    newvalue);
588f1f6501dSRobert Watson 
589f1f6501dSRobert Watson 	/*
590f1f6501dSRobert Watson 	 * If we set it to true, check for '1', otherwise '0.
591f1f6501dSRobert Watson 	 */
592f1f6501dSRobert Watson 	if (val[0] != (newvalue ? 1 : 0))
593cdeeed7aSRobert Watson 		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "
594cdeeed7aSRobert Watson 		    "to %d returned %d", socktypename, optionname, newvalue,
595cdeeed7aSRobert Watson 		    val[0]);
596f1f6501dSRobert Watson 
597f1f6501dSRobert Watson 	/*
598f1f6501dSRobert Watson 	 * Reset to initial value.
599f1f6501dSRobert Watson 	 */
600f1f6501dSRobert Watson 	newvalue = initial;
601f1f6501dSRobert Watson 	if (setsockopt(sock, IPPROTO_IP, option, &newvalue, sizeof(newvalue))
602f1f6501dSRobert Watson 	    < 0)
603cdeeed7aSRobert Watson 		err(-1, "test_ip_boolean(%s, %s): setsockopt() to reset",
604cdeeed7aSRobert Watson 		    socktypename, optionname);
605f1f6501dSRobert Watson 
606f1f6501dSRobert Watson 	/*
607f1f6501dSRobert Watson 	 * Check reset version.
608f1f6501dSRobert Watson 	 */
609f1f6501dSRobert Watson 	val[0] = -1;
610f1f6501dSRobert Watson 	val[1] = -1;
611f1f6501dSRobert Watson 	len = sizeof(val);
612f1f6501dSRobert Watson 	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
613cdeeed7aSRobert Watson 		err(-1, "test_ip_boolean(%s, %s): getsockopt() after reset",
614cdeeed7aSRobert Watson 		    socktypename, optionname);
615f1f6501dSRobert Watson 
616f1f6501dSRobert Watson 	if (len != sizeof(val[0]))
617cdeeed7aSRobert Watson 		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "
618cdeeed7aSRobert Watson 		    "returned %d bytes", socktypename, optionname, len);
619f1f6501dSRobert Watson 
620f1f6501dSRobert Watson 	if (val[0] == -1)
621cdeeed7aSRobert Watson 		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "
622cdeeed7aSRobert Watson 		    "didn't return data", socktypename, optionname);
623f1f6501dSRobert Watson 
624f1f6501dSRobert Watson 	if (val[0] != newvalue)
625cdeeed7aSRobert Watson 		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "
626cdeeed7aSRobert Watson 		    "returned %d", socktypename, optionname, newvalue);
627f1f6501dSRobert Watson }
628f1f6501dSRobert Watson 
629f1f6501dSRobert Watson /*
630f1f6501dSRobert Watson  * XXX: For now, nothing here.
631f1f6501dSRobert Watson  */
632f1f6501dSRobert Watson static void
633cdeeed7aSRobert Watson test_ip_multicast_if(int sock, const char *socktypename)
634f1f6501dSRobert Watson {
635f1f6501dSRobert Watson 
636f1f6501dSRobert Watson 	/*
637f1f6501dSRobert Watson 	 * It's probably worth trying INADDR_ANY and INADDR_LOOPBACK here
638f1f6501dSRobert Watson 	 * to see what happens.
639f1f6501dSRobert Watson 	 */
640f1f6501dSRobert Watson }
641f1f6501dSRobert Watson 
642f1f6501dSRobert Watson /*
643f1f6501dSRobert Watson  * XXX: For now, nothing here.
644f1f6501dSRobert Watson  */
645f1f6501dSRobert Watson static void
646cdeeed7aSRobert Watson test_ip_multicast_vif(int sock, const char *socktypename)
647f1f6501dSRobert Watson {
648f1f6501dSRobert Watson 
649f1f6501dSRobert Watson 	/*
650f1f6501dSRobert Watson 	 * This requires some knowledge of the number of virtual interfaces,
651f1f6501dSRobert Watson 	 * and what is valid.
652f1f6501dSRobert Watson 	 */
653f1f6501dSRobert Watson }
654f1f6501dSRobert Watson 
655f1f6501dSRobert Watson /*
656f1f6501dSRobert Watson  * XXX: For now, nothing here.
657f1f6501dSRobert Watson  */
658f1f6501dSRobert Watson static void
659cdeeed7aSRobert Watson test_ip_multicast_membership(int sock, const char *socktypename)
660f1f6501dSRobert Watson {
661f1f6501dSRobert Watson 
662f1f6501dSRobert Watson }
663f1f6501dSRobert Watson 
664f1f6501dSRobert Watson static void
665cdeeed7aSRobert Watson testsuite(int priv)
666f1f6501dSRobert Watson {
667cdeeed7aSRobert Watson 	const char *socktypenameset[] = {"SOCK_DGRAM", "SOCK_STREAM",
668cdeeed7aSRobert Watson 	    "SOCK_RAW"};
669cdeeed7aSRobert Watson 	int socktypeset[] = {SOCK_DGRAM, SOCK_STREAM, SOCK_RAW};
670cdeeed7aSRobert Watson 	const char *socktypename;
671cdeeed7aSRobert Watson 	int i, sock, socktype;
672f1f6501dSRobert Watson 
673f1f6501dSRobert Watson 	test_ip_hdrincl();
674f1f6501dSRobert Watson 
675cdeeed7aSRobert Watson 	for (i = 0; i < sizeof(socktypeset)/sizeof(int); i++) {
676cdeeed7aSRobert Watson 		socktype = socktypeset[i];
677cdeeed7aSRobert Watson 		socktypename = socktypenameset[i];
678f1f6501dSRobert Watson 
679cdeeed7aSRobert Watson 		/*
680cdeeed7aSRobert Watson 		 * If we can't acquire root privilege, we can't open raw
681cdeeed7aSRobert Watson 		 * sockets, so don't actually try.
682cdeeed7aSRobert Watson 		 */
683cdeeed7aSRobert Watson 		if (getuid() != 0 && socktype == SOCK_RAW)
684cdeeed7aSRobert Watson 			continue;
685a1626faaSRobert Watson 		if (geteuid() != 0 && !priv && socktype == SOCK_RAW)
686a1626faaSRobert Watson 			continue;
687f1f6501dSRobert Watson 
688f1f6501dSRobert Watson 		/*
689cdeeed7aSRobert Watson 		 * XXXRW: On 5.3, this seems not to work for SOCK_RAW.
690cdeeed7aSRobert Watson 		 */
691cdeeed7aSRobert Watson 		sock = get_socket(socktype, priv);
692cdeeed7aSRobert Watson 		if (sock == -1)
693cdeeed7aSRobert Watson 			err(-1, "get_socket(%s, %d) for test_ip_uchar(IP_TOS)",
694cdeeed7aSRobert Watson 			    socktypename, priv);
695cdeeed7aSRobert Watson 		test_ip_uchar(sock, socktypename, IP_TOS, "IP_TOS", 0);
696cdeeed7aSRobert Watson 		close(sock);
697cdeeed7aSRobert Watson 
698cdeeed7aSRobert Watson 		sock = get_socket(socktype, priv);
699cdeeed7aSRobert Watson 		if (sock == -1)
700cdeeed7aSRobert Watson 			err(-1, "get_socket(%s %d) for test_ip_uchar(IP_TTL)",
701cdeeed7aSRobert Watson 			    socktypename, priv);
702cdeeed7aSRobert Watson 		test_ip_uchar(sock, socktypename, IP_TTL, "IP_TTL", 64);
703cdeeed7aSRobert Watson 		close(sock);
704cdeeed7aSRobert Watson 
705cdeeed7aSRobert Watson 		sock = get_socket(socktype, priv);
706cdeeed7aSRobert Watson 		if (sock == -1)
707cdeeed7aSRobert Watson 			err(-1, "get_socket(%s, %d) for test_ip_boolean"
708cdeeed7aSRobert Watson 			    "(IP_RECVOPTS)", socktypename, priv);
709cdeeed7aSRobert Watson 		test_ip_boolean(sock, socktypename, IP_RECVOPTS,
710cdeeed7aSRobert Watson 		    "IP_RECVOPTS", 0, BOOLEAN_ANYONE);
711cdeeed7aSRobert Watson 		close(sock);
712cdeeed7aSRobert Watson 
713cdeeed7aSRobert Watson 		sock = get_socket(socktype, priv);
714cdeeed7aSRobert Watson 		if (sock == -1)
715cdeeed7aSRobert Watson 			err(-1, "get_socket(%s, %d) for test_ip_boolean"
716cdeeed7aSRobert Watson 			     "(IP_RECVRETOPTS)", socktypename, priv);
717cdeeed7aSRobert Watson 		test_ip_boolean(sock, socktypename, IP_RECVRETOPTS,
718cdeeed7aSRobert Watson 		    "IP_RECVRETOPTS", 0, BOOLEAN_ANYONE);
719cdeeed7aSRobert Watson 		close(sock);
720cdeeed7aSRobert Watson 
721cdeeed7aSRobert Watson 		sock = get_socket(socktype, priv);
722cdeeed7aSRobert Watson 		if (sock == -1)
723cdeeed7aSRobert Watson 			err(-1, "get_socket(%s, %d) for test_ip_boolean"
724cdeeed7aSRobert Watson 			    "(IP_RECVDSTADDR)", socktypename, priv);
725cdeeed7aSRobert Watson 		test_ip_boolean(sock, socktypename, IP_RECVDSTADDR,
726cdeeed7aSRobert Watson 		    "IP_RECVDSTADDR", 0, BOOLEAN_ANYONE);
727cdeeed7aSRobert Watson 		close(sock);
728cdeeed7aSRobert Watson 
729cdeeed7aSRobert Watson 		sock = get_socket(socktype, priv);
730cdeeed7aSRobert Watson 		if (sock == -1)
731cdeeed7aSRobert Watson 			err(-1, "get_socket(%s, %d) for test_ip_boolean"
732cdeeed7aSRobert Watson 			    "(IP_RECVTTL)", socktypename, priv);
733cdeeed7aSRobert Watson 		test_ip_boolean(sock, socktypename, IP_RECVTTL, "IP_RECVTTL",
734cdeeed7aSRobert Watson 		    0, BOOLEAN_ANYONE);
735cdeeed7aSRobert Watson 		close(sock);
736cdeeed7aSRobert Watson 
737cdeeed7aSRobert Watson 		sock = get_socket(socktype, priv);
738cdeeed7aSRobert Watson 		if (sock == -1)
739cdeeed7aSRobert Watson 			err(-1, "get_socket(%s, %d) for test_ip_boolean"
740cdeeed7aSRobert Watson 			    "(IP_RECVIF)", socktypename, priv);
741cdeeed7aSRobert Watson 		test_ip_boolean(sock, socktypename, IP_RECVIF, "IP_RECVIF",
742cdeeed7aSRobert Watson 		    0, BOOLEAN_ANYONE);
743cdeeed7aSRobert Watson 		close(sock);
744cdeeed7aSRobert Watson 
745cdeeed7aSRobert Watson 		sock = get_socket(socktype, priv);
746cdeeed7aSRobert Watson 		if (sock == -1)
747cdeeed7aSRobert Watson 			err(-1, "get_socket(%s, %d) for test_ip_boolean"
748cdeeed7aSRobert Watson 			    "(IP_FAITH)", socktypename, priv);
749cdeeed7aSRobert Watson 		test_ip_boolean(sock, socktypename, IP_FAITH, "IP_FAITH", 0,
750cdeeed7aSRobert Watson 		    BOOLEAN_ANYONE);
751cdeeed7aSRobert Watson 		close(sock);
752cdeeed7aSRobert Watson 
753cdeeed7aSRobert Watson 		sock = get_socket(socktype, priv);
754cdeeed7aSRobert Watson 		if (sock == -1)
755cdeeed7aSRobert Watson 			err(-1, "get_socket(%s, %d) for test_ip_boolean"
756cdeeed7aSRobert Watson 			    "(IP_ONESBCAST)", socktypename, priv);
757cdeeed7aSRobert Watson 		test_ip_boolean(sock, socktypename, IP_ONESBCAST,
758cdeeed7aSRobert Watson 		    "IP_ONESBCAST", 0, BOOLEAN_ANYONE);
759cdeeed7aSRobert Watson 		close(sock);
760cdeeed7aSRobert Watson 
761cdeeed7aSRobert Watson 		/*
762cdeeed7aSRobert Watson 		 * Test the multicast TTL exactly as we would the regular
763cdeeed7aSRobert Watson 		 * TTL, only expect a different default.
764cdeeed7aSRobert Watson 		 */
765cdeeed7aSRobert Watson 		sock = get_socket(socktype, priv);
766cdeeed7aSRobert Watson 		if (sock == -1)
767cdeeed7aSRobert Watson 			err(-1, "get_socket(%s, %d) for IP_MULTICAST_TTL",
768cdeeed7aSRobert Watson 			    socktypename, priv);
769cdeeed7aSRobert Watson 		test_ip_uchar(sock, socktypename, IP_MULTICAST_TTL,
770cdeeed7aSRobert Watson 		    "IP_MULTICAST_TTL", 1);
771cdeeed7aSRobert Watson 		close(sock);
772cdeeed7aSRobert Watson 
773cdeeed7aSRobert Watson 		/*
774cdeeed7aSRobert Watson 		 * The multicast loopback flag can be tested using our
775cdeeed7aSRobert Watson 		 * boolean tester, but only because the FreeBSD API is a bit
776cdeeed7aSRobert Watson 		 * more flexible than earlir APIs and will accept an int as
777cdeeed7aSRobert Watson 		 * well as a u_char.  Loopback is enabled by default.
778cdeeed7aSRobert Watson 		 */
779cdeeed7aSRobert Watson 		sock = get_socket(socktype, priv);
780cdeeed7aSRobert Watson 		if (sock == -1)
781cdeeed7aSRobert Watson 			err(-1, "get_socket(%s, %d) for IP_MULTICAST_LOOP",
782cdeeed7aSRobert Watson 			    socktypename, priv);
783cdeeed7aSRobert Watson 		test_ip_boolean(sock, socktypename, IP_MULTICAST_LOOP,
784cdeeed7aSRobert Watson 		    "IP_MULTICAST_LOOP", 1, BOOLEAN_ANYONE);
785cdeeed7aSRobert Watson 		close(sock);
786cdeeed7aSRobert Watson 
787cdeeed7aSRobert Watson 		sock = get_socket(socktype, priv);
788cdeeed7aSRobert Watson 		if (sock == -1)
789cdeeed7aSRobert Watson 			err(-1, "get_socket(%s, %d) for test_ip_options",
790cdeeed7aSRobert Watson 			    socktypename, priv);
791cdeeed7aSRobert Watson 		//test_ip_options(sock, socktypename);
792cdeeed7aSRobert Watson 		close(sock);
793cdeeed7aSRobert Watson 
794cdeeed7aSRobert Watson 		test_ip_multicast_if(0, NULL);
795cdeeed7aSRobert Watson 		test_ip_multicast_vif(0, NULL);
796cdeeed7aSRobert Watson 		test_ip_multicast_membership(0, NULL);
797cdeeed7aSRobert Watson 		/*
798f1f6501dSRobert Watson 		 * XXX: Still need to test:
799f1f6501dSRobert Watson 		 * IP_PORTRANGE
800f1f6501dSRobert Watson 		 * IP_IPSEC_POLICY?
801f1f6501dSRobert Watson 		 */
802cdeeed7aSRobert Watson 	}
803f1f6501dSRobert Watson }
804f1f6501dSRobert Watson 
805f1f6501dSRobert Watson /*
806f1f6501dSRobert Watson  * Very simply exercise that we can get and set each option.  If we're running
807f1f6501dSRobert Watson  * as root, run it also as nobody.  If not as root, complain about that.
808f1f6501dSRobert Watson  */
809f1f6501dSRobert Watson int
810f1f6501dSRobert Watson main(int argc, char *argv[])
811f1f6501dSRobert Watson {
812f1f6501dSRobert Watson 
81300e13b1dSNik Clayton 	printf("1..1\n");
814f1f6501dSRobert Watson 	if (geteuid() != 0) {
815cdeeed7aSRobert Watson 		warnx("Not running as root, can't run tests as root");
816f1f6501dSRobert Watson 		fprintf(stderr, "\n");
817cdeeed7aSRobert Watson 		fprintf(stderr,
818cdeeed7aSRobert Watson 		   "Running tests with uid %d sock uid %d\n", geteuid(),
819cdeeed7aSRobert Watson 		    geteuid());
820cdeeed7aSRobert Watson 		testsuite(PRIV_ASIS);
821f1f6501dSRobert Watson 	} else {
822cdeeed7aSRobert Watson 		fprintf(stderr,
823cdeeed7aSRobert Watson 		    "Running tests with ruid %d euid %d sock uid 0\n",
824cdeeed7aSRobert Watson 		    getuid(), geteuid());
825cdeeed7aSRobert Watson 		testsuite(PRIV_ASIS);
826cdeeed7aSRobert Watson 		if (seteuid(65534) != 0)
827cdeeed7aSRobert Watson 			err(-1, "seteuid(65534)");
828cdeeed7aSRobert Watson 		fprintf(stderr,
829cdeeed7aSRobert Watson 		    "Running tests with ruid %d euid %d sock uid 65534\n",
830cdeeed7aSRobert Watson 		    getuid(), geteuid());
831cdeeed7aSRobert Watson 		testsuite(PRIV_ASIS);
832a1626faaSRobert Watson 		fprintf(stderr,
833a1626faaSRobert Watson 		    "Running tests with ruid %d euid %d sock uid 0\n",
834a1626faaSRobert Watson 		    getuid(), geteuid());
835a1626faaSRobert Watson 		testsuite(PRIV_GETROOT);
836f1f6501dSRobert Watson 	}
83700e13b1dSNik Clayton 	printf("ok 1 - ipsockopt\n");
838f1f6501dSRobert Watson 	exit(0);
839f1f6501dSRobert Watson }
840