1136384Srwatson/*-
2136384Srwatson * Copyright (c) 2004 Robert N. M. Watson
3136384Srwatson * All rights reserved.
4136384Srwatson *
5136384Srwatson * Redistribution and use in source and binary forms, with or without
6136384Srwatson * modification, are permitted provided that the following conditions
7136384Srwatson * are met:
8136384Srwatson * 1. Redistributions of source code must retain the above copyright
9136384Srwatson *    notice, this list of conditions and the following disclaimer.
10136384Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11136384Srwatson *    notice, this list of conditions and the following disclaimer in the
12136384Srwatson *    documentation and/or other materials provided with the distribution.
13136384Srwatson *
14136384Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15136384Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16136384Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17136384Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18136384Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19136384Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20136384Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21136384Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22136384Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23136384Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24136384Srwatson * SUCH DAMAGE.
25136384Srwatson *
26136384Srwatson * $FreeBSD$
27136384Srwatson */
28136384Srwatson
29136384Srwatson#include <sys/types.h>
30136384Srwatson#include <sys/socket.h>
31136384Srwatson
32136384Srwatson#include <netinet/in.h>
33136384Srwatson#include <netinet/in_systm.h>
34136384Srwatson#include <netinet/ip.h>
35166437Sbms#include <arpa/inet.h>
36136384Srwatson
37136384Srwatson#include <err.h>
38136384Srwatson#include <errno.h>
39166437Sbms#include <getopt.h>
40136384Srwatson#include <stdio.h>
41136384Srwatson#include <stdlib.h>
42136384Srwatson#include <string.h>
43136384Srwatson#include <unistd.h>
44136384Srwatson
45166437Sbmsstatic int dorandom = 0;
46166437Sbmsstatic int nmcastgroups = IP_MAX_MEMBERSHIPS;
47166437Sbmsstatic int verbose = 0;
48166437Sbms
49136384Srwatson/*
50136384Srwatson * The test tool exercises IP-level socket options by interrogating the
51136384Srwatson * getsockopt()/setsockopt() APIs.  It does not currently test that the
52136384Srwatson * intended semantics of each option are implemented (i.e., that setting IP
53136384Srwatson * options on the socket results in packets with the desired IP options in
54136384Srwatson * it).
55136384Srwatson */
56136384Srwatson
57136384Srwatson/*
58136390Srwatson * get_socket() is a wrapper function that returns a socket of the specified
59136390Srwatson * type, and created with or without restored root privilege (if running
60136390Srwatson * with a real uid of root and an effective uid of some other user).  This
61136390Srwatson * us to test whether the same rights are granted using a socket with a
62136390Srwatson * privileged cached credential vs. a socket with a regular credential.
63136390Srwatson */
64136390Srwatson#define	PRIV_ASIS	0
65136390Srwatson#define	PRIV_GETROOT	1
66136390Srwatsonstatic int
67136390Srwatsonget_socket_unpriv(int type)
68136390Srwatson{
69136390Srwatson
70136390Srwatson	return (socket(PF_INET, type, 0));
71136390Srwatson}
72136390Srwatson
73136390Srwatsonstatic int
74136390Srwatsonget_socket_priv(int type)
75136390Srwatson{
76136390Srwatson	uid_t olduid;
77136390Srwatson	int sock;
78136390Srwatson
79136390Srwatson	if (getuid() != 0)
80136390Srwatson		errx(-1, "get_sock_priv: running without real uid 0");
81136390Srwatson
82136390Srwatson	olduid = geteuid();
83136390Srwatson	if (seteuid(0) < 0)
84136390Srwatson		err(-1, "get_sock_priv: seteuid(0)");
85136390Srwatson
86136390Srwatson	sock = socket(PF_INET, type, 0);
87136390Srwatson
88136390Srwatson	if (seteuid(olduid) < 0)
89136390Srwatson		err(-1, "get_sock_priv: seteuid(%d)", olduid);
90136390Srwatson
91136390Srwatson	return (sock);
92136390Srwatson}
93136390Srwatson
94136390Srwatsonstatic int
95136390Srwatsonget_socket(int type, int priv)
96136390Srwatson{
97136390Srwatson
98136390Srwatson	if (priv)
99136390Srwatson		return (get_socket_priv(type));
100136390Srwatson	else
101136390Srwatson		return (get_socket_unpriv(type));
102136390Srwatson}
103136390Srwatson
104136390Srwatson/*
105136384Srwatson * Exercise the IP_OPTIONS socket option.  Confirm the following properties:
106136384Srwatson *
107136384Srwatson * - That there is no initial set of options (length returned is 0).
108136384Srwatson * - That if we set a specific set of options, we can read it back.
109136384Srwatson * - That if we then reset the options, they go away.
110136384Srwatson *
111136384Srwatson * Use a UDP socket for this.
112136384Srwatson */
113136384Srwatsonstatic void
114136390Srwatsontest_ip_options(int sock, const char *socktypename)
115136384Srwatson{
116136384Srwatson	u_int32_t new_options, test_options[2];
117136384Srwatson	socklen_t len;
118136384Srwatson
119136384Srwatson	/*
120136384Srwatson	 * Start off by confirming the default IP options on a socket are to
121136384Srwatson	 * have no options set.
122136384Srwatson	 */
123136384Srwatson	len = sizeof(test_options);
124136384Srwatson	if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
125136390Srwatson		err(-1, "test_ip_options(%s): initial getsockopt()",
126136390Srwatson		    socktypename);
127136384Srwatson
128136384Srwatson	if (len != 0)
129136390Srwatson		errx(-1, "test_ip_options(%s): initial getsockopt() returned "
130136390Srwatson		    "%d bytes", socktypename, len);
131136384Srwatson
132136384Srwatson#define	TEST_MAGIC	0xc34e4212
133136384Srwatson#define	NEW_OPTIONS	htonl(IPOPT_EOL | (IPOPT_NOP << 8) | (IPOPT_NOP << 16) \
134136384Srwatson			 | (IPOPT_NOP << 24))
135136384Srwatson
136136384Srwatson	/*
137136384Srwatson	 * Write some new options into the socket.
138136384Srwatson	 */
139136384Srwatson	new_options = NEW_OPTIONS;
140136384Srwatson	if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, &new_options,
141136384Srwatson	    sizeof(new_options)) < 0)
142136390Srwatson		err(-1, "test_ip_options(%s): setsockopt(NOP|NOP|NOP|EOL)",
143136390Srwatson		    socktypename);
144136384Srwatson
145136384Srwatson	/*
146136384Srwatson	 * Store some random cruft in a local variable and retrieve the
147136384Srwatson	 * options to make sure they set.  Note that we pass in an array
148136384Srwatson	 * of u_int32_t's so that if whatever ended up in the option was
149136384Srwatson	 * larger than what we put in, we find out about it here.
150136384Srwatson	 */
151136384Srwatson	test_options[0] = TEST_MAGIC;
152136384Srwatson	test_options[1] = TEST_MAGIC;
153136384Srwatson	len = sizeof(test_options);
154136384Srwatson	if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
155136390Srwatson		err(-1, "test_ip_options(%s): getsockopt() after set",
156136390Srwatson		    socktypename);
157136384Srwatson
158136384Srwatson	/*
159136384Srwatson	 * Getting the right amount back is important.
160136384Srwatson	 */
161136384Srwatson	if (len != sizeof(new_options))
162136390Srwatson		errx(-1, "test_ip_options(%s): getsockopt() after set "
163136390Srwatson		    "returned %d bytes of data", socktypename, len);
164136384Srwatson
165136384Srwatson	/*
166136384Srwatson	 * One posible failure mode is that the call succeeds but neglects to
167136384Srwatson	 * copy out the data.
168136384Srwatson 	 */
169136384Srwatson	if (test_options[0] == TEST_MAGIC)
170136390Srwatson		errx(-1, "test_ip_options(%s): getsockopt() after set didn't "
171136390Srwatson		    "return data", socktypename);
172136384Srwatson
173136384Srwatson	/*
174136384Srwatson	 * Make sure we get back what we wrote on.
175136384Srwatson	 */
176136384Srwatson	if (new_options != test_options[0])
177136390Srwatson		errx(-1, "test_ip_options(%s): getsockopt() after set "
178136390Srwatson		    "returned wrong options (%08x, %08x)", socktypename,
179136390Srwatson		    new_options, test_options[0]);
180136384Srwatson
181136384Srwatson	/*
182136384Srwatson	 * Now we reset the value to make sure clearing works.
183136384Srwatson	 */
184136384Srwatson	if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, NULL, 0) < 0)
185136390Srwatson		err(-1, "test_ip_options(%s): setsockopt() to reset",
186136390Srwatson		    socktypename);
187136384Srwatson
188136384Srwatson	/*
189136384Srwatson	 * Make sure it was really cleared.
190136384Srwatson	 */
191136384Srwatson	test_options[0] = TEST_MAGIC;
192136384Srwatson	test_options[1] = TEST_MAGIC;
193136384Srwatson	len = sizeof(test_options);
194136384Srwatson	if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
195136390Srwatson		err(-1, "test_ip_options(%s): getsockopt() after reset",
196136390Srwatson		    socktypename);
197136384Srwatson
198136384Srwatson	if (len != 0)
199136390Srwatson		errx(-1, "test_ip_options(%s): getsockopt() after reset "
200136390Srwatson		    "returned %d bytes", socktypename, len);
201136384Srwatson}
202136384Srwatson
203136384Srwatson/*
204136384Srwatson * This test checks the behavior of the IP_HDRINCL socket option, which
205136384Srwatson * allows users with privilege to specify the full header on an IP raw
206136384Srwatson * socket.  We test that the option can only be used with raw IP sockets, not
207136384Srwatson * with UDP or TCP sockets.  We also confirm that the raw socket is only
208136384Srwatson * available to a privileged user (subject to the UID when called).  We
209136384Srwatson * confirm that it defaults to off
210136390Srwatson *
211136390Srwatson * Unlike other tests, doesn't use caller-provided socket.  Probably should
212136390Srwatson * be fixed.
213136384Srwatson */
214136384Srwatsonstatic void
215136384Srwatsontest_ip_hdrincl(void)
216136384Srwatson{
217136384Srwatson	int flag[2], sock;
218136384Srwatson	socklen_t len;
219136384Srwatson
220136384Srwatson	/*
221136384Srwatson	 * Try to receive or set the IP_HDRINCL flag on a TCP socket.
222136384Srwatson	 */
223136384Srwatson	sock = socket(PF_INET, SOCK_STREAM, 0);
224136390Srwatson	if (sock == -1)
225136390Srwatson		err(-1, "test_ip_hdrincl(): socket(SOCK_STREAM)");
226136384Srwatson
227136384Srwatson	flag[0] = -1;
228136384Srwatson	len = sizeof(flag[0]);
229136390Srwatson	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0)
230136390Srwatson		err(-1, "test_ip_hdrincl(): initial getsockopt(IP_HDRINCL)");
231136384Srwatson
232136390Srwatson	if (errno != ENOPROTOOPT)
233136390Srwatson		errx(-1, "test_ip_hdrincl(): initial getsockopt(IP_HDRINC) "
234136390Srwatson		    "returned %d (%s) not ENOPROTOOPT", errno,
235136390Srwatson		    strerror(errno));
236136384Srwatson
237136384Srwatson	flag[0] = 1;
238136384Srwatson	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
239136390Srwatson	    == 0)
240136390Srwatson		err(-1,"test_ip_hdrincl(): setsockopt(IP_HDRINCL) on TCP "
241136390Srwatson		    "succeeded\n");
242136384Srwatson
243136390Srwatson	if (errno != ENOPROTOOPT)
244136390Srwatson		errx(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on TCP "
245136390Srwatson		    "returned %d (%s) not ENOPROTOOPT\n", errno,
246136390Srwatson		    strerror(errno));
247136384Srwatson
248136384Srwatson	close(sock);
249136384Srwatson
250136384Srwatson	/*
251136384Srwatson	 * Try to receive or set the IP_HDRINCL flag on a UDP socket.
252136384Srwatson	 */
253136384Srwatson	sock = socket(PF_INET, SOCK_DGRAM, 0);
254136390Srwatson	if (sock == -1)
255136390Srwatson		err(-1, "test_ip_hdrincl(): socket(SOCK_DGRAM");
256136384Srwatson
257136384Srwatson	flag[0] = -1;
258136384Srwatson	len = sizeof(flag[0]);
259136390Srwatson	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0)
260136390Srwatson		err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on UDP "
261136390Srwatson		    "succeeded\n");
262136384Srwatson
263136390Srwatson	if (errno != ENOPROTOOPT)
264136390Srwatson		errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on UDP "
265136390Srwatson		    "returned %d (%s) not ENOPROTOOPT\n", errno,
266136390Srwatson		    strerror(errno));
267136384Srwatson
268136384Srwatson	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
269136390Srwatson	    == 0)
270136390Srwatson		err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on UDP "
271136390Srwatson		    "succeeded\n");
272136384Srwatson
273136390Srwatson	if (errno != ENOPROTOOPT)
274136390Srwatson		errx(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on UDP "
275136390Srwatson		    "returned %d (%s) not ENOPROTOOPT\n", errno,
276136390Srwatson		    strerror(errno));
277136384Srwatson
278136384Srwatson	close(sock);
279136384Srwatson
280136384Srwatson	/*
281136384Srwatson	 * Now try on a raw socket.  Access ontrol should prevent non-root
282136384Srwatson	 * users from creating the raw socket, so check that here based on
283136384Srwatson	 * geteuid().  If we're non-root, we just return assuming the socket
284136384Srwatson	 * create fails since the remainder of the tests apply only on a raw
285136384Srwatson	 * socket.
286136384Srwatson	 */
287136384Srwatson	sock = socket(PF_INET, SOCK_RAW, 0);
288136384Srwatson	if (geteuid() != 0) {
289136384Srwatson		if (sock != -1)
290136384Srwatson			errx(-1, "test_ip_hdrincl: created raw socket as "
291136384Srwatson			    "uid %d", geteuid());
292136384Srwatson		return;
293136384Srwatson	}
294136390Srwatson	if (sock == -1)
295136390Srwatson		err(-1, "test_ip_hdrincl(): socket(PF_INET, SOCK_RAW)");
296136384Srwatson
297136384Srwatson	/*
298136384Srwatson	 * Make sure the initial value of the flag is 0 (disabled).
299136384Srwatson	 */
300136384Srwatson	flag[0] = -1;
301136384Srwatson	flag[1] = -1;
302136384Srwatson	len = sizeof(flag);
303136390Srwatson	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)
304136390Srwatson		err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on raw "
305136390Srwatson		    "socket");
306136384Srwatson
307136390Srwatson	if (len != sizeof(flag[0]))
308136390Srwatson		errx(-1, "test_ip_hdrincl(): %d bytes returned on "
309136384Srwatson		    "initial get\n", len);
310136384Srwatson
311136390Srwatson	if (flag[0] != 0)
312136390Srwatson		errx(-1, "test_ip_hdrincl(): initial flag value of %d\n",
313136384Srwatson		    flag[0]);
314136384Srwatson
315136384Srwatson	/*
316136384Srwatson	 * Enable the IP_HDRINCL flag.
317136384Srwatson	 */
318136384Srwatson	flag[0] = 1;
319136384Srwatson	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
320136390Srwatson	    < 0)
321136390Srwatson		err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL, 1)");
322136384Srwatson
323136384Srwatson	/*
324136384Srwatson	 * Check that the IP_HDRINCL flag was set.
325136384Srwatson	 */
326136384Srwatson	flag[0] = -1;
327136384Srwatson	flag[1] = -1;
328136384Srwatson	len = sizeof(flag);
329136390Srwatson	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)
330136390Srwatson		err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) after "
331136390Srwatson		    "set");
332136384Srwatson
333136390Srwatson	if (flag[0] == 0)
334136390Srwatson		errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) "
335136384Srwatson		    "after set had flag of %d\n", flag[0]);
336136384Srwatson
337136384Srwatson#define	HISTORICAL_INP_HDRINCL	8
338136390Srwatson	if (flag[0] != HISTORICAL_INP_HDRINCL)
339136390Srwatson		warnx("test_ip_hdrincl(): WARNING: getsockopt(IP_H"
340136384Srwatson		    "DRINCL) after set had non-historical value of %d\n",
341136384Srwatson		    flag[0]);
342136384Srwatson
343136384Srwatson	/*
344136384Srwatson	 * Reset the IP_HDRINCL flag to 0.
345136384Srwatson	 */
346136384Srwatson	flag[0] = 0;
347136384Srwatson	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
348136390Srwatson	    < 0)
349136390Srwatson		err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL, 0)");
350136384Srwatson
351136384Srwatson	/*
352136384Srwatson	 * Check that the IP_HDRINCL flag was reset to 0.
353136384Srwatson	 */
354136384Srwatson	flag[0] = -1;
355136384Srwatson	flag[1] = -1;
356136384Srwatson	len = sizeof(flag);
357136390Srwatson	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)
358136390Srwatson		err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) after "
359136390Srwatson		    "reset");
360136384Srwatson
361136390Srwatson	if (flag[0] != 0)
362136390Srwatson		errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) "
363136384Srwatson		    "after set had flag of %d\n", flag[0]);
364136384Srwatson
365136384Srwatson	close(sock);
366136384Srwatson}
367136384Srwatson
368136384Srwatson/*
369136384Srwatson * As with other non-int or larger sized socket options, the IP_TOS and
370136384Srwatson * IP_TTL fields in kernel is stored as an 8-bit value, reflecting the IP
371136384Srwatson * header fields, but useful I/O to the field occurs using 32-bit integers.
372136384Srwatson * The FreeBSD kernel will permit writes from variables at least an int in
373136384Srwatson * size (and ignore additional bytes), and will permit a read to buffers 1
374136384Srwatson * byte or larger (but depending on endianness, may truncate out useful
375136384Srwatson * values if the caller provides less room).
376136384Srwatson *
377136384Srwatson * Given the limitations of the API, use a UDP socket to confirm that the
378136384Srwatson * following are true:
379136384Srwatson *
380136384Srwatson * - We can read the IP_TOS/IP_TTL options.
381136384Srwatson * - The initial value of the TOS option is 0, TTL is 64.
382136384Srwatson * - That if we provide more than 32 bits of storage, we get back only 32
383136384Srwatson *   bits of data.
384136384Srwatson * - When we set it to a non-zero value expressible with a u_char, we can
385136384Srwatson *   read that value back.
386136384Srwatson * - When we reset it back to zero, we can read it as 0.
387136384Srwatson * - When we set it to a value >255, the value is truncated to something less
388136384Srwatson *   than 255.
389136384Srwatson */
390136384Srwatsonstatic void
391136390Srwatsontest_ip_uchar(int sock, const char *socktypename, int option,
392136390Srwatson    const char *optionname, int initial)
393136384Srwatson{
394136390Srwatson	int val[2];
395136384Srwatson	socklen_t len;
396136384Srwatson
397136384Srwatson	/*
398136384Srwatson	 * Check that the initial value is 0, and that the size is one
399136384Srwatson	 * u_char;
400136384Srwatson	 */
401136384Srwatson	val[0] = -1;
402136384Srwatson	val[1] = -1;
403136384Srwatson	len = sizeof(val);
404136384Srwatson	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
405136390Srwatson		err(-1, "test_ip_uchar(%s, %s): initial getsockopt()",
406136390Srwatson		    socktypename, optionname);
407136384Srwatson
408136384Srwatson	if (len != sizeof(val[0]))
409136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() "
410136390Srwatson		    "returned %d bytes", socktypename, optionname, len);
411136384Srwatson
412136384Srwatson	if (val[0] == -1)
413136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() didn't "
414136390Srwatson		    "return data", socktypename, optionname);
415136384Srwatson
416136384Srwatson	if (val[0] != initial)
417136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() "
418136390Srwatson		    "returned value of %d, not %d", socktypename, optionname,
419136390Srwatson		    val[0], initial);
420136384Srwatson
421136384Srwatson	/*
422136384Srwatson	 * Set the field to a valid value.
423136384Srwatson	 */
424136384Srwatson	val[0] = 128;
425136384Srwatson	val[1] = -1;
426136384Srwatson	if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0)
427136390Srwatson		err(-1, "test_ip_uchar(%s, %s): setsockopt(128)",
428136390Srwatson		    socktypename, optionname);
429136384Srwatson
430136384Srwatson	/*
431136384Srwatson	 * Check that when we read back the field, we get the same value.
432136384Srwatson	 */
433136384Srwatson	val[0] = -1;
434136384Srwatson	val[1] = -1;
435136384Srwatson	len = sizeof(val);
436136384Srwatson	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
437136390Srwatson		err(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
438136390Srwatson		    "128", socktypename, optionname);
439136384Srwatson
440136384Srwatson	if (len != sizeof(val[0]))
441136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
442136390Srwatson		    "128 returned %d bytes", socktypename, optionname, len);
443136384Srwatson
444136384Srwatson	if (val[0] == -1)
445136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
446136390Srwatson		    "128 didn't return data", socktypename, optionname);
447136384Srwatson
448136384Srwatson	if (val[0] != 128)
449136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
450136390Srwatson		    "128 returned %d", socktypename, optionname, val[0]);
451136384Srwatson
452136384Srwatson	/*
453136384Srwatson	 * Reset the value to 0, check that it was reset.
454136384Srwatson	 */
455136384Srwatson	val[0] = 0;
456136384Srwatson	val[1] = 0;
457136384Srwatson	if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0)
458136390Srwatson		err(-1, "test_ip_uchar(%s, %s): setsockopt() to reset from "
459136390Srwatson		    "128", socktypename, optionname);
460136384Srwatson
461136384Srwatson	if (len != sizeof(val[0]))
462136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "
463136390Srwatson		   "from 128 returned %d bytes", socktypename, optionname,
464136390Srwatson		    len);
465136384Srwatson
466136384Srwatson	if (val[0] == -1)
467136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "
468136390Srwatson		    "from 128 didn't return data", socktypename, optionname);
469136384Srwatson
470136384Srwatson	if (val[0] != 0)
471136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "
472136390Srwatson		    "from 128 returned %d", socktypename, optionname,
473136390Srwatson		    val[0]);
474136384Srwatson
475136384Srwatson	/*
476136384Srwatson	 * Set the value to something out of range and check that it comes
477136384Srwatson	 * back truncated, or that we get EINVAL back.  Traditional u_char
478136384Srwatson	 * IP socket options truncate, but newer ones (such as multicast
479136384Srwatson	 * socket options) will return EINVAL.
480136384Srwatson	 */
481136384Srwatson	val[0] = 32000;
482136384Srwatson	val[1] = -1;
483136384Srwatson	if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0) {
484136384Srwatson		/*
485136384Srwatson		 * EINVAL is a fine outcome, no need to run the truncation
486136384Srwatson		 * tests.
487136384Srwatson		 */
488136390Srwatson		if (errno == EINVAL)
489136384Srwatson			return;
490136390Srwatson		err(-1, "test_ip_uchar(%s, %s): getsockopt(32000)",
491136390Srwatson		    socktypename, optionname);
492136384Srwatson	}
493136384Srwatson
494136384Srwatson	val[0] = -1;
495136384Srwatson	val[1] = -1;
496136384Srwatson	len = sizeof(val);
497136384Srwatson	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
498136390Srwatson		err(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
499136390Srwatson		    "32000", socktypename, optionname);
500136384Srwatson
501136384Srwatson	if (len != sizeof(val[0]))
502136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
503136390Srwatson		    "32000 returned %d bytes", socktypename, optionname,
504136390Srwatson		    len);
505136384Srwatson
506136384Srwatson	if (val[0] == -1)
507136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
508136390Srwatson		    "32000 didn't return data", socktypename, optionname);
509136384Srwatson
510136384Srwatson	if (val[0] == 32000)
511136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
512136390Srwatson		    "32000 returned 32000: failed to truncate", socktypename,
513136390Srwatson		    optionname);
514136384Srwatson}
515136384Srwatson
516136384Srwatson/*
517136384Srwatson * Generic test for a boolean socket option.  Caller provides the option
518136384Srwatson * number, string name, expected default (initial) value, and whether or not
519136384Srwatson * the option is root-only.  For each option, test:
520136384Srwatson *
521136384Srwatson * - That we can read the option.
522136384Srwatson * - That the initial value is as expected.
523136384Srwatson * - That we can modify the value.
524136384Srwatson * - That on modification, the new value can be read back.
525136384Srwatson * - That we can reset the value.
526136384Srwatson * - that on reset, the new value can be read back.
527136384Srwatson */
528136384Srwatson#define	BOOLEAN_ANYONE		1
529136384Srwatson#define	BOOLEAN_ROOTONLY	1
530136384Srwatsonstatic void
531136390Srwatsontest_ip_boolean(int sock, const char *socktypename, int option,
532136390Srwatson    char *optionname, int initial, int rootonly)
533136384Srwatson{
534136390Srwatson	int newvalue, val[2];
535136384Srwatson	socklen_t len;
536136384Srwatson
537136384Srwatson	/*
538136384Srwatson	 * The default for a boolean might be true or false.  If it's false,
539136384Srwatson	 * we will try setting it to true (but using a non-1 value of true).
540136384Srwatson	 * If it's true, we'll set it to false.
541136384Srwatson	 */
542136384Srwatson	if (initial == 0)
543136384Srwatson		newvalue = 0xff;
544136384Srwatson	else
545136384Srwatson		newvalue = 0;
546136384Srwatson
547136384Srwatson	val[0] = -1;
548136384Srwatson	val[1] = -1;
549136384Srwatson	len = sizeof(val);
550136384Srwatson	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
551136384Srwatson		err(-1, "test_ip_boolean: initial getsockopt()");
552136384Srwatson
553136384Srwatson	if (len != sizeof(val[0]))
554136390Srwatson		errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "
555136390Srwatson		    "returned %d bytes", socktypename, optionname, len);
556136384Srwatson
557136384Srwatson	if (val[0] == -1)
558136390Srwatson		errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "
559136390Srwatson		    "didn't return data", socktypename, optionname);
560136384Srwatson
561136384Srwatson	if (val[0] != initial)
562136390Srwatson		errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "
563136390Srwatson		    "returned %d (expected %d)", socktypename, optionname,
564136390Srwatson		    val[0], initial);
565136384Srwatson
566136384Srwatson	/*
567136384Srwatson	 * Set the socket option to a new non-default value.
568136384Srwatson	 */
569136384Srwatson	if (setsockopt(sock, IPPROTO_IP, option, &newvalue, sizeof(newvalue))
570136384Srwatson	    < 0)
571136390Srwatson		err(-1, "test_ip_boolean(%s, %s): setsockopt() to %d",
572136390Srwatson		    socktypename, optionname, newvalue);
573136384Srwatson
574136384Srwatson	/*
575136384Srwatson	 * Read the value back and see if it is not the default (note: will
576136384Srwatson	 * not be what we set it to, as we set it to 0xff above).
577136384Srwatson	 */
578136384Srwatson	val[0] = -1;
579136384Srwatson	val[1] = -1;
580136384Srwatson	len = sizeof(val);
581136384Srwatson	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
582136390Srwatson		err(-1, "test_ip_boolean(%s, %s): getsockopt() after set to "
583136390Srwatson		    "%d", socktypename, optionname, newvalue);
584136384Srwatson
585136384Srwatson	if (len != sizeof(val[0]))
586136390Srwatson		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "
587136390Srwatson		    "to %d returned %d bytes", socktypename, optionname,
588136390Srwatson		    newvalue, len);
589136384Srwatson
590136384Srwatson	if (val[0] == -1)
591136390Srwatson		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "
592136390Srwatson		    "to %d didn't return data", socktypename, optionname,
593136390Srwatson		    newvalue);
594136384Srwatson
595136384Srwatson	/*
596136384Srwatson	 * If we set it to true, check for '1', otherwise '0.
597136384Srwatson	 */
598136384Srwatson	if (val[0] != (newvalue ? 1 : 0))
599136390Srwatson		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "
600136390Srwatson		    "to %d returned %d", socktypename, optionname, newvalue,
601136390Srwatson		    val[0]);
602136384Srwatson
603136384Srwatson	/*
604136384Srwatson	 * Reset to initial value.
605136384Srwatson	 */
606136384Srwatson	newvalue = initial;
607136384Srwatson	if (setsockopt(sock, IPPROTO_IP, option, &newvalue, sizeof(newvalue))
608136384Srwatson	    < 0)
609136390Srwatson		err(-1, "test_ip_boolean(%s, %s): setsockopt() to reset",
610136390Srwatson		    socktypename, optionname);
611136384Srwatson
612136384Srwatson	/*
613136384Srwatson	 * Check reset version.
614136384Srwatson	 */
615136384Srwatson	val[0] = -1;
616136384Srwatson	val[1] = -1;
617136384Srwatson	len = sizeof(val);
618136384Srwatson	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
619136390Srwatson		err(-1, "test_ip_boolean(%s, %s): getsockopt() after reset",
620136390Srwatson		    socktypename, optionname);
621136384Srwatson
622136384Srwatson	if (len != sizeof(val[0]))
623136390Srwatson		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "
624136390Srwatson		    "returned %d bytes", socktypename, optionname, len);
625136384Srwatson
626136384Srwatson	if (val[0] == -1)
627136390Srwatson		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "
628136390Srwatson		    "didn't return data", socktypename, optionname);
629136384Srwatson
630136384Srwatson	if (val[0] != newvalue)
631136390Srwatson		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "
632136390Srwatson		    "returned %d", socktypename, optionname, newvalue);
633136384Srwatson}
634136384Srwatson
635136384Srwatson/*
636158561Sbms * Test the IP_ADD_MEMBERSHIP socket option, and the dynamic allocator
637158561Sbms * for the imo_membership vector which now hangs off struct ip_moptions.
638158561Sbms * We then call IP_DROP_MEMBERSHIP for each group so joined.
639158561Sbms */
640158561Sbmsstatic void
641158561Sbmstest_ip_multicast_membership(int sock, const char *socktypename)
642158561Sbms{
643166437Sbms    char addrbuf[16];
644158561Sbms    struct ip_mreq mreq;
645158561Sbms    uint32_t basegroup;
646158561Sbms    uint16_t i;
647158561Sbms    int sotype;
648158561Sbms    socklen_t sotypelen;
649158561Sbms
650158561Sbms    sotypelen = sizeof(sotype);
651158561Sbms    if (getsockopt(sock, SOL_SOCKET, SO_TYPE, &sotype, &sotypelen) < 0)
652158561Sbms	err(-1, "test_ip_multicast_membership(%s): so_type getsockopt()",
653158561Sbms	    socktypename);
654158561Sbms    /*
655158561Sbms     * Do not perform the test for SOCK_STREAM sockets, as this makes
656158561Sbms     * no sense.
657158561Sbms     */
658158561Sbms    if (sotype == SOCK_STREAM)
659158561Sbms	return;
660158561Sbms    /*
661166437Sbms     * The 224/8 range is administratively scoped and has special meaning,
662166437Sbms     * therefore it is not used for this test.
663166437Sbms     * If we were not told to be non-deterministic:
664166437Sbms     * Join multicast groups from 238.1.1.0 up to nmcastgroups.
665166437Sbms     * Otherwise, pick a multicast group ID in subnet 238/5 with 11 random
666166437Sbms     * bits in the middle, and join groups in linear order up to nmcastgroups.
667158561Sbms     */
668166437Sbms    if (dorandom) {
669166437Sbms	/* be non-deterministic (for interactive operation; a fuller test) */
670166437Sbms	srandomdev();
671166437Sbms	basegroup = 0xEE000000;	/* 238.0.0.0 */
672166437Sbms	basegroup |= ((random() % ((1 << 11) - 1)) << 16);	/* 11 bits */
673166437Sbms    } else {
674166437Sbms	/* be deterministic (for automated operation) */
675166437Sbms	basegroup = 0xEE010100;	/* 238.1.1.0 */
676166437Sbms    }
677158561Sbms    /*
678158561Sbms     * Join the multicast group(s) on the default multicast interface;
679158561Sbms     * this usually maps to the interface to which the default
680158561Sbms     * route is pointing.
681158561Sbms     */
682170613Sbms    for (i = 1; i < nmcastgroups+1; i++) {
683168548Sbms	mreq.imr_multiaddr.s_addr = htonl((basegroup + i));
684158561Sbms	mreq.imr_interface.s_addr = INADDR_ANY;
685166437Sbms	inet_ntop(AF_INET, &mreq.imr_multiaddr, addrbuf, sizeof(addrbuf));
686166437Sbms	if (verbose)
687166437Sbms		fprintf(stderr, "IP_ADD_MEMBERSHIP %s INADDR_ANY\n", addrbuf);
688158561Sbms	if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
689158561Sbms		       sizeof(mreq)) < 0) {
690158561Sbms		err(-1,
691158561Sbms"test_ip_multicast_membership(%d, %s): failed IP_ADD_MEMBERSHIP (%s, %s)",
692166437Sbms		    sock, socktypename, addrbuf, "INADDR_ANY");
693158561Sbms	}
694158561Sbms    }
695170613Sbms    for (i = 1; i < nmcastgroups+1; i++) {
696168548Sbms	mreq.imr_multiaddr.s_addr = htonl((basegroup + i));
697158561Sbms	mreq.imr_interface.s_addr = INADDR_ANY;
698166437Sbms	inet_ntop(AF_INET, &mreq.imr_multiaddr, addrbuf, sizeof(addrbuf));
699166437Sbms	if (verbose)
700166437Sbms		fprintf(stderr, "IP_DROP_MEMBERSHIP %s INADDR_ANY\n", addrbuf);
701158561Sbms	if (setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq,
702158561Sbms		       sizeof(mreq)) < 0) {
703158561Sbms		err(-1,
704158561Sbms"test_ip_multicast_membership(%d, %s): failed IP_DROP_MEMBERSHIP (%s, %s)",
705166437Sbms		    sock, socktypename, addrbuf, "INADDR_ANY");
706158561Sbms	}
707158561Sbms    }
708158561Sbms}
709158561Sbms
710158561Sbms/*
711136384Srwatson * XXX: For now, nothing here.
712136384Srwatson */
713136384Srwatsonstatic void
714136390Srwatsontest_ip_multicast_if(int sock, const char *socktypename)
715136384Srwatson{
716136384Srwatson
717136384Srwatson	/*
718136384Srwatson	 * It's probably worth trying INADDR_ANY and INADDR_LOOPBACK here
719136384Srwatson	 * to see what happens.
720136384Srwatson	 */
721136384Srwatson}
722136384Srwatson
723136384Srwatson/*
724136384Srwatson * XXX: For now, nothing here.
725136384Srwatson */
726136384Srwatsonstatic void
727136390Srwatsontest_ip_multicast_vif(int sock, const char *socktypename)
728136384Srwatson{
729136384Srwatson
730136384Srwatson	/*
731136384Srwatson	 * This requires some knowledge of the number of virtual interfaces,
732136384Srwatson	 * and what is valid.
733136384Srwatson	 */
734136384Srwatson}
735136384Srwatson
736136384Srwatsonstatic void
737136390Srwatsontestsuite(int priv)
738136384Srwatson{
739136390Srwatson	const char *socktypenameset[] = {"SOCK_DGRAM", "SOCK_STREAM",
740136390Srwatson	    "SOCK_RAW"};
741136390Srwatson	int socktypeset[] = {SOCK_DGRAM, SOCK_STREAM, SOCK_RAW};
742136390Srwatson	const char *socktypename;
743136390Srwatson	int i, sock, socktype;
744136384Srwatson
745136390Srwatson	test_ip_hdrincl();
746136384Srwatson
747136390Srwatson	for (i = 0; i < sizeof(socktypeset)/sizeof(int); i++) {
748136390Srwatson		socktype = socktypeset[i];
749136390Srwatson		socktypename = socktypenameset[i];
750136384Srwatson
751136390Srwatson		/*
752136390Srwatson		 * If we can't acquire root privilege, we can't open raw
753136390Srwatson		 * sockets, so don't actually try.
754136390Srwatson		 */
755136390Srwatson		if (getuid() != 0 && socktype == SOCK_RAW)
756136390Srwatson			continue;
757136391Srwatson		if (geteuid() != 0 && !priv && socktype == SOCK_RAW)
758136391Srwatson			continue;
759136384Srwatson
760136390Srwatson		/*
761136390Srwatson		 * XXXRW: On 5.3, this seems not to work for SOCK_RAW.
762136390Srwatson		 */
763136390Srwatson		sock = get_socket(socktype, priv);
764136390Srwatson		if (sock == -1)
765136390Srwatson			err(-1, "get_socket(%s, %d) for test_ip_uchar(IP_TOS)",
766136390Srwatson			    socktypename, priv);
767136390Srwatson		test_ip_uchar(sock, socktypename, IP_TOS, "IP_TOS", 0);
768136390Srwatson		close(sock);
769136384Srwatson
770136390Srwatson		sock = get_socket(socktype, priv);
771136390Srwatson		if (sock == -1)
772136390Srwatson			err(-1, "get_socket(%s %d) for test_ip_uchar(IP_TTL)",
773136390Srwatson			    socktypename, priv);
774136390Srwatson		test_ip_uchar(sock, socktypename, IP_TTL, "IP_TTL", 64);
775136390Srwatson		close(sock);
776136384Srwatson
777136390Srwatson		sock = get_socket(socktype, priv);
778136390Srwatson		if (sock == -1)
779136390Srwatson			err(-1, "get_socket(%s, %d) for test_ip_boolean"
780136390Srwatson			    "(IP_RECVOPTS)", socktypename, priv);
781136390Srwatson		test_ip_boolean(sock, socktypename, IP_RECVOPTS,
782136390Srwatson		    "IP_RECVOPTS", 0, BOOLEAN_ANYONE);
783136390Srwatson		close(sock);
784136384Srwatson
785136390Srwatson		sock = get_socket(socktype, priv);
786136390Srwatson		if (sock == -1)
787136390Srwatson			err(-1, "get_socket(%s, %d) for test_ip_boolean"
788136390Srwatson			     "(IP_RECVRETOPTS)", socktypename, priv);
789136390Srwatson		test_ip_boolean(sock, socktypename, IP_RECVRETOPTS,
790136390Srwatson		    "IP_RECVRETOPTS", 0, BOOLEAN_ANYONE);
791136390Srwatson		close(sock);
792136384Srwatson
793136390Srwatson		sock = get_socket(socktype, priv);
794136390Srwatson		if (sock == -1)
795136390Srwatson			err(-1, "get_socket(%s, %d) for test_ip_boolean"
796136390Srwatson			    "(IP_RECVDSTADDR)", socktypename, priv);
797136390Srwatson		test_ip_boolean(sock, socktypename, IP_RECVDSTADDR,
798136390Srwatson		    "IP_RECVDSTADDR", 0, BOOLEAN_ANYONE);
799136390Srwatson		close(sock);
800136384Srwatson
801136390Srwatson		sock = get_socket(socktype, priv);
802136390Srwatson		if (sock == -1)
803136390Srwatson			err(-1, "get_socket(%s, %d) for test_ip_boolean"
804136390Srwatson			    "(IP_RECVTTL)", socktypename, priv);
805136390Srwatson		test_ip_boolean(sock, socktypename, IP_RECVTTL, "IP_RECVTTL",
806136390Srwatson		    0, BOOLEAN_ANYONE);
807136390Srwatson		close(sock);
808136384Srwatson
809136390Srwatson		sock = get_socket(socktype, priv);
810136390Srwatson		if (sock == -1)
811136390Srwatson			err(-1, "get_socket(%s, %d) for test_ip_boolean"
812136390Srwatson			    "(IP_RECVIF)", socktypename, priv);
813136390Srwatson		test_ip_boolean(sock, socktypename, IP_RECVIF, "IP_RECVIF",
814136390Srwatson		    0, BOOLEAN_ANYONE);
815136390Srwatson		close(sock);
816136384Srwatson
817136390Srwatson		sock = get_socket(socktype, priv);
818136390Srwatson		if (sock == -1)
819136390Srwatson			err(-1, "get_socket(%s, %d) for test_ip_boolean"
820136390Srwatson			    "(IP_FAITH)", socktypename, priv);
821136390Srwatson		test_ip_boolean(sock, socktypename, IP_FAITH, "IP_FAITH", 0,
822136390Srwatson		    BOOLEAN_ANYONE);
823136390Srwatson		close(sock);
824136390Srwatson
825136390Srwatson		sock = get_socket(socktype, priv);
826136390Srwatson		if (sock == -1)
827136390Srwatson			err(-1, "get_socket(%s, %d) for test_ip_boolean"
828136390Srwatson			    "(IP_ONESBCAST)", socktypename, priv);
829136390Srwatson		test_ip_boolean(sock, socktypename, IP_ONESBCAST,
830136390Srwatson		    "IP_ONESBCAST", 0, BOOLEAN_ANYONE);
831136390Srwatson		close(sock);
832136390Srwatson
833136390Srwatson		/*
834136390Srwatson		 * Test the multicast TTL exactly as we would the regular
835136390Srwatson		 * TTL, only expect a different default.
836136390Srwatson		 */
837136390Srwatson		sock = get_socket(socktype, priv);
838136390Srwatson		if (sock == -1)
839136390Srwatson			err(-1, "get_socket(%s, %d) for IP_MULTICAST_TTL",
840136390Srwatson			    socktypename, priv);
841136390Srwatson		test_ip_uchar(sock, socktypename, IP_MULTICAST_TTL,
842136390Srwatson		    "IP_MULTICAST_TTL", 1);
843136390Srwatson		close(sock);
844136390Srwatson
845136390Srwatson		/*
846136390Srwatson		 * The multicast loopback flag can be tested using our
847136390Srwatson		 * boolean tester, but only because the FreeBSD API is a bit
848136390Srwatson		 * more flexible than earlir APIs and will accept an int as
849136390Srwatson		 * well as a u_char.  Loopback is enabled by default.
850136390Srwatson		 */
851136390Srwatson		sock = get_socket(socktype, priv);
852136390Srwatson		if (sock == -1)
853136390Srwatson			err(-1, "get_socket(%s, %d) for IP_MULTICAST_LOOP",
854136390Srwatson			    socktypename, priv);
855136390Srwatson		test_ip_boolean(sock, socktypename, IP_MULTICAST_LOOP,
856136390Srwatson		    "IP_MULTICAST_LOOP", 1, BOOLEAN_ANYONE);
857136390Srwatson		close(sock);
858136390Srwatson
859136390Srwatson		sock = get_socket(socktype, priv);
860136390Srwatson		if (sock == -1)
861136390Srwatson			err(-1, "get_socket(%s, %d) for test_ip_options",
862136390Srwatson			    socktypename, priv);
863136390Srwatson		//test_ip_options(sock, socktypename);
864136390Srwatson		close(sock);
865136390Srwatson
866158561Sbms		sock = get_socket(socktype, priv);
867158561Sbms		if (sock == -1)
868158561Sbms			err(-1, "get_socket(%s, %d) for test_ip_options",
869158561Sbms			    socktypename, priv);
870158561Sbms		test_ip_multicast_membership(sock, socktypename);
871158561Sbms		close(sock);
872158561Sbms
873136390Srwatson		test_ip_multicast_if(0, NULL);
874136390Srwatson		test_ip_multicast_vif(0, NULL);
875136390Srwatson		/*
876136390Srwatson		 * XXX: Still need to test:
877136390Srwatson		 * IP_PORTRANGE
878136390Srwatson		 * IP_IPSEC_POLICY?
879136390Srwatson		 */
880136390Srwatson	}
881136384Srwatson}
882136384Srwatson
883166437Sbmsstatic void
884166437Sbmsusage()
885166437Sbms{
886166437Sbms
887166437Sbms	fprintf(stderr, "usage: ipsockopt [-M ngroups] [-r] [-v]\n");
888166437Sbms	exit(EXIT_FAILURE);
889166437Sbms}
890166437Sbms
891136384Srwatson/*
892136384Srwatson * Very simply exercise that we can get and set each option.  If we're running
893136384Srwatson * as root, run it also as nobody.  If not as root, complain about that.
894136384Srwatson */
895136384Srwatsonint
896136384Srwatsonmain(int argc, char *argv[])
897136384Srwatson{
898166437Sbms	int ch;
899136384Srwatson
900166437Sbms	while ((ch = getopt(argc, argv, "M:rv")) != -1) {
901166437Sbms		switch (ch) {
902166437Sbms		case 'M':
903166437Sbms			nmcastgroups = atoi(optarg);
904166437Sbms			break;
905166437Sbms		case 'r':
906166437Sbms			dorandom = 1;	/* introduce non-determinism */
907166437Sbms			break;
908166437Sbms		case 'v':
909166437Sbms			verbose = 1;
910166437Sbms			break;
911166437Sbms		default:
912166437Sbms			usage();
913166437Sbms		}
914166437Sbms	}
915166437Sbms
916137587Snik	printf("1..1\n");
917166437Sbms
918136384Srwatson	if (geteuid() != 0) {
919136390Srwatson		warnx("Not running as root, can't run tests as root");
920136384Srwatson		fprintf(stderr, "\n");
921136390Srwatson		fprintf(stderr,
922136390Srwatson		   "Running tests with uid %d sock uid %d\n", geteuid(),
923136390Srwatson		    geteuid());
924136390Srwatson		testsuite(PRIV_ASIS);
925136384Srwatson	} else {
926136390Srwatson		fprintf(stderr,
927136390Srwatson		    "Running tests with ruid %d euid %d sock uid 0\n",
928136390Srwatson		    getuid(), geteuid());
929136390Srwatson		testsuite(PRIV_ASIS);
930136390Srwatson		if (seteuid(65534) != 0)
931136390Srwatson			err(-1, "seteuid(65534)");
932136390Srwatson		fprintf(stderr,
933136391Srwatson		    "Running tests with ruid %d euid %d sock uid 65534\n",
934136391Srwatson		    getuid(), geteuid());
935136391Srwatson		testsuite(PRIV_ASIS);
936136391Srwatson		fprintf(stderr,
937136390Srwatson		    "Running tests with ruid %d euid %d sock uid 0\n",
938136390Srwatson		    getuid(), geteuid());
939136390Srwatson		testsuite(PRIV_GETROOT);
940136384Srwatson	}
941137587Snik	printf("ok 1 - ipsockopt\n");
942136384Srwatson	exit(0);
943136384Srwatson}
944