NetBSD Problem Report #348

From gnats  Tue Jul 19 17:51:28 1994
Received: from goanna.cs.rmit.oz.au (root@[131.170.24.40]) by sun-lamp.cs.berkeley.edu (8.6.9/8.6.9) with ESMTP id RAA16253 for <gnats-bugs@sun-lamp.cs.berkeley.edu>; Tue, 19 Jul 1994 17:51:24 -0700
Message-Id: <199407200051.KAA00254@karybdis.cs.rmit.OZ.AU>
Date: Wed, 20 Jul 1994 10:51:23 +1000
From: Luke Mewburn <lm@karybdis.cs.rmit.OZ.AU>
Reply-To: lm@karybdis.cs.rmit.OZ.AU
To: gnats-bugs@sun-lamp.cs.berkeley.edu
Subject: print owner of connection in netstat(1)
X-Send-Pr-Version: 3.2

>Number:         348
>Category:       bin
>Synopsis:       a hack to netstat(1) to show the owner of a connection
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    gnats-admin
>State:          closed
>Class:          change-request
>Submitter-Id:   lm
>Arrival-Date:   Tue Jul 19 18:05:04 +0000 1994
>Closed-Date:    Tue Jul 19 23:53:19 +0000 1994
>Last-Modified:  
>Originator:     Luke Mewburn
>Release:        
>Organization:
"	Technical Services Group, RMIT Computer Science Department"
>Environment:

System: NetBSD karybdis 1.0-ALPHA NetBSD 1.0-ALPHA (KARYBDIS) #6: Wed Jul 20 10:35:04 EST 1994 root@karybdis:/Src/src/sys/arch/i386/compile/KARYBDIS i386


>Description:
	Netstat(1) currently does not show the owner of connections.
	This feature would be rather useful to determine the user who
	owns the process tied to a certain outbound socket.
	A while ago I wrote a program which uses the appropriate OS
	module from identd (which, btw, needs to be upgraded on
	netbsd.) to determine who a specific connection belonged to,
	but having the feature in netstat directly is more useful.

>How-To-Repeat:
	run netstat.
	Now, apply this patch, and run netstat with the -U option.
	Effect is more noticable when a non-root process has a telnet
	going out, or has a unix domain server.

>Fix:
	Apply this patch. Note that it's not the most elegant solution
	(especially for inet sockets), and I really should go through
	the open file list once and cache it rather than scan it for
	each connection. But, like ps(1), netstat can't be relied on
	to have _perfect_ information :)


diff -cb /usr/src/usr.bin/netstat/inet.c netstat/inet.c
*** /usr/src/usr.bin/netstat/inet.c	Fri May 13 21:51:48 1994
--- netstat/inet.c	Tue Jul 19 15:07:57 1994
***************
*** 124,134 ****
  			putchar('\n');
  			if (Aflag)
  				printf("%-8.8s ", "PCB");
! 			printf(Aflag ?
! 				"%-5.5s %-6.6s %-6.6s  %-18.18s %-18.18s %s\n" :
! 				"%-5.5s %-6.6s %-6.6s  %-22.22s %-22.22s %s\n",
  				"Proto", "Recv-Q", "Send-Q",
! 				"Local Address", "Foreign Address", "(state)");
  			first = 0;
  		}
  		if (Aflag)
--- 124,137 ----
  			putchar('\n');
  			if (Aflag)
  				printf("%-8.8s ", "PCB");
! 			printf((Aflag | Uflag) ?
! 				"%-5.5s %-6.6s %-6.6s  %-18.18s %-18.18s" :
! 				"%-5.5s %-6.6s %-6.6s  %-22.22s %-22.22s" ,
  				"Proto", "Recv-Q", "Send-Q",
! 				"Local Address", "Foreign Address");
! 			if (Uflag)
! 				printf(" %-8.8s", "User");
! 			printf(" (state)\n");
  			first = 0;
  		}
  		if (Aflag)
***************
*** 140,145 ****
--- 143,152 ----
  			sockb.so_snd.sb_cc);
  		inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport, name);
  		inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport, name);
+ 		if (Uflag)
+ 			printf(" %-8.8s",
+ 			    ucred_to_name(
+ 				    (socket_ucred((void *)inpcb.inp_socket))));
  		if (istcp) {
  			if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
  				printf(" %d", tcpcb.t_state);
***************
*** 425,431 ****
  	char line[80], *cp;
  	int width;

! 	sprintf(line, "%.*s.", (Aflag && !nflag) ? 12 : 16, inetname(in));
  	cp = index(line, '\0');
  	if (!nflag && port)
  		sp = getservbyport((int)port, proto);
--- 432,438 ----
  	char line[80], *cp;
  	int width;

! 	sprintf(line, "%.*s.", ((Aflag || Uflag) && !nflag) ? 12 : 16, inetname(in));
  	cp = index(line, '\0');
  	if (!nflag && port)
  		sp = getservbyport((int)port, proto);
***************
*** 433,439 ****
  		sprintf(cp, "%.8s", sp ? sp->s_name : "*");
  	else
  		sprintf(cp, "%d", ntohs((u_short)port));
! 	width = Aflag ? 18 : 22;
  	printf(" %-*.*s", width, width, line);
  }

--- 440,446 ----
  		sprintf(cp, "%.8s", sp ? sp->s_name : "*");
  	else
  		sprintf(cp, "%d", ntohs((u_short)port));
! 	width = (Aflag | Uflag) ? 18 : 22;
  	printf(" %-*.*s", width, width, line);
  }

diff -cb /usr/src/usr.bin/netstat/main.c netstat/main.c
*** /usr/src/usr.bin/netstat/main.c	Fri May 13 21:51:50 1994
--- netstat/main.c	Tue Jul 19 15:17:54 1994
***************
*** 46,51 ****
--- 46,52 ----
  #include <sys/file.h>
  #include <sys/protosw.h>
  #include <sys/socket.h>
+ #include <sys/ucred.h>

  #include <netinet/in.h>

***************
*** 60,65 ****
--- 61,67 ----
  #include <stdlib.h>
  #include <string.h>
  #include <unistd.h>
+ #include <pwd.h>
  #include "netstat.h"

  struct nlist nl[] = {
***************
*** 203,209 ****
  		prog = argv[0];
  	af = AF_UNSPEC;

! 	while ((ch = getopt(argc, argv, "Aadf:ghI:iM:mN:np:rstuw:")) != EOF)
  		switch(ch) {
  		case 'A':
  			Aflag = 1;
--- 205,211 ----
  		prog = argv[0];
  	af = AF_UNSPEC;

! 	while ((ch = getopt(argc, argv, "AUadf:ghI:iM:mN:np:rstuw:")) != EOF)
  		switch(ch) {
  		case 'A':
  			Aflag = 1;
***************
*** 279,284 ****
--- 281,289 ----
  		case 'u':
  			af = AF_UNIX;
  			break;
+ 		case 'U':
+ 			Uflag = 1;
+ 			break;
  		case 'w':
  			interval = atoi(optarg);
  			iflag = 1;
***************
*** 494,504 ****
  	return (NULL);
  }

  static void
  usage()
  {
  	(void)fprintf(stderr,
! "usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n", prog);
  	(void)fprintf(stderr,
  "       %s [-ghimnrs] [-f address_family] [-M core] [-N system]\n", prog);
  	(void)fprintf(stderr,
--- 499,533 ----
  	return (NULL);
  }

+ /*
+  * Get the username from the ucred struct, and return a pointer
+  * to the static data structure.
+  */
+ char *
+ ucred_to_name(creds)
+ 	void *creds;	/* actually a (struct ucred *) */
+ {
+ 	static char res[9];
+ 	struct ucred ucd, *ucp = &ucd;
+ 	struct passwd *pwent;
+ 
+ 	res[0] = '\0';
+ 	if (creds == NULL)
+ 		return res;
+ 	if (kread((u_long)creds, (char *)ucp, sizeof(*ucp)))
+ 		return res;
+ 	if ((pwent = getpwuid(ucp->cr_uid)) != NULL)
+ 		sprintf(res, "%-8.8s", pwent->pw_name);
+ 	else
+ 		sprintf(res, "%-8d", ucp->cr_uid);
+ 	return res;
+ }
+ 
  static void
  usage()
  {
  	(void)fprintf(stderr,
! "usage: %s [-AanU] [-f address_family] [-M core] [-N system]\n", prog);
  	(void)fprintf(stderr,
  "       %s [-ghimnrs] [-f address_family] [-M core] [-N system]\n", prog);
  	(void)fprintf(stderr,
diff -cb /usr/src/usr.bin/netstat/netstat.1 netstat/netstat.1
*** /usr/src/usr.bin/netstat/netstat.1	Fri May 13 21:51:53 1994
--- netstat/netstat.1	Wed Jul 20 10:42:56 1994
***************
*** 40,46 ****
  .Nd show network status
  .Sh SYNOPSIS
  .Nm netstat
! .Op Fl Aan
  .Op Fl f Ar address_family
  .Op Fl M Ar core
  .Op Fl N Ar system
--- 40,46 ----
  .Nd show network status
  .Sh SYNOPSIS
  .Nm netstat
! .Op Fl AanU
  .Op Fl f Ar address_family
  .Op Fl M Ar core
  .Op Fl N Ar system
***************
*** 172,177 ****
--- 172,180 ----
  When
  .Fl s
  is also present, show routing statistics instead.
+ .It Fl U
+ Show the username of the owner of the connection. (Implemented only for inet
+ and unix domain connections at this time.)
  .It Fl w Ar wait
  Show network interface statistics at intervals of
  .Ar wait
diff -cb /usr/src/usr.bin/netstat/netstat.h netstat/netstat.h
*** /usr/src/usr.bin/netstat/netstat.h	Fri May 13 18:08:20 1994
--- netstat/netstat.h	Tue Jul 19 15:05:55 1994
***************
*** 37,42 ****
--- 37,43 ----
  #include <sys/cdefs.h>

  int	Aflag;		/* show addresses of protocol control block */
+ int	Uflag;		/* show username of connection owner */
  int	aflag;		/* show all sockets (including servers) */
  int	dflag;		/* show i/f dropped packets */
  int	gflag;		/* show group (multicast) routing or stats */
***************
*** 108,110 ****
--- 109,114 ----

  void	mroutepr __P((u_long, u_long, u_long));
  void	mrt_stats __P((u_long, u_long));
+ 
+ char   *ucred_to_name __P((void *));
+ void   *socket_ucred __P((void *));
Common subdirectories: /usr/src/usr.bin/netstat/obj and netstat/obj
diff -cb /usr/src/usr.bin/netstat/unix.c netstat/unix.c
*** /usr/src/usr.bin/netstat/unix.c	Fri May 13 21:51:55 1994
--- netstat/unix.c	Tue Jul 19 15:06:11 1994
***************
*** 59,65 ****
  #include <stdlib.h>
  #include "netstat.h"

! static	void unixdomainpr __P((struct socket *, caddr_t));

  static struct	file *file, *fileNFILE;
  static int	nfiles;
--- 59,65 ----
  #include <stdlib.h>
  #include "netstat.h"

! static	void unixdomainpr __P((struct socket *, struct file *));

  static struct	file *file, *fileNFILE;
  static int	nfiles;
***************
*** 89,95 ****
  		/* kludge */
  		if (so->so_proto >= unixsw && so->so_proto <= unixsw + 2)
  			if (so->so_pcb)
! 				unixdomainpr(so, fp->f_data);
  	}
  }

--- 89,95 ----
  		/* kludge */
  		if (so->so_proto >= unixsw && so->so_proto <= unixsw + 2)
  			if (so->so_pcb)
! 				unixdomainpr(so, fp);
  	}
  }

***************
*** 97,110 ****
      { "#0", "stream", "dgram", "raw", "rdm", "seqpacket" };

  static void
! unixdomainpr(so, soaddr)
  	register struct socket *so;
! 	caddr_t soaddr;
  {
  	struct unpcb unpcb, *unp = &unpcb;
  	struct mbuf mbuf, *m;
  	struct sockaddr_un *sa;
  	static int first = 1;

  	if (kread((u_long)so->so_pcb, (char *)unp, sizeof (*unp)))
  		return;
--- 97,111 ----
      { "#0", "stream", "dgram", "raw", "rdm", "seqpacket" };

  static void
! unixdomainpr(so, fp)
  	register struct socket *so;
! 	register struct file *fp;
  {
  	struct unpcb unpcb, *unp = &unpcb;
  	struct mbuf mbuf, *m;
  	struct sockaddr_un *sa;
  	static int first = 1;
+ 	caddr_t soaddr = fp->f_data;

  	if (kread((u_long)so->so_pcb, (char *)unp, sizeof (*unp)))
  		return;
***************
*** 118,135 ****
  	if (first) {
  		printf("Active UNIX domain sockets\n");
  		printf(
! "%-8.8s %-6.6s %-6.6s %-6.6s %8.8s %8.8s %8.8s %8.8s Addr\n",
  		    "Address", "Type", "Recv-Q", "Send-Q",
  		    "Inode", "Conn", "Refs", "Nextref");
  		first = 0;
  	}
  	printf("%8x %-6.6s %6d %6d %8x %8x %8x %8x",
  	    soaddr, socktype[so->so_type], so->so_rcv.sb_cc, so->so_snd.sb_cc,
  	    unp->unp_vnode, unp->unp_conn,
  	    unp->unp_refs, unp->unp_nextref);
  	if (m)
  		printf(" %.*s",
  		    m->m_len - (int)(sizeof(*sa) - sizeof(sa->sun_path)),
  		    sa->sun_path);
  	putchar('\n');
  }
--- 119,167 ----
  	if (first) {
  		printf("Active UNIX domain sockets\n");
  		printf(
! 		    "%-8.8s %-6.6s %-6.6s %-6.6s %8.8s %8.8s %8.8s %8.8s",
  		    "Address", "Type", "Recv-Q", "Send-Q",
  		    "Inode", "Conn", "Refs", "Nextref");
+ 		if (Uflag)
+ 			printf(" %-8.8s", "User");
+ 		printf(" Addr\n");
  		first = 0;
  	}
  	printf("%8x %-6.6s %6d %6d %8x %8x %8x %8x",
  	    soaddr, socktype[so->so_type], so->so_rcv.sb_cc, so->so_snd.sb_cc,
  	    unp->unp_vnode, unp->unp_conn,
  	    unp->unp_refs, unp->unp_nextref);
+ 	if (Uflag)
+ 		printf(" %-8.8s", ucred_to_name((void *)fp->f_cred));
  	if (m)
  		printf(" %.*s",
  		    m->m_len - (int)(sizeof(*sa) - sizeof(sa->sun_path)),
  		    sa->sun_path);
  	putchar('\n');
+ }
+ 
+ void *
+ socket_ucred(the_sock)
+ 	void *the_sock;
+ {
+ 	register struct file *fp;
+ 	struct socket sock, *so = &sock;
+ 	char *filebuf;
+ 
+ 	filebuf = (char *)kvm_getfiles(kvmd, KERN_FILE, 0, &nfiles);
+ 	if (filebuf == 0) {
+ 		printf("Out of memory (file table).\n");
+ 		return NULL;
+ 	}
+ 	file = (struct file *)(filebuf + sizeof(fp));
+ 	fileNFILE = file + nfiles;
+ 	for (fp = file; fp < fileNFILE; fp++) {
+ 		if (fp->f_count == 0 || fp->f_type != DTYPE_SOCKET)
+ 			continue;
+ 		if (kread((u_long)fp->f_data, (char *)so, sizeof (*so)))
+ 			continue;
+ 		if ((void *)fp->f_data == the_sock)
+ 			return (void *)fp->f_cred;
+ 	}
+ 	return NULL;
  }
>Release-Note:
>Audit-Trail:

State-Changed-From-To: open->closed
State-Changed-By: glass
State-Changed-When: Tue Jul 19 23:53:19 1994
State-Changed-Why:

This functionality is available by using netstat, and fstat in
concert.  By keeping them separate, the adminstrator can easily change
the accessibility of 'fstat' to suit their tastes without affecting
access to 'netstat'.

A dissenting opinion holds that this is cool functionality, and we
should include the shell scripts to accomplish same if we don't
include this hack.

>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.