1b13321fcSBruce M Simpson /*- 2b13321fcSBruce M Simpson * Copyright (c) 2007 Bruce M. Simpson 3b13321fcSBruce M Simpson * All rights reserved. 4b13321fcSBruce M Simpson * 5b13321fcSBruce M Simpson * Redistribution and use in source and binary forms, with or without 6b13321fcSBruce M Simpson * modification, are permitted provided that the following conditions 7b13321fcSBruce M Simpson * are met: 8b13321fcSBruce M Simpson * 1. Redistributions of source code must retain the above copyright 9b13321fcSBruce M Simpson * notice, this list of conditions and the following disclaimer. 10b13321fcSBruce M Simpson * 2. Redistributions in binary form must reproduce the above copyright 11b13321fcSBruce M Simpson * notice, this list of conditions and the following disclaimer in the 12b13321fcSBruce M Simpson * documentation and/or other materials provided with the distribution. 13b13321fcSBruce M Simpson * 14b13321fcSBruce M Simpson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15b13321fcSBruce M Simpson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16b13321fcSBruce M Simpson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17b13321fcSBruce M Simpson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18b13321fcSBruce M Simpson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19b13321fcSBruce M Simpson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20b13321fcSBruce M Simpson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21b13321fcSBruce M Simpson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22b13321fcSBruce M Simpson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23b13321fcSBruce M Simpson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24b13321fcSBruce M Simpson * SUCH DAMAGE. 25b13321fcSBruce M Simpson */ 26b13321fcSBruce M Simpson 27b13321fcSBruce M Simpson /* 28b13321fcSBruce M Simpson * Regression test utility for RFC 3678 Advanced Multicast API in FreeBSD. 29b13321fcSBruce M Simpson * 30b13321fcSBruce M Simpson * TODO: Test the SSM paths. 31b13321fcSBruce M Simpson * TODO: Support INET6. The code has been written to facilitate this later. 32b13321fcSBruce M Simpson * TODO: Merge multicast socket option tests from ipsockopt. 33b13321fcSBruce M Simpson */ 34b13321fcSBruce M Simpson 35b13321fcSBruce M Simpson #include <sys/cdefs.h> 36b13321fcSBruce M Simpson __FBSDID("$FreeBSD$"); 37b13321fcSBruce M Simpson 38b13321fcSBruce M Simpson #include <sys/param.h> 39b13321fcSBruce M Simpson #include <sys/types.h> 40b13321fcSBruce M Simpson #include <sys/ioctl.h> 41b13321fcSBruce M Simpson #include <sys/socket.h> 42b13321fcSBruce M Simpson 43b13321fcSBruce M Simpson #include <net/if.h> 44b13321fcSBruce M Simpson #include <net/if_dl.h> 45b13321fcSBruce M Simpson #include <netinet/in.h> 46b13321fcSBruce M Simpson #include <arpa/inet.h> 47b13321fcSBruce M Simpson #include <netdb.h> 48b13321fcSBruce M Simpson 49b13321fcSBruce M Simpson #include <assert.h> 50b13321fcSBruce M Simpson #include <err.h> 51b13321fcSBruce M Simpson #include <errno.h> 52b13321fcSBruce M Simpson #include <getopt.h> 53b13321fcSBruce M Simpson #include <libgen.h> 54b13321fcSBruce M Simpson #include <pwd.h> 55b13321fcSBruce M Simpson #include <setjmp.h> 56b13321fcSBruce M Simpson #include <signal.h> 57b13321fcSBruce M Simpson #include <stddef.h> 58b13321fcSBruce M Simpson #include <stdio.h> 59b13321fcSBruce M Simpson #include <stdlib.h> 60b13321fcSBruce M Simpson #include <string.h> 61b13321fcSBruce M Simpson #include <sysexits.h> 62b13321fcSBruce M Simpson #include <time.h> 63b13321fcSBruce M Simpson #include <unistd.h> 64b13321fcSBruce M Simpson 65b13321fcSBruce M Simpson #ifndef __SOCKUNION_DECLARED 66b13321fcSBruce M Simpson union sockunion { 67b13321fcSBruce M Simpson struct sockaddr_storage ss; 68b13321fcSBruce M Simpson struct sockaddr sa; 69b13321fcSBruce M Simpson struct sockaddr_dl sdl; 70b13321fcSBruce M Simpson struct sockaddr_in sin; 71b13321fcSBruce M Simpson #ifdef INET6 72b13321fcSBruce M Simpson struct sockaddr_in6 sin6; 73b13321fcSBruce M Simpson #endif 74b13321fcSBruce M Simpson }; 75b13321fcSBruce M Simpson typedef union sockunion sockunion_t; 76b13321fcSBruce M Simpson #define __SOCKUNION_DECLARED 77b13321fcSBruce M Simpson #endif /* __SOCKUNION_DECLARED */ 78b13321fcSBruce M Simpson 79b13321fcSBruce M Simpson #define ADDRBUF_LEN 16 80b13321fcSBruce M Simpson #define DEFAULT_GROUP_STR "238.1.1.0" 81b13321fcSBruce M Simpson #define DEFAULT_IFNAME "lo0" 82b13321fcSBruce M Simpson #define DEFAULT_IFADDR_STR "127.0.0.1" 83b13321fcSBruce M Simpson #define DEFAULT_PORT 6698 84b13321fcSBruce M Simpson #define DEFAULT_TIMEOUT 0 /* don't wait for traffic */ 85b13321fcSBruce M Simpson #define RXBUFSIZE 2048 86b13321fcSBruce M Simpson 87b13321fcSBruce M Simpson static sockunion_t basegroup; 88b13321fcSBruce M Simpson static const char *basegroup_str = NULL; 89b13321fcSBruce M Simpson static int dobindaddr = 0; 90b13321fcSBruce M Simpson static int dodebug = 1; 91b13321fcSBruce M Simpson static int doipv4 = 0; 92b13321fcSBruce M Simpson static int domiscopts = 0; 93b13321fcSBruce M Simpson static int dorandom = 0; 94b13321fcSBruce M Simpson static int doreuseport = 0; 95b13321fcSBruce M Simpson static int dossm = 0; 96b13321fcSBruce M Simpson static int dossf = 0; 97b13321fcSBruce M Simpson static int doverbose = 0; 98b13321fcSBruce M Simpson static sockunion_t ifaddr; 99b13321fcSBruce M Simpson static const char *ifaddr_str = NULL; 100b13321fcSBruce M Simpson static uint32_t ifindex = 0; 101b13321fcSBruce M Simpson static const char *ifname = NULL; 102b13321fcSBruce M Simpson struct in_addr *ipv4_sources = NULL; 103b13321fcSBruce M Simpson static jmp_buf jmpbuf; 104b13321fcSBruce M Simpson static size_t nmcastgroups = IP_MAX_MEMBERSHIPS; 105b13321fcSBruce M Simpson static size_t nmcastsources = 0; 106b13321fcSBruce M Simpson static uint16_t portno = DEFAULT_PORT; 107b13321fcSBruce M Simpson static char *progname = NULL; 108b13321fcSBruce M Simpson struct sockaddr_storage *ss_sources = NULL; 109b13321fcSBruce M Simpson static uint32_t timeout = 0; 110b13321fcSBruce M Simpson 111b13321fcSBruce M Simpson static int do_asm_ipv4(void); 112b13321fcSBruce M Simpson static int do_asm_pim(void); 113b13321fcSBruce M Simpson #ifdef notyet 114b13321fcSBruce M Simpson static int do_misc_opts(void); 115b13321fcSBruce M Simpson #endif 116b13321fcSBruce M Simpson static int do_ssf_ipv4(void); 117b13321fcSBruce M Simpson static int do_ssf_pim(void); 118b13321fcSBruce M Simpson static int do_ssm_ipv4(void); 119b13321fcSBruce M Simpson static int do_ssm_pim(void); 120b13321fcSBruce M Simpson static int open_and_bind_socket(sockunion_t *); 121b13321fcSBruce M Simpson static int recv_loop_with_match(int, sockunion_t *, sockunion_t *); 122b13321fcSBruce M Simpson static void signal_handler(int); 123b13321fcSBruce M Simpson static void usage(void); 124b13321fcSBruce M Simpson 125b13321fcSBruce M Simpson /* 126b13321fcSBruce M Simpson * Test the IPv4 set/getipv4sourcefilter() libc API functions. 127b13321fcSBruce M Simpson * Build a single socket. 128b13321fcSBruce M Simpson * Join a source group. 129b13321fcSBruce M Simpson * Repeatedly change the source filters via setipv4sourcefilter. 130b13321fcSBruce M Simpson * Read it back with getipv4sourcefilter up to IP_MAX_SOURCES 131b13321fcSBruce M Simpson * and check for inconsistency. 132b13321fcSBruce M Simpson */ 133b13321fcSBruce M Simpson static int 134b13321fcSBruce M Simpson do_ssf_ipv4(void) 135b13321fcSBruce M Simpson { 136b13321fcSBruce M Simpson 137b13321fcSBruce M Simpson fprintf(stderr, "not yet implemented\n"); 138b13321fcSBruce M Simpson return (0); 139b13321fcSBruce M Simpson } 140b13321fcSBruce M Simpson 141b13321fcSBruce M Simpson /* 142b13321fcSBruce M Simpson * Test the protocol-independent set/getsourcefilter() functions. 143b13321fcSBruce M Simpson */ 144b13321fcSBruce M Simpson static int 145b13321fcSBruce M Simpson do_ssf_pim(void) 146b13321fcSBruce M Simpson { 147b13321fcSBruce M Simpson 148b13321fcSBruce M Simpson fprintf(stderr, "not yet implemented\n"); 149b13321fcSBruce M Simpson return (0); 150b13321fcSBruce M Simpson } 151b13321fcSBruce M Simpson 152b13321fcSBruce M Simpson /* 153b13321fcSBruce M Simpson * Test the IPv4 ASM API. 154b13321fcSBruce M Simpson * Repeatedly join, block sources, unblock and leave groups. 155b13321fcSBruce M Simpson */ 156b13321fcSBruce M Simpson static int 157b13321fcSBruce M Simpson do_asm_ipv4(void) 158b13321fcSBruce M Simpson { 159b13321fcSBruce M Simpson int error; 160b13321fcSBruce M Simpson char gaddrbuf[ADDRBUF_LEN]; 161b13321fcSBruce M Simpson int i; 162b13321fcSBruce M Simpson sockunion_t laddr; 163b13321fcSBruce M Simpson struct ip_mreq mreq; 164b13321fcSBruce M Simpson struct ip_mreq_source mreqs; 165b13321fcSBruce M Simpson in_addr_t ngroupbase; 166b13321fcSBruce M Simpson char saddrbuf[ADDRBUF_LEN]; 167b13321fcSBruce M Simpson int sock; 168b13321fcSBruce M Simpson sockunion_t tmpgroup; 169b13321fcSBruce M Simpson sockunion_t tmpsource; 170b13321fcSBruce M Simpson 171b13321fcSBruce M Simpson memset(&mreq, 0, sizeof(struct ip_mreq)); 172b13321fcSBruce M Simpson memset(&mreqs, 0, sizeof(struct ip_mreq_source)); 173b13321fcSBruce M Simpson memset(&laddr, 0, sizeof(sockunion_t)); 174b13321fcSBruce M Simpson 175b13321fcSBruce M Simpson if (dobindaddr) { 176b13321fcSBruce M Simpson laddr = ifaddr; 177b13321fcSBruce M Simpson } else { 178b13321fcSBruce M Simpson laddr.sin.sin_family = AF_INET; 179b13321fcSBruce M Simpson laddr.sin.sin_len = sizeof(struct sockaddr_in); 180b13321fcSBruce M Simpson laddr.sin.sin_addr.s_addr = INADDR_ANY; 181b13321fcSBruce M Simpson } 182b13321fcSBruce M Simpson laddr.sin.sin_port = htons(portno); 183b13321fcSBruce M Simpson 184b13321fcSBruce M Simpson tmpgroup = basegroup; 185b13321fcSBruce M Simpson ngroupbase = ntohl(basegroup.sin.sin_addr.s_addr) + 1; /* XXX */ 186b13321fcSBruce M Simpson tmpgroup.sin.sin_addr.s_addr = htonl(ngroupbase); 187b13321fcSBruce M Simpson 188b13321fcSBruce M Simpson sock = open_and_bind_socket(&laddr); 189b13321fcSBruce M Simpson if (sock == -1) 190b13321fcSBruce M Simpson return (EX_OSERR); 191b13321fcSBruce M Simpson 192b13321fcSBruce M Simpson for (i = 0; i < (signed)nmcastgroups; i++) { 193b13321fcSBruce M Simpson mreq.imr_multiaddr.s_addr = htonl((ngroupbase + i)); 194b13321fcSBruce M Simpson mreq.imr_interface = ifaddr.sin.sin_addr; 195b13321fcSBruce M Simpson if (doverbose) { 196b13321fcSBruce M Simpson inet_ntop(AF_INET, &mreq.imr_multiaddr, gaddrbuf, 197b13321fcSBruce M Simpson sizeof(gaddrbuf)); 198b13321fcSBruce M Simpson fprintf(stderr, "IP_ADD_MEMBERSHIP %s %s\n", 199b13321fcSBruce M Simpson gaddrbuf, inet_ntoa(mreq.imr_interface)); 200b13321fcSBruce M Simpson } 201b13321fcSBruce M Simpson error = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 202b13321fcSBruce M Simpson &mreq, sizeof(struct ip_mreq)); 203b13321fcSBruce M Simpson if (error < 0) { 204b13321fcSBruce M Simpson warn("setsockopt IP_ADD_MEMBERSHIP"); 205b13321fcSBruce M Simpson close(sock); 206b13321fcSBruce M Simpson return (EX_OSERR); 207b13321fcSBruce M Simpson } 208b13321fcSBruce M Simpson } 209b13321fcSBruce M Simpson 210b13321fcSBruce M Simpson /* 211b13321fcSBruce M Simpson * If no test sources auto-generated or specified on command line, 212b13321fcSBruce M Simpson * skip source filter portion of ASM test. 213b13321fcSBruce M Simpson */ 214b13321fcSBruce M Simpson if (nmcastsources == 0) 215b13321fcSBruce M Simpson goto skipsources; 216b13321fcSBruce M Simpson 217b13321fcSBruce M Simpson /* 218b13321fcSBruce M Simpson * Begin blocking sources on the first group chosen. 219b13321fcSBruce M Simpson */ 220b13321fcSBruce M Simpson for (i = 0; i < (signed)nmcastsources; i++) { 221b13321fcSBruce M Simpson mreqs.imr_multiaddr = tmpgroup.sin.sin_addr; 222b13321fcSBruce M Simpson mreqs.imr_interface = ifaddr.sin.sin_addr; 223b13321fcSBruce M Simpson mreqs.imr_sourceaddr = ipv4_sources[i]; 224b13321fcSBruce M Simpson if (doverbose) { 225b13321fcSBruce M Simpson inet_ntop(AF_INET, &mreqs.imr_multiaddr, gaddrbuf, 226b13321fcSBruce M Simpson sizeof(gaddrbuf)); 227b13321fcSBruce M Simpson inet_ntop(AF_INET, &mreqs.imr_sourceaddr, saddrbuf, 228b13321fcSBruce M Simpson sizeof(saddrbuf)); 229b13321fcSBruce M Simpson fprintf(stderr, "IP_BLOCK_SOURCE %s %s %s\n", 230b13321fcSBruce M Simpson gaddrbuf, inet_ntoa(mreqs.imr_interface), 231b13321fcSBruce M Simpson saddrbuf); 232b13321fcSBruce M Simpson } 233b13321fcSBruce M Simpson error = setsockopt(sock, IPPROTO_IP, IP_BLOCK_SOURCE, &mreqs, 234b13321fcSBruce M Simpson sizeof(struct ip_mreq_source)); 235b13321fcSBruce M Simpson if (error < 0) { 236b13321fcSBruce M Simpson warn("setsockopt IP_BLOCK_SOURCE"); 237b13321fcSBruce M Simpson close(sock); 238b13321fcSBruce M Simpson return (EX_OSERR); 239b13321fcSBruce M Simpson } 240b13321fcSBruce M Simpson } 241b13321fcSBruce M Simpson 242b13321fcSBruce M Simpson /* 243b13321fcSBruce M Simpson * Choose the first group and source for a match. 244b13321fcSBruce M Simpson * Enter the I/O loop. 245b13321fcSBruce M Simpson */ 246b13321fcSBruce M Simpson memset(&tmpsource, 0, sizeof(sockunion_t)); 247b13321fcSBruce M Simpson tmpsource.sin.sin_family = AF_INET; 248b13321fcSBruce M Simpson tmpsource.sin.sin_len = sizeof(struct sockaddr_in); 249b13321fcSBruce M Simpson tmpsource.sin.sin_addr = ipv4_sources[0]; 250b13321fcSBruce M Simpson 251b13321fcSBruce M Simpson error = recv_loop_with_match(sock, &tmpgroup, &tmpsource); 252b13321fcSBruce M Simpson 253b13321fcSBruce M Simpson /* 254b13321fcSBruce M Simpson * Unblock sources. 255b13321fcSBruce M Simpson */ 256b13321fcSBruce M Simpson for (i = nmcastsources-1; i >= 0; i--) { 257b13321fcSBruce M Simpson mreqs.imr_multiaddr = tmpgroup.sin.sin_addr; 258b13321fcSBruce M Simpson mreqs.imr_interface = ifaddr.sin.sin_addr; 259b13321fcSBruce M Simpson mreqs.imr_sourceaddr = ipv4_sources[i]; 260b13321fcSBruce M Simpson if (doverbose) { 261b13321fcSBruce M Simpson inet_ntop(AF_INET, &mreqs.imr_multiaddr, gaddrbuf, 262b13321fcSBruce M Simpson sizeof(gaddrbuf)); 263b13321fcSBruce M Simpson inet_ntop(AF_INET, &mreqs.imr_sourceaddr, saddrbuf, 264b13321fcSBruce M Simpson sizeof(saddrbuf)); 265b13321fcSBruce M Simpson fprintf(stderr, "IP_UNBLOCK_SOURCE %s %s %s\n", 266b13321fcSBruce M Simpson gaddrbuf, inet_ntoa(mreqs.imr_interface), 267b13321fcSBruce M Simpson saddrbuf); 268b13321fcSBruce M Simpson } 269b13321fcSBruce M Simpson error = setsockopt(sock, IPPROTO_IP, IP_UNBLOCK_SOURCE, &mreqs, 270b13321fcSBruce M Simpson sizeof(struct ip_mreq_source)); 271b13321fcSBruce M Simpson if (error < 0) { 272b13321fcSBruce M Simpson warn("setsockopt IP_UNBLOCK_SOURCE"); 273b13321fcSBruce M Simpson close(sock); 274b13321fcSBruce M Simpson return (EX_OSERR); 275b13321fcSBruce M Simpson } 276b13321fcSBruce M Simpson } 277b13321fcSBruce M Simpson 278b13321fcSBruce M Simpson skipsources: 279b13321fcSBruce M Simpson /* 280b13321fcSBruce M Simpson * Leave groups. 281b13321fcSBruce M Simpson */ 282b13321fcSBruce M Simpson for (i = nmcastgroups-1; i >= 0; i--) { 283b13321fcSBruce M Simpson mreq.imr_multiaddr.s_addr = htonl((ngroupbase + i)); 284b13321fcSBruce M Simpson mreq.imr_interface = ifaddr.sin.sin_addr; 285b13321fcSBruce M Simpson if (doverbose) { 286b13321fcSBruce M Simpson inet_ntop(AF_INET, &mreq.imr_multiaddr, gaddrbuf, 287b13321fcSBruce M Simpson sizeof(gaddrbuf)); 288b13321fcSBruce M Simpson fprintf(stderr, "IP_DROP_MEMBERSHIP %s %s\n", 289b13321fcSBruce M Simpson gaddrbuf, inet_ntoa(mreq.imr_interface)); 290b13321fcSBruce M Simpson } 291b13321fcSBruce M Simpson error = setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, 292b13321fcSBruce M Simpson &mreq, sizeof(struct ip_mreq)); 293b13321fcSBruce M Simpson if (error < 0) { 294b13321fcSBruce M Simpson warn("setsockopt IP_DROP_MEMBERSHIP"); 295b13321fcSBruce M Simpson close(sock); 296b13321fcSBruce M Simpson return (EX_OSERR); 297b13321fcSBruce M Simpson } 298b13321fcSBruce M Simpson } 299b13321fcSBruce M Simpson 300b13321fcSBruce M Simpson return (0); 301b13321fcSBruce M Simpson } 302b13321fcSBruce M Simpson 303b13321fcSBruce M Simpson static int 304b13321fcSBruce M Simpson do_asm_pim(void) 305b13321fcSBruce M Simpson { 306b13321fcSBruce M Simpson 307b13321fcSBruce M Simpson fprintf(stderr, "not yet implemented\n"); 308b13321fcSBruce M Simpson return (0); 309b13321fcSBruce M Simpson } 310b13321fcSBruce M Simpson 311b13321fcSBruce M Simpson #ifdef notyet 312b13321fcSBruce M Simpson /* 313b13321fcSBruce M Simpson * Test misceallaneous IPv4 options. 314b13321fcSBruce M Simpson */ 315b13321fcSBruce M Simpson static int 316b13321fcSBruce M Simpson do_misc_opts(void) 317b13321fcSBruce M Simpson { 318b13321fcSBruce M Simpson int sock; 319b13321fcSBruce M Simpson 320b13321fcSBruce M Simpson sock = open_and_bind_socket(NULL); 321b13321fcSBruce M Simpson if (sock == -1) 322b13321fcSBruce M Simpson return (EX_OSERR); 323b13321fcSBruce M Simpson test_ip_uchar(sock, socktypename, IP_MULTICAST_TTL, 324b13321fcSBruce M Simpson "IP_MULTICAST_TTL", 1); 325b13321fcSBruce M Simpson close(sock); 326b13321fcSBruce M Simpson 327b13321fcSBruce M Simpson sock = open_and_bind_socket(NULL); 328b13321fcSBruce M Simpson if (sock == -1) 329b13321fcSBruce M Simpson return (EX_OSERR); 330b13321fcSBruce M Simpson test_ip_boolean(sock, socktypename, IP_MULTICAST_LOOP, 331b13321fcSBruce M Simpson "IP_MULTICAST_LOOP", 1, BOOLEAN_ANYONE); 332b13321fcSBruce M Simpson close(sock); 333b13321fcSBruce M Simpson 334b13321fcSBruce M Simpson return (0); 335b13321fcSBruce M Simpson } 336b13321fcSBruce M Simpson #endif 337b13321fcSBruce M Simpson 338b13321fcSBruce M Simpson /* 339b13321fcSBruce M Simpson * Test the IPv4 SSM API. 340b13321fcSBruce M Simpson */ 341b13321fcSBruce M Simpson static int 342b13321fcSBruce M Simpson do_ssm_ipv4(void) 343b13321fcSBruce M Simpson { 344b13321fcSBruce M Simpson 345b13321fcSBruce M Simpson fprintf(stderr, "not yet implemented\n"); 346b13321fcSBruce M Simpson return (0); 347b13321fcSBruce M Simpson } 348b13321fcSBruce M Simpson 349b13321fcSBruce M Simpson /* 350b13321fcSBruce M Simpson * Test the protocol-independent SSM API with IPv4 addresses. 351b13321fcSBruce M Simpson */ 352b13321fcSBruce M Simpson static int 353b13321fcSBruce M Simpson do_ssm_pim(void) 354b13321fcSBruce M Simpson { 355b13321fcSBruce M Simpson 356b13321fcSBruce M Simpson fprintf(stderr, "not yet implemented\n"); 357b13321fcSBruce M Simpson return (0); 358b13321fcSBruce M Simpson } 359b13321fcSBruce M Simpson 360b13321fcSBruce M Simpson int 361b13321fcSBruce M Simpson main(int argc, char *argv[]) 362b13321fcSBruce M Simpson { 363b13321fcSBruce M Simpson struct addrinfo aih; 364b13321fcSBruce M Simpson struct addrinfo *aip; 365b13321fcSBruce M Simpson int ch; 366b13321fcSBruce M Simpson int error; 367b13321fcSBruce M Simpson int exitval; 368b13321fcSBruce M Simpson size_t i; 369b13321fcSBruce M Simpson struct in_addr *pina; 370b13321fcSBruce M Simpson struct sockaddr_storage *pbss; 371b13321fcSBruce M Simpson 372b13321fcSBruce M Simpson ifname = DEFAULT_IFNAME; 373b13321fcSBruce M Simpson ifaddr_str = DEFAULT_IFADDR_STR; 374b13321fcSBruce M Simpson basegroup_str = DEFAULT_GROUP_STR; 375b13321fcSBruce M Simpson ifname = DEFAULT_IFNAME; 376b13321fcSBruce M Simpson portno = DEFAULT_PORT; 377b13321fcSBruce M Simpson basegroup.ss.ss_family = AF_UNSPEC; 378b13321fcSBruce M Simpson ifaddr.ss.ss_family = AF_UNSPEC; 379b13321fcSBruce M Simpson 380b13321fcSBruce M Simpson progname = basename(argv[0]); 381b13321fcSBruce M Simpson while ((ch = getopt(argc, argv, "4bg:i:I:mM:p:rsS:tT:v")) != -1) { 382b13321fcSBruce M Simpson switch (ch) { 383b13321fcSBruce M Simpson case '4': 384b13321fcSBruce M Simpson doipv4 = 1; 385b13321fcSBruce M Simpson break; 386b13321fcSBruce M Simpson case 'b': 387b13321fcSBruce M Simpson dobindaddr = 1; 388b13321fcSBruce M Simpson break; 389b13321fcSBruce M Simpson case 'g': 390b13321fcSBruce M Simpson basegroup_str = optarg; 391b13321fcSBruce M Simpson break; 392b13321fcSBruce M Simpson case 'i': 393b13321fcSBruce M Simpson ifname = optarg; 394b13321fcSBruce M Simpson break; 395b13321fcSBruce M Simpson case 'I': 396b13321fcSBruce M Simpson ifaddr_str = optarg; 397b13321fcSBruce M Simpson break; 398b13321fcSBruce M Simpson case 'm': 399b13321fcSBruce M Simpson usage(); /* notyet */ 400b13321fcSBruce M Simpson /*NOTREACHED*/ 401b13321fcSBruce M Simpson domiscopts = 1; 402b13321fcSBruce M Simpson break; 403b13321fcSBruce M Simpson case 'M': 404b13321fcSBruce M Simpson nmcastgroups = atoi(optarg); 405b13321fcSBruce M Simpson break; 406b13321fcSBruce M Simpson case 'p': 407b13321fcSBruce M Simpson portno = atoi(optarg); 408b13321fcSBruce M Simpson break; 409b13321fcSBruce M Simpson case 'r': 410b13321fcSBruce M Simpson doreuseport = 1; 411b13321fcSBruce M Simpson break; 412b13321fcSBruce M Simpson case 'S': 413b13321fcSBruce M Simpson nmcastsources = atoi(optarg); 414b13321fcSBruce M Simpson break; 415b13321fcSBruce M Simpson case 's': 416b13321fcSBruce M Simpson dossm = 1; 417b13321fcSBruce M Simpson break; 418b13321fcSBruce M Simpson case 't': 419b13321fcSBruce M Simpson dossf = 1; 420b13321fcSBruce M Simpson break; 421b13321fcSBruce M Simpson case 'T': 422b13321fcSBruce M Simpson timeout = atoi(optarg); 423b13321fcSBruce M Simpson break; 424b13321fcSBruce M Simpson case 'v': 425b13321fcSBruce M Simpson doverbose = 1; 426b13321fcSBruce M Simpson break; 427b13321fcSBruce M Simpson default: 428b13321fcSBruce M Simpson usage(); 429b13321fcSBruce M Simpson break; 430b13321fcSBruce M Simpson /*NOTREACHED*/ 431b13321fcSBruce M Simpson } 432b13321fcSBruce M Simpson } 433b13321fcSBruce M Simpson argc -= optind; 434b13321fcSBruce M Simpson argv += optind; 435b13321fcSBruce M Simpson 436b13321fcSBruce M Simpson memset(&aih, 0, sizeof(struct addrinfo)); 437b13321fcSBruce M Simpson aih.ai_flags = AI_NUMERICHOST | AI_PASSIVE; 438b13321fcSBruce M Simpson aih.ai_family = PF_INET; 439b13321fcSBruce M Simpson aih.ai_socktype = SOCK_DGRAM; 440b13321fcSBruce M Simpson aih.ai_protocol = IPPROTO_UDP; 441b13321fcSBruce M Simpson 442b13321fcSBruce M Simpson /* 443b13321fcSBruce M Simpson * Fill out base group. 444b13321fcSBruce M Simpson */ 445b13321fcSBruce M Simpson aip = NULL; 446b13321fcSBruce M Simpson error = getaddrinfo(basegroup_str, NULL, &aih, &aip); 447b13321fcSBruce M Simpson if (error != 0) { 448b13321fcSBruce M Simpson fprintf(stderr, "%s: getaddrinfo: %s\n", progname, 449b13321fcSBruce M Simpson gai_strerror(error)); 450b13321fcSBruce M Simpson exit(EX_USAGE); 451b13321fcSBruce M Simpson } 452b13321fcSBruce M Simpson memcpy(&basegroup, aip->ai_addr, aip->ai_addrlen); 453b13321fcSBruce M Simpson if (dodebug) { 454b13321fcSBruce M Simpson fprintf(stderr, "debug: gai thinks %s is %s\n", 455b13321fcSBruce M Simpson basegroup_str, inet_ntoa(basegroup.sin.sin_addr)); 456b13321fcSBruce M Simpson } 457b13321fcSBruce M Simpson freeaddrinfo(aip); 458b13321fcSBruce M Simpson 459b13321fcSBruce M Simpson assert(basegroup.ss.ss_family == AF_INET); 460b13321fcSBruce M Simpson 461b13321fcSBruce M Simpson /* 462b13321fcSBruce M Simpson * If user specified interface as an address, and protocol 463b13321fcSBruce M Simpson * specific APIs were selected, parse it. 464b13321fcSBruce M Simpson * Otherwise, parse interface index from name if protocol 465b13321fcSBruce M Simpson * independent APIs were selected (the default). 466b13321fcSBruce M Simpson */ 467b13321fcSBruce M Simpson if (doipv4) { 468b13321fcSBruce M Simpson if (ifaddr_str == NULL) { 469b13321fcSBruce M Simpson warnx("required argument missing: ifaddr"); 470b13321fcSBruce M Simpson usage(); 471b13321fcSBruce M Simpson /* NOTREACHED */ 472b13321fcSBruce M Simpson } 473b13321fcSBruce M Simpson aip = NULL; 474b13321fcSBruce M Simpson error = getaddrinfo(ifaddr_str, NULL, &aih, &aip); 475b13321fcSBruce M Simpson if (error != 0) { 476b13321fcSBruce M Simpson fprintf(stderr, "%s: getaddrinfo: %s\n", progname, 477b13321fcSBruce M Simpson gai_strerror(error)); 478b13321fcSBruce M Simpson exit(EX_USAGE); 479b13321fcSBruce M Simpson } 480b13321fcSBruce M Simpson memcpy(&ifaddr, aip->ai_addr, aip->ai_addrlen); 481b13321fcSBruce M Simpson if (dodebug) { 482b13321fcSBruce M Simpson fprintf(stderr, "debug: gai thinks %s is %s\n", 483b13321fcSBruce M Simpson ifaddr_str, inet_ntoa(ifaddr.sin.sin_addr)); 484b13321fcSBruce M Simpson } 485b13321fcSBruce M Simpson freeaddrinfo(aip); 486b13321fcSBruce M Simpson } 487b13321fcSBruce M Simpson 488b13321fcSBruce M Simpson if (!doipv4) { 489b13321fcSBruce M Simpson if (ifname == NULL) { 490b13321fcSBruce M Simpson warnx("required argument missing: ifname"); 491b13321fcSBruce M Simpson usage(); 492b13321fcSBruce M Simpson /* NOTREACHED */ 493b13321fcSBruce M Simpson } 494b13321fcSBruce M Simpson ifindex = if_nametoindex(ifname); 495b13321fcSBruce M Simpson if (ifindex == 0) 496b13321fcSBruce M Simpson err(EX_USAGE, "if_nametoindex"); 497b13321fcSBruce M Simpson } 498b13321fcSBruce M Simpson 499b13321fcSBruce M Simpson /* 500b13321fcSBruce M Simpson * Introduce randomness into group base if specified. 501b13321fcSBruce M Simpson */ 502b13321fcSBruce M Simpson if (dorandom) { 503b13321fcSBruce M Simpson in_addr_t ngroupbase; 504b13321fcSBruce M Simpson 505b13321fcSBruce M Simpson srandomdev(); 506b13321fcSBruce M Simpson ngroupbase = ntohl(basegroup.sin.sin_addr.s_addr); 507b13321fcSBruce M Simpson ngroupbase |= ((random() % ((1 << 11) - 1)) << 16); 508b13321fcSBruce M Simpson basegroup.sin.sin_addr.s_addr = htonl(ngroupbase); 509b13321fcSBruce M Simpson } 510b13321fcSBruce M Simpson 511b13321fcSBruce M Simpson if (argc > 0) { 512b13321fcSBruce M Simpson nmcastsources = argc; 513b13321fcSBruce M Simpson if (doipv4) { 514b13321fcSBruce M Simpson ipv4_sources = calloc(nmcastsources, 515b13321fcSBruce M Simpson sizeof(struct in_addr)); 516b13321fcSBruce M Simpson if (ipv4_sources == NULL) { 517b13321fcSBruce M Simpson exitval = EX_OSERR; 518b13321fcSBruce M Simpson goto out; 519b13321fcSBruce M Simpson } 520b13321fcSBruce M Simpson } else { 521b13321fcSBruce M Simpson ss_sources = calloc(nmcastsources, 522b13321fcSBruce M Simpson sizeof(struct sockaddr_storage)); 523b13321fcSBruce M Simpson if (ss_sources == NULL) { 524b13321fcSBruce M Simpson exitval = EX_OSERR; 525b13321fcSBruce M Simpson goto out; 526b13321fcSBruce M Simpson } 527b13321fcSBruce M Simpson } 528b13321fcSBruce M Simpson } 529b13321fcSBruce M Simpson 530b13321fcSBruce M Simpson /* 531b13321fcSBruce M Simpson * Parse source list, if any were specified on the command line. 532b13321fcSBruce M Simpson */ 533b13321fcSBruce M Simpson assert(aih.ai_family == PF_INET); 534b13321fcSBruce M Simpson pbss = ss_sources; 535b13321fcSBruce M Simpson pina = ipv4_sources; 536b13321fcSBruce M Simpson for (i = 0; i < (size_t)argc; i++) { 537b13321fcSBruce M Simpson aip = NULL; 538b13321fcSBruce M Simpson error = getaddrinfo(argv[i], NULL, &aih, &aip); 539b13321fcSBruce M Simpson if (error != 0) { 540b13321fcSBruce M Simpson fprintf(stderr, "getaddrinfo: %s\n", 541b13321fcSBruce M Simpson gai_strerror(error)); 542b13321fcSBruce M Simpson exitval = EX_USAGE; 543b13321fcSBruce M Simpson goto out; 544b13321fcSBruce M Simpson } 545b13321fcSBruce M Simpson if (doipv4) { 546b13321fcSBruce M Simpson struct sockaddr_in *sin = 547b13321fcSBruce M Simpson (struct sockaddr_in *)aip->ai_addr; 548b13321fcSBruce M Simpson *pina++ = sin->sin_addr; 549b13321fcSBruce M Simpson } else { 550b13321fcSBruce M Simpson memcpy(pbss++, aip->ai_addr, aip->ai_addrlen); 551b13321fcSBruce M Simpson } 552b13321fcSBruce M Simpson freeaddrinfo(aip); 553b13321fcSBruce M Simpson } 554b13321fcSBruce M Simpson 555b13321fcSBruce M Simpson /* 556b13321fcSBruce M Simpson * Perform the regression tests which the user requested. 557b13321fcSBruce M Simpson */ 558b13321fcSBruce M Simpson #ifdef notyet 559b13321fcSBruce M Simpson if (domiscopts) { 560b13321fcSBruce M Simpson exitval = do_misc_opts(); 561b13321fcSBruce M Simpson if (exitval) 562b13321fcSBruce M Simpson goto out; 563b13321fcSBruce M Simpson } 564b13321fcSBruce M Simpson #endif 565b13321fcSBruce M Simpson if (doipv4) { 566b13321fcSBruce M Simpson /* IPv4 protocol specific API tests */ 567b13321fcSBruce M Simpson if (dossm) { 568b13321fcSBruce M Simpson /* Source-specific multicast */ 569b13321fcSBruce M Simpson exitval = do_ssm_ipv4(); 570b13321fcSBruce M Simpson if (exitval) 571b13321fcSBruce M Simpson goto out; 572b13321fcSBruce M Simpson if (dossf) { 573b13321fcSBruce M Simpson /* Do setipvsourcefilter() too */ 574b13321fcSBruce M Simpson exitval = do_ssf_ipv4(); 575b13321fcSBruce M Simpson } 576b13321fcSBruce M Simpson } else { 577b13321fcSBruce M Simpson /* Any-source multicast */ 578b13321fcSBruce M Simpson exitval = do_asm_ipv4(); 579b13321fcSBruce M Simpson } 580b13321fcSBruce M Simpson } else { 581b13321fcSBruce M Simpson /* Protocol independent API tests */ 582b13321fcSBruce M Simpson if (dossm) { 583b13321fcSBruce M Simpson /* Source-specific multicast */ 584b13321fcSBruce M Simpson exitval = do_ssm_pim(); 585b13321fcSBruce M Simpson if (exitval) 586b13321fcSBruce M Simpson goto out; 587b13321fcSBruce M Simpson if (dossf) { 588b13321fcSBruce M Simpson /* Do setsourcefilter() too */ 589b13321fcSBruce M Simpson exitval = do_ssf_pim(); 590b13321fcSBruce M Simpson } 591b13321fcSBruce M Simpson } else { 592b13321fcSBruce M Simpson /* Any-source multicast */ 593b13321fcSBruce M Simpson exitval = do_asm_pim(); 594b13321fcSBruce M Simpson } 595b13321fcSBruce M Simpson } 596b13321fcSBruce M Simpson 597b13321fcSBruce M Simpson out: 598b13321fcSBruce M Simpson if (ipv4_sources != NULL) 599b13321fcSBruce M Simpson free(ipv4_sources); 600b13321fcSBruce M Simpson 601b13321fcSBruce M Simpson if (ss_sources != NULL) 602b13321fcSBruce M Simpson free(ss_sources); 603b13321fcSBruce M Simpson 604b13321fcSBruce M Simpson exit(exitval); 605b13321fcSBruce M Simpson } 606b13321fcSBruce M Simpson 607b13321fcSBruce M Simpson static int 608b13321fcSBruce M Simpson open_and_bind_socket(sockunion_t *bsu) 609b13321fcSBruce M Simpson { 610b13321fcSBruce M Simpson int error, optval, sock; 611b13321fcSBruce M Simpson 612b13321fcSBruce M Simpson sock = -1; 613b13321fcSBruce M Simpson 614b13321fcSBruce M Simpson sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 615b13321fcSBruce M Simpson if (sock == -1) { 616b13321fcSBruce M Simpson warn("socket"); 617b13321fcSBruce M Simpson return (-1); 618b13321fcSBruce M Simpson } 619b13321fcSBruce M Simpson 620b13321fcSBruce M Simpson if (doreuseport) { 621b13321fcSBruce M Simpson optval = 1; 622b13321fcSBruce M Simpson if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &optval, 623b13321fcSBruce M Simpson sizeof(optval)) < 0) { 624b13321fcSBruce M Simpson warn("setsockopt SO_REUSEPORT"); 625b13321fcSBruce M Simpson close(sock); 626b13321fcSBruce M Simpson return (-1); 627b13321fcSBruce M Simpson } 628b13321fcSBruce M Simpson } 629b13321fcSBruce M Simpson 630b13321fcSBruce M Simpson if (bsu != NULL) { 631b13321fcSBruce M Simpson error = bind(sock, &bsu->sa, bsu->sa.sa_len); 632b13321fcSBruce M Simpson if (error == -1) { 633b13321fcSBruce M Simpson warn("bind"); 634b13321fcSBruce M Simpson close(sock); 635b13321fcSBruce M Simpson return (-1); 636b13321fcSBruce M Simpson } 637b13321fcSBruce M Simpson } 638b13321fcSBruce M Simpson 639b13321fcSBruce M Simpson return (sock); 640b13321fcSBruce M Simpson } 641b13321fcSBruce M Simpson 642b13321fcSBruce M Simpson /* 643b13321fcSBruce M Simpson * Protocol-agnostic multicast I/O loop. 644b13321fcSBruce M Simpson * 645b13321fcSBruce M Simpson * Wait for 'timeout' seconds looking for traffic on group, so that manual 646b13321fcSBruce M Simpson * or automated regression tests (possibly running on another host) have an 647b13321fcSBruce M Simpson * opportunity to transmit within the group to test source filters. 648b13321fcSBruce M Simpson * 649b13321fcSBruce M Simpson * If the filter failed, this loop will report if we received traffic 650b13321fcSBruce M Simpson * from the source we elected to monitor. 651b13321fcSBruce M Simpson */ 652b13321fcSBruce M Simpson static int 653b13321fcSBruce M Simpson recv_loop_with_match(int sock, sockunion_t *group, sockunion_t *source) 654b13321fcSBruce M Simpson { 655b13321fcSBruce M Simpson int error; 656b13321fcSBruce M Simpson sockunion_t from; 657b13321fcSBruce M Simpson char groupname[NI_MAXHOST]; 658b13321fcSBruce M Simpson ssize_t len; 659b13321fcSBruce M Simpson size_t npackets; 660b13321fcSBruce M Simpson int jmpretval; 661b13321fcSBruce M Simpson char rxbuf[RXBUFSIZE]; 662b13321fcSBruce M Simpson char sourcename[NI_MAXHOST]; 663b13321fcSBruce M Simpson 664b13321fcSBruce M Simpson assert(source->sa.sa_family == AF_INET); 665b13321fcSBruce M Simpson 666b13321fcSBruce M Simpson /* 667b13321fcSBruce M Simpson * Return immediately if we don't need to wait for traffic. 668b13321fcSBruce M Simpson */ 669b13321fcSBruce M Simpson if (timeout == 0) 670b13321fcSBruce M Simpson return (0); 671b13321fcSBruce M Simpson 672b13321fcSBruce M Simpson error = getnameinfo(&group->sa, group->sa.sa_len, groupname, 673b13321fcSBruce M Simpson NI_MAXHOST, NULL, 0, NI_NUMERICHOST); 674b13321fcSBruce M Simpson if (error) { 675b13321fcSBruce M Simpson fprintf(stderr, "getnameinfo: %s\n", gai_strerror(error)); 676b13321fcSBruce M Simpson return (error); 677b13321fcSBruce M Simpson } 678b13321fcSBruce M Simpson 679b13321fcSBruce M Simpson error = getnameinfo(&source->sa, source->sa.sa_len, sourcename, 680b13321fcSBruce M Simpson NI_MAXHOST, NULL, 0, NI_NUMERICHOST); 681b13321fcSBruce M Simpson if (error) { 682b13321fcSBruce M Simpson fprintf(stderr, "getnameinfo: %s\n", gai_strerror(error)); 683b13321fcSBruce M Simpson return (error); 684b13321fcSBruce M Simpson } 685b13321fcSBruce M Simpson 686b13321fcSBruce M Simpson fprintf(stdout, 687b13321fcSBruce M Simpson "Waiting %d seconds for inbound traffic on group %s\n" 688b13321fcSBruce M Simpson "Expecting no traffic from blocked source: %s\n", 689b13321fcSBruce M Simpson (int)timeout, groupname, sourcename); 690b13321fcSBruce M Simpson 691b13321fcSBruce M Simpson signal(SIGINT, signal_handler); 692b13321fcSBruce M Simpson signal(SIGALRM, signal_handler); 693b13321fcSBruce M Simpson 694b13321fcSBruce M Simpson error = 0; 695b13321fcSBruce M Simpson npackets = 0; 696b13321fcSBruce M Simpson alarm(timeout); 697b13321fcSBruce M Simpson while (0 == (jmpretval = setjmp(jmpbuf))) { 698b13321fcSBruce M Simpson len = recvfrom(sock, rxbuf, RXBUFSIZE, 0, &from.sa, 699b13321fcSBruce M Simpson (socklen_t *)&from.sa.sa_len); 700b13321fcSBruce M Simpson if (dodebug) { 701b13321fcSBruce M Simpson fprintf(stderr, "debug: packet received from %s\n", 702b13321fcSBruce M Simpson inet_ntoa(from.sin.sin_addr)); 703b13321fcSBruce M Simpson } 704b13321fcSBruce M Simpson if (source && 705b13321fcSBruce M Simpson source->sin.sin_addr.s_addr == from.sin.sin_addr.s_addr) 706b13321fcSBruce M Simpson break; 707b13321fcSBruce M Simpson npackets++; 708b13321fcSBruce M Simpson } 709b13321fcSBruce M Simpson 710b13321fcSBruce M Simpson if (doverbose) { 711b13321fcSBruce M Simpson fprintf(stderr, "Number of datagrams received from " 712b13321fcSBruce M Simpson "non-blocked sources: %d\n", (int)npackets); 713b13321fcSBruce M Simpson } 714b13321fcSBruce M Simpson 715b13321fcSBruce M Simpson switch (jmpretval) { 716b13321fcSBruce M Simpson case SIGALRM: /* ok */ 717b13321fcSBruce M Simpson break; 718b13321fcSBruce M Simpson case SIGINT: /* go bye bye */ 719b13321fcSBruce M Simpson fprintf(stderr, "interrupted\n"); 720b13321fcSBruce M Simpson error = 20; 721b13321fcSBruce M Simpson break; 722b13321fcSBruce M Simpson case 0: /* Broke out of loop; saw a bad source. */ 723b13321fcSBruce M Simpson fprintf(stderr, "FAIL: got packet from blocked source\n"); 724b13321fcSBruce M Simpson error = EX_IOERR; 725b13321fcSBruce M Simpson break; 726b13321fcSBruce M Simpson default: 727b13321fcSBruce M Simpson warnx("recvfrom"); 728b13321fcSBruce M Simpson error = EX_OSERR; 729b13321fcSBruce M Simpson break; 730b13321fcSBruce M Simpson } 731b13321fcSBruce M Simpson 732b13321fcSBruce M Simpson signal(SIGINT, SIG_DFL); 733b13321fcSBruce M Simpson signal(SIGALRM, SIG_DFL); 734b13321fcSBruce M Simpson 735b13321fcSBruce M Simpson return (error); 736b13321fcSBruce M Simpson } 737b13321fcSBruce M Simpson 738b13321fcSBruce M Simpson static void 739b13321fcSBruce M Simpson signal_handler(int signo) 740b13321fcSBruce M Simpson { 741b13321fcSBruce M Simpson 742b13321fcSBruce M Simpson longjmp(jmpbuf, signo); 743b13321fcSBruce M Simpson } 744b13321fcSBruce M Simpson 745b13321fcSBruce M Simpson static void 746b13321fcSBruce M Simpson usage(void) 747b13321fcSBruce M Simpson { 748b13321fcSBruce M Simpson 749b13321fcSBruce M Simpson fprintf(stderr, "\nIP multicast regression test utility\n"); 750b13321fcSBruce M Simpson fprintf(stderr, 751b13321fcSBruce M Simpson "usage: %s [-4] [-b] [-g groupaddr] [-i ifname] [-I ifaddr] [-m]\n" 752b13321fcSBruce M Simpson " [-M ngroups] [-p portno] [-r] [-R] [-s] [-S nsources] [-t] [-T timeout]\n" 753b13321fcSBruce M Simpson " [-v] [blockaddr ...]\n\n", progname); 754b13321fcSBruce M Simpson fprintf(stderr, "-4: Use IPv4 API " 755b13321fcSBruce M Simpson "(default: Use protocol-independent API)\n"); 756b13321fcSBruce M Simpson fprintf(stderr, "-b: bind listening socket to ifaddr " 757b13321fcSBruce M Simpson "(default: INADDR_ANY)\n"); 758b13321fcSBruce M Simpson fprintf(stderr, "-g: Base IPv4 multicast group to join (default: %s)\n", 759b13321fcSBruce M Simpson DEFAULT_GROUP_STR); 760b13321fcSBruce M Simpson fprintf(stderr, "-i: interface for multicast joins (default: %s)\n", 761b13321fcSBruce M Simpson DEFAULT_IFNAME); 762b13321fcSBruce M Simpson fprintf(stderr, "-I: IPv4 address to join groups on, if using IPv4 " 763b13321fcSBruce M Simpson "API\n (default: %s)\n", DEFAULT_IFADDR_STR); 764b13321fcSBruce M Simpson #ifdef notyet 765b13321fcSBruce M Simpson fprintf(stderr, "-m: Test misc IPv4 multicast socket options " 766b13321fcSBruce M Simpson "(default: off)\n"); 767b13321fcSBruce M Simpson #endif 768b13321fcSBruce M Simpson fprintf(stderr, "-M: Number of multicast groups to join " 769b13321fcSBruce M Simpson "(default: %d)\n", (int)nmcastgroups); 770b13321fcSBruce M Simpson fprintf(stderr, "-p: Set local and remote port (default: %d)\n", 771b13321fcSBruce M Simpson DEFAULT_PORT); 772b13321fcSBruce M Simpson fprintf(stderr, "-r: Set SO_REUSEPORT on (default: off)\n"); 773b13321fcSBruce M Simpson fprintf(stderr, "-R: Randomize groups/sources (default: off)\n"); 774b13321fcSBruce M Simpson fprintf(stderr, "-s: Test source-specific API " 775b13321fcSBruce M Simpson "(default: test any-source API)\n"); 776b13321fcSBruce M Simpson fprintf(stderr, "-S: Number of multicast sources to generate if\n" 777b13321fcSBruce M Simpson " none specified on command line (default: %d)\n", 778b13321fcSBruce M Simpson (int)nmcastsources); 779b13321fcSBruce M Simpson fprintf(stderr, "-t: Test get/setNsourcefilter() (default: off)\n"); 780b13321fcSBruce M Simpson fprintf(stderr, "-T: Timeout to wait for blocked traffic on first " 781b13321fcSBruce M Simpson "group (default: %d)\n", DEFAULT_TIMEOUT); 782b13321fcSBruce M Simpson fprintf(stderr, "-v: Be verbose (default: off)\n"); 783b13321fcSBruce M Simpson fprintf(stderr, "\nRemaining arguments are treated as a list of IPv4 " 784b13321fcSBruce M Simpson "sources to filter.\n\n"); 785b13321fcSBruce M Simpson 786b13321fcSBruce M Simpson exit(EX_USAGE); 787b13321fcSBruce M Simpson } 788