Subject: bin/348: print owner of connection in netstat(1)
To: None <gnats-admin>
From: Luke Mewburn <lm@karybdis.cs.rmit.OZ.AU>
List: netbsd-bugs
Date: 07/19/1994 18:05:06
>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 (Utility Bug People)
>State: open
>Class: change-request
>Submitter-Id: lm
>Arrival-Date: Tue Jul 19 18:05:04 1994
>Originator: Luke Mewburn
>Organization:
" Technical Services Group, RMIT Computer Science Department"
>Release:
>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;
}
>Audit-Trail:
>Unformatted:
------------------------------------------------------------------------------