Skip site navigation (1)Skip section navigation (2)
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>