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