1a93c2382SBruce M Simpson /*- 2*1de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*1de7b4b8SPedro F. Giffuni * 44ab13459SBruce M Simpson * Copyright (c) 2007-2009 Bruce Simpson. 5a93c2382SBruce M Simpson * Copyright (c) 2000 Wilbert De Graaf. 6a93c2382SBruce M Simpson * All rights reserved. 7fc3cc3f5SBill Fenner * 8a93c2382SBruce M Simpson * Redistribution and use in source and binary forms, with or without 9a93c2382SBruce M Simpson * modification, are permitted provided that the following conditions 10a93c2382SBruce M Simpson * are met: 11a93c2382SBruce M Simpson * 1. Redistributions of source code must retain the above copyright 12a93c2382SBruce M Simpson * notice, this list of conditions and the following disclaimer. 13a93c2382SBruce M Simpson * 2. Redistributions in binary form must reproduce the above copyright 14a93c2382SBruce M Simpson * notice, this list of conditions and the following disclaimer in the 15a93c2382SBruce M Simpson * documentation and/or other materials provided with the distribution. 16a93c2382SBruce M Simpson * 17a93c2382SBruce M Simpson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18a93c2382SBruce M Simpson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19a93c2382SBruce M Simpson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20a93c2382SBruce M Simpson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21a93c2382SBruce M Simpson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22a93c2382SBruce M Simpson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23a93c2382SBruce M Simpson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24a93c2382SBruce M Simpson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25a93c2382SBruce M Simpson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26a93c2382SBruce M Simpson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27a93c2382SBruce M Simpson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28a93c2382SBruce M Simpson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29a93c2382SBruce M Simpson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30a93c2382SBruce M Simpson * SUCH DAMAGE. 31a93c2382SBruce M Simpson */ 32a93c2382SBruce M Simpson 33a93c2382SBruce M Simpson /* 347369700eSBruce M Simpson * Diagnostic and test utility for multicast sockets. 357369700eSBruce M Simpson * XXX: This file currently assumes INET support in the base system. 367369700eSBruce M Simpson * TODO: Support embedded KAME Scope ID in IPv6 group addresses. 377369700eSBruce M Simpson * TODO: Use IPv4 link-local address when source address selection 387369700eSBruce M Simpson * is implemented; use MCAST_JOIN_SOURCE for IPv4. 39fc3cc3f5SBill Fenner */ 40fc3cc3f5SBill Fenner 4154ede02dSPhilippe Charnier #include <sys/cdefs.h> 4254ede02dSPhilippe Charnier __FBSDID("$FreeBSD$"); 432694efd4SDima Dorfman 44fc3cc3f5SBill Fenner #include <sys/types.h> 457369700eSBruce M Simpson #include <sys/param.h> 46a93c2382SBruce M Simpson #include <sys/errno.h> 47fc3cc3f5SBill Fenner #include <sys/socket.h> 48cf20f871SBill Fenner #include <sys/time.h> 49a93c2382SBruce M Simpson #include <sys/ioctl.h> 50a93c2382SBruce M Simpson 51fc3cc3f5SBill Fenner #include <net/if.h> 524a71a2e7SJulian Elischer #include <net/if_dl.h> 53a93c2382SBruce M Simpson #include <net/ethernet.h> 547369700eSBruce M Simpson #ifdef INET 55fc3cc3f5SBill Fenner #include <netinet/in.h> 567369700eSBruce M Simpson #include <netinet/in_systm.h> 577369700eSBruce M Simpson #include <netinet/ip.h> 587369700eSBruce M Simpson #include <netinet/ip_var.h> 597369700eSBruce M Simpson #endif 607369700eSBruce M Simpson #ifdef INET6 617369700eSBruce M Simpson #include <netinet/in.h> 627369700eSBruce M Simpson #include <netinet/ip6.h> 637369700eSBruce M Simpson #endif 64fc3cc3f5SBill Fenner 657369700eSBruce M Simpson #include <assert.h> 66a93c2382SBruce M Simpson #include <stdlib.h> 67a93c2382SBruce M Simpson #include <stdio.h> 68a93c2382SBruce M Simpson #include <string.h> 69a93c2382SBruce M Simpson #include <ctype.h> 707369700eSBruce M Simpson #include <errno.h> 71a93c2382SBruce M Simpson #include <err.h> 72a93c2382SBruce M Simpson #include <unistd.h> 73a93c2382SBruce M Simpson 747369700eSBruce M Simpson #include <arpa/inet.h> 757369700eSBruce M Simpson #include <netdb.h> 767369700eSBruce M Simpson #include <ifaddrs.h> 777369700eSBruce M Simpson 787369700eSBruce M Simpson union sockunion { 797369700eSBruce M Simpson struct sockaddr_storage ss; 807369700eSBruce M Simpson struct sockaddr sa; 817369700eSBruce M Simpson struct sockaddr_dl sdl; 827369700eSBruce M Simpson #ifdef INET 837369700eSBruce M Simpson struct sockaddr_in sin; 847369700eSBruce M Simpson #endif 857369700eSBruce M Simpson #ifdef INET6 867369700eSBruce M Simpson struct sockaddr_in6 sin6; 877369700eSBruce M Simpson #endif 887369700eSBruce M Simpson }; 897369700eSBruce M Simpson typedef union sockunion sockunion_t; 907369700eSBruce M Simpson 917369700eSBruce M Simpson union mrequnion { 927369700eSBruce M Simpson #ifdef INET 937369700eSBruce M Simpson struct ip_mreq mr; 947369700eSBruce M Simpson struct ip_mreq_source mrs; 957369700eSBruce M Simpson #endif 967369700eSBruce M Simpson #ifdef INET6 977369700eSBruce M Simpson struct ipv6_mreq mr6; 987369700eSBruce M Simpson struct group_source_req gr; 997369700eSBruce M Simpson #endif 1007369700eSBruce M Simpson }; 1017369700eSBruce M Simpson typedef union mrequnion mrequnion_t; 102a93c2382SBruce M Simpson 103a93c2382SBruce M Simpson #define MAX_ADDRS 20 104a93c2382SBruce M Simpson #define STR_SIZE 20 105a93c2382SBruce M Simpson #define LINE_LENGTH 80 106a93c2382SBruce M Simpson 1077369700eSBruce M Simpson #ifdef INET 1087369700eSBruce M Simpson static int __ifindex_to_primary_ip(const uint32_t, struct in_addr *); 1097369700eSBruce M Simpson #endif 1107369700eSBruce M Simpson static uint32_t parse_cmd_args(sockunion_t *, sockunion_t *, 1117369700eSBruce M Simpson const char *, const char *, const char *); 1127369700eSBruce M Simpson static void process_file(char *, int, int); 1137369700eSBruce M Simpson static void process_cmd(char*, int, int, FILE *); 1147369700eSBruce M Simpson static int su_cmp(const void *, const void *); 1157369700eSBruce M Simpson static void usage(void); 1167369700eSBruce M Simpson 1177369700eSBruce M Simpson /* 1187369700eSBruce M Simpson * Ordering predicate for qsort(). 1197369700eSBruce M Simpson */ 1204ab13459SBruce M Simpson static int 1217369700eSBruce M Simpson su_cmp(const void *a, const void *b) 1224ab13459SBruce M Simpson { 1237369700eSBruce M Simpson const sockunion_t *sua = (const sockunion_t *)a; 1247369700eSBruce M Simpson const sockunion_t *sub = (const sockunion_t *)b; 1257369700eSBruce M Simpson 1267369700eSBruce M Simpson assert(sua->sa.sa_family == sub->sa.sa_family); 1277369700eSBruce M Simpson 1287369700eSBruce M Simpson switch (sua->sa.sa_family) { 1297369700eSBruce M Simpson #ifdef INET 1307369700eSBruce M Simpson case AF_INET: 1317369700eSBruce M Simpson return ((int)(sua->sin.sin_addr.s_addr - 1327369700eSBruce M Simpson sub->sin.sin_addr.s_addr)); 1337369700eSBruce M Simpson break; 1347369700eSBruce M Simpson #endif 1357369700eSBruce M Simpson #ifdef INET6 1367369700eSBruce M Simpson case AF_INET6: 1377369700eSBruce M Simpson return (memcmp(&sua->sin6.sin6_addr, &sub->sin6.sin6_addr, 1387369700eSBruce M Simpson sizeof(struct in6_addr))); 1397369700eSBruce M Simpson break; 1407369700eSBruce M Simpson #endif 1417369700eSBruce M Simpson default: 1427369700eSBruce M Simpson break; 1434ab13459SBruce M Simpson } 1444ab13459SBruce M Simpson 1457369700eSBruce M Simpson assert(sua->sa.sa_len == sub->sa.sa_len); 1467369700eSBruce M Simpson return (memcmp(sua, sub, sua->sa.sa_len)); 1477369700eSBruce M Simpson } 1487369700eSBruce M Simpson 1497369700eSBruce M Simpson #ifdef INET 1507369700eSBruce M Simpson /* 1517369700eSBruce M Simpson * Internal: Map an interface index to primary IPv4 address. 1527369700eSBruce M Simpson * This is somewhat inefficient. This is a useful enough operation 1537369700eSBruce M Simpson * that it probably belongs in the C library. 1547369700eSBruce M Simpson * Return zero if found, -1 on error, 1 on not found. 1557369700eSBruce M Simpson */ 1567369700eSBruce M Simpson static int 1577369700eSBruce M Simpson __ifindex_to_primary_ip(const uint32_t ifindex, struct in_addr *pina) 1587369700eSBruce M Simpson { 1597369700eSBruce M Simpson char ifname[IFNAMSIZ]; 1607369700eSBruce M Simpson struct ifaddrs *ifa; 1617369700eSBruce M Simpson struct ifaddrs *ifaddrs; 1627369700eSBruce M Simpson sockunion_t *psu; 1637369700eSBruce M Simpson int retval; 1647369700eSBruce M Simpson 1657369700eSBruce M Simpson assert(ifindex != 0); 1667369700eSBruce M Simpson 1677369700eSBruce M Simpson retval = -1; 1687369700eSBruce M Simpson if (if_indextoname(ifindex, ifname) == NULL) 1697369700eSBruce M Simpson return (retval); 1707369700eSBruce M Simpson if (getifaddrs(&ifaddrs) < 0) 1717369700eSBruce M Simpson return (retval); 1727369700eSBruce M Simpson 1737369700eSBruce M Simpson /* 1747369700eSBruce M Simpson * Find the ifaddr entry corresponding to the interface name, 1757369700eSBruce M Simpson * and return the first matching IPv4 address. 1767369700eSBruce M Simpson */ 1777369700eSBruce M Simpson retval = 1; 1787369700eSBruce M Simpson for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { 1797369700eSBruce M Simpson if (strcmp(ifa->ifa_name, ifname) != 0) 1807369700eSBruce M Simpson continue; 1817369700eSBruce M Simpson psu = (sockunion_t *)ifa->ifa_addr; 1827369700eSBruce M Simpson if (psu && psu->sa.sa_family == AF_INET) { 1837369700eSBruce M Simpson retval = 0; 1847369700eSBruce M Simpson memcpy(pina, &psu->sin.sin_addr, 1857369700eSBruce M Simpson sizeof(struct in_addr)); 1867369700eSBruce M Simpson break; 1877369700eSBruce M Simpson } 1887369700eSBruce M Simpson } 1897369700eSBruce M Simpson 1907369700eSBruce M Simpson if (retval != 0) 1917369700eSBruce M Simpson errno = EADDRNOTAVAIL; /* XXX */ 1927369700eSBruce M Simpson 1937369700eSBruce M Simpson freeifaddrs(ifaddrs); 1947369700eSBruce M Simpson return (retval); 1957369700eSBruce M Simpson } 1967369700eSBruce M Simpson #endif /* INET */ 1977369700eSBruce M Simpson 198a93c2382SBruce M Simpson int 199a93c2382SBruce M Simpson main(int argc, char **argv) 200a93c2382SBruce M Simpson { 201a93c2382SBruce M Simpson char line[LINE_LENGTH]; 202a93c2382SBruce M Simpson char *p; 2037369700eSBruce M Simpson int i, s, s6; 204a93c2382SBruce M Simpson 2057369700eSBruce M Simpson s = -1; 2067369700eSBruce M Simpson s6 = -1; 2077369700eSBruce M Simpson #ifdef INET 208a93c2382SBruce M Simpson s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 209a5752d55SKevin Lo if (s == -1 && errno != EAFNOSUPPORT) 2107369700eSBruce M Simpson err(1, "can't open IPv4 socket"); 2117369700eSBruce M Simpson #endif 2127369700eSBruce M Simpson #ifdef INET6 2137369700eSBruce M Simpson s6 = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 214a5752d55SKevin Lo if (s6 == -1 && errno != EAFNOSUPPORT) 2157369700eSBruce M Simpson err(1, "can't open IPv6 socket"); 2167369700eSBruce M Simpson #endif 2170b6d7bb4SJohn Baldwin if (s == -1 && s6 == -1) 2180b6d7bb4SJohn Baldwin errc(1, EPROTONOSUPPORT, "can't open socket"); 219fc3cc3f5SBill Fenner 220a93c2382SBruce M Simpson if (argc < 2) { 221a93c2382SBruce M Simpson if (isatty(STDIN_FILENO)) { 222a93c2382SBruce M Simpson printf("multicast membership test program; " 223a93c2382SBruce M Simpson "enter ? for list of commands\n"); 224a93c2382SBruce M Simpson } 225a93c2382SBruce M Simpson do { 226a93c2382SBruce M Simpson if (fgets(line, sizeof(line), stdin) != NULL) { 227a93c2382SBruce M Simpson if (line[0] != 'f') 2287369700eSBruce M Simpson process_cmd(line, s, s6, stdin); 229a93c2382SBruce M Simpson else { 230a93c2382SBruce M Simpson /* Get the filename */ 231a93c2382SBruce M Simpson for (i = 1; isblank(line[i]); i++); 232a93c2382SBruce M Simpson if ((p = (char*)strchr(line, '\n')) 233a93c2382SBruce M Simpson != NULL) 234a93c2382SBruce M Simpson *p = '\0'; 2357369700eSBruce M Simpson process_file(&line[i], s, s6); 236a93c2382SBruce M Simpson } 237a93c2382SBruce M Simpson } 238a93c2382SBruce M Simpson } while (!feof(stdin)); 239a93c2382SBruce M Simpson } else { 240a93c2382SBruce M Simpson for (i = 1; i < argc; i++) { 2417369700eSBruce M Simpson process_file(argv[i], s, s6); 242a93c2382SBruce M Simpson } 243a93c2382SBruce M Simpson } 244fc3cc3f5SBill Fenner 2457369700eSBruce M Simpson if (s != -1) 2467369700eSBruce M Simpson close(s); 2477369700eSBruce M Simpson if (s6 != -1) 2487369700eSBruce M Simpson close(s6); 2497369700eSBruce M Simpson 250a93c2382SBruce M Simpson exit (0); 251a93c2382SBruce M Simpson } 252a93c2382SBruce M Simpson 253a93c2382SBruce M Simpson static void 2547369700eSBruce M Simpson process_file(char *fname, int s, int s6) 255fc3cc3f5SBill Fenner { 256a93c2382SBruce M Simpson char line[80]; 257a93c2382SBruce M Simpson FILE *fp; 258a93c2382SBruce M Simpson char *lineptr; 259a93c2382SBruce M Simpson 260a93c2382SBruce M Simpson fp = fopen(fname, "r"); 261a93c2382SBruce M Simpson if (fp == NULL) { 262a93c2382SBruce M Simpson warn("fopen"); 263a93c2382SBruce M Simpson return; 264a93c2382SBruce M Simpson } 265a93c2382SBruce M Simpson 266a93c2382SBruce M Simpson /* Skip comments and empty lines. */ 267a93c2382SBruce M Simpson while (fgets(line, sizeof(line), fp) != NULL) { 268fc3cc3f5SBill Fenner lineptr = line; 269a93c2382SBruce M Simpson while (isblank(*lineptr)) 270a93c2382SBruce M Simpson lineptr++; 271a93c2382SBruce M Simpson if (*lineptr != '#' && *lineptr != '\n') 2727369700eSBruce M Simpson process_cmd(lineptr, s, s6, fp); 273a93c2382SBruce M Simpson } 274a93c2382SBruce M Simpson 275a93c2382SBruce M Simpson fclose(fp); 276a93c2382SBruce M Simpson } 277a93c2382SBruce M Simpson 2787369700eSBruce M Simpson /* 2797369700eSBruce M Simpson * Parse join/leave/allow/block arguments, given: 2807369700eSBruce M Simpson * str1: group (as AF_INET or AF_INET6 printable) 2817369700eSBruce M Simpson * str2: ifname 2827369700eSBruce M Simpson * str3: optional source address (may be NULL). 2837369700eSBruce M Simpson * This argument must have the same parsed address family as str1. 2847369700eSBruce M Simpson * Return the ifindex of ifname, or 0 if any parse element failed. 2857369700eSBruce M Simpson */ 2867369700eSBruce M Simpson static uint32_t 2877369700eSBruce M Simpson parse_cmd_args(sockunion_t *psu, sockunion_t *psu2, 2887369700eSBruce M Simpson const char *str1, const char *str2, const char *str3) 2897369700eSBruce M Simpson { 2907369700eSBruce M Simpson struct addrinfo hints; 2917369700eSBruce M Simpson struct addrinfo *res; 2927369700eSBruce M Simpson uint32_t ifindex; 2937369700eSBruce M Simpson int af, error; 2947369700eSBruce M Simpson 2957369700eSBruce M Simpson assert(psu != NULL); 2967369700eSBruce M Simpson assert(str1 != NULL); 2977369700eSBruce M Simpson assert(str2 != NULL); 2987369700eSBruce M Simpson 2997369700eSBruce M Simpson af = AF_UNSPEC; 3007369700eSBruce M Simpson 3017369700eSBruce M Simpson ifindex = if_nametoindex(str2); 3027369700eSBruce M Simpson if (ifindex == 0) 3037369700eSBruce M Simpson return (0); 3047369700eSBruce M Simpson 3057369700eSBruce M Simpson memset(&hints, 0, sizeof(struct addrinfo)); 3067369700eSBruce M Simpson hints.ai_flags = AI_NUMERICHOST; 3077369700eSBruce M Simpson hints.ai_family = PF_UNSPEC; 3087369700eSBruce M Simpson hints.ai_socktype = SOCK_DGRAM; 3097369700eSBruce M Simpson 3107369700eSBruce M Simpson memset(psu, 0, sizeof(sockunion_t)); 3117369700eSBruce M Simpson psu->sa.sa_family = AF_UNSPEC; 3127369700eSBruce M Simpson 3137369700eSBruce M Simpson error = getaddrinfo(str1, "0", &hints, &res); 3147369700eSBruce M Simpson if (error) { 3157369700eSBruce M Simpson warnx("getaddrinfo: %s", gai_strerror(error)); 3167369700eSBruce M Simpson return (0); 3177369700eSBruce M Simpson } 3187369700eSBruce M Simpson assert(res != NULL); 3197369700eSBruce M Simpson af = res->ai_family; 3207369700eSBruce M Simpson memcpy(psu, res->ai_addr, res->ai_addrlen); 3217369700eSBruce M Simpson freeaddrinfo(res); 3227369700eSBruce M Simpson 3237369700eSBruce M Simpson /* sscanf() may pass the empty string. */ 3247369700eSBruce M Simpson if (psu2 != NULL && str3 != NULL && *str3 != '\0') { 3257369700eSBruce M Simpson memset(psu2, 0, sizeof(sockunion_t)); 3267369700eSBruce M Simpson psu2->sa.sa_family = AF_UNSPEC; 3277369700eSBruce M Simpson 3287369700eSBruce M Simpson /* look for following address family; str3 is *optional*. */ 3297369700eSBruce M Simpson hints.ai_family = af; 3307369700eSBruce M Simpson error = getaddrinfo(str3, "0", &hints, &res); 3317369700eSBruce M Simpson if (error) { 3327369700eSBruce M Simpson warnx("getaddrinfo: %s", gai_strerror(error)); 3337369700eSBruce M Simpson ifindex = 0; 3347369700eSBruce M Simpson } else { 3357369700eSBruce M Simpson if (af != res->ai_family) { 3367369700eSBruce M Simpson errno = EINVAL; /* XXX */ 3377369700eSBruce M Simpson ifindex = 0; 3387369700eSBruce M Simpson } 3397369700eSBruce M Simpson memcpy(psu2, res->ai_addr, res->ai_addrlen); 3407369700eSBruce M Simpson freeaddrinfo(res); 3417369700eSBruce M Simpson } 3427369700eSBruce M Simpson } 3437369700eSBruce M Simpson 3447369700eSBruce M Simpson return (ifindex); 3457369700eSBruce M Simpson } 3467369700eSBruce M Simpson 3477369700eSBruce M Simpson static __inline int 3487369700eSBruce M Simpson af2sock(const int af, int s, int s6) 3497369700eSBruce M Simpson { 3507369700eSBruce M Simpson 3517369700eSBruce M Simpson #ifdef INET 3527369700eSBruce M Simpson if (af == AF_INET) 3537369700eSBruce M Simpson return (s); 3547369700eSBruce M Simpson #endif 3557369700eSBruce M Simpson #ifdef INET6 3567369700eSBruce M Simpson if (af == AF_INET6) 3577369700eSBruce M Simpson return (s6); 3587369700eSBruce M Simpson #endif 3597369700eSBruce M Simpson return (-1); 3607369700eSBruce M Simpson } 3617369700eSBruce M Simpson 3627369700eSBruce M Simpson static __inline int 3637369700eSBruce M Simpson af2socklen(const int af) 3647369700eSBruce M Simpson { 3657369700eSBruce M Simpson 3667369700eSBruce M Simpson #ifdef INET 3677369700eSBruce M Simpson if (af == AF_INET) 3687369700eSBruce M Simpson return (sizeof(struct sockaddr_in)); 3697369700eSBruce M Simpson #endif 3707369700eSBruce M Simpson #ifdef INET6 3717369700eSBruce M Simpson if (af == AF_INET6) 3727369700eSBruce M Simpson return (sizeof(struct sockaddr_in6)); 3737369700eSBruce M Simpson #endif 3747369700eSBruce M Simpson return (-1); 3757369700eSBruce M Simpson } 3767369700eSBruce M Simpson 377a93c2382SBruce M Simpson static void 3780b6d7bb4SJohn Baldwin process_cmd(char *cmd, int s, int s6, FILE *fp __unused) 379fc3cc3f5SBill Fenner { 380a93c2382SBruce M Simpson char str1[STR_SIZE]; 381a93c2382SBruce M Simpson char str2[STR_SIZE]; 382a93c2382SBruce M Simpson char str3[STR_SIZE]; 3837369700eSBruce M Simpson mrequnion_t mr; 3847369700eSBruce M Simpson sockunion_t su, su2; 385a93c2382SBruce M Simpson struct ifreq ifr; 386a93c2382SBruce M Simpson char *line; 3877369700eSBruce M Simpson char *toptname; 3887369700eSBruce M Simpson void *optval; 3897369700eSBruce M Simpson uint32_t fmode, ifindex; 3907369700eSBruce M Simpson socklen_t optlen; 3917369700eSBruce M Simpson int af, error, f, flags, i, level, n, optname; 3927369700eSBruce M Simpson 3937369700eSBruce M Simpson af = AF_UNSPEC; 3947369700eSBruce M Simpson su.sa.sa_family = AF_UNSPEC; 3957369700eSBruce M Simpson su2.sa.sa_family = AF_UNSPEC; 396a93c2382SBruce M Simpson 397a93c2382SBruce M Simpson line = cmd; 398a93c2382SBruce M Simpson while (isblank(*++line)) 399a93c2382SBruce M Simpson ; /* Skip whitespace. */ 400a93c2382SBruce M Simpson 4012b5554feSPedro F. Giffuni n = 0; 402a93c2382SBruce M Simpson switch (*cmd) { 403fc3cc3f5SBill Fenner case '?': 404a93c2382SBruce M Simpson usage(); 405a93c2382SBruce M Simpson break; 406a93c2382SBruce M Simpson 407a93c2382SBruce M Simpson case 'q': 408a93c2382SBruce M Simpson close(s); 409a93c2382SBruce M Simpson exit(0); 410a93c2382SBruce M Simpson 411a93c2382SBruce M Simpson case 's': 412a93c2382SBruce M Simpson if ((sscanf(line, "%d", &n) != 1) || (n < 1)) { 413a93c2382SBruce M Simpson printf("-1\n"); 414fc3cc3f5SBill Fenner break; 415fc3cc3f5SBill Fenner } 416a93c2382SBruce M Simpson sleep(n); 417a93c2382SBruce M Simpson printf("ok\n"); 418a93c2382SBruce M Simpson break; 419fc3cc3f5SBill Fenner 420fc3cc3f5SBill Fenner case 'j': 421fc3cc3f5SBill Fenner case 'l': 4224ab13459SBruce M Simpson str3[0] = '\0'; 4237369700eSBruce M Simpson toptname = ""; 4244ab13459SBruce M Simpson sscanf(line, "%s %s %s", str1, str2, str3); 4257369700eSBruce M Simpson ifindex = parse_cmd_args(&su, &su2, str1, str2, str3); 4267369700eSBruce M Simpson if (ifindex == 0) { 4274ab13459SBruce M Simpson printf("-1\n"); 4284ab13459SBruce M Simpson break; 4294ab13459SBruce M Simpson } 4307369700eSBruce M Simpson af = su.sa.sa_family; 4317369700eSBruce M Simpson #ifdef INET 4327369700eSBruce M Simpson if (af == AF_INET) { 4337369700eSBruce M Simpson struct in_addr ina; 4347369700eSBruce M Simpson 4357369700eSBruce M Simpson error = __ifindex_to_primary_ip(ifindex, &ina); 4367369700eSBruce M Simpson if (error != 0) { 4377369700eSBruce M Simpson warn("primary_ip_lookup %s", str2); 4387369700eSBruce M Simpson printf("-1\n"); 4397369700eSBruce M Simpson break; 4407369700eSBruce M Simpson } 4417369700eSBruce M Simpson level = IPPROTO_IP; 4427369700eSBruce M Simpson 4437369700eSBruce M Simpson if (su2.sa.sa_family != AF_UNSPEC) { 4447369700eSBruce M Simpson mr.mrs.imr_multiaddr = su.sin.sin_addr; 4457369700eSBruce M Simpson mr.mrs.imr_sourceaddr = su2.sin.sin_addr; 4467369700eSBruce M Simpson mr.mrs.imr_interface = ina; 4477369700eSBruce M Simpson optname = (*cmd == 'j') ? 4487369700eSBruce M Simpson IP_ADD_SOURCE_MEMBERSHIP : 4494ab13459SBruce M Simpson IP_DROP_SOURCE_MEMBERSHIP; 4507369700eSBruce M Simpson toptname = (*cmd == 'j') ? 4514ab13459SBruce M Simpson "IP_ADD_SOURCE_MEMBERSHIP" : 4527369700eSBruce M Simpson "IP_DROP_SOURCE_MEMBERSHIP"; 4537369700eSBruce M Simpson optval = (void *)&mr.mrs; 4547369700eSBruce M Simpson optlen = sizeof(mr.mrs); 4554ab13459SBruce M Simpson } else { 4567369700eSBruce M Simpson mr.mr.imr_multiaddr = su.sin.sin_addr; 4577369700eSBruce M Simpson mr.mr.imr_interface = ina; 4587369700eSBruce M Simpson optname = (*cmd == 'j') ? 4597369700eSBruce M Simpson IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; 4607369700eSBruce M Simpson toptname = (*cmd == 'j') ? 4617369700eSBruce M Simpson "IP_ADD_MEMBERSHIP" : "IP_DROP_MEMBERSHIP"; 4627369700eSBruce M Simpson optval = (void *)&mr.mr; 4637369700eSBruce M Simpson optlen = sizeof(mr.mr); 4644ab13459SBruce M Simpson } 4650b6d7bb4SJohn Baldwin if (s < 0) { 4660b6d7bb4SJohn Baldwin warnc(EPROTONOSUPPORT, "setsockopt %s", 4670b6d7bb4SJohn Baldwin toptname); 4680b6d7bb4SJohn Baldwin } else if (setsockopt(s, level, optname, optval, 4697369700eSBruce M Simpson optlen) == 0) { 4707369700eSBruce M Simpson printf("ok\n"); 4717369700eSBruce M Simpson break; 4724ab13459SBruce M Simpson } else { 4737369700eSBruce M Simpson warn("setsockopt %s", toptname); 4747369700eSBruce M Simpson } 4757369700eSBruce M Simpson } 4767369700eSBruce M Simpson #ifdef INET6 4777369700eSBruce M Simpson else 4787369700eSBruce M Simpson #endif /* INET with INET6 */ 4797369700eSBruce M Simpson #endif /* INET */ 4807369700eSBruce M Simpson #ifdef INET6 4817369700eSBruce M Simpson if (af == AF_INET6) { 4827369700eSBruce M Simpson level = IPPROTO_IPV6; 4837369700eSBruce M Simpson if (su2.sa.sa_family != AF_UNSPEC) { 4847369700eSBruce M Simpson mr.gr.gsr_interface = ifindex; 4857369700eSBruce M Simpson mr.gr.gsr_group = su.ss; 4867369700eSBruce M Simpson mr.gr.gsr_source = su2.ss; 4877369700eSBruce M Simpson optname = (*cmd == 'j') ? 4887369700eSBruce M Simpson MCAST_JOIN_SOURCE_GROUP: 4897369700eSBruce M Simpson MCAST_LEAVE_SOURCE_GROUP; 4907369700eSBruce M Simpson toptname = (*cmd == 'j') ? 4917369700eSBruce M Simpson "MCAST_JOIN_SOURCE_GROUP": 4927369700eSBruce M Simpson "MCAST_LEAVE_SOURCE_GROUP"; 4937369700eSBruce M Simpson optval = (void *)&mr.gr; 4947369700eSBruce M Simpson optlen = sizeof(mr.gr); 4957369700eSBruce M Simpson } else { 4967369700eSBruce M Simpson mr.mr6.ipv6mr_multiaddr = su.sin6.sin6_addr; 4977369700eSBruce M Simpson mr.mr6.ipv6mr_interface = ifindex; 4987369700eSBruce M Simpson optname = (*cmd == 'j') ? 4997369700eSBruce M Simpson IPV6_JOIN_GROUP : 5007369700eSBruce M Simpson IPV6_LEAVE_GROUP; 5017369700eSBruce M Simpson toptname = (*cmd == 'j') ? 5027369700eSBruce M Simpson "IPV6_JOIN_GROUP" : 5037369700eSBruce M Simpson "IPV6_LEAVE_GROUP"; 5047369700eSBruce M Simpson optval = (void *)&mr.mr6; 5057369700eSBruce M Simpson optlen = sizeof(mr.mr6); 5067369700eSBruce M Simpson } 5070b6d7bb4SJohn Baldwin if (s6 < 0) { 5080b6d7bb4SJohn Baldwin warnc(EPROTONOSUPPORT, "setsockopt %s", 5090b6d7bb4SJohn Baldwin toptname); 5100b6d7bb4SJohn Baldwin } else if (setsockopt(s6, level, optname, optval, 5117369700eSBruce M Simpson optlen) == 0) { 5127369700eSBruce M Simpson printf("ok\n"); 5137369700eSBruce M Simpson break; 5147369700eSBruce M Simpson } else { 5157369700eSBruce M Simpson warn("setsockopt %s", toptname); 5167369700eSBruce M Simpson } 5177369700eSBruce M Simpson } 5187369700eSBruce M Simpson #endif /* INET6 */ 5197369700eSBruce M Simpson /* FALLTHROUGH */ 5207369700eSBruce M Simpson printf("-1\n"); 5217369700eSBruce M Simpson break; 5227369700eSBruce M Simpson 5237369700eSBruce M Simpson /* 5247369700eSBruce M Simpson * Set the socket to include or exclude filter mode, and 5257369700eSBruce M Simpson * add some sources to the filterlist, using the full-state API. 5267369700eSBruce M Simpson */ 5277369700eSBruce M Simpson case 'i': 5287369700eSBruce M Simpson case 'e': { 5297369700eSBruce M Simpson sockunion_t sources[MAX_ADDRS]; 5307369700eSBruce M Simpson struct addrinfo hints; 5317369700eSBruce M Simpson struct addrinfo *res; 5327369700eSBruce M Simpson char *cp; 5337369700eSBruce M Simpson int af1; 5347369700eSBruce M Simpson 5357369700eSBruce M Simpson n = 0; 5367369700eSBruce M Simpson fmode = (*cmd == 'i') ? MCAST_INCLUDE : MCAST_EXCLUDE; 5377369700eSBruce M Simpson if ((sscanf(line, "%s %s %d", str1, str2, &n)) != 3) { 538a93c2382SBruce M Simpson printf("-1\n"); 539fc3cc3f5SBill Fenner break; 540fc3cc3f5SBill Fenner } 5417369700eSBruce M Simpson 5427369700eSBruce M Simpson ifindex = parse_cmd_args(&su, NULL, str1, str2, NULL); 5437369700eSBruce M Simpson if (ifindex == 0 || n < 0 || n > MAX_ADDRS) { 5447369700eSBruce M Simpson printf("-1\n"); 545fc3cc3f5SBill Fenner break; 5467369700eSBruce M Simpson } 5477369700eSBruce M Simpson af = su.sa.sa_family; 5480b6d7bb4SJohn Baldwin if (af2sock(af, s, s6) == -1) { 5490b6d7bb4SJohn Baldwin warnc(EPROTONOSUPPORT, "setsourcefilter"); 5500b6d7bb4SJohn Baldwin break; 5510b6d7bb4SJohn Baldwin } 5527369700eSBruce M Simpson 5537369700eSBruce M Simpson memset(&hints, 0, sizeof(struct addrinfo)); 5547369700eSBruce M Simpson hints.ai_flags = AI_NUMERICHOST; 5557369700eSBruce M Simpson hints.ai_family = af; 5567369700eSBruce M Simpson hints.ai_socktype = SOCK_DGRAM; 5577369700eSBruce M Simpson 5587369700eSBruce M Simpson for (i = 0; i < n; i++) { 5597369700eSBruce M Simpson sockunion_t *psu = (sockunion_t *)&sources[i]; 5607369700eSBruce M Simpson /* 5617369700eSBruce M Simpson * Trim trailing whitespace, as getaddrinfo() 5627369700eSBruce M Simpson * can't cope with it. 5637369700eSBruce M Simpson */ 5647369700eSBruce M Simpson fgets(str1, sizeof(str1), fp); 5657369700eSBruce M Simpson cp = strchr(str1, '\n'); 5667369700eSBruce M Simpson if (cp != NULL) 5677369700eSBruce M Simpson *cp = '\0'; 5687369700eSBruce M Simpson 5697369700eSBruce M Simpson res = NULL; 5707369700eSBruce M Simpson error = getaddrinfo(str1, "0", &hints, &res); 5717369700eSBruce M Simpson if (error) 5727369700eSBruce M Simpson break; 5737369700eSBruce M Simpson assert(res != NULL); 5747369700eSBruce M Simpson 5757369700eSBruce M Simpson memset(psu, 0, sizeof(sockunion_t)); 5767369700eSBruce M Simpson af1 = res->ai_family; 5777369700eSBruce M Simpson if (af1 == af) 5787369700eSBruce M Simpson memcpy(psu, res->ai_addr, res->ai_addrlen); 5797369700eSBruce M Simpson freeaddrinfo(res); 5807369700eSBruce M Simpson if (af1 != af) 5817369700eSBruce M Simpson break; 5827369700eSBruce M Simpson } 5837369700eSBruce M Simpson if (i < n) { 5847369700eSBruce M Simpson if (error) 5857369700eSBruce M Simpson warnx("getaddrinfo: %s", gai_strerror(error)); 5867369700eSBruce M Simpson printf("-1\n"); 5877369700eSBruce M Simpson break; 5887369700eSBruce M Simpson } 5897369700eSBruce M Simpson if (setsourcefilter(af2sock(af, s, s6), ifindex, 5907369700eSBruce M Simpson &su.sa, su.sa.sa_len, fmode, n, &sources[0].ss) != 0) 5917369700eSBruce M Simpson warn("setsourcefilter"); 5927369700eSBruce M Simpson else 5937369700eSBruce M Simpson printf("ok\n"); 5947369700eSBruce M Simpson } break; 5957369700eSBruce M Simpson 5967369700eSBruce M Simpson /* 5977369700eSBruce M Simpson * Allow or block traffic from a source, using the 5987369700eSBruce M Simpson * delta based api. 5997369700eSBruce M Simpson */ 6007369700eSBruce M Simpson case 't': 6017369700eSBruce M Simpson case 'b': { 6027369700eSBruce M Simpson str3[0] = '\0'; 6037369700eSBruce M Simpson toptname = ""; 6047369700eSBruce M Simpson sscanf(line, "%s %s %s", str1, str2, str3); 6057369700eSBruce M Simpson ifindex = parse_cmd_args(&su, &su2, str1, str2, str3); 6067369700eSBruce M Simpson if (ifindex == 0 || su2.sa.sa_family == AF_UNSPEC) { 6077369700eSBruce M Simpson printf("-1\n"); 6087369700eSBruce M Simpson break; 6097369700eSBruce M Simpson } 6107369700eSBruce M Simpson af = su.sa.sa_family; 6110b6d7bb4SJohn Baldwin if (af2sock(af, s, s6) == -1) { 6120b6d7bb4SJohn Baldwin warnc(EPROTONOSUPPORT, "getsourcefilter"); 6130b6d7bb4SJohn Baldwin break; 6140b6d7bb4SJohn Baldwin } 6157369700eSBruce M Simpson 6167369700eSBruce M Simpson /* First determine our current filter mode. */ 6177369700eSBruce M Simpson if (getsourcefilter(af2sock(af, s, s6), ifindex, 6187369700eSBruce M Simpson &su.sa, su.sa.sa_len, &fmode, &n, NULL) != 0) { 6197369700eSBruce M Simpson warn("getsourcefilter"); 6207369700eSBruce M Simpson break; 6217369700eSBruce M Simpson } 6227369700eSBruce M Simpson #ifdef INET 6237369700eSBruce M Simpson if (af == AF_INET) { 6247369700eSBruce M Simpson struct in_addr ina; 6257369700eSBruce M Simpson 6267369700eSBruce M Simpson error = __ifindex_to_primary_ip(ifindex, &ina); 6277369700eSBruce M Simpson if (error != 0) { 6287369700eSBruce M Simpson warn("primary_ip_lookup %s", str2); 6297369700eSBruce M Simpson printf("-1\n"); 6307369700eSBruce M Simpson break; 6317369700eSBruce M Simpson } 6327369700eSBruce M Simpson level = IPPROTO_IP; 6337369700eSBruce M Simpson optval = (void *)&mr.mrs; 6347369700eSBruce M Simpson optlen = sizeof(mr.mrs); 6357369700eSBruce M Simpson mr.mrs.imr_multiaddr = su.sin.sin_addr; 6367369700eSBruce M Simpson mr.mrs.imr_sourceaddr = su2.sin.sin_addr; 6377369700eSBruce M Simpson mr.mrs.imr_interface = ina; 6387369700eSBruce M Simpson if (fmode == MCAST_EXCLUDE) { 6397369700eSBruce M Simpson /* Any-source mode socket membership. */ 6407369700eSBruce M Simpson optname = (*cmd == 't') ? 6417369700eSBruce M Simpson IP_UNBLOCK_SOURCE : 6427369700eSBruce M Simpson IP_BLOCK_SOURCE; 6437369700eSBruce M Simpson toptname = (*cmd == 't') ? 6447369700eSBruce M Simpson "IP_UNBLOCK_SOURCE" : 6457369700eSBruce M Simpson "IP_BLOCK_SOURCE"; 6467369700eSBruce M Simpson } else { 6477369700eSBruce M Simpson /* Source-specific mode socket membership. */ 6487369700eSBruce M Simpson optname = (*cmd == 't') ? 6497369700eSBruce M Simpson IP_ADD_SOURCE_MEMBERSHIP : 6507369700eSBruce M Simpson IP_DROP_SOURCE_MEMBERSHIP; 6517369700eSBruce M Simpson toptname = (*cmd == 't') ? 6527369700eSBruce M Simpson "IP_ADD_SOURCE_MEMBERSHIP" : 6537369700eSBruce M Simpson "IP_DROP_SOURCE_MEMBERSHIP"; 6547369700eSBruce M Simpson } 6557369700eSBruce M Simpson if (setsockopt(s, level, optname, optval, 6567369700eSBruce M Simpson optlen) == 0) { 6577369700eSBruce M Simpson printf("ok\n"); 6587369700eSBruce M Simpson break; 6597369700eSBruce M Simpson } else { 6607369700eSBruce M Simpson warn("setsockopt %s", toptname); 6617369700eSBruce M Simpson } 6627369700eSBruce M Simpson } 6637369700eSBruce M Simpson #ifdef INET6 6647369700eSBruce M Simpson else 6657369700eSBruce M Simpson #endif /* INET with INET6 */ 6667369700eSBruce M Simpson #endif /* INET */ 6677369700eSBruce M Simpson #ifdef INET6 6687369700eSBruce M Simpson if (af == AF_INET6) { 6697369700eSBruce M Simpson level = IPPROTO_IPV6; 6707369700eSBruce M Simpson mr.gr.gsr_interface = ifindex; 6717369700eSBruce M Simpson mr.gr.gsr_group = su.ss; 6727369700eSBruce M Simpson mr.gr.gsr_source = su2.ss; 6737369700eSBruce M Simpson if (fmode == MCAST_EXCLUDE) { 6747369700eSBruce M Simpson /* Any-source mode socket membership. */ 6757369700eSBruce M Simpson optname = (*cmd == 't') ? 6767369700eSBruce M Simpson MCAST_UNBLOCK_SOURCE : 6777369700eSBruce M Simpson MCAST_BLOCK_SOURCE; 6787369700eSBruce M Simpson toptname = (*cmd == 't') ? 6797369700eSBruce M Simpson "MCAST_UNBLOCK_SOURCE" : 6807369700eSBruce M Simpson "MCAST_BLOCK_SOURCE"; 6817369700eSBruce M Simpson } else { 6827369700eSBruce M Simpson /* Source-specific mode socket membership. */ 6837369700eSBruce M Simpson optname = (*cmd == 't') ? 6847369700eSBruce M Simpson MCAST_JOIN_SOURCE_GROUP : 6857369700eSBruce M Simpson MCAST_LEAVE_SOURCE_GROUP; 6867369700eSBruce M Simpson toptname = (*cmd == 't') ? 6877369700eSBruce M Simpson "MCAST_JOIN_SOURCE_GROUP": 6887369700eSBruce M Simpson "MCAST_LEAVE_SOURCE_GROUP"; 6897369700eSBruce M Simpson } 6907369700eSBruce M Simpson optval = (void *)&mr.gr; 6917369700eSBruce M Simpson optlen = sizeof(mr.gr); 6927369700eSBruce M Simpson if (setsockopt(s6, level, optname, optval, 6937369700eSBruce M Simpson optlen) == 0) { 6947369700eSBruce M Simpson printf("ok\n"); 6957369700eSBruce M Simpson break; 6967369700eSBruce M Simpson } else { 6977369700eSBruce M Simpson warn("setsockopt %s", toptname); 6987369700eSBruce M Simpson } 6997369700eSBruce M Simpson } 7007369700eSBruce M Simpson #endif /* INET6 */ 7017369700eSBruce M Simpson /* FALLTHROUGH */ 7027369700eSBruce M Simpson printf("-1\n"); 7037369700eSBruce M Simpson } break; 7047369700eSBruce M Simpson 7057369700eSBruce M Simpson case 'g': { 7067369700eSBruce M Simpson sockunion_t sources[MAX_ADDRS]; 7077369700eSBruce M Simpson char addrbuf[NI_MAXHOST]; 7087369700eSBruce M Simpson int nreqsrc, nsrc; 7097369700eSBruce M Simpson 7107369700eSBruce M Simpson if ((sscanf(line, "%s %s %d", str1, str2, &nreqsrc)) != 3) { 7117369700eSBruce M Simpson printf("-1\n"); 7127369700eSBruce M Simpson break; 7137369700eSBruce M Simpson } 7147369700eSBruce M Simpson ifindex = parse_cmd_args(&su, NULL, str1, str2, NULL); 7157369700eSBruce M Simpson if (ifindex == 0 || (n < 0 || n > MAX_ADDRS)) { 7167369700eSBruce M Simpson printf("-1\n"); 7177369700eSBruce M Simpson break; 7187369700eSBruce M Simpson } 7197369700eSBruce M Simpson 7207369700eSBruce M Simpson af = su.sa.sa_family; 7210b6d7bb4SJohn Baldwin if (af2sock(af, s, s6) == -1) { 7220b6d7bb4SJohn Baldwin warnc(EPROTONOSUPPORT, "getsourcefilter"); 7230b6d7bb4SJohn Baldwin break; 7240b6d7bb4SJohn Baldwin } 7257369700eSBruce M Simpson nsrc = nreqsrc; 7267369700eSBruce M Simpson if (getsourcefilter(af2sock(af, s, s6), ifindex, &su.sa, 7277369700eSBruce M Simpson su.sa.sa_len, &fmode, &nsrc, &sources[0].ss) != 0) { 7287369700eSBruce M Simpson warn("getsourcefilter"); 7297369700eSBruce M Simpson printf("-1\n"); 7307369700eSBruce M Simpson break; 7317369700eSBruce M Simpson } 7327369700eSBruce M Simpson printf("%s\n", (fmode == MCAST_INCLUDE) ? "include" : 7337369700eSBruce M Simpson "exclude"); 7347369700eSBruce M Simpson printf("%d\n", nsrc); 7357369700eSBruce M Simpson 7367369700eSBruce M Simpson nsrc = MIN(nreqsrc, nsrc); 7377369700eSBruce M Simpson fprintf(stderr, "hexdump of sources:\n"); 7387369700eSBruce M Simpson uint8_t *bp = (uint8_t *)&sources[0]; 7397369700eSBruce M Simpson for (i = 0; i < (nsrc * sizeof(sources[0])); i++) { 7407369700eSBruce M Simpson fprintf(stderr, "%02x", bp[i]); 7417369700eSBruce M Simpson } 7427369700eSBruce M Simpson fprintf(stderr, "\nend hexdump\n"); 7437369700eSBruce M Simpson 7447369700eSBruce M Simpson qsort(sources, nsrc, af2socklen(af), su_cmp); 7457369700eSBruce M Simpson for (i = 0; i < nsrc; i++) { 7467369700eSBruce M Simpson sockunion_t *psu = (sockunion_t *)&sources[i]; 7477369700eSBruce M Simpson addrbuf[0] = '\0'; 7487369700eSBruce M Simpson error = getnameinfo(&psu->sa, psu->sa.sa_len, 7497369700eSBruce M Simpson addrbuf, sizeof(addrbuf), NULL, 0, 7507369700eSBruce M Simpson NI_NUMERICHOST); 7517369700eSBruce M Simpson if (error) 7527369700eSBruce M Simpson warnx("getnameinfo: %s", gai_strerror(error)); 7537369700eSBruce M Simpson else 7547369700eSBruce M Simpson printf("%s\n", addrbuf); 7557369700eSBruce M Simpson } 7567369700eSBruce M Simpson printf("ok\n"); 7577369700eSBruce M Simpson } break; 7587369700eSBruce M Simpson 7597369700eSBruce M Simpson /* link-layer stuff follows. */ 760fc3cc3f5SBill Fenner 761fc3cc3f5SBill Fenner case 'a': 762a93c2382SBruce M Simpson case 'd': { 7634a71a2e7SJulian Elischer struct sockaddr_dl *dlp; 764a93c2382SBruce M Simpson struct ether_addr *ep; 765fc3cc3f5SBill Fenner 766a93c2382SBruce M Simpson memset(&ifr, 0, sizeof(struct ifreq)); 7674a71a2e7SJulian Elischer dlp = (struct sockaddr_dl *)&ifr.ifr_addr; 7684a71a2e7SJulian Elischer dlp->sdl_len = sizeof(struct sockaddr_dl); 7694a71a2e7SJulian Elischer dlp->sdl_family = AF_LINK; 7704a71a2e7SJulian Elischer dlp->sdl_index = 0; 7714a71a2e7SJulian Elischer dlp->sdl_nlen = 0; 772a93c2382SBruce M Simpson dlp->sdl_alen = ETHER_ADDR_LEN; 7734a71a2e7SJulian Elischer dlp->sdl_slen = 0; 774a93c2382SBruce M Simpson if (sscanf(line, "%s %s", str1, str2) != 2) { 775a93c2382SBruce M Simpson warnc(EINVAL, "sscanf"); 776a93c2382SBruce M Simpson break; 777a93c2382SBruce M Simpson } 778a93c2382SBruce M Simpson ep = ether_aton(str2); 779a93c2382SBruce M Simpson if (ep == NULL) { 780a93c2382SBruce M Simpson warnc(EINVAL, "ether_aton"); 781a93c2382SBruce M Simpson break; 782a93c2382SBruce M Simpson } 783a93c2382SBruce M Simpson strlcpy(ifr.ifr_name, str1, IF_NAMESIZE); 784a93c2382SBruce M Simpson memcpy(LLADDR(dlp), ep, ETHER_ADDR_LEN); 785a93c2382SBruce M Simpson if (ioctl(s, (*cmd == 'a') ? SIOCADDMULTI : SIOCDELMULTI, 7867369700eSBruce M Simpson &ifr) == -1) { 787a93c2382SBruce M Simpson warn("ioctl SIOCADDMULTI/SIOCDELMULTI"); 7887369700eSBruce M Simpson printf("-1\n"); 7897369700eSBruce M Simpson } else 790a93c2382SBruce M Simpson printf("ok\n"); 791fc3cc3f5SBill Fenner break; 792fc3cc3f5SBill Fenner } 793fc3cc3f5SBill Fenner 794fc3cc3f5SBill Fenner case 'm': 7957369700eSBruce M Simpson fprintf(stderr, 7967369700eSBruce M Simpson "warning: IFF_ALLMULTI cannot be set from userland " 797a93c2382SBruce M Simpson "in FreeBSD; command ignored.\n"); 7987369700eSBruce M Simpson printf("-1\n"); 799fc3cc3f5SBill Fenner break; 8004ab13459SBruce M Simpson 801fc3cc3f5SBill Fenner case 'p': 802a93c2382SBruce M Simpson if (sscanf(line, "%s %u", ifr.ifr_name, &f) != 2) { 803a93c2382SBruce M Simpson printf("-1\n"); 804fc3cc3f5SBill Fenner break; 805fc3cc3f5SBill Fenner } 806a93c2382SBruce M Simpson if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1) { 807a93c2382SBruce M Simpson warn("ioctl SIOCGIFFLAGS"); 808fc3cc3f5SBill Fenner break; 809fc3cc3f5SBill Fenner } 810a93c2382SBruce M Simpson flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); 811a93c2382SBruce M Simpson if (f == 0) { 8127369700eSBruce M Simpson flags &= ~IFF_PPROMISC; 813a93c2382SBruce M Simpson } else { 8147369700eSBruce M Simpson flags |= IFF_PPROMISC; 815a93c2382SBruce M Simpson } 816a93c2382SBruce M Simpson ifr.ifr_flags = flags & 0xffff; 817a93c2382SBruce M Simpson ifr.ifr_flagshigh = flags >> 16; 818a93c2382SBruce M Simpson if (ioctl(s, SIOCSIFFLAGS, &ifr) == -1) 819a93c2382SBruce M Simpson warn("ioctl SIOCGIFFLAGS"); 820a93c2382SBruce M Simpson else 821a93c2382SBruce M Simpson printf( "changed to 0x%08x\n", flags ); 822a93c2382SBruce M Simpson break; 823a93c2382SBruce M Simpson 824a93c2382SBruce M Simpson case '\n': 825a93c2382SBruce M Simpson break; 826fc3cc3f5SBill Fenner default: 827a93c2382SBruce M Simpson printf("invalid command\n"); 828fc3cc3f5SBill Fenner break; 829fc3cc3f5SBill Fenner } 830fc3cc3f5SBill Fenner } 831a93c2382SBruce M Simpson 832a93c2382SBruce M Simpson static void 833a93c2382SBruce M Simpson usage(void) 834a93c2382SBruce M Simpson { 835a93c2382SBruce M Simpson 8367369700eSBruce M Simpson printf("j mcast-addr ifname [src-addr] - join IP multicast group\n"); 8377369700eSBruce M Simpson printf("l mcast-addr ifname [src-addr] - leave IP multicast group\n"); 8387369700eSBruce M Simpson printf( 8397369700eSBruce M Simpson "i mcast-addr ifname n - set n include mode src filter\n"); 8407369700eSBruce M Simpson printf( 8417369700eSBruce M Simpson "e mcast-addr ifname n - set n exclude mode src filter\n"); 8427369700eSBruce M Simpson printf("t mcast-addr ifname src-addr - allow traffic from src\n"); 8437369700eSBruce M Simpson printf("b mcast-addr ifname src-addr - block traffic from src\n"); 8447369700eSBruce M Simpson printf("g mcast-addr ifname n - get and show n src filters\n"); 8457369700eSBruce M Simpson printf("a ifname mac-addr - add link multicast filter\n"); 8467369700eSBruce M Simpson printf("d ifname mac-addr - delete link multicast filter\n"); 847a93c2382SBruce M Simpson printf("m ifname 1/0 - set/clear ether allmulti flag\n"); 848a93c2382SBruce M Simpson printf("p ifname 1/0 - set/clear ether promisc flag\n"); 849a93c2382SBruce M Simpson printf("f filename - read command(s) from file\n"); 850a93c2382SBruce M Simpson printf("s seconds - sleep for some time\n"); 851a93c2382SBruce M Simpson printf("q - quit\n"); 852fc3cc3f5SBill Fenner } 8537369700eSBruce M Simpson 854