summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbms <bms@FreeBSD.org>2007-03-08 18:56:37 +0000
committerbms <bms@FreeBSD.org>2007-03-08 18:56:37 +0000
commite76d938902ab30bec1ac2cae255877bdb5729696 (patch)
tree7e55765bc004ec3d490003538bfc2a8e591641b9
parentb7ddf066c4a1485b34113395c36c8baa183328e8 (diff)
downloadFreeBSD-src-e76d938902ab30bec1ac2cae255877bdb5729696.zip
FreeBSD-src-e76d938902ab30bec1ac2cae255877bdb5729696.tar.gz
Merge a slightly cleaner and SSM capable mtest(8).
Submitted by: Wilbert De Graaf MFC after: 1 month
-rw-r--r--usr.sbin/mtest/Makefile1
-rw-r--r--usr.sbin/mtest/mtest.871
-rw-r--r--usr.sbin/mtest/mtest.c575
3 files changed, 445 insertions, 202 deletions
diff --git a/usr.sbin/mtest/Makefile b/usr.sbin/mtest/Makefile
index 95bbe12..142de06 100644
--- a/usr.sbin/mtest/Makefile
+++ b/usr.sbin/mtest/Makefile
@@ -2,5 +2,6 @@
PROG= mtest
MAN= mtest.8
+WARNS?= 6
.include <bsd.prog.mk>
diff --git a/usr.sbin/mtest/mtest.8 b/usr.sbin/mtest/mtest.8
index 4b1f299..8bc6f33 100644
--- a/usr.sbin/mtest/mtest.8
+++ b/usr.sbin/mtest/mtest.8
@@ -2,7 +2,7 @@
.\" $FreeBSD$
.\"
.\" The following requests are required for all man pages.
-.Dd December 15, 1996
+.Dd March 8, 2007
.Os
.Dt MTEST 8
.Sh NAME
@@ -46,13 +46,74 @@ Set or reset ALLMULTI mode on interface
.It Ic p Ar ifname Ar 1/0
Set or reset promiscuous mode on interface
.Ar ifname .
+.\"
+.It Ic i Ar g.g.g.g Ar i.i.i.i Ar n Ar x.x.x.x ...
+Set the socket with group membership of
+.Ar g.g.g.g
+on IPv4 address
+.Ar i.i.i.i
+to include filter mode, and add
+.Ar n
+sources beginning with
+.Ar x.x.x.x
+to the inclusion filter list.
+.\"
+.It Ic e Ar g.g.g.g Ar i.i.i.i Ar n Ar x.x.x.x ...
+Set the socket with group membership of
+.Ar g.g.g.g
+on IPv4 address
+.Ar i.i.i.i
+to exclude filter mode, and add
+.Ar n
+sources beginning with
+.Ar x.x.x.x
+to the exclusion filter list.
+.\"
+.It Ic t Ar g.g.g.g Ar i.i.i.i Ar s.s.s.s
+Set the socket with group membership of
+.Ar g.g.g.g
+on IPv4 address
+.Ar i.i.i.i
+to block traffic from source
+.Ar s.s.s.s .
+.\"
+.It Ic b Ar g.g.g.g Ar i.i.i.i Ar s.s.s.s
+Set the socket with group membership of
+.Ar g.g.g.g
+on IPv4 address
+.Ar i.i.i.i
+to allow traffic from source
+.Ar s.s.s.s .
+.\"
+.It Ic g Ar g.g.g.g Ar i.i.i.i Ar n
+Print
+.Ar n
+source filter entries for group
+.An g.g.g.g
+on IPv4 address
+.An i.i.i.i .
+.\"
+.It Ic f Ar filename
+Read commands from the file
+.Ar filename .
+.It Ic s Ar n
+Sleep for
+.Ar n
+seconds.
.It Ic ?\&
List legal commands.
.It Ic q
Quit the program.
.El
-.\" .Sh SEE ALSO
+.Sh SEE ALSO
+.Rs
+.%A D. Thaler
+.%A B. Fenner
+.%A B. Quinn
+.%T "Socket Interface Extensions for Multicast Filters"
+.%O RFC 3678
+.Re
.Sh AUTHORS
-.An Steve Deering
-.Sh BUGS
-The command parser is not very flexible.
+.An -split
+.An "Steve Deering"
+.An "Wilbert De Graaf"
diff --git a/usr.sbin/mtest/mtest.c b/usr.sbin/mtest/mtest.c
index b0ccef1..747a1f3 100644
--- a/usr.sbin/mtest/mtest.c
+++ b/usr.sbin/mtest/mtest.c
@@ -1,228 +1,409 @@
-/*
- * Program to test new [sg]etsockopts and ioctls for manipulating IP and
- * Ethernet multicast address filters.
+/*-
+ * Copyright (c) 2007 Bruce M. Simpson.
+ * Copyright (c) 2000 Wilbert De Graaf.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
*
- * Written by Steve Deering, Stanford University, February 1989.
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Diagnostic and test utility for IPv4 multicast sockets.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
#include <sys/types.h>
+#include <sys/errno.h>
#include <sys/socket.h>
#include <sys/time.h>
+#include <sys/ioctl.h>
+
#include <net/if.h>
#include <net/if_dl.h>
-#include <sys/ioctl.h>
+#include <net/ethernet.h>
#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <err.h>
+#include <unistd.h>
+
+static void process_file(char *, int);
+static void process_cmd(char*, int, FILE *fp);
+static void usage(void);
+#ifdef WITH_IGMPV3
+static int inaddr_cmp(const void *a, const void *b);
+#endif
+
+#define MAX_ADDRS 20
+#define STR_SIZE 20
+#define LINE_LENGTH 80
+
int
-main( argc, argv )
- int argc;
- char **argv;
- {
- int so;
- char line[80];
- char *lineptr;
- struct ip_mreq imr;
- struct ifreq ifr;
- int n, f;
- unsigned i1, i2, i3, i4, g1, g2, g3, g4;
- unsigned e1, e2, e3, e4, e5, e6;
-
- if( (so = socket( AF_INET, SOCK_DGRAM, 0 )) == -1)
- err( 1, "can't open socket" );
-
- printf( "multicast membership test program; " );
- printf( "enter ? for list of commands\n" );
-
- while( fgets( line, sizeof(line) - 1, stdin ) != NULL )
- {
- lineptr = line;
- while( *lineptr == ' ' || *lineptr == '\t' ) ++lineptr;
- switch( *lineptr )
- {
- case '?':
- {
- printf( "%s%s%s%s%s%s%s",
- " j g.g.g.g i.i.i.i - join IP multicast group \n",
- " l g.g.g.g i.i.i.i - leave IP multicast group \n",
- " a ifname e.e.e.e.e.e - add ether multicast address \n",
- " d ifname e.e.e.e.e.e - del ether multicast address \n",
- " m ifname 1/0 - set/clear ether allmulti flag \n",
- " p ifname 1/0 - set/clear ether promisc flag \n",
- " q - quit \n\n" );
+main(int argc, char **argv)
+{
+ char line[LINE_LENGTH];
+ char *p;
+ int i, s;
+
+ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (s == -1)
+ err(1, "can't open socket");
+
+ if (argc < 2) {
+ if (isatty(STDIN_FILENO)) {
+ printf("multicast membership test program; "
+ "enter ? for list of commands\n");
+ }
+ do {
+ if (fgets(line, sizeof(line), stdin) != NULL) {
+ if (line[0] != 'f')
+ process_cmd(line, s, stdin);
+ else {
+ /* Get the filename */
+ for (i = 1; isblank(line[i]); i++);
+ if ((p = (char*)strchr(line, '\n'))
+ != NULL)
+ *p = '\0';
+ process_file(&line[i], s);
+ }
+ }
+ } while (!feof(stdin));
+ } else {
+ for (i = 1; i < argc; i++) {
+ process_file(argv[i], s);
+ }
+ }
+
+ exit (0);
+}
+
+static void
+process_file(char *fname, int s)
+{
+ char line[80];
+ FILE *fp;
+ char *lineptr;
+
+ fp = fopen(fname, "r");
+ if (fp == NULL) {
+ warn("fopen");
+ return;
+ }
+
+ /* Skip comments and empty lines. */
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ lineptr = line;
+ while (isblank(*lineptr))
+ lineptr++;
+ if (*lineptr != '#' && *lineptr != '\n')
+ process_cmd(lineptr, s, fp);
+ }
+
+ fclose(fp);
+}
+
+static void
+process_cmd(char *cmd, int s, FILE *fp __unused)
+{
+ char str1[STR_SIZE];
+ char str2[STR_SIZE];
+#ifdef WITH_IGMPV3
+ char str3[STR_SIZE];
+ char filtbuf[IP_MSFILTER_SIZE(MAX_ADDRS)];
+#endif
+ struct ifreq ifr;
+ struct ip_mreq imr;
+#ifdef WITH_IGMPV3
+ struct ip_mreq_source imrs;
+ struct ip_msfilter *imsfp;
+#endif
+ char *line;
+ int n, opt, f, flags;
+
+ line = cmd;
+ while (isblank(*++line))
+ ; /* Skip whitespace. */
+
+ switch (*cmd) {
+ case '?':
+ usage();
break;
- }
-
- case 'j':
- {
- ++lineptr;
- while( *lineptr == ' ' || *lineptr == '\t' ) ++lineptr;
- if( (n = sscanf( lineptr, "%u.%u.%u.%u %u.%u.%u.%u",
- &g1, &g2, &g3, &g4, &i1, &i2, &i3, &i4 )) != 8 )
- {
- printf( "bad args\n" );
- break;
- }
- imr.imr_multiaddr.s_addr = (g1<<24) | (g2<<16) | (g3<<8) | g4;
- imr.imr_multiaddr.s_addr = htonl(imr.imr_multiaddr.s_addr);
- imr.imr_interface.s_addr = (i1<<24) | (i2<<16) | (i3<<8) | i4;
- imr.imr_interface.s_addr = htonl(imr.imr_interface.s_addr);
- if( setsockopt( so, IPPROTO_IP, IP_ADD_MEMBERSHIP,
- &imr, sizeof(struct ip_mreq) ) == -1 )
- warn( "can't join group" );
- else printf( "group joined\n" );
+
+ case 'q':
+ close(s);
+ exit(0);
+
+ case 's':
+ if ((sscanf(line, "%d", &n) != 1) || (n < 1)) {
+ printf("-1\n");
+ break;
+ }
+ sleep(n);
+ printf("ok\n");
break;
- }
-
- case 'l':
- {
- ++lineptr;
- while( *lineptr == ' ' || *lineptr == '\t' ) ++lineptr;
- if( (n = sscanf( lineptr, "%u.%u.%u.%u %u.%u.%u.%u",
- &g1, &g2, &g3, &g4, &i1, &i2, &i3, &i4 )) != 8 )
- {
- printf( "bad args\n" );
- break;
- }
- imr.imr_multiaddr.s_addr = (g1<<24) | (g2<<16) | (g3<<8) | g4;
- imr.imr_multiaddr.s_addr = htonl(imr.imr_multiaddr.s_addr);
- imr.imr_interface.s_addr = (i1<<24) | (i2<<16) | (i3<<8) | i4;
- imr.imr_interface.s_addr = htonl(imr.imr_interface.s_addr);
- if( setsockopt( so, IPPROTO_IP, IP_DROP_MEMBERSHIP,
- &imr, sizeof(struct ip_mreq) ) == -1 )
- warn( "can't leave group" );
- else printf( "group left\n" );
+
+ case 'j':
+ case 'l':
+ sscanf(line, "%s %s", str1, str2);
+ if (((imr.imr_multiaddr.s_addr = inet_addr(str1)) ==
+ INADDR_NONE) ||
+ ((imr.imr_interface.s_addr = inet_addr(str2)) ==
+ INADDR_NONE)) {
+ printf("-1\n");
+ break;
+ }
+ opt = (*cmd == 'j') ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
+ if (setsockopt( s, IPPROTO_IP, opt, &imr,
+ sizeof(imr)) != 0)
+ warn("setsockopt IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP");
+ else
+ printf("ok\n");
break;
- }
-
- case 'a':
- {
- struct sockaddr_dl *dlp;
- unsigned char *bp;
- ++lineptr;
- while( *lineptr == ' ' || *lineptr == '\t' ) ++lineptr;
- if( (n = sscanf( lineptr, "%s %x.%x.%x.%x.%x.%x",
- ifr.ifr_name, &e1, &e2, &e3, &e4, &e5, &e6 )) != 7 )
- {
- printf( "bad args\n" );
- break;
- }
+
+ case 'a':
+ case 'd': {
+ struct sockaddr_dl *dlp;
+ struct ether_addr *ep;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
dlp = (struct sockaddr_dl *)&ifr.ifr_addr;
dlp->sdl_len = sizeof(struct sockaddr_dl);
dlp->sdl_family = AF_LINK;
dlp->sdl_index = 0;
dlp->sdl_nlen = 0;
- dlp->sdl_alen = 6;
+ dlp->sdl_alen = ETHER_ADDR_LEN;
dlp->sdl_slen = 0;
- bp = LLADDR(dlp);
- bp[0] = e1;
- bp[1] = e2;
- bp[2] = e3;
- bp[3] = e4;
- bp[4] = e5;
- bp[5] = e6;
- if( ioctl( so, SIOCADDMULTI, &ifr ) == -1 )
- warn( "can't add ether address" );
- else printf( "ether address added\n" );
+ if (sscanf(line, "%s %s", str1, str2) != 2) {
+ warnc(EINVAL, "sscanf");
+ break;
+ }
+ ep = ether_aton(str2);
+ if (ep == NULL) {
+ warnc(EINVAL, "ether_aton");
+ break;
+ }
+ strlcpy(ifr.ifr_name, str1, IF_NAMESIZE);
+ memcpy(LLADDR(dlp), ep, ETHER_ADDR_LEN);
+ if (ioctl(s, (*cmd == 'a') ? SIOCADDMULTI : SIOCDELMULTI,
+ &ifr) == -1)
+ warn("ioctl SIOCADDMULTI/SIOCDELMULTI");
+ else
+ printf("ok\n");
break;
- }
-
- case 'd':
- {
- struct sockaddr_dl *dlp;
- unsigned char *bp;
- ++lineptr;
- while( *lineptr == ' ' || *lineptr == '\t' ) ++lineptr;
- if( (n = sscanf( lineptr, "%s %x.%x.%x.%x.%x.%x",
- ifr.ifr_name, &e1, &e2, &e3, &e4, &e5, &e6 )) != 7 )
- {
- printf( "bad args\n" );
- break;
- }
- dlp = (struct sockaddr_dl *)&ifr.ifr_addr;
- dlp->sdl_len = sizeof(struct sockaddr_dl);
- dlp->sdl_family = AF_LINK;
- dlp->sdl_index = 0;
- dlp->sdl_nlen = 0;
- dlp->sdl_alen = 6;
- dlp->sdl_slen = 0;
- bp = LLADDR(dlp);
- bp[0] = e1;
- bp[1] = e2;
- bp[2] = e3;
- bp[3] = e4;
- bp[4] = e5;
- bp[5] = e6;
- if( ioctl( so, SIOCDELMULTI, &ifr ) == -1 )
- warn( "can't delete ether address" );
- else printf( "ether address deleted\n" );
+ }
+
+ case 'm':
+ printf("warning: IFF_ALLMULTI cannot be set from userland "
+ "in FreeBSD; command ignored.\n");
break;
- }
-
- case 'm':
- {
- ++lineptr;
- while( *lineptr == ' ' || *lineptr == '\t' ) ++lineptr;
- if( (n = sscanf( lineptr, "%s %u", ifr.ifr_name, &f )) != 2 )
- {
- printf( "bad args\n" );
- break;
- }
- if( ioctl( so, SIOCGIFFLAGS, &ifr ) == -1 )
- {
- warn( "can't get interface flags" );
- break;
- }
- printf( "interface flags %x, ", ifr.ifr_flags );
- fflush( stdout );
- if( f ) ifr.ifr_flags |= IFF_ALLMULTI;
- else ifr.ifr_flags &= ~IFF_ALLMULTI;
- if( ioctl( so, SIOCSIFFLAGS, &ifr ) == -1 )
- warn( "can't set" );
- else printf( "changed to %x\n", ifr.ifr_flags );
+ case 'p':
+ if (sscanf(line, "%s %u", ifr.ifr_name, &f) != 2) {
+ printf("-1\n");
+ break;
+ }
+ if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1) {
+ warn("ioctl SIOCGIFFLAGS");
+ break;
+ }
+ flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
+ opt = IFF_PPROMISC;
+ if (f == 0) {
+ flags &= ~opt;
+ } else {
+ flags |= opt;
+ }
+ ifr.ifr_flags = flags & 0xffff;
+ ifr.ifr_flagshigh = flags >> 16;
+ if (ioctl(s, SIOCSIFFLAGS, &ifr) == -1)
+ warn("ioctl SIOCGIFFLAGS");
+ else
+ printf( "changed to 0x%08x\n", flags );
break;
- }
-
- case 'p':
- {
- ++lineptr;
- while( *lineptr == ' ' || *lineptr == '\t' ) ++lineptr;
- if( (n = sscanf( lineptr, "%s %u", ifr.ifr_name, &f )) != 2 )
- {
- printf( "bad args\n" );
- break;
- }
- if( ioctl( so, SIOCGIFFLAGS, &ifr ) == -1 )
- {
- warn( "can't get interface flags" );
- break;
- }
- printf( "interface flags %x, ", ifr.ifr_flags );
- fflush( stdout );
- if( f ) ifr.ifr_flags |= IFF_PROMISC;
- else ifr.ifr_flags &= ~IFF_PROMISC;
- if( ioctl( so, SIOCSIFFLAGS, &ifr ) == -1 )
- warn( "can't set" );
- else printf( "changed to %x\n", ifr.ifr_flags );
+
+#ifdef WITH_IGMPV3
+ /*
+ * Set the socket to include or exclude filter mode, and
+ * add some sources to the filterlist, using the full-state,
+ * or advanced api.
+ */
+ case 'i':
+ case 'e':
+ if ((sscanf(line, "%s %s %d", str1, str2, &n)) != 3) {
+ printf("-1\n");
+ break;
+ }
+ imsfp = (struct ip_msfilter *)filtbuf;
+ if (((imsfp->imsf_multiaddr.s_addr = inet_addr(str1)) ==
+ INADDR_NONE) ||
+ ((imsfp->imsf_interface.s_addr = inet_addr(str2)) ==
+ INADDR_NONE) || (n > MAX_ADDRS)) {
+ printf("-1\n");
+ break;
+ }
+ imsfp->imsf_fmode = (*cmd == 'i') ? MCAST_INCLUDE :
+ MCAST_EXCLUDE;
+ imsfp->imsf_numsrc = n;
+ for (i = 0; i < n; i++) {
+ fgets(str1, sizeof(str1), fp);
+ if ((imsfp->imsf_slist[i].s_addr = inet_addr(str1)) ==
+ INADDR_NONE) {
+ printf("-1\n");
+ return;
+ }
+ }
+ if (ioctl(s, SIOCSIPMSFILTER, imsfp) != 0)
+ warn("setsockopt SIOCSIPMSFILTER");
+ else
+ printf("ok\n");
break;
- }
- case 'q': exit( 0 );
+ /*
+ * Allow or block traffic from a source, using the
+ * delta based api.
+ */
+ case 't':
+ case 'b':
+ sscanf(line, "%s %s %s", str1, str2, str3);
+ if (((imrs.imr_multiaddr.s_addr = inet_addr(str1)) ==
+ INADDR_NONE) ||
+ ((imrs.imr_interface.s_addr = inet_addr(str2)) ==
+ INADDR_NONE) ||
+ ((imrs.imr_sourceaddr.s_addr = inet_addr(str3)) ==
+ INADDR_NONE)) {
+ printf("-1\n");
+ break;
+ }
+
+ /* First determine out current filter mode. */
+ imsfp = (struct ip_msfilter *)filtbuf;
+ imsfp->imsf_multiaddr.s_addr = imrs.imr_multiaddr.s_addr;
+ imsfp->imsf_interface.s_addr = imrs.imr_interface.s_addr;
+ imsfp->imsf_numsrc = 5;
+ if (ioctl(s, SIOCSIPMSFILTER, imsfp) != 0) {
+ /* It's only okay for 't' to fail */
+ if (*cmd != 't') {
+ warn("ioctl SIOCSIPMSFILTER");
+ break;
+ } else {
+ imsfp->imsf_fmode = MCAST_INCLUDE;
+ }
+ }
+ if (imsfp->imsf_fmode == MCAST_EXCLUDE) {
+ /* Any source */
+ opt = (*cmd == 't') ? IP_UNBLOCK_SOURCE :
+ IP_BLOCK_SOURCE;
+ } else {
+ /* Controlled source */
+ opt = (*cmd == 't') ? IP_ADD_SOURCE_MEMBERSHIP :
+ IP_DROP_SOURCE_MEMBERSHIP;
+ }
+ if (setsockopt(s, IPPROTO_IP, opt, &imrs, sizeof(imrs)) == -1)
+ warn("ioctl IP_ADD_SOURCE_MEMBERSHIP/IP_DROP_SOURCE_MEMBERSHIP/IP_UNBLOCK_SOURCE/IP_BLOCK_SOURCE");
+ else
+ printf("ok\n");
+ break;
- case 0:
- case '\n': break;
+ case 'g':
+ if ((sscanf(line, "%s %s %d", str1, str2, &n)) != 3) {
+ printf("-1\n");
+ break;
+ }
+ imsfp = (struct ip_msfilter *)filtbuf;
+ if (((imsfp->imsf_multiaddr.s_addr = inet_addr(str1)) ==
+ INADDR_NONE) ||
+ ((imsfp->imsf_interface.s_addr = inet_addr(str2)) ==
+ INADDR_NONE) || (n < 0 || n > MAX_ADDRS)) {
+ printf("-1\n");
+ break;
+ }
+ imsfp->imsf_numsrc = n;
+ if (ioctl(s, SIOCSIPMSFILTER, imsfp) != 0) {
+ warn("setsockopt SIOCSIPMSFILTER");
+ break;
+ }
+ printf("%s\n", (imsfp->imsf_fmode == MCAST_INCLUDE) ?
+ "include" : "exclude");
+ printf("%d\n", imsfp->imsf_numsrc);
+ if (n >= imsfp->imsf_numsrc) {
+ n = imsfp->imsf_numsrc;
+ qsort(imsfp->imsf_slist, n, sizeof(struct in_addr),
+ &inaddr_cmp);
+ for (i = 0; i < n; i++)
+ printf("%s\n", inet_ntoa(imsfp->imsf_slist[i]));
+ }
+ break;
+#else /* !WITH_IGMPV3 */
+ case 'i':
+ case 'e':
+ case 't':
+ case 'b':
+ case 'g':
+ printf("warning: IGMPv3 is not supported by this version "
+ "of FreeBSD; command ignored.\n");
+ break;
+#endif /* WITH_IGMPV3 */
- default:
- {
- printf( "bad command\n" );
+ case '\n':
+ break;
+ default:
+ printf("invalid command\n");
break;
- }
- }
- }
- return(0);
- }
+ }
+}
+
+static void
+usage(void)
+{
+
+ printf("j g.g.g.g i.i.i.i - join IP multicast group\n");
+ printf("l g.g.g.g i.i.i.i - leave IP multicast group\n");
+ printf("a ifname e.e.e.e.e.e - add ether multicast address\n");
+ printf("d ifname e.e.e.e.e.e - delete ether multicast address\n");
+ printf("m ifname 1/0 - set/clear ether allmulti flag\n");
+ printf("p ifname 1/0 - set/clear ether promisc flag\n");
+ printf("i g.g.g.g i.i.i.i n - set n include mode src filter\n");
+ printf("e g.g.g.g i.i.i.i n - set n exclude mode src filter\n");
+ printf("t g.g.g.g i.i.i.i s.s.s.s - allow traffic from src\n");
+ printf("b g.g.g.g i.i.i.i s.s.s.s - block traffic from src\n");
+ printf("g g.g.g.g i.i.i.i n - get and show n src filters\n");
+ printf("f filename - read command(s) from file\n");
+ printf("s seconds - sleep for some time\n");
+ printf("q - quit\n");
+}
+
+#ifdef WITH_IGMPV3
+static int
+inaddr_cmp(const void *a, const void *b)
+{
+ return((int)((const struct in_addr *)a)->s_addr -
+ ((const struct in_addr *)b)->s_addr);
+}
+#endif
OpenPOWER on IntegriCloud