Path: blob/main/tools/regression/netinet/msocket_ifnet_remove/msocket_ifnet_remove.c
39491 views
/*-1* Copyright (c) 2005 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/param.h>27#include <sys/ioctl.h>28#include <sys/linker.h>29#include <sys/socket.h>3031#include <net/if.h>3233#include <netinet/in.h>3435#include <arpa/inet.h>3637#include <err.h>38#include <errno.h>39#include <fcntl.h>40#include <stdio.h>41#include <string.h>42#include <unistd.h>4344/*45* Regression test to reproduce problems associated with the removal of a46* network interface being used by an active multicast socket. This proves47* to be somewhat complicated, as we need a multicast-capable synthetic48* network device that can be torn down on demand, in order that the test49* program can open a multicast socket, join a group on the interface, tear50* down the interface, and then close the multicast socket. We use the51* if_disc ("discard") synthetic interface for this purpose.52*53* Because potential solutions to this problem require separate handling for54* different IP socket types, we actually run the test twice: once for UDP55* sockets, and once for raw IP sockets.56*/5758/*59* XXX: The following hopefully don't conflict with the local configuration.60*/61#define MULTICAST_IP "224.100.100.100"62#define DISC_IP "192.0.2.100"63#define DISC_MASK "255.255.255.0"64#define DISC_IFNAME "disc"65#define DISC_IFUNIT 1006667static int68disc_setup(void)69{70struct ifreq ifr;71int s;7273if (kldload("if_disc") < 0) {74switch (errno) {75case EEXIST:76break;77default:78warn("disc_setup: kldload(if_disc)");79return (-1);80}81}8283s = socket(PF_INET, SOCK_RAW, 0);84if (s < 0) {85warn("disc_setup: socket(PF_INET, SOCK_RAW, 0)");86return (-1);87}8889bzero(&ifr, sizeof(ifr));90snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", DISC_IFNAME,91DISC_IFUNIT);9293if (ioctl(s, SIOCIFCREATE, &ifr) < 0) {94warn("disc_setup: ioctl(%s, SIOCIFCREATE)", ifr.ifr_name);95close(s);96return (-1);97}9899close(s);100return (0);101}102103static void104disc_done(void)105{106struct ifreq ifr;107int s;108109s = socket(PF_INET, SOCK_RAW, 0);110if (s < 0) {111warn("disc_done: socket(PF_INET, SOCK_RAW, 0)");112return;113}114115bzero(&ifr, sizeof(ifr));116snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", DISC_IFNAME,117DISC_IFUNIT);118119if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)120warn("disc_done: ioctl(%s, SIOCIFDESTROY)", ifr.ifr_name);121close(s);122}123124/*125* Configure an IP address and netmask on a network interface.126*/127static int128ifconfig_inet(char *ifname, int ifunit, char *ip, char *netmask)129{130struct sockaddr_in *sinp;131struct ifaliasreq ifra;132int s;133134s = socket(PF_INET, SOCK_RAW, 0);135if (s < 0) {136warn("ifconfig_inet: socket(PF_INET, SOCK_RAW, 0)");137return (-1);138}139140bzero(&ifra, sizeof(ifra));141snprintf(ifra.ifra_name, sizeof(ifra.ifra_name), "%s%d", ifname,142ifunit);143144sinp = (struct sockaddr_in *)&ifra.ifra_addr;145sinp->sin_family = AF_INET;146sinp->sin_len = sizeof(ifra.ifra_addr);147sinp->sin_addr.s_addr = inet_addr(ip);148149sinp = (struct sockaddr_in *)&ifra.ifra_mask;150sinp->sin_family = AF_INET;151sinp->sin_len = sizeof(ifra.ifra_addr);152sinp->sin_addr.s_addr = inet_addr(netmask);153154if (ioctl(s, SIOCAIFADDR, &ifra) < 0) {155warn("ifconfig_inet: ioctl(%s%d, SIOCAIFADDR, %s)", ifname,156ifunit, ip);157close(s);158return (-1);159}160161close(s);162return (0);163}164165static int166multicast_open(int *sockp, int type, const char *type_string)167{168struct ip_mreq imr;169int sock;170171sock = socket(PF_INET, type, 0);172if (sock < 0) {173warn("multicast_test: socket(PF_INET, %s, 0)", type_string);174return (-1);175}176177bzero(&imr, sizeof(imr));178imr.imr_multiaddr.s_addr = inet_addr(MULTICAST_IP);179imr.imr_interface.s_addr = inet_addr(DISC_IP);180181if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr,182sizeof(imr)) < 0) {183warn("multicast_test: setsockopt(IPPROTO_IP, "184"IP_ADD_MEMBERSHIP, {%s, %s})", MULTICAST_IP, DISC_IP);185close(sock);186return (-1);187}188189*sockp = sock;190return (0);191}192193static void194multicast_close(int udp_socket)195{196197close(udp_socket);198}199200static int201test_sock_type(int type, const char *type_string)202{203int sock;204205if (disc_setup() < 0)206return (-1);207208if (ifconfig_inet(DISC_IFNAME, DISC_IFUNIT, DISC_IP, DISC_MASK) < 0) {209disc_done();210return (-1);211}212213if (multicast_open(&sock, type, type_string) < 0) {214disc_done();215return (-1);216}217218/*219* Tear down the interface first, then close the multicast socket and220* see if we make it to the end of the function.221*/222disc_done();223multicast_close(sock);224225printf("test_sock_type(%s) passed\n", type_string);226227return (0);228}229230int231main(int argc, char *argv[])232{233234if (test_sock_type(SOCK_RAW, "SOCK_RAW") < 0)235return (-1);236237if (test_sock_type(SOCK_DGRAM, "SOCK_DGRAM") < 0)238return (-1);239240return (0);241}242243244