ipsockopt.c revision 158561
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: head/tools/regression/netinet/ipsockopt/ipsockopt.c 158561 2006-05-14 14:11:54Z bms $
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>
35136384Srwatson
36136384Srwatson#include <err.h>
37136384Srwatson#include <errno.h>
38136384Srwatson#include <stdio.h>
39136384Srwatson#include <stdlib.h>
40136384Srwatson#include <string.h>
41136384Srwatson#include <unistd.h>
42136384Srwatson
43136384Srwatson/*
44136384Srwatson * The test tool exercises IP-level socket options by interrogating the
45136384Srwatson * getsockopt()/setsockopt() APIs.  It does not currently test that the
46136384Srwatson * intended semantics of each option are implemented (i.e., that setting IP
47136384Srwatson * options on the socket results in packets with the desired IP options in
48136384Srwatson * it).
49136384Srwatson */
50136384Srwatson
51136384Srwatson/*
52136390Srwatson * get_socket() is a wrapper function that returns a socket of the specified
53136390Srwatson * type, and created with or without restored root privilege (if running
54136390Srwatson * with a real uid of root and an effective uid of some other user).  This
55136390Srwatson * us to test whether the same rights are granted using a socket with a
56136390Srwatson * privileged cached credential vs. a socket with a regular credential.
57136390Srwatson */
58136390Srwatson#define	PRIV_ASIS	0
59136390Srwatson#define	PRIV_GETROOT	1
60136390Srwatsonstatic int
61136390Srwatsonget_socket_unpriv(int type)
62136390Srwatson{
63136390Srwatson
64136390Srwatson	return (socket(PF_INET, type, 0));
65136390Srwatson}
66136390Srwatson
67136390Srwatsonstatic int
68136390Srwatsonget_socket_priv(int type)
69136390Srwatson{
70136390Srwatson	uid_t olduid;
71136390Srwatson	int sock;
72136390Srwatson
73136390Srwatson	if (getuid() != 0)
74136390Srwatson		errx(-1, "get_sock_priv: running without real uid 0");
75136390Srwatson
76136390Srwatson	olduid = geteuid();
77136390Srwatson	if (seteuid(0) < 0)
78136390Srwatson		err(-1, "get_sock_priv: seteuid(0)");
79136390Srwatson
80136390Srwatson	sock = socket(PF_INET, type, 0);
81136390Srwatson
82136390Srwatson	if (seteuid(olduid) < 0)
83136390Srwatson		err(-1, "get_sock_priv: seteuid(%d)", olduid);
84136390Srwatson
85136390Srwatson	return (sock);
86136390Srwatson}
87136390Srwatson
88136390Srwatsonstatic int
89136390Srwatsonget_socket(int type, int priv)
90136390Srwatson{
91136390Srwatson
92136390Srwatson	if (priv)
93136390Srwatson		return (get_socket_priv(type));
94136390Srwatson	else
95136390Srwatson		return (get_socket_unpriv(type));
96136390Srwatson}
97136390Srwatson
98136390Srwatson/*
99136384Srwatson * Exercise the IP_OPTIONS socket option.  Confirm the following properties:
100136384Srwatson *
101136384Srwatson * - That there is no initial set of options (length returned is 0).
102136384Srwatson * - That if we set a specific set of options, we can read it back.
103136384Srwatson * - That if we then reset the options, they go away.
104136384Srwatson *
105136384Srwatson * Use a UDP socket for this.
106136384Srwatson */
107136384Srwatsonstatic void
108136390Srwatsontest_ip_options(int sock, const char *socktypename)
109136384Srwatson{
110136384Srwatson	u_int32_t new_options, test_options[2];
111136384Srwatson	socklen_t len;
112136384Srwatson
113136384Srwatson	/*
114136384Srwatson	 * Start off by confirming the default IP options on a socket are to
115136384Srwatson	 * have no options set.
116136384Srwatson	 */
117136384Srwatson	len = sizeof(test_options);
118136384Srwatson	if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
119136390Srwatson		err(-1, "test_ip_options(%s): initial getsockopt()",
120136390Srwatson		    socktypename);
121136384Srwatson
122136384Srwatson	if (len != 0)
123136390Srwatson		errx(-1, "test_ip_options(%s): initial getsockopt() returned "
124136390Srwatson		    "%d bytes", socktypename, len);
125136384Srwatson
126136384Srwatson#define	TEST_MAGIC	0xc34e4212
127136384Srwatson#define	NEW_OPTIONS	htonl(IPOPT_EOL | (IPOPT_NOP << 8) | (IPOPT_NOP << 16) \
128136384Srwatson			 | (IPOPT_NOP << 24))
129136384Srwatson
130136384Srwatson	/*
131136384Srwatson	 * Write some new options into the socket.
132136384Srwatson	 */
133136384Srwatson	new_options = NEW_OPTIONS;
134136384Srwatson	if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, &new_options,
135136384Srwatson	    sizeof(new_options)) < 0)
136136390Srwatson		err(-1, "test_ip_options(%s): setsockopt(NOP|NOP|NOP|EOL)",
137136390Srwatson		    socktypename);
138136384Srwatson
139136384Srwatson	/*
140136384Srwatson	 * Store some random cruft in a local variable and retrieve the
141136384Srwatson	 * options to make sure they set.  Note that we pass in an array
142136384Srwatson	 * of u_int32_t's so that if whatever ended up in the option was
143136384Srwatson	 * larger than what we put in, we find out about it here.
144136384Srwatson	 */
145136384Srwatson	test_options[0] = TEST_MAGIC;
146136384Srwatson	test_options[1] = TEST_MAGIC;
147136384Srwatson	len = sizeof(test_options);
148136384Srwatson	if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
149136390Srwatson		err(-1, "test_ip_options(%s): getsockopt() after set",
150136390Srwatson		    socktypename);
151136384Srwatson
152136384Srwatson	/*
153136384Srwatson	 * Getting the right amount back is important.
154136384Srwatson	 */
155136384Srwatson	if (len != sizeof(new_options))
156136390Srwatson		errx(-1, "test_ip_options(%s): getsockopt() after set "
157136390Srwatson		    "returned %d bytes of data", socktypename, len);
158136384Srwatson
159136384Srwatson	/*
160136384Srwatson	 * One posible failure mode is that the call succeeds but neglects to
161136384Srwatson	 * copy out the data.
162136384Srwatson 	 */
163136384Srwatson	if (test_options[0] == TEST_MAGIC)
164136390Srwatson		errx(-1, "test_ip_options(%s): getsockopt() after set didn't "
165136390Srwatson		    "return data", socktypename);
166136384Srwatson
167136384Srwatson	/*
168136384Srwatson	 * Make sure we get back what we wrote on.
169136384Srwatson	 */
170136384Srwatson	if (new_options != test_options[0])
171136390Srwatson		errx(-1, "test_ip_options(%s): getsockopt() after set "
172136390Srwatson		    "returned wrong options (%08x, %08x)", socktypename,
173136390Srwatson		    new_options, test_options[0]);
174136384Srwatson
175136384Srwatson	/*
176136384Srwatson	 * Now we reset the value to make sure clearing works.
177136384Srwatson	 */
178136384Srwatson	if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, NULL, 0) < 0)
179136390Srwatson		err(-1, "test_ip_options(%s): setsockopt() to reset",
180136390Srwatson		    socktypename);
181136384Srwatson
182136384Srwatson	/*
183136384Srwatson	 * Make sure it was really cleared.
184136384Srwatson	 */
185136384Srwatson	test_options[0] = TEST_MAGIC;
186136384Srwatson	test_options[1] = TEST_MAGIC;
187136384Srwatson	len = sizeof(test_options);
188136384Srwatson	if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
189136390Srwatson		err(-1, "test_ip_options(%s): getsockopt() after reset",
190136390Srwatson		    socktypename);
191136384Srwatson
192136384Srwatson	if (len != 0)
193136390Srwatson		errx(-1, "test_ip_options(%s): getsockopt() after reset "
194136390Srwatson		    "returned %d bytes", socktypename, len);
195136384Srwatson}
196136384Srwatson
197136384Srwatson/*
198136384Srwatson * This test checks the behavior of the IP_HDRINCL socket option, which
199136384Srwatson * allows users with privilege to specify the full header on an IP raw
200136384Srwatson * socket.  We test that the option can only be used with raw IP sockets, not
201136384Srwatson * with UDP or TCP sockets.  We also confirm that the raw socket is only
202136384Srwatson * available to a privileged user (subject to the UID when called).  We
203136384Srwatson * confirm that it defaults to off
204136390Srwatson *
205136390Srwatson * Unlike other tests, doesn't use caller-provided socket.  Probably should
206136390Srwatson * be fixed.
207136384Srwatson */
208136384Srwatsonstatic void
209136384Srwatsontest_ip_hdrincl(void)
210136384Srwatson{
211136384Srwatson	int flag[2], sock;
212136384Srwatson	socklen_t len;
213136384Srwatson
214136384Srwatson	/*
215136384Srwatson	 * Try to receive or set the IP_HDRINCL flag on a TCP socket.
216136384Srwatson	 */
217136384Srwatson	sock = socket(PF_INET, SOCK_STREAM, 0);
218136390Srwatson	if (sock == -1)
219136390Srwatson		err(-1, "test_ip_hdrincl(): socket(SOCK_STREAM)");
220136384Srwatson
221136384Srwatson	flag[0] = -1;
222136384Srwatson	len = sizeof(flag[0]);
223136390Srwatson	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0)
224136390Srwatson		err(-1, "test_ip_hdrincl(): initial getsockopt(IP_HDRINCL)");
225136384Srwatson
226136390Srwatson	if (errno != ENOPROTOOPT)
227136390Srwatson		errx(-1, "test_ip_hdrincl(): initial getsockopt(IP_HDRINC) "
228136390Srwatson		    "returned %d (%s) not ENOPROTOOPT", errno,
229136390Srwatson		    strerror(errno));
230136384Srwatson
231136384Srwatson	flag[0] = 1;
232136384Srwatson	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
233136390Srwatson	    == 0)
234136390Srwatson		err(-1,"test_ip_hdrincl(): setsockopt(IP_HDRINCL) on TCP "
235136390Srwatson		    "succeeded\n");
236136384Srwatson
237136390Srwatson	if (errno != ENOPROTOOPT)
238136390Srwatson		errx(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on TCP "
239136390Srwatson		    "returned %d (%s) not ENOPROTOOPT\n", errno,
240136390Srwatson		    strerror(errno));
241136384Srwatson
242136384Srwatson	close(sock);
243136384Srwatson
244136384Srwatson	/*
245136384Srwatson	 * Try to receive or set the IP_HDRINCL flag on a UDP socket.
246136384Srwatson	 */
247136384Srwatson	sock = socket(PF_INET, SOCK_DGRAM, 0);
248136390Srwatson	if (sock == -1)
249136390Srwatson		err(-1, "test_ip_hdrincl(): socket(SOCK_DGRAM");
250136384Srwatson
251136384Srwatson	flag[0] = -1;
252136384Srwatson	len = sizeof(flag[0]);
253136390Srwatson	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0)
254136390Srwatson		err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on UDP "
255136390Srwatson		    "succeeded\n");
256136384Srwatson
257136390Srwatson	if (errno != ENOPROTOOPT)
258136390Srwatson		errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on UDP "
259136390Srwatson		    "returned %d (%s) not ENOPROTOOPT\n", errno,
260136390Srwatson		    strerror(errno));
261136384Srwatson
262136384Srwatson	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
263136390Srwatson	    == 0)
264136390Srwatson		err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on UDP "
265136390Srwatson		    "succeeded\n");
266136384Srwatson
267136390Srwatson	if (errno != ENOPROTOOPT)
268136390Srwatson		errx(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on UDP "
269136390Srwatson		    "returned %d (%s) not ENOPROTOOPT\n", errno,
270136390Srwatson		    strerror(errno));
271136384Srwatson
272136384Srwatson	close(sock);
273136384Srwatson
274136384Srwatson	/*
275136384Srwatson	 * Now try on a raw socket.  Access ontrol should prevent non-root
276136384Srwatson	 * users from creating the raw socket, so check that here based on
277136384Srwatson	 * geteuid().  If we're non-root, we just return assuming the socket
278136384Srwatson	 * create fails since the remainder of the tests apply only on a raw
279136384Srwatson	 * socket.
280136384Srwatson	 */
281136384Srwatson	sock = socket(PF_INET, SOCK_RAW, 0);
282136384Srwatson	if (geteuid() != 0) {
283136384Srwatson		if (sock != -1)
284136384Srwatson			errx(-1, "test_ip_hdrincl: created raw socket as "
285136384Srwatson			    "uid %d", geteuid());
286136384Srwatson		return;
287136384Srwatson	}
288136390Srwatson	if (sock == -1)
289136390Srwatson		err(-1, "test_ip_hdrincl(): socket(PF_INET, SOCK_RAW)");
290136384Srwatson
291136384Srwatson	/*
292136384Srwatson	 * Make sure the initial value of the flag is 0 (disabled).
293136384Srwatson	 */
294136384Srwatson	flag[0] = -1;
295136384Srwatson	flag[1] = -1;
296136384Srwatson	len = sizeof(flag);
297136390Srwatson	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)
298136390Srwatson		err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on raw "
299136390Srwatson		    "socket");
300136384Srwatson
301136390Srwatson	if (len != sizeof(flag[0]))
302136390Srwatson		errx(-1, "test_ip_hdrincl(): %d bytes returned on "
303136384Srwatson		    "initial get\n", len);
304136384Srwatson
305136390Srwatson	if (flag[0] != 0)
306136390Srwatson		errx(-1, "test_ip_hdrincl(): initial flag value of %d\n",
307136384Srwatson		    flag[0]);
308136384Srwatson
309136384Srwatson	/*
310136384Srwatson	 * Enable the IP_HDRINCL flag.
311136384Srwatson	 */
312136384Srwatson	flag[0] = 1;
313136384Srwatson	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
314136390Srwatson	    < 0)
315136390Srwatson		err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL, 1)");
316136384Srwatson
317136384Srwatson	/*
318136384Srwatson	 * Check that the IP_HDRINCL flag was set.
319136384Srwatson	 */
320136384Srwatson	flag[0] = -1;
321136384Srwatson	flag[1] = -1;
322136384Srwatson	len = sizeof(flag);
323136390Srwatson	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)
324136390Srwatson		err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) after "
325136390Srwatson		    "set");
326136384Srwatson
327136390Srwatson	if (flag[0] == 0)
328136390Srwatson		errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) "
329136384Srwatson		    "after set had flag of %d\n", flag[0]);
330136384Srwatson
331136384Srwatson#define	HISTORICAL_INP_HDRINCL	8
332136390Srwatson	if (flag[0] != HISTORICAL_INP_HDRINCL)
333136390Srwatson		warnx("test_ip_hdrincl(): WARNING: getsockopt(IP_H"
334136384Srwatson		    "DRINCL) after set had non-historical value of %d\n",
335136384Srwatson		    flag[0]);
336136384Srwatson
337136384Srwatson	/*
338136384Srwatson	 * Reset the IP_HDRINCL flag to 0.
339136384Srwatson	 */
340136384Srwatson	flag[0] = 0;
341136384Srwatson	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
342136390Srwatson	    < 0)
343136390Srwatson		err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL, 0)");
344136384Srwatson
345136384Srwatson	/*
346136384Srwatson	 * Check that the IP_HDRINCL flag was reset to 0.
347136384Srwatson	 */
348136384Srwatson	flag[0] = -1;
349136384Srwatson	flag[1] = -1;
350136384Srwatson	len = sizeof(flag);
351136390Srwatson	if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)
352136390Srwatson		err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) after "
353136390Srwatson		    "reset");
354136384Srwatson
355136390Srwatson	if (flag[0] != 0)
356136390Srwatson		errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) "
357136384Srwatson		    "after set had flag of %d\n", flag[0]);
358136384Srwatson
359136384Srwatson	close(sock);
360136384Srwatson}
361136384Srwatson
362136384Srwatson/*
363136384Srwatson * As with other non-int or larger sized socket options, the IP_TOS and
364136384Srwatson * IP_TTL fields in kernel is stored as an 8-bit value, reflecting the IP
365136384Srwatson * header fields, but useful I/O to the field occurs using 32-bit integers.
366136384Srwatson * The FreeBSD kernel will permit writes from variables at least an int in
367136384Srwatson * size (and ignore additional bytes), and will permit a read to buffers 1
368136384Srwatson * byte or larger (but depending on endianness, may truncate out useful
369136384Srwatson * values if the caller provides less room).
370136384Srwatson *
371136384Srwatson * Given the limitations of the API, use a UDP socket to confirm that the
372136384Srwatson * following are true:
373136384Srwatson *
374136384Srwatson * - We can read the IP_TOS/IP_TTL options.
375136384Srwatson * - The initial value of the TOS option is 0, TTL is 64.
376136384Srwatson * - That if we provide more than 32 bits of storage, we get back only 32
377136384Srwatson *   bits of data.
378136384Srwatson * - When we set it to a non-zero value expressible with a u_char, we can
379136384Srwatson *   read that value back.
380136384Srwatson * - When we reset it back to zero, we can read it as 0.
381136384Srwatson * - When we set it to a value >255, the value is truncated to something less
382136384Srwatson *   than 255.
383136384Srwatson */
384136384Srwatsonstatic void
385136390Srwatsontest_ip_uchar(int sock, const char *socktypename, int option,
386136390Srwatson    const char *optionname, int initial)
387136384Srwatson{
388136390Srwatson	int val[2];
389136384Srwatson	socklen_t len;
390136384Srwatson
391136384Srwatson	/*
392136384Srwatson	 * Check that the initial value is 0, and that the size is one
393136384Srwatson	 * u_char;
394136384Srwatson	 */
395136384Srwatson	val[0] = -1;
396136384Srwatson	val[1] = -1;
397136384Srwatson	len = sizeof(val);
398136384Srwatson	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
399136390Srwatson		err(-1, "test_ip_uchar(%s, %s): initial getsockopt()",
400136390Srwatson		    socktypename, optionname);
401136384Srwatson
402136384Srwatson	if (len != sizeof(val[0]))
403136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() "
404136390Srwatson		    "returned %d bytes", socktypename, optionname, len);
405136384Srwatson
406136384Srwatson	if (val[0] == -1)
407136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() didn't "
408136390Srwatson		    "return data", socktypename, optionname);
409136384Srwatson
410136384Srwatson	if (val[0] != initial)
411136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() "
412136390Srwatson		    "returned value of %d, not %d", socktypename, optionname,
413136390Srwatson		    val[0], initial);
414136384Srwatson
415136384Srwatson	/*
416136384Srwatson	 * Set the field to a valid value.
417136384Srwatson	 */
418136384Srwatson	val[0] = 128;
419136384Srwatson	val[1] = -1;
420136384Srwatson	if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0)
421136390Srwatson		err(-1, "test_ip_uchar(%s, %s): setsockopt(128)",
422136390Srwatson		    socktypename, optionname);
423136384Srwatson
424136384Srwatson	/*
425136384Srwatson	 * Check that when we read back the field, we get the same value.
426136384Srwatson	 */
427136384Srwatson	val[0] = -1;
428136384Srwatson	val[1] = -1;
429136384Srwatson	len = sizeof(val);
430136384Srwatson	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
431136390Srwatson		err(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
432136390Srwatson		    "128", socktypename, optionname);
433136384Srwatson
434136384Srwatson	if (len != sizeof(val[0]))
435136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
436136390Srwatson		    "128 returned %d bytes", socktypename, optionname, len);
437136384Srwatson
438136384Srwatson	if (val[0] == -1)
439136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
440136390Srwatson		    "128 didn't return data", socktypename, optionname);
441136384Srwatson
442136384Srwatson	if (val[0] != 128)
443136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
444136390Srwatson		    "128 returned %d", socktypename, optionname, val[0]);
445136384Srwatson
446136384Srwatson	/*
447136384Srwatson	 * Reset the value to 0, check that it was reset.
448136384Srwatson	 */
449136384Srwatson	val[0] = 0;
450136384Srwatson	val[1] = 0;
451136384Srwatson	if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0)
452136390Srwatson		err(-1, "test_ip_uchar(%s, %s): setsockopt() to reset from "
453136390Srwatson		    "128", socktypename, optionname);
454136384Srwatson
455136384Srwatson	if (len != sizeof(val[0]))
456136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "
457136390Srwatson		   "from 128 returned %d bytes", socktypename, optionname,
458136390Srwatson		    len);
459136384Srwatson
460136384Srwatson	if (val[0] == -1)
461136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "
462136390Srwatson		    "from 128 didn't return data", socktypename, optionname);
463136384Srwatson
464136384Srwatson	if (val[0] != 0)
465136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "
466136390Srwatson		    "from 128 returned %d", socktypename, optionname,
467136390Srwatson		    val[0]);
468136384Srwatson
469136384Srwatson	/*
470136384Srwatson	 * Set the value to something out of range and check that it comes
471136384Srwatson	 * back truncated, or that we get EINVAL back.  Traditional u_char
472136384Srwatson	 * IP socket options truncate, but newer ones (such as multicast
473136384Srwatson	 * socket options) will return EINVAL.
474136384Srwatson	 */
475136384Srwatson	val[0] = 32000;
476136384Srwatson	val[1] = -1;
477136384Srwatson	if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0) {
478136384Srwatson		/*
479136384Srwatson		 * EINVAL is a fine outcome, no need to run the truncation
480136384Srwatson		 * tests.
481136384Srwatson		 */
482136390Srwatson		if (errno == EINVAL)
483136384Srwatson			return;
484136390Srwatson		err(-1, "test_ip_uchar(%s, %s): getsockopt(32000)",
485136390Srwatson		    socktypename, optionname);
486136384Srwatson	}
487136384Srwatson
488136384Srwatson	val[0] = -1;
489136384Srwatson	val[1] = -1;
490136384Srwatson	len = sizeof(val);
491136384Srwatson	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
492136390Srwatson		err(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
493136390Srwatson		    "32000", socktypename, optionname);
494136384Srwatson
495136384Srwatson	if (len != sizeof(val[0]))
496136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
497136390Srwatson		    "32000 returned %d bytes", socktypename, optionname,
498136390Srwatson		    len);
499136384Srwatson
500136384Srwatson	if (val[0] == -1)
501136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
502136390Srwatson		    "32000 didn't return data", socktypename, optionname);
503136384Srwatson
504136384Srwatson	if (val[0] == 32000)
505136390Srwatson		errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
506136390Srwatson		    "32000 returned 32000: failed to truncate", socktypename,
507136390Srwatson		    optionname);
508136384Srwatson}
509136384Srwatson
510136384Srwatson/*
511136384Srwatson * Generic test for a boolean socket option.  Caller provides the option
512136384Srwatson * number, string name, expected default (initial) value, and whether or not
513136384Srwatson * the option is root-only.  For each option, test:
514136384Srwatson *
515136384Srwatson * - That we can read the option.
516136384Srwatson * - That the initial value is as expected.
517136384Srwatson * - That we can modify the value.
518136384Srwatson * - That on modification, the new value can be read back.
519136384Srwatson * - That we can reset the value.
520136384Srwatson * - that on reset, the new value can be read back.
521136384Srwatson */
522136384Srwatson#define	BOOLEAN_ANYONE		1
523136384Srwatson#define	BOOLEAN_ROOTONLY	1
524136384Srwatsonstatic void
525136390Srwatsontest_ip_boolean(int sock, const char *socktypename, int option,
526136390Srwatson    char *optionname, int initial, int rootonly)
527136384Srwatson{
528136390Srwatson	int newvalue, val[2];
529136384Srwatson	socklen_t len;
530136384Srwatson
531136384Srwatson	/*
532136384Srwatson	 * The default for a boolean might be true or false.  If it's false,
533136384Srwatson	 * we will try setting it to true (but using a non-1 value of true).
534136384Srwatson	 * If it's true, we'll set it to false.
535136384Srwatson	 */
536136384Srwatson	if (initial == 0)
537136384Srwatson		newvalue = 0xff;
538136384Srwatson	else
539136384Srwatson		newvalue = 0;
540136384Srwatson
541136384Srwatson	val[0] = -1;
542136384Srwatson	val[1] = -1;
543136384Srwatson	len = sizeof(val);
544136384Srwatson	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
545136384Srwatson		err(-1, "test_ip_boolean: initial getsockopt()");
546136384Srwatson
547136384Srwatson	if (len != sizeof(val[0]))
548136390Srwatson		errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "
549136390Srwatson		    "returned %d bytes", socktypename, optionname, len);
550136384Srwatson
551136384Srwatson	if (val[0] == -1)
552136390Srwatson		errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "
553136390Srwatson		    "didn't return data", socktypename, optionname);
554136384Srwatson
555136384Srwatson	if (val[0] != initial)
556136390Srwatson		errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "
557136390Srwatson		    "returned %d (expected %d)", socktypename, optionname,
558136390Srwatson		    val[0], initial);
559136384Srwatson
560136384Srwatson	/*
561136384Srwatson	 * Set the socket option to a new non-default value.
562136384Srwatson	 */
563136384Srwatson	if (setsockopt(sock, IPPROTO_IP, option, &newvalue, sizeof(newvalue))
564136384Srwatson	    < 0)
565136390Srwatson		err(-1, "test_ip_boolean(%s, %s): setsockopt() to %d",
566136390Srwatson		    socktypename, optionname, newvalue);
567136384Srwatson
568136384Srwatson	/*
569136384Srwatson	 * Read the value back and see if it is not the default (note: will
570136384Srwatson	 * not be what we set it to, as we set it to 0xff above).
571136384Srwatson	 */
572136384Srwatson	val[0] = -1;
573136384Srwatson	val[1] = -1;
574136384Srwatson	len = sizeof(val);
575136384Srwatson	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
576136390Srwatson		err(-1, "test_ip_boolean(%s, %s): getsockopt() after set to "
577136390Srwatson		    "%d", socktypename, optionname, newvalue);
578136384Srwatson
579136384Srwatson	if (len != sizeof(val[0]))
580136390Srwatson		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "
581136390Srwatson		    "to %d returned %d bytes", socktypename, optionname,
582136390Srwatson		    newvalue, len);
583136384Srwatson
584136384Srwatson	if (val[0] == -1)
585136390Srwatson		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "
586136390Srwatson		    "to %d didn't return data", socktypename, optionname,
587136390Srwatson		    newvalue);
588136384Srwatson
589136384Srwatson	/*
590136384Srwatson	 * If we set it to true, check for '1', otherwise '0.
591136384Srwatson	 */
592136384Srwatson	if (val[0] != (newvalue ? 1 : 0))
593136390Srwatson		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "
594136390Srwatson		    "to %d returned %d", socktypename, optionname, newvalue,
595136390Srwatson		    val[0]);
596136384Srwatson
597136384Srwatson	/*
598136384Srwatson	 * Reset to initial value.
599136384Srwatson	 */
600136384Srwatson	newvalue = initial;
601136384Srwatson	if (setsockopt(sock, IPPROTO_IP, option, &newvalue, sizeof(newvalue))
602136384Srwatson	    < 0)
603136390Srwatson		err(-1, "test_ip_boolean(%s, %s): setsockopt() to reset",
604136390Srwatson		    socktypename, optionname);
605136384Srwatson
606136384Srwatson	/*
607136384Srwatson	 * Check reset version.
608136384Srwatson	 */
609136384Srwatson	val[0] = -1;
610136384Srwatson	val[1] = -1;
611136384Srwatson	len = sizeof(val);
612136384Srwatson	if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
613136390Srwatson		err(-1, "test_ip_boolean(%s, %s): getsockopt() after reset",
614136390Srwatson		    socktypename, optionname);
615136384Srwatson
616136384Srwatson	if (len != sizeof(val[0]))
617136390Srwatson		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "
618136390Srwatson		    "returned %d bytes", socktypename, optionname, len);
619136384Srwatson
620136384Srwatson	if (val[0] == -1)
621136390Srwatson		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "
622136390Srwatson		    "didn't return data", socktypename, optionname);
623136384Srwatson
624136384Srwatson	if (val[0] != newvalue)
625136390Srwatson		errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "
626136390Srwatson		    "returned %d", socktypename, optionname, newvalue);
627136384Srwatson}
628136384Srwatson
629136384Srwatson/*
630158561Sbms * Test the IP_ADD_MEMBERSHIP socket option, and the dynamic allocator
631158561Sbms * for the imo_membership vector which now hangs off struct ip_moptions.
632158561Sbms * We then call IP_DROP_MEMBERSHIP for each group so joined.
633158561Sbms */
634158561Sbmsstatic void
635158561Sbmstest_ip_multicast_membership(int sock, const char *socktypename)
636158561Sbms{
637158561Sbms    struct ip_mreq mreq;
638158561Sbms    uint32_t basegroup;
639158561Sbms    uint16_t i;
640158561Sbms    int sotype;
641158561Sbms    socklen_t sotypelen;
642158561Sbms
643158561Sbms    sotypelen = sizeof(sotype);
644158561Sbms    if (getsockopt(sock, SOL_SOCKET, SO_TYPE, &sotype, &sotypelen) < 0)
645158561Sbms	err(-1, "test_ip_multicast_membership(%s): so_type getsockopt()",
646158561Sbms	    socktypename);
647158561Sbms    /*
648158561Sbms     * Do not perform the test for SOCK_STREAM sockets, as this makes
649158561Sbms     * no sense.
650158561Sbms     */
651158561Sbms    if (sotype == SOCK_STREAM)
652158561Sbms	return;
653158561Sbms    /*
654158561Sbms     * For SOCK_DGRAM and SOCK_RAW sockets, pick a multicast group ID
655158561Sbms     * in subnet 224/5 with 11 random bits in the middle, and the groups
656158561Sbms     * themselves joined in sequential order up to IP_MAX_MEMBERSHIPS.
657158561Sbms     * The 224/8 range has special meaning, so don't use it.
658158561Sbms     */
659158561Sbms    basegroup = 0xEE000000;	/* 224.0.0.0/5 i.e. 5 bits. */
660158561Sbms    basegroup |= ((random() % ((1 << 11) - 1)) << 16);	/* Mid 11 bits. */
661158561Sbms    /*
662158561Sbms     * Join the multicast group(s) on the default multicast interface;
663158561Sbms     * this usually maps to the interface to which the default
664158561Sbms     * route is pointing.
665158561Sbms     */
666158561Sbms    for (i = 0; i < IP_MAX_MEMBERSHIPS; i++) {
667158561Sbms	mreq.imr_multiaddr.s_addr = htonl((basegroup | i));
668158561Sbms	mreq.imr_interface.s_addr = INADDR_ANY;
669158561Sbms	if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
670158561Sbms		       sizeof(mreq)) < 0) {
671158561Sbms		err(-1,
672158561Sbms"test_ip_multicast_membership(%d, %s): failed IP_ADD_MEMBERSHIP (%s, %s)",
673158561Sbms		    sock, socktypename,
674158561Sbms		    inet_ntoa(mreq.imr_multiaddr), "INADDR_ANY");
675158561Sbms	}
676158561Sbms    }
677158561Sbms    for (i = 0; i < IP_MAX_MEMBERSHIPS; i++) {
678158561Sbms	mreq.imr_multiaddr.s_addr = htonl((basegroup | i));
679158561Sbms	mreq.imr_interface.s_addr = INADDR_ANY;
680158561Sbms	if (setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq,
681158561Sbms		       sizeof(mreq)) < 0) {
682158561Sbms		err(-1,
683158561Sbms"test_ip_multicast_membership(%d, %s): failed IP_DROP_MEMBERSHIP (%s, %s)",
684158561Sbms		    sock, socktypename,
685158561Sbms		    inet_ntoa(mreq.imr_multiaddr), "INADDR_ANY");
686158561Sbms	}
687158561Sbms    }
688158561Sbms}
689158561Sbms
690158561Sbms/*
691136384Srwatson * XXX: For now, nothing here.
692136384Srwatson */
693136384Srwatsonstatic void
694136390Srwatsontest_ip_multicast_if(int sock, const char *socktypename)
695136384Srwatson{
696136384Srwatson
697136384Srwatson	/*
698136384Srwatson	 * It's probably worth trying INADDR_ANY and INADDR_LOOPBACK here
699136384Srwatson	 * to see what happens.
700136384Srwatson	 */
701136384Srwatson}
702136384Srwatson
703136384Srwatson/*
704136384Srwatson * XXX: For now, nothing here.
705136384Srwatson */
706136384Srwatsonstatic void
707136390Srwatsontest_ip_multicast_vif(int sock, const char *socktypename)
708136384Srwatson{
709136384Srwatson
710136384Srwatson	/*
711136384Srwatson	 * This requires some knowledge of the number of virtual interfaces,
712136384Srwatson	 * and what is valid.
713136384Srwatson	 */
714136384Srwatson}
715136384Srwatson
716136384Srwatsonstatic void
717136390Srwatsontestsuite(int priv)
718136384Srwatson{
719136390Srwatson	const char *socktypenameset[] = {"SOCK_DGRAM", "SOCK_STREAM",
720136390Srwatson	    "SOCK_RAW"};
721136390Srwatson	int socktypeset[] = {SOCK_DGRAM, SOCK_STREAM, SOCK_RAW};
722136390Srwatson	const char *socktypename;
723136390Srwatson	int i, sock, socktype;
724136384Srwatson
725136390Srwatson	test_ip_hdrincl();
726136384Srwatson
727136390Srwatson	for (i = 0; i < sizeof(socktypeset)/sizeof(int); i++) {
728136390Srwatson		socktype = socktypeset[i];
729136390Srwatson		socktypename = socktypenameset[i];
730136384Srwatson
731136390Srwatson		/*
732136390Srwatson		 * If we can't acquire root privilege, we can't open raw
733136390Srwatson		 * sockets, so don't actually try.
734136390Srwatson		 */
735136390Srwatson		if (getuid() != 0 && socktype == SOCK_RAW)
736136390Srwatson			continue;
737136391Srwatson		if (geteuid() != 0 && !priv && socktype == SOCK_RAW)
738136391Srwatson			continue;
739136384Srwatson
740136390Srwatson		/*
741136390Srwatson		 * XXXRW: On 5.3, this seems not to work for SOCK_RAW.
742136390Srwatson		 */
743136390Srwatson		sock = get_socket(socktype, priv);
744136390Srwatson		if (sock == -1)
745136390Srwatson			err(-1, "get_socket(%s, %d) for test_ip_uchar(IP_TOS)",
746136390Srwatson			    socktypename, priv);
747136390Srwatson		test_ip_uchar(sock, socktypename, IP_TOS, "IP_TOS", 0);
748136390Srwatson		close(sock);
749136384Srwatson
750136390Srwatson		sock = get_socket(socktype, priv);
751136390Srwatson		if (sock == -1)
752136390Srwatson			err(-1, "get_socket(%s %d) for test_ip_uchar(IP_TTL)",
753136390Srwatson			    socktypename, priv);
754136390Srwatson		test_ip_uchar(sock, socktypename, IP_TTL, "IP_TTL", 64);
755136390Srwatson		close(sock);
756136384Srwatson
757136390Srwatson		sock = get_socket(socktype, priv);
758136390Srwatson		if (sock == -1)
759136390Srwatson			err(-1, "get_socket(%s, %d) for test_ip_boolean"
760136390Srwatson			    "(IP_RECVOPTS)", socktypename, priv);
761136390Srwatson		test_ip_boolean(sock, socktypename, IP_RECVOPTS,
762136390Srwatson		    "IP_RECVOPTS", 0, BOOLEAN_ANYONE);
763136390Srwatson		close(sock);
764136384Srwatson
765136390Srwatson		sock = get_socket(socktype, priv);
766136390Srwatson		if (sock == -1)
767136390Srwatson			err(-1, "get_socket(%s, %d) for test_ip_boolean"
768136390Srwatson			     "(IP_RECVRETOPTS)", socktypename, priv);
769136390Srwatson		test_ip_boolean(sock, socktypename, IP_RECVRETOPTS,
770136390Srwatson		    "IP_RECVRETOPTS", 0, BOOLEAN_ANYONE);
771136390Srwatson		close(sock);
772136384Srwatson
773136390Srwatson		sock = get_socket(socktype, priv);
774136390Srwatson		if (sock == -1)
775136390Srwatson			err(-1, "get_socket(%s, %d) for test_ip_boolean"
776136390Srwatson			    "(IP_RECVDSTADDR)", socktypename, priv);
777136390Srwatson		test_ip_boolean(sock, socktypename, IP_RECVDSTADDR,
778136390Srwatson		    "IP_RECVDSTADDR", 0, BOOLEAN_ANYONE);
779136390Srwatson		close(sock);
780136384Srwatson
781136390Srwatson		sock = get_socket(socktype, priv);
782136390Srwatson		if (sock == -1)
783136390Srwatson			err(-1, "get_socket(%s, %d) for test_ip_boolean"
784136390Srwatson			    "(IP_RECVTTL)", socktypename, priv);
785136390Srwatson		test_ip_boolean(sock, socktypename, IP_RECVTTL, "IP_RECVTTL",
786136390Srwatson		    0, BOOLEAN_ANYONE);
787136390Srwatson		close(sock);
788136384Srwatson
789136390Srwatson		sock = get_socket(socktype, priv);
790136390Srwatson		if (sock == -1)
791136390Srwatson			err(-1, "get_socket(%s, %d) for test_ip_boolean"
792136390Srwatson			    "(IP_RECVIF)", socktypename, priv);
793136390Srwatson		test_ip_boolean(sock, socktypename, IP_RECVIF, "IP_RECVIF",
794136390Srwatson		    0, BOOLEAN_ANYONE);
795136390Srwatson		close(sock);
796136384Srwatson
797136390Srwatson		sock = get_socket(socktype, priv);
798136390Srwatson		if (sock == -1)
799136390Srwatson			err(-1, "get_socket(%s, %d) for test_ip_boolean"
800136390Srwatson			    "(IP_FAITH)", socktypename, priv);
801136390Srwatson		test_ip_boolean(sock, socktypename, IP_FAITH, "IP_FAITH", 0,
802136390Srwatson		    BOOLEAN_ANYONE);
803136390Srwatson		close(sock);
804136390Srwatson
805136390Srwatson		sock = get_socket(socktype, priv);
806136390Srwatson		if (sock == -1)
807136390Srwatson			err(-1, "get_socket(%s, %d) for test_ip_boolean"
808136390Srwatson			    "(IP_ONESBCAST)", socktypename, priv);
809136390Srwatson		test_ip_boolean(sock, socktypename, IP_ONESBCAST,
810136390Srwatson		    "IP_ONESBCAST", 0, BOOLEAN_ANYONE);
811136390Srwatson		close(sock);
812136390Srwatson
813136390Srwatson		/*
814136390Srwatson		 * Test the multicast TTL exactly as we would the regular
815136390Srwatson		 * TTL, only expect a different default.
816136390Srwatson		 */
817136390Srwatson		sock = get_socket(socktype, priv);
818136390Srwatson		if (sock == -1)
819136390Srwatson			err(-1, "get_socket(%s, %d) for IP_MULTICAST_TTL",
820136390Srwatson			    socktypename, priv);
821136390Srwatson		test_ip_uchar(sock, socktypename, IP_MULTICAST_TTL,
822136390Srwatson		    "IP_MULTICAST_TTL", 1);
823136390Srwatson		close(sock);
824136390Srwatson
825136390Srwatson		/*
826136390Srwatson		 * The multicast loopback flag can be tested using our
827136390Srwatson		 * boolean tester, but only because the FreeBSD API is a bit
828136390Srwatson		 * more flexible than earlir APIs and will accept an int as
829136390Srwatson		 * well as a u_char.  Loopback is enabled by default.
830136390Srwatson		 */
831136390Srwatson		sock = get_socket(socktype, priv);
832136390Srwatson		if (sock == -1)
833136390Srwatson			err(-1, "get_socket(%s, %d) for IP_MULTICAST_LOOP",
834136390Srwatson			    socktypename, priv);
835136390Srwatson		test_ip_boolean(sock, socktypename, IP_MULTICAST_LOOP,
836136390Srwatson		    "IP_MULTICAST_LOOP", 1, BOOLEAN_ANYONE);
837136390Srwatson		close(sock);
838136390Srwatson
839136390Srwatson		sock = get_socket(socktype, priv);
840136390Srwatson		if (sock == -1)
841136390Srwatson			err(-1, "get_socket(%s, %d) for test_ip_options",
842136390Srwatson			    socktypename, priv);
843136390Srwatson		//test_ip_options(sock, socktypename);
844136390Srwatson		close(sock);
845136390Srwatson
846158561Sbms		sock = get_socket(socktype, priv);
847158561Sbms		if (sock == -1)
848158561Sbms			err(-1, "get_socket(%s, %d) for test_ip_options",
849158561Sbms			    socktypename, priv);
850158561Sbms		test_ip_multicast_membership(sock, socktypename);
851158561Sbms		close(sock);
852158561Sbms
853136390Srwatson		test_ip_multicast_if(0, NULL);
854136390Srwatson		test_ip_multicast_vif(0, NULL);
855136390Srwatson		/*
856136390Srwatson		 * XXX: Still need to test:
857136390Srwatson		 * IP_PORTRANGE
858136390Srwatson		 * IP_IPSEC_POLICY?
859136390Srwatson		 */
860136390Srwatson	}
861136384Srwatson}
862136384Srwatson
863136384Srwatson/*
864136384Srwatson * Very simply exercise that we can get and set each option.  If we're running
865136384Srwatson * as root, run it also as nobody.  If not as root, complain about that.
866136384Srwatson */
867136384Srwatsonint
868136384Srwatsonmain(int argc, char *argv[])
869136384Srwatson{
870136384Srwatson
871137587Snik	printf("1..1\n");
872136384Srwatson	if (geteuid() != 0) {
873136390Srwatson		warnx("Not running as root, can't run tests as root");
874136384Srwatson		fprintf(stderr, "\n");
875136390Srwatson		fprintf(stderr,
876136390Srwatson		   "Running tests with uid %d sock uid %d\n", geteuid(),
877136390Srwatson		    geteuid());
878136390Srwatson		testsuite(PRIV_ASIS);
879136384Srwatson	} else {
880136390Srwatson		fprintf(stderr,
881136390Srwatson		    "Running tests with ruid %d euid %d sock uid 0\n",
882136390Srwatson		    getuid(), geteuid());
883136390Srwatson		testsuite(PRIV_ASIS);
884136390Srwatson		if (seteuid(65534) != 0)
885136390Srwatson			err(-1, "seteuid(65534)");
886136390Srwatson		fprintf(stderr,
887136391Srwatson		    "Running tests with ruid %d euid %d sock uid 65534\n",
888136391Srwatson		    getuid(), geteuid());
889136391Srwatson		testsuite(PRIV_ASIS);
890136391Srwatson		fprintf(stderr,
891136390Srwatson		    "Running tests with ruid %d euid %d sock uid 0\n",
892136390Srwatson		    getuid(), geteuid());
893136390Srwatson		testsuite(PRIV_GETROOT);
894136384Srwatson	}
895137587Snik	printf("ok 1 - ipsockopt\n");
896136384Srwatson	exit(0);
897136384Srwatson}
898