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