Path: blob/main/tools/regression/ethernet/ethermulti/ethermulti.c
48253 views
/*-1* Copyright (c) 2007 Bruce M. Simpson2* 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>28#include <sys/time.h>29#include <sys/ioctl.h>3031#include <net/if.h>32#include <net/if_dl.h>33#include <net/if_types.h>34#include <net/ethernet.h>3536#include <err.h>37#include <errno.h>38#include <getopt.h>39#include <stdio.h>40#include <stdlib.h>41#include <string.h>42#include <unistd.h>4344#include <ifaddrs.h>4546static int dorandom = 0;47static int verbose = 0;48static char *ifname = NULL;4950/*51* The test tool exercises IP-level socket options by interrogating the52* getsockopt()/setsockopt() APIs. It does not currently test that the53* intended semantics of each option are implemented (i.e., that setting IP54* options on the socket results in packets with the desired IP options in55* it).56*/5758/*59* get_socket() is a wrapper function that returns a socket of the specified60* type, and created with or without restored root privilege (if running61* with a real uid of root and an effective uid of some other user). This62* us to test whether the same rights are granted using a socket with a63* privileged cached credential vs. a socket with a regular credential.64*/65#define PRIV_ASIS 066#define PRIV_GETROOT 167static int68get_socket_unpriv(int type)69{7071return (socket(PF_INET, type, 0));72}7374static int75get_socket_priv(int type)76{77uid_t olduid;78int sock;7980if (getuid() != 0)81errx(-1, "get_sock_priv: running without real uid 0");8283olduid = geteuid();84if (seteuid(0) < 0)85err(-1, "get_sock_priv: seteuid(0)");8687sock = socket(PF_INET, type, 0);8889if (seteuid(olduid) < 0)90err(-1, "get_sock_priv: seteuid(%d)", olduid);9192return (sock);93}9495static int96get_socket(int type, int priv)97{9899if (priv)100return (get_socket_priv(type));101else102return (get_socket_unpriv(type));103}104105union sockunion {106struct sockaddr_storage ss;107struct sockaddr sa;108struct sockaddr_dl sdl;109};110typedef union sockunion sockunion_t;111112static void113test_ether_multi(int sock)114{115struct ifreq ifr;116struct sockaddr_dl *dlp;117struct ether_addr ea;118struct ifmaddrs *ifma, *ifmap;119int found;120121/* Choose an 802 multicast address. */122if (dorandom) {123uint32_t mac4;124125srandomdev();126mac4 = random();127ea.octet[0] = 0x01;128ea.octet[1] = 0x80;129ea.octet[2] = ((mac4 >> 24 & 0xFF));130ea.octet[3] = ((mac4 >> 16 & 0xFF));131ea.octet[4] = ((mac4 >> 8 & 0xFF));132ea.octet[5] = (mac4 & 0xFF);133} else {134struct ether_addr *nep = ether_aton("01:80:DE:FA:CA:7E");135ea = *nep;136}137138/* Fill out ifreq, and fill out 802 group address. */139memset(&ifr, 0, sizeof(struct ifreq));140strlcpy(&ifr.ifr_name[0], ifname, IFNAMSIZ);141dlp = (struct sockaddr_dl *)&ifr.ifr_addr;142memset(dlp, 0, sizeof(struct sockaddr_dl));143dlp->sdl_len = sizeof(struct sockaddr_dl);144dlp->sdl_family = AF_LINK;145dlp->sdl_alen = sizeof(struct ether_addr);146memcpy(LLADDR(dlp), &ea, sizeof(struct ether_addr));147148/* Join an 802 group. */149if (ioctl(sock, SIOCADDMULTI, &ifr) < 0) {150warn("can't add ethernet multicast membership");151return;152}153154/* Check that we joined the group by calling getifmaddrs(). */155found = 0;156if (getifmaddrs(&ifmap) != 0) {157warn("getifmaddrs()");158} else {159for (ifma = ifmap; ifma; ifma = ifma->ifma_next) {160sockunion_t *psa = (sockunion_t *)ifma->ifma_addr;161if (ifma->ifma_name == NULL || psa == NULL)162continue;163164if (psa->sa.sa_family != AF_LINK ||165psa->sdl.sdl_alen != ETHER_ADDR_LEN)166continue;167168if (bcmp(LLADDR(&psa->sdl), LLADDR(dlp),169ETHER_ADDR_LEN) == 0) {170found = 1;171break;172}173}174freeifmaddrs(ifmap);175}176if (!found) {177warnx("group membership for %s not returned by getifmaddrs()",178ether_ntoa(&ea));179}180181/* Fill out ifreq, and fill out 802 group address. */182memset(&ifr, 0, sizeof(struct ifreq));183strlcpy(&ifr.ifr_name[0], ifname, IFNAMSIZ);184dlp = (struct sockaddr_dl *)&ifr.ifr_addr;185memset(dlp, 0, sizeof(struct sockaddr_dl));186dlp->sdl_len = sizeof(struct sockaddr_dl);187dlp->sdl_family = AF_LINK;188dlp->sdl_alen = sizeof(struct ether_addr);189memcpy(LLADDR(dlp), &ea, sizeof(struct ether_addr));190191/* Leave an 802 group. */192if (ioctl(sock, SIOCDELMULTI, &ifr) < 0)193warn("can't delete ethernet multicast membership");194195}196197static void198testsuite(int priv)199{200int sock;201202sock = get_socket(SOCK_DGRAM, 0);203if (sock == -1)204err(-1, "get_socket(SOCK_DGRAM) for test_ether_multi()", priv);205test_ether_multi(sock);206close(sock);207}208209static void210usage()211{212213fprintf(stderr, "usage: ethermulti -i ifname [-r] [-v]\n");214exit(EXIT_FAILURE);215}216217int218main(int argc, char *argv[])219{220int ch;221222while ((ch = getopt(argc, argv, "i:rv")) != -1) {223switch (ch) {224case 'i':225ifname = optarg;226break;227case 'r':228dorandom = 1; /* introduce non-determinism */229break;230case 'v':231verbose = 1;232break;233default:234usage();235}236}237if (ifname == NULL)238usage();239240printf("1..1\n");241if (geteuid() != 0) {242errx(1, "Not running as root, can't run tests as non-root");243/*NOTREACHED*/244} else {245fprintf(stderr,246"Running tests with ruid %d euid %d sock uid 0\n",247getuid(), geteuid());248testsuite(PRIV_ASIS);249}250printf("ok 1 - ethermulti\n");251exit(0);252}253254255