Make netstat use sysctl when dumping routing tables/stats.

Heavily based on similar code from Claudio Jeker (at OpenBSD).

While here, fix inet/inet6 sysctl stuff commited previously to
actually work, and some other nits to make netstat more sysctl
friendly.

One step closer to losing setgid kmem on this one...
This commit is contained in:
elad 2006-05-28 16:51:40 +00:00
parent ad560fa074
commit 5d7aa1a613
9 changed files with 786 additions and 679 deletions

View File

@ -1,11 +1,11 @@
# $NetBSD: Makefile,v 1.25 2005/08/04 19:40:00 rpaulo Exp $
# $NetBSD: Makefile,v 1.26 2006/05/28 16:51:40 elad Exp $
# from: @(#)Makefile 8.1 (Berkeley) 6/12/93
.include <bsd.own.mk>
PROG= netstat
SRCS= atalk.c bpf.c fast_ipsec.c if.c inet.c inet6.c ipsec.c iso.c \
main.c mbuf.c mroute.c mroute6.c ns.c route.c tp_astring.c \
main.c mbuf.c mroute.c mroute6.c ns.c show.c route.c tp_astring.c \
unix.c
.PATH: ${NETBSDSRCDIR}/sys/netiso
BINGRP= kmem

View File

@ -1,4 +1,4 @@
/* $NetBSD: if.c,v 1.59 2005/08/04 19:41:28 rpaulo Exp $ */
/* $NetBSD: if.c,v 1.60 2006/05/28 16:51:40 elad Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@ -34,7 +34,7 @@
#if 0
static char sccsid[] = "from: @(#)if.c 8.2 (Berkeley) 2/21/94";
#else
__RCSID("$NetBSD: if.c,v 1.59 2005/08/04 19:41:28 rpaulo Exp $");
__RCSID("$NetBSD: if.c,v 1.60 2006/05/28 16:51:40 elad Exp $");
#endif
#endif /* not lint */
@ -199,10 +199,10 @@ intpr(interval, ifnetaddr, pfunc)
*/
in = inet_makeaddr(ifaddr.in.ia_subnet,
INADDR_ANY);
cp = netname(in.s_addr,
cp = netname4(in.s_addr,
ifaddr.in.ia_subnetmask);
#else
cp = netname(ifaddr.in.ia_subnet,
cp = netname4(ifaddr.in.ia_subnet,
ifaddr.in.ia_subnetmask);
#endif
if (vflag)
@ -210,7 +210,7 @@ intpr(interval, ifnetaddr, pfunc)
else
n = 13;
printf("%-*.*s ", n, n, cp);
cp = routename(sin->sin_addr.s_addr);
cp = routename4(sin->sin_addr.s_addr);
if (vflag)
n = strlen(cp) < 17 ? 17 : strlen(cp);
else
@ -226,7 +226,7 @@ intpr(interval, ifnetaddr, pfunc)
kread(multiaddr, (char *)&inm,
sizeof inm);
printf("\n%25s %-17.17s ", "",
routename(
routename4(
inm.inm_addr.s_addr));
multiaddr =
(u_long)inm.inm_list.le_next;
@ -249,7 +249,7 @@ intpr(interval, ifnetaddr, pfunc)
}
#endif
cp = netname6(&ifaddr.in6.ia_addr,
&ifaddr.in6.ia_prefixmask.sin6_addr);
&ifaddr.in6.ia_prefixmask);
if (vflag)
n = strlen(cp) < 13 ? 13 : strlen(cp);
else

View File

@ -1,4 +1,4 @@
/* $NetBSD: inet.c,v 1.71 2006/05/21 21:01:55 liamjfoy Exp $ */
/* $NetBSD: inet.c,v 1.72 2006/05/28 16:51:40 elad Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@ -34,7 +34,7 @@
#if 0
static char sccsid[] = "from: @(#)inet.c 8.4 (Berkeley) 4/20/94";
#else
__RCSID("$NetBSD: inet.c,v 1.71 2006/05/21 21:01:55 liamjfoy Exp $");
__RCSID("$NetBSD: inet.c,v 1.72 2006/05/28 16:51:40 elad Exp $");
#endif
#endif /* not lint */
@ -168,14 +168,6 @@ protopr(off, name)
int istcp;
static int first = 1;
if (off == 0)
return;
istcp = strcmp(name, "tcp") == 0;
kread(off, (char *)&table, sizeof table);
prev = head =
(struct inpcb *)&((struct inpcbtable *)off)->inpt_queue.cqh_first;
next = (struct inpcb *)table.inpt_queue.cqh_first;
compact = 0;
if (Aflag) {
if (!numeric_addr)
@ -239,6 +231,14 @@ protopr(off, name)
return;
}
if (off == 0)
return;
istcp = strcmp(name, "tcp") == 0;
kread(off, (char *)&table, sizeof table);
prev = head =
(struct inpcb *)&((struct inpcbtable *)off)->inpt_queue.cqh_first;
next = (struct inpcb *)table.inpt_queue.cqh_first;
while (next != head) {
kread((u_long)next, (char *)&inpcb, sizeof inpcb);
if ((struct inpcb *)inpcb.inp_queue.cqe_prev != prev) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: inet6.c,v 1.37 2006/05/21 21:01:56 liamjfoy Exp $ */
/* $NetBSD: inet6.c,v 1.38 2006/05/28 16:51:40 elad Exp $ */
/* BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp */
/*
@ -64,7 +64,7 @@
#if 0
static char sccsid[] = "@(#)inet.c 8.4 (Berkeley) 4/20/94";
#else
__RCSID("$NetBSD: inet6.c,v 1.37 2006/05/21 21:01:56 liamjfoy Exp $");
__RCSID("$NetBSD: inet6.c,v 1.38 2006/05/28 16:51:40 elad Exp $");
#endif
#endif /* not lint */
@ -224,14 +224,6 @@ ip6protopr(off, name)
int istcp;
static int first = 1;
if (off == 0)
return;
istcp = strcmp(name, "tcp6") == 0;
kread(off, (char *)&table, sizeof (table));
head = prev =
(struct in6pcb *)&((struct inpcbtable *)off)->inpt_queue.cqh_first;
next = (struct in6pcb *)table.inpt_queue.cqh_first;
compact = 0;
if (Aflag) {
if (!numeric_addr)
@ -295,6 +287,14 @@ ip6protopr(off, name)
return;
}
if (off == 0)
return;
istcp = strcmp(name, "tcp6") == 0;
kread(off, (char *)&table, sizeof (table));
head = prev =
(struct in6pcb *)&((struct inpcbtable *)off)->inpt_queue.cqh_first;
next = (struct in6pcb *)table.inpt_queue.cqh_first;
while (next != head) {
kread((u_long)next, (char *)&in6pcb, sizeof in6pcb);
if ((struct in6pcb *)in6pcb.in6p_queue.cqe_prev != prev) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: main.c,v 1.52 2006/05/18 09:05:51 liamjfoy Exp $ */
/* $NetBSD: main.c,v 1.53 2006/05/28 16:51:40 elad Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993\n\
#if 0
static char sccsid[] = "from: @(#)main.c 8.4 (Berkeley) 3/1/94";
#else
__RCSID("$NetBSD: main.c,v 1.52 2006/05/18 09:05:51 liamjfoy Exp $");
__RCSID("$NetBSD: main.c,v 1.53 2006/05/28 16:51:40 elad Exp $");
#endif
#endif /* not lint */
@ -450,7 +450,7 @@ main(argc, argv)
nlistf = optarg;
break;
case 'n':
numeric_addr = numeric_port = 1;
numeric_addr = numeric_port = nflag = 1;
break;
case 'P':
errno = 0;
@ -529,7 +529,7 @@ main(argc, argv)
use_sysctl = (nlistf == NULL && memf == NULL);
if ((kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY,
if (!use_sysctl && (kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY,
buf)) == NULL)
errx(1, "%s", buf);
@ -547,7 +547,7 @@ main(argc, argv)
}
#endif
if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) {
if (!use_sysctl && (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0)) {
if (nlistf)
errx(1, "%s: no namelist", nlistf);
else
@ -599,9 +599,13 @@ main(argc, argv)
}
if (rflag) {
if (sflag)
rt_stats(nl[N_RTSTAT].n_value);
else
routepr(nl[N_RTREE].n_value);
rt_stats(use_sysctl ? 0 : nl[N_RTSTAT].n_value);
else {
if (use_sysctl)
p_rttables(af);
else
routepr(nl[N_RTREE].n_value);
}
exit(0);
}
#ifndef SMALL
@ -708,8 +712,9 @@ printproto(tp, name)
pr = tp->pr_cblocks;
off = nl[tp->pr_index].n_value;
}
if (pr != NULL && (off || af != AF_UNSPEC))
if (pr != NULL && ((off || af != AF_UNSPEC) || use_sysctl)) {
(*pr)(off, name);
}
}
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: mroute.c,v 1.20 2005/08/04 19:41:28 rpaulo Exp $ */
/* $NetBSD: mroute.c,v 1.21 2006/05/28 16:51:40 elad Exp $ */
/*
* Copyright (c) 1992, 1993
@ -76,7 +76,7 @@
#if 0
static char sccsid[] = "from: @(#)mroute.c 8.1 (Berkeley) 6/6/93";
#else
__RCSID("$NetBSD: mroute.c,v 1.20 2005/08/04 19:41:28 rpaulo Exp $");
__RCSID("$NetBSD: mroute.c,v 1.21 2006/05/28 16:51:40 elad Exp $");
#endif
#endif /* not lint */
@ -198,9 +198,9 @@ mroutepr(mrpaddr, mfchashtbladdr, mfchashaddr, vifaddr)
printf(" %3u %3u %5u %-15.15s",
vifi, v->v_threshold, v->v_rate_limit,
routename(v->v_lcl_addr.s_addr));
routename4(v->v_lcl_addr.s_addr));
printf(" %-15.15s %6lu %7lu\n", (v->v_flags & VIFF_TUNNEL) ?
routename(v->v_rmt_addr.s_addr) : "",
routename4(v->v_rmt_addr.s_addr) : "",
v->v_pkt_in, v->v_pkt_out);
}
if (!banner_printed)
@ -225,9 +225,9 @@ mroutepr(mrpaddr, mfchashtbladdr, mfchashaddr, vifaddr)
kread((u_long)mfcp, (char *)&mfc, sizeof(mfc));
printf(" %3u %-15.15s",
i, routename(mfc.mfc_origin.s_addr));
i, routename4(mfc.mfc_origin.s_addr));
printf(" %-15.15s %7s %3u ",
routename(mfc.mfc_mcastgrp.s_addr),
routename4(mfc.mfc_mcastgrp.s_addr),
pktscale(mfc.mfc_pkt_cnt), mfc.mfc_parent);
for (vifi = 0; vifi <= numvifs; ++vifi)
if (mfc.mfc_ttls[vifi])

View File

@ -1,4 +1,4 @@
/* $NetBSD: netstat.h,v 1.34 2006/05/23 14:31:11 rpaulo Exp $ */
/* $NetBSD: netstat.h,v 1.35 2006/05/28 16:51:40 elad Exp $ */
/*
* Copyright (c) 1992, 1993
@ -47,6 +47,7 @@ int lflag; /* show routing table with use and ref */
int mflag; /* show memory stats */
int numeric_addr; /* show addresses numerically */
int numeric_port; /* show ports numerically */
int nflag; /* same as above, for show.c compat */
int Pflag; /* dump a PCB */
int pflag; /* show given protocol */
int qflag; /* show softintrq */
@ -114,16 +115,26 @@ void mbpr(u_long, u_long, u_long, u_long, u_long);
void hostpr __P((u_long, u_long));
void impstats __P((u_long, u_long));
void pr_rthdr __P((int));
void pr_rthdr __P((int, int));
void pr_family __P((int));
void rt_stats __P((u_long));
char *ns_phost __P((struct sockaddr *));
void upHex __P((char *));
char *routename __P((u_int32_t));
char *netname __P((u_int32_t, u_int32_t));
void p_rttables(int);
void p_flags(int, char *);
void p_addr(struct sockaddr *, struct sockaddr *, int);
void p_gwaddr(struct sockaddr *, int);
void p_sockaddr(struct sockaddr *, struct sockaddr *, int, int);
char *routename(struct sockaddr *);
char *routename4(in_addr_t);
char *netname(struct sockaddr *, struct sockaddr *);
char *netname4(in_addr_t, in_addr_t);
/* char *routename __P((u_int32_t)); */
/* char *netname __P((u_int32_t, u_int32_t)); */
#ifdef INET6
char *netname6 __P((struct sockaddr_in6 *, struct in6_addr *));
char *netname6 __P((struct sockaddr_in6 *, struct sockaddr_in6 *));
#endif
char *atalk_print __P((const struct sockaddr *, int));
char *atalk_print2 __P((const struct sockaddr *, const struct sockaddr *,
@ -157,3 +168,5 @@ void mrt_stats __P((u_long, u_long));
void bpf_stats(void);
void bpf_dump(char *);
#define PLEN (LONG_BIT / 4 + 2)

View File

@ -1,4 +1,4 @@
/* $NetBSD: route.c,v 1.66 2005/08/04 19:41:28 rpaulo Exp $ */
/* $NetBSD: route.c,v 1.67 2006/05/28 16:51:40 elad Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@ -34,7 +34,7 @@
#if 0
static char sccsid[] = "from: @(#)route.c 8.3 (Berkeley) 3/9/94";
#else
__RCSID("$NetBSD: route.c,v 1.66 2005/08/04 19:41:28 rpaulo Exp $");
__RCSID("$NetBSD: route.c,v 1.67 2006/05/28 16:51:40 elad Exp $");
#endif
#endif /* not lint */
@ -77,32 +77,6 @@ __RCSID("$NetBSD: route.c,v 1.66 2005/08/04 19:41:28 rpaulo Exp $");
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
/*
* Definitions for showing gateway flags.
*/
struct bits {
short b_mask;
char b_val;
} bits[] = {
{ RTF_UP, 'U' },
{ RTF_GATEWAY, 'G' },
{ RTF_HOST, 'H' },
{ RTF_REJECT, 'R' },
{ RTF_DYNAMIC, 'D' },
{ RTF_MODIFIED, 'M' },
{ RTF_DONE, 'd' }, /* Completed -- for routing messages only */
{ RTF_MASK, 'm' }, /* Mask Present -- for routing messages only */
{ RTF_CLONING, 'C' },
{ RTF_XRESOLVE, 'X' },
{ RTF_LLINFO, 'L' },
{ RTF_STATIC, 'S' },
{ RTF_BLACKHOLE,'B' },
{ RTF_CLONED, 'c' },
{ RTF_PROTO1, '1' },
{ RTF_PROTO2, '2' },
{ 0 }
};
/*
* XXX we put all of the sockaddr types in here to force the alignment
* to be correct.
@ -124,20 +98,10 @@ struct rtentry rtentry;
struct radix_node rnode;
struct radix_mask rmask;
int NewTree = 0;
static struct sockaddr *kgetsa __P((struct sockaddr *));
static void p_tree __P((struct radix_node *));
static void p_rtnode __P((void));
static void ntreestuff __P((void));
static void np_rtentry __P((struct rt_msghdr *));
static void p_sockaddr __P((const struct sockaddr *,
const struct sockaddr *, int, int));
static void p_flags __P((int));
static void p_rtentry __P((struct rtentry *));
static void ntreestuff __P((void));
static u_long forgemask __P((u_long));
static void domask __P((char *, size_t, u_long, u_long));
static struct sockaddr *kgetsa(struct sockaddr *);
static void p_tree(struct radix_node *);
static void p_rtnode(void);
static void p_krtentry(struct rtentry *);
/*
* Print routing tables.
@ -152,107 +116,30 @@ routepr(rtree)
printf("Routing tables\n");
if (Aflag == 0 && NewTree)
ntreestuff();
else {
if (rtree == 0) {
printf("rt_tables: symbol not in namelist\n");
return;
}
if (rtree == 0) {
printf("rt_tables: symbol not in namelist\n");
return;
}
kget(rtree, rt_tables);
for (i = 0; i <= AF_MAX; i++) {
if ((rnh = rt_tables[i]) == 0)
continue;
kget(rnh, head);
if (i == AF_UNSPEC) {
if (Aflag && af == 0) {
printf("Netmasks:\n");
p_tree(head.rnh_treetop);
}
} else if (af == AF_UNSPEC || af == i) {
pr_family(i);
do_rtent = 1;
pr_rthdr(i);
kget(rtree, rt_tables);
for (i = 0; i <= AF_MAX; i++) {
if ((rnh = rt_tables[i]) == 0)
continue;
kget(rnh, head);
if (i == AF_UNSPEC) {
if (Aflag && (af == 0 || af == 0xff)) {
printf("Netmasks:\n");
p_tree(head.rnh_treetop);
}
} else if (af == AF_UNSPEC || af == i) {
pr_family(i);
do_rtent = 1;
pr_rthdr(i, Aflag);
p_tree(head.rnh_treetop);
}
}
}
/*
* Print address family header before a section of the routing table.
*/
void
pr_family(af)
int af;
{
char *afname;
switch (af) {
case AF_INET:
afname = "Internet";
break;
#ifdef INET6
case AF_INET6:
afname = "Internet6";
break;
#endif
case AF_NS:
afname = "XNS";
break;
case AF_ISO:
afname = "ISO";
break;
case AF_APPLETALK:
afname = "AppleTalk";
break;
case AF_CCITT:
afname = "X.25";
break;
default:
afname = NULL;
break;
}
if (afname)
printf("\n%s:\n", afname);
else
printf("\nProtocol Family %d:\n", af);
}
/* column widths; each followed by one space */
#ifndef INET6
#define WID_DST(af) 18 /* width of destination column */
#define WID_GW(af) 18 /* width of gateway column */
#else
/* width of destination/gateway column */
#if 1
/* strlen("fe80::aaaa:bbbb:cccc:dddd@gif0") == 30, strlen("/128") == 4 */
#define WID_DST(af) ((af) == AF_INET6 ? (numeric_addr ? 34 : 18) : 18)
#define WID_GW(af) ((af) == AF_INET6 ? (numeric_addr ? 30 : 18) : 18)
#else
/* strlen("fe80::aaaa:bbbb:cccc:dddd") == 25, strlen("/128") == 4 */
#define WID_DST(af) ((af) == AF_INET6 ? (numeric_addr ? 29 : 18) : 18)
#define WID_GW(af) ((af) == AF_INET6 ? (numeric_addr ? 25 : 18) : 18)
#endif
#endif /* INET6 */
/*
* Print header for routing table columns.
*/
void
pr_rthdr(af)
int af;
{
if (Aflag)
printf("%-8.8s ","Address");
printf("%-*.*s %-*.*s %-6.6s %6.6s%8.8s %6.6s %s\n",
WID_DST(af), WID_DST(af), "Destination",
WID_GW(af), WID_GW(af), "Gateway",
"Flags", "Refs", "Use", "Mtu", "Interface");
}
static struct sockaddr *
kgetsa(dst)
struct sockaddr *dst;
@ -280,7 +167,7 @@ again:
rnode.rn_dupedkey ? " =>\n" : "\n");
} else if (do_rtent) {
kget(rn, rtentry);
p_rtentry(&rtentry);
p_krtentry(&rtentry);
if (Aflag)
p_rtnode();
} else {
@ -340,212 +227,6 @@ p_rtnode()
putchar('\n');
}
static void
ntreestuff()
{
size_t needed;
int mib[6];
char *buf, *next, *lim;
struct rt_msghdr *rtm;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = 0;
mib[4] = NET_RT_DUMP;
mib[5] = 0;
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
err(1, "route sysctl estimate");
if ((buf = malloc(needed)) == 0)
errx(1, "out of space");
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
err(1, "sysctl of routing table");
lim = buf + needed;
for (next = buf; next < lim; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)next;
np_rtentry(rtm);
}
}
static void
np_rtentry(rtm)
struct rt_msghdr *rtm;
{
struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
#ifdef notdef
static int masks_done, banner_printed;
#endif
static int old_af;
int af = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST;
if (Lflag && (rtm->rtm_flags & RTF_LLINFO))
return;
#ifdef notdef
/* for the moment, netmasks are skipped over */
if (!banner_printed) {
printf("Netmasks:\n");
banner_printed = 1;
}
if (masks_done == 0) {
if (rtm->rtm_addrs != RTA_DST ) {
masks_done = 1;
af = sa->sa_family;
}
} else
#endif
af = sa->sa_family;
if (af != old_af) {
pr_family(af);
old_af = af;
}
if (rtm->rtm_addrs == RTA_DST)
p_sockaddr(sa, NULL, 0, 36);
else {
p_sockaddr(sa, NULL, rtm->rtm_flags, 16);
#if 0
if (sa->sa_len == 0)
sa->sa_len = sizeof(long);
#endif
sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
p_sockaddr(sa, NULL, 0, 18);
}
p_flags(rtm->rtm_flags & interesting);
putchar('\n');
}
static void
p_sockaddr(sa, mask, flags, width)
const struct sockaddr *sa, *mask;
int flags, width;
{
char workbuf[128], *cplim;
char *cp = workbuf;
char *ep = workbuf + sizeof(workbuf);
int n;
switch(sa->sa_family) {
case AF_INET:
{
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
if ((sin->sin_addr.s_addr == INADDR_ANY) &&
(mask != NULL) &&
(((struct sockaddr_in *)mask)->sin_addr.s_addr == 0))
cp = "default";
else if (flags & RTF_HOST)
cp = routename(sin->sin_addr.s_addr);
else if (mask)
cp = netname(sin->sin_addr.s_addr,
((struct sockaddr_in *)mask)->sin_addr.s_addr);
else
cp = netname(sin->sin_addr.s_addr, INADDR_ANY);
break;
}
#ifdef INET6
case AF_INET6:
{
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
#ifdef __KAME__
struct in6_addr *in6 = &sa6->sin6_addr;
/*
* XXX: This is a special workaround for KAME kernels.
* sin6_scope_id field of SA should be set in the future.
*/
if (IN6_IS_ADDR_LINKLOCAL(in6) ||
IN6_IS_ADDR_MC_LINKLOCAL(in6)) {
/* XXX: override is ok? */
sa6->sin6_scope_id = (u_int32_t)ntohs(*(u_short *)&in6->s6_addr[2]);
*(u_short *)&in6->s6_addr[2] = 0;
}
#endif
if (flags & RTF_HOST)
cp = routename6(sa6);
else if (mask) {
cp = netname6(sa6,
&((struct sockaddr_in6 *)mask)->sin6_addr);
} else
cp = netname6(sa6, NULL);
break;
}
#endif
#ifndef SMALL
case AF_APPLETALK:
case 0:
{
if (!(flags & RTF_HOST) && mask)
cp = atalk_print2(sa,mask,11);
else
cp = atalk_print(sa,11);
break;
}
case AF_NS:
cp = ns_print((struct sockaddr *)sa);
break;
#endif
case AF_LINK:
if (getnameinfo(sa, sa->sa_len, workbuf, sizeof(workbuf),
NULL, 0, NI_NUMERICHOST) != 0)
strlcpy(workbuf, "invalid", sizeof(workbuf));
cp = workbuf;
break;
default:
{
u_char *s = (u_char *)sa->sa_data, *slim;
slim = sa->sa_len + (u_char *) sa;
cplim = cp + sizeof(workbuf) - 6;
n = snprintf(cp, ep - cp, "(%d)", sa->sa_family);
if (n >= ep - cp)
n = ep - cp - 1;
if (n > 0)
cp += n;
while (s < slim && cp < cplim) {
n = snprintf(cp, ep - cp, " %02x", *s++);
if (n >= ep - cp)
n = ep - cp - 1;
if (n > 0)
cp += n;
if (s < slim) {
n = snprintf(cp, ep - cp, "%02x", *s++);
if (n >= ep - cp)
n = ep - cp - 1;
if (n > 0)
cp += n;
}
}
cp = workbuf;
}
}
if (width < 0 )
printf("%s ", cp);
else {
if (numeric_addr)
printf("%-*s ", width, cp);
else
printf("%-*.*s ", width, width, cp);
}
}
static void
p_flags(f)
int f;
{
char name[33], *flags;
struct bits *p = bits;
for (flags = name; p->b_mask && flags - name < sizeof(name); p++)
if (p->b_mask & f)
*flags++ = p->b_val;
*flags = '\0';
printf("%-6.6s ", name);
}
static struct sockaddr *sockcopy __P((struct sockaddr *,
union sockaddr_union *));
@ -570,7 +251,7 @@ sockcopy(sp, dp)
}
static void
p_rtentry(rt)
p_krtentry(rt)
struct rtentry *rt;
{
static struct ifnet ifnet, *lastif;
@ -589,9 +270,9 @@ p_rtentry(rt)
mask = sockcopy(kgetsa(rt_mask(rt)), &mask_un);
else
mask = sockcopy(NULL, &mask_un);
p_sockaddr(addr, mask, rt->rt_flags, WID_DST(af));
p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, WID_GW(af));
p_flags(rt->rt_flags);
p_addr(addr, mask, rt->rt_flags);
p_gwaddr(kgetsa(rt->rt_gateway), kgetsa(rt->rt_gateway)->sa_family);
p_flags(rt->rt_flags, "%-6.6s ");
printf("%6d %8lu ", rt->rt_refcnt, rt->rt_use);
if (rt->rt_rmx.rmx_mtu)
printf("%6lu", rt->rt_rmx.rmx_mtu);
@ -630,286 +311,6 @@ p_rtentry(rt)
}
}
char *
routename(in)
u_int32_t in;
{
char *cp;
static char line[MAXHOSTNAMELEN + 1];
struct hostent *hp;
static char domain[MAXHOSTNAMELEN + 1];
static int first = 1;
if (first) {
first = 0;
if (gethostname(domain, MAXHOSTNAMELEN) == 0) {
domain[sizeof(domain) - 1] = '\0';
if ((cp = strchr(domain, '.')))
(void)strlcpy(domain, cp + 1, sizeof(domain));
else
domain[0] = 0;
} else
domain[0] = 0;
}
cp = 0;
if (!numeric_addr) {
hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
AF_INET);
if (hp) {
if ((cp = strchr(hp->h_name, '.')) &&
!strcmp(cp + 1, domain))
*cp = 0;
cp = hp->h_name;
}
}
if (cp)
strlcpy(line, cp, sizeof(line));
else {
#define C(x) ((x) & 0xff)
in = ntohl(in);
snprintf(line, sizeof line, "%u.%u.%u.%u",
C(in >> 24), C(in >> 16), C(in >> 8), C(in));
}
return (line);
}
static u_long
forgemask(a)
u_long a;
{
u_long m;
if (IN_CLASSA(a))
m = IN_CLASSA_NET;
else if (IN_CLASSB(a))
m = IN_CLASSB_NET;
else
m = IN_CLASSC_NET;
return (m);
}
static void
domask(dst, dlen, addr, mask)
char *dst;
size_t dlen;
u_long addr, mask;
{
int b, i;
if (!mask) {
*dst = '\0';
return;
}
i = 0;
for (b = 0; b < 32; b++)
if (mask & (1 << b)) {
int bb;
i = b;
for (bb = b+1; bb < 32; bb++)
if (!(mask & (1 << bb))) {
i = -1; /* noncontig */
break;
}
break;
}
if (i == -1)
(void)snprintf(dst, dlen, "&0x%lx", mask);
else
(void)snprintf(dst, dlen, "/%d", 32-i);
}
/*
* Return the name of the network whose address is given.
* The address is assumed to be that of a net or subnet, not a host.
*/
char *
netname(in, mask)
u_int32_t in, mask;
{
char *cp = 0;
static char line[MAXHOSTNAMELEN + 4];
struct netent *np = 0;
u_int32_t net, omask;
u_int32_t i;
int subnetshift;
i = ntohl(in);
omask = mask = ntohl(mask);
if (!numeric_addr && i != INADDR_ANY) {
if (mask == INADDR_ANY) {
switch (mask = forgemask(i)) {
case IN_CLASSA_NET:
subnetshift = 8;
break;
case IN_CLASSB_NET:
subnetshift = 8;
break;
case IN_CLASSC_NET:
subnetshift = 4;
break;
default:
abort();
}
/*
* If there are more bits than the standard mask
* would suggest, subnets must be in use.
* Guess at the subnet mask, assuming reasonable
* width subnet fields.
*/
while (i &~ mask)
mask = (long)mask >> subnetshift;
}
net = i & mask;
/*
* Note: shift the hosts bits out in octet units, since
* not all versions of getnetbyaddr() do this for us (e.g.
* the current `etc/networks' parser).
*/
while ((mask & 0xff) == 0)
mask >>= 8, net >>= 8;
np = getnetbyaddr(net, AF_INET);
if (np)
cp = np->n_name;
}
if (cp)
strlcpy(line, cp, sizeof(line));
else if ((i & 0xffffff) == 0)
(void)snprintf(line, sizeof line, "%u", C(i >> 24));
else if ((i & 0xffff) == 0)
(void)snprintf(line, sizeof line, "%u.%u", C(i >> 24)
, C(i >> 16));
else if ((i & 0xff) == 0)
(void)snprintf(line, sizeof line, "%u.%u.%u", C(i >> 24),
C(i >> 16), C(i >> 8));
else
(void)snprintf(line, sizeof line, "%u.%u.%u.%u", C(i >> 24),
C(i >> 16), C(i >> 8), C(i));
domask(line + strlen(line), sizeof(line) - strlen(line), i, omask);
return (line);
}
#ifdef INET6
char *
netname6(sa6, mask)
struct sockaddr_in6 *sa6;
struct in6_addr *mask;
{
static char line[NI_MAXHOST];
u_char *p, *q;
u_char *lim;
int masklen, final = 0, illegal = 0;
int flag = 0;
int error;
struct sockaddr_in6 sin6;
sin6 = *sa6;
if (mask) {
masklen = 0;
lim = (u_char *)(mask + 1);
for (p = (u_char *)mask, q = (u_char *)&sin6.sin6_addr;
p < lim;
p++, q++) {
if (final && *p) {
illegal++;
*q = 0;
continue;
}
switch (*p & 0xff) {
case 0xff:
masklen += 8;
break;
case 0xfe:
masklen += 7;
final++;
break;
case 0xfc:
masklen += 6;
final++;
break;
case 0xf8:
masklen += 5;
final++;
break;
case 0xf0:
masklen += 4;
final++;
break;
case 0xe0:
masklen += 3;
final++;
break;
case 0xc0:
masklen += 2;
final++;
break;
case 0x80:
masklen += 1;
final++;
break;
case 0x00:
final++;
break;
default:
final++;
illegal++;
break;
}
if (!illegal)
*q &= *p;
else
*q = 0;
}
} else
masklen = 128;
if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr))
return("default");
if (numeric_addr)
flag |= NI_NUMERICHOST;
error = getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
line, sizeof(line), NULL, 0, flag);
if (error)
strlcpy(line, "invalid", sizeof(line));
if (numeric_addr)
snprintf(&line[strlen(line)], sizeof(line) - strlen(line),
"/%d", masklen);
return line;
}
char *
routename6(sa6)
struct sockaddr_in6 *sa6;
{
static char line[NI_MAXHOST];
int flag = 0;
/* use local variable for safety */
struct sockaddr_in6 sa6_local;
int error;
memset(&sa6_local, 0, sizeof(sa6_local));
sa6_local.sin6_family = AF_INET6;
sa6_local.sin6_len = sizeof(struct sockaddr_in6);
sa6_local.sin6_addr = sa6->sin6_addr;
sa6_local.sin6_scope_id = sa6->sin6_scope_id;
if (numeric_addr)
flag |= NI_NUMERICHOST;
error = getnameinfo((struct sockaddr *)&sa6_local, sa6_local.sin6_len,
line, sizeof(line), NULL, 0, flag);
if (error)
strlcpy(line, "invalid", sizeof(line));
return line;
}
#endif /*INET6*/
/*
* Print routing statistics
*/
@ -919,11 +320,18 @@ rt_stats(off)
{
struct rtstat rtstat;
if (off == 0) {
if (use_sysctl) {
size_t rtsize = sizeof(rtstat);
if (sysctlbyname("net.route.stats", &rtstat, &rtsize,
NULL, 0) == -1)
err(1, "rt_stats: sysctl");
} else if (off == 0) {
printf("rtstat: symbol not in namelist\n");
return;
}
kread(off, (char *)&rtstat, sizeof (rtstat));
} else
kread(off, (char *)&rtstat, sizeof (rtstat));
printf("routing:\n");
printf("\t%llu bad routing redirect%s\n",
(unsigned long long)rtstat.rts_badredirect,
@ -941,6 +349,7 @@ rt_stats(off)
(unsigned long long)rtstat.rts_wildcard,
plural(rtstat.rts_wildcard));
}
short ns_nullh[] = {0,0,0};
short ns_bh[] = {-1,-1,-1};
@ -1032,3 +441,5 @@ upHex(p0)
*p += ('A' - 'a');
}
}

678
usr.bin/netstat/show.c Normal file
View File

@ -0,0 +1,678 @@
/* $NetBSD: show.c,v 1.1 2006/05/28 16:51:40 elad Exp $ */
/* $OpenBSD: show.c,v 1.1 2006/05/27 19:16:37 claudio Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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/param.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/mbuf.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/pfvar.h>
#include <net/pfkeyv2.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <arpa/inet.h>
#include <err.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "netstat.h"
char *any_ntoa(const struct sockaddr *);
char *link_print(struct sockaddr *);
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
#define PFKEYV2_CHUNK sizeof(u_int64_t)
/*
* Definitions for showing gateway flags.
*/
struct bits {
int b_mask;
char b_val;
};
static const struct bits bits[] = {
{ RTF_UP, 'U' },
{ RTF_GATEWAY, 'G' },
{ RTF_HOST, 'H' },
{ RTF_REJECT, 'R' },
{ RTF_BLACKHOLE, 'B' },
{ RTF_DYNAMIC, 'D' },
{ RTF_MODIFIED, 'M' },
{ RTF_DONE, 'd' }, /* Completed -- for routing messages only */
{ RTF_MASK, 'm' }, /* Mask Present -- for routing messages only */
{ RTF_CLONING, 'C' },
{ RTF_XRESOLVE, 'X' },
{ RTF_LLINFO, 'L' },
{ RTF_STATIC, 'S' },
{ RTF_PROTO1, '1' },
{ RTF_PROTO2, '2' },
/* { RTF_PROTO3, '3' }, */
{ RTF_CLONED, 'c' },
/* { RTF_JUMBO, 'J' }, */
{ 0 }
};
void pr_rthdr(int, int);
void p_rtentry(struct rt_msghdr *);
void pr_family(int);
void p_sockaddr(struct sockaddr *, struct sockaddr *, int, int);
void p_flags(int, char *);
char *routename4(in_addr_t);
char *routename6(struct sockaddr_in6 *);
/*
* Print routing tables.
*/
void
p_rttables(int af)
{
struct rt_msghdr *rtm;
char *buf = NULL, *next, *lim = NULL;
size_t needed;
int mib[6];
struct sockaddr *sa;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = af;
mib[4] = NET_RT_DUMP;
mib[5] = 0;
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
err(1, "route-sysctl-estimate");
if (needed > 0) {
if ((buf = malloc(needed)) == 0)
err(1, NULL);
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
err(1, "sysctl of routing table");
lim = buf + needed;
}
printf("Routing tables\n");
if (buf) {
for (next = buf; next < lim; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)next;
sa = (struct sockaddr *)(rtm + 1);
if (af != AF_UNSPEC && sa->sa_family != af)
continue;
p_rtentry(rtm);
}
free(buf);
buf = NULL;
}
if (af != 0 && af != PF_KEY)
return;
#ifdef notyet /* XXX elad */
mib[0] = CTL_NET;
mib[1] = PF_KEY;
mib[2] = PF_KEY_V2;
mib[3] = NET_KEY_SPD_DUMP;
mib[4] = mib[5] = 0;
if (sysctl(mib, 4, NULL, &needed, NULL, 0) == -1) {
if (errno == ENOPROTOOPT)
return;
err(1, "spd-sysctl-estimate");
}
if (needed > 0) {
if ((buf = malloc(needed)) == 0)
err(1, NULL);
if (sysctl(mib, 4, buf, &needed, NULL, 0) == -1)
err(1,"sysctl of spd");
lim = buf + needed;
}
if (buf) {
printf("\nEncap:\n");
for (next = buf; next < lim; next += msg->sadb_msg_len *
PFKEYV2_CHUNK) {
msg = (struct sadb_msg *)next;
if (msg->sadb_msg_len == 0)
break;
p_pfkentry(msg);
}
free(buf);
buf = NULL;
}
#endif
}
/*
* column widths; each followed by one space
* width of destination/gateway column
* strlen("fe80::aaaa:bbbb:cccc:dddd@gif0") == 30, strlen("/128") == 4
*/
#define WID_DST(af) ((af) == AF_INET6 ? (nflag ? 34 : 18) : 18)
#define WID_GW(af) ((af) == AF_INET6 ? (nflag ? 30 : 18) : 18)
/*
* Print header for routing table columns.
*/
void
pr_rthdr(int af, int Aflag)
{
if (Aflag)
printf("%-*.*s ", PLEN, PLEN, "Address");
if (af != PF_KEY)
printf("%-*.*s %-*.*s %-6.6s %6.6s %8.8s %6.6s %s\n",
WID_DST(af), WID_DST(af), "Destination",
WID_GW(af), WID_GW(af), "Gateway",
"Flags", "Refs", "Use", "Mtu", "Interface");
else
printf("%-18s %-5s %-18s %-5s %-5s %-22s\n",
"Source", "Port", "Destination",
"Port", "Proto", "SA(Address/Proto/Type/Direction)");
}
static void
get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
{
int i;
for (i = 0; i < RTAX_MAX; i++) {
if (addrs & (1 << i)) {
rti_info[i] = sa;
sa = (struct sockaddr *)((char *)(sa) +
ROUNDUP(sa->sa_len));
} else
rti_info[i] = NULL;
}
}
/*
* Print a routing table entry.
*/
void
p_rtentry(struct rt_msghdr *rtm)
{
static int old_af = -1;
struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
struct sockaddr *mask, *rti_info[RTAX_MAX];
char ifbuf[IF_NAMESIZE];
if (old_af != sa->sa_family) {
old_af = sa->sa_family;
pr_family(sa->sa_family);
pr_rthdr(sa->sa_family, 0);
}
get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
mask = rti_info[RTAX_NETMASK];
if ((sa = rti_info[RTAX_DST]) == NULL)
return;
p_sockaddr(sa, mask, rtm->rtm_flags, WID_DST(sa->sa_family));
p_sockaddr(rti_info[RTAX_GATEWAY], NULL, RTF_HOST,
WID_GW(sa->sa_family));
p_flags(rtm->rtm_flags, "%-6.6s ");
#ifdef notyet /* XXX elad */
printf("%6d %8ld ", (int)rtm->rtm_rmx.rmx_refcnt,
rtm->rtm_rmx.rmx_pksent);
#endif
if (rtm->rtm_rmx.rmx_mtu)
printf("%6ld ", rtm->rtm_rmx.rmx_mtu);
else
printf("%6s ", "-");
putchar((rtm->rtm_rmx.rmx_locks & RTV_MTU) ? 'L' : ' ');
printf(" %.16s", if_indextoname(rtm->rtm_index, ifbuf));
putchar('\n');
}
/*
* Print address family header before a section of the routing table.
*/
void
pr_family(int af)
{
char *afname;
switch (af) {
case AF_INET:
afname = "Internet";
break;
case AF_INET6:
afname = "Internet6";
break;
case PF_KEY:
afname = "Encap";
break;
case AF_APPLETALK:
afname = "AppleTalk";
break;
default:
afname = NULL;
break;
}
if (afname)
printf("\n%s:\n", afname);
else
printf("\nProtocol Family %d:\n", af);
}
void
p_addr(struct sockaddr *sa, struct sockaddr *mask, int flags)
{
p_sockaddr(sa, mask, flags, WID_DST(sa->sa_family));
}
void
p_gwaddr(struct sockaddr *sa, int af)
{
p_sockaddr(sa, 0, RTF_HOST, WID_GW(af));
}
void
p_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags, int width)
{
char *cp;
switch (sa->sa_family) {
case AF_INET6:
{
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
struct in6_addr *in6 = &sa6->sin6_addr;
/*
* XXX: This is a special workaround for KAME kernels.
* sin6_scope_id field of SA should be set in the future.
*/
if (IN6_IS_ADDR_LINKLOCAL(in6) ||
IN6_IS_ADDR_MC_LINKLOCAL(in6)) {
/* XXX: override is ok? */
sa6->sin6_scope_id = (u_int32_t)ntohs(*(u_short *)
&in6->s6_addr[2]);
*(u_short *)&in6->s6_addr[2] = 0;
}
if (flags & RTF_HOST)
cp = routename((struct sockaddr *)sa6);
else
cp = netname((struct sockaddr *)sa6, mask);
break;
}
default:
if ((flags & RTF_HOST) || mask == NULL)
cp = routename(sa);
else
cp = netname(sa, mask);
break;
}
if (width < 0)
printf("%s", cp);
else {
if (nflag)
printf("%-*s ", width, cp);
else
printf("%-*.*s ", width, width, cp);
}
}
void
p_flags(int f, char *format)
{
char name[33], *flags;
const struct bits *p = bits;
for (flags = name; p->b_mask && flags < &name[sizeof(name) - 2]; p++)
if (p->b_mask & f)
*flags++ = p->b_val;
*flags = '\0';
printf(format, name);
}
static char line[MAXHOSTNAMELEN];
static char domain[MAXHOSTNAMELEN];
char *
routename(struct sockaddr *sa)
{
char *cp = NULL;
static int first = 1;
if (first) {
first = 0;
if (gethostname(domain, sizeof(domain)) == 0 &&
(cp = strchr(domain, '.')))
(void)strlcpy(domain, cp + 1, sizeof(domain));
else
domain[0] = '\0';
cp = NULL;
}
if (sa->sa_len == 0) {
(void)strlcpy(line, "default", sizeof(line));
return (line);
}
switch (sa->sa_family) {
case AF_INET:
return
(routename4(((struct sockaddr_in *)sa)->sin_addr.s_addr));
case AF_INET6:
{
struct sockaddr_in6 sin6;
memset(&sin6, 0, sizeof(sin6));
memcpy(&sin6, sa, sa->sa_len);
sin6.sin6_len = sizeof(struct sockaddr_in6);
sin6.sin6_family = AF_INET6;
if (sa->sa_len == sizeof(struct sockaddr_in6) &&
(IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
sin6.sin6_scope_id == 0) {
sin6.sin6_scope_id =
ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
sin6.sin6_addr.s6_addr[2] = 0;
sin6.sin6_addr.s6_addr[3] = 0;
}
return (routename6(&sin6));
}
case AF_LINK:
return (link_print(sa));
#ifdef notyet /* XXX elad */
case AF_UNSPEC:
if (sa->sa_len == sizeof(struct sockaddr_rtlabel)) {
static char name[RTLABEL_LEN];
struct sockaddr_rtlabel *sr;
sr = (struct sockaddr_rtlabel *)sa;
strlcpy(name, sr->sr_label, sizeof(name));
return (name);
}
/* FALLTHROUGH */
#endif
default:
(void)snprintf(line, sizeof(line), "(%d) %s",
sa->sa_family, any_ntoa(sa));
break;
}
return (line);
}
char *
routename4(in_addr_t in)
{
char *cp = NULL;
struct in_addr ina;
struct hostent *hp;
if (in == INADDR_ANY)
cp = "default";
if (!cp && !nflag) {
if ((hp = gethostbyaddr((char *)&in,
sizeof(in), AF_INET)) != NULL) {
if ((cp = strchr(hp->h_name, '.')) &&
!strcmp(cp + 1, domain))
*cp = '\0';
cp = hp->h_name;
}
}
ina.s_addr = in;
strlcpy(line, cp ? cp : inet_ntoa(ina), sizeof(line));
return (line);
}
char *
routename6(struct sockaddr_in6 *sin6)
{
int niflags = 0;
if (nflag)
niflags |= NI_NUMERICHOST;
else
niflags |= NI_NOFQDN;
if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
line, sizeof(line), NULL, 0, niflags) != 0)
strncpy(line, "invalid", sizeof(line));
return (line);
}
/*
* Return the name of the network whose address is given.
* The address is assumed to be that of a net or subnet, not a host.
*/
char *
netname4(in_addr_t in, in_addr_t mask)
{
char *cp = NULL;
struct netent *np = NULL;
int mbits;
in = ntohl(in);
mask = ntohl(mask);
if (!nflag && in != INADDR_ANY) {
if ((np = getnetbyaddr(in, AF_INET)) != NULL)
cp = np->n_name;
}
if (in == INADDR_ANY)
cp = "default";
mbits = mask ? 33 - ffs(mask) : 0;
if (cp)
strlcpy(line, cp, sizeof(line));
#define C(x) ((x) & 0xff)
else if (mbits < 9)
snprintf(line, sizeof(line), "%u/%d", C(in >> 24), mbits);
else if (mbits < 17)
snprintf(line, sizeof(line), "%u.%u/%d",
C(in >> 24) , C(in >> 16), mbits);
else if (mbits < 25)
snprintf(line, sizeof(line), "%u.%u.%u/%d",
C(in >> 24), C(in >> 16), C(in >> 8), mbits);
else
snprintf(line, sizeof(line), "%u.%u.%u.%u/%d", C(in >> 24),
C(in >> 16), C(in >> 8), C(in), mbits);
#undef C
return (line);
}
char *
netname6(struct sockaddr_in6 *sa6, struct sockaddr_in6 *mask)
{
struct sockaddr_in6 sin6;
u_char *p;
int masklen, final = 0, illegal = 0;
int i, lim, flag, error;
char hbuf[NI_MAXHOST];
sin6 = *sa6;
flag = 0;
masklen = 0;
if (mask) {
lim = mask->sin6_len - offsetof(struct sockaddr_in6, sin6_addr);
lim = lim < sizeof(struct in6_addr) ?
lim : sizeof(struct in6_addr);
for (p = (u_char *)&mask->sin6_addr, i = 0; i < lim; p++) {
if (final && *p) {
illegal++;
sin6.sin6_addr.s6_addr[i++] = 0x00;
continue;
}
switch (*p & 0xff) {
case 0xff:
masklen += 8;
break;
case 0xfe:
masklen += 7;
final++;
break;
case 0xfc:
masklen += 6;
final++;
break;
case 0xf8:
masklen += 5;
final++;
break;
case 0xf0:
masklen += 4;
final++;
break;
case 0xe0:
masklen += 3;
final++;
break;
case 0xc0:
masklen += 2;
final++;
break;
case 0x80:
masklen += 1;
final++;
break;
case 0x00:
final++;
break;
default:
final++;
illegal++;
break;
}
if (!illegal)
sin6.sin6_addr.s6_addr[i++] &= *p;
else
sin6.sin6_addr.s6_addr[i++] = 0x00;
}
while (i < sizeof(struct in6_addr))
sin6.sin6_addr.s6_addr[i++] = 0x00;
} else
masklen = 128;
if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr))
return ("default");
if (illegal)
warnx("illegal prefixlen");
if (nflag)
flag |= NI_NUMERICHOST;
error = getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
hbuf, sizeof(hbuf), NULL, 0, flag);
if (error)
snprintf(hbuf, sizeof(hbuf), "invalid");
snprintf(line, sizeof(line), "%s/%d", hbuf, masklen);
return (line);
}
/*
* Return the name of the network whose address is given.
* The address is assumed to be that of a net or subnet, not a host.
*/
char *
netname(struct sockaddr *sa, struct sockaddr *mask)
{
switch (sa->sa_family) {
case AF_INET:
return netname4(((struct sockaddr_in *)sa)->sin_addr.s_addr,
((struct sockaddr_in *)mask)->sin_addr.s_addr);
case AF_INET6:
return netname6((struct sockaddr_in6 *)sa,
(struct sockaddr_in6 *)mask);
case AF_LINK:
return (link_print(sa));
default:
snprintf(line, sizeof(line), "af %d: %s",
sa->sa_family, any_ntoa(sa));
break;
}
return (line);
}
static const char hexlist[] = "0123456789abcdef";
char *
any_ntoa(const struct sockaddr *sa)
{
static char obuf[240];
const char *in = sa->sa_data;
char *out = obuf;
int len = sa->sa_len - offsetof(struct sockaddr, sa_data);
*out++ = 'Q';
do {
*out++ = hexlist[(*in >> 4) & 15];
*out++ = hexlist[(*in++) & 15];
*out++ = '.';
} while (--len > 0 && (out + 3) < &obuf[sizeof(obuf) - 1]);
out[-1] = '\0';
return (obuf);
}
char *
link_print(struct sockaddr *sa)
{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
u_char *lla = (u_char *)sdl->sdl_data + sdl->sdl_nlen;
if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
sdl->sdl_slen == 0) {
(void)snprintf(line, sizeof(line), "link#%d", sdl->sdl_index);
return (line);
}
switch (sdl->sdl_type) {
case IFT_ETHER:
#ifdef notyet /* XXX elad */
case IFT_CARP:
#endif
return (ether_ntoa((struct ether_addr *)lla));
default:
return (link_ntoa(sdl));
}
}