Date: Sat, 10 Jan 1998 13:53:05 +0300 From: Vadim Kolontsov <vadim@tversu.ru> To: freebsd-hackers@FreeBSD.ORG Subject: Re: Adding process ID listing to netstat Message-ID: <19980110135305.53253@tversu.ru> In-Reply-To: <199801090654.AAA15353@detlev.UUCP>; from Joel Ray Holveck on Fri, Jan 09, 1998 at 12:54:13AM -0600 References: <199801090654.AAA15353@detlev.UUCP>
next in thread | previous in thread | raw e-mail | index | archive | help
Hi, On Fri, Jan 09, 1998 at 12:54:13AM -0600, Joel Ray Holveck wrote: > Would it be useful to others to allow netstat to give the process ID's > that are using sockets? For me, yes Btw, when I played with kvm, I wrote a program (as programming example) which does almost the same - it walks in process table and prints TCP/UDP sockets, used by process (reinventing lsof, yes). Sample output: PID PROTOCOL/STATE LOCAL ADDRESS FOREIGN ADDRESS 20249 tcp:ESTABLISHED 194.190.141.69:23 194.190.141.45:1027 102 tcp:LISTEN *:23 *:* 80 udp *:9535 *:* In case that someone will be interested, I've included source in the letter. I've tried to make the code as clear as possible (please notify me if you'll find any bugs), to be useful for novice (can it be kinda "kvm tutorial"? :) Best regards, V. ----------------------------- psock.c ------------------------------------ /* psock -- shows a table containing pid, connection type, local/foreign addr Program must be run by root or be setgid to kmem This utility intended to be more programming example than every-day-tool. Copyright (C) 1997 Vadim Kolontsov <vadim@tversu.ru> Compilation: gcc -o psock psock.c -lkvm -g -DKERNEL -DTCPSTATES Tested under FreeBSD 2.2.2 TODO: filtering dup()'ed fds? */ #include <kvm.h> #include <stdio.h> #include <stdlib.h> #include <sys/param.h> #include <vm/vm.h> #include <vm/lock.h> #include <vm/pmap.h> #include <vm/vm_map.h> #include <sys/proc.h> #include <sys/types.h> #include <sys/filedesc.h> #include <sys/socket.h> #include <sys/socketvar.h> #include <sys/file.h> #include <sys/sysctl.h> #include <sys/protosw.h> #include <sys/domain.h> #include <sys/user.h> #include <net/route.h> #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/in_pcb.h> #include <netinet/tcp.h> #include <netinet/tcp_timer.h> #include <netinet/tcp_var.h> #include <netinet/tcp_fsm.h> #include <fcntl.h> #include <pwd.h> int main(int argc, char *argv[]) { kvm_t *kd; struct kinfo_proc *kp; int cntproc, cntfiles, i, j, pid, fileslen; struct proc *kproc; struct file **files; struct file file; struct socket socket; struct filedesc filedesc; struct protosw protosw; struct tcpcb tcpcb; struct domain domain; struct inpcb inpcb; char *nlistf, *memf, *swapf, buf[256]; /* ------ Can be changed with command-line interface, for example ---- */ nlistf = memf = swapf = NULL; /* -------------- Initalize kvm ------------- */ kd = kvm_openfiles(nlistf, memf, swapf, O_RDONLY, buf); if (kd == 0) errx(1, buf); /* ------- Get table of all processes ------- */ if ((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &cntproc)) == 0) errx(1, kvm_geterr(kd)); /* ----------- Walk by process... ----------- */ for (i = 0; i < cntproc; i++, kp++) { kproc = &(kp->kp_proc); pid = kproc->p_pid; /* ------- Read file descriptor table ------- */ if (kvm_read(kd, (u_long)kproc->p_fd, &filedesc, sizeof(struct filedesc)) <= 0) errx(1, kvm_geterr(kd)); /* ---------- Number of opened files -------- */ cntfiles = filedesc.fd_nfiles; fileslen = cntfiles*sizeof(struct file *); files = malloc(fileslen); /* ---- Read array of pointers to 'file' struct ------ */ if (kvm_read(kd, (u_long)filedesc.fd_ofiles, files, fileslen) <= 0) errx(1, kvm_geterr(kd)); /* ------------- Walk by files ----------------------- */ for (j = 0; j < cntfiles; j++, files++) { if (*files == NULL) continue; /* --------------- Load file ------------------------ */ if (kvm_read(kd, (u_long)*files, &file, sizeof(struct file)) <= 0) errx(1, kvm_geterr(kd)); if (file.f_type == DTYPE_SOCKET) { /* ------------- Load socket ------------------------ */ if (kvm_read(kd, (u_long)file.f_data, &socket, sizeof(struct socket)) <= 0) errx(1, kvm_geterr(kd)); /* ---------- Skip if has no references ------------ */ if (socket.so_state == 0) continue; /* ------ We need to deterimine socket family.. so let's load protosw --- */ if (kvm_read(kd, (u_long)socket.so_proto, &protosw, sizeof(struct protosw)) <= 0) errx(1, kvm_geterr(kd)); /* ----- Now loading domain... -------- */ if (kvm_read(kd, (u_long)protosw.pr_domain, &domain, sizeof(struct domain)) <= 0) errx(1, kvm_geterr(kd)); if (domain.dom_family != AF_INET) continue; /* ------- Voila, now we can print information ----------- */ printf("%-6d ", pid); if (socket.so_type == SOCK_DGRAM) printf("%-20s", "udp"); else if (socket.so_type == SOCK_STREAM) if (socket.so_pcb) { /* ------------- Loading protocol control block... ------------- */ if (kvm_read(kd, (u_long)socket.so_pcb, &inpcb, sizeof(struct inpcb)) <= 0) errx(1, kvm_geterr(kd)); /* ----------- Let's determine state of connection... ----------- */ if (kvm_read(kd, (u_long)inpcb.inp_ppcb, &tcpcb, sizeof(struct tcpcb)) <= 0) errx(1, kvm_geterr(kd)); printf("tcp:%-16s", tcpstates[tcpcb.t_state]); } else printf("%-20s", "tcp"); /* --------------- Printing local address & port ---------------- */ if (inpcb.inp_laddr.s_addr) sprintf(buf, "%s:", inet_ntoa(inpcb.inp_laddr)); else sprintf(buf, "*:"); if (inpcb.inp_lport) sprintf(&buf[strlen(buf)], "%d", ntohs(inpcb.inp_lport)); else sprintf(&buf[strlen(buf)], "*"); printf("%-20s\t\t", buf); /* ------------- Printing foreign address and port --------------- */ if (inpcb.inp_faddr.s_addr) printf("%s:", inet_ntoa(inpcb.inp_faddr)); else printf("*:"); if (inpcb.inp_fport) printf("%d\n", ntohs(inpcb.inp_fport)); else printf("*\n"); } } } kvm_close(kd); } ----------------------------- cut here ----------------------------------- -- Vadim Kolontsov Tver Internet Center NOC
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?19980110135305.53253>