1239844Sdes/*-
2239844Sdes * Copyright (c) 2004 Robert N. M. Watson
3239844Sdes * All rights reserved.
4239844Sdes *
5239844Sdes * Redistribution and use in source and binary forms, with or without
6239844Sdes * modification, are permitted provided that the following conditions
7239844Sdes * are met:
8239844Sdes * 1. Redistributions of source code must retain the above copyright
9239844Sdes *    notice, this list of conditions and the following disclaimer.
10239844Sdes * 2. Redistributions in binary form must reproduce the above copyright
11239844Sdes *    notice, this list of conditions and the following disclaimer in the
12239844Sdes *    documentation and/or other materials provided with the distribution.
13239844Sdes *
14239844Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15239844Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16239844Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17239844Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18239844Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19239844Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20239844Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21239844Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22239844Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23239844Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24239844Sdes * SUCH DAMAGE.
25239844Sdes *
26239844Sdes * $FreeBSD$
27239844Sdes */
28295367Sdes
29295367Sdes#include <sys/types.h>
30239844Sdes#include <sys/socket.h>
31239844Sdes
32239844Sdes#include <netinet/in.h>
33239844Sdes#include <netinet/in_systm.h>
34239844Sdes#include <netinet/ip.h>
35239844Sdes#include <arpa/inet.h>
36239844Sdes
37239844Sdes#include <err.h>
38239844Sdes#include <errno.h>
39239844Sdes#include <getopt.h>
40239844Sdes#include <stdio.h>
41239844Sdes#include <stdlib.h>
42239844Sdes#include <string.h>
43239844Sdes#include <unistd.h>
44239844Sdes
45239844Sdesstatic int dorandom = 0;
46295367Sdesstatic int nmcastgroups = IP_MAX_MEMBERSHIPS;
47239844Sdesstatic int verbose = 0;
48239844Sdes
49239844Sdes/*
50248613Sdes * The test tool exercises IP-level socket options by interrogating the
51239844Sdes * getsockopt()/setsockopt() APIs.  It does not currently test that the
52239844Sdes * intended semantics of each option are implemented (i.e., that setting IP
53239844Sdes * options on the socket results in packets with the desired IP options in
54239844Sdes * it).
55239844Sdes */
56239844Sdes
57239844Sdes/*
58239844Sdes * get_socket() is a wrapper function that returns a socket of the specified
59239844Sdes * type, and created with or without restored root privilege (if running
60239844Sdes * with a real uid of root and an effective uid of some other user).  This
61239844Sdes * us to test whether the same rights are granted using a socket with a
62239844Sdes * privileged cached credential vs. a socket with a regular credential.
63239844Sdes */
64239844Sdes#define	PRIV_ASIS	0
65239844Sdes#define	PRIV_GETROOT	1
66239844Sdesstatic int
67239844Sdesget_socket_unpriv(int type)
68239844Sdes{
69239844Sdes
70239844Sdes	return (socket(PF_INET, type, 0));
71239844Sdes}
72239844Sdes
73239844Sdesstatic int
74239844Sdesget_socket_priv(int type)
75239844Sdes{
76239844Sdes	uid_t olduid;
77239844Sdes	int sock;
78239844Sdes
79239844Sdes	if (getuid() != 0)
80239844Sdes		errx(-1, "get_sock_priv: running without real uid 0");
81239844Sdes
82239844Sdes	olduid = geteuid();
83295367Sdes	if (seteuid(0) < 0)
84295367Sdes		err(-1, "get_sock_priv: seteuid(0)");
85295367Sdes
86295367Sdes	sock = socket(PF_INET, type, 0);
87295367Sdes
88295367Sdes	if (seteuid(olduid) < 0)
89295367Sdes		err(-1, "get_sock_priv: seteuid(%d)", olduid);
90295367Sdes
91295367Sdes	return (sock);
92295367Sdes}
93239844Sdes
94239844Sdesstatic int
95239844Sdesget_socket(int type, int priv)
96239844Sdes{
97239844Sdes
98239844Sdes	if (priv)
99239844Sdes		return (get_socket_priv(type));
100239844Sdes	else
101239844Sdes		return (get_socket_unpriv(type));
102239844Sdes}
103239844Sdes
104295367Sdes/*
105295367Sdes * Exercise the IP_OPTIONS socket option.  Confirm the following properties:
106323124Sdes *
107323124Sdes * - That there is no initial set of options (length returned is 0).
108323124Sdes * - That if we set a specific set of options, we can read it back.
109323124Sdes * - That if we then reset the options, they go away.
110323124Sdes *
111323124Sdes * Use a UDP socket for this.
112295367Sdes */
113295367Sdesstatic void
114295367Sdestest_ip_options(int sock, const char *socktypename)
115295367Sdes{
116295367Sdes	u_int32_t new_options, test_options[2];
117295367Sdes	socklen_t len;
118295367Sdes
119239844Sdes	/*
120295367Sdes	 * Start off by confirming the default IP options on a socket are to
121295367Sdes	 * have no options set.
122295367Sdes	 */
123295367Sdes	len = sizeof(test_options);
124295367Sdes	if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
125295367Sdes		err(-1, "test_ip_options(%s): initial getsockopt()",
126295367Sdes		    socktypename);
127295367Sdes
128295367Sdes	if (len != 0)
129295367Sdes		errx(-1, "test_ip_options(%s): initial getsockopt() returned "
130295367Sdes		    "%d bytes", socktypename, len);
131295367Sdes
132295367Sdes#define	TEST_MAGIC	0xc34e4212
133295367Sdes#define	NEW_OPTIONS	htonl(IPOPT_EOL | (IPOPT_NOP << 8) | (IPOPT_NOP << 16) \
134295367Sdes			 | (IPOPT_NOP << 24))
135295367Sdes
136295367Sdes	/*
137295367Sdes	 * Write some new options into the socket.
138295367Sdes	 */
139255767Sdes	new_options = NEW_OPTIONS;
140248613Sdes	if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, &new_options,
141295367Sdes	    sizeof(new_options)) < 0)
142239844Sdes		err(-1, "test_ip_options(%s): setsockopt(NOP|NOP|NOP|EOL)",
143264377Sdes		    socktypename);
144295367Sdes
145295367Sdes	/*
146239844Sdes	 * Store some random cruft in a local variable and retrieve the
147295367Sdes	 * options to make sure they set.  Note that we pass in an array
148295367Sdes	 * of u_int32_t's so that if whatever ended up in the option was
149295367Sdes	 * larger than what we put in, we find out about it here.
150295367Sdes	 */
151295367Sdes	test_options[0] = TEST_MAGIC;
152295367Sdes	test_options[1] = TEST_MAGIC;
153295367Sdes	len = sizeof(test_options);
154295367Sdes	if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
155295367Sdes		err(-1, "test_ip_options(%s): getsockopt() after set",
156296781Sdes		    socktypename);
157296781Sdes
158296781Sdes	/*
159295367Sdes	 * Getting the right amount back is important.
160295367Sdes	 */
161295367Sdes	if (len != sizeof(new_options))
162295367Sdes		errx(-1, "test_ip_options(%s): getsockopt() after set "
163239844Sdes		    "returned %d bytes of data", socktypename, len);
164248613Sdes
165248613Sdes	/*
166239844Sdes	 * One posible failure mode is that the call succeeds but neglects to
167248613Sdes	 * copy out the data.
168295367Sdes 	 */
169295367Sdes	if (test_options[0] == TEST_MAGIC)
170295367Sdes		errx(-1, "test_ip_options(%s): getsockopt() after set didn't "
171295367Sdes		    "return data", socktypename);
172295367Sdes
173295367Sdes	/*
174295367Sdes	 * Make sure we get back what we wrote on.
175239844Sdes	 */
176295367Sdes	if (new_options != test_options[0])
177295367Sdes		errx(-1, "test_ip_options(%s): getsockopt() after set "
178295367Sdes		    "returned wrong options (%08x, %08x)", socktypename,
179295367Sdes		    new_options, test_options[0]);
180295367Sdes
181295367Sdes	/*
182295367Sdes	 * Now we reset the value to make sure clearing works.
183295367Sdes	 */
184295367Sdes	if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, NULL, 0) < 0)
185295367Sdes		err(-1, "test_ip_options(%s): setsockopt() to reset",
186295367Sdes		    socktypename);
187295367Sdes
188295367Sdes	/*
189239844Sdes	 * Make sure it was really cleared.
190239844Sdes	 */
191295367Sdes	test_options[0] = TEST_MAGIC;
192295367Sdes	test_options[1] = TEST_MAGIC;
193295367Sdes	len = sizeof(test_options);
194295367Sdes	if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
195295367Sdes		err(-1, "test_ip_options(%s): getsockopt() after reset",
196295367Sdes		    socktypename);
197295367Sdes
198295367Sdes	if (len != 0)
199239844Sdes		errx(-1, "test_ip_options(%s): getsockopt() after reset "
200239844Sdes		    "returned %d bytes", socktypename, len);
201295367Sdes}
202295367Sdes
203295367Sdes/*
204295367Sdes * This test checks the behavior of the IP_HDRINCL socket option, which
205295367Sdes * allows users with privilege to specify the full header on an IP raw
206295367Sdes * socket.  We test that the option can only be used with raw IP sockets, not
207295367Sdes * with UDP or TCP sockets.  We also confirm that the raw socket is only
208295367Sdes * available to a privileged user (subject to the UID when called).  We
209295367Sdes * confirm that it defaults to off
210295367Sdes *
211295367Sdes * Unlike other tests, doesn't use caller-provided socket.  Probably should
212239844Sdes * be fixed.
213239844Sdes */
214239844Sdesstatic void
215239844Sdestest_ip_hdrincl(void)
216239844Sdes{
217239844Sdes	int flag[2], sock;
218239844Sdes	socklen_t len;
219239844Sdes
220239844Sdes	/*
221239844Sdes	 * Try to receive or set the IP_HDRINCL flag on a TCP socket.
222239844Sdes	 */
223239844Sdes	sock = socket(PF_INET, SOCK_STREAM, 0);
224239844Sdes	if (sock == -1)
225262566Sdes		err(-1, "test_ip_hdrincl(): socket(SOCK_STREAM)");
226239844Sdes
227239844Sdes	flag[0] = -1;
228239844Sdes	len = sizeof(flag[0]);
229239844Sdes	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0)
230239844Sdes		err(-1, "test_ip_hdrincl(): initial getsockopt(IP_HDRINCL)");
231239844Sdes
232239844Sdes	if (errno != ENOPROTOOPT)
233239844Sdes		errx(-1, "test_ip_hdrincl(): initial getsockopt(IP_HDRINC) "
234239844Sdes		    "returned %d (%s) not ENOPROTOOPT", errno,
235239844Sdes		    strerror(errno));
236239844Sdes
237239844Sdes	flag[0] = 1;
238239844Sdes	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
239239844Sdes	    == 0)
240239844Sdes		err(-1,"test_ip_hdrincl(): setsockopt(IP_HDRINCL) on TCP "
241239844Sdes		    "succeeded\n");
242239844Sdes
243239844Sdes	if (errno != ENOPROTOOPT)
244239844Sdes		errx(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on TCP "
245239844Sdes		    "returned %d (%s) not ENOPROTOOPT\n", errno,
246239844Sdes		    strerror(errno));
247239844Sdes
248239844Sdes	close(sock);
249239844Sdes
250239844Sdes	/*
251239844Sdes	 * Try to receive or set the IP_HDRINCL flag on a UDP socket.
252239844Sdes	 */
253239844Sdes	sock = socket(PF_INET, SOCK_DGRAM, 0);
254239844Sdes	if (sock == -1)
255239844Sdes		err(-1, "test_ip_hdrincl(): socket(SOCK_DGRAM");
256239844Sdes
257239844Sdes	flag[0] = -1;
258239844Sdes	len = sizeof(flag[0]);
259239844Sdes	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0)
260239844Sdes		err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on UDP "
261239844Sdes		    "succeeded\n");
262239844Sdes
263239844Sdes	if (errno != ENOPROTOOPT)
264239844Sdes		errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on UDP "
265239844Sdes		    "returned %d (%s) not ENOPROTOOPT\n", errno,
266239844Sdes		    strerror(errno));
267239844Sdes
268239844Sdes	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
269239844Sdes	    == 0)
270239844Sdes		err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on UDP "
271239844Sdes		    "succeeded\n");
272239844Sdes
273239844Sdes	if (errno != ENOPROTOOPT)
274239844Sdes		errx(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on UDP "
275239844Sdes		    "returned %d (%s) not ENOPROTOOPT\n", errno,
276239844Sdes		    strerror(errno));
277239844Sdes
278239844Sdes	close(sock);
279239844Sdes
280239844Sdes	/*
281239849Sdes	 * Now try on a raw socket.  Access ontrol should prevent non-root
282239844Sdes	 * users from creating the raw socket, so check that here based on
283239844Sdes	 * geteuid().  If we're non-root, we just return assuming the socket
284239844Sdes	 * create fails since the remainder of the tests apply only on a raw
285239844Sdes	 * socket.
286239844Sdes	 */
287239844Sdes	sock = socket(PF_INET, SOCK_RAW, 0);
288239844Sdes	if (geteuid() != 0) {
289239844Sdes		if (sock != -1)
290239844Sdes			errx(-1, "test_ip_hdrincl: created raw socket as "
291239844Sdes			    "uid %d", geteuid());
292239844Sdes		return;
293239844Sdes	}
294239844Sdes	if (sock == -1)
295239844Sdes		err(-1, "test_ip_hdrincl(): socket(PF_INET, SOCK_RAW)");
296239844Sdes
297239844Sdes	/*
298239844Sdes	 * Make sure the initial value of the flag is 0 (disabled).
299239844Sdes	 */
300239849Sdes	flag[0] = -1;
301239849Sdes	flag[1] = -1;
302239844Sdes	len = sizeof(flag);
303239849Sdes	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)
304239849Sdes		err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on raw "
305239844Sdes		    "socket");
306239844Sdes
307239849Sdes	if (len != sizeof(flag[0]))
308239844Sdes		errx(-1, "test_ip_hdrincl(): %d bytes returned on "
309239849Sdes		    "initial get\n", len);
310239849Sdes
311239849Sdes	if (flag[0] != 0)
312239844Sdes		errx(-1, "test_ip_hdrincl(): initial flag value of %d\n",
313239844Sdes		    flag[0]);
314239844Sdes
315239844Sdes	/*
316239844Sdes	 * Enable the IP_HDRINCL flag.
317239844Sdes	 */
318239844Sdes	flag[0] = 1;
319239844Sdes	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
320239844Sdes	    < 0)
321239844Sdes		err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL, 1)");
322239844Sdes
323239844Sdes	/*
324239844Sdes	 * Check that the IP_HDRINCL flag was set.
325239844Sdes	 */
326239844Sdes	flag[0] = -1;
327239844Sdes	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 */
390static void
391test_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
530static void
531test_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 */
640static void
641test_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 */
713static void
714test_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 */
726static void
727test_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
736static void
737testsuite(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
883static void
884usage()
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 */
895int
896main(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