version 1.101, 2016/09/15 01:01:07 |
version 1.102, 2019/04/28 17:59:51 |
|
|
|
|
#include "netstat.h" |
#include "netstat.h" |
|
|
/* alignment constraint for routing socket */ |
|
#define ROUNDUP(a) \ |
|
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) |
|
#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) |
|
|
|
struct radix_node_head ***rt_head; |
|
struct radix_node_head ***rnt; |
|
struct radix_node_head *rt_tables[AF_MAX+1]; /* provides enough space */ |
|
u_int8_t af2rtafidx[AF_MAX+1]; |
|
|
|
static union { |
static union { |
struct sockaddr u_sa; |
struct sockaddr u_sa; |
u_int32_t u_data[64]; |
u_int32_t u_data[64]; |
int u_dummy; /* force word-alignment */ |
int u_dummy; /* force word-alignment */ |
} pt_u; |
} pt_u; |
|
|
int do_rtent = 0; |
|
struct rtentry rtentry; |
struct rtentry rtentry; |
struct radix_node rnode; |
|
struct radix_mask rmask; |
|
|
|
static struct sockaddr *kgetsa(struct sockaddr *); |
static struct sockaddr *kgetsa(struct sockaddr *); |
static void p_tree(struct radix_node *); |
static struct sockaddr *plentosa(sa_family_t, int, struct sockaddr *); |
static void p_rtnode(void); |
static struct art_node *getdefault(struct art_table *); |
static void p_rtflags(u_char); |
static void p_table(struct art_table *); |
|
static void p_artnode(struct art_node *); |
static void p_krtentry(struct rtentry *); |
static void p_krtentry(struct rtentry *); |
|
|
/* |
/* |
* Print routing tables. |
* Print routing tables. |
*/ |
*/ |
void |
void |
routepr(u_long rtree, u_long mtree, u_long af2idx, u_long rtbl_id_max, |
routepr(u_long afmap, u_long af2idx, u_long af2idx_max, u_int tableid) |
u_int tableid) |
|
{ |
{ |
struct radix_node_head *rnh, head; |
struct art_root ar; |
int i, idxmax = 0; |
struct art_node *node; |
u_int rtidxmax; |
struct srp *afm_head, *afm; |
|
struct { |
|
unsigned int limit; |
|
void **tbl; |
|
} map; |
|
void **tbl; |
|
int i; |
|
uint8_t af2i[AF_MAX+1]; |
|
uint8_t af2i_max; |
|
|
printf("Routing tables\n"); |
printf("Routing tables\n"); |
|
|
if (rtree == 0 || af2idx == 0) { |
if (afmap == 0 || af2idx == 0 || af2idx_max == 0) { |
printf("rt_tables: symbol not in namelist\n"); |
printf("symbol not in namelist\n"); |
return; |
return; |
} |
} |
|
|
kread((u_long)rtree, &rt_head, sizeof(rt_head)); |
kread(afmap, &afm_head, sizeof(afm_head)); |
kread((u_long)rtbl_id_max, &rtidxmax, sizeof(rtidxmax)); |
kread(af2idx, af2i, sizeof(af2i)); |
kread((long)af2idx, &af2rtafidx, sizeof(af2rtafidx)); |
kread(af2idx_max, &af2i_max, sizeof(af2i_max)); |
|
|
for (i = 0; i <= AF_MAX; i++) { |
if ((afm = calloc(af2i_max + 1, sizeof(*afm))) == NULL) |
if (af2rtafidx[i] > idxmax) |
|
idxmax = af2rtafidx[i]; |
|
} |
|
|
|
if ((rnt = calloc(rtidxmax + 1, sizeof(struct radix_node_head **))) == |
|
NULL) |
|
err(1, NULL); |
err(1, NULL); |
|
|
kread((u_long)rt_head, rnt, (rtidxmax + 1) * |
kread((u_long)afm_head, afm, (af2i_max + 1) * sizeof(*afm)); |
sizeof(struct radix_node_head **)); |
|
if (tableid > rtidxmax || rnt[tableid] == NULL) { |
|
printf("Bad table %u\n", tableid); |
|
return; |
|
} |
|
kread((u_long)rnt[tableid], rt_tables, (idxmax + 1) * sizeof(rnh)); |
|
|
|
for (i = 0; i <= AF_MAX; i++) { |
for (i = 1; i <= AF_MAX; i++) { |
if (i == AF_UNSPEC) { |
if (af != AF_UNSPEC && af != i) |
if (Aflag && (af == AF_UNSPEC || af == 0xff)) { |
|
kread(mtree, &rnh, sizeof(rnh)); |
|
kread((u_long)rnh, &head, sizeof(head)); |
|
printf("Netmasks:\n"); |
|
p_tree(head.rnh_treetop); |
|
} |
|
continue; |
continue; |
} |
if (af2i[i] == 0 || afm[af2i[i]].ref == NULL) |
if (af2rtafidx[i] == 0) |
|
/* no table for this AF */ |
|
continue; |
continue; |
if ((rnh = rt_tables[af2rtafidx[i]]) == NULL) |
|
|
kread((u_long)afm[af2i[i]].ref, &map, sizeof(map)); |
|
if (tableid >= map.limit) |
continue; |
continue; |
kread((u_long)rnh, &head, sizeof(head)); |
|
if (af == AF_UNSPEC || af == i) { |
if ((tbl = calloc(map.limit, sizeof(*tbl))) == NULL) |
pr_family(i); |
err(1, NULL); |
do_rtent = 1; |
|
pr_rthdr(i, Aflag); |
kread((u_long)map.tbl, tbl, map.limit * sizeof(*tbl)); |
p_tree(head.rnh_treetop); |
if (tbl[tableid] == NULL) |
} |
continue; |
|
|
|
kread((u_long)tbl[tableid], &ar, sizeof(ar)); |
|
|
|
free(tbl); |
|
|
|
if (ar.ar_root.ref == NULL) |
|
continue; |
|
|
|
pr_family(i); |
|
pr_rthdr(i, Aflag); |
|
|
|
node = getdefault(ar.ar_root.ref); |
|
if (node != NULL) |
|
p_artnode(node); |
|
|
|
p_table(ar.ar_root.ref); |
} |
} |
|
|
|
free(afm); |
} |
} |
|
|
static struct sockaddr * |
static struct sockaddr * |
|
|
return (&pt_u.u_sa); |
return (&pt_u.u_sa); |
} |
} |
|
|
static void |
static struct sockaddr * |
p_tree(struct radix_node *rn) |
plentosa(sa_family_t af, int plen, struct sockaddr *sa_mask) |
{ |
{ |
|
struct sockaddr_in *sin = (struct sockaddr_in *)sa_mask; |
|
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa_mask; |
|
uint8_t *p; |
|
int i; |
|
|
again: |
if (plen < 0) |
kread((u_long)rn, &rnode, sizeof(rnode)); |
return (NULL); |
if (rnode.rn_b < 0) { |
|
if (Aflag) |
memset(sa_mask, 0, sizeof(struct sockaddr_storage)); |
printf("%-16p ", rn); |
|
if (rnode.rn_flags & RNF_ROOT) { |
switch (af) { |
if (Aflag) |
case AF_INET: |
printf("(root node)%s", |
if (plen > 32) |
rnode.rn_dupedkey ? " =>\n" : "\n"); |
return (NULL); |
} else if (do_rtent) { |
sin->sin_family = AF_INET; |
kread((u_long)rn, &rtentry, sizeof(rtentry)); |
sin->sin_len = sizeof(struct sockaddr_in); |
p_krtentry(&rtentry); |
memset(&sin->sin_addr, 0, sizeof(sin->sin_addr)); |
if (Aflag) |
p = (uint8_t *)&sin->sin_addr; |
p_rtnode(); |
break; |
} else { |
case AF_INET6: |
p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key), |
if (plen > 128) |
0, 0, 44); |
return (NULL); |
putchar('\n'); |
sin6->sin6_family = AF_INET6; |
} |
sin6->sin6_len = sizeof(struct sockaddr_in6); |
if ((rn = rnode.rn_dupedkey)) |
memset(&sin6->sin6_addr.s6_addr, 0, sizeof(sin6->sin6_addr.s6_addr)); |
goto again; |
p = sin6->sin6_addr.s6_addr; |
} else { |
break; |
if (Aflag && do_rtent) { |
default: |
printf("%-16p ", rn); |
return (NULL); |
p_rtnode(); |
|
} |
|
rn = rnode.rn_r; |
|
p_tree(rnode.rn_l); |
|
p_tree(rn); |
|
} |
} |
|
|
|
for (i = 0; i < plen / 8; i++) |
|
p[i] = 0xff; |
|
if (plen % 8) |
|
p[i] = (0xff00 >> (plen % 8)) & 0xff; |
|
|
|
return (sa_mask); |
} |
} |
|
|
static void |
static struct art_node * |
p_rtflags(u_char flags) |
getdefault(struct art_table *at) |
{ |
{ |
putchar('<'); |
struct art_node *node; |
if (flags & RNF_NORMAL) |
struct art_table table; |
putchar('N'); |
union { |
if (flags & RNF_ROOT) |
struct srp node; |
putchar('R'); |
unsigned long count; |
if (flags & RNF_ACTIVE) |
} *heap; |
putchar('A'); |
|
if (flags & ~(RNF_NORMAL | RNF_ROOT | RNF_ACTIVE)) |
|
printf("/0x%02x", flags); |
|
putchar('>'); |
|
} |
|
|
|
char nbuf[25]; |
kread((u_long)at, &table, sizeof(table)); |
|
heap = calloc(1, AT_HEAPSIZE(table.at_bits)); |
|
kread((u_long)table.at_heap, heap, AT_HEAPSIZE(table.at_bits)); |
|
|
|
node = heap[1].node.ref; |
|
|
|
free(heap); |
|
|
|
return (node); |
|
} |
|
|
static void |
static void |
p_rtnode(void) |
p_table(struct art_table *at) |
{ |
{ |
struct radix_mask *rm = rnode.rn_mklist; |
struct art_node *next, *node; |
|
struct art_table *nat, table; |
|
union { |
|
struct srp node; |
|
unsigned long count; |
|
} *heap; |
|
int i, j; |
|
|
if (rnode.rn_b < 0) { |
kread((u_long)at, &table, sizeof(table)); |
snprintf(nbuf, sizeof nbuf, " => %p", rnode.rn_dupedkey); |
heap = calloc(1, AT_HEAPSIZE(table.at_bits)); |
printf("\t (%p)%s", rnode.rn_p, rnode.rn_dupedkey ? nbuf : ""); |
kread((u_long)table.at_heap, heap, AT_HEAPSIZE(table.at_bits)); |
if (rnode.rn_mask) { |
|
printf(" mask "); |
for (j = 1; j < table.at_minfringe; j += 2) { |
p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask), |
for (i = (j > 2) ? j : 2; i < table.at_minfringe; i <<= 1) { |
0, 0, -1); |
next = heap[i >> 1].node.ref; |
} else if (rm == NULL) { |
node = heap[i].node.ref; |
putchar('\n'); |
if (node != NULL && node != next) |
return; |
p_artnode(node); |
} |
} |
} else { |
|
snprintf(nbuf, sizeof nbuf, "(%d)", rnode.rn_b); |
|
printf("%6.6s (%p) %16p : %16p", nbuf, |
|
rnode.rn_p, rnode.rn_l, rnode.rn_r); |
|
} |
} |
|
|
putchar(' '); |
for (i = table.at_minfringe; i < table.at_minfringe << 1; i++) { |
p_rtflags(rnode.rn_flags); |
next = heap[i >> 1].node.ref; |
|
node = heap[i].node.ref; |
|
if (!ISLEAF(node)) { |
|
nat = SUBTABLE(node); |
|
node = getdefault(nat); |
|
} else |
|
nat = NULL; |
|
|
while (rm) { |
if (node != NULL && node != next) |
kread((u_long)rm, &rmask, sizeof(rmask)); |
p_artnode(node); |
snprintf(nbuf, sizeof nbuf, " %d refs, ", rmask.rm_refs); |
|
printf("\n\tmk = %p {(%d),%s", rm, -1 - rmask.rm_b, |
|
rmask.rm_refs ? nbuf : " "); |
|
p_rtflags(rmask.rm_flags); |
|
printf(", "); |
|
if (rmask.rm_flags & RNF_NORMAL) { |
|
struct radix_node rnode_aux; |
|
|
|
printf("leaf = %p ", rmask.rm_leaf); |
if (nat != NULL) |
kread((u_long)rmask.rm_leaf, &rnode_aux, sizeof(rnode_aux)); |
p_table(nat); |
p_sockaddr(kgetsa((struct sockaddr *)rnode_aux.rn_mask), |
|
0, 0, -1); |
|
} else |
|
p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask), |
|
0, 0, -1); |
|
putchar('}'); |
|
if ((rm = rmask.rm_mklist)) |
|
printf(" ->"); |
|
} |
} |
putchar('\n'); |
|
|
free(heap); |
} |
} |
|
|
static void |
static void |
|
p_artnode(struct art_node *an) |
|
{ |
|
struct art_node node; |
|
struct rtentry *rt; |
|
|
|
kread((u_long)an, &node, sizeof(node)); |
|
rt = node.an_rtlist.sl_head.ref; |
|
|
|
while (rt != NULL) { |
|
kread((u_long)rt, &rtentry, sizeof(rtentry)); |
|
if (Aflag) |
|
printf("%-16p ", rt); |
|
p_krtentry(&rtentry); |
|
rt = rtentry.rt_next.se_next.ref; |
|
} |
|
} |
|
|
|
static void |
p_krtentry(struct rtentry *rt) |
p_krtentry(struct rtentry *rt) |
{ |
{ |
struct sockaddr_storage sock1, sock2; |
struct sockaddr_storage sock1, sock2; |
|
|
return; |
return; |
} |
} |
|
|
if (rt_mask(rt)) { |
mask = plentosa(sa->sa_family, rt_plen(rt), mask); |
bcopy(kgetsa(rt_mask(rt)), mask, sizeof(struct sockaddr)); |
|
if (sa->sa_len > sizeof(struct sockaddr)) |
|
bcopy(kgetsa(rt_mask(rt)), mask, sa->sa_len); |
|
} else |
|
mask = 0; |
|
|
|
p_addr(sa, mask, rt->rt_flags); |
p_addr(sa, mask, rt->rt_flags); |
p_gwaddr(kgetsa(rt->rt_gateway), 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("%5u %8lld ", rt->rt_refcnt, rt->rt_use); |
printf("%5u %8lld ", rt->rt_refcnt - 1, rt->rt_use); |
if (rt->rt_rmx.rmx_mtu) |
if (rt->rt_rmx.rmx_mtu) |
printf("%5u ", rt->rt_rmx.rmx_mtu); |
printf("%5u ", rt->rt_rmx.rmx_mtu); |
else |
else |
printf("%5s ", "-"); |
printf("%5s ", "-"); |
putchar((rt->rt_rmx.rmx_locks & RTV_MTU) ? 'L' : ' '); |
putchar((rt->rt_rmx.rmx_locks & RTV_MTU) ? 'L' : ' '); |
printf(" %2d", rt->rt_priority); |
printf(" %2d", rt->rt_priority & RTP_MASK); |
|
|
if (rt->rt_ifidx != 0) { |
if (rt->rt_ifidx != 0) |
printf(" if%d%s", rt->rt_ifidx, |
printf(" if%d", rt->rt_ifidx); |
rt->rt_nodes[0].rn_dupedkey ? " =>" : ""); |
|
} |
|
putchar('\n'); |
putchar('\n'); |
if (vflag) |
if (vflag) |
printf("\texpire %10lld%c\n", |
printf("\texpire %10lld%c\n", |