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
get_socket_unpriv(int type)67 get_socket_unpriv(int type)
68 {
69
70 return (socket(PF_INET, type, 0));
71 }
72
73 static int
get_socket_priv(int type)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
get_socket(int type,int priv)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
test_ip_options(int sock,const char * socktypename)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
test_ip_hdrincl(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
test_ip_uchar(int sock,const char * socktypename,int option,const char * optionname,int initial)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
test_ip_boolean(int sock,const char * socktypename,int option,char * optionname,int initial,int rootonly)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
test_ip_multicast_membership(int sock,const char * socktypename)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
test_ip_multicast_if(int sock,const char * socktypename)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
test_ip_multicast_vif(int sock,const char * socktypename)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
testsuite(int priv)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
usage()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
main(int argc,char * argv[])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 }
944