version 1.71, 2006/04/12 09:24:44 |
version 1.72, 2006/05/27 19:16:37 |
|
|
#include <netinet/in.h> |
#include <netinet/in.h> |
#include <arpa/inet.h> |
#include <arpa/inet.h> |
|
|
#include <netipx/ipx.h> |
|
|
|
#include <netatalk/at.h> |
|
|
|
#include <sys/sysctl.h> |
#include <sys/sysctl.h> |
|
|
#include <arpa/inet.h> |
|
|
|
#include <err.h> |
#include <err.h> |
#include <limits.h> |
#include <limits.h> |
#include <netdb.h> |
#include <netdb.h> |
|
|
|
|
struct radix_node_head *rt_tables[AF_MAX+1]; |
struct radix_node_head *rt_tables[AF_MAX+1]; |
|
|
/* |
|
* Definitions for showing gateway flags. |
|
*/ |
|
struct bits { |
|
int b_mask; |
|
char b_val; |
|
} 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' }, |
|
{ 0 } |
|
}; |
|
|
|
static union { |
static union { |
struct sockaddr u_sa; |
struct sockaddr u_sa; |
u_int32_t u_data[64]; |
u_int32_t u_data[64]; |
|
|
struct radix_node rnode; |
struct radix_node rnode; |
struct radix_mask rmask; |
struct radix_mask rmask; |
|
|
int NewTree = 0; |
|
|
|
static struct sockaddr *kgetsa(struct sockaddr *); |
static struct sockaddr *kgetsa(struct sockaddr *); |
static void p_tree(struct radix_node *); |
static void p_tree(struct radix_node *); |
static void p_rtnode(void); |
static void p_rtnode(void); |
static void p_rtflags(u_char); |
static void p_rtflags(u_char); |
static void ntreestuff(void); |
static void p_krtentry(struct rtentry *); |
static void np_rtentry(struct rt_msghdr *); |
|
static void p_sockaddr(struct sockaddr *, struct sockaddr *, int, int); |
|
static void p_flags(int, char *); |
|
static void p_rtentry(struct rtentry *); |
|
static void encap_print(struct rtentry *); |
static void encap_print(struct rtentry *); |
|
|
/* |
/* |
|
|
|
|
printf("Routing tables\n"); |
printf("Routing tables\n"); |
|
|
if (Aflag == 0 && NewTree) |
if (rtree == 0) { |
ntreestuff(); |
printf("rt_tables: symbol not in namelist\n"); |
else { |
return; |
if (rtree == 0) { |
} |
printf("rt_tables: symbol not in namelist\n"); |
|
return; |
|
} |
|
|
|
kget(rtree, rt_tables); |
kget(rtree, rt_tables); |
for (i = 0; i <= AF_MAX; i++) { |
for (i = 0; i <= AF_MAX; i++) { |
if ((rnh = rt_tables[i]) == 0) |
if ((rnh = rt_tables[i]) == 0) |
continue; |
continue; |
kget(rnh, head); |
kget(rnh, head); |
if (i == AF_UNSPEC) { |
if (i == AF_UNSPEC) { |
if (Aflag && af == 0) { |
if (Aflag && (af == 0 || af == 0xff)) { |
printf("Netmasks:\n"); |
printf("Netmasks:\n"); |
p_tree(head.rnh_treetop); |
|
} |
|
} else if (af == AF_UNSPEC || af == i) { |
|
pr_family(i); |
|
do_rtent = 1; |
|
if (i != PF_KEY) |
|
pr_rthdr(i); |
|
else |
|
pr_encaphdr(); |
|
p_tree(head.rnh_treetop); |
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(int af) |
|
{ |
|
char *afname; |
|
|
|
switch (af) { |
|
case AF_INET: |
|
afname = "Internet"; |
|
break; |
|
#ifdef INET6 |
|
case AF_INET6: |
|
afname = "Internet6"; |
|
break; |
|
#endif |
|
case AF_IPX: |
|
afname = "IPX"; |
|
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); |
|
} |
|
|
|
/* 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 ? (nflag ? 34 : 18) : 18) |
|
#define WID_GW(af) ((af) == AF_INET6 ? (nflag ? 30 : 18) : 18) |
|
#else |
|
/* strlen("fe80::aaaa:bbbb:cccc:dddd") == 25, strlen("/128") == 4 */ |
|
#define WID_DST(af) ((af) == AF_INET6 ? (nflag ? 29 : 18) : 18) |
|
#define WID_GW(af) ((af) == AF_INET6 ? (nflag ? 25 : 18) : 18) |
|
#endif |
|
#endif /* INET6 */ |
|
|
|
/* |
|
* Print header for routing table columns. |
|
*/ |
|
void |
|
pr_rthdr(int af) |
|
{ |
|
|
|
if (Aflag) |
|
printf("%-*.*s ", PLEN, PLEN, "Address"); |
|
printf("%-*.*s %-*.*s %-6.6s %6.6s %6.6s %6.6s %s\n", |
|
WID_DST(af), WID_DST(af), "Destination", |
|
WID_GW(af), WID_GW(af), "Gateway", |
|
"Flags", "Refs", "Use", "Mtu", "Interface"); |
|
} |
|
|
|
/* |
|
* Print header for PF_KEY entries. |
|
*/ |
|
void |
|
pr_encaphdr(void) |
|
{ |
|
if (Aflag) |
|
printf("%-*s ", PLEN, "Address"); |
|
printf("%-18s %-5s %-18s %-5s %-5s %-22s\n", |
|
"Source", "Port", "Destination", |
|
"Port", "Proto", "SA(Address/Proto/Type/Direction)"); |
|
} |
|
|
|
static struct sockaddr * |
static struct sockaddr * |
kgetsa(struct sockaddr *dst) |
kgetsa(struct sockaddr *dst) |
{ |
{ |
|
|
rnode.rn_dupedkey ? " =>\n" : "\n"); |
rnode.rn_dupedkey ? " =>\n" : "\n"); |
} else if (do_rtent) { |
} else if (do_rtent) { |
kget(rn, rtentry); |
kget(rn, rtentry); |
p_rtentry(&rtentry); |
p_krtentry(&rtentry); |
if (Aflag) |
if (Aflag) |
p_rtnode(); |
p_rtnode(); |
} else { |
} else { |
|
|
} |
} |
|
|
static void |
static void |
ntreestuff(void) |
p_krtentry(struct rtentry *rt) |
{ |
{ |
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) { |
|
perror("route-sysctl-estimate"); |
|
exit(1); |
|
} |
|
if ((buf = malloc(needed)) == NULL) |
|
err(1, NULL); |
|
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { |
|
perror("sysctl of routing table"); |
|
exit(1); |
|
} |
|
lim = buf + needed; |
|
for (next = buf; next < lim; next += rtm->rtm_msglen) { |
|
rtm = (struct rt_msghdr *)next; |
|
np_rtentry(rtm); |
|
} |
|
free(buf); |
|
} |
|
|
|
static void |
|
np_rtentry(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; |
|
|
|
#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, 0, 0, 36); |
|
else { |
|
p_sockaddr(sa, 0, rtm->rtm_flags, 16); |
|
sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa); |
|
p_sockaddr(sa, 0, 0, 18); |
|
} |
|
p_flags(rtm->rtm_flags & interesting, "%-6.6s "); |
|
putchar('\n'); |
|
} |
|
|
|
static void |
|
p_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags, int width) |
|
{ |
|
char workbuf[128], *cplim; |
|
char *cp = workbuf; |
|
size_t n; |
|
|
|
switch (sa->sa_family) { |
|
case AF_INET: |
|
{ |
|
struct sockaddr_in *sin = (struct sockaddr_in *)sa; |
|
struct sockaddr_in *msin = (struct sockaddr_in *)mask; |
|
|
|
cp = (sin->sin_addr.s_addr == 0 && mask && |
|
msin->sin_addr.s_addr == 0) ? "default" : |
|
(mask == NULL || msin->sin_addr.s_addr == (in_addr_t)-1 ? |
|
routename(sin->sin_addr.s_addr) : |
|
netname(sin->sin_addr.s_addr, msin->sin_addr.s_addr)); |
|
|
|
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 |
|
|
|
case AF_IPX: |
|
cp = ipx_print(sa); |
|
break; |
|
|
|
case AF_LINK: |
|
{ |
|
struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; |
|
|
|
if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && |
|
sdl->sdl_slen == 0) |
|
(void) snprintf(workbuf, sizeof workbuf, |
|
"link#%d", sdl->sdl_index); |
|
else switch (sdl->sdl_type) { |
|
case IFT_ETHER: |
|
{ |
|
int i; |
|
u_char *lla = (u_char *)sdl->sdl_data + |
|
sdl->sdl_nlen; |
|
|
|
cplim = ""; |
|
for (i = 0; i < sdl->sdl_alen; i++, lla++) { |
|
n = snprintf(cp, |
|
workbuf + sizeof (workbuf) - cp, |
|
"%s%x", cplim, *lla); |
|
cplim = ":"; |
|
if (n < 0) /* What else to do ? */ |
|
continue; |
|
if (n >= workbuf + sizeof (workbuf) - cp) |
|
n = workbuf + sizeof (workbuf) - cp - 1; |
|
cp += n; |
|
} |
|
cp = workbuf; |
|
break; |
|
} |
|
default: |
|
cp = link_ntoa(sdl); |
|
break; |
|
} |
|
break; |
|
} |
|
|
|
case AF_APPLETALK: |
|
{ |
|
/* XXX could do better */ |
|
cp = atalk_print(sa,11); |
|
break; |
|
} |
|
default: |
|
{ |
|
u_char *s = (u_char *)sa->sa_data, *slim; |
|
|
|
slim = sa->sa_len + (u_char *) sa; |
|
cplim = cp + sizeof(workbuf) - 6; |
|
if ((n = snprintf(cp, cplim - cp, "(%d)", sa->sa_family)) >= |
|
cplim - cp) |
|
n = cplim - cp - 1; |
|
if (n > 0) |
|
cp += n; |
|
while (s < slim && cp < cplim) { |
|
if ((n = snprintf(cp, workbuf + sizeof (workbuf) - cp, |
|
" %02x", *s++)) >= workbuf + sizeof (workbuf) - cp) |
|
n = workbuf + sizeof (workbuf) - cp - 1; |
|
if (n > 0) |
|
cp += n; |
|
if (s < slim) { |
|
if ((n = snprintf(cp, |
|
workbuf + sizeof (workbuf) - cp, |
|
"%02x", *s++)) >= |
|
workbuf + sizeof (workbuf) - cp) |
|
n = workbuf + sizeof (workbuf) - cp - 1; |
|
if (n > 0) |
|
cp += n; |
|
} |
|
} |
|
cp = workbuf; |
|
} |
|
} |
|
if (width < 0 ) |
|
printf("%s ", cp); |
|
else { |
|
if (nflag) |
|
printf("%-*s ", width, cp); |
|
else |
|
printf("%-*.*s ", width, width, cp); |
|
} |
|
} |
|
|
|
static void |
|
p_flags(int f, char *format) |
|
{ |
|
char name[33], *flags; |
|
struct bits *p = bits; |
|
|
|
for (flags = name; p->b_mask; p++) |
|
if (p->b_mask & f) |
|
*flags++ = p->b_val; |
|
*flags = '\0'; |
|
printf(format, name); |
|
} |
|
|
|
static void |
|
p_rtentry(struct rtentry *rt) |
|
{ |
|
static struct ifnet ifnet, *lastif; |
static struct ifnet ifnet, *lastif; |
struct sockaddr_storage sock1, sock2; |
struct sockaddr_storage sock1, sock2; |
struct sockaddr *sa = (struct sockaddr *)&sock1; |
struct sockaddr *sa = (struct sockaddr *)&sock1; |
|
|
} else |
} else |
mask = 0; |
mask = 0; |
|
|
p_sockaddr(sa, mask, rt->rt_flags, WID_DST(sa->sa_family)); |
p_addr(sa, mask, rt->rt_flags); |
p_sockaddr(kgetsa(rt->rt_gateway), 0, RTF_HOST, WID_GW(sa->sa_family)); |
p_gwaddr(kgetsa(rt->rt_gateway), sa->sa_family); |
p_flags(rt->rt_flags, "%-6.6s "); |
p_flags(rt->rt_flags, "%-6.6s "); |
printf("%6d %8ld ", rt->rt_refcnt, rt->rt_use); |
printf("%6d %8ld ", rt->rt_refcnt, rt->rt_use); |
if (rt->rt_rmx.rmx_mtu) |
if (rt->rt_rmx.rmx_mtu) |
|
|
else |
else |
printf("%6s ", "-"); |
printf("%6s ", "-"); |
putchar((rt->rt_rmx.rmx_locks & RTV_MTU) ? 'L' : ' '); |
putchar((rt->rt_rmx.rmx_locks & RTV_MTU) ? 'L' : ' '); |
|
|
if (rt->rt_ifp) { |
if (rt->rt_ifp) { |
if (rt->rt_ifp != lastif) { |
if (rt->rt_ifp != lastif) { |
kget(rt->rt_ifp, ifnet); |
kget(rt->rt_ifp, ifnet); |
|
|
(rt->rt_rmx.rmx_locks & RTV_EXPIRE) ? 'L' : ' '); |
(rt->rt_rmx.rmx_locks & RTV_EXPIRE) ? 'L' : ' '); |
} |
} |
|
|
char * |
|
routename(in_addr_t in) |
|
{ |
|
char *cp; |
|
static char line[MAXHOSTNAMELEN]; |
|
struct hostent *hp; |
|
static char domain[MAXHOSTNAMELEN]; |
|
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 (!nflag) { |
|
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); |
|
} |
|
|
|
/* |
/* |
* 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_addr_t in, in_addr_t mask) |
|
{ |
|
char *cp = NULL; |
|
static char line[MAXHOSTNAMELEN]; |
|
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; |
|
} |
|
mbits = mask ? 33 - ffs(mask) : 0; |
|
if (cp) { |
|
strlcpy(line, cp, sizeof(line)); |
|
} 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); |
|
return (line); |
|
} |
|
|
|
#ifdef INET6 |
|
char * |
|
netname6(struct sockaddr_in6 *sa6, struct in6_addr *mask) |
|
{ |
|
static char line[MAXHOSTNAMELEN + 1]; |
|
struct sockaddr_in6 sin6; |
|
u_char *p; |
|
u_char *lim; |
|
int masklen, final = 0, illegal = 0; |
|
int i; |
|
char hbuf[NI_MAXHOST]; |
|
int flag = 0; |
|
int error; |
|
|
|
sin6 = *sa6; |
|
|
|
masklen = 0; |
|
lim = (u_char *)(mask + 1); |
|
i = 0; |
|
if (mask) { |
|
for (p = (u_char *)mask; p < 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; |
|
} |
|
} else |
|
masklen = 128; |
|
|
|
if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) |
|
return("default"); |
|
|
|
if (illegal) |
|
fprintf(stderr, "illegal prefixlen\n"); |
|
|
|
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; |
|
} |
|
|
|
char * |
|
routename6(struct sockaddr_in6 *sa6) |
|
{ |
|
static char line[NI_MAXHOST]; |
|
const int niflag = NI_NUMERICHOST; |
|
|
|
if (getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, |
|
line, sizeof(line), NULL, 0, niflag) != 0) |
|
strlcpy(line, "", sizeof line); |
|
return line; |
|
} |
|
#endif /*INET6*/ |
|
|
|
/* |
|
* Print routing statistics |
* Print routing statistics |
*/ |
*/ |
void |
void |
rt_stats(u_long off) |
rt_stats(int usesysctl, u_long off) |
{ |
{ |
struct rtstat rtstat; |
struct rtstat rtstat; |
|
int mib[6]; |
|
size_t size; |
|
|
|
if (usesysctl) { |
|
mib[0] = CTL_NET; |
|
mib[1] = PF_ROUTE; |
|
mib[2] = 0; |
|
mib[3] = 0; |
|
mib[4] = NET_RT_STATS; |
|
mib[5] = 0; |
|
size = sizeof (rtstat); |
|
|
if (off == 0) { |
if (sysctl(mib, 6, &rtstat, &size, NULL, 0) < 0) { |
|
perror("sysctl of routing table statistics"); |
|
exit(1); |
|
} |
|
} else if (off == 0) { |
printf("rtstat: symbol not in namelist\n"); |
printf("rtstat: symbol not in namelist\n"); |
return; |
return; |
} |
} else |
kread(off, &rtstat, sizeof (rtstat)); |
kread(off, &rtstat, sizeof (rtstat)); |
|
|
printf("routing:\n"); |
printf("routing:\n"); |
printf("\t%u bad routing redirect%s\n", |
printf("\t%u bad routing redirect%s\n", |
rtstat.rts_badredirect, plural(rtstat.rts_badredirect)); |
rtstat.rts_badredirect, plural(rtstat.rts_badredirect)); |
|
|
rtstat.rts_wildcard, plural(rtstat.rts_wildcard)); |
rtstat.rts_wildcard, plural(rtstat.rts_wildcard)); |
} |
} |
|
|
u_short ipx_nullh[] = {0,0,0}; |
|
u_short ipx_bh[] = {0xffff,0xffff,0xffff}; |
|
|
|
char * |
|
ipx_print(struct sockaddr *sa) |
|
{ |
|
struct sockaddr_ipx *sipx = (struct sockaddr_ipx*)sa; |
|
struct ipx_addr work; |
|
union { union ipx_net net_e; u_long long_e; } net; |
|
in_port_t port; |
|
static char mybuf[50], cport[10], chost[25]; |
|
char *host = ""; |
|
char *q; |
|
|
|
work = sipx->sipx_addr; |
|
port = ntohs(work.ipx_port); |
|
work.ipx_port = 0; |
|
net.net_e = work.ipx_net; |
|
if (ipx_nullhost(work) && net.long_e == 0) { |
|
if (port != 0) { |
|
snprintf(mybuf, sizeof mybuf, "*.%xH", port); |
|
upHex(mybuf); |
|
} else |
|
snprintf(mybuf, sizeof mybuf, "*.*"); |
|
return (mybuf); |
|
} |
|
|
|
if (bcmp(ipx_bh, work.ipx_host.c_host, 6) == 0) { |
|
host = "any"; |
|
} else if (bcmp(ipx_nullh, work.ipx_host.c_host, 6) == 0) { |
|
host = "*"; |
|
} else { |
|
q = work.ipx_host.c_host; |
|
snprintf(chost, sizeof chost, "%02x:%02x:%02x:%02x:%02x:%02x", |
|
q[0], q[1], q[2], q[3], q[4], q[5]); |
|
host = chost; |
|
} |
|
if (port) |
|
snprintf(cport, sizeof cport, ".%xH", htons(port)); |
|
else |
|
*cport = 0; |
|
|
|
snprintf(mybuf, sizeof mybuf, "%xH.%s%s", ntohl(net.long_e), |
|
host, cport); |
|
upHex(mybuf); |
|
return(mybuf); |
|
} |
|
|
|
char * |
|
ipx_phost(struct sockaddr *sa) |
|
{ |
|
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)sa; |
|
struct sockaddr_ipx work; |
|
static union ipx_net ipx_zeronet; |
|
char *p; |
|
|
|
work = *sipx; |
|
work.sipx_addr.ipx_port = 0; |
|
work.sipx_addr.ipx_net = ipx_zeronet; |
|
|
|
p = ipx_print((struct sockaddr *)&work); |
|
if (strncmp("0H.", p, 3) == 0) |
|
p += 3; |
|
return(p); |
|
} |
|
|
|
static void |
static void |
encap_print(struct rtentry *rt) |
encap_print(struct rtentry *rt) |
{ |
{ |
|
|
bcopy(kgetsa(rt->rt_gateway), &sen3, sizeof(sen3)); |
bcopy(kgetsa(rt->rt_gateway), &sen3, sizeof(sen3)); |
|
|
if (sen1.sen_type == SENT_IP4) { |
if (sen1.sen_type == SENT_IP4) { |
printf("%-18s %-5u ", netname(sen1.sen_ip_src.s_addr, |
printf("%-18s %-5u ", netname4(sen1.sen_ip_src.s_addr, |
sen2.sen_ip_src.s_addr), ntohs(sen1.sen_sport)); |
sen2.sen_ip_src.s_addr), ntohs(sen1.sen_sport)); |
printf("%-18s %-5u %-5u ", netname(sen1.sen_ip_dst.s_addr, |
printf("%-18s %-5u %-5u ", netname4(sen1.sen_ip_dst.s_addr, |
sen2.sen_ip_dst.s_addr), |
sen2.sen_ip_dst.s_addr), |
ntohs(sen1.sen_dport), sen1.sen_proto); |
ntohs(sen1.sen_dport), sen1.sen_proto); |
} |
} |
|
|
} |
} |
#endif |
#endif |
|
|
printf("%-42s %-5u ", netname6(&s61, &s62.sin6_addr), |
printf("%-42s %-5u ", netname6(&s61, &s62), |
ntohs(sen1.sen_ip6_sport)); |
ntohs(sen1.sen_ip6_sport)); |
|
|
bzero(&s61, sizeof(s61)); |
bzero(&s61, sizeof(s61)); |
|
|
} |
} |
#endif |
#endif |
|
|
printf("%-42s %-5u %-5u ", netname6(&s61, &s62.sin6_addr), |
printf("%-42s %-5u %-5u ", netname6(&s61, &s62), |
ntohs(sen1.sen_ip6_dport), sen1.sen_ip6_proto); |
ntohs(sen1.sen_ip6_dport), sen1.sen_ip6_proto); |
} |
} |
#endif /* INET6 */ |
#endif /* INET6 */ |
|
|
printf("/out\n"); |
printf("/out\n"); |
else |
else |
printf("/<unknown>\n"); |
printf("/<unknown>\n"); |
} |
|
} |
|
|
|
void |
|
upHex(char *p0) |
|
{ |
|
char *p = p0; |
|
|
|
for (; *p; p++) |
|
switch (*p) { |
|
case 'a': |
|
case 'b': |
|
case 'c': |
|
case 'd': |
|
case 'e': |
|
case 'f': |
|
*p += ('A' - 'a'); |
|
break; |
|
} |
} |
} |
} |