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:
(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.