xref: /freebsd/tools/regression/netinet/ipsockopt/ipsockopt.c (revision 2b8331622f0b212cf3bb4fc4914a501e5321d506)
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 #include <arpa/inet.h>
36 
37 #include <err.h>
38 #include <errno.h>
39 #include <getopt.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 
45 static int dorandom = 0;
46 static int nmcastgroups = IP_MAX_MEMBERSHIPS;
47 static int verbose = 0;
48 
49 /*
50  * The test tool exercises IP-level socket options by interrogating the
51  * getsockopt()/setsockopt() APIs.  It does not currently test that the
52  * intended semantics of each option are implemented (i.e., that setting IP
53  * options on the socket results in packets with the desired IP options in
54  * it).
55  */
56 
57 /*
58  * get_socket() is a wrapper function that returns a socket of the specified
59  * type, and created with or without restored root privilege (if running
60  * with a real uid of root and an effective uid of some other user).  This
61  * us to test whether the same rights are granted using a socket with a
62  * privileged cached credential vs. a socket with a regular credential.
63  */
64 #define	PRIV_ASIS	0
65 #define	PRIV_GETROOT	1
66 static int
67 get_socket_unpriv(int type)
68 {
69 
70 	return (socket(PF_INET, type, 0));
71 }
72 
73 static int
74 get_socket_priv(int type)
75 {
76 	uid_t olduid;
77 	int sock;
78 
79 	if (getuid() != 0)
80 		errx(-1, "get_sock_priv: running without real uid 0");
81 
82 	olduid = geteuid();
83 	if (seteuid(0) < 0)
84 		err(-1, "get_sock_priv: seteuid(0)");
85 
86 	sock = socket(PF_INET, type, 0);
87 
88 	if (seteuid(olduid) < 0)
89 		err(-1, "get_sock_priv: seteuid(%d)", olduid);
90 
91 	return (sock);
92 }
93 
94 static int
95 get_socket(int type, int priv)
96 {
97 
98 	if (priv)
99 		return (get_socket_priv(type));
100 	else
101 		return (get_socket_unpriv(type));
102 }
103 
104 /*
105  * Exercise the IP_OPTIONS socket option.  Confirm the following properties:
106  *
107  * - That there is no initial set of options (length returned is 0).
108  * - That if we set a specific set of options, we can read it back.
109  * - That if we then reset the options, they go away.
110  *
111  * Use a UDP socket for this.
112  */
113 static void
114 test_ip_options(int sock, const char *socktypename)
115 {
116 	u_int32_t new_options, test_options[2];
117 	socklen_t len;
118 
119 	/*
120 	 * Start off by confirming the default IP options on a socket are to
121 	 * have no options set.
122 	 */
123 	len = sizeof(test_options);
124 	if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
125 		err(-1, "test_ip_options(%s): initial getsockopt()",
126 		    socktypename);
127 
128 	if (len != 0)
129 		errx(-1, "test_ip_options(%s): initial getsockopt() returned "
130 		    "%d bytes", socktypename, len);
131 
132 #define	TEST_MAGIC	0xc34e4212
133 #define	NEW_OPTIONS	htonl(IPOPT_EOL | (IPOPT_NOP << 8) | (IPOPT_NOP << 16) \
134 			 | (IPOPT_NOP << 24))
135 
136 	/*
137 	 * Write some new options into the socket.
138 	 */
139 	new_options = NEW_OPTIONS;
140 	if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, &new_options,
141 	    sizeof(new_options)) < 0)
142 		err(-1, "test_ip_options(%s): setsockopt(NOP|NOP|NOP|EOL)",
143 		    socktypename);
144 
145 	/*
146 	 * Store some random cruft in a local variable and retrieve the
147 	 * options to make sure they set.  Note that we pass in an array
148 	 * of u_int32_t's so that if whatever ended up in the option was
149 	 * larger than what we put in, we find out about it here.
150 	 */
151 	test_options[0] = TEST_MAGIC;
152 	test_options[1] = TEST_MAGIC;
153 	len = sizeof(test_options);
154 	if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
155 		err(-1, "test_ip_options(%s): getsockopt() after set",
156 		    socktypename);
157 
158 	/*
159 	 * Getting the right amount back is important.
160 	 */
161 	if (len != sizeof(new_options))
162 		errx(-1, "test_ip_options(%s): getsockopt() after set "
163 		    "returned %d bytes of data", socktypename, len);
164 
165 	/*
166 	 * One possible failure mode is that the call succeeds but neglects to
167 	 * copy out the data.
168  	 */
169 	if (test_options[0] == TEST_MAGIC)
170 		errx(-1, "test_ip_options(%s): getsockopt() after set didn't "
171 		    "return data", socktypename);
172 
173 	/*
174 	 * Make sure we get back what we wrote on.
175 	 */
176 	if (new_options != test_options[0])
177 		errx(-1, "test_ip_options(%s): getsockopt() after set "
178 		    "returned wrong options (%08x, %08x)", socktypename,
179 		    new_options, test_options[0]);
180 
181 	/*
182 	 * Now we reset the value to make sure clearing works.
183 	 */
184 	if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, NULL, 0) < 0)
185 		err(-1, "test_ip_options(%s): setsockopt() to reset",
186 		    socktypename);
187 
188 	/*
189 	 * Make sure it was really cleared.
190 	 */
191 	test_options[0] = TEST_MAGIC;
192 	test_options[1] = TEST_MAGIC;
193 	len = sizeof(test_options);
194 	if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
195 		err(-1, "test_ip_options(%s): getsockopt() after reset",
196 		    socktypename);
197 
198 	if (len != 0)
199 		errx(-1, "test_ip_options(%s): getsockopt() after reset "
200 		    "returned %d bytes", socktypename, len);
201 }
202 
203 /*
204  * This test checks the behavior of the IP_HDRINCL socket option, which
205  * allows users with privilege to specify the full header on an IP raw
206  * socket.  We test that the option can only be used with raw IP sockets, not
207  * with UDP or TCP sockets.  We also confirm that the raw socket is only
208  * available to a privileged user (subject to the UID when called).  We
209  * confirm that it defaults to off
210  *
211  * Unlike other tests, doesn't use caller-provided socket.  Probably should
212  * be fixed.
213  */
214 static void
215 test_ip_hdrincl(void)
216 {
217 	int flag[2], sock;
218 	socklen_t len;
219 
220 	/*
221 	 * Try to receive or set the IP_HDRINCL flag on a TCP socket.
222 	 */
223 	sock = socket(PF_INET, SOCK_STREAM, 0);
224 	if (sock == -1)
225 		err(-1, "test_ip_hdrincl(): socket(SOCK_STREAM)");
226 
227 	flag[0] = -1;
228 	len = sizeof(flag[0]);
229 	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0)
230 		err(-1, "test_ip_hdrincl(): initial getsockopt(IP_HDRINCL)");
231 
232 	if (errno != ENOPROTOOPT)
233 		errx(-1, "test_ip_hdrincl(): initial getsockopt(IP_HDRINC) "
234 		    "returned %d (%s) not ENOPROTOOPT", errno,
235 		    strerror(errno));
236 
237 	flag[0] = 1;
238 	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
239 	    == 0)
240 		err(-1,"test_ip_hdrincl(): setsockopt(IP_HDRINCL) on TCP "
241 		    "succeeded\n");
242 
243 	if (errno != ENOPROTOOPT)
244 		errx(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on TCP "
245 		    "returned %d (%s) not ENOPROTOOPT\n", errno,
246 		    strerror(errno));
247 
248 	close(sock);
249 
250 	/*
251 	 * Try to receive or set the IP_HDRINCL flag on a UDP socket.
252 	 */
253 	sock = socket(PF_INET, SOCK_DGRAM, 0);
254 	if (sock == -1)
255 		err(-1, "test_ip_hdrincl(): socket(SOCK_DGRAM");
256 
257 	flag[0] = -1;
258 	len = sizeof(flag[0]);
259 	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0)
260 		err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on UDP "
261 		    "succeeded\n");
262 
263 	if (errno != ENOPROTOOPT)
264 		errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on UDP "
265 		    "returned %d (%s) not ENOPROTOOPT\n", errno,
266 		    strerror(errno));
267 
268 	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
269 	    == 0)
270 		err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on UDP "
271 		    "succeeded\n");
272 
273 	if (errno != ENOPROTOOPT)
274 		errx(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on UDP "
275 		    "returned %d (%s) not ENOPROTOOPT\n", errno,
276 		    strerror(errno));
277 
278 	close(sock);
279 
280 	/*
281 	 * Now try on a raw socket.  Access ontrol should prevent non-root
282 	 * users from creating the raw socket, so check that here based on
283 	 * geteuid().  If we're non-root, we just return assuming the socket
284 	 * create fails since the remainder of the tests apply only on a raw
285 	 * socket.
286 	 */
287 	sock = socket(PF_INET, SOCK_RAW, 0);
288 	if (geteuid() != 0) {
289 		if (sock != -1)
290 			errx(-1, "test_ip_hdrincl: created raw socket as "
291 			    "uid %d", geteuid());
292 		return;
293 	}
294 	if (sock == -1)
295 		err(-1, "test_ip_hdrincl(): socket(PF_INET, SOCK_RAW)");
296 
297 	/*
298 	 * Make sure the initial value of the flag is 0 (disabled).
299 	 */
300 	flag[0] = -1;
301 	flag[1] = -1;
302 	len = sizeof(flag);
303 	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)
304 		err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on raw "
305 		    "socket");
306 
307 	if (len != sizeof(flag[0]))
308 		errx(-1, "test_ip_hdrincl(): %d bytes returned on "
309 		    "initial get\n", len);
310 
311 	if (flag[0] != 0)
312 		errx(-1, "test_ip_hdrincl(): initial flag value of %d\n",
313 		    flag[0]);
314 
315 	/*
316 	 * Enable the IP_HDRINCL flag.
317 	 */
318 	flag[0] = 1;
319 	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
320 	    < 0)
321 		err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL, 1)");
322 
323 	/*
324 	 * Check that the IP_HDRINCL flag was set.
325 	 */
326 	flag[0] = -1;
327 	flag[1] = -1;
328 	len = sizeof(flag);
329 	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)
330 		err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) after "
331 		    "set");
332 
333 	if (flag[0] == 0)
334 		errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) "
335 		    "after set had flag of %d\n", flag[0]);
336 
337 #define	HISTORICAL_INP_HDRINCL	8
338 	if (flag[0] != HISTORICAL_INP_HDRINCL)
339 		warnx("test_ip_hdrincl(): WARNING: getsockopt(IP_H"
340 		    "DRINCL) after set had non-historical value of %d\n",
341 		    flag[0]);
342 
343 	/*
344 	 * Reset the IP_HDRINCL flag to 0.
345 	 */
346 	flag[0] = 0;
347 	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
348 	    < 0)
349 		err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL, 0)");
350 
351 	/*
352 	 * Check that the IP_HDRINCL flag was reset to 0.
353 	 */
354 	flag[0] = -1;
355 	flag[1] = -1;
356 	len = sizeof(flag);
357 	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)
358 		err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) after "
359 		    "reset");
360 
361 	if (flag[0] != 0)
362 		errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) "
363 		    "after set had flag of %d\n", flag[0]);
364 
365 	close(sock);
366 }
367 
368 /*
369  * As with other non-int or larger sized socket options, the IP_TOS and
370  * IP_TTL fields in kernel is stored as an 8-bit value, reflecting the IP
371  * header fields, but useful I/O to the field occurs using 32-bit integers.
372  * The FreeBSD kernel will permit writes from variables at least an int in
373  * size (and ignore additional bytes), and will permit a read to buffers 1
374  * byte or larger (but depending on endianness, may truncate out useful
375  * values if the caller provides less room).
376  *
377  * Given the limitations of the API, use a UDP socket to confirm that the
378  * following are true:
379  *
380  * - We can read the IP_TOS/IP_TTL options.
381  * - The initial value of the TOS option is 0, TTL is 64.
382  * - That if we provide more than 32 bits of storage, we get back only 32
383  *   bits of data.
384  * - When we set it to a non-zero value expressible with a u_char, we can
385  *   read that value back.
386  * - When we reset it back to zero, we can read it as 0.
387  * - When we set it to a value >255, the value is truncated to something less
388  *   than 255.
389  */
390 static void
391 test_ip_uchar(int sock, const char *socktypename, int option,
392     const char *optionname, int initial)
393 {
394 	int val[2];
395 	socklen_t len;
396 
397 	/*
398 	 * Check that the initial value is 0, and that the size is one
399 	 * u_char;
400 	 */
401 	val[0] = -1;
402 	val[1] = -1;
403 	len = sizeof(val);
404 	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
405 		err(-1, "test_ip_uchar(%s, %s): initial getsockopt()",
406 		    socktypename, optionname);
407 
408 	if (len != sizeof(val[0]))
409 		errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() "
410 		    "returned %d bytes", socktypename, optionname, len);
411 
412 	if (val[0] == -1)
413 		errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() didn't "
414 		    "return data", socktypename, optionname);
415 
416 	if (val[0] != initial)
417 		errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() "
418 		    "returned value of %d, not %d", socktypename, optionname,
419 		    val[0], initial);
420 
421 	/*
422 	 * Set the field to a valid value.
423 	 */
424 	val[0] = 128;
425 	val[1] = -1;
426 	if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0)
427 		err(-1, "test_ip_uchar(%s, %s): setsockopt(128)",
428 		    socktypename, optionname);
429 
430 	/*
431 	 * Check that when we read back the field, we get the same value.
432 	 */
433 	val[0] = -1;
434 	val[1] = -1;
435 	len = sizeof(val);
436 	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
437 		err(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
438 		    "128", socktypename, optionname);
439 
440 	if (len != sizeof(val[0]))
441 		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
442 		    "128 returned %d bytes", socktypename, optionname, len);
443 
444 	if (val[0] == -1)
445 		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
446 		    "128 didn't return data", socktypename, optionname);
447 
448 	if (val[0] != 128)
449 		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
450 		    "128 returned %d", socktypename, optionname, val[0]);
451 
452 	/*
453 	 * Reset the value to 0, check that it was reset.
454 	 */
455 	val[0] = 0;
456 	val[1] = 0;
457 	if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0)
458 		err(-1, "test_ip_uchar(%s, %s): setsockopt() to reset from "
459 		    "128", socktypename, optionname);
460 
461 	if (len != sizeof(val[0]))
462 		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "
463 		   "from 128 returned %d bytes", socktypename, optionname,
464 		    len);
465 
466 	if (val[0] == -1)
467 		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "
468 		    "from 128 didn't return data", socktypename, optionname);
469 
470 	if (val[0] != 0)
471 		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "
472 		    "from 128 returned %d", socktypename, optionname,
473 		    val[0]);
474 
475 	/*
476 	 * Set the value to something out of range and check that it comes
477 	 * back truncated, or that we get EINVAL back.  Traditional u_char
478 	 * IP socket options truncate, but newer ones (such as multicast
479 	 * socket options) will return EINVAL.
480 	 */
481 	val[0] = 32000;
482 	val[1] = -1;
483 	if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0) {
484 		/*
485 		 * EINVAL is a fine outcome, no need to run the truncation
486 		 * tests.
487 		 */
488 		if (errno == EINVAL)
489 			return;
490 		err(-1, "test_ip_uchar(%s, %s): getsockopt(32000)",
491 		    socktypename, optionname);
492 	}
493 
494 	val[0] = -1;
495 	val[1] = -1;
496 	len = sizeof(val);
497 	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
498 		err(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
499 		    "32000", socktypename, optionname);
500 
501 	if (len != sizeof(val[0]))
502 		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
503 		    "32000 returned %d bytes", socktypename, optionname,
504 		    len);
505 
506 	if (val[0] == -1)
507 		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
508 		    "32000 didn't return data", socktypename, optionname);
509 
510 	if (val[0] == 32000)
511 		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
512 		    "32000 returned 32000: failed to truncate", socktypename,
513 		    optionname);
514 }
515 
516 /*
517  * Generic test for a boolean socket option.  Caller provides the option
518  * number, string name, expected default (initial) value, and whether or not
519  * the option is root-only.  For each option, test:
520  *
521  * - That we can read the option.
522  * - That the initial value is as expected.
523  * - That we can modify the value.
524  * - That on modification, the new value can be read back.
525  * - That we can reset the value.
526  * - that on reset, the new value can be read back.
527  */
528 #define	BOOLEAN_ANYONE		1
529 #define	BOOLEAN_ROOTONLY	1
530 static void
531 test_ip_boolean(int sock, const char *socktypename, int option,
532     char *optionname, int initial, int rootonly)
533 {
534 	int newvalue, val[2];
535 	socklen_t len;
536 
537 	/*
538 	 * The default for a boolean might be true or false.  If it's false,
539 	 * we will try setting it to true (but using a non-1 value of true).
540 	 * If it's true, we'll set it to false.
541 	 */
542 	if (initial == 0)
543 		newvalue = 0xff;
544 	else
545 		newvalue = 0;
546 
547 	val[0] = -1;
548 	val[1] = -1;
549 	len = sizeof(val);
550 	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
551 		err(-1, "test_ip_boolean: initial getsockopt()");
552 
553 	if (len != sizeof(val[0]))
554 		errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "
555 		    "returned %d bytes", socktypename, optionname, len);
556 
557 	if (val[0] == -1)
558 		errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "
559 		    "didn't return data", socktypename, optionname);
560 
561 	if (val[0] != initial)
562 		errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "
563 		    "returned %d (expected %d)", socktypename, optionname,
564 		    val[0], initial);
565 
566 	/*
567 	 * Set the socket option to a new non-default value.
568 	 */
569 	if (setsockopt(sock, IPPROTO_IP, option, &newvalue, sizeof(newvalue))
570 	    < 0)
571 		err(-1, "test_ip_boolean(%s, %s): setsockopt() to %d",
572 		    socktypename, optionname, newvalue);
573 
574 	/*
575 	 * Read the value back and see if it is not the default (note: will
576 	 * not be what we set it to, as we set it to 0xff above).
577 	 */
578 	val[0] = -1;
579 	val[1] = -1;
580 	len = sizeof(val);
581 	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
582 		err(-1, "test_ip_boolean(%s, %s): getsockopt() after set to "
583 		    "%d", socktypename, optionname, newvalue);
584 
585 	if (len != sizeof(val[0]))
586 		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "
587 		    "to %d returned %d bytes", socktypename, optionname,
588 		    newvalue, len);
589 
590 	if (val[0] == -1)
591 		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "
592 		    "to %d didn't return data", socktypename, optionname,
593 		    newvalue);
594 
595 	/*
596 	 * If we set it to true, check for '1', otherwise '0.
597 	 */
598 	if (val[0] != (newvalue ? 1 : 0))
599 		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "
600 		    "to %d returned %d", socktypename, optionname, newvalue,
601 		    val[0]);
602 
603 	/*
604 	 * Reset to initial value.
605 	 */
606 	newvalue = initial;
607 	if (setsockopt(sock, IPPROTO_IP, option, &newvalue, sizeof(newvalue))
608 	    < 0)
609 		err(-1, "test_ip_boolean(%s, %s): setsockopt() to reset",
610 		    socktypename, optionname);
611 
612 	/*
613 	 * Check reset version.
614 	 */
615 	val[0] = -1;
616 	val[1] = -1;
617 	len = sizeof(val);
618 	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
619 		err(-1, "test_ip_boolean(%s, %s): getsockopt() after reset",
620 		    socktypename, optionname);
621 
622 	if (len != sizeof(val[0]))
623 		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "
624 		    "returned %d bytes", socktypename, optionname, len);
625 
626 	if (val[0] == -1)
627 		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "
628 		    "didn't return data", socktypename, optionname);
629 
630 	if (val[0] != newvalue)
631 		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "
632 		    "returned %d", socktypename, optionname, newvalue);
633 }
634 
635 /*
636  * Test the IP_ADD_MEMBERSHIP socket option, and the dynamic allocator
637  * for the imo_membership vector which now hangs off struct ip_moptions.
638  * We then call IP_DROP_MEMBERSHIP for each group so joined.
639  */
640 static void
641 test_ip_multicast_membership(int sock, const char *socktypename)
642 {
643     char addrbuf[16];
644     struct ip_mreq mreq;
645     uint32_t basegroup;
646     uint16_t i;
647     int sotype;
648     socklen_t sotypelen;
649 
650     sotypelen = sizeof(sotype);
651     if (getsockopt(sock, SOL_SOCKET, SO_TYPE, &sotype, &sotypelen) < 0)
652 	err(-1, "test_ip_multicast_membership(%s): so_type getsockopt()",
653 	    socktypename);
654     /*
655      * Do not perform the test for SOCK_STREAM sockets, as this makes
656      * no sense.
657      */
658     if (sotype == SOCK_STREAM)
659 	return;
660     /*
661      * The 224/8 range is administratively scoped and has special meaning,
662      * therefore it is not used for this test.
663      * If we were not told to be non-deterministic:
664      * Join multicast groups from 238.1.1.0 up to nmcastgroups.
665      * Otherwise, pick a multicast group ID in subnet 238/5 with 11 random
666      * bits in the middle, and join groups in linear order up to nmcastgroups.
667      */
668     if (dorandom) {
669 	/* be non-deterministic (for interactive operation; a fuller test) */
670 	srandomdev();
671 	basegroup = 0xEE000000;	/* 238.0.0.0 */
672 	basegroup |= ((random() % ((1 << 11) - 1)) << 16);	/* 11 bits */
673     } else {
674 	/* be deterministic (for automated operation) */
675 	basegroup = 0xEE010100;	/* 238.1.1.0 */
676     }
677     /*
678      * Join the multicast group(s) on the default multicast interface;
679      * this usually maps to the interface to which the default
680      * route is pointing.
681      */
682     for (i = 1; i < nmcastgroups+1; i++) {
683 	mreq.imr_multiaddr.s_addr = htonl((basegroup + i));
684 	mreq.imr_interface.s_addr = INADDR_ANY;
685 	inet_ntop(AF_INET, &mreq.imr_multiaddr, addrbuf, sizeof(addrbuf));
686 	if (verbose)
687 		fprintf(stderr, "IP_ADD_MEMBERSHIP %s INADDR_ANY\n", addrbuf);
688 	if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
689 		       sizeof(mreq)) < 0) {
690 		err(-1,
691 "test_ip_multicast_membership(%d, %s): failed IP_ADD_MEMBERSHIP (%s, %s)",
692 		    sock, socktypename, addrbuf, "INADDR_ANY");
693 	}
694     }
695     for (i = 1; i < nmcastgroups+1; i++) {
696 	mreq.imr_multiaddr.s_addr = htonl((basegroup + i));
697 	mreq.imr_interface.s_addr = INADDR_ANY;
698 	inet_ntop(AF_INET, &mreq.imr_multiaddr, addrbuf, sizeof(addrbuf));
699 	if (verbose)
700 		fprintf(stderr, "IP_DROP_MEMBERSHIP %s INADDR_ANY\n", addrbuf);
701 	if (setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq,
702 		       sizeof(mreq)) < 0) {
703 		err(-1,
704 "test_ip_multicast_membership(%d, %s): failed IP_DROP_MEMBERSHIP (%s, %s)",
705 		    sock, socktypename, addrbuf, "INADDR_ANY");
706 	}
707     }
708 }
709 
710 /*
711  * XXX: For now, nothing here.
712  */
713 static void
714 test_ip_multicast_if(int sock, const char *socktypename)
715 {
716 
717 	/*
718 	 * It's probably worth trying INADDR_ANY and INADDR_LOOPBACK here
719 	 * to see what happens.
720 	 */
721 }
722 
723 /*
724  * XXX: For now, nothing here.
725  */
726 static void
727 test_ip_multicast_vif(int sock, const char *socktypename)
728 {
729 
730 	/*
731 	 * This requires some knowledge of the number of virtual interfaces,
732 	 * and what is valid.
733 	 */
734 }
735 
736 static void
737 testsuite(int priv)
738 {
739 	const char *socktypenameset[] = {"SOCK_DGRAM", "SOCK_STREAM",
740 	    "SOCK_RAW"};
741 	int socktypeset[] = {SOCK_DGRAM, SOCK_STREAM, SOCK_RAW};
742 	const char *socktypename;
743 	int i, sock, socktype;
744 
745 	test_ip_hdrincl();
746 
747 	for (i = 0; i < sizeof(socktypeset)/sizeof(int); i++) {
748 		socktype = socktypeset[i];
749 		socktypename = socktypenameset[i];
750 
751 		/*
752 		 * If we can't acquire root privilege, we can't open raw
753 		 * sockets, so don't actually try.
754 		 */
755 		if (getuid() != 0 && socktype == SOCK_RAW)
756 			continue;
757 		if (geteuid() != 0 && !priv && socktype == SOCK_RAW)
758 			continue;
759 
760 		/*
761 		 * XXXRW: On 5.3, this seems not to work for SOCK_RAW.
762 		 */
763 		sock = get_socket(socktype, priv);
764 		if (sock == -1)
765 			err(-1, "get_socket(%s, %d) for test_ip_uchar(IP_TOS)",
766 			    socktypename, priv);
767 		test_ip_uchar(sock, socktypename, IP_TOS, "IP_TOS", 0);
768 		close(sock);
769 
770 		sock = get_socket(socktype, priv);
771 		if (sock == -1)
772 			err(-1, "get_socket(%s %d) for test_ip_uchar(IP_TTL)",
773 			    socktypename, priv);
774 		test_ip_uchar(sock, socktypename, IP_TTL, "IP_TTL", 64);
775 		close(sock);
776 
777 		sock = get_socket(socktype, priv);
778 		if (sock == -1)
779 			err(-1, "get_socket(%s, %d) for test_ip_boolean"
780 			    "(IP_RECVOPTS)", socktypename, priv);
781 		test_ip_boolean(sock, socktypename, IP_RECVOPTS,
782 		    "IP_RECVOPTS", 0, BOOLEAN_ANYONE);
783 		close(sock);
784 
785 		sock = get_socket(socktype, priv);
786 		if (sock == -1)
787 			err(-1, "get_socket(%s, %d) for test_ip_boolean"
788 			     "(IP_RECVRETOPTS)", socktypename, priv);
789 		test_ip_boolean(sock, socktypename, IP_RECVRETOPTS,
790 		    "IP_RECVRETOPTS", 0, BOOLEAN_ANYONE);
791 		close(sock);
792 
793 		sock = get_socket(socktype, priv);
794 		if (sock == -1)
795 			err(-1, "get_socket(%s, %d) for test_ip_boolean"
796 			    "(IP_RECVDSTADDR)", socktypename, priv);
797 		test_ip_boolean(sock, socktypename, IP_RECVDSTADDR,
798 		    "IP_RECVDSTADDR", 0, BOOLEAN_ANYONE);
799 		close(sock);
800 
801 		sock = get_socket(socktype, priv);
802 		if (sock == -1)
803 			err(-1, "get_socket(%s, %d) for test_ip_boolean"
804 			    "(IP_RECVTTL)", socktypename, priv);
805 		test_ip_boolean(sock, socktypename, IP_RECVTTL, "IP_RECVTTL",
806 		    0, BOOLEAN_ANYONE);
807 		close(sock);
808 
809 		sock = get_socket(socktype, priv);
810 		if (sock == -1)
811 			err(-1, "get_socket(%s, %d) for test_ip_boolean"
812 			    "(IP_RECVIF)", socktypename, priv);
813 		test_ip_boolean(sock, socktypename, IP_RECVIF, "IP_RECVIF",
814 		    0, BOOLEAN_ANYONE);
815 		close(sock);
816 
817 		sock = get_socket(socktype, priv);
818 		if (sock == -1)
819 			err(-1, "get_socket(%s, %d) for test_ip_boolean"
820 			    "(IP_FAITH)", socktypename, priv);
821 		test_ip_boolean(sock, socktypename, IP_FAITH, "IP_FAITH", 0,
822 		    BOOLEAN_ANYONE);
823 		close(sock);
824 
825 		sock = get_socket(socktype, priv);
826 		if (sock == -1)
827 			err(-1, "get_socket(%s, %d) for test_ip_boolean"
828 			    "(IP_ONESBCAST)", socktypename, priv);
829 		test_ip_boolean(sock, socktypename, IP_ONESBCAST,
830 		    "IP_ONESBCAST", 0, BOOLEAN_ANYONE);
831 		close(sock);
832 
833 		/*
834 		 * Test the multicast TTL exactly as we would the regular
835 		 * TTL, only expect a different default.
836 		 */
837 		sock = get_socket(socktype, priv);
838 		if (sock == -1)
839 			err(-1, "get_socket(%s, %d) for IP_MULTICAST_TTL",
840 			    socktypename, priv);
841 		test_ip_uchar(sock, socktypename, IP_MULTICAST_TTL,
842 		    "IP_MULTICAST_TTL", 1);
843 		close(sock);
844 
845 		/*
846 		 * The multicast loopback flag can be tested using our
847 		 * boolean tester, but only because the FreeBSD API is a bit
848 		 * more flexible than earlir APIs and will accept an int as
849 		 * well as a u_char.  Loopback is enabled by default.
850 		 */
851 		sock = get_socket(socktype, priv);
852 		if (sock == -1)
853 			err(-1, "get_socket(%s, %d) for IP_MULTICAST_LOOP",
854 			    socktypename, priv);
855 		test_ip_boolean(sock, socktypename, IP_MULTICAST_LOOP,
856 		    "IP_MULTICAST_LOOP", 1, BOOLEAN_ANYONE);
857 		close(sock);
858 
859 		sock = get_socket(socktype, priv);
860 		if (sock == -1)
861 			err(-1, "get_socket(%s, %d) for test_ip_options",
862 			    socktypename, priv);
863 		//test_ip_options(sock, socktypename);
864 		close(sock);
865 
866 		sock = get_socket(socktype, priv);
867 		if (sock == -1)
868 			err(-1, "get_socket(%s, %d) for test_ip_options",
869 			    socktypename, priv);
870 		test_ip_multicast_membership(sock, socktypename);
871 		close(sock);
872 
873 		test_ip_multicast_if(0, NULL);
874 		test_ip_multicast_vif(0, NULL);
875 		/*
876 		 * XXX: Still need to test:
877 		 * IP_PORTRANGE
878 		 * IP_IPSEC_POLICY?
879 		 */
880 	}
881 }
882 
883 static void
884 usage()
885 {
886 
887 	fprintf(stderr, "usage: ipsockopt [-M ngroups] [-r] [-v]\n");
888 	exit(EXIT_FAILURE);
889 }
890 
891 /*
892  * Very simply exercise that we can get and set each option.  If we're running
893  * as root, run it also as nobody.  If not as root, complain about that.
894  */
895 int
896 main(int argc, char *argv[])
897 {
898 	int ch;
899 
900 	while ((ch = getopt(argc, argv, "M:rv")) != -1) {
901 		switch (ch) {
902 		case 'M':
903 			nmcastgroups = atoi(optarg);
904 			break;
905 		case 'r':
906 			dorandom = 1;	/* introduce non-determinism */
907 			break;
908 		case 'v':
909 			verbose = 1;
910 			break;
911 		default:
912 			usage();
913 		}
914 	}
915 
916 	printf("1..1\n");
917 
918 	if (geteuid() != 0) {
919 		warnx("Not running as root, can't run tests as root");
920 		fprintf(stderr, "\n");
921 		fprintf(stderr,
922 		   "Running tests with uid %d sock uid %d\n", geteuid(),
923 		    geteuid());
924 		testsuite(PRIV_ASIS);
925 	} else {
926 		fprintf(stderr,
927 		    "Running tests with ruid %d euid %d sock uid 0\n",
928 		    getuid(), geteuid());
929 		testsuite(PRIV_ASIS);
930 		if (seteuid(65534) != 0)
931 			err(-1, "seteuid(65534)");
932 		fprintf(stderr,
933 		    "Running tests with ruid %d euid %d sock uid 65534\n",
934 		    getuid(), geteuid());
935 		testsuite(PRIV_ASIS);
936 		fprintf(stderr,
937 		    "Running tests with ruid %d euid %d sock uid 0\n",
938 		    getuid(), geteuid());
939 		testsuite(PRIV_GETROOT);
940 	}
941 	printf("ok 1 - ipsockopt\n");
942 	exit(0);
943 }
944