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