ipsockopt.c revision 136384
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: head/tools/regression/netinet/ipsockopt/ipsockopt.c 136384 2004-10-11 16:09:45Z rwatson $
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 * Exercise the IP_OPTIONS socket option.  Confirm the following properties:
53 *
54 * - That there is no initial set of options (length returned is 0).
55 * - That if we set a specific set of options, we can read it back.
56 * - That if we then reset the options, they go away.
57 *
58 * Use a UDP socket for this.
59 */
60static void
61test_ip_options(void)
62{
63	u_int32_t new_options, test_options[2];
64	socklen_t len;
65	int sock;
66
67	sock = socket(PF_INET, SOCK_DGRAM, 0);
68	if (sock == -1)
69		err(-1, "test_ip_options: socket(SOCK_DGRAM)");
70
71	/*
72	 * Start off by confirming the default IP options on a socket are to
73	 * have no options set.
74	 */
75	len = sizeof(test_options);
76	if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
77		err(-1, "test_ip_options: initial getsockopt()");
78
79	if (len != 0)
80		errx(-1, "test_ip_options: initial getsockopt() returned "
81		    "%d bytes", len);
82
83#define	TEST_MAGIC	0xc34e4212
84#define	NEW_OPTIONS	htonl(IPOPT_EOL | (IPOPT_NOP << 8) | (IPOPT_NOP << 16) \
85			 | (IPOPT_NOP << 24))
86
87	/*
88	 * Write some new options into the socket.
89	 */
90	new_options = NEW_OPTIONS;
91	if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, &new_options,
92	    sizeof(new_options)) < 0)
93		err(-1, "test_ip_options: setsockopt(NOP|NOP|NOP|EOL)");
94
95	/*
96	 * Store some random cruft in a local variable and retrieve the
97	 * options to make sure they set.  Note that we pass in an array
98	 * of u_int32_t's so that if whatever ended up in the option was
99	 * larger than what we put in, we find out about it here.
100	 */
101	test_options[0] = TEST_MAGIC;
102	test_options[1] = TEST_MAGIC;
103	len = sizeof(test_options);
104	if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
105		err(-1, "test_ip_options: getsockopt() after set");
106
107	/*
108	 * Getting the right amount back is important.
109	 */
110	if (len != sizeof(new_options))
111		errx(-1, "test_ip_options: getsockopt() after set returned "
112		    "%d bytes of data", len);
113
114	/*
115	 * One posible failure mode is that the call succeeds but neglects to
116	 * copy out the data.
117 	 */
118	if (test_options[0] == TEST_MAGIC)
119		errx(-1, "test_ip_options: getsockopt() after set didn't "
120		    "return data");
121
122	/*
123	 * Make sure we get back what we wrote on.
124	 */
125	if (new_options != test_options[0])
126		errx(-1, "test_ip_options: getsockopt() after set returned "
127		    "wrong options (%08x, %08x)", new_options,
128		    test_options[0]);
129
130	/*
131	 * Now we reset the value to make sure clearing works.
132	 */
133	if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, NULL, 0) < 0)
134		err(-1, "test_ip_options: setsockopt() to reset");
135
136	/*
137	 * Make sure it was really cleared.
138	 */
139	test_options[0] = TEST_MAGIC;
140	test_options[1] = TEST_MAGIC;
141	len = sizeof(test_options);
142	if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
143		err(-1, "test_ip_options: getsockopt() after reset");
144
145	if (len != 0)
146		errx(-1, "test_ip_options: getsockopt() after reset returned "
147		    "%d bytes", len);
148
149	close(sock);
150}
151
152/*
153 * This test checks the behavior of the IP_HDRINCL socket option, which
154 * allows users with privilege to specify the full header on an IP raw
155 * socket.  We test that the option can only be used with raw IP sockets, not
156 * with UDP or TCP sockets.  We also confirm that the raw socket is only
157 * available to a privileged user (subject to the UID when called).  We
158 * confirm that it defaults to off
159 */
160static void
161test_ip_hdrincl(void)
162{
163	int flag[2], sock;
164	socklen_t len;
165
166	/*
167	 * Try to receive or set the IP_HDRINCL flag on a TCP socket.
168	 */
169	sock = socket(PF_INET, SOCK_STREAM, 0);
170	if (sock == -1) {
171		perror("socket");
172		exit(-1);
173	}
174
175	flag[0] = -1;
176	len = sizeof(flag[0]);
177	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0) {
178		fprintf(stderr, "getsockopt(IP_HDRINCL) on TCP succeeded\n");
179		exit(-1);
180	}
181
182	if (errno != ENOPROTOOPT) {
183		fprintf(stderr, "getsockopt(IP_HDRINCL) on TCP returned %d "
184		    "(%s) not ENOPROTOOPT\n", errno, strerror(errno));
185		exit(-1);
186	}
187
188	flag[0] = 1;
189	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
190	    == 0) {
191		fprintf(stderr, "setsockopt(IP_HDRINCL) on TCP succeeded\n");
192		exit(-1);
193	}
194
195	if (errno != ENOPROTOOPT) {
196		fprintf(stderr, "setsockopt(IP_HDRINCL) on TCP returned %d "
197		    "(%s) not ENOPROTOOPT\n", errno, strerror(errno));
198		exit(-1);
199	}
200
201	close(sock);
202
203	/*
204	 * Try to receive or set the IP_HDRINCL flag on a UDP socket.
205	 */
206	sock = socket(PF_INET, SOCK_DGRAM, 0);
207	if (sock == -1) {
208		perror("socket");
209		exit(-1);
210	}
211
212	flag[0] = -1;
213	len = sizeof(flag[0]);
214	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0) {
215		fprintf(stderr, "getsockopt(IP_HDRINCL) on UDP succeeded\n");
216		exit(-1);
217	}
218
219	if (errno != ENOPROTOOPT) {
220		fprintf(stderr, "getsockopt(IP_HDRINCL) on UDP returned %d "
221		    "(%s) not ENOPROTOOPT\n", errno, strerror(errno));
222		exit(-1);
223	}
224
225	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
226	    == 0) {
227		fprintf(stderr, "setsockopt(IP_HDRINCL) on UDPsucceeded\n");
228		exit(-1);
229	}
230
231	if (errno != ENOPROTOOPT) {
232		fprintf(stderr, "setsockopt(IP_HDRINCL) on UDP returned %d "
233		    "(%s) not ENOPROTOOPT\n", errno, strerror(errno));
234		exit(-1);
235	}
236
237	close(sock);
238
239	/*
240	 * Now try on a raw socket.  Access ontrol should prevent non-root
241	 * users from creating the raw socket, so check that here based on
242	 * geteuid().  If we're non-root, we just return assuming the socket
243	 * create fails since the remainder of the tests apply only on a raw
244	 * socket.
245	 */
246	sock = socket(PF_INET, SOCK_RAW, 0);
247	if (geteuid() != 0) {
248		if (sock != -1)
249			errx(-1, "test_ip_hdrincl: created raw socket as "
250			    "uid %d", geteuid());
251		return;
252	}
253	if (sock == -1) {
254		perror("test_ip_hdrincl: socket(PF_INET, SOCK_RAW)");
255		exit(-1);
256	}
257
258	/*
259	 * Make sure the initial value of the flag is 0 (disabled).
260	 */
261	flag[0] = -1;
262	flag[1] = -1;
263	len = sizeof(flag);
264	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0) {
265		perror("test_ip_hdrincl: getsockopt(IP_HDRINCL) on raw");
266		exit(-1);
267	}
268
269	if (len != sizeof(flag[0])) {
270		fprintf(stderr, "test_ip_hdrincl: %d bytes returned on "
271		    "initial get\n", len);
272		exit(-1);
273	}
274
275	if (flag[0] != 0) {
276		fprintf(stderr, "test_ip_hdrincl: initial flag value of %d\n",
277		    flag[0]);
278		exit(-1);
279	}
280
281	/*
282	 * Enable the IP_HDRINCL flag.
283	 */
284	flag[0] = 1;
285	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
286	    < 0) {
287		perror("test_ip_hdrincl: setsockopt(IP_HDRINCL, 1)");
288		exit(-1);
289	}
290
291	/*
292	 * Check that the IP_HDRINCL flag was set.
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		perror("test_ip_hdrincl: getsockopt(IP_HDRINCL) after set");
299		exit(-1);
300	}
301
302	if (flag[0] == 0) {
303		fprintf(stderr, "test_ip_hdrincl: getsockopt(IP_HDRINCL) "
304		    "after set had flag of %d\n", flag[0]);
305		exit(-1);
306	}
307
308#define	HISTORICAL_INP_HDRINCL	8
309	if (flag[0] != HISTORICAL_INP_HDRINCL) {
310		fprintf(stderr, "test_ip_hdrincl: WARNING: getsockopt(IP_H"
311		    "DRINCL) after set had non-historical value of %d\n",
312		    flag[0]);
313	}
314
315	/*
316	 * Reset the IP_HDRINCL flag to 0.
317	 */
318	flag[0] = 0;
319	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
320	    < 0) {
321		perror("test_ip_hdrincl: setsockopt(IP_HDRINCL, 0)");
322		exit(-1);
323	}
324
325	/*
326	 * Check that the IP_HDRINCL flag was reset to 0.
327	 */
328	flag[0] = -1;
329	flag[1] = -1;
330	len = sizeof(flag);
331	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0) {
332		perror("test_ip_hdrincl: getsockopt(IP_HDRINCL) after reset");
333		exit(-1);
334	}
335
336	if (flag[0] != 0) {
337		fprintf(stderr, "test_ip_hdrincl: getsockopt(IP_HDRINCL) "
338		    "after set had flag of %d\n", flag[0]);
339		exit(-1);
340	}
341
342	close(sock);
343}
344
345/*
346 * As with other non-int or larger sized socket options, the IP_TOS and
347 * IP_TTL fields in kernel is stored as an 8-bit value, reflecting the IP
348 * header fields, but useful I/O to the field occurs using 32-bit integers.
349 * The FreeBSD kernel will permit writes from variables at least an int in
350 * size (and ignore additional bytes), and will permit a read to buffers 1
351 * byte or larger (but depending on endianness, may truncate out useful
352 * values if the caller provides less room).
353 *
354 * Given the limitations of the API, use a UDP socket to confirm that the
355 * following are true:
356 *
357 * - We can read the IP_TOS/IP_TTL options.
358 * - The initial value of the TOS option is 0, TTL is 64.
359 * - That if we provide more than 32 bits of storage, we get back only 32
360 *   bits of data.
361 * - When we set it to a non-zero value expressible with a u_char, we can
362 *   read that value back.
363 * - When we reset it back to zero, we can read it as 0.
364 * - When we set it to a value >255, the value is truncated to something less
365 *   than 255.
366 */
367static void
368test_ip_uchar(int option, char *optionname, int initial)
369{
370	int sock, val[2];
371	socklen_t len;
372
373	sock = socket(PF_INET, SOCK_DGRAM, 0);
374	if (sock == -1)
375		err(-1, "test_ip_tosttl(%s): socket", optionname);
376
377	/*
378	 * Check that the initial value is 0, and that the size is one
379	 * u_char;
380	 */
381	val[0] = -1;
382	val[1] = -1;
383	len = sizeof(val);
384	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
385		err(-1, "test_ip_tosttl: initial getsockopt(%s)",
386		    optionname);
387
388	if (len != sizeof(val[0]))
389		errx(-1, "test_ip_tosttl(%s): initial getsockopt() returned "
390		    "%d bytes", optionname, len);
391
392	if (val[0] == -1)
393		errx(-1, "test_ip_tosttl(%s): initial getsockopt() didn't "
394		    "return data", optionname);
395
396	if (val[0] != initial)
397		errx(-1, "test_ip_tosttl(%s): initial getsockopt() returned "
398		   "value of %d, not %d", optionname, val[0], initial);
399
400	/*
401	 * Set the field to a valid value.
402	 */
403	val[0] = 128;
404	val[1] = -1;
405	if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0)
406		err(-1, "test_ip_tosttl(%s): setsockopt(128)", optionname);
407
408	/*
409	 * Check that when we read back the field, we get the same value.
410	 */
411	val[0] = -1;
412	val[1] = -1;
413	len = sizeof(val);
414	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
415		err(-1, "test_ip_tosttl(%s): getsockopt() after set to 128",
416		    optionname);
417
418	if (len != sizeof(val[0]))
419		errx(-1, "test_ip_tosttl(%s): getsockopt() after set to 128 "
420		    "returned %d bytes", optionname, len);
421
422	if (val[0] == -1)
423		errx(-1, "test_ip_tosttl(%s): getsockopt() after set to 128 "
424		    "didn't return data", optionname);
425
426	if (val[0] != 128)
427		errx(-1, "test_ip_tosttl(%s): getsockopt() after set to 128 "
428		    "returned %d", optionname, val[0]);
429
430	/*
431	 * Reset the value to 0, check that it was reset.
432	 */
433	val[0] = 0;
434	val[1] = 0;
435	if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0)
436		err(-1, "test_ip_tosttl(%s): setsockopt() to reset from 128",
437		    optionname);
438
439	if (len != sizeof(val[0]))
440		errx(-1, "test_ip_tosttl(%s): getsockopt() after reset from "
441		    "128 returned %d bytes", optionname, len);
442
443	if (val[0] == -1)
444		errx(-1, "test_ip_tosttl(%s): getsockopt() after reset from "
445		    "128 didn't return data", optionname);
446
447	if (val[0] != 0)
448		errx(-1, "test_ip_tosttl(%s): getsockopt() after reset from "
449		    "128 returned %d", optionname, val[0]);
450
451	/*
452	 * Set the value to something out of range and check that it comes
453	 * back truncated, or that we get EINVAL back.  Traditional u_char
454	 * IP socket options truncate, but newer ones (such as multicast
455	 * socket options) will return EINVAL.
456	 */
457	val[0] = 32000;
458	val[1] = -1;
459	if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0) {
460		/*
461		 * EINVAL is a fine outcome, no need to run the truncation
462		 * tests.
463		 */
464		if (errno == EINVAL) {
465			close(sock);
466			return;
467		}
468		err(-1, "test_ip_tosttl(%s): getsockopt(32000)", optionname);
469	}
470
471	val[0] = -1;
472	val[1] = -1;
473	len = sizeof(val);
474	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
475		err(-1, "test_ip_tosttl(%s): getsockopt() after set to 32000",
476		    optionname);
477
478	if (len != sizeof(val[0]))
479		errx(-1, "test_ip_tosttl(%s): getsockopt() after set to 32000"
480		    "returned %d bytes",  optionname, len);
481
482	if (val[0] == -1)
483		errx(-1, "test_ip_tosttl(%s): getsockopt() after set to 32000"
484		    "didn't return data", optionname);
485
486	if (val[0] == 32000)
487		errx(-1, "test_ip_tosttl(%s): getsockopt() after set to 32000"
488		    "returned 32000: failed to truncate", optionname);
489
490	close(sock);
491}
492
493/*
494 * Generic test for a boolean socket option.  Caller provides the option
495 * number, string name, expected default (initial) value, and whether or not
496 * the option is root-only.  For each option, test:
497 *
498 * - That we can read the option.
499 * - That the initial value is as expected.
500 * - That we can modify the value.
501 * - That on modification, the new value can be read back.
502 * - That we can reset the value.
503 * - that on reset, the new value can be read back.
504 *
505 * Test using a UDP socket.
506 */
507#define	BOOLEAN_ANYONE		1
508#define	BOOLEAN_ROOTONLY	1
509static void
510test_ip_boolean(int option, char *optionname, int initial, int rootonly)
511{
512	int newvalue, sock, val[2];
513	socklen_t len;
514
515	sock = socket(PF_INET, SOCK_DGRAM, 0);
516	if (sock == -1)
517		err(-1, "test_ip_boolean(%s): socket", optionname);
518
519	/*
520	 * The default for a boolean might be true or false.  If it's false,
521	 * we will try setting it to true (but using a non-1 value of true).
522	 * If it's true, we'll set it to false.
523	 */
524	if (initial == 0)
525		newvalue = 0xff;
526	else
527		newvalue = 0;
528
529	val[0] = -1;
530	val[1] = -1;
531	len = sizeof(val);
532	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
533		err(-1, "test_ip_boolean: initial getsockopt()");
534
535	if (len != sizeof(val[0]))
536		errx(-1, "test_ip_boolean(%s): initial getsockopt() returned "
537		   "%d bytes", optionname, len);
538
539	if (val[0] == -1)
540		errx(-1, "test_ip_boolean(%s): initial getsockopt() didn't "
541		    "return data", optionname);
542
543	if (val[0] != initial)
544		errx(-1, "test_ip_boolean(%s): initial getsockopt() returned "
545		    "%d (expected %d)", optionname, val[0], initial);
546
547	/*
548	 * Set the socket option to a new non-default value.
549	 */
550	if (setsockopt(sock, IPPROTO_IP, option, &newvalue, sizeof(newvalue))
551	    < 0)
552		err(-1, "test_ip_boolean(%s): setsockopt() to %d", optionname,
553		    newvalue);
554
555	/*
556	 * Read the value back and see if it is not the default (note: will
557	 * not be what we set it to, as we set it to 0xff above).
558	 */
559	val[0] = -1;
560	val[1] = -1;
561	len = sizeof(val);
562	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
563		err(-1, "test_ip_boolean(%s): getsockopt() after set to %d",
564		    optionname, newvalue);
565
566	if (len != sizeof(val[0]))
567		errx(-1, "test_ip_boolean(%s): getsockopt() after set to %d "
568		    "returned %d bytes", optionname, newvalue, len);
569
570	if (val[0] == -1)
571		errx(-1, "test_ip_boolean(%s): getsockopt() after set to %d "
572		    "didn't return data", optionname, newvalue);
573
574	/*
575	 * If we set it to true, check for '1', otherwise '0.
576	 */
577	if (val[0] != (newvalue ? 1 : 0))
578		errx(-1, "test_ip_boolean(%s): getsockopt() after set to %d "
579		    "returned %d", optionname, newvalue, val[0]);
580
581	/*
582	 * Reset to initial value.
583	 */
584	newvalue = initial;
585	if (setsockopt(sock, IPPROTO_IP, option, &newvalue, sizeof(newvalue))
586	    < 0)
587		err(-1, "test_ip_boolean(%s): setsockopt() to reset",
588		    optionname);
589
590	/*
591	 * Check reset version.
592	 */
593	val[0] = -1;
594	val[1] = -1;
595	len = sizeof(val);
596	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
597		err(-1, "test_ip_boolean(%s): getsockopt() after reset",
598		    optionname);
599
600	if (len != sizeof(val[0]))
601		errx(-1, "test_ip_boolean(%s): getsockopt() after reset "
602		    "returned %d bytes", optionname, len);
603
604	if (val[0] == -1)
605		errx(-1, "test_ip_boolean(%s): getsockopt() after reset "
606		    "didn't return data", optionname);
607
608	if (val[0] != newvalue)
609		errx(-1, "test_ip_boolean(%s): getsockopt() after reset "
610		    "returned %d", optionname, newvalue);
611
612	close(sock);
613}
614
615/*
616 * XXX: For now, nothing here.
617 */
618static void
619test_ip_multicast_if(void)
620{
621
622	/*
623	 * It's probably worth trying INADDR_ANY and INADDR_LOOPBACK here
624	 * to see what happens.
625	 */
626}
627
628/*
629 * XXX: For now, nothing here.
630 */
631static void
632test_ip_multicast_vif(void)
633{
634
635	/*
636	 * This requires some knowledge of the number of virtual interfaces,
637	 * and what is valid.
638	 */
639}
640
641/*
642 * XXX: For now, nothing here.
643 */
644static void
645test_ip_multicast_membership(void)
646{
647
648}
649
650static void
651test_ip_multicast(void)
652{
653
654	test_ip_multicast_if();
655	test_ip_multicast_vif();
656
657	/*
658	 * Test the multicast TTL exactly as we would the regular TTL, only
659	 * expect a different default.
660	 */
661	test_ip_uchar(IP_MULTICAST_TTL, "IP_MULTICAST_TTL", 1);
662
663	/*
664	 * The multicast loopback flag can be tested using our boolean
665	 * tester, but only because the FreeBSD API is a bit more flexible
666	 * than earlir APIs and will accept an int as well as a u_char.
667	 * Loopback is enabled by default.
668	 */
669	test_ip_boolean(IP_MULTICAST_LOOP, "IP_MULTICAST_LOOP", 1,
670	    BOOLEAN_ANYONE);
671
672	test_ip_multicast_membership();
673}
674
675static void
676testsuite(void)
677{
678
679	test_ip_hdrincl();
680
681	test_ip_uchar(IP_TOS, "IP_TOS", 0);
682	test_ip_uchar(IP_TTL, "IP_TTL", 64);
683
684	test_ip_boolean(IP_RECVOPTS, "IP_RECVOPTS", 0, BOOLEAN_ANYONE);
685	test_ip_boolean(IP_RECVRETOPTS, "IP_RECVRETOPTS", 0, BOOLEAN_ANYONE);
686	test_ip_boolean(IP_RECVDSTADDR, "IP_RECVDSTADDR", 0, BOOLEAN_ANYONE);
687	test_ip_boolean(IP_RECVTTL, "IP_RECVTTL", 0, BOOLEAN_ANYONE);
688	test_ip_boolean(IP_RECVIF, "IP_RECVIF", 0, BOOLEAN_ANYONE);
689	test_ip_boolean(IP_FAITH, "IP_FAITH", 0, BOOLEAN_ANYONE);
690	test_ip_boolean(IP_ONESBCAST, "IP_ONESBCAST", 0, BOOLEAN_ANYONE);
691
692	/*
693	 * XXX: Still need to test:
694	 * IP_PORTRANGE
695	 * IP_IPSEC_POLICY?
696	 */
697
698	test_ip_multicast();
699
700	test_ip_options();
701}
702
703/*
704 * Very simply exercise that we can get and set each option.  If we're running
705 * as root, run it also as nobody.  If not as root, complain about that.
706 */
707int
708main(int argc, char *argv[])
709{
710
711	if (geteuid() != 0) {
712		warnx("Not running as root, can't run as-root tests");
713		fprintf(stderr, "\n");
714		fprintf(stderr, "Running tests with uid %d\n", geteuid());
715		testsuite();
716		fprintf(stderr, "PASS\n");
717	} else {
718		fprintf(stderr, "Running tests with uid 0\n");
719		testsuite();
720		if (setuid(65534) != 0)
721			err(-1, "setuid(65534)");
722		fprintf(stderr, "Running tests with uid 65535\n");
723		testsuite();
724		fprintf(stderr, "PASS\n");
725	}
726	exit(0);
727}
728