we shouldn't be shipping it, pim6[sd]d is not part of our base tree
This commit is contained in:
parent
a1b3869d7e
commit
eb78c879ca
@ -1,11 +0,0 @@
|
||||
# $NetBSD: Makefile,v 1.3 2000/02/26 11:44:28 itojun Exp $
|
||||
|
||||
PROG= mtrace6
|
||||
MAN= mtrace6.8
|
||||
|
||||
BINMODE=4555
|
||||
BINOWN= root
|
||||
|
||||
CPPFLAGS+= -I${.CURDIR}/../pim6sd -DHAVE_GETIFADDRS
|
||||
|
||||
.include <bsd.prog.mk>
|
@ -1,115 +0,0 @@
|
||||
.\" $NetBSD: mtrace6.8,v 1.4 2002/02/02 01:19:48 wiz Exp $
|
||||
.\" $KAME: mtrace6.8,v 1.5 2000/12/04 07:02:27 itojun Exp $
|
||||
.\"
|
||||
.\" Copyright (C) 1999 WIDE Project.
|
||||
.\" 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.
|
||||
.\" 3. Neither the name of the project nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd September 12, 1999
|
||||
.Dt MTRACE6 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm mtrace6
|
||||
.Nd print IPv6 multicast path from a source to
|
||||
a receiver
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl d Ar destination
|
||||
.Op Fl g Ar gateway
|
||||
.Op Fl h Ar hops
|
||||
.Op Fl i Ar interface
|
||||
.Op Fl m Ar maxhops
|
||||
.Op Fl n
|
||||
.Op Fl r Ar response_addr
|
||||
.Op Fl w Ar waittime
|
||||
.Ar source
|
||||
.Ar group
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
utilizes a tracing feature implemented in multicast routers that is
|
||||
accessed via an extension to the MLD protocol. A trace query is
|
||||
passed hop-by-hop along the reverse path from the
|
||||
.Ar destination
|
||||
to the
|
||||
.Ar source ,
|
||||
collecting hop addresses, packet counts, and routing error conditions
|
||||
along the path, and then the response is returned to the requestor.
|
||||
.Sh OPTIONS
|
||||
.Bl -tag -width Ds
|
||||
.It Fl d Ar destination
|
||||
Specifies the multicast receiver that the query wants to trace.
|
||||
It is the host running
|
||||
.Nm mtrace6
|
||||
by default.
|
||||
.It Fl g Ar gateway
|
||||
Send the trace query via unicast directly to the multicast router
|
||||
.Ar gateway .
|
||||
The unicast router must be the last-hop router on the path from the
|
||||
intended source to the receiver.
|
||||
.Ar gateway
|
||||
can also be a multicast address that the last hop router joins.
|
||||
.It Fl h Ar hops
|
||||
Set
|
||||
.Ar hops
|
||||
to the IPv6 hop limit field of query packets. The default is 64.
|
||||
.It Fl i Ar interface
|
||||
Specifies the local interface (on a multi-homed host) for sending
|
||||
the trace query and as the default for the receiver and the response
|
||||
destination.
|
||||
.It Fl m Ar maxhops
|
||||
Set to
|
||||
.Ar maxhops
|
||||
to the maximum number of hops that will be traced from the receiver
|
||||
back toward the source. The default is 127 hops.
|
||||
.It Fl n
|
||||
Print hop addresses numerically rather than symbolically and numerically
|
||||
(saves a nameserver address-to-name lookup for each router found on
|
||||
the path).
|
||||
.It Fl r Ar response_addr
|
||||
Specify the host that the trace response sends to.
|
||||
By default, the response will send to the host running
|
||||
.Nm mtrace6 .
|
||||
.It Fl w Ar waittime
|
||||
Set the time to wait for a trace response to
|
||||
.Ar waittime
|
||||
seconds. The default is 3 seconds.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr mtrace 8 ,
|
||||
.Xr pim6dd 8 ,
|
||||
.Xr pim6sd 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm mtrace6
|
||||
command first appeared in WIDE/KAME IPv6 protocol stack kit.
|
||||
.Sh BUGS
|
||||
Multicast trace for IPv6 is experimental. MLD types for query and
|
||||
response, and packet format are not officially defined.
|
||||
.Pp
|
||||
.Ar waittime
|
||||
specified by the
|
||||
.Fl w
|
||||
option is currently meaningless.
|
@ -1,721 +0,0 @@
|
||||
/* $NetBSD: mtrace6.c,v 1.7 2002/03/04 01:38:32 wiz Exp $ */
|
||||
/* $KAME: mtrace6.c,v 1.16 2000/12/04 06:45:34 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1999 WIDE Project.
|
||||
* 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.
|
||||
* 3. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
|
||||
#include <net/if_var.h>
|
||||
#endif
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <netinet6/in6_var.h>
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <netdb.h>
|
||||
#include <err.h>
|
||||
#ifdef HAVE_GETIFADDRS
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
static char *gateway, *intface, *source, *group, *receiver, *destination;
|
||||
static int mldsoc, hops = 64, maxhops = 127, waittime = 3, querylen, opt_n;
|
||||
static struct sockaddr *gw_sock, *src_sock, *grp_sock, *dst_sock, *rcv_sock;
|
||||
static char *querypacket;
|
||||
static char frombuf[1024]; /* XXX: enough size? */
|
||||
|
||||
int main __P((int, char *[]));
|
||||
static char *proto_type __P((u_int));
|
||||
static char *pr_addr __P((struct sockaddr *, int));
|
||||
static void setqid __P((int, char *));
|
||||
static void mtrace_loop __P((void));
|
||||
static char *str_rflags __P((int));
|
||||
static void show_ip6_result __P((struct sockaddr_in6 *, int));
|
||||
static void show_result __P((struct sockaddr *, int));
|
||||
static void set_sockaddr __P((char *, struct addrinfo *, struct sockaddr *));
|
||||
static int is_multicast __P((struct sockaddr *));
|
||||
static char *all_routers_str __P((int));
|
||||
static int ip6_validaddr __P((char *, struct sockaddr_in6 *));
|
||||
static int get_my_sockaddr __P((int, struct sockaddr *));
|
||||
static void set_hlim __P((int, struct sockaddr *, int));
|
||||
static void set_join __P((int, char *, struct sockaddr *));
|
||||
static void set_filter __P((int, int));
|
||||
static void open_socket __P((void));
|
||||
static void make_ip6_packet __P((void));
|
||||
static void make_packet __P((void));
|
||||
static void usage __P((void));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int op;
|
||||
|
||||
/* get parameters */
|
||||
while((op = getopt(argc, argv, "d:g:h:i:m:nr:w:")) != -1) {
|
||||
switch(op) {
|
||||
case 'd':
|
||||
destination = optarg;
|
||||
break;
|
||||
case 'g':
|
||||
gateway = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
hops = atoi(optarg);
|
||||
if (hops < 0 || hops > 255) {
|
||||
warnx("query/response hops must be between 0 and 255");
|
||||
usage();
|
||||
}
|
||||
break;
|
||||
case 'i':
|
||||
intface = optarg;
|
||||
break;
|
||||
case 'm':
|
||||
maxhops = atoi(optarg);
|
||||
if (maxhops < 0 || maxhops > 255) {
|
||||
warnx("maxhops must be between 0 and 255");
|
||||
usage();
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
opt_n = 1;
|
||||
break;
|
||||
case 'r':
|
||||
receiver = optarg;
|
||||
break;
|
||||
case 'w':
|
||||
waittime = atoi(optarg);
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc < 2)
|
||||
usage();
|
||||
source = argv[0];
|
||||
group = argv[1];
|
||||
|
||||
/* examine addresses and open a socket */
|
||||
open_socket();
|
||||
|
||||
/* construct a query packet according to the specified parameters */
|
||||
make_packet();
|
||||
|
||||
mtrace_loop();
|
||||
exit(0);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
static char *
|
||||
proto_type(type)
|
||||
u_int type;
|
||||
{
|
||||
static char buf[80];
|
||||
|
||||
switch (type) {
|
||||
case PROTO_DVMRP:
|
||||
return ("DVMRP");
|
||||
case PROTO_MOSPF:
|
||||
return ("MOSPF");
|
||||
case PROTO_PIM:
|
||||
return ("PIM");
|
||||
case PROTO_CBT:
|
||||
return ("CBT");
|
||||
case PROTO_PIM_SPECIAL:
|
||||
return ("PIM/Special");
|
||||
case PROTO_PIM_STATIC:
|
||||
return ("PIM/Static");
|
||||
case PROTO_DVMRP_STATIC:
|
||||
return ("DVMRP/Static");
|
||||
case 0:
|
||||
return ("None");
|
||||
default:
|
||||
(void) sprintf(buf, "Unknown protocol code %d", type);
|
||||
return (buf);
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
pr_addr(addr, numeric)
|
||||
struct sockaddr *addr;
|
||||
int numeric;
|
||||
{
|
||||
static char buf[MAXHOSTNAMELEN];
|
||||
int flag = 0;
|
||||
|
||||
if (numeric)
|
||||
flag |= NI_NUMERICHOST;
|
||||
flag |= NI_WITHSCOPEID;
|
||||
|
||||
getnameinfo(addr, addr->sa_len, buf, sizeof(buf), NULL, 0, flag);
|
||||
|
||||
return (buf);
|
||||
}
|
||||
|
||||
static void
|
||||
setqid(family, query)
|
||||
int family;
|
||||
char *query;
|
||||
{
|
||||
struct tr6_query *q6;
|
||||
|
||||
switch(family) {
|
||||
case AF_INET6:
|
||||
q6 = (struct tr6_query *)((struct mld6_hdr *)query + 1);
|
||||
q6->tr_qid = (u_int32_t)random();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mtrace_loop()
|
||||
{
|
||||
int nsoc, fromlen, rcvcc;
|
||||
struct timeval tv, tv_wait;
|
||||
struct fd_set *fdsp;
|
||||
size_t nfdsp;
|
||||
struct sockaddr_storage from_ss;
|
||||
struct sockaddr *from_sock = (struct sockaddr *)&from_ss;
|
||||
|
||||
/* initializa random number of query ID */
|
||||
gettimeofday(&tv, 0);
|
||||
srandom(tv.tv_usec);
|
||||
|
||||
while(1) { /* XXX */
|
||||
setqid(gw_sock->sa_family, querypacket);
|
||||
|
||||
if (sendto(mldsoc, (void *)querypacket, querylen, 0, gw_sock,
|
||||
gw_sock->sa_len) < 0)
|
||||
err(1, "sendto");
|
||||
|
||||
tv_wait.tv_sec = waittime;
|
||||
tv_wait.tv_usec = 0;
|
||||
|
||||
nfdsp = howmany(mldsoc + 1, NFDBITS) * sizeof(fd_mask);
|
||||
fdsp = malloc(nfdsp);
|
||||
if (!fdsp)
|
||||
err(1, "malloc");
|
||||
memset(fdsp, 0, nfdsp);
|
||||
FD_SET(mldsoc, fdsp);
|
||||
|
||||
if ((nsoc = select(mldsoc + 1, fdsp, NULL, NULL, &tv_wait)) < 0)
|
||||
err(1, "select");
|
||||
free(fdsp);
|
||||
|
||||
if (nsoc == 0) {
|
||||
printf("Timeout\n");
|
||||
exit(0); /* XXX try again? */
|
||||
}
|
||||
|
||||
fromlen = sizeof(from_ss);
|
||||
if ((rcvcc = recvfrom(mldsoc, frombuf, sizeof(frombuf), 0,
|
||||
from_sock, &fromlen))
|
||||
< 0)
|
||||
err(1, "recvfrom");
|
||||
|
||||
show_result(from_sock, rcvcc);
|
||||
exit(0); /* XXX */
|
||||
}
|
||||
}
|
||||
|
||||
char *fwd_code[] = {"NOERR", "WRONGIF", "SPRUNE", "RPRUNE", "SCOPED", "NORT",
|
||||
"WRONGLH", "NOFWD", "RP", "RPFIF", "NOMC", "HIDDEN"};
|
||||
char *fwd_errcode[] = {"", "NOSPC", "OLD", "ADMIN"};
|
||||
|
||||
static char *
|
||||
str_rflags(flag)
|
||||
int flag;
|
||||
{
|
||||
if (0x80 & flag) { /* fatal error */
|
||||
flag &= ~0x80;
|
||||
if (flag >= sizeof(fwd_errcode) / sizeof(char *) ||
|
||||
flag == 0) {
|
||||
warnx("unknown error code(%d)", flag);
|
||||
return("UNKNOWN");
|
||||
}
|
||||
return(fwd_errcode[flag]);
|
||||
}
|
||||
|
||||
/* normal code */
|
||||
if (flag >= sizeof(fwd_code) / sizeof(char *)) {
|
||||
warnx("unknown forward code(%d)", flag);
|
||||
return("UNKNOWN");
|
||||
}
|
||||
return(fwd_code[flag]);
|
||||
}
|
||||
|
||||
static void
|
||||
show_ip6_result(from6, datalen)
|
||||
struct sockaddr_in6 *from6;
|
||||
int datalen;
|
||||
{
|
||||
struct mld6_hdr *mld6_tr_resp = (struct mld6_hdr *)frombuf;
|
||||
struct mld6_hdr *mld6_tr_query = (struct mld6_hdr *)querypacket;
|
||||
struct tr6_query *tr6_rquery = (struct tr6_query *)(mld6_tr_resp + 1);
|
||||
struct tr6_query *tr6_query = (struct tr6_query *)(mld6_tr_query + 1);
|
||||
struct tr6_resp *tr6_resp = (struct tr6_resp *)(tr6_rquery + 1),
|
||||
*rp, *rp_end;
|
||||
int i;
|
||||
|
||||
if (datalen < sizeof(*mld6_tr_resp) + sizeof(*tr6_rquery) +
|
||||
sizeof(*tr6_resp)) {
|
||||
warnx("show_ip6_result: receive data length(%d) is short",
|
||||
datalen);
|
||||
return;
|
||||
}
|
||||
|
||||
switch(mld6_tr_resp->mld6_type) {
|
||||
case MLD6_MTRACE_RESP:
|
||||
if ((datalen - sizeof(*mld6_tr_resp) - sizeof(*tr6_rquery)) %
|
||||
sizeof(*tr6_resp)) {
|
||||
warnx("show_ip6_result: incomplete response (%d bytes)",
|
||||
datalen);
|
||||
return;
|
||||
}
|
||||
rp_end = (struct tr6_resp *)((char *)mld6_tr_resp + datalen);
|
||||
|
||||
/* sanity check for the response */
|
||||
if (tr6_query->tr_qid != tr6_rquery->tr_qid ||
|
||||
!IN6_ARE_ADDR_EQUAL(&tr6_query->tr_src, &tr6_rquery->tr_src) ||
|
||||
!IN6_ARE_ADDR_EQUAL(&tr6_query->tr_dst, &tr6_rquery->tr_dst))
|
||||
return; /* XXX: bark here? */
|
||||
|
||||
for (i = 0, rp = tr6_resp; rp < rp_end; i++, rp++) {
|
||||
struct sockaddr_in6 sa_resp, sa_upstream;
|
||||
|
||||
/* reinitialize the sockaddr. paranoid? */
|
||||
memset((void *)&sa_resp, 0, sizeof(sa_resp));
|
||||
sa_resp.sin6_family = AF_INET6;
|
||||
sa_resp.sin6_len = sizeof(sa_resp);
|
||||
memset((void *)&sa_upstream, 0, sizeof(sa_upstream));
|
||||
sa_upstream.sin6_family = AF_INET6;
|
||||
sa_upstream.sin6_len = sizeof(sa_upstream);
|
||||
|
||||
sa_resp.sin6_addr = rp->tr_lcladdr;
|
||||
sa_upstream.sin6_addr = rp->tr_rmtaddr;
|
||||
|
||||
/* print information for the router */
|
||||
printf("%3d ", -i);/* index */
|
||||
/* router address and incoming/outgoing interface */
|
||||
printf("%s", pr_addr((struct sockaddr *)&sa_resp, opt_n));
|
||||
printf("(%s/%d->%d) ",
|
||||
pr_addr((struct sockaddr *)&sa_upstream, 1),
|
||||
ntohl(rp->tr_inifid), ntohl(rp->tr_outifid));
|
||||
/* multicast routing protocol type */
|
||||
printf("%s ", proto_type(rp->tr_rproto));
|
||||
/* forwarding error code */
|
||||
printf("%s", str_rflags(rp->tr_rflags & 0xff));
|
||||
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
break;
|
||||
default: /* impossible... */
|
||||
warnx("show_ip6_result: invalid ICMPv6 type(%d)",
|
||||
mld6_tr_resp->mld6_type); /* assert? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
show_result(from, datalen)
|
||||
struct sockaddr *from;
|
||||
int datalen;
|
||||
{
|
||||
switch(from->sa_family) {
|
||||
case AF_INET6:
|
||||
show_ip6_result((struct sockaddr_in6 *)from, datalen);
|
||||
break;
|
||||
default:
|
||||
errx(1, "show_result: illegal AF(%d) on recv", from->sa_family);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_sockaddr(addrname, hints, sap)
|
||||
char *addrname;
|
||||
struct addrinfo *hints;
|
||||
struct sockaddr *sap;
|
||||
{
|
||||
struct addrinfo *res;
|
||||
int ret_ga;
|
||||
|
||||
ret_ga = getaddrinfo(addrname, NULL, hints, &res);
|
||||
if (ret_ga)
|
||||
errx(1, "getaddrinfo failed: %s", gai_strerror(ret_ga));
|
||||
if (!res->ai_addr)
|
||||
errx(1, "getaddrinfo failed");
|
||||
memcpy((void *)sap, (void *)res->ai_addr, res->ai_addr->sa_len);
|
||||
|
||||
freeaddrinfo(res);
|
||||
}
|
||||
|
||||
static int
|
||||
is_multicast(sa)
|
||||
struct sockaddr *sa;
|
||||
{
|
||||
switch(sa->sa_family) {
|
||||
case AF_INET6:
|
||||
if (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)sa)->sin6_addr))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
return 0; /* XXX: support IPv4? */
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
all_routers_str(family)
|
||||
int family;
|
||||
{
|
||||
switch(family) {
|
||||
case AF_INET6:
|
||||
return("ff02::1");
|
||||
default:
|
||||
errx(1, "all_routers_str: unknown AF(%d)", family);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ip6_validaddr(ifname, addr)
|
||||
char *ifname;
|
||||
struct sockaddr_in6 *addr;
|
||||
{
|
||||
int s;
|
||||
struct in6_ifreq ifr6;
|
||||
u_int32_t flags6;
|
||||
|
||||
/* we need a global address only...XXX: should be flexible? */
|
||||
if (IN6_IS_ADDR_LOOPBACK(&addr->sin6_addr) ||
|
||||
IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr) ||
|
||||
IN6_IS_ADDR_SITELOCAL(&addr->sin6_addr))
|
||||
return(0);
|
||||
|
||||
/* get IPv6 dependent flags and examine them */
|
||||
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
|
||||
err(1, "ip6_validaddr: socket");
|
||||
|
||||
strncpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
|
||||
ifr6.ifr_addr = *addr;
|
||||
if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0)
|
||||
err(1, "ioctl(SIOCGIFAFLAG_IN6)");
|
||||
close(s);
|
||||
flags6 = ifr6.ifr_ifru.ifru_flags6;
|
||||
if (flags6 & (IN6_IFF_ANYCAST | IN6_IFF_TENTATIVE |
|
||||
IN6_IFF_DUPLICATED | IN6_IFF_DETACHED))
|
||||
return(0);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
get_my_sockaddr(family, addrp)
|
||||
int family;
|
||||
struct sockaddr *addrp;
|
||||
{
|
||||
#ifdef HAVE_GETIFADDRS
|
||||
struct ifaddrs *ifap, *ifa;
|
||||
|
||||
if (getifaddrs(&ifap) != 0) {
|
||||
err(1, "getifaddrs");
|
||||
/*NOTREACHED */
|
||||
}
|
||||
|
||||
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
|
||||
if (ifa->ifa_addr->sa_family == family) {
|
||||
switch(family) {
|
||||
case AF_INET6:
|
||||
if (ip6_validaddr(ifa->ifa_name,
|
||||
(struct sockaddr_in6 *)ifa->ifa_addr))
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(ifap);
|
||||
return (-1); /* not found */
|
||||
|
||||
found:
|
||||
memcpy((void *)addrp, (void *)ifa->ifa_addr, ifa->ifa_addr->sa_len);
|
||||
freeifaddrs(ifap);
|
||||
return (0);
|
||||
#else
|
||||
#define IF_BUFSIZE 8192 /* XXX: adhoc...should be customizable? */
|
||||
int i, s;
|
||||
struct ifconf ifconf;
|
||||
struct ifreq *ifrp;
|
||||
static char ifbuf[IF_BUFSIZE];
|
||||
|
||||
if ((s = socket(family, SOCK_DGRAM, 0)) < 0)
|
||||
err(1, "socket");
|
||||
|
||||
ifconf.ifc_buf = ifbuf;
|
||||
ifconf.ifc_len = sizeof(ifbuf);
|
||||
|
||||
if (ioctl(s, SIOCGIFCONF, (char *)&ifconf) < 0)
|
||||
err(1, "ioctl(SIOCGIFCONF)");
|
||||
close(s);
|
||||
|
||||
for (i = 0; i < ifconf.ifc_len; ) {
|
||||
ifrp = (struct ifreq *)(ifbuf + i);
|
||||
if (ifrp->ifr_addr.sa_family == family) {
|
||||
switch(family) {
|
||||
case AF_INET6:
|
||||
if (ip6_validaddr(ifrp->ifr_name,
|
||||
(struct sockaddr_in6 *)&ifrp->ifr_addr))
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
i += IFNAMSIZ;
|
||||
/* i += max(sizeof(sockaddr), ifr_addr.sa_len) */
|
||||
if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr))
|
||||
i += ifrp->ifr_addr.sa_len;
|
||||
else
|
||||
i += sizeof(struct sockaddr);
|
||||
}
|
||||
|
||||
return(-1); /* not found */
|
||||
|
||||
found:
|
||||
memcpy((void *)addrp, (void *)&ifrp->ifr_addr, ifrp->ifr_addr.sa_len);
|
||||
return(0);
|
||||
#undef IF_BUFSIZE
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
set_hlim(s, addr, hops)
|
||||
int s, hops;
|
||||
struct sockaddr *addr;
|
||||
{
|
||||
struct sockaddr_in6 *sin6;
|
||||
int opt;
|
||||
|
||||
switch(addr->sa_family) {
|
||||
case AF_INET6:
|
||||
sin6 = (struct sockaddr_in6 *)addr;
|
||||
opt = IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr) ?
|
||||
IPV6_MULTICAST_HOPS : IPV6_UNICAST_HOPS;
|
||||
if (setsockopt(s, IPPROTO_IPV6, opt, (char *)&hops,
|
||||
sizeof(hops)) == -1)
|
||||
err(1, "setsockopt(%s)",
|
||||
(opt == IPV6_MULTICAST_HOPS) ?
|
||||
"IPV6_MULTICAST_HOPS" : "IPV6_UNICAST_HOPS");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_join(s, ifname, group)
|
||||
int s;
|
||||
char *ifname;
|
||||
struct sockaddr *group;
|
||||
{
|
||||
struct ipv6_mreq mreq6;
|
||||
u_int ifindex;
|
||||
|
||||
switch(group->sa_family) {
|
||||
case AF_INET6:
|
||||
if ((ifindex = if_nametoindex(ifname)) == 0)
|
||||
err(1, "set_join: if_nametoindex failed for %s", ifname);
|
||||
mreq6.ipv6mr_multiaddr =
|
||||
((struct sockaddr_in6 *)group)->sin6_addr;
|
||||
mreq6.ipv6mr_interface = ifindex;
|
||||
|
||||
if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6,
|
||||
sizeof(mreq6)) < 0)
|
||||
err(1, "setsockopt(IPV6_JOIN_GROUP)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_filter(s, family)
|
||||
int s, family;
|
||||
{
|
||||
struct icmp6_filter filter6;
|
||||
|
||||
switch(family) {
|
||||
case AF_INET6:
|
||||
ICMP6_FILTER_SETBLOCKALL(&filter6);
|
||||
ICMP6_FILTER_SETPASS(MLD6_MTRACE_RESP, &filter6);
|
||||
if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter6,
|
||||
sizeof(filter6)) < 0)
|
||||
err(1, "setsockopt(ICMP6_FILTER)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
open_socket()
|
||||
{
|
||||
struct addrinfo hints;
|
||||
static struct sockaddr_storage gw_ss, src_ss, grp_ss, dst_ss, rcv_ss;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_INET6; /* to be independent of AF? */
|
||||
hints.ai_socktype = SOCK_RAW;
|
||||
hints.ai_protocol = IPPROTO_ICMPV6;
|
||||
|
||||
/* multicast group(must be specified) */
|
||||
grp_sock = (struct sockaddr *)&grp_ss;
|
||||
set_sockaddr(group, &hints, grp_sock);
|
||||
if (!is_multicast(grp_sock))
|
||||
errx(1, "group(%s) is not a multicast address", group);
|
||||
|
||||
/* multicast source(must be specified) */
|
||||
src_sock = (struct sockaddr *)&src_ss;
|
||||
set_sockaddr(source, &hints, src_sock);
|
||||
if (is_multicast(src_sock))
|
||||
errx(1, "source(%s) is not a unicast address", source);
|
||||
|
||||
/* last hop gateway for the destination(if specified) */
|
||||
gw_sock = (struct sockaddr *)&gw_ss;
|
||||
if (gateway) /* can be either multicast or unicast */
|
||||
set_sockaddr(gateway, &hints, gw_sock);
|
||||
else {
|
||||
char *r = all_routers_str(grp_sock->sa_family);
|
||||
|
||||
set_sockaddr(r, &hints, gw_sock);
|
||||
}
|
||||
|
||||
/* destination address for the trace */
|
||||
dst_sock = (struct sockaddr *)&dst_ss;
|
||||
if (destination) {
|
||||
set_sockaddr(destination, &hints, dst_sock);
|
||||
if (is_multicast(dst_sock))
|
||||
errx(1, "destination(%s) is not a unicast address",
|
||||
destination);
|
||||
}
|
||||
else {
|
||||
/* XXX: consider interface? */
|
||||
get_my_sockaddr(grp_sock->sa_family, dst_sock);
|
||||
}
|
||||
|
||||
/* response receiver(if specified) */
|
||||
rcv_sock = (struct sockaddr *)&rcv_ss;
|
||||
if (receiver) { /* can be either multicast or unicast */
|
||||
set_sockaddr(receiver, &hints, rcv_sock);
|
||||
if (is_multicast(rcv_sock) &&
|
||||
intface == NULL) {
|
||||
#ifdef notyet
|
||||
warnx("receive I/F is not specified for multicast"
|
||||
"response(%s)", receiver);
|
||||
intface = default_intface;
|
||||
#else
|
||||
errx(1, "receive I/F is not specified for multicast"
|
||||
"response(%s)", receiver);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* XXX: consider interface? */
|
||||
get_my_sockaddr(grp_sock->sa_family, rcv_sock);
|
||||
}
|
||||
|
||||
if ((mldsoc = socket(hints.ai_family, hints.ai_socktype,
|
||||
hints.ai_protocol)) < 0)
|
||||
err(1, "socket");
|
||||
|
||||
/* set necessary socket options */
|
||||
if (hops)
|
||||
set_hlim(mldsoc, gw_sock, hops);
|
||||
if (receiver && is_multicast(rcv_sock))
|
||||
set_join(mldsoc, intface, rcv_sock);
|
||||
set_filter(mldsoc, grp_sock->sa_family);
|
||||
}
|
||||
|
||||
static void
|
||||
make_ip6_packet()
|
||||
{
|
||||
struct mld6_hdr *mld6_tr_query;
|
||||
struct tr6_query *tr6_query;
|
||||
|
||||
querylen = sizeof(*mld6_tr_query) + sizeof(*tr6_query);
|
||||
if ((querypacket = malloc(querylen)) == NULL)
|
||||
errx(1, "make_ip6_packet: malloc failed");
|
||||
memset(querypacket, 0, querylen);
|
||||
|
||||
/* fill in MLD header */
|
||||
mld6_tr_query = (struct mld6_hdr *)querypacket;
|
||||
mld6_tr_query->mld6_type = MLD6_MTRACE;
|
||||
mld6_tr_query->mld6_code = maxhops & 0xff;
|
||||
mld6_tr_query->mld6_addr = ((struct sockaddr_in6 *)grp_sock)->sin6_addr;
|
||||
|
||||
/* fill in mtrace query fields */
|
||||
tr6_query = (struct tr6_query *)(mld6_tr_query + 1);
|
||||
tr6_query->tr_src = ((struct sockaddr_in6 *)src_sock)->sin6_addr;
|
||||
tr6_query->tr_dst = ((struct sockaddr_in6 *)dst_sock)->sin6_addr;
|
||||
tr6_query->tr_raddr = ((struct sockaddr_in6 *)rcv_sock)->sin6_addr;
|
||||
tr6_query->tr_rhlim = 0xff & hops;
|
||||
}
|
||||
|
||||
static void
|
||||
make_packet()
|
||||
{
|
||||
switch(grp_sock->sa_family) {
|
||||
case AF_INET6:
|
||||
make_ip6_packet();
|
||||
break;
|
||||
default:
|
||||
errx(1, "make_packet: unsupported AF(%d)", grp_sock->sa_family);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
usage()
|
||||
{
|
||||
fprintf(stderr, "usage: mtrace6 %s\n",
|
||||
"[-d destination] [-g gateway] [-h hops] [-i interface] "
|
||||
"[-m maxhops] [-n] [-r response_addr] [-w waittime] source group");
|
||||
exit(1);
|
||||
}
|
Loading…
Reference in New Issue
Block a user