From owner-freebsd-hackers Sat Jan 10 03:03:37 1998 Return-Path: Received: (from majordom@localhost) by hub.freebsd.org (8.8.7/8.8.7) id DAA21038 for hackers-outgoing; Sat, 10 Jan 1998 03:03:37 -0800 (PST) (envelope-from owner-freebsd-hackers@FreeBSD.ORG) Received: from pcadm1.tversu.ru (pcadm1.tversu.ru [194.190.141.69]) by hub.freebsd.org (8.8.7/8.8.7) with ESMTP id DAA21023 for ; Sat, 10 Jan 1998 03:03:21 -0800 (PST) (envelope-from vadim@pcadm1.tversu.ru) Received: (from vadim@localhost) by pcadm1.tversu.ru (8.8.7/8.8.7) id NAA21771; Sat, 10 Jan 1998 13:53:06 +0300 (MSK) Message-ID: <19980110135305.53253@tversu.ru> Date: Sat, 10 Jan 1998 13:53:05 +0300 From: Vadim Kolontsov To: freebsd-hackers@FreeBSD.ORG Subject: Re: Adding process ID listing to netstat References: <199801090654.AAA15353@detlev.UUCP> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Mailer: Mutt 0.88 In-Reply-To: <199801090654.AAA15353@detlev.UUCP>; from Joel Ray Holveck on Fri, Jan 09, 1998 at 12:54:13AM -0600 Sender: owner-freebsd-hackers@FreeBSD.ORG Precedence: bulk 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 Compilation: gcc -o psock psock.c -lkvm -g -DKERNEL -DTCPSTATES Tested under FreeBSD 2.2.2 TODO: filtering dup()'ed fds? */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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