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 65 get_socket_unpriv(int type) 66 { 67 68 return (socket(PF_INET, type, 0)); 69 } 70 71 static int 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 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 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 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 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 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 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 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 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 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 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 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