diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2019-04-28 17:59:52 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2019-04-28 17:59:52 +0000 |
commit | 85a27b2729a3964babaadc7ed78346074dbc638c (patch) | |
tree | b103464191657f6a34e3eb09e2f5374f63ddf3d8 /usr.bin/netstat | |
parent | 3f2496c46638b1e4301b6cec4b38463d763bf812 (diff) |
Fix reading route entries via kvm(3).
From Naoki Fukaumi, ok yasuoka@, sthen@
Diffstat (limited to 'usr.bin/netstat')
-rw-r--r-- | usr.bin/netstat/main.c | 44 | ||||
-rw-r--r-- | usr.bin/netstat/netstat.h | 4 | ||||
-rw-r--r-- | usr.bin/netstat/route.c | 328 |
3 files changed, 189 insertions, 187 deletions
diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c index 4c406ce60bc..13f14020332 100644 --- a/usr.bin/netstat/main.c +++ b/usr.bin/netstat/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.115 2019/03/05 06:47:12 jmc Exp $ */ +/* $OpenBSD: main.c,v 1.116 2019/04/28 17:59:51 mpi Exp $ */ /* $NetBSD: main.c,v 1.9 1996/05/07 02:55:02 thorpej Exp $ */ /* @@ -54,14 +54,12 @@ #include "netstat.h" struct nlist nl[] = { -#define N_RTREE 0 - { "_rt_tables"}, -#define N_RTMASK 1 - { "_mask_rnhead" }, -#define N_AF2RTAFIDX 2 - { "_af2rtafidx" }, -#define N_RTBLIDMAX 3 - { "_rtbl_id_max" }, +#define N_AFMAP 0 + { "_afmap"}, +#define N_AF2IDX 1 + { "_af2idx" }, +#define N_AF2IDXMAX 2 + { "_af2idx_max" }, { "" } }; @@ -104,7 +102,7 @@ struct protox *protoprotox[] = { static void usage(void); static struct protox *name2protox(char *); static struct protox *knownname(char *); -u_int gettable(const char *); +void gettable(u_int); kvm_t *kvmd; @@ -168,8 +166,6 @@ main(int argc, char *argv[]) af = AF_UNIX; else if (strcmp(optarg, "mpls") == 0) af = AF_MPLS; - else if (strcmp(optarg, "mask") == 0) - af = 0xff; else { (void)fprintf(stderr, "%s: %s: unknown address family\n", @@ -236,8 +232,10 @@ main(int argc, char *argv[]) ++sflag; break; case 'T': + tableid = strtonum(optarg, 0, RT_TABLEID_MAX, &errstr); + if (errstr) + errx(1, "invalid table id: %s", errstr); Tflag = 1; - tableid = gettable(optarg); break; case 't': tflag = 1; @@ -341,11 +339,13 @@ main(int argc, char *argv[]) errx(1, "no namelist"); } + if (!need_nlist && Tflag) + gettable(tableid); + if (rflag) { if (Aflag || nlistf != NULL || memf != NULL) - routepr(nl[N_RTREE].n_value, nl[N_RTMASK].n_value, - nl[N_AF2RTAFIDX].n_value, nl[N_RTBLIDMAX].n_value, - tableid); + routepr(nl[N_AFMAP].n_value, nl[N_AF2IDX].n_value, + nl[N_AF2IDXMAX].n_value, tableid); else p_rttables(af, tableid); exit(0); @@ -458,18 +458,12 @@ usage(void) exit(1); } -u_int -gettable(const char *s) +void +gettable(u_int tableid) { - const char *errstr; struct rt_tableinfo info; int mib[6]; size_t len; - u_int tableid; - - tableid = strtonum(s, 0, RT_TABLEID_MAX, &errstr); - if (errstr) - errx(1, "invalid table id: %s", errstr); mib[0] = CTL_NET; mib[1] = PF_ROUTE; @@ -481,6 +475,4 @@ gettable(const char *s) len = sizeof(info); if (sysctl(mib, 6, &info, &len, NULL, 0) == -1) err(1, "routing table %d", tableid); - - return (tableid); } diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h index 8f8e01f8718..96bc6f3f8cb 100644 --- a/usr.bin/netstat/netstat.h +++ b/usr.bin/netstat/netstat.h @@ -1,4 +1,4 @@ -/* $OpenBSD: netstat.h,v 1.73 2019/03/04 21:32:26 dlg Exp $ */ +/* $OpenBSD: netstat.h,v 1.74 2019/04/28 17:59:51 mpi Exp $ */ /* $NetBSD: netstat.h,v 1.6 1996/05/07 02:55:05 thorpej Exp $ */ /* @@ -138,7 +138,7 @@ char *routename4(in_addr_t); char *netname(struct sockaddr *, struct sockaddr *); char *netname4(in_addr_t, in_addr_t); char *mpls_op(u_int32_t); -void routepr(u_long, u_long, u_long, u_long, u_int); +void routepr(u_long, u_long, u_long, u_int); void nsprotopr(u_long, char *); diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c index 64531d4d509..c13d5ca8d4e 100644 --- a/usr.bin/netstat/route.c +++ b/usr.bin/netstat/route.c @@ -1,4 +1,4 @@ -/* $OpenBSD: route.c,v 1.101 2016/09/15 01:01:07 dlg Exp $ */ +/* $OpenBSD: route.c,v 1.102 2019/04/28 17:59:51 mpi Exp $ */ /* $NetBSD: route.c,v 1.15 1996/05/07 02:55:06 thorpej Exp $ */ /* @@ -55,95 +55,90 @@ #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 { struct sockaddr u_sa; u_int32_t u_data[64]; int u_dummy; /* force word-alignment */ } pt_u; -int do_rtent = 0; struct rtentry rtentry; -struct radix_node rnode; -struct radix_mask rmask; static struct sockaddr *kgetsa(struct sockaddr *); -static void p_tree(struct radix_node *); -static void p_rtnode(void); -static void p_rtflags(u_char); +static struct sockaddr *plentosa(sa_family_t, int, struct sockaddr *); +static struct art_node *getdefault(struct art_table *); +static void p_table(struct art_table *); +static void p_artnode(struct art_node *); static void p_krtentry(struct rtentry *); /* * Print routing tables. */ void -routepr(u_long rtree, u_long mtree, u_long af2idx, u_long rtbl_id_max, - u_int tableid) +routepr(u_long afmap, u_long af2idx, u_long af2idx_max, u_int tableid) { - struct radix_node_head *rnh, head; - int i, idxmax = 0; - u_int rtidxmax; + struct art_root ar; + struct art_node *node; + 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"); - if (rtree == 0 || af2idx == 0) { - printf("rt_tables: symbol not in namelist\n"); + if (afmap == 0 || af2idx == 0 || af2idx_max == 0) { + printf("symbol not in namelist\n"); return; } - kread((u_long)rtree, &rt_head, sizeof(rt_head)); - kread((u_long)rtbl_id_max, &rtidxmax, sizeof(rtidxmax)); - kread((long)af2idx, &af2rtafidx, sizeof(af2rtafidx)); - - for (i = 0; i <= AF_MAX; i++) { - if (af2rtafidx[i] > idxmax) - idxmax = af2rtafidx[i]; - } + kread(afmap, &afm_head, sizeof(afm_head)); + kread(af2idx, af2i, sizeof(af2i)); + kread(af2idx_max, &af2i_max, sizeof(af2i_max)); - if ((rnt = calloc(rtidxmax + 1, sizeof(struct radix_node_head **))) == - NULL) + if ((afm = calloc(af2i_max + 1, sizeof(*afm))) == NULL) err(1, NULL); - kread((u_long)rt_head, rnt, (rtidxmax + 1) * - 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++) { - if (i == AF_UNSPEC) { - 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); - } + kread((u_long)afm_head, afm, (af2i_max + 1) * sizeof(*afm)); + + for (i = 1; i <= AF_MAX; i++) { + if (af != AF_UNSPEC && af != i) continue; - } - if (af2rtafidx[i] == 0) - /* no table for this AF */ + if (af2i[i] == 0 || afm[af2i[i]].ref == NULL) continue; - if ((rnh = rt_tables[af2rtafidx[i]]) == NULL) + + kread((u_long)afm[af2i[i]].ref, &map, sizeof(map)); + if (tableid >= map.limit) continue; - kread((u_long)rnh, &head, sizeof(head)); - if (af == AF_UNSPEC || af == i) { - pr_family(i); - do_rtent = 1; - pr_rthdr(i, Aflag); - p_tree(head.rnh_treetop); - } + + if ((tbl = calloc(map.limit, sizeof(*tbl))) == NULL) + err(1, NULL); + + kread((u_long)map.tbl, tbl, map.limit * sizeof(*tbl)); + 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 * @@ -156,106 +151,128 @@ kgetsa(struct sockaddr *dst) return (&pt_u.u_sa); } -static void -p_tree(struct radix_node *rn) +static struct sockaddr * +plentosa(sa_family_t af, int plen, struct sockaddr *sa_mask) { - -again: - kread((u_long)rn, &rnode, sizeof(rnode)); - if (rnode.rn_b < 0) { - if (Aflag) - printf("%-16p ", rn); - if (rnode.rn_flags & RNF_ROOT) { - if (Aflag) - printf("(root node)%s", - rnode.rn_dupedkey ? " =>\n" : "\n"); - } else if (do_rtent) { - kread((u_long)rn, &rtentry, sizeof(rtentry)); - p_krtentry(&rtentry); - if (Aflag) - p_rtnode(); - } else { - p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key), - 0, 0, 44); - putchar('\n'); - } - if ((rn = rnode.rn_dupedkey)) - goto again; - } else { - if (Aflag && do_rtent) { - printf("%-16p ", rn); - p_rtnode(); - } - rn = rnode.rn_r; - p_tree(rnode.rn_l); - p_tree(rn); + struct sockaddr_in *sin = (struct sockaddr_in *)sa_mask; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa_mask; + uint8_t *p; + int i; + + if (plen < 0) + return (NULL); + + memset(sa_mask, 0, sizeof(struct sockaddr_storage)); + + switch (af) { + case AF_INET: + if (plen > 32) + return (NULL); + sin->sin_family = AF_INET; + sin->sin_len = sizeof(struct sockaddr_in); + memset(&sin->sin_addr, 0, sizeof(sin->sin_addr)); + p = (uint8_t *)&sin->sin_addr; + break; + case AF_INET6: + if (plen > 128) + return (NULL); + sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(struct sockaddr_in6); + memset(&sin6->sin6_addr.s6_addr, 0, sizeof(sin6->sin6_addr.s6_addr)); + p = sin6->sin6_addr.s6_addr; + break; + default: + return (NULL); } + + for (i = 0; i < plen / 8; i++) + p[i] = 0xff; + if (plen % 8) + p[i] = (0xff00 >> (plen % 8)) & 0xff; + + return (sa_mask); } -static void -p_rtflags(u_char flags) +static struct art_node * +getdefault(struct art_table *at) { - putchar('<'); - if (flags & RNF_NORMAL) - putchar('N'); - if (flags & RNF_ROOT) - putchar('R'); - if (flags & RNF_ACTIVE) - putchar('A'); - if (flags & ~(RNF_NORMAL | RNF_ROOT | RNF_ACTIVE)) - printf("/0x%02x", flags); - putchar('>'); -} + struct art_node *node; + struct art_table table; + union { + struct srp node; + unsigned long count; + } *heap; + + 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; -char nbuf[25]; + free(heap); + + return (node); +} static void -p_rtnode(void) +p_table(struct art_table *at) { - struct radix_mask *rm = rnode.rn_mklist; - - if (rnode.rn_b < 0) { - snprintf(nbuf, sizeof nbuf, " => %p", rnode.rn_dupedkey); - printf("\t (%p)%s", rnode.rn_p, rnode.rn_dupedkey ? nbuf : ""); - if (rnode.rn_mask) { - printf(" mask "); - p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask), - 0, 0, -1); - } else if (rm == NULL) { - putchar('\n'); - return; + struct art_node *next, *node; + struct art_table *nat, table; + union { + struct srp node; + unsigned long count; + } *heap; + int i, j; + + 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)); + + for (j = 1; j < table.at_minfringe; j += 2) { + for (i = (j > 2) ? j : 2; i < table.at_minfringe; i <<= 1) { + next = heap[i >> 1].node.ref; + node = heap[i].node.ref; + if (node != NULL && node != next) + 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(' '); - p_rtflags(rnode.rn_flags); - - while (rm) { - kread((u_long)rm, &rmask, sizeof(rmask)); - 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); - kread((u_long)rmask.rm_leaf, &rnode_aux, sizeof(rnode_aux)); - p_sockaddr(kgetsa((struct sockaddr *)rnode_aux.rn_mask), - 0, 0, -1); + for (i = table.at_minfringe; i < table.at_minfringe << 1; i++) { + next = heap[i >> 1].node.ref; + node = heap[i].node.ref; + if (!ISLEAF(node)) { + nat = SUBTABLE(node); + node = getdefault(nat); } else - p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask), - 0, 0, -1); - putchar('}'); - if ((rm = rmask.rm_mklist)) - printf(" ->"); + nat = NULL; + + if (node != NULL && node != next) + p_artnode(node); + + if (nat != NULL) + p_table(nat); + } + + free(heap); +} + +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; } - putchar('\n'); } static void @@ -274,28 +291,21 @@ p_krtentry(struct rtentry *rt) return; } - if (rt_mask(rt)) { - 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; + mask = plentosa(sa->sa_family, rt_plen(rt), mask); p_addr(sa, mask, rt->rt_flags); p_gwaddr(kgetsa(rt->rt_gateway), sa->sa_family); 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) printf("%5u ", rt->rt_rmx.rmx_mtu); else printf("%5s ", "-"); 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) { - printf(" if%d%s", rt->rt_ifidx, - rt->rt_nodes[0].rn_dupedkey ? " =>" : ""); - } + if (rt->rt_ifidx != 0) + printf(" if%d", rt->rt_ifidx); putchar('\n'); if (vflag) printf("\texpire %10lld%c\n", |