summaryrefslogtreecommitdiff
path: root/usr.bin/netstat
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2019-04-28 17:59:52 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2019-04-28 17:59:52 +0000
commit85a27b2729a3964babaadc7ed78346074dbc638c (patch)
treeb103464191657f6a34e3eb09e2f5374f63ddf3d8 /usr.bin/netstat
parent3f2496c46638b1e4301b6cec4b38463d763bf812 (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.c44
-rw-r--r--usr.bin/netstat/netstat.h4
-rw-r--r--usr.bin/netstat/route.c328
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",