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