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