Fix mld6query(8) and add a new -g option

The mld6query command relies on KAME behaviour which allows the
ipv6mr_multiaddr member of the request object in a IPV6_JOIN_GROUP
setsockopt() call to be INADDR6_ANY. The FreeBSD stack doesn't allow
this, so mld6query has been non-functional.

Also, add a -g option which sends a General Query (query INADDR6_ANY)

Reviewed by:	sbruno, mmacy
Sponsored by:	Limelight Networks
Differential Revision:	https://reviews.freebsd.org/D15384
This commit is contained in:
Stephen Hurd 2018-05-11 19:37:18 +00:00
parent 8dcbd0eae6
commit 71cf0564f8
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=333501
2 changed files with 35 additions and 15 deletions

View file

@ -85,7 +85,7 @@ int s;
#define QUERY_RESPONSE_INTERVAL 10000
void make_msg(int index, struct in6_addr *addr, u_int type);
void make_msg(int index, struct in6_addr *addr, u_int type, struct in6_addr *qaddr);
void usage(void);
void dump(int);
void quit(int);
@ -100,14 +100,26 @@ main(int argc, char *argv[])
struct itimerval itimer;
u_int type;
int ch;
struct in6_addr *qaddr = &maddr;
type = MLD_LISTENER_QUERY;
while ((ch = getopt(argc, argv, "dr")) != -1) {
while ((ch = getopt(argc, argv, "dgr")) != -1) {
switch (ch) {
case 'd':
if (type != MLD_LISTENER_QUERY) {
printf("Can not specifiy -d with -r\n");
return 1;
}
type = MLD_LISTENER_DONE;
break;
case 'g':
qaddr = &any;
break;
case 'r':
if (type != MLD_LISTENER_QUERY) {
printf("Can not specifiy -r with -d\n");
return 1;
}
type = MLD_LISTENER_REPORT;
break;
default:
@ -127,6 +139,10 @@ main(int argc, char *argv[])
usage();
if (argc == 2 && inet_pton(AF_INET6, argv[1], &maddr) != 1)
usage();
if (type != MLD_LISTENER_QUERY && qaddr != &maddr) {
printf("Can not specifiy -g with -d or -r\n");
return 1;
}
if ((s = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
err(1, "socket");
@ -135,7 +151,12 @@ main(int argc, char *argv[])
sizeof(hlim)) == -1)
err(1, "setsockopt(IPV6_MULTICAST_HOPS)");
mreq.ipv6mr_multiaddr = any;
if (IN6_IS_ADDR_UNSPECIFIED(&maddr)) {
if (inet_pton(AF_INET6, "ff02::1", &maddr) != 1)
errx(1, "inet_pton failed");
}
mreq.ipv6mr_multiaddr = maddr;
mreq.ipv6mr_interface = ifindex;
if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq,
sizeof(mreq)) == -1)
@ -149,7 +170,7 @@ main(int argc, char *argv[])
sizeof(filt)) < 0)
err(1, "setsockopt(ICMP6_FILTER)");
make_msg(ifindex, &maddr, type);
make_msg(ifindex, &maddr, type, qaddr);
if (sendmsg(s, &m, 0) < 0)
err(1, "sendmsg");
@ -177,7 +198,7 @@ main(int argc, char *argv[])
}
void
make_msg(int index, struct in6_addr *addr, u_int type)
make_msg(int index, struct in6_addr *addr, u_int type, struct in6_addr *qaddr)
{
static struct iovec iov[2];
static u_char *cmsgbuf;
@ -196,12 +217,7 @@ make_msg(int index, struct in6_addr *addr, u_int type)
dst.sin6_len = sizeof(dst);
dst.sin6_family = AF_INET6;
if (IN6_IS_ADDR_UNSPECIFIED(addr)) {
if (inet_pton(AF_INET6, "ff02::1", &dst.sin6_addr) != 1)
errx(1, "inet_pton failed");
}
else
dst.sin6_addr = *addr;
dst.sin6_addr = *addr;
m.msg_name = (caddr_t)&dst;
m.msg_namelen = dst.sin6_len;
iov[0].iov_base = (caddr_t)&mldh;
@ -212,7 +228,7 @@ make_msg(int index, struct in6_addr *addr, u_int type)
bzero(&mldh, sizeof(mldh));
mldh.mld_type = type & 0xff;
mldh.mld_maxdelay = htons(QUERY_RESPONSE_INTERVAL);
mldh.mld_addr = *addr;
mldh.mld_addr = *qaddr;
/* MLD packet should be advertised from linklocal address */
getifaddrs(&ifa);
@ -337,7 +353,7 @@ dump(int s)
void
quit(int signum __unused)
{
mreq.ipv6mr_multiaddr = any;
mreq.ipv6mr_multiaddr = maddr;
mreq.ipv6mr_interface = ifindex;
if (setsockopt(s, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq,
sizeof(mreq)) == -1)
@ -349,6 +365,6 @@ quit(int signum __unused)
void
usage(void)
{
(void)fprintf(stderr, "usage: mld6query ifname [addr]\n");
(void)fprintf(stderr, "usage: mld6query [-dgr] ifname [addr]\n");
exit(1);
}

View file

@ -39,7 +39,7 @@
.\"
.Sh SYNOPSIS
.Nm
.Op Fl dr
.Op Fl dgr
.Ar intface
.Op Ar maddr
.\"
@ -66,6 +66,10 @@ This program is provided only for debugging.
It is not necessary for normal use.
.Pp
With
.Fl g ,
.Nm
will transmit a General Query instead of the default Multicast-Address-Specific Query.
With
.Fl d ,
.Nm
will transmit MLD done packet instead of MLD query packet.