diff options
Diffstat (limited to 'usr.sbin/mld6query/mld6.c')
-rw-r--r-- | usr.sbin/mld6query/mld6.c | 113 |
1 files changed, 97 insertions, 16 deletions
diff --git a/usr.sbin/mld6query/mld6.c b/usr.sbin/mld6query/mld6.c index 9b0b30ad644fc..1f73203433e41 100644 --- a/usr.sbin/mld6query/mld6.c +++ b/usr.sbin/mld6query/mld6.c @@ -1,4 +1,4 @@ -/* $KAME: mld6.c,v 1.11 2001/05/13 15:45:07 suz Exp $ */ +/* $KAME: mld6.c,v 1.15 2003/04/02 11:29:54 suz Exp $ */ /* $FreeBSD$ */ /* @@ -34,6 +34,7 @@ #include <sys/socket.h> #include <sys/types.h> #include <sys/time.h> +#include <ifaddrs.h> #include <unistd.h> #include <signal.h> @@ -51,9 +52,28 @@ #include <string.h> #include <err.h> +/* portability with older KAME headers */ +#ifndef MLD_LISTENER_QUERY +#define MLD_LISTENER_QUERY MLD6_LISTENER_QUERY +#define MLD_LISTENER_REPORT MLD6_LISTENER_REPORT +#define MLD_LISTENER_DONE MLD6_LISTENER_DONE +#define MLD_MTRACE_RESP MLD6_MTRACE_RESP +#define MLD_MTRACE MLD6_MTRACE +#define mld_hdr mld6_hdr +#define mld_type mld6_type +#define mld_code mld6_code +#define mld_cksum mld6_cksum +#define mld_maxdelay mld6_maxdelay +#define mld_reserved mld6_reserved +#define mld_addr mld6_addr +#endif +#ifndef IP6OPT_ROUTER_ALERT +#define IP6OPT_ROUTER_ALERT IP6OPT_RTALERT +#endif + struct msghdr m; struct sockaddr_in6 dst; -struct mld6_hdr mldh; +struct mld_hdr mldh; struct in6_addr maddr = IN6ADDR_ANY_INIT, any = IN6ADDR_ANY_INIT; struct ipv6_mreq mreq; u_short ifindex; @@ -77,14 +97,14 @@ main(int argc, char *argv[]) u_int type; int ch; - type = MLD6_LISTENER_QUERY; + type = MLD_LISTENER_QUERY; while ((ch = getopt(argc, argv, "dr")) != -1) { switch (ch) { case 'd': - type = MLD6_LISTENER_DONE; + type = MLD_LISTENER_DONE; break; case 'r': - type = MLD6_LISTENER_REPORT; + type = MLD_LISTENER_REPORT; break; default: usage(); @@ -139,6 +159,8 @@ main(int argc, char *argv[]) (void)setitimer(ITIMER_REAL, &itimer, NULL); FD_ZERO(&fdset); + if (s >= FD_SETSIZE) + errx(1, "descriptor too big"); for (;;) { FD_SET(s, &fdset); if ((i = select(s + 1, &fdset, NULL, NULL, NULL)) < 0) @@ -156,10 +178,17 @@ make_msg(int index, struct in6_addr *addr, u_int type) static struct iovec iov[2]; static u_char *cmsgbuf; int cmsglen, hbhlen = 0; +#ifdef USE_RFC2292BIS + void *hbhbuf = NULL, *optp = NULL; + int currentlen; +#else u_int8_t raopt[IP6OPT_RTALERT_LEN]; +#endif struct in6_pktinfo *pi; struct cmsghdr *cmsgp; u_short rtalert_code = htons(IP6OPT_RTALERT_MLD); + struct ifaddrs *ifa, *ifap; + struct in6_addr src; dst.sin6_len = sizeof(dst); dst.sin6_family = AF_INET6; @@ -177,13 +206,47 @@ make_msg(int index, struct in6_addr *addr, u_int type) m.msg_iovlen = 1; bzero(&mldh, sizeof(mldh)); - mldh.mld6_type = type & 0xff; - mldh.mld6_maxdelay = htons(QUERY_RESPONSE_INTERVAL); - mldh.mld6_addr = *addr; + mldh.mld_type = type & 0xff; + mldh.mld_maxdelay = htons(QUERY_RESPONSE_INTERVAL); + mldh.mld_addr = *addr; + + /* MLD packet should be advertised from linklocal address */ + getifaddrs(&ifa); + for (ifap = ifa; ifap; ifap = ifap->ifa_next) { + if (index != if_nametoindex(ifap->ifa_name)) + continue; + if (ifap->ifa_addr->sa_family != AF_INET6) + continue; + if (!IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *) + ifap->ifa_addr)->sin6_addr)) + continue; + break; + } + if (ifap == NULL) + errx(1, "no linkocal address is available"); + memcpy(&src, &((struct sockaddr_in6 *)ifap->ifa_addr)->sin6_addr, + sizeof(src)); + freeifaddrs(ifa); +#ifdef __KAME__ + /* remove embedded ifindex */ + src.s6_addr[2] = src.s6_addr[3] = 0; +#endif + +#ifdef USE_RFC2292BIS + if ((hbhlen = inet6_opt_init(NULL, 0)) == -1) + errx(1, "inet6_opt_init(0) failed"); + if ((hbhlen = inet6_opt_append(NULL, 0, hbhlen, IP6OPT_ROUTER_ALERT, 2, + 2, NULL)) == -1) + errx(1, "inet6_opt_append(0) failed"); + if ((hbhlen = inet6_opt_finish(NULL, 0, hbhlen)) == -1) + errx(1, "inet6_opt_finish(0) failed"); + cmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(hbhlen); +#else hbhlen = sizeof(raopt); cmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + inet6_option_space(hbhlen); +#endif if ((cmsgbuf = malloc(cmsglen)) == NULL) errx(1, "can't allocate enough memory for cmsg"); @@ -196,23 +259,40 @@ make_msg(int index, struct in6_addr *addr, u_int type) cmsgp->cmsg_type = IPV6_PKTINFO; pi = (struct in6_pktinfo *)CMSG_DATA(cmsgp); pi->ipi6_ifindex = index; - memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); + memcpy(&pi->ipi6_addr, &src, sizeof(pi->ipi6_addr)); /* specifiy to insert router alert option in a hop-by-hop opt hdr. */ cmsgp = CMSG_NXTHDR(&m, cmsgp); +#ifdef USE_RFC2292BIS + cmsgp->cmsg_len = CMSG_LEN(hbhlen); + cmsgp->cmsg_level = IPPROTO_IPV6; + cmsgp->cmsg_type = IPV6_HOPOPTS; + hbhbuf = CMSG_DATA(cmsgp); + if ((currentlen = inet6_opt_init(hbhbuf, hbhlen)) == -1) + errx(1, "inet6_opt_init(len = %d) failed", hbhlen); + if ((currentlen = inet6_opt_append(hbhbuf, hbhlen, currentlen, + IP6OPT_ROUTER_ALERT, 2, + 2, &optp)) == -1) + errx(1, "inet6_opt_append(currentlen = %d, hbhlen = %d) failed", + currentlen, hbhlen); + (void)inet6_opt_set_val(optp, 0, &rtalert_code, sizeof(rtalert_code)); + if ((currentlen = inet6_opt_finish(hbhbuf, hbhlen, currentlen)) == -1) + errx(1, "inet6_opt_finish(buf) failed"); +#else /* old advanced API */ if (inet6_option_init((void *)cmsgp, &cmsgp, IPV6_HOPOPTS)) errx(1, "inet6_option_init failed\n"); - raopt[0] = IP6OPT_RTALERT; + raopt[0] = IP6OPT_ROUTER_ALERT; raopt[1] = IP6OPT_RTALERT_LEN - 2; memcpy(&raopt[2], (caddr_t)&rtalert_code, sizeof(u_short)); if (inet6_option_append(cmsgp, raopt, 4, 0)) errx(1, "inet6_option_append failed\n"); +#endif } void dump(int s) { int i; - struct mld6_hdr *mld; + struct mld_hdr *mld; u_char buf[1024]; struct sockaddr_in6 from; int from_len = sizeof(from); @@ -223,17 +303,17 @@ dump(int s) &from_len)) < 0) return; - if (i < sizeof(struct mld6_hdr)) { + if (i < sizeof(struct mld_hdr)) { printf("too short!\n"); return; } - mld = (struct mld6_hdr *)buf; + mld = (struct mld_hdr *)buf; printf("from %s, ", inet_ntop(AF_INET6, &from.sin6_addr, ntop_buf, sizeof(ntop_buf))); - switch (mld->mld6_type) { + switch (mld->mld_type) { case ICMP6_MEMBERSHIP_QUERY: printf("type=Multicast Listener Query, "); break; @@ -244,7 +324,7 @@ dump(int s) printf("type=Multicast Listener Done, "); break; } - printf("addr=%s\n", inet_ntop(AF_INET6, &mld->mld6_addr, + printf("addr=%s\n", inet_ntop(AF_INET6, &mld->mld_addr, ntop_buf, sizeof(ntop_buf))); fflush(stdout); @@ -252,7 +332,8 @@ dump(int s) /* ARGSUSED */ void -quit(int signum) { +quit(int signum) +{ mreq.ipv6mr_multiaddr = any; mreq.ipv6mr_interface = ifindex; if (setsockopt(s, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, |