diff options
author | 2015-02-12 01:49:02 +0000 | |
---|---|---|
committer | 2015-02-12 01:49:02 +0000 | |
commit | 543e2d55756daece4cfce071d42245d5565a5694 (patch) | |
tree | 4eaf225ab1223f36e39c52c178bed563aa75d2ff | |
parent | Put the dev+ino table for cpio hardlink matching behind #ifndef NOCPIO (diff) | |
download | wireguard-openbsd-543e2d55756daece4cfce071d42245d5565a5694.tar.xz wireguard-openbsd-543e2d55756daece4cfce071d42245d5565a5694.zip |
Switch the printing of open sockets from ugly KVM internals to use
kvm_getfiles. This allows to run netstat without any extra privileges
and removes another setgid program from base..
There is still kvm reader code in there which is used for debugging
purposes (crashdump). netstat should still behave mostly the same.
deraadt@ and sthen@ agree that it is time to get this puppy in.
-rw-r--r-- | usr.bin/netstat/Makefile | 4 | ||||
-rw-r--r-- | usr.bin/netstat/inet.c | 394 | ||||
-rw-r--r-- | usr.bin/netstat/inet6.c | 5 | ||||
-rw-r--r-- | usr.bin/netstat/main.c | 241 | ||||
-rw-r--r-- | usr.bin/netstat/netstat.1 | 12 | ||||
-rw-r--r-- | usr.bin/netstat/netstat.h | 28 | ||||
-rw-r--r-- | usr.bin/netstat/route.c | 23 | ||||
-rw-r--r-- | usr.bin/netstat/unix.c | 45 |
8 files changed, 377 insertions, 375 deletions
diff --git a/usr.bin/netstat/Makefile b/usr.bin/netstat/Makefile index e30def3115a..5a6a1afaef5 100644 --- a/usr.bin/netstat/Makefile +++ b/usr.bin/netstat/Makefile @@ -1,10 +1,8 @@ -# $OpenBSD: Makefile,v 1.23 2015/02/08 02:02:21 claudio Exp $ +# $OpenBSD: Makefile,v 1.24 2015/02/12 01:49:02 claudio Exp $ PROG= netstat SRCS= if.c inet.c inet6.c main.c mbuf.c mroute.c route.c \ unix.c mroute6.c net80211.c show.c -BINGRP= kmem -BINMODE=2555 LDADD= -lkvm -lutil DPADD= ${LIBKVM} ${LIBUTIL} CFLAGS+= -Wall diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c index e1478bc23ae..1c1ac3bbd6e 100644 --- a/usr.bin/netstat/inet.c +++ b/usr.bin/netstat/inet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: inet.c,v 1.139 2015/02/08 04:40:50 yasuoka Exp $ */ +/* $OpenBSD: inet.c,v 1.140 2015/02/12 01:49:02 claudio Exp $ */ /* $NetBSD: inet.c,v 1.14 1995/10/03 21:42:37 thorpej Exp $ */ /* @@ -36,6 +36,10 @@ #include <sys/domain.h> #include <sys/protosw.h> #include <sys/sysctl.h> +#define _KERNEL +#include <sys/ucred.h> +#include <sys/file.h> +#undef _KERNEL #include <net/route.h> #include <netinet/in.h> @@ -87,9 +91,8 @@ struct tcpcb tcpcb; struct socket sockb; char *inetname(struct in_addr *); -void inetprint(struct in_addr *, in_port_t, char *, int); +void inetprint(struct in_addr *, in_port_t, const char *, int); char *inet6name(struct in6_addr *); -void inet6print(struct in6_addr *, int, char *); void sosplice_dump(u_long); void sockbuf_dump(struct sockbuf *, const char *); void protosw_dump(u_long, u_long); @@ -97,6 +100,109 @@ void domain_dump(u_long, u_long, short); void inpcb_dump(u_long, short, int); void tcpcb_dump(u_long); +int type_map[] = { -1, 2, 3, 1, 4, 5 }; + +int +kf_comp(const void *a, const void *b) +{ + const struct kinfo_file *ka = a, *kb = b; + + if (ka->so_family != kb->so_family) { + /* AF_INET < AF_INET6 < AF_LOCAL */ + if (ka->so_family == AF_INET) + return (-1); + if (ka->so_family == AF_LOCAL) + return (1); + if (kb->so_family == AF_LOCAL) + return (-1); + return (1); + } + if (ka->so_family == AF_LOCAL) { + if (type_map[ka->so_type] < type_map[kb->so_type]) + return (-1); + if (type_map[ka->so_type] > type_map[kb->so_type]) + return (1); + } else if (ka->so_family == AF_INET || ka->so_family == AF_INET6) { + if (ka->so_protocol < kb->so_protocol) + return (-1); + if (ka->so_protocol > kb->so_protocol) + return (1); + if (ka->so_type == SOCK_DGRAM || ka->so_type == SOCK_STREAM) { + /* order sockets by remote port desc */ + if (ka->inp_fport > kb->inp_fport) + return (-1); + if (ka->inp_fport < kb->inp_fport) + return (1); + } else if (ka->so_type == SOCK_RAW) { + if (ka->inp_proto > kb->inp_proto) + return (-1); + if (ka->inp_proto < kb->inp_proto) + return (1); + } + } + return (0); +} + +void +protopr(kvm_t *kvmd, u_long pcbaddr, u_int tableid, int proto) +{ + struct kinfo_file *kf; + int i, fcnt; + + kf = kvm_getfiles(kvmd, KERN_FILE_BYFILE, DTYPE_SOCKET, + sizeof(*kf), &fcnt); + if (kf == NULL) { + printf("Out of memory (file table).\n"); + return; + } + + /* sort sockets by AF and type */ + qsort(kf, fcnt, sizeof(*kf), kf_comp); + + for (i = 0; i < fcnt; i++) { + if (Pflag) { + switch (kf[i].so_family) { + case AF_INET: + case AF_INET6: + /* + * XXX at the moment fstat returns the pointer + * to the so_pcb or for tcp sockets the tcpcb + * pointer (inp_ppcb) so check both. + */ + if (pcbaddr == kf[i].so_pcb) { + inpcb_dump(pcbaddr, kf[i].so_protocol, + kf[i].so_family); + return; + } else if (pcbaddr == kf[i].inp_ppcb && + kf[i].so_protocol == IPPROTO_TCP) { + tcpcb_dump(pcbaddr); + return; + } + break; + case AF_UNIX: + if (pcbaddr == kf[i].so_pcb) { + unpcb_dump(pcbaddr); + return; + } + break; + } + continue; + } + if (kf[i].so_family == AF_LOCAL && (kf[i].so_pcb != 0 || + kf[i].unp_path[0] != '\0')) + if ((af == AF_LOCAL || af == AF_UNSPEC) && !proto) + unixdomainpr(&kf[i]); + if (kf[i].so_family == AF_INET && kf[i].so_pcb != 0 && + kf[i].inp_rtableid == tableid) + if (af == AF_INET || af == AF_UNSPEC) + netdomainpr(&kf[i], proto); + if (kf[i].so_family == AF_INET6 && kf[i].so_pcb != 0 && + kf[i].inp_rtableid == tableid) + if (af == AF_INET6 || af == AF_UNSPEC) + netdomainpr(&kf[i], proto); + } +} + /* * Print a summary of connections related to an Internet * protocol. For TCP, also give state of connection. @@ -104,144 +210,136 @@ void tcpcb_dump(u_long); * -a (all) flag is specified. */ void -protopr(u_long off, char *name, int af, u_int tableid, u_long pcbaddr) +netdomainpr(struct kinfo_file *kf, int proto) { - struct inpcbtable table; - struct inpcb *prev, *next; - struct inpcb inpcb, prevpcb; - int istcp, israw, isany; + static int af = 0, type = 0; + struct in_addr laddr, faddr; + struct in6_addr laddr6, faddr6; + const char *name, *name6; int addrlen = 22; - int first = 1; - char *name0; - char namebuf[20]; + int isany = 0; + int istcp = 0; + int isip6 = 0; - name0 = name; - if (off == 0) - return; - istcp = strcmp(name, "tcp") == 0; - israw = strncmp(name, "ip", 2) == 0; - kread(off, &table, sizeof table); - prev = NULL; - next = TAILQ_FIRST(&table.inpt_queue); - - while (next != NULL) { - kread((u_long)next, &inpcb, sizeof inpcb); - if (prev != NULL) { - kread((u_long)prev, &prevpcb, sizeof prevpcb); - if (TAILQ_NEXT(&prevpcb, inp_queue) != next) { - printf("PCB list changed\n"); - break; - } - } - prev = next; - next = TAILQ_NEXT(&inpcb, inp_queue); + /* XXX should fix kinfo_file instead but not now */ + if (kf->so_pcb == -1) + kf->so_pcb = 0; - switch (af) { - case AF_INET: - if ((inpcb.inp_flags & INP_IPV6) != 0) - continue; - isany = inet_lnaof(inpcb.inp_faddr) == INADDR_ANY; - break; - case AF_INET6: - if ((inpcb.inp_flags & INP_IPV6) == 0) - continue; - isany = IN6_IS_ADDR_UNSPECIFIED(&inpcb.inp_faddr6); - break; - default: - isany = 0; - break; - } + switch (proto) { + case IPPROTO_TCP: + case IPPROTO_UDP: + case IPPROTO_DIVERT: + if (kf->so_protocol != proto) + return; + break; + case IPPROTO_IPV4: + if (kf->so_type != SOCK_RAW || kf->so_family != AF_INET) + return; + break; + case IPPROTO_IPV6: + if (kf->so_type != SOCK_RAW || kf->so_family != AF_INET6) + return; + break; + } - if (Pflag) { - if (istcp && pcbaddr == (u_long)inpcb.inp_ppcb) { - if (vflag) - socket_dump((u_long)inpcb.inp_socket); - else - tcpcb_dump(pcbaddr); - } else if (pcbaddr == (u_long)prev) { - if (vflag) - socket_dump((u_long)inpcb.inp_socket); - else - inpcb_dump(pcbaddr, 0, af); - } - continue; - } + /* make in_addr6 access a bit easier */ +#define s6_addr32 __u6_addr.__u6_addr32 + laddr.s_addr = kf->inp_laddru[0]; + laddr6.s6_addr32[0] = kf->inp_laddru[0]; + laddr6.s6_addr32[1] = kf->inp_laddru[1]; + laddr6.s6_addr32[2] = kf->inp_laddru[2]; + laddr6.s6_addr32[3] = kf->inp_laddru[3]; + + faddr.s_addr = kf->inp_faddru[0]; + faddr6.s6_addr32[0] = kf->inp_faddru[0]; + faddr6.s6_addr32[1] = kf->inp_faddru[1]; + faddr6.s6_addr32[2] = kf->inp_faddru[2]; + faddr6.s6_addr32[3] = kf->inp_faddru[3]; +#undef s6_addr32 + + switch (kf->so_family) { + case AF_INET: + isany = faddr.s_addr == INADDR_ANY; + break; + case AF_INET6: + isany = IN6_IS_ADDR_UNSPECIFIED(&faddr6); + isip6 = 1; + break; + } - if (inpcb.inp_rtableid != tableid) - continue; + switch (kf->so_protocol) { + case IPPROTO_TCP: + name = "tcp"; + name6 = "tcp6"; + istcp = 1; + break; + case IPPROTO_UDP: + name = "udp"; + name6 = "udp6"; + break; + case IPPROTO_DIVERT: + name = "divert"; + name6 = "divert6"; + break; + default: + name = "ip"; + name6 = "ip6"; + break; + } - kread((u_long)inpcb.inp_socket, &sockb, sizeof (sockb)); - if (istcp) { - kread((u_long)inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb)); - if (!aflag && tcpcb.t_state <= TCPS_LISTEN) - continue; - } else if (!aflag && isany) - continue; - if (first) { - printf("Active Internet connections"); - if (aflag) - printf(" (including servers)"); - putchar('\n'); - if (Aflag) { - addrlen = 18; - printf("%-*.*s ", PLEN, PLEN, "PCB"); - } - printf("%-7.7s %-6.6s %-6.6s ", - "Proto", "Recv-Q", "Send-Q"); - if (Bflag && istcp) - printf("%-6.6s %-6.6s %-6.6s ", - "Recv-W", "Send-W", "Cgst-W"); - printf(" %-*.*s %-*.*s %s\n", - addrlen, addrlen, "Local Address", - addrlen, addrlen, "Foreign Address", "(state)"); - first = 0; - } + /* filter listening sockets out unless -a is set */ + if (!aflag && istcp && kf->t_state <= TCPS_LISTEN) + return; + else if (!aflag && isany) + return; + + if (af != kf->so_family || type != kf->so_type) { + af = kf->so_family; + type = kf->so_type; + printf("Active Internet connections"); + if (aflag) + printf(" (including servers)"); + putchar('\n'); if (Aflag) { - if (istcp) - printf("%*p ", PLEN, hideroot ? 0 : inpcb.inp_ppcb); - else - printf("%*p ", PLEN, hideroot ? 0 : prev); + addrlen = 18; + printf("%-*.*s ", PLEN, PLEN, "PCB"); } - if (inpcb.inp_flags & INP_IPV6 && !israw) { - strlcpy(namebuf, name0, sizeof namebuf); - strlcat(namebuf, "6", sizeof namebuf); - name = namebuf; - } else - name = name0; - printf("%-7.7s %6lu %6lu ", - name, sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc); + printf("%-7.7s %-6.6s %-6.6s ", + "Proto", "Recv-Q", "Send-Q"); if (Bflag && istcp) - printf("%6lu %6lu %6lu ", tcpcb.rcv_wnd, tcpcb.snd_wnd, - (tcpcb.t_state == TCPS_ESTABLISHED) ? - tcpcb.snd_cwnd : 0); - - if (inpcb.inp_flags & INP_IPV6) { - inet6print(&inpcb.inp_laddr6, (int)inpcb.inp_lport, - name); - inet6print(&inpcb.inp_faddr6, (int)inpcb.inp_fport, - name); - } else { - inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport, - name, 1); - inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport, - name, 0); - } - if (istcp) { - if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES) - printf(" %d", tcpcb.t_state); - else - printf(" %s", tcpstates[tcpcb.t_state]); - } else if (israw) { - u_int8_t proto; + printf("%-6.6s %-6.6s %-6.6s ", + "Recv-W", "Send-W", "Cgst-W"); + printf(" %-*.*s %-*.*s %s\n", + addrlen, addrlen, "Local Address", + addrlen, addrlen, "Foreign Address", "(state)"); + } - if (inpcb.inp_flags & INP_IPV6) - proto = inpcb.inp_ipv6.ip6_nxt; - else - proto = inpcb.inp_ip.ip_p; - printf(" %u", proto); - } - putchar('\n'); + if (Aflag) + printf("%#*llx%s ", FAKE_PTR(kf->so_pcb)); + + printf("%-7.7s %6llu %6llu ", + isip6 ? name6: name, kf->so_rcv_cc, kf->so_snd_cc); + if (Bflag && istcp) + printf("%6llu %6llu %6llu ", kf->t_rcv_wnd, kf->t_snd_wnd, + (kf->t_state == TCPS_ESTABLISHED) ? + kf->t_snd_cwnd : 0); + + if (isip6) { + inet6print(&laddr6, kf->inp_lport, name); + inet6print(&faddr6, kf->inp_fport, name); + } else { + inetprint(&laddr, kf->inp_lport, name, 1); + inetprint(&faddr, kf->inp_fport, name, 0); + } + if (istcp) { + if (kf->t_state < 0 || kf->t_state >= TCP_NSTATES) + printf(" %d", kf->t_state); + else + printf(" %s", tcpstates[kf->t_state]); + } else if (kf->so_type == SOCK_RAW) { + printf(" %u", kf->inp_proto); } + putchar('\n'); } /* @@ -767,7 +865,7 @@ getrpcportnam(in_port_t port, int proto) * If the nflag was specified, use numbers instead of names. */ void -inetprint(struct in_addr *in, in_port_t port, char *proto, int local) +inetprint(struct in_addr *in, in_port_t port, const char *proto, int local) { struct servent *sp = 0; char line[80], *cp, *nam; @@ -1167,8 +1265,8 @@ socket_dump(u_long off) kread(off, &so, sizeof(so)); #define p(fmt, v, sep) printf(#v " " fmt sep, so.v); -#define pp(fmt, v, sep) printf(#v " " fmt sep, hideroot ? 0 : so.v); - printf("socket %#lx\n ", hideroot ? 0 : off); +#define pp(fmt, v, sep) printf(#v " " fmt sep, so.v); + printf("socket %#lx\n ", off); p("%#.4x", so_type, "\n "); p("%#.4x", so_options, "\n "); p("%d", so_linger, "\n "); @@ -1197,8 +1295,6 @@ socket_dump(u_long off) #undef p #undef pp - if (!vflag) - return; protosw_dump((u_long)so.so_proto, (u_long)so.so_pcb); } @@ -1216,7 +1312,7 @@ sosplice_dump(u_long off) #define p(fmt, v, sep) printf(#v " " fmt sep, ssp.v); #define pll(fmt, v, sep) printf(#v " " fmt sep, (long long) ssp.v); -#define pp(fmt, v, sep) printf(#v " " fmt sep, hideroot ? 0 : ssp.v); +#define pp(fmt, v, sep) printf(#v " " fmt sep, ssp.v); pp("%p", ssp_socket, ", "); pp("%p", ssp_soback, "\n "); p("%lld", ssp_len, ", "); @@ -1264,8 +1360,8 @@ protosw_dump(u_long off, u_long pcb) kread(off, &proto, sizeof(proto)); #define p(fmt, v, sep) printf(#v " " fmt sep, proto.v); -#define pp(fmt, v, sep) printf(#v " " fmt sep, hideroot ? 0 : proto.v); - printf("protosw %#lx\n ", hideroot ? 0 : off); +#define pp(fmt, v, sep) printf(#v " " fmt sep, proto.v); + printf("protosw %#lx\n ", off); p("%#.4x", pr_type, "\n "); pp("%p", pr_domain, "\n "); p("%d", pr_protocol, "\n "); @@ -1291,20 +1387,10 @@ domain_dump(u_long off, u_long pcb, short protocol) kread((u_long)dom.dom_name, name, sizeof(name)); #define p(fmt, v, sep) printf(#v " " fmt sep, dom.v); - printf("domain %#lx\n ", hideroot ? 0 : off); + printf("domain %#lx\n ", off); p("%d", dom_family, "\n "); printf("dom_name %.*s\n", (int)sizeof(name), name); #undef p - - switch (dom.dom_family) { - case AF_INET: - case AF_INET6: - inpcb_dump(pcb, protocol, dom.dom_family); - break; - case AF_UNIX: - unpcb_dump(pcb); - break; - } } /* @@ -1319,6 +1405,10 @@ inpcb_dump(u_long off, short protocol, int af) if (off == 0) return; kread(off, &inp, sizeof(inp)); + + if (vflag) + socket_dump((u_long)inp.inp_socket); + switch (af) { case AF_INET: inet_ntop(af, &inp.inp_faddr, faddr, sizeof(faddr)); @@ -1333,8 +1423,8 @@ inpcb_dump(u_long off, short protocol, int af) } #define p(fmt, v, sep) printf(#v " " fmt sep, inp.v); -#define pp(fmt, v, sep) printf(#v " " fmt sep, hideroot ? 0 : inp.v); - printf("inpcb %#lx\n ", hideroot ? 0 : off); +#define pp(fmt, v, sep) printf(#v " " fmt sep, inp.v); + printf("inpcb %#lx\n ", off); pp("%p", inp_table, "\n "); printf("inp_faddru %s, inp_laddru %s\n ", faddr, laddr); HTONS(inp.inp_fport); @@ -1385,8 +1475,8 @@ tcpcb_dump(u_long off) kread(off, (char *)&tcpcb, sizeof (tcpcb)); #define p(fmt, v, sep) printf(#v " " fmt sep, tcpcb.v); -#define pp(fmt, v, sep) printf(#v " " fmt sep, hideroot ? 0 : tcpcb.v); - printf("tcpcb %#lx\n ", hideroot ? 0 : off); +#define pp(fmt, v, sep) printf(#v " " fmt sep, tcpcb.v); + printf("tcpcb %#lx\n ", off); pp("%p", t_inpcb, "\n "); p("%d", t_state, ""); if (tcpcb.t_state >= 0 && tcpcb.t_state < TCP_NSTATES) diff --git a/usr.bin/netstat/inet6.c b/usr.bin/netstat/inet6.c index 124e28cd57a..9ed44b10bc9 100644 --- a/usr.bin/netstat/inet6.c +++ b/usr.bin/netstat/inet6.c @@ -1,4 +1,4 @@ -/* $OpenBSD: inet6.c,v 1.47 2015/01/16 06:40:10 deraadt Exp $ */ +/* $OpenBSD: inet6.c,v 1.48 2015/02/12 01:49:02 claudio Exp $ */ /* BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp */ /* * Copyright (c) 1983, 1988, 1993 @@ -66,7 +66,6 @@ struct socket sockb; char *inet6name(struct in6_addr *); -void inet6print(struct in6_addr *, int, char *); static char *ip6nh[] = { "hop by hop", @@ -1063,7 +1062,7 @@ div6_stats(char *name) */ void -inet6print(struct in6_addr *in6, int port, char *proto) +inet6print(struct in6_addr *in6, int port, const char *proto) { #define GETSERVBYPORT6(port, proto, ret) do { \ diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c index 41661ead9f6..78514d583a3 100644 --- a/usr.bin/netstat/main.c +++ b/usr.bin/netstat/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.105 2015/02/09 12:25:03 claudio Exp $ */ +/* $OpenBSD: main.c,v 1.106 2015/02/12 01:49:02 claudio Exp $ */ /* $NetBSD: main.c,v 1.9 1996/05/07 02:55:02 thorpej Exp $ */ /* @@ -54,80 +54,59 @@ #include "netstat.h" struct nlist nl[] = { -#define N_TCBTABLE 0 - { "_tcbtable" }, -#define N_UDBTABLE 1 - { "_udbtable" }, - -#define N_RTREE 7 +#define N_RTREE 0 { "_rt_tables"}, -#define N_RTMASK 8 +#define N_RTMASK 1 { "_mask_rnhead" }, -#define N_AF2RTAFIDX 9 +#define N_AF2RTAFIDX 2 { "_af2rtafidx" }, -#define N_RTBLIDMAX 10 +#define N_RTBLIDMAX 3 { "_rtbl_id_max" }, -#define N_RAWIPTABLE 11 - { "_rawcbtable" }, -#define N_RAWIP6TABLE 12 - { "_rawin6pcbtable" }, -#define N_DIVBTABLE 13 - { "_divbtable" }, -#define N_DIVB6TABLE 14 - { "_divb6table" }, - { "" } }; struct protox { - u_char pr_index; /* index into nlist of cb head */ - void (*pr_cblocks)(u_long, char *, int, u_int, u_long); - /* control blocks printing routine */ void (*pr_stats)(char *); /* statistics printing routine */ char *pr_name; /* well-known name */ + int pr_proto; /* protocol number */ } protox[] = { - { N_TCBTABLE, protopr, tcp_stats, "tcp" }, - { N_UDBTABLE, protopr, udp_stats, "udp" }, - { N_RAWIPTABLE, protopr, ip_stats, "ip" }, - { N_DIVBTABLE, protopr, div_stats, "divert" }, - { -1, NULL, icmp_stats, "icmp" }, - { -1, NULL, igmp_stats, "igmp" }, - { -1, NULL, ah_stats, "ah" }, - { -1, NULL, esp_stats, "esp" }, - { -1, NULL, ipip_stats, "ipencap" }, - { -1, NULL, etherip_stats, "etherip" }, - { -1, NULL, ipcomp_stats, "ipcomp" }, - { -1, NULL, carp_stats, "carp" }, - { -1, NULL, pfsync_stats, "pfsync" }, - { -1, NULL, pim_stats, "pim" }, - { -1, NULL, pflow_stats, "pflow" }, - { -1, NULL, NULL, NULL } + { ip_stats, "ip", IPPROTO_IPV4 }, + { icmp_stats, "icmp", 0 }, + { igmp_stats, "igmp", 0 }, + { ipip_stats, "ipencap", 0 }, + { tcp_stats, "tcp", IPPROTO_TCP }, + { udp_stats, "udp", IPPROTO_UDP }, + { esp_stats, "esp", 0 }, + { ah_stats, "ah", 0 }, + { etherip_stats,"etherip", 0 }, + { ipcomp_stats, "ipcomp", 0 }, + { carp_stats, "carp", 0 }, + { pfsync_stats, "pfsync", 0 }, + { div_stats, "divert", IPPROTO_DIVERT }, + { pim_stats, "pim", 0 }, + { pflow_stats, "pflow", 0 }, + { NULL, NULL, 0 } }; struct protox ip6protox[] = { - { N_TCBTABLE, protopr, NULL, "tcp" }, - { N_UDBTABLE, protopr, NULL, "udp" }, - { N_RAWIP6TABLE,protopr, ip6_stats, "ip6" }, - { N_DIVB6TABLE, protopr, div6_stats, "divert6" }, - { -1, NULL, icmp6_stats, "icmp6" }, - { -1, NULL, pim6_stats, "pim6" }, - { -1, NULL, rip6_stats, "rip6" }, - { -1, NULL, NULL, NULL } + { ip6_stats, "ip6", IPPROTO_IPV6 }, + { div6_stats, "divert6", IPPROTO_DIVERT }, + { icmp6_stats, "icmp6", 0 }, + { pim6_stats, "pim6", 0 }, + { rip6_stats, "rip6", 0 }, + { NULL, NULL, 0 } }; struct protox *protoprotox[] = { protox, ip6protox, NULL }; -static void printproto(struct protox *, char *, int, u_int, u_long); static void usage(void); static struct protox *name2protox(char *); static struct protox *knownname(char *); u_int gettable(const char *); -int hideroot; - kvm_t *kvmd; int @@ -136,20 +115,17 @@ main(int argc, char *argv[]) extern char *optarg; extern int optind; const char *errstr; - struct protoent *p; struct protox *tp = NULL; /* for printing cblocks & stats */ int ch; char *nlistf = NULL, *memf = NULL, *ep; char buf[_POSIX2_LINE_MAX]; - gid_t gid; u_long pcbaddr = 0; u_int tableid; int Tflag = 0; int repeatcount = 0; + int proto = 0; int need_nlist; - hideroot = getuid(); - af = AF_UNSPEC; tableid = getrtable(); @@ -190,8 +166,6 @@ main(int argc, char *argv[]) af = AF_UNIX; else if (strcmp(optarg, "mpls") == 0) af = AF_MPLS; - else if (strcmp(optarg, "pflow") == 0) - af = PF_PFLOW; else if (strcmp(optarg, "mask") == 0) af = 0xff; else { @@ -289,17 +263,6 @@ main(int argc, char *argv[]) argv += optind; argc -= optind; - /* - * Show per-interface statistics which don't need access to - * kernel memory (they're using IOCTLs) - */ - if (Wflag) { - if (interface == NULL) - usage(); - net80211_ifstats(interface); - exit(0); - } - #define BACKWARD_COMPATIBILITY #ifdef BACKWARD_COMPATIBILITY if (*argv) { @@ -318,122 +281,90 @@ main(int argc, char *argv[]) } #endif - need_nlist = !mflag && (pflag || nlistf != NULL || memf != NULL || - (!iflag && !sflag && !gflag && (rflag ? Aflag : - (af != AF_UNIX || Pflag)))); - /* - * Discard setgid privileges if not the running kernel so that bad - * guys can't print interesting stuff from kernel memory. - * Dumping PCB info is also restricted. + * Show per-interface statistics which don't need access to + * kernel memory (they're using IOCTLs) */ - gid = getgid(); - if (nlistf != NULL || memf != NULL || Pflag) - if (setresgid(gid, gid, gid) == -1) - err(1, "setresgid"); - - if ((kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY | - (need_nlist ? 0 : KVM_NO_FILES), buf)) == NULL) { - fprintf(stderr, "%s: kvm_openfiles: %s\n", __progname, buf); - exit(1); + if (Wflag) { + if (interface == NULL) + usage(); + net80211_ifstats(interface); + exit(0); } - if (nlistf == NULL && memf == NULL && !Pflag) - if (setresgid(gid, gid, gid) == -1) - err(1, "setresgid"); - - if (need_nlist && (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0)) { - if (nlistf) - fprintf(stderr, "%s: %s: no namelist\n", __progname, - nlistf); - else - fprintf(stderr, "%s: no namelist\n", __progname); - exit(1); - } if (mflag) { mbpr(); exit(0); } - if (pflag) { - printproto(tp, tp->pr_name, af, tableid, pcbaddr); - exit(0); - } if (iflag) { intpr(interval, repeatcount); exit(0); } - if (rflag) { - if (sflag) + if (sflag) { + if (rflag) { rt_stats(); - else 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); - else - p_rttables(af, tableid); - exit(0); - } - if (gflag) { - if (sflag) { + } else if (gflag) { if (af == AF_INET || af == AF_UNSPEC) mrt_stats(); if (af == AF_INET6 || af == AF_UNSPEC) mrt6_stats(); + } else if (pflag && tp->pr_name) { + (*tp->pr_stats)(tp->pr_name); } else { if (af == AF_INET || af == AF_UNSPEC) - mroutepr(); + for (tp = protox; tp->pr_name; tp++) + (*tp->pr_stats)(tp->pr_name); if (af == AF_INET6 || af == AF_UNSPEC) - mroute6pr(); + for (tp = ip6protox; tp->pr_name; tp++) + (*tp->pr_stats)(tp->pr_name); } exit(0); } - if (af == AF_INET || af == AF_UNSPEC) { - setprotoent(1); - setservent(1); - /* ugh, this is O(MN) ... why do we do this? */ - while ((p = getprotoent())) { - for (tp = protox; tp->pr_name; tp++) - if (strcmp(tp->pr_name, p->p_name) == 0) - break; - if (tp->pr_name == 0) - continue; - printproto(tp, p->p_name, AF_INET, tableid, pcbaddr); - } - endprotoent(); + if (gflag) { + if (af == AF_INET || af == AF_UNSPEC) + mroutepr(); + if (af == AF_INET6 || af == AF_UNSPEC) + mroute6pr(); + exit(0); } - if (af == PF_PFLOW || af == AF_UNSPEC) { - tp = name2protox("pflow"); - printproto(tp, tp->pr_name, af, tableid, pcbaddr); + + /* + * The remaining code may need kvm so lets try to open it. + * -r and -P are the only bits left that actually can use this. + */ + need_nlist = nlistf != NULL || memf != NULL || Pflag || (Aflag && rflag); + + if ((kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY | + (need_nlist ? 0 : KVM_NO_FILES), buf)) == NULL) + errx(1, "kvm_openfiles: %s", buf); + + if (need_nlist && (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0)) { + if (nlistf) + errx(1, "%s: no namelist", nlistf); + else + errx(1, "no namelist"); } - if (af == AF_INET6 || af == AF_UNSPEC) - for (tp = ip6protox; tp->pr_name; tp++) - printproto(tp, tp->pr_name, AF_INET6, tableid, - pcbaddr); - if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) - unixpr(kvmd, pcbaddr); - exit(0); -} -/* - * Print out protocol statistics or control blocks (per sflag). - * If the interface was not specifically requested, and the symbol - * is not in the namelist, ignore this one. - */ -static void -printproto(struct protox *tp, char *name, int af, u_int tableid, - u_long pcbaddr) -{ - if (sflag) { - if (tp->pr_stats != NULL) - (*tp->pr_stats)(name); - } else { - u_char i = tp->pr_index; - if (tp->pr_cblocks != NULL && - i < sizeof(nl) / sizeof(nl[0]) && - (nl[i].n_value || af != AF_UNSPEC)) - (*tp->pr_cblocks)(nl[i].n_value, name, af, tableid, - pcbaddr); + 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); + else + p_rttables(af, tableid); + exit(0); } + + if (pflag) { + if (tp->pr_proto == 0) + errx(1, "no protocol handler for protocol %s", + tp->pr_name); + else + proto = tp->pr_proto; + } + + protopr(kvmd, pcbaddr, tableid, proto); + exit(0); } /* diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1 index a94d9139c95..ec7d899c401 100644 --- a/usr.bin/netstat/netstat.1 +++ b/usr.bin/netstat/netstat.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: netstat.1,v 1.74 2015/02/08 04:29:53 claudio Exp $ +.\" $OpenBSD: netstat.1,v 1.75 2015/02/12 01:49:02 claudio Exp $ .\" $NetBSD: netstat.1,v 1.11 1995/10/03 21:42:43 thorpej Exp $ .\" .\" Copyright (c) 1983, 1990, 1992, 1993 @@ -30,7 +30,7 @@ .\" .\" from: @(#)netstat.1 8.8 (Berkeley) 4/18/94 .\" -.Dd $Mdocdate: February 8 2015 $ +.Dd $Mdocdate: February 12 2015 $ .Dt NETSTAT 1 .Os .Sh NAME @@ -110,6 +110,10 @@ show the address of any protocol control blocks associated with sockets; used for debugging, e.g. with the .Fl P flag. +When used with the +.Fl -r +flag it shows the internal pointers of the routing table. +Only the super-user can use this option. .It Fl a With the default display, show the state of all sockets; normally sockets used by @@ -155,7 +159,6 @@ The following address families are recognized: .It "inet6" Ta Dv "AF_INET6" Ta "IP Version 6" .It "local" Ta Dv "AF_LOCAL" Ta "Local to Host (i.e., pipes)" .It "mpls" Ta Dv "AF_MPLS" Ta "MPLS" -.It "pflow" Ta Dv "PF_FLOW" Ta "pflow data export" .It "unix" Ta Dv "AF_UNIX" Ta "Local to Host (i.e., pipes)" .El .It Fl h @@ -219,7 +222,7 @@ interprets addresses and attempts to display them symbolically). This option may be used with any of the display formats. .It Fl P Ar pcbaddr -Display the contents of the socket or protocol control block (PCB) +Display the contents of the protocol control block (PCB) located at the kernel virtual address .Ar pcbaddr . PCB addresses can be obtained using the @@ -228,6 +231,7 @@ flag. When used with the .Fl v option, also print socket, domain and protocol specific structures. +Only the super-user can use this option. .It Fl p Ar protocol Restrict the output to .Ar protocol , diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h index bbc6efd2c00..9407b645036 100644 --- a/usr.bin/netstat/netstat.h +++ b/usr.bin/netstat/netstat.h @@ -1,4 +1,4 @@ -/* $OpenBSD: netstat.h,v 1.67 2015/02/09 12:25:03 claudio Exp $ */ +/* $OpenBSD: netstat.h,v 1.68 2015/02/12 01:49:02 claudio Exp $ */ /* $NetBSD: netstat.h,v 1.6 1996/05/07 02:55:05 thorpej Exp $ */ /* @@ -37,6 +37,9 @@ /* What is the max length of a pointer printed with %p (including 0x)? */ #define PLEN (LONG_BIT / 4 + 2) +/* a bit of magic to print addresses as they should */ +#define FAKE_PTR(p) (PLEN - ((p) ? 0 : 2)), p, ((p) ? "" : "x0") + int Aflag; /* show addresses of protocol control block */ int aflag; /* show all sockets (including servers) */ int Bflag; /* show TCP send and receive buffer sizes */ @@ -66,13 +69,19 @@ int af; /* address family */ extern char *__progname; /* program name, from crt0.o */ -extern int hideroot; - int kread(u_long addr, void *buf, int size); char *plural(u_int64_t); char *plurales(u_int64_t); -void protopr(u_long, char *, int, u_int, u_long); +void protopr(kvm_t *, u_long, u_int, int); + +struct kinfo_file; +void netdomainpr(struct kinfo_file *, int); +void unixdomainpr(struct kinfo_file *); + +void socket_dump(u_long); +void unpcb_dump(u_long); + void tcp_stats(char *); void udp_stats(char *); void ip_stats(char *); @@ -91,9 +100,6 @@ void ipcomp_stats(char *); void net80211_ifstats(char *); -void socket_dump(u_long); -void unpcb_dump(u_long); - void mbpr(void); void hostpr(u_long, u_long); @@ -104,8 +110,6 @@ void pr_rthdr(int, int); void pr_encaphdr(void); void pr_family(int); -struct in6_addr; -struct sockaddr_in6; void ip6_stats(char *); void ip6_ifstats(char *); void icmp6_stats(char *); @@ -115,6 +119,10 @@ void div6_stats(char *); void rip6_stats(char *); void mroute6pr(void); void mrt6_stats(void); + +struct in6_addr; +struct sockaddr_in6; +void inet6print(struct in6_addr *, int, const char *); char *routename6(struct sockaddr_in6 *); char *netname6(struct sockaddr_in6 *, struct sockaddr_in6 *); @@ -135,7 +143,5 @@ void nsprotopr(u_long, char *); void intpr(int, int); -void unixpr(kvm_t *, u_long); - void mroutepr(void); void mrt_stats(void); diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c index a3aea57ef3c..09b2306456a 100644 --- a/usr.bin/netstat/route.c +++ b/usr.bin/netstat/route.c @@ -1,4 +1,4 @@ -/* $OpenBSD: route.c,v 1.97 2015/02/06 03:22:00 reyk Exp $ */ +/* $OpenBSD: route.c,v 1.98 2015/02/12 01:49:02 claudio Exp $ */ /* $NetBSD: route.c,v 1.15 1996/05/07 02:55:06 thorpej Exp $ */ /* @@ -166,7 +166,7 @@ again: kread((u_long)rn, &rnode, sizeof(rnode)); if (rnode.rn_b < 0) { if (Aflag) - printf("%-16p ", hideroot ? 0 : rn); + printf("%-16p ", rn); if (rnode.rn_flags & RNF_ROOT) { if (Aflag) printf("(root node)%s", @@ -185,7 +185,7 @@ again: goto again; } else { if (Aflag && do_rtent) { - printf("%-16p ", hideroot ? 0 : rn); + printf("%-16p ", rn); p_rtnode(); } rn = rnode.rn_r; @@ -217,10 +217,8 @@ p_rtnode(void) struct radix_mask *rm = rnode.rn_mklist; if (rnode.rn_b < 0) { - snprintf(nbuf, sizeof nbuf, " => %p", - hideroot ? 0 : rnode.rn_dupedkey); - printf("\t (%p)%s", hideroot ? 0 : rnode.rn_p, - rnode.rn_dupedkey ? nbuf : ""); + 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), @@ -232,9 +230,7 @@ p_rtnode(void) } else { snprintf(nbuf, sizeof nbuf, "(%d)", rnode.rn_b); printf("%6.6s (%p) %16p : %16p", nbuf, - hideroot ? 0 : rnode.rn_p, - hideroot ? 0 : rnode.rn_l, - hideroot ? 0 : rnode.rn_r); + rnode.rn_p, rnode.rn_l, rnode.rn_r); } putchar(' '); @@ -243,15 +239,14 @@ p_rtnode(void) while (rm) { kread((u_long)rm, &rmask, sizeof(rmask)); snprintf(nbuf, sizeof nbuf, " %d refs, ", rmask.rm_refs); - printf("\n\tmk = %p {(%d),%s", - hideroot ? 0 : rm, - -1 - rmask.rm_b, rmask.rm_refs ? nbuf : " "); + 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 ", hideroot ? 0 : rmask.rm_leaf); + 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); diff --git a/usr.bin/netstat/unix.c b/usr.bin/netstat/unix.c index 27ed2816812..fbf98ca2eaa 100644 --- a/usr.bin/netstat/unix.c +++ b/usr.bin/netstat/unix.c @@ -1,4 +1,4 @@ -/* $OpenBSD: unix.c,v 1.25 2015/01/20 18:26:57 deraadt Exp $ */ +/* $OpenBSD: unix.c,v 1.26 2015/02/12 01:49:02 claudio Exp $ */ /* $NetBSD: unix.c,v 1.13 1995/10/03 21:42:48 thorpej Exp $ */ /*- @@ -53,40 +53,17 @@ #include <kvm.h> #include "netstat.h" -static void unixdomainpr(const struct kinfo_file *, u_long); - -void -unixpr(kvm_t *kvmd, u_long pcbaddr) -{ - struct kinfo_file *kf; - int i, fcnt; - - kf = kvm_getfiles(kvmd, KERN_FILE_BYFILE, 0, sizeof(*kf), &fcnt); - if (kf == NULL) { - printf("Out of memory (file table).\n"); - return; - } - for (i = 0; i < fcnt; i++) { - if (kf[i].f_count != 0 && kf[i].f_type == DTYPE_SOCKET && - kf[i].so_family == AF_LOCAL && (kf[i].so_pcb != 0 || - kf[i].unp_path[0] != '\0')) - unixdomainpr(&kf[i], pcbaddr); - } -} - static const char *socktype[] = { "#0", "stream", "dgram", "raw", "rdm", "seqpacket" }; -static void -unixdomainpr(const struct kinfo_file *kf, u_long pcbaddr) +void +unixdomainpr(struct kinfo_file *kf) { static int first = 1; - if (Pflag) { - if (pcbaddr == kf->f_data) - socket_dump(pcbaddr); - return; - } + /* XXX should fix kinfo_file instead but not now */ + if (kf->so_pcb == -1) + kf->so_pcb = 0; if (first) { printf("Active UNIX domain sockets\n"); @@ -97,9 +74,8 @@ unixdomainpr(const struct kinfo_file *kf, u_long pcbaddr) first = 0; } -#define FAKE_PTR(p) (PLEN - ((p) ? 0 : 2)), p, ((p) ? "" : "x0") printf("%#*llx%s %-6.6s %6llu %6llu %#*llx%s %#*llx%s %#*llx%s %#*llx%s", - FAKE_PTR(kf->f_data), socktype[kf->so_type], + FAKE_PTR(kf->so_pcb), socktype[kf->so_type], kf->so_rcv_cc, kf->so_snd_cc, FAKE_PTR(kf->v_un), FAKE_PTR(kf->unp_conn), @@ -122,11 +98,14 @@ unpcb_dump(u_long off) return; kread(off, &unp, sizeof(unp)); + if (vflag) + socket_dump((u_long)unp.unp_socket); + #define p(fmt, v, sep) printf(#v " " fmt sep, unp.v); #define pll(fmt, v, sep) printf(#v " " fmt sep, (long long) unp.v); #define pull(fmt, v, sep) printf(#v " " fmt sep, (unsigned long long) unp.v); -#define pp(fmt, v, sep) printf(#v " " fmt sep, hideroot ? 0 : unp.v); - printf("unpcb %#lx\n ", hideroot ? 0 : off); +#define pp(fmt, v, sep) printf(#v " " fmt sep, unp.v); + printf("unpcb %#lx\n ", off); pp("%p", unp_socket, "\n "); pp("%p", unp_vnode, ", "); pull("%llu", unp_ino, "\n "); |