Path: blob/main/tools/regression/netinet/ipsockopt/ipsockopt.c
39491 views
/*-1* Copyright (c) 2004 Robert N. M. Watson2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526#include <sys/types.h>27#include <sys/socket.h>2829#include <netinet/in.h>30#include <netinet/in_systm.h>31#include <netinet/ip.h>32#include <arpa/inet.h>3334#include <err.h>35#include <errno.h>36#include <getopt.h>37#include <stdio.h>38#include <stdlib.h>39#include <string.h>40#include <unistd.h>4142static int dorandom = 0;43static int nmcastgroups = IP_MAX_MEMBERSHIPS;44static int verbose = 0;4546/*47* The test tool exercises IP-level socket options by interrogating the48* getsockopt()/setsockopt() APIs. It does not currently test that the49* intended semantics of each option are implemented (i.e., that setting IP50* options on the socket results in packets with the desired IP options in51* it).52*/5354/*55* get_socket() is a wrapper function that returns a socket of the specified56* type, and created with or without restored root privilege (if running57* with a real uid of root and an effective uid of some other user). This58* us to test whether the same rights are granted using a socket with a59* privileged cached credential vs. a socket with a regular credential.60*/61#define PRIV_ASIS 062#define PRIV_GETROOT 163static int64get_socket_unpriv(int type)65{6667return (socket(PF_INET, type, 0));68}6970static int71get_socket_priv(int type)72{73uid_t olduid;74int sock;7576if (getuid() != 0)77errx(-1, "get_sock_priv: running without real uid 0");7879olduid = geteuid();80if (seteuid(0) < 0)81err(-1, "get_sock_priv: seteuid(0)");8283sock = socket(PF_INET, type, 0);8485if (seteuid(olduid) < 0)86err(-1, "get_sock_priv: seteuid(%d)", olduid);8788return (sock);89}9091static int92get_socket(int type, int priv)93{9495if (priv)96return (get_socket_priv(type));97else98return (get_socket_unpriv(type));99}100101/*102* Exercise the IP_OPTIONS socket option. Confirm the following properties:103*104* - That there is no initial set of options (length returned is 0).105* - That if we set a specific set of options, we can read it back.106* - That if we then reset the options, they go away.107*108* Use a UDP socket for this.109*/110static void111test_ip_options(int sock, const char *socktypename)112{113u_int32_t new_options, test_options[2];114socklen_t len;115116/*117* Start off by confirming the default IP options on a socket are to118* have no options set.119*/120len = sizeof(test_options);121if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)122err(-1, "test_ip_options(%s): initial getsockopt()",123socktypename);124125if (len != 0)126errx(-1, "test_ip_options(%s): initial getsockopt() returned "127"%d bytes", socktypename, len);128129#define TEST_MAGIC 0xc34e4212130#define NEW_OPTIONS htonl(IPOPT_EOL | (IPOPT_NOP << 8) | (IPOPT_NOP << 16) \131| (IPOPT_NOP << 24))132133/*134* Write some new options into the socket.135*/136new_options = NEW_OPTIONS;137if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, &new_options,138sizeof(new_options)) < 0)139err(-1, "test_ip_options(%s): setsockopt(NOP|NOP|NOP|EOL)",140socktypename);141142/*143* Store some random cruft in a local variable and retrieve the144* options to make sure they set. Note that we pass in an array145* of u_int32_t's so that if whatever ended up in the option was146* larger than what we put in, we find out about it here.147*/148test_options[0] = TEST_MAGIC;149test_options[1] = TEST_MAGIC;150len = sizeof(test_options);151if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)152err(-1, "test_ip_options(%s): getsockopt() after set",153socktypename);154155/*156* Getting the right amount back is important.157*/158if (len != sizeof(new_options))159errx(-1, "test_ip_options(%s): getsockopt() after set "160"returned %d bytes of data", socktypename, len);161162/*163* One possible failure mode is that the call succeeds but neglects to164* copy out the data.165*/166if (test_options[0] == TEST_MAGIC)167errx(-1, "test_ip_options(%s): getsockopt() after set didn't "168"return data", socktypename);169170/*171* Make sure we get back what we wrote on.172*/173if (new_options != test_options[0])174errx(-1, "test_ip_options(%s): getsockopt() after set "175"returned wrong options (%08x, %08x)", socktypename,176new_options, test_options[0]);177178/*179* Now we reset the value to make sure clearing works.180*/181if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, NULL, 0) < 0)182err(-1, "test_ip_options(%s): setsockopt() to reset",183socktypename);184185/*186* Make sure it was really cleared.187*/188test_options[0] = TEST_MAGIC;189test_options[1] = TEST_MAGIC;190len = sizeof(test_options);191if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)192err(-1, "test_ip_options(%s): getsockopt() after reset",193socktypename);194195if (len != 0)196errx(-1, "test_ip_options(%s): getsockopt() after reset "197"returned %d bytes", socktypename, len);198}199200/*201* This test checks the behavior of the IP_HDRINCL socket option, which202* allows users with privilege to specify the full header on an IP raw203* socket. We test that the option can only be used with raw IP sockets, not204* with UDP or TCP sockets. We also confirm that the raw socket is only205* available to a privileged user (subject to the UID when called). We206* confirm that it defaults to off207*208* Unlike other tests, doesn't use caller-provided socket. Probably should209* be fixed.210*/211static void212test_ip_hdrincl(void)213{214int flag[2], sock;215socklen_t len;216217/*218* Try to receive or set the IP_HDRINCL flag on a TCP socket.219*/220sock = socket(PF_INET, SOCK_STREAM, 0);221if (sock == -1)222err(-1, "test_ip_hdrincl(): socket(SOCK_STREAM)");223224flag[0] = -1;225len = sizeof(flag[0]);226if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0)227err(-1, "test_ip_hdrincl(): initial getsockopt(IP_HDRINCL)");228229if (errno != ENOPROTOOPT)230errx(-1, "test_ip_hdrincl(): initial getsockopt(IP_HDRINC) "231"returned %d (%s) not ENOPROTOOPT", errno,232strerror(errno));233234flag[0] = 1;235if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))236== 0)237err(-1,"test_ip_hdrincl(): setsockopt(IP_HDRINCL) on TCP "238"succeeded\n");239240if (errno != ENOPROTOOPT)241errx(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on TCP "242"returned %d (%s) not ENOPROTOOPT\n", errno,243strerror(errno));244245close(sock);246247/*248* Try to receive or set the IP_HDRINCL flag on a UDP socket.249*/250sock = socket(PF_INET, SOCK_DGRAM, 0);251if (sock == -1)252err(-1, "test_ip_hdrincl(): socket(SOCK_DGRAM");253254flag[0] = -1;255len = sizeof(flag[0]);256if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0)257err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on UDP "258"succeeded\n");259260if (errno != ENOPROTOOPT)261errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on UDP "262"returned %d (%s) not ENOPROTOOPT\n", errno,263strerror(errno));264265if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))266== 0)267err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on UDP "268"succeeded\n");269270if (errno != ENOPROTOOPT)271errx(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on UDP "272"returned %d (%s) not ENOPROTOOPT\n", errno,273strerror(errno));274275close(sock);276277/*278* Now try on a raw socket. Access ontrol should prevent non-root279* users from creating the raw socket, so check that here based on280* geteuid(). If we're non-root, we just return assuming the socket281* create fails since the remainder of the tests apply only on a raw282* socket.283*/284sock = socket(PF_INET, SOCK_RAW, 0);285if (geteuid() != 0) {286if (sock != -1)287errx(-1, "test_ip_hdrincl: created raw socket as "288"uid %d", geteuid());289return;290}291if (sock == -1)292err(-1, "test_ip_hdrincl(): socket(PF_INET, SOCK_RAW)");293294/*295* Make sure the initial value of the flag is 0 (disabled).296*/297flag[0] = -1;298flag[1] = -1;299len = sizeof(flag);300if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)301err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on raw "302"socket");303304if (len != sizeof(flag[0]))305errx(-1, "test_ip_hdrincl(): %d bytes returned on "306"initial get\n", len);307308if (flag[0] != 0)309errx(-1, "test_ip_hdrincl(): initial flag value of %d\n",310flag[0]);311312/*313* Enable the IP_HDRINCL flag.314*/315flag[0] = 1;316if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))317< 0)318err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL, 1)");319320/*321* Check that the IP_HDRINCL flag was set.322*/323flag[0] = -1;324flag[1] = -1;325len = sizeof(flag);326if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)327err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) after "328"set");329330if (flag[0] == 0)331errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) "332"after set had flag of %d\n", flag[0]);333334#define HISTORICAL_INP_HDRINCL 8335if (flag[0] != HISTORICAL_INP_HDRINCL)336warnx("test_ip_hdrincl(): WARNING: getsockopt(IP_H"337"DRINCL) after set had non-historical value of %d\n",338flag[0]);339340/*341* Reset the IP_HDRINCL flag to 0.342*/343flag[0] = 0;344if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))345< 0)346err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL, 0)");347348/*349* Check that the IP_HDRINCL flag was reset to 0.350*/351flag[0] = -1;352flag[1] = -1;353len = sizeof(flag);354if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)355err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) after "356"reset");357358if (flag[0] != 0)359errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) "360"after set had flag of %d\n", flag[0]);361362close(sock);363}364365/*366* As with other non-int or larger sized socket options, the IP_TOS and367* IP_TTL fields in kernel is stored as an 8-bit value, reflecting the IP368* header fields, but useful I/O to the field occurs using 32-bit integers.369* The FreeBSD kernel will permit writes from variables at least an int in370* size (and ignore additional bytes), and will permit a read to buffers 1371* byte or larger (but depending on endianness, may truncate out useful372* values if the caller provides less room).373*374* Given the limitations of the API, use a UDP socket to confirm that the375* following are true:376*377* - We can read the IP_TOS/IP_TTL options.378* - The initial value of the TOS option is 0, TTL is 64.379* - That if we provide more than 32 bits of storage, we get back only 32380* bits of data.381* - When we set it to a non-zero value expressible with a u_char, we can382* read that value back.383* - When we reset it back to zero, we can read it as 0.384* - When we set it to a value >255, the value is truncated to something less385* than 255.386*/387static void388test_ip_uchar(int sock, const char *socktypename, int option,389const char *optionname, int initial)390{391int val[2];392socklen_t len;393394/*395* Check that the initial value is 0, and that the size is one396* u_char;397*/398val[0] = -1;399val[1] = -1;400len = sizeof(val);401if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)402err(-1, "test_ip_uchar(%s, %s): initial getsockopt()",403socktypename, optionname);404405if (len != sizeof(val[0]))406errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() "407"returned %d bytes", socktypename, optionname, len);408409if (val[0] == -1)410errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() didn't "411"return data", socktypename, optionname);412413if (val[0] != initial)414errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() "415"returned value of %d, not %d", socktypename, optionname,416val[0], initial);417418/*419* Set the field to a valid value.420*/421val[0] = 128;422val[1] = -1;423if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0)424err(-1, "test_ip_uchar(%s, %s): setsockopt(128)",425socktypename, optionname);426427/*428* Check that when we read back the field, we get the same value.429*/430val[0] = -1;431val[1] = -1;432len = sizeof(val);433if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)434err(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "435"128", socktypename, optionname);436437if (len != sizeof(val[0]))438errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "439"128 returned %d bytes", socktypename, optionname, len);440441if (val[0] == -1)442errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "443"128 didn't return data", socktypename, optionname);444445if (val[0] != 128)446errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "447"128 returned %d", socktypename, optionname, val[0]);448449/*450* Reset the value to 0, check that it was reset.451*/452val[0] = 0;453val[1] = 0;454if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0)455err(-1, "test_ip_uchar(%s, %s): setsockopt() to reset from "456"128", socktypename, optionname);457458if (len != sizeof(val[0]))459errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "460"from 128 returned %d bytes", socktypename, optionname,461len);462463if (val[0] == -1)464errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "465"from 128 didn't return data", socktypename, optionname);466467if (val[0] != 0)468errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "469"from 128 returned %d", socktypename, optionname,470val[0]);471472/*473* Set the value to something out of range and check that it comes474* back truncated, or that we get EINVAL back. Traditional u_char475* IP socket options truncate, but newer ones (such as multicast476* socket options) will return EINVAL.477*/478val[0] = 32000;479val[1] = -1;480if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0) {481/*482* EINVAL is a fine outcome, no need to run the truncation483* tests.484*/485if (errno == EINVAL)486return;487err(-1, "test_ip_uchar(%s, %s): getsockopt(32000)",488socktypename, optionname);489}490491val[0] = -1;492val[1] = -1;493len = sizeof(val);494if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)495err(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "496"32000", socktypename, optionname);497498if (len != sizeof(val[0]))499errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "500"32000 returned %d bytes", socktypename, optionname,501len);502503if (val[0] == -1)504errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "505"32000 didn't return data", socktypename, optionname);506507if (val[0] == 32000)508errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "509"32000 returned 32000: failed to truncate", socktypename,510optionname);511}512513/*514* Generic test for a boolean socket option. Caller provides the option515* number, string name, expected default (initial) value, and whether or not516* the option is root-only. For each option, test:517*518* - That we can read the option.519* - That the initial value is as expected.520* - That we can modify the value.521* - That on modification, the new value can be read back.522* - That we can reset the value.523* - that on reset, the new value can be read back.524*/525#define BOOLEAN_ANYONE 1526#define BOOLEAN_ROOTONLY 1527static void528test_ip_boolean(int sock, const char *socktypename, int option,529char *optionname, int initial, int rootonly)530{531int newvalue, val[2];532socklen_t len;533534/*535* The default for a boolean might be true or false. If it's false,536* we will try setting it to true (but using a non-1 value of true).537* If it's true, we'll set it to false.538*/539if (initial == 0)540newvalue = 0xff;541else542newvalue = 0;543544val[0] = -1;545val[1] = -1;546len = sizeof(val);547if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)548err(-1, "test_ip_boolean: initial getsockopt()");549550if (len != sizeof(val[0]))551errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "552"returned %d bytes", socktypename, optionname, len);553554if (val[0] == -1)555errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "556"didn't return data", socktypename, optionname);557558if (val[0] != initial)559errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "560"returned %d (expected %d)", socktypename, optionname,561val[0], initial);562563/*564* Set the socket option to a new non-default value.565*/566if (setsockopt(sock, IPPROTO_IP, option, &newvalue, sizeof(newvalue))567< 0)568err(-1, "test_ip_boolean(%s, %s): setsockopt() to %d",569socktypename, optionname, newvalue);570571/*572* Read the value back and see if it is not the default (note: will573* not be what we set it to, as we set it to 0xff above).574*/575val[0] = -1;576val[1] = -1;577len = sizeof(val);578if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)579err(-1, "test_ip_boolean(%s, %s): getsockopt() after set to "580"%d", socktypename, optionname, newvalue);581582if (len != sizeof(val[0]))583errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "584"to %d returned %d bytes", socktypename, optionname,585newvalue, len);586587if (val[0] == -1)588errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "589"to %d didn't return data", socktypename, optionname,590newvalue);591592/*593* If we set it to true, check for '1', otherwise '0.594*/595if (val[0] != (newvalue ? 1 : 0))596errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "597"to %d returned %d", socktypename, optionname, newvalue,598val[0]);599600/*601* Reset to initial value.602*/603newvalue = initial;604if (setsockopt(sock, IPPROTO_IP, option, &newvalue, sizeof(newvalue))605< 0)606err(-1, "test_ip_boolean(%s, %s): setsockopt() to reset",607socktypename, optionname);608609/*610* Check reset version.611*/612val[0] = -1;613val[1] = -1;614len = sizeof(val);615if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)616err(-1, "test_ip_boolean(%s, %s): getsockopt() after reset",617socktypename, optionname);618619if (len != sizeof(val[0]))620errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "621"returned %d bytes", socktypename, optionname, len);622623if (val[0] == -1)624errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "625"didn't return data", socktypename, optionname);626627if (val[0] != newvalue)628errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "629"returned %d", socktypename, optionname, newvalue);630}631632/*633* Test the IP_ADD_MEMBERSHIP socket option, and the dynamic allocator634* for the imo_membership vector which now hangs off struct ip_moptions.635* We then call IP_DROP_MEMBERSHIP for each group so joined.636*/637static void638test_ip_multicast_membership(int sock, const char *socktypename)639{640char addrbuf[16];641struct ip_mreq mreq;642uint32_t basegroup;643uint16_t i;644int sotype;645socklen_t sotypelen;646647sotypelen = sizeof(sotype);648if (getsockopt(sock, SOL_SOCKET, SO_TYPE, &sotype, &sotypelen) < 0)649err(-1, "test_ip_multicast_membership(%s): so_type getsockopt()",650socktypename);651/*652* Do not perform the test for SOCK_STREAM sockets, as this makes653* no sense.654*/655if (sotype == SOCK_STREAM)656return;657/*658* The 224/8 range is administratively scoped and has special meaning,659* therefore it is not used for this test.660* If we were not told to be non-deterministic:661* Join multicast groups from 238.1.1.0 up to nmcastgroups.662* Otherwise, pick a multicast group ID in subnet 238/5 with 11 random663* bits in the middle, and join groups in linear order up to nmcastgroups.664*/665if (dorandom) {666/* be non-deterministic (for interactive operation; a fuller test) */667srandomdev();668basegroup = 0xEE000000; /* 238.0.0.0 */669basegroup |= ((random() % ((1 << 11) - 1)) << 16); /* 11 bits */670} else {671/* be deterministic (for automated operation) */672basegroup = 0xEE010100; /* 238.1.1.0 */673}674/*675* Join the multicast group(s) on the default multicast interface;676* this usually maps to the interface to which the default677* route is pointing.678*/679for (i = 1; i < nmcastgroups+1; i++) {680mreq.imr_multiaddr.s_addr = htonl((basegroup + i));681mreq.imr_interface.s_addr = INADDR_ANY;682inet_ntop(AF_INET, &mreq.imr_multiaddr, addrbuf, sizeof(addrbuf));683if (verbose)684fprintf(stderr, "IP_ADD_MEMBERSHIP %s INADDR_ANY\n", addrbuf);685if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,686sizeof(mreq)) < 0) {687err(-1,688"test_ip_multicast_membership(%d, %s): failed IP_ADD_MEMBERSHIP (%s, %s)",689sock, socktypename, addrbuf, "INADDR_ANY");690}691}692for (i = 1; i < nmcastgroups+1; i++) {693mreq.imr_multiaddr.s_addr = htonl((basegroup + i));694mreq.imr_interface.s_addr = INADDR_ANY;695inet_ntop(AF_INET, &mreq.imr_multiaddr, addrbuf, sizeof(addrbuf));696if (verbose)697fprintf(stderr, "IP_DROP_MEMBERSHIP %s INADDR_ANY\n", addrbuf);698if (setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq,699sizeof(mreq)) < 0) {700err(-1,701"test_ip_multicast_membership(%d, %s): failed IP_DROP_MEMBERSHIP (%s, %s)",702sock, socktypename, addrbuf, "INADDR_ANY");703}704}705}706707/*708* XXX: For now, nothing here.709*/710static void711test_ip_multicast_if(int sock, const char *socktypename)712{713714/*715* It's probably worth trying INADDR_ANY and INADDR_LOOPBACK here716* to see what happens.717*/718}719720/*721* XXX: For now, nothing here.722*/723static void724test_ip_multicast_vif(int sock, const char *socktypename)725{726727/*728* This requires some knowledge of the number of virtual interfaces,729* and what is valid.730*/731}732733static void734testsuite(int priv)735{736const char *socktypenameset[] = {"SOCK_DGRAM", "SOCK_STREAM",737"SOCK_RAW"};738int socktypeset[] = {SOCK_DGRAM, SOCK_STREAM, SOCK_RAW};739const char *socktypename;740int i, sock, socktype;741742test_ip_hdrincl();743744for (i = 0; i < sizeof(socktypeset)/sizeof(int); i++) {745socktype = socktypeset[i];746socktypename = socktypenameset[i];747748/*749* If we can't acquire root privilege, we can't open raw750* sockets, so don't actually try.751*/752if (getuid() != 0 && socktype == SOCK_RAW)753continue;754if (geteuid() != 0 && !priv && socktype == SOCK_RAW)755continue;756757/*758* XXXRW: On 5.3, this seems not to work for SOCK_RAW.759*/760sock = get_socket(socktype, priv);761if (sock == -1)762err(-1, "get_socket(%s, %d) for test_ip_uchar(IP_TOS)",763socktypename, priv);764test_ip_uchar(sock, socktypename, IP_TOS, "IP_TOS", 0);765close(sock);766767sock = get_socket(socktype, priv);768if (sock == -1)769err(-1, "get_socket(%s %d) for test_ip_uchar(IP_TTL)",770socktypename, priv);771test_ip_uchar(sock, socktypename, IP_TTL, "IP_TTL", 64);772close(sock);773774sock = get_socket(socktype, priv);775if (sock == -1)776err(-1, "get_socket(%s, %d) for test_ip_boolean"777"(IP_RECVOPTS)", socktypename, priv);778test_ip_boolean(sock, socktypename, IP_RECVOPTS,779"IP_RECVOPTS", 0, BOOLEAN_ANYONE);780close(sock);781782sock = get_socket(socktype, priv);783if (sock == -1)784err(-1, "get_socket(%s, %d) for test_ip_boolean"785"(IP_RECVRETOPTS)", socktypename, priv);786test_ip_boolean(sock, socktypename, IP_RECVRETOPTS,787"IP_RECVRETOPTS", 0, BOOLEAN_ANYONE);788close(sock);789790sock = get_socket(socktype, priv);791if (sock == -1)792err(-1, "get_socket(%s, %d) for test_ip_boolean"793"(IP_RECVDSTADDR)", socktypename, priv);794test_ip_boolean(sock, socktypename, IP_RECVDSTADDR,795"IP_RECVDSTADDR", 0, BOOLEAN_ANYONE);796close(sock);797798sock = get_socket(socktype, priv);799if (sock == -1)800err(-1, "get_socket(%s, %d) for test_ip_boolean"801"(IP_RECVTTL)", socktypename, priv);802test_ip_boolean(sock, socktypename, IP_RECVTTL, "IP_RECVTTL",8030, BOOLEAN_ANYONE);804close(sock);805806sock = get_socket(socktype, priv);807if (sock == -1)808err(-1, "get_socket(%s, %d) for test_ip_boolean"809"(IP_RECVIF)", socktypename, priv);810test_ip_boolean(sock, socktypename, IP_RECVIF, "IP_RECVIF",8110, BOOLEAN_ANYONE);812close(sock);813814sock = get_socket(socktype, priv);815if (sock == -1)816err(-1, "get_socket(%s, %d) for test_ip_boolean"817"(IP_FAITH)", socktypename, priv);818test_ip_boolean(sock, socktypename, IP_FAITH, "IP_FAITH", 0,819BOOLEAN_ANYONE);820close(sock);821822sock = get_socket(socktype, priv);823if (sock == -1)824err(-1, "get_socket(%s, %d) for test_ip_boolean"825"(IP_ONESBCAST)", socktypename, priv);826test_ip_boolean(sock, socktypename, IP_ONESBCAST,827"IP_ONESBCAST", 0, BOOLEAN_ANYONE);828close(sock);829830/*831* Test the multicast TTL exactly as we would the regular832* TTL, only expect a different default.833*/834sock = get_socket(socktype, priv);835if (sock == -1)836err(-1, "get_socket(%s, %d) for IP_MULTICAST_TTL",837socktypename, priv);838test_ip_uchar(sock, socktypename, IP_MULTICAST_TTL,839"IP_MULTICAST_TTL", 1);840close(sock);841842/*843* The multicast loopback flag can be tested using our844* boolean tester, but only because the FreeBSD API is a bit845* more flexible than earlir APIs and will accept an int as846* well as a u_char. Loopback is enabled by default.847*/848sock = get_socket(socktype, priv);849if (sock == -1)850err(-1, "get_socket(%s, %d) for IP_MULTICAST_LOOP",851socktypename, priv);852test_ip_boolean(sock, socktypename, IP_MULTICAST_LOOP,853"IP_MULTICAST_LOOP", 1, BOOLEAN_ANYONE);854close(sock);855856sock = get_socket(socktype, priv);857if (sock == -1)858err(-1, "get_socket(%s, %d) for test_ip_options",859socktypename, priv);860//test_ip_options(sock, socktypename);861close(sock);862863sock = get_socket(socktype, priv);864if (sock == -1)865err(-1, "get_socket(%s, %d) for test_ip_options",866socktypename, priv);867test_ip_multicast_membership(sock, socktypename);868close(sock);869870test_ip_multicast_if(0, NULL);871test_ip_multicast_vif(0, NULL);872/*873* XXX: Still need to test:874* IP_PORTRANGE875* IP_IPSEC_POLICY?876*/877}878}879880static void881usage()882{883884fprintf(stderr, "usage: ipsockopt [-M ngroups] [-r] [-v]\n");885exit(EXIT_FAILURE);886}887888/*889* Very simply exercise that we can get and set each option. If we're running890* as root, run it also as nobody. If not as root, complain about that.891*/892int893main(int argc, char *argv[])894{895int ch;896897while ((ch = getopt(argc, argv, "M:rv")) != -1) {898switch (ch) {899case 'M':900nmcastgroups = atoi(optarg);901break;902case 'r':903dorandom = 1; /* introduce non-determinism */904break;905case 'v':906verbose = 1;907break;908default:909usage();910}911}912913printf("1..1\n");914915if (geteuid() != 0) {916warnx("Not running as root, can't run tests as root");917fprintf(stderr, "\n");918fprintf(stderr,919"Running tests with uid %d sock uid %d\n", geteuid(),920geteuid());921testsuite(PRIV_ASIS);922} else {923fprintf(stderr,924"Running tests with ruid %d euid %d sock uid 0\n",925getuid(), geteuid());926testsuite(PRIV_ASIS);927if (seteuid(65534) != 0)928err(-1, "seteuid(65534)");929fprintf(stderr,930"Running tests with ruid %d euid %d sock uid 65534\n",931getuid(), geteuid());932testsuite(PRIV_ASIS);933fprintf(stderr,934"Running tests with ruid %d euid %d sock uid 0\n",935getuid(), geteuid());936testsuite(PRIV_GETROOT);937}938printf("ok 1 - ipsockopt\n");939exit(0);940}941942943