1149796Srwatson/*- 2149796Srwatson * Copyright (c) 2005 Robert N. M. Watson 3149796Srwatson * All rights reserved. 4149796Srwatson * 5149796Srwatson * Redistribution and use in source and binary forms, with or without 6149796Srwatson * modification, are permitted provided that the following conditions 7149796Srwatson * are met: 8149796Srwatson * 1. Redistributions of source code must retain the above copyright 9149796Srwatson * notice, this list of conditions and the following disclaimer. 10149796Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11149796Srwatson * notice, this list of conditions and the following disclaimer in the 12149796Srwatson * documentation and/or other materials provided with the distribution. 13149796Srwatson * 14149796Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15149796Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16149796Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17149796Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18149796Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19149796Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20149796Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21149796Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22149796Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23149796Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24149796Srwatson * SUCH DAMAGE. 25149796Srwatson * 26149796Srwatson * $FreeBSD$ 27149796Srwatson */ 28149796Srwatson 29149796Srwatson#include <sys/param.h> 30149796Srwatson#include <sys/ioctl.h> 31149796Srwatson#include <sys/linker.h> 32149796Srwatson#include <sys/socket.h> 33149796Srwatson 34149796Srwatson#include <net/if.h> 35149796Srwatson 36149796Srwatson#include <netinet/in.h> 37149796Srwatson 38149796Srwatson#include <arpa/inet.h> 39149796Srwatson 40149796Srwatson#include <err.h> 41149796Srwatson#include <errno.h> 42149796Srwatson#include <fcntl.h> 43149796Srwatson#include <stdio.h> 44149796Srwatson#include <string.h> 45149796Srwatson#include <unistd.h> 46149796Srwatson 47149796Srwatson/* 48149796Srwatson * Regression test to reproduce problems associated with the removal of a 49149796Srwatson * network interface being used by an active multicast socket. This proves 50149796Srwatson * to be somewhat complicated, as we need a multicast-capable synthetic 51149796Srwatson * network device that can be torn down on demand, in order that the test 52149796Srwatson * program can open a multicast socket, join a group on the interface, tear 53149796Srwatson * down the interface, and then close the multicast socket. We use the 54149796Srwatson * if_disc ("discard") synthetic interface for this purpose. 55149796Srwatson * 56149796Srwatson * Because potential solutions to this problem require separate handling for 57149796Srwatson * different IP socket types, we actually run the test twice: once for UDP 58149796Srwatson * sockets, and once for raw IP sockets. 59149796Srwatson */ 60149796Srwatson 61149796Srwatson/* 62149796Srwatson * XXX: The following hopefully don't conflict with the local configuration. 63149796Srwatson */ 64149796Srwatson#define MULTICAST_IP "224.100.100.100" 65149796Srwatson#define DISC_IP "192.0.2.100" 66149796Srwatson#define DISC_MASK "255.255.255.0" 67149796Srwatson#define DISC_IFNAME "disc" 68149796Srwatson#define DISC_IFUNIT 100 69149796Srwatson 70149796Srwatsonstatic int 71149796Srwatsondisc_setup(void) 72149796Srwatson{ 73149796Srwatson struct ifreq ifr; 74149796Srwatson int s; 75149796Srwatson 76149796Srwatson if (kldload("if_disc") < 0) { 77149796Srwatson switch (errno) { 78149796Srwatson case EEXIST: 79149796Srwatson break; 80149796Srwatson default: 81149796Srwatson warn("disc_setup: kldload(if_disc)"); 82149796Srwatson return (-1); 83149796Srwatson } 84149796Srwatson } 85149796Srwatson 86149796Srwatson s = socket(PF_INET, SOCK_RAW, 0); 87149796Srwatson if (s < 0) { 88149796Srwatson warn("disc_setup: socket(PF_INET, SOCK_RAW, 0)"); 89149796Srwatson return (-1); 90149796Srwatson } 91149796Srwatson 92149796Srwatson bzero(&ifr, sizeof(ifr)); 93149796Srwatson snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", DISC_IFNAME, 94149796Srwatson DISC_IFUNIT); 95149796Srwatson 96149796Srwatson if (ioctl(s, SIOCIFCREATE, &ifr) < 0) { 97149796Srwatson warn("disc_setup: ioctl(%s, SIOCIFCREATE)", ifr.ifr_name); 98149796Srwatson close(s); 99149796Srwatson return (-1); 100149796Srwatson } 101149796Srwatson 102149796Srwatson close(s); 103149796Srwatson return (0); 104149796Srwatson} 105149796Srwatson 106149796Srwatsonstatic void 107149796Srwatsondisc_done(void) 108149796Srwatson{ 109149796Srwatson struct ifreq ifr; 110149796Srwatson int s; 111149796Srwatson 112149796Srwatson s = socket(PF_INET, SOCK_RAW, 0); 113149796Srwatson if (s < 0) { 114149796Srwatson warn("disc_done: socket(PF_INET, SOCK_RAW, 0)"); 115149796Srwatson return; 116149796Srwatson } 117149796Srwatson 118149796Srwatson bzero(&ifr, sizeof(ifr)); 119149796Srwatson snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", DISC_IFNAME, 120149796Srwatson DISC_IFUNIT); 121149796Srwatson 122149796Srwatson if (ioctl(s, SIOCIFDESTROY, &ifr) < 0) 123149796Srwatson warn("disc_done: ioctl(%s, SIOCIFDESTROY)", ifr.ifr_name); 124149796Srwatson close(s); 125149796Srwatson} 126149796Srwatson 127149796Srwatson/* 128149796Srwatson * Configure an IP address and netmask on a network interface. 129149796Srwatson */ 130149796Srwatsonstatic int 131149796Srwatsonifconfig_inet(char *ifname, int ifunit, char *ip, char *netmask) 132149796Srwatson{ 133149796Srwatson struct sockaddr_in *sinp; 134149796Srwatson struct ifaliasreq ifra; 135149796Srwatson int s; 136149796Srwatson 137149796Srwatson s = socket(PF_INET, SOCK_RAW, 0); 138149796Srwatson if (s < 0) { 139149796Srwatson warn("ifconfig_inet: socket(PF_INET, SOCK_RAW, 0)"); 140149796Srwatson return (-1); 141149796Srwatson } 142149796Srwatson 143149796Srwatson bzero(&ifra, sizeof(ifra)); 144149796Srwatson snprintf(ifra.ifra_name, sizeof(ifra.ifra_name), "%s%d", ifname, 145149796Srwatson ifunit); 146149796Srwatson 147149796Srwatson sinp = (struct sockaddr_in *)&ifra.ifra_addr; 148149796Srwatson sinp->sin_family = AF_INET; 149149796Srwatson sinp->sin_len = sizeof(ifra.ifra_addr); 150149796Srwatson sinp->sin_addr.s_addr = inet_addr(ip); 151149796Srwatson 152149796Srwatson sinp = (struct sockaddr_in *)&ifra.ifra_mask; 153149796Srwatson sinp->sin_family = AF_INET; 154149796Srwatson sinp->sin_len = sizeof(ifra.ifra_addr); 155149796Srwatson sinp->sin_addr.s_addr = inet_addr(netmask); 156149796Srwatson 157149796Srwatson if (ioctl(s, SIOCAIFADDR, &ifra) < 0) { 158149796Srwatson warn("ifconfig_inet: ioctl(%s%d, SIOCAIFADDR, %s)", ifname, 159149796Srwatson ifunit, ip); 160149796Srwatson close(s); 161149796Srwatson return (-1); 162149796Srwatson } 163149796Srwatson 164149796Srwatson close(s); 165149796Srwatson return (0); 166149796Srwatson} 167149796Srwatson 168149796Srwatsonstatic int 169149796Srwatsonmulticast_open(int *sockp, int type, const char *type_string) 170149796Srwatson{ 171149796Srwatson struct ip_mreq imr; 172149796Srwatson int sock; 173149796Srwatson 174149796Srwatson sock = socket(PF_INET, type, 0); 175149796Srwatson if (sock < 0) { 176149796Srwatson warn("multicast_test: socket(PF_INET, %s, 0)", type_string); 177149796Srwatson return (-1); 178149796Srwatson } 179149796Srwatson 180149796Srwatson bzero(&imr, sizeof(imr)); 181149796Srwatson imr.imr_multiaddr.s_addr = inet_addr(MULTICAST_IP); 182149796Srwatson imr.imr_interface.s_addr = inet_addr(DISC_IP); 183149796Srwatson 184149796Srwatson if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, 185149796Srwatson sizeof(imr)) < 0) { 186149796Srwatson warn("multicast_test: setsockopt(IPPROTO_IP, " 187149796Srwatson "IP_ADD_MEMBERSHIP, {%s, %s})", MULTICAST_IP, DISC_IP); 188149796Srwatson close(sock); 189149796Srwatson return (-1); 190149796Srwatson } 191149796Srwatson 192149796Srwatson *sockp = sock; 193149796Srwatson return (0); 194149796Srwatson} 195149796Srwatson 196149796Srwatsonstatic void 197149796Srwatsonmulticast_close(int udp_socket) 198149796Srwatson{ 199149796Srwatson 200149796Srwatson close(udp_socket); 201149796Srwatson} 202149796Srwatson 203149796Srwatsonstatic int 204149796Srwatsontest_sock_type(int type, const char *type_string) 205149796Srwatson{ 206149796Srwatson int sock; 207149796Srwatson 208149796Srwatson if (disc_setup() < 0) 209149796Srwatson return (-1); 210149796Srwatson 211149796Srwatson if (ifconfig_inet(DISC_IFNAME, DISC_IFUNIT, DISC_IP, DISC_MASK) < 0) { 212149796Srwatson disc_done(); 213149796Srwatson return (-1); 214149796Srwatson } 215149796Srwatson 216149796Srwatson if (multicast_open(&sock, type, type_string) < 0) { 217149796Srwatson disc_done(); 218149796Srwatson return (-1); 219149796Srwatson } 220149796Srwatson 221149796Srwatson /* 222149796Srwatson * Tear down the interface first, then close the multicast socket and 223149796Srwatson * see if we make it to the end of the function. 224149796Srwatson */ 225149796Srwatson disc_done(); 226149796Srwatson multicast_close(sock); 227149796Srwatson 228149796Srwatson printf("test_sock_type(%s) passed\n", type_string); 229149796Srwatson 230149796Srwatson return (0); 231149796Srwatson} 232149796Srwatson 233149796Srwatsonint 234149796Srwatsonmain(int argc, char *argv[]) 235149796Srwatson{ 236149796Srwatson 237149796Srwatson if (test_sock_type(SOCK_RAW, "SOCK_RAW") < 0) 238149796Srwatson return (-1); 239149796Srwatson 240149796Srwatson if (test_sock_type(SOCK_DGRAM, "SOCK_DGRAM") < 0) 241149796Srwatson return (-1); 242149796Srwatson 243149796Srwatson return (0); 244149796Srwatson} 245