1239844Sdes/*- 2239844Sdes * Copyright (c) 2004 Robert N. M. Watson 3239844Sdes * All rights reserved. 4239844Sdes * 5239844Sdes * Redistribution and use in source and binary forms, with or without 6239844Sdes * modification, are permitted provided that the following conditions 7239844Sdes * are met: 8239844Sdes * 1. Redistributions of source code must retain the above copyright 9239844Sdes * notice, this list of conditions and the following disclaimer. 10239844Sdes * 2. Redistributions in binary form must reproduce the above copyright 11239844Sdes * notice, this list of conditions and the following disclaimer in the 12239844Sdes * documentation and/or other materials provided with the distribution. 13239844Sdes * 14239844Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15239844Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16239844Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17239844Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18239844Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19239844Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20239844Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21239844Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22239844Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23239844Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24239844Sdes * SUCH DAMAGE. 25239844Sdes * 26239844Sdes * $FreeBSD$ 27239844Sdes */ 28295367Sdes 29295367Sdes#include <sys/types.h> 30239844Sdes#include <sys/socket.h> 31239844Sdes 32239844Sdes#include <netinet/in.h> 33239844Sdes#include <netinet/in_systm.h> 34239844Sdes#include <netinet/ip.h> 35239844Sdes#include <arpa/inet.h> 36239844Sdes 37239844Sdes#include <err.h> 38239844Sdes#include <errno.h> 39239844Sdes#include <getopt.h> 40239844Sdes#include <stdio.h> 41239844Sdes#include <stdlib.h> 42239844Sdes#include <string.h> 43239844Sdes#include <unistd.h> 44239844Sdes 45239844Sdesstatic int dorandom = 0; 46295367Sdesstatic int nmcastgroups = IP_MAX_MEMBERSHIPS; 47239844Sdesstatic int verbose = 0; 48239844Sdes 49239844Sdes/* 50248613Sdes * The test tool exercises IP-level socket options by interrogating the 51239844Sdes * getsockopt()/setsockopt() APIs. It does not currently test that the 52239844Sdes * intended semantics of each option are implemented (i.e., that setting IP 53239844Sdes * options on the socket results in packets with the desired IP options in 54239844Sdes * it). 55239844Sdes */ 56239844Sdes 57239844Sdes/* 58239844Sdes * get_socket() is a wrapper function that returns a socket of the specified 59239844Sdes * type, and created with or without restored root privilege (if running 60239844Sdes * with a real uid of root and an effective uid of some other user). This 61239844Sdes * us to test whether the same rights are granted using a socket with a 62239844Sdes * privileged cached credential vs. a socket with a regular credential. 63239844Sdes */ 64239844Sdes#define PRIV_ASIS 0 65239844Sdes#define PRIV_GETROOT 1 66239844Sdesstatic int 67239844Sdesget_socket_unpriv(int type) 68239844Sdes{ 69239844Sdes 70239844Sdes return (socket(PF_INET, type, 0)); 71239844Sdes} 72239844Sdes 73239844Sdesstatic int 74239844Sdesget_socket_priv(int type) 75239844Sdes{ 76239844Sdes uid_t olduid; 77239844Sdes int sock; 78239844Sdes 79239844Sdes if (getuid() != 0) 80239844Sdes errx(-1, "get_sock_priv: running without real uid 0"); 81239844Sdes 82239844Sdes olduid = geteuid(); 83295367Sdes if (seteuid(0) < 0) 84295367Sdes err(-1, "get_sock_priv: seteuid(0)"); 85295367Sdes 86295367Sdes sock = socket(PF_INET, type, 0); 87295367Sdes 88295367Sdes if (seteuid(olduid) < 0) 89295367Sdes err(-1, "get_sock_priv: seteuid(%d)", olduid); 90295367Sdes 91295367Sdes return (sock); 92295367Sdes} 93239844Sdes 94239844Sdesstatic int 95239844Sdesget_socket(int type, int priv) 96239844Sdes{ 97239844Sdes 98239844Sdes if (priv) 99239844Sdes return (get_socket_priv(type)); 100239844Sdes else 101239844Sdes return (get_socket_unpriv(type)); 102239844Sdes} 103239844Sdes 104295367Sdes/* 105295367Sdes * Exercise the IP_OPTIONS socket option. Confirm the following properties: 106323124Sdes * 107323124Sdes * - That there is no initial set of options (length returned is 0). 108323124Sdes * - That if we set a specific set of options, we can read it back. 109323124Sdes * - That if we then reset the options, they go away. 110323124Sdes * 111323124Sdes * Use a UDP socket for this. 112295367Sdes */ 113295367Sdesstatic void 114295367Sdestest_ip_options(int sock, const char *socktypename) 115295367Sdes{ 116295367Sdes u_int32_t new_options, test_options[2]; 117295367Sdes socklen_t len; 118295367Sdes 119239844Sdes /* 120295367Sdes * Start off by confirming the default IP options on a socket are to 121295367Sdes * have no options set. 122295367Sdes */ 123295367Sdes len = sizeof(test_options); 124295367Sdes if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0) 125295367Sdes err(-1, "test_ip_options(%s): initial getsockopt()", 126295367Sdes socktypename); 127295367Sdes 128295367Sdes if (len != 0) 129295367Sdes errx(-1, "test_ip_options(%s): initial getsockopt() returned " 130295367Sdes "%d bytes", socktypename, len); 131295367Sdes 132295367Sdes#define TEST_MAGIC 0xc34e4212 133295367Sdes#define NEW_OPTIONS htonl(IPOPT_EOL | (IPOPT_NOP << 8) | (IPOPT_NOP << 16) \ 134295367Sdes | (IPOPT_NOP << 24)) 135295367Sdes 136295367Sdes /* 137295367Sdes * Write some new options into the socket. 138295367Sdes */ 139255767Sdes new_options = NEW_OPTIONS; 140248613Sdes if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, &new_options, 141295367Sdes sizeof(new_options)) < 0) 142239844Sdes err(-1, "test_ip_options(%s): setsockopt(NOP|NOP|NOP|EOL)", 143264377Sdes socktypename); 144295367Sdes 145295367Sdes /* 146239844Sdes * Store some random cruft in a local variable and retrieve the 147295367Sdes * options to make sure they set. Note that we pass in an array 148295367Sdes * of u_int32_t's so that if whatever ended up in the option was 149295367Sdes * larger than what we put in, we find out about it here. 150295367Sdes */ 151295367Sdes test_options[0] = TEST_MAGIC; 152295367Sdes test_options[1] = TEST_MAGIC; 153295367Sdes len = sizeof(test_options); 154295367Sdes if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0) 155295367Sdes err(-1, "test_ip_options(%s): getsockopt() after set", 156296781Sdes socktypename); 157296781Sdes 158296781Sdes /* 159295367Sdes * Getting the right amount back is important. 160295367Sdes */ 161295367Sdes if (len != sizeof(new_options)) 162295367Sdes errx(-1, "test_ip_options(%s): getsockopt() after set " 163239844Sdes "returned %d bytes of data", socktypename, len); 164248613Sdes 165248613Sdes /* 166239844Sdes * One posible failure mode is that the call succeeds but neglects to 167248613Sdes * copy out the data. 168295367Sdes */ 169295367Sdes if (test_options[0] == TEST_MAGIC) 170295367Sdes errx(-1, "test_ip_options(%s): getsockopt() after set didn't " 171295367Sdes "return data", socktypename); 172295367Sdes 173295367Sdes /* 174295367Sdes * Make sure we get back what we wrote on. 175239844Sdes */ 176295367Sdes if (new_options != test_options[0]) 177295367Sdes errx(-1, "test_ip_options(%s): getsockopt() after set " 178295367Sdes "returned wrong options (%08x, %08x)", socktypename, 179295367Sdes new_options, test_options[0]); 180295367Sdes 181295367Sdes /* 182295367Sdes * Now we reset the value to make sure clearing works. 183295367Sdes */ 184295367Sdes if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, NULL, 0) < 0) 185295367Sdes err(-1, "test_ip_options(%s): setsockopt() to reset", 186295367Sdes socktypename); 187295367Sdes 188295367Sdes /* 189239844Sdes * Make sure it was really cleared. 190239844Sdes */ 191295367Sdes test_options[0] = TEST_MAGIC; 192295367Sdes test_options[1] = TEST_MAGIC; 193295367Sdes len = sizeof(test_options); 194295367Sdes if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0) 195295367Sdes err(-1, "test_ip_options(%s): getsockopt() after reset", 196295367Sdes socktypename); 197295367Sdes 198295367Sdes if (len != 0) 199239844Sdes errx(-1, "test_ip_options(%s): getsockopt() after reset " 200239844Sdes "returned %d bytes", socktypename, len); 201295367Sdes} 202295367Sdes 203295367Sdes/* 204295367Sdes * This test checks the behavior of the IP_HDRINCL socket option, which 205295367Sdes * allows users with privilege to specify the full header on an IP raw 206295367Sdes * socket. We test that the option can only be used with raw IP sockets, not 207295367Sdes * with UDP or TCP sockets. We also confirm that the raw socket is only 208295367Sdes * available to a privileged user (subject to the UID when called). We 209295367Sdes * confirm that it defaults to off 210295367Sdes * 211295367Sdes * Unlike other tests, doesn't use caller-provided socket. Probably should 212239844Sdes * be fixed. 213239844Sdes */ 214239844Sdesstatic void 215239844Sdestest_ip_hdrincl(void) 216239844Sdes{ 217239844Sdes int flag[2], sock; 218239844Sdes socklen_t len; 219239844Sdes 220239844Sdes /* 221239844Sdes * Try to receive or set the IP_HDRINCL flag on a TCP socket. 222239844Sdes */ 223239844Sdes sock = socket(PF_INET, SOCK_STREAM, 0); 224239844Sdes if (sock == -1) 225262566Sdes err(-1, "test_ip_hdrincl(): socket(SOCK_STREAM)"); 226239844Sdes 227239844Sdes flag[0] = -1; 228239844Sdes len = sizeof(flag[0]); 229239844Sdes if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0) 230239844Sdes err(-1, "test_ip_hdrincl(): initial getsockopt(IP_HDRINCL)"); 231239844Sdes 232239844Sdes if (errno != ENOPROTOOPT) 233239844Sdes errx(-1, "test_ip_hdrincl(): initial getsockopt(IP_HDRINC) " 234239844Sdes "returned %d (%s) not ENOPROTOOPT", errno, 235239844Sdes strerror(errno)); 236239844Sdes 237239844Sdes flag[0] = 1; 238239844Sdes if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0])) 239239844Sdes == 0) 240239844Sdes err(-1,"test_ip_hdrincl(): setsockopt(IP_HDRINCL) on TCP " 241239844Sdes "succeeded\n"); 242239844Sdes 243239844Sdes if (errno != ENOPROTOOPT) 244239844Sdes errx(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on TCP " 245239844Sdes "returned %d (%s) not ENOPROTOOPT\n", errno, 246239844Sdes strerror(errno)); 247239844Sdes 248239844Sdes close(sock); 249239844Sdes 250239844Sdes /* 251239844Sdes * Try to receive or set the IP_HDRINCL flag on a UDP socket. 252239844Sdes */ 253239844Sdes sock = socket(PF_INET, SOCK_DGRAM, 0); 254239844Sdes if (sock == -1) 255239844Sdes err(-1, "test_ip_hdrincl(): socket(SOCK_DGRAM"); 256239844Sdes 257239844Sdes flag[0] = -1; 258239844Sdes len = sizeof(flag[0]); 259239844Sdes if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0) 260239844Sdes err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on UDP " 261239844Sdes "succeeded\n"); 262239844Sdes 263239844Sdes if (errno != ENOPROTOOPT) 264239844Sdes errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on UDP " 265239844Sdes "returned %d (%s) not ENOPROTOOPT\n", errno, 266239844Sdes strerror(errno)); 267239844Sdes 268239844Sdes if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0])) 269239844Sdes == 0) 270239844Sdes err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on UDP " 271239844Sdes "succeeded\n"); 272239844Sdes 273239844Sdes if (errno != ENOPROTOOPT) 274239844Sdes errx(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on UDP " 275239844Sdes "returned %d (%s) not ENOPROTOOPT\n", errno, 276239844Sdes strerror(errno)); 277239844Sdes 278239844Sdes close(sock); 279239844Sdes 280239844Sdes /* 281239849Sdes * Now try on a raw socket. Access ontrol should prevent non-root 282239844Sdes * users from creating the raw socket, so check that here based on 283239844Sdes * geteuid(). If we're non-root, we just return assuming the socket 284239844Sdes * create fails since the remainder of the tests apply only on a raw 285239844Sdes * socket. 286239844Sdes */ 287239844Sdes sock = socket(PF_INET, SOCK_RAW, 0); 288239844Sdes if (geteuid() != 0) { 289239844Sdes if (sock != -1) 290239844Sdes errx(-1, "test_ip_hdrincl: created raw socket as " 291239844Sdes "uid %d", geteuid()); 292239844Sdes return; 293239844Sdes } 294239844Sdes if (sock == -1) 295239844Sdes err(-1, "test_ip_hdrincl(): socket(PF_INET, SOCK_RAW)"); 296239844Sdes 297239844Sdes /* 298239844Sdes * Make sure the initial value of the flag is 0 (disabled). 299239844Sdes */ 300239849Sdes flag[0] = -1; 301239849Sdes flag[1] = -1; 302239844Sdes len = sizeof(flag); 303239849Sdes if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0) 304239849Sdes err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on raw " 305239844Sdes "socket"); 306239844Sdes 307239849Sdes if (len != sizeof(flag[0])) 308239844Sdes errx(-1, "test_ip_hdrincl(): %d bytes returned on " 309239849Sdes "initial get\n", len); 310239849Sdes 311239849Sdes if (flag[0] != 0) 312239844Sdes errx(-1, "test_ip_hdrincl(): initial flag value of %d\n", 313239844Sdes flag[0]); 314239844Sdes 315239844Sdes /* 316239844Sdes * Enable the IP_HDRINCL flag. 317239844Sdes */ 318239844Sdes flag[0] = 1; 319239844Sdes if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0])) 320239844Sdes < 0) 321239844Sdes err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL, 1)"); 322239844Sdes 323239844Sdes /* 324239844Sdes * Check that the IP_HDRINCL flag was set. 325239844Sdes */ 326239844Sdes flag[0] = -1; 327239844Sdes 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 */ 390static void 391test_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 530static void 531test_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 */ 640static void 641test_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 */ 713static void 714test_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 */ 726static void 727test_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 736static void 737testsuite(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 883static void 884usage() 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 */ 895int 896main(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