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