Improve ifmcstat(8) and fix a few bugs while we're at it:
* Retire the old 'ifmcstat <kernel>' usage. * Print AF_LINK records even if run against KVM. This makes the KVM backend consistent with the sysctl backend. * Suppress printing of link-layer group records by default. * Add a -v switch to allow link-layer groups to be printed. * If compiled without INET6 support, actually work. * If compiled with INET6 support, print the scope ID of all IPv6 addresses in both backends. * Update man page. * Update copyrights. With this change, it is now reasonable to retire netstat -g. Most of the SSM related gunk in this file will require later refactoring. MFC after: 2 weeks
This commit is contained in:
parent
d1ec640bcf
commit
d508ff40b9
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=188645
@ -1,5 +1,6 @@
|
||||
.\" $KAME: ifmcstat.8,v 1.6 2002/10/31 04:23:43 suz Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2007-2009 Bruce Simpson.
|
||||
.\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
@ -29,7 +30,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd October 30, 2007
|
||||
.Dd February 15, 2009
|
||||
.Dt IFMCSTAT 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -39,10 +40,9 @@
|
||||
.Nm
|
||||
.Op Fl i Ar interface
|
||||
.Op Fl f Ar address-family
|
||||
.Op Fl v
|
||||
.Op Fl M Ar core
|
||||
.Op Fl N Ar system
|
||||
.Nm
|
||||
.Op Ar kernel
|
||||
.\"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
@ -55,17 +55,23 @@ The following options are supported:
|
||||
specifies the interface to be displayed.
|
||||
.Pp
|
||||
.It Fl f Ar address-family
|
||||
specifies the address-family to be displayed; currently only
|
||||
.Ar inet
|
||||
and
|
||||
specifies the address family to be displayed;
|
||||
.Ar inet ,
|
||||
.Ar inet6
|
||||
and
|
||||
.Ar link
|
||||
are supported.
|
||||
.It Fl v
|
||||
specifies that link-layer memberships should be printed;
|
||||
they are suppressed by default.
|
||||
It may not be specified for
|
||||
.Fl f Ar link .
|
||||
.El
|
||||
.Pp
|
||||
The following options are only available if
|
||||
.Nm
|
||||
has been built with support for
|
||||
.Xr kvm 3 .
|
||||
.Xr kvm 3 :
|
||||
.Bl -tag -width Fl
|
||||
.It Fl M Ar core
|
||||
extracts values associated with the name list from the specified core,
|
||||
@ -74,24 +80,11 @@ instead of the default
|
||||
.It Fl N Ar system
|
||||
extracts the name list from the specified kernel instead of the
|
||||
default, which is the kernel image the system has booted from.
|
||||
.It Nm Ar system
|
||||
This is the same as specifying
|
||||
.Nm
|
||||
.Fl N Ar system .
|
||||
This usage is deprecated; it is supported only for backwards compatibility.
|
||||
.El
|
||||
.Sh IMPLEMENTATION NOTES
|
||||
When built without
|
||||
.Xr kvm 3
|
||||
support, the information displayed by
|
||||
.Nm
|
||||
is more limited.
|
||||
This support is recommended for debugging purposes.
|
||||
It requires superuser privilege if used to inspect a running kernel.
|
||||
.Pp
|
||||
When run without using
|
||||
.Xr kvm 3
|
||||
support,
|
||||
When run with the
|
||||
.Fl v
|
||||
option,
|
||||
.Nm
|
||||
may print multicast MAC addresses twice if they are
|
||||
referenced by a layer 3 protocol.
|
||||
@ -101,16 +94,24 @@ When run with
|
||||
support,
|
||||
the names of all interfaces configured in the system will be
|
||||
printed in the first column of output, even if no multicast
|
||||
addresses are configured on those interfaces.
|
||||
group memberships are present on those interfaces.
|
||||
The output may also be slightly different, as the kernel
|
||||
data structures are being traversed with minimal post-processing
|
||||
of the output.
|
||||
.Pp
|
||||
When built without
|
||||
.Xr kvm 3
|
||||
support, the information displayed by
|
||||
.Nm
|
||||
is more limited.
|
||||
This support is recommended for debugging purposes.
|
||||
It requires super-user privilege if used to inspect a running kernel.
|
||||
.Xr kvm 3
|
||||
will be used by default if
|
||||
.Nm
|
||||
is run with super-user privileges.
|
||||
.Sh SEE ALSO
|
||||
.Xr getifaddrs 3 ,
|
||||
.Xr getifmaddrs 3 ,
|
||||
.Xr kvm 3 ,
|
||||
.Xr netstat 8
|
||||
.Sh BUGS
|
||||
.Nm
|
||||
does not support the
|
||||
.Ar link
|
||||
argument to the
|
||||
.Ar address-family
|
||||
option.
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* $KAME: ifmcstat.c,v 1.48 2006/11/15 05:13:59 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Bruce M. Simpson <bms@FreeBSD.org>
|
||||
* Copyright (c) 2007-2009 Bruce Simpson.
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -111,6 +111,7 @@ typedef union sockunion sockunion_t;
|
||||
|
||||
uint32_t ifindex = 0;
|
||||
int af = AF_UNSPEC;
|
||||
int vflag = 0;
|
||||
|
||||
#define sa_equal(a1, a2) \
|
||||
(bcmp((a1), (a2), ((a1))->sa_len) == 0)
|
||||
@ -144,10 +145,11 @@ static struct in6_multi *
|
||||
#ifdef HAVE_MLDV2
|
||||
static void in6_addr_slistentry(struct in6_addr_slist *, char *);
|
||||
#endif
|
||||
static const char * inet6_n2a(struct in6_addr *);
|
||||
#endif /* INET6 */
|
||||
|
||||
static void kread(u_long, void *, int);
|
||||
static void ll_addrlist(struct ifaddr *);
|
||||
|
||||
static int ifmcstat_kvm(const char *kernel, const char *core);
|
||||
|
||||
#define KREAD(addr, buf, type) \
|
||||
@ -163,8 +165,25 @@ struct nlist nl[] = {
|
||||
#endif /* WITH_KVM */
|
||||
|
||||
static int ifmcstat_getifmaddrs(void);
|
||||
#ifdef INET6
|
||||
static const char * inet6_n2a(struct in6_addr *);
|
||||
#endif
|
||||
int main(int, char **);
|
||||
|
||||
static void
|
||||
usage()
|
||||
{
|
||||
|
||||
fprintf(stderr,
|
||||
"usage: ifmcstat [-i interface] [-f address family]"
|
||||
" [-v]"
|
||||
#ifdef WITH_KVM
|
||||
" [-M core] [-N system]"
|
||||
#endif
|
||||
"\n");
|
||||
exit(EX_USAGE);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
@ -172,13 +191,9 @@ main(int argc, char **argv)
|
||||
#ifdef WITH_KVM
|
||||
const char *kernel = NULL;
|
||||
const char *core = NULL;
|
||||
|
||||
/* "ifmcstat [kernel]" format is supported for backward compatiblity */
|
||||
if (argc == 2)
|
||||
kernel = argv[1];
|
||||
#endif
|
||||
|
||||
while ((c = getopt(argc, argv, "i:f:M:N:")) != -1) {
|
||||
while ((c = getopt(argc, argv, "i:f:vM:N:")) != -1) {
|
||||
switch (c) {
|
||||
case 'i':
|
||||
if ((ifindex = if_nametoindex(optarg)) == 0) {
|
||||
@ -201,11 +216,19 @@ main(int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (strcmp(optarg, "link") == 0) {
|
||||
af = AF_LINK;
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, "%s: unknown address family\n", optarg);
|
||||
exit(1);
|
||||
/*NOTREACHED*/
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
vflag = 1;
|
||||
break;
|
||||
|
||||
#ifdef WITH_KVM
|
||||
case 'M':
|
||||
core = strdup(optarg);
|
||||
@ -217,18 +240,15 @@ main(int argc, char **argv)
|
||||
#endif
|
||||
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"usage: ifmcstat [-i interface] [-f address family]"
|
||||
#ifdef WITH_KVM
|
||||
" [-M core] [-N system]"
|
||||
#endif
|
||||
"\n");
|
||||
exit(1);
|
||||
usage();
|
||||
break;
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
}
|
||||
|
||||
if (af == AF_LINK && vflag)
|
||||
usage();
|
||||
|
||||
#ifdef WITH_KVM
|
||||
error = ifmcstat_kvm(kernel, core);
|
||||
/*
|
||||
@ -280,6 +300,8 @@ ifmcstat_kvm(const char *kernel, const char *core)
|
||||
#ifdef INET6
|
||||
if6_addrlist(TAILQ_FIRST(&ifnet.if_addrhead));
|
||||
#endif
|
||||
if (vflag)
|
||||
ll_addrlist(TAILQ_FIRST(&ifnet.if_addrhead));
|
||||
next:
|
||||
ifp = nifp;
|
||||
}
|
||||
@ -297,36 +319,67 @@ kread(u_long addr, void *buf, int len)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
|
||||
static const char *
|
||||
inet6_n2a(struct in6_addr *p)
|
||||
static void
|
||||
ll_addrlist(struct ifaddr *ifap)
|
||||
{
|
||||
static char buf[NI_MAXHOST];
|
||||
struct sockaddr_in6 sin6;
|
||||
u_int32_t scopeid;
|
||||
const int niflags = NI_NUMERICHOST;
|
||||
char addrbuf[NI_MAXHOST];
|
||||
struct ifaddr ifa;
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_dl sdl;
|
||||
struct ifaddr *ifap0;
|
||||
int error;
|
||||
|
||||
memset(&sin6, 0, sizeof(sin6));
|
||||
sin6.sin6_family = AF_INET6;
|
||||
sin6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
sin6.sin6_addr = *p;
|
||||
if (IN6_IS_ADDR_LINKLOCAL(p) || IN6_IS_ADDR_MC_LINKLOCAL(p) ||
|
||||
IN6_IS_ADDR_MC_NODELOCAL(p)) {
|
||||
scopeid = ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
|
||||
if (scopeid) {
|
||||
sin6.sin6_scope_id = scopeid;
|
||||
sin6.sin6_addr.s6_addr[2] = 0;
|
||||
sin6.sin6_addr.s6_addr[3] = 0;
|
||||
if (af && af != AF_LINK)
|
||||
return;
|
||||
|
||||
ifap0 = ifap;
|
||||
while (ifap) {
|
||||
KREAD(ifap, &ifa, struct ifaddr);
|
||||
if (ifa.ifa_addr == NULL)
|
||||
goto nextifap;
|
||||
KREAD(ifa.ifa_addr, &sa, struct sockaddr);
|
||||
if (sa.sa_family != PF_LINK)
|
||||
goto nextifap;
|
||||
KREAD(ifa.ifa_addr, &sdl, struct sockaddr_dl);
|
||||
if (sdl.sdl_alen == 0)
|
||||
goto nextifap;
|
||||
addrbuf[0] = '\0';
|
||||
error = getnameinfo((struct sockaddr *)&sdl, sdl.sdl_len,
|
||||
addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST);
|
||||
printf("\tlink %s\n", addrbuf);
|
||||
nextifap:
|
||||
ifap = ifa.ifa_link.tqe_next;
|
||||
}
|
||||
if (ifap0) {
|
||||
struct ifnet ifnet;
|
||||
struct ifmultiaddr ifm, *ifmp = 0;
|
||||
|
||||
KREAD(ifap0, &ifa, struct ifaddr);
|
||||
KREAD(ifa.ifa_ifp, &ifnet, struct ifnet);
|
||||
if (TAILQ_FIRST(&ifnet.if_multiaddrs))
|
||||
ifmp = TAILQ_FIRST(&ifnet.if_multiaddrs);
|
||||
while (ifmp) {
|
||||
KREAD(ifmp, &ifm, struct ifmultiaddr);
|
||||
if (ifm.ifma_addr == NULL)
|
||||
goto nextmulti;
|
||||
KREAD(ifm.ifma_addr, &sa, struct sockaddr);
|
||||
if (sa.sa_family != AF_LINK)
|
||||
goto nextmulti;
|
||||
KREAD(ifm.ifma_addr, &sdl, struct sockaddr_dl);
|
||||
addrbuf[0] = '\0';
|
||||
error = getnameinfo((struct sockaddr *)&sdl,
|
||||
sdl.sdl_len, addrbuf, sizeof(addrbuf),
|
||||
NULL, 0, NI_NUMERICHOST);
|
||||
printf("\t\tgroup %s refcnt %d\n",
|
||||
addrbuf, ifm.ifma_refcount);
|
||||
nextmulti:
|
||||
ifmp = TAILQ_NEXT(&ifm, ifma_link);
|
||||
}
|
||||
}
|
||||
if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
|
||||
buf, sizeof(buf), NULL, 0, niflags) == 0)
|
||||
return buf;
|
||||
else
|
||||
return "(invalid)";
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
|
||||
static void
|
||||
if6_addrlist(struct ifaddr *ifap)
|
||||
{
|
||||
@ -619,11 +672,41 @@ in_addr_slistentry(struct in_addr_slist *ias, char *heading)
|
||||
|
||||
#endif /* WITH_KVM */
|
||||
|
||||
#ifdef INET6
|
||||
static const char *
|
||||
inet6_n2a(struct in6_addr *p)
|
||||
{
|
||||
static char buf[NI_MAXHOST];
|
||||
struct sockaddr_in6 sin6;
|
||||
u_int32_t scopeid;
|
||||
const int niflags = NI_NUMERICHOST;
|
||||
|
||||
memset(&sin6, 0, sizeof(sin6));
|
||||
sin6.sin6_family = AF_INET6;
|
||||
sin6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
sin6.sin6_addr = *p;
|
||||
if (IN6_IS_ADDR_LINKLOCAL(p) || IN6_IS_ADDR_MC_LINKLOCAL(p) ||
|
||||
IN6_IS_ADDR_MC_NODELOCAL(p)) {
|
||||
scopeid = ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
|
||||
if (scopeid) {
|
||||
sin6.sin6_scope_id = scopeid;
|
||||
sin6.sin6_addr.s6_addr[2] = 0;
|
||||
sin6.sin6_addr.s6_addr[3] = 0;
|
||||
}
|
||||
}
|
||||
if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
|
||||
buf, sizeof(buf), NULL, 0, niflags) == 0)
|
||||
return buf;
|
||||
else
|
||||
return "(invalid)";
|
||||
}
|
||||
#endif /* INET6 */
|
||||
|
||||
static int
|
||||
ifmcstat_getifmaddrs(void)
|
||||
{
|
||||
char thisifname[IFNAMSIZ];
|
||||
char addrbuf[INET6_ADDRSTRLEN];
|
||||
char addrbuf[NI_MAXHOST];
|
||||
struct ifaddrs *ifap, *ifa;
|
||||
struct ifmaddrs *ifmap, *ifma;
|
||||
sockunion_t lastifasa;
|
||||
@ -698,25 +781,28 @@ ifmcstat_getifmaddrs(void)
|
||||
(ifa->ifa_addr == NULL) ||
|
||||
(ifa->ifa_addr->sa_family != pgsa->sa.sa_family))
|
||||
continue;
|
||||
#ifdef INET6
|
||||
/*
|
||||
* For AF_INET6 only the link-local address should
|
||||
* be returned.
|
||||
* XXX: ifmcstat actually prints all of the inet6
|
||||
* addresses, but never mind...
|
||||
* be returned. If built without IPv6 support,
|
||||
* skip this address entirely.
|
||||
*/
|
||||
pifasa = (sockunion_t *)ifa->ifa_addr;
|
||||
if (pifasa->sa.sa_family == AF_INET6 &&
|
||||
!IN6_IS_ADDR_LINKLOCAL(&pifasa->sin6.sin6_addr)) {
|
||||
if (pifasa->sa.sa_family == AF_INET6
|
||||
#ifdef INET6
|
||||
&& !IN6_IS_ADDR_LINKLOCAL(&pifasa->sin6.sin6_addr)
|
||||
#endif
|
||||
) {
|
||||
pifasa = NULL;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if (pifasa == NULL)
|
||||
continue; /* primary address not found */
|
||||
|
||||
if (!vflag && pifasa->sa.sa_family == AF_LINK)
|
||||
continue;
|
||||
|
||||
/* Parse and print primary address, if not already printed. */
|
||||
if (lastifasa.ss.ss_family == AF_UNSPEC ||
|
||||
((lastifasa.ss.ss_family == AF_LINK &&
|
||||
@ -739,8 +825,18 @@ ifmcstat_getifmaddrs(void)
|
||||
}
|
||||
|
||||
switch (pifasa->sa.sa_family) {
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
#ifdef INET6
|
||||
{
|
||||
const char *p =
|
||||
inet6_n2a(&pifasa->sin6.sin6_addr);
|
||||
strlcpy(addrbuf, p, sizeof(addrbuf));
|
||||
break;
|
||||
}
|
||||
#else
|
||||
/* FALLTHROUGH */
|
||||
#endif
|
||||
case AF_INET:
|
||||
case AF_LINK:
|
||||
error = getnameinfo(&pifasa->sa,
|
||||
pifasa->sa.sa_len,
|
||||
@ -759,10 +855,19 @@ ifmcstat_getifmaddrs(void)
|
||||
}
|
||||
|
||||
/* Print this group address. */
|
||||
error = getnameinfo(&pgsa->sa, pgsa->sa.sa_len, addrbuf,
|
||||
sizeof(addrbuf), NULL, 0, NI_NUMERICHOST);
|
||||
if (error)
|
||||
perror("getnameinfo");
|
||||
#ifdef INET6
|
||||
if (pgsa->sa.sa_family == AF_INET6) {
|
||||
const char *p = inet6_n2a(&pgsa->sin6.sin6_addr);
|
||||
strlcpy(addrbuf, p, sizeof(addrbuf));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
error = getnameinfo(&pgsa->sa, pgsa->sa.sa_len,
|
||||
addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST);
|
||||
if (error)
|
||||
perror("getnameinfo");
|
||||
}
|
||||
|
||||
fprintf(stdout, "\t\tgroup %s\n", addrbuf);
|
||||
|
||||
/* Link-layer mapping, if present. */
|
||||
|
Loading…
Reference in New Issue
Block a user