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