Module Name: src Committed By: christos Date: Wed Jun 19 21:12:03 UTC 2013
Modified Files: src/usr.bin/netstat: inet.c inet6.c main.c netstat.h Log Message: Don't use -P as a kmem printer, verify that the address points to a pcb first! To generate a diff of this commit: cvs rdiff -u -r1.101 -r1.102 src/usr.bin/netstat/inet.c cvs rdiff -u -r1.60 -r1.61 src/usr.bin/netstat/inet6.c cvs rdiff -u -r1.85 -r1.86 src/usr.bin/netstat/main.c cvs rdiff -u -r1.46 -r1.47 src/usr.bin/netstat/netstat.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.bin/netstat/inet.c diff -u src/usr.bin/netstat/inet.c:1.101 src/usr.bin/netstat/inet.c:1.102 --- src/usr.bin/netstat/inet.c:1.101 Sat Dec 24 15:18:35 2011 +++ src/usr.bin/netstat/inet.c Wed Jun 19 17:12:03 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: inet.c,v 1.101 2011/12/24 20:18:35 christos Exp $ */ +/* $NetBSD: inet.c,v 1.102 2013/06/19 21:12:03 christos 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.101 2011/12/24 20:18:35 christos Exp $"); +__RCSID("$NetBSD: inet.c,v 1.102 2013/06/19 21:12:03 christos Exp $"); #endif #endif /* not lint */ @@ -226,96 +226,72 @@ print_vtw_v4(const vtw_t *vtw) TCPS_TIME_WAIT, "tcp", 0, &vtw->expire); } -void -protopr(u_long off, const char *name) -{ - struct inpcbtable table; - struct inpcb *head, *next, *prev; - struct inpcb inpcb; - struct tcpcb tcpcb; - struct socket sockb; - int istcp = strcmp(name, "tcp") == 0; - static int first = 1; - - compact = 0; - if (Aflag) { - if (!numeric_addr) - width = 18; - else { - width = 21; - compact = 1; - } - } else - width = 22; - - if (use_sysctl) { - struct kinfo_pcb *pcblist; - int mib[8]; - size_t namelen = 0, size = 0, i; - char *mibname = NULL; - - memset(mib, 0, sizeof(mib)); +struct kinfo_pcb * +getpcblist_sysctl(const char *name, size_t *len) { + int mib[8]; + size_t namelen = 0, size = 0; + char *mibname = NULL; + struct kinfo_pcb *pcblist; - if (asprintf(&mibname, "net.inet.%s.pcblist", name) == -1) - err(1, "asprintf"); + memset(mib, 0, sizeof(mib)); - /* get dynamic pcblist node */ - if (sysctlnametomib(mibname, mib, &namelen) == -1) - err(1, "sysctlnametomib: %s", mibname); + if (asprintf(&mibname, "net.inet%s.%s.pcblist", name + 3, name) == -1) + err(1, "asprintf"); - if (prog_sysctl(mib, __arraycount(mib), - NULL, &size, NULL, 0) == -1) - err(1, "sysctl (query)"); + /* get dynamic pcblist node */ + if (sysctlnametomib(mibname, mib, &namelen) == -1) + err(1, "sysctlnametomib: %s", mibname); - if ((pcblist = malloc(size)) == NULL) - err(1, "malloc"); - memset(pcblist, 0, size); + free(mibname); - mib[6] = sizeof(*pcblist); - mib[7] = size / sizeof(*pcblist); + if (prog_sysctl(mib, __arraycount(mib), NULL, &size, NULL, 0) == -1) + err(1, "sysctl (query)"); - if (prog_sysctl(mib, __arraycount(mib), - pcblist, &size, NULL, 0) == -1) - err(1, "sysctl (copy)"); + if ((pcblist = malloc(size)) == NULL) + err(1, "malloc"); + memset(pcblist, 0, size); - for (i = 0; i < size / sizeof(*pcblist); i++) { - struct sockaddr_in src, dst; + mib[6] = sizeof(*pcblist); + mib[7] = size / sizeof(*pcblist); - memcpy(&src, &pcblist[i].ki_s, sizeof(src)); - memcpy(&dst, &pcblist[i].ki_d, sizeof(dst)); + if (prog_sysctl(mib, __arraycount(mib), pcblist, &size, NULL, 0) == -1) + err(1, "sysctl (copy)"); - if (!aflag && - inet_lnaof(dst.sin_addr) == INADDR_ANY) - continue; + *len = size / sizeof(*pcblist); + return pcblist; - if (first) { - protoprhdr(); - first = 0; - } - - protopr0((intptr_t) pcblist[i].ki_ppcbaddr, - pcblist[i].ki_rcvq, pcblist[i].ki_sndq, - &src.sin_addr, src.sin_port, - &dst.sin_addr, dst.sin_port, - pcblist[i].ki_tstate, name, - pcblist[i].ki_pflags, NULL); - } +} - free(pcblist); - goto end; +static struct kinfo_pcb * +getpcblist_kmem(u_long off, const char *name, size_t *len) { + struct inpcbtable table; + struct inpcb *head, *next, *prev; + struct inpcb inpcb; + struct tcpcb tcpcb; + struct socket sockb; + int istcp = strcmp(name, "tcp") == 0; + struct kinfo_pcb *pcblist; + size_t size = 100, i; + struct sockaddr_in sin; + + if (off == 0) { + *len = 0; + return NULL; } - if (off == 0) - return; 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; + if ((pcblist = malloc(size)) == NULL) + err(1, "malloc"); + + i = 0; while (next != head) { kread((u_long)next, (char *)&inpcb, sizeof inpcb); if ((struct inpcb *)inpcb.inp_queue.cqe_prev != prev) { - printf("???\n"); + warnx("bad pcb"); break; } prev = next; @@ -324,28 +300,83 @@ protopr(u_long off, const char *name) if (inpcb.inp_af != AF_INET) continue; - if (!aflag && - inet_lnaof(inpcb.inp_faddr) == INADDR_ANY) - continue; - kread((u_long)inpcb.inp_socket, (char *)&sockb, sizeof (sockb)); + kread((u_long)inpcb.inp_socket, (char *)&sockb, sizeof(sockb)); if (istcp) { kread((u_long)inpcb.inp_ppcb, (char *)&tcpcb, sizeof (tcpcb)); } + pcblist[i].ki_ppcbaddr = + istcp ? (uint64_t) inpcb.inp_ppcb : (uint64_t) prev; + pcblist[i].ki_rcvq = (uint64_t)sockb.so_rcv.sb_cc; + pcblist[i].ki_sndq = (uint64_t)sockb.so_snd.sb_cc; + + sin.sin_addr = inpcb.inp_laddr; + sin.sin_port = inpcb.inp_lport; + memcpy(&pcblist[i].ki_s, &sin, sizeof(sin)); + sin.sin_addr = inpcb.inp_faddr; + sin.sin_port = inpcb.inp_fport; + memcpy(&pcblist[i].ki_d, &sin, sizeof(sin)); + pcblist[i].ki_tstate = tcpcb.t_state; + pcblist[i].ki_pflags = inpcb.inp_flags; + if (i++ == size) { + struct kinfo_pcb *n = realloc(pcblist, size += 100); + if (n == NULL) + err(1, "realloc"); + pcblist = n; + } + } + *len = i; + return pcblist; +} + +void +protopr(u_long off, const char *name) +{ + static int first = 1; + struct kinfo_pcb *pcblist; + size_t i, len; + + compact = 0; + if (Aflag) { + if (!numeric_addr) + width = 18; + else { + width = 21; + compact = 1; + } + } else + width = 22; + + if (use_sysctl) + pcblist = getpcblist_sysctl(name, &len); + else + pcblist = getpcblist_kmem(off, name, &len); + + for (i = 0; i < len; i++) { + struct sockaddr_in src, dst; + + memcpy(&src, &pcblist[i].ki_s, sizeof(src)); + memcpy(&dst, &pcblist[i].ki_d, sizeof(dst)); + + if (!aflag && + inet_lnaof(dst.sin_addr) == INADDR_ANY) + continue; if (first) { protoprhdr(); first = 0; } - - protopr0(istcp ? (intptr_t) inpcb.inp_ppcb : (intptr_t) prev, - sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc, - &inpcb.inp_laddr, inpcb.inp_lport, - &inpcb.inp_faddr, inpcb.inp_fport, - tcpcb.t_state, name, inpcb.inp_flags, NULL); + protopr0((intptr_t) pcblist[i].ki_ppcbaddr, + pcblist[i].ki_rcvq, pcblist[i].ki_sndq, + &src.sin_addr, src.sin_port, + &dst.sin_addr, dst.sin_port, + pcblist[i].ki_tstate, name, + pcblist[i].ki_pflags, NULL); } -end: - if (istcp) { + + free(pcblist); + + if (strcmp(name, "tcp") == 0) { struct timeval t; timebase(&t); gettimeofday(&now, NULL); @@ -926,11 +957,26 @@ inetname(struct in_addr *inp) * Dump the contents of a TCP PCB. */ void -tcp_dump(u_long pcbaddr) +tcp_dump(u_long off, const char *name, u_long pcbaddr) { callout_impl_t *ci; struct tcpcb tcpcb; int i, hardticks; + struct kinfo_pcb *pcblist; + size_t j, len; + + if (use_sysctl) + pcblist = getpcblist_sysctl(name, &len); + else + pcblist = getpcblist_kmem(off, name, &len); + + for (j = 0; j < len; j++) + if (pcblist[j].ki_ppcbaddr == pcbaddr) + break; + free(pcblist); + + if (j == len) + errx(1, "0x%lx is not a valid pcb address", pcbaddr); kread(pcbaddr, (char *)&tcpcb, sizeof(tcpcb)); hardticks = get_hardticks(); Index: src/usr.bin/netstat/inet6.c diff -u src/usr.bin/netstat/inet6.c:1.60 src/usr.bin/netstat/inet6.c:1.61 --- src/usr.bin/netstat/inet6.c:1.60 Fri Mar 1 13:26:11 2013 +++ src/usr.bin/netstat/inet6.c Wed Jun 19 17:12:03 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: inet6.c,v 1.60 2013/03/01 18:26:11 joerg Exp $ */ +/* $NetBSD: inet6.c,v 1.61 2013/06/19 21:12:03 christos 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.60 2013/03/01 18:26:11 joerg Exp $"); +__RCSID("$NetBSD: inet6.c,v 1.61 2013/06/19 21:12:03 christos Exp $"); #endif #endif /* not lint */ @@ -275,95 +275,34 @@ print_vtw_v6(const vtw_t *vtw) TCPS_TIME_WAIT, "tcp6", &vtw->expire); } -void -ip6protopr(u_long off, const char *name) -{ + +static struct kinfo_pcb * +getpcblist_kmem(u_long off, const char *name, size_t *len) { + struct inpcbtable table; struct in6pcb *head, *prev, *next; int istcp = strcmp(name, "tcp6") == 0; - static int first = 1; - - compact = 0; - if (Aflag) { - if (!numeric_addr) - width = 18; - else { - width = 21; - compact = 1; - } - } else - width = 22; - - if (use_sysctl) { - struct kinfo_pcb *pcblist; - int mib[8]; - size_t namelen = 0, size = 0, i; - char *mibname = NULL; - - memset(mib, 0, sizeof(mib)); - - if (asprintf(&mibname, "net.inet6.%s.pcblist", name) == -1) - err(1, "asprintf"); - - /* get dynamic pcblist node */ - if (sysctlnametomib(mibname, mib, &namelen) == -1) { - if (errno == ENOENT) - return; - - err(1, "sysctlnametomib: %s", mibname); - } - - if (prog_sysctl(mib, __arraycount(mib), - NULL, &size, NULL, 0) == -1) - err(1, "sysctl (query)"); - - if ((pcblist = malloc(size)) == NULL) - err(1, "malloc"); - memset(pcblist, 0, size); - - mib[6] = sizeof(*pcblist); - mib[7] = size / sizeof(*pcblist); - - if (prog_sysctl(mib, __arraycount(mib), pcblist, - &size, NULL, 0) == -1) - err(1, "sysctl (copy)"); - - for (i = 0; i < size / sizeof(*pcblist); i++) { - struct sockaddr_in6 src, dst; - - memcpy(&src, &pcblist[i].ki_s, sizeof(src)); - memcpy(&dst, &pcblist[i].ki_d, sizeof(dst)); - - if (!aflag && IN6_IS_ADDR_UNSPECIFIED(&dst.sin6_addr)) - continue; - - if (first) { - ip6protoprhdr(); - first = 0; - } - - ip6protopr0((intptr_t) pcblist[i].ki_ppcbaddr, - pcblist[i].ki_rcvq, pcblist[i].ki_sndq, - &src.sin6_addr, src.sin6_port, - &dst.sin6_addr, dst.sin6_port, - pcblist[i].ki_tstate, name, NULL); - } + struct kinfo_pcb *pcblist; + size_t size = 100, i; + struct sockaddr_in6 sin6; - free(pcblist); - goto end; + if (off == 0) { + *len = 0; + return NULL; } - - if (off == 0) - return; 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; + if ((pcblist = malloc(size)) == NULL) + err(1, "malloc"); + + i = 0; while (next != head) { kread((u_long)next, (char *)&in6pcb, sizeof in6pcb); if ((struct in6pcb *)in6pcb.in6p_queue.cqe_prev != prev) { - printf("???\n"); + warnx("bad pcb"); break; } prev = next; @@ -372,8 +311,6 @@ ip6protopr(u_long off, const char *name) if (in6pcb.in6p_af != AF_INET6) continue; - if (!aflag && IN6_IS_ADDR_UNSPECIFIED(&in6pcb.in6p_faddr)) - continue; kread((u_long)in6pcb.in6p_socket, (char *)&sockb, sizeof (sockb)); if (istcp) { @@ -385,19 +322,75 @@ ip6protopr(u_long off, const char *name) (char *)&tcpcb, sizeof (tcpcb)); #endif } + pcblist[i].ki_ppcbaddr = + istcp ? (uint64_t) in6pcb.in6p_ppcb : (uint64_t) prev; + pcblist[i].ki_rcvq = (uint64_t)sockb.so_rcv.sb_cc; + pcblist[i].ki_sndq = (uint64_t)sockb.so_snd.sb_cc; + sin6.sin6_addr = in6pcb.in6p_laddr; + sin6.sin6_port = in6pcb.in6p_lport; + memcpy(&pcblist[i].ki_s, &sin6, sizeof(sin6)); + sin6.sin6_addr = in6pcb.in6p_faddr; + sin6.sin6_port = in6pcb.in6p_fport; + memcpy(&pcblist[i].ki_d, &sin6, sizeof(sin6)); + pcblist[i].ki_tstate = tcpcb.t_state; + if (i++ == size) { + struct kinfo_pcb *n = realloc(pcblist, size += 100); + if (n == NULL) + err(1, "realloc"); + pcblist = n; + } + } + *len = i; + return pcblist; +} + +void +ip6protopr(u_long off, const char *name) +{ + struct kinfo_pcb *pcblist; + size_t i, len; + static int first = 1; + + compact = 0; + if (Aflag) { + if (!numeric_addr) + width = 18; + else { + width = 21; + compact = 1; + } + } else + width = 22; + + if (use_sysctl) + pcblist = getpcblist_sysctl(name, &len); + else + pcblist = getpcblist_kmem(off, name, &len); + + for (i = 0; i < len; i++) { + struct sockaddr_in6 src, dst; + + memcpy(&src, &pcblist[i].ki_s, sizeof(src)); + memcpy(&dst, &pcblist[i].ki_d, sizeof(dst)); + + if (!aflag && IN6_IS_ADDR_UNSPECIFIED(&dst.sin6_addr)) + continue; + if (first) { ip6protoprhdr(); first = 0; } - ip6protopr0(istcp ? (intptr_t) in6pcb.in6p_ppcb : - (intptr_t) prev, sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc, - &in6pcb.in6p_laddr, in6pcb.in6p_lport, - &in6pcb.in6p_faddr, in6pcb.in6p_fport, - tcpcb.t_state, name, NULL); - + + ip6protopr0((intptr_t) pcblist[i].ki_ppcbaddr, + pcblist[i].ki_rcvq, pcblist[i].ki_sndq, + &src.sin6_addr, src.sin6_port, + &dst.sin6_addr, dst.sin6_port, + pcblist[i].ki_tstate, name, NULL); } -end: - if (istcp) { + + free(pcblist); + + if (strcmp(name, "tcp6") == 0) { struct timeval t; timebase(&t); gettimeofday(&now, NULL); @@ -1454,6 +1447,21 @@ tcp6_dump(u_long pcbaddr) { struct tcp6cb tcp6cb; int i; + struct kinfo_pcb *pcblist; + size_t j, len; + + if (use_sysctl) + pcblist = getpcblist_sysctl(name, &len); + else + pcblist = getpcblist_kmem(off, name, &len); + + for (j = 0; j < len; j++) + if (pcblist[j].ki_ppcbaddr == pcbaddr) + break; + free(pcblist); + + if (j == len) + errx(1, "0x%lx is not a valid pcb address", pcbaddr); kread(pcbaddr, (char *)&tcp6cb, sizeof(tcp6cb)); Index: src/usr.bin/netstat/main.c diff -u src/usr.bin/netstat/main.c:1.85 src/usr.bin/netstat/main.c:1.86 --- src/usr.bin/netstat/main.c:1.85 Fri Mar 1 13:26:11 2013 +++ src/usr.bin/netstat/main.c Wed Jun 19 17:12:03 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: main.c,v 1.85 2013/03/01 18:26:11 joerg Exp $ */ +/* $NetBSD: main.c,v 1.86 2013/06/19 21:12:03 christos Exp $ */ /* * Copyright (c) 1983, 1988, 1993 @@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 19 #if 0 static char sccsid[] = "from: @(#)main.c 8.4 (Berkeley) 3/1/94"; #else -__RCSID("$NetBSD: main.c,v 1.85 2013/03/01 18:26:11 joerg Exp $"); +__RCSID("$NetBSD: main.c,v 1.86 2013/06/19 21:12:03 christos Exp $"); #endif #endif /* not lint */ @@ -189,7 +189,7 @@ struct protox { void (*pr_istats) __P((const char *)); /* per/if statistics printing routine */ void (*pr_dump) /* PCB state dump routine */ - __P((u_long)); + __P((u_long, const char *, u_long)); const char *pr_name; /* well-known name */ } protox[] = { { N_TCBTABLE, N_TCPSTAT, 1, protopr, @@ -577,7 +577,8 @@ main(int argc, char *argv[]) tp = name2protox("tcp"); } if (tp->pr_dump) - (*tp->pr_dump)(pcbaddr); + (*tp->pr_dump)(nl[tp->pr_index].n_value, tp->pr_name, + pcbaddr); else printf("%s: no PCB dump routine\n", tp->pr_name); exit(0); Index: src/usr.bin/netstat/netstat.h diff -u src/usr.bin/netstat/netstat.h:1.46 src/usr.bin/netstat/netstat.h:1.47 --- src/usr.bin/netstat/netstat.h:1.46 Fri Mar 1 13:26:11 2013 +++ src/usr.bin/netstat/netstat.h Wed Jun 19 17:12:03 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: netstat.h,v 1.46 2013/03/01 18:26:11 joerg Exp $ */ +/* $NetBSD: netstat.h,v 1.47 2013/06/19 21:12:03 christos Exp $ */ /* * Copyright (c) 1992, 1993 @@ -74,7 +74,7 @@ int get_hardticks __P((void)); void protopr __P((u_long, const char *)); void tcp_stats __P((u_long, const char *)); -void tcp_dump __P((u_long)); +void tcp_dump __P((u_long, const char *, u_long)); void udp_stats __P((u_long, const char *)); void ip_stats __P((u_long, const char *)); void icmp_stats __P((u_long, const char *)); @@ -161,4 +161,6 @@ kvm_t *get_kvmd(void); char *mpls_ntoa(const struct sockaddr *); +struct kinfo_pcb *getpcblist_sysctl(const char *, size_t *); + #define PLEN (LONG_BIT / 4 + 2)