diff options
author | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2015-08-03 14:20:40 +0000 |
---|---|---|
committer | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2015-08-03 14:20:40 +0000 |
commit | ec277591a1cc3ae4a44ea42885c9f54f503e751c (patch) | |
tree | 2339988c63a2e43d13e84ad8208dfcf7ddff94ff | |
parent | 95f89092683ed3d7a9585dfa9d460015a23bfe93 (diff) |
Unfortunately netstat did not show sockets without file descriptors
since it had been converted from kvm to sysctl. This was hiding a
bunch of TCP states which are important for network debugging.
Loop over the internet PCB tables to fill the network information
into the KERN_FILE_BYFILE sysctl result. Skip internet sockets
when looping over the file desciptors.
From markus@; OK guenther@; Go for it deraadt@
-rw-r--r-- | sys/kern/kern_sysctl.c | 78 |
1 files changed, 59 insertions, 19 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index 2347af3d18c..e00b101c01a 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sysctl.c,v 1.286 2015/07/19 02:35:35 deraadt Exp $ */ +/* $OpenBSD: kern_sysctl.c,v 1.287 2015/08/03 14:20:39 bluhm Exp $ */ /* $NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $ */ /*- @@ -87,11 +87,14 @@ #include <net/route.h> #include <netinet/in.h> #include <netinet/ip.h> +#include <netinet/ip_var.h> #include <netinet/in_pcb.h> #include <netinet/ip6.h> #include <netinet/tcp.h> #include <netinet/tcp_timer.h> #include <netinet/tcp_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> #include <netinet6/ip6_var.h> #ifdef DDB @@ -129,8 +132,8 @@ int sysctl_sensors(int *, u_int, void *, size_t *, void *, size_t); int sysctl_emul(int *, u_int, void *, size_t *, void *, size_t); int sysctl_cptime2(int *, u_int, void *, size_t *, void *, size_t); -void fill_file(struct kinfo_file *, struct file *, struct filedesc *, - int, struct vnode *, struct process *, struct proc *, int); +void fill_file(struct kinfo_file *, struct file *, struct filedesc *, int, + struct vnode *, struct process *, struct proc *, struct socket *, int); void fill_kproc(struct process *, struct kinfo_proc *, struct proc *, int); int (*cpu_cpuspeed)(int *); @@ -1004,7 +1007,7 @@ sysctl_rdstruct(void *oldp, size_t *oldlenp, void *newp, const void *sp, void fill_file(struct kinfo_file *kf, struct file *fp, struct filedesc *fdp, int fd, struct vnode *vp, struct process *pr, struct proc *p, - int show_pointers) + struct socket *so, int show_pointers) { struct vattr va; @@ -1045,6 +1048,9 @@ fill_file(struct kinfo_file *kf, struct file *fp, struct filedesc *fdp, kf->f_flag = FREAD; if (fd == KERN_FILE_TRACE) kf->f_flag |= FWRITE; + } else if (so != NULL) { + /* fake it */ + kf->f_type = DTYPE_SOCKET; } /* information about the object associated with this file */ @@ -1077,7 +1083,8 @@ fill_file(struct kinfo_file *kf, struct file *fp, struct filedesc *fdp, break; case DTYPE_SOCKET: { - struct socket *so = (struct socket *)fp->f_data; + if (so == NULL) + so = (struct socket *)fp->f_data; kf->so_type = so->so_type; kf->so_state = so->so_state; @@ -1242,23 +1249,47 @@ sysctl_file(int *name, u_int namelen, char *where, size_t *sizep, kf = malloc(sizeof(*kf), M_TEMP, M_WAITOK); -#define FILLIT(fp, fdp, i, vp, pr) do { \ - if (buflen >= elem_size && elem_count > 0) { \ - fill_file(kf, fp, fdp, i, vp, pr, p, show_pointers); \ - error = copyout(kf, dp, outsize); \ - if (error) \ - break; \ - dp += elem_size; \ - buflen -= elem_size; \ - elem_count--; \ - } \ - needed += elem_size; \ +#define FILLIT2(fp, fdp, i, vp, pr, so) do { \ + if (buflen >= elem_size && elem_count > 0) { \ + fill_file(kf, fp, fdp, i, vp, pr, p, so, show_pointers);\ + error = copyout(kf, dp, outsize); \ + if (error) \ + break; \ + dp += elem_size; \ + buflen -= elem_size; \ + elem_count--; \ + } \ + needed += elem_size; \ } while (0) +#define FILLIT(fp, fdp, i, vp, pr) \ + FILLIT2(fp, fdp, i, vp, pr, NULL) +#define FILLSO(so) \ + FILLIT2(NULL, NULL, 0, NULL, NULL, so) switch (op) { case KERN_FILE_BYFILE: + /* use the inp-tables to pick up closed connections, too */ + if (arg == DTYPE_SOCKET) { + extern struct inpcbtable rawcbtable, rawin6pcbtable; + struct inpcb *inp; + int s; + + s = splnet(); + TAILQ_FOREACH(inp, &tcbtable.inpt_queue, inp_queue) + FILLSO(inp->inp_socket); + TAILQ_FOREACH(inp, &udbtable.inpt_queue, inp_queue) + FILLSO(inp->inp_socket); + TAILQ_FOREACH(inp, &rawcbtable.inpt_queue, inp_queue) + FILLSO(inp->inp_socket); +#ifdef INET6 + TAILQ_FOREACH(inp, &rawin6pcbtable.inpt_queue, + inp_queue) + FILLSO(inp->inp_socket); +#endif + splx(s); + } fp = LIST_FIRST(&filehead); - /* don't FREF when f_count == 0 to avoid race in fdrop() */ + /* don't FREF when f_count == 0 to avoid race in fdrop() */ while (fp != NULL && fp->f_count == 0) fp = LIST_NEXT(fp, f_list); if (fp == NULL) @@ -1266,8 +1297,17 @@ sysctl_file(int *name, u_int namelen, char *where, size_t *sizep, FREF(fp); do { if (fp->f_count > 1 && /* 0, +1 for our FREF() */ - (arg == 0 || fp->f_type == arg)) - FILLIT(fp, NULL, 0, NULL, NULL); + (arg == 0 || fp->f_type == arg)) { + int af, skip = 0; + if (arg == DTYPE_SOCKET && fp->f_type == arg) { + af = ((struct socket *)fp->f_data)-> + so_proto->pr_domain->dom_family; + if (af == AF_INET || af == AF_INET6) + skip = 1; + } + if (!skip) + FILLIT(fp, NULL, 0, NULL, NULL); + } nfp = LIST_NEXT(fp, f_list); while (nfp != NULL && nfp->f_count == 0) nfp = LIST_NEXT(nfp, f_list); |