sockstat(1): print out full connection graph for unix(4) sockets
Kernel provides us with enough information to display all possible connections between UNIX sockets. o Store unp_conn, xu_firstref and xu_nextref in the faddr of a UNIX sock. o Build tree of file descriptors, indexed by the socket pointer. o In displaysock() print out all possible information: 1) if socket is bound, print name of this socket 2) if socket has connected to a peer with a name, print peers name 3) if socket has connected to a peer without a name, print [pid fd] 4) if a bound socket has received connections, print list of them as [pid fd] Previously, only 1) either 2) were printed. Reviewed by: tuexen Differential revision: https://reviews.freebsd.org/D35726
This commit is contained in:
parent
c5bdcd1f10
commit
2c436d4890
@ -27,7 +27,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd February 2, 2022
|
||||
.Dd June 6, 2022
|
||||
.Dt SOCKSTAT 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -151,18 +151,27 @@ sockets.
|
||||
For Internet sockets, this is the address the local end of the socket
|
||||
is bound to (see
|
||||
.Xr getsockname 2 ) .
|
||||
.Pp
|
||||
For bound
|
||||
.Ux
|
||||
sockets, it is the socket's filename.
|
||||
For other
|
||||
sockets, socket's filename is printed.
|
||||
For not bound
|
||||
.Ux
|
||||
sockets, it is a right arrow followed by the endpoint's filename, or
|
||||
.Dq Li ??
|
||||
if the endpoint could not be determined.
|
||||
sockets, the field is empty.
|
||||
.It Li FOREIGN ADDRESS
|
||||
(Internet sockets only)
|
||||
The address the foreign end of the socket is bound to (see
|
||||
For Internet sockets, this is the address the foreign end of the socket
|
||||
is bound to (see
|
||||
.Xr getpeername 2 ) .
|
||||
.Pp
|
||||
For bound
|
||||
.Ux
|
||||
sockets a left arrow followed by the peer list is printed.
|
||||
For
|
||||
.Ux
|
||||
sockets that went through
|
||||
.Xr connect 2
|
||||
system call a right arrow followed by the peer is printed.
|
||||
Peers are printed in square brackets as [PID FD].
|
||||
.It Li ID
|
||||
The inp_gencnt if
|
||||
.Fl i
|
||||
|
@ -114,7 +114,14 @@ static int *ports;
|
||||
#define CHK_PORT(p) (ports[p / INT_BIT] & (1 << (p % INT_BIT)))
|
||||
|
||||
struct addr {
|
||||
union {
|
||||
struct sockaddr_storage address;
|
||||
struct { /* unix(4) faddr */
|
||||
kvaddr_t conn;
|
||||
kvaddr_t firstref;
|
||||
kvaddr_t nextref;
|
||||
};
|
||||
};
|
||||
unsigned int encaps_port;
|
||||
int state;
|
||||
struct addr *next;
|
||||
@ -159,8 +166,24 @@ RB_GENERATE_STATIC(pcbs_t, sock, pcb_tree, pcb_compare);
|
||||
|
||||
static SLIST_HEAD(, sock) nosocks = SLIST_HEAD_INITIALIZER(&nosocks);
|
||||
|
||||
static struct xfile *xfiles;
|
||||
static int nxfiles;
|
||||
struct file {
|
||||
RB_ENTRY(file) file_tree;
|
||||
kvaddr_t xf_data;
|
||||
pid_t xf_pid;
|
||||
uid_t xf_uid;
|
||||
int xf_fd;
|
||||
};
|
||||
|
||||
static RB_HEAD(files_t, file) ftree = RB_INITIALIZER(&ftree);
|
||||
static int64_t
|
||||
file_compare(const struct file *a, const struct file *b)
|
||||
{
|
||||
return ((int64_t)(a->xf_data/2 - b->xf_data/2));
|
||||
}
|
||||
RB_GENERATE_STATIC(files_t, file, file_tree, file_compare);
|
||||
|
||||
static struct file *files;
|
||||
static int nfiles;
|
||||
|
||||
static cap_channel_t *capnet;
|
||||
static cap_channel_t *capnetdb;
|
||||
@ -862,8 +885,9 @@ gather_unix(int proto)
|
||||
if (xup->xu_addr.sun_family == AF_UNIX)
|
||||
laddr->address =
|
||||
*(struct sockaddr_storage *)(void *)&xup->xu_addr;
|
||||
else if (xup->unp_conn != 0)
|
||||
*(kvaddr_t*)&(faddr->address) = xup->unp_conn;
|
||||
faddr->conn = xup->unp_conn;
|
||||
faddr->firstref = xup->xu_firstref;
|
||||
faddr->nextref = xup->xu_nextref;
|
||||
laddr->next = NULL;
|
||||
faddr->next = NULL;
|
||||
sock->laddr = laddr;
|
||||
@ -878,6 +902,7 @@ gather_unix(int proto)
|
||||
static void
|
||||
getfiles(void)
|
||||
{
|
||||
struct xfile *xfiles;
|
||||
size_t len, olen;
|
||||
|
||||
olen = len = sizeof(*xfiles);
|
||||
@ -893,7 +918,20 @@ getfiles(void)
|
||||
}
|
||||
if (len > 0)
|
||||
enforce_ksize(xfiles->xf_size, struct xfile);
|
||||
nxfiles = len / sizeof(*xfiles);
|
||||
nfiles = len / sizeof(*xfiles);
|
||||
|
||||
if ((files = malloc(nfiles * sizeof(struct file))) == NULL)
|
||||
err(1, "malloc()");
|
||||
|
||||
for (int i = 0; i < nfiles; i++) {
|
||||
files[i].xf_data = xfiles[i].xf_data;
|
||||
files[i].xf_pid = xfiles[i].xf_pid;
|
||||
files[i].xf_uid = xfiles[i].xf_uid;
|
||||
files[i].xf_fd = xfiles[i].xf_fd;
|
||||
RB_INSERT(files_t, &ftree, &files[i]);
|
||||
}
|
||||
|
||||
free(xfiles);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1066,10 +1104,8 @@ sctp_path_state(int state)
|
||||
static void
|
||||
displaysock(struct sock *s, int pos)
|
||||
{
|
||||
kvaddr_t p;
|
||||
int first, offset;
|
||||
struct addr *laddr, *faddr;
|
||||
struct sock *s_tmp;
|
||||
|
||||
while (pos < 30)
|
||||
pos += xprintf(" ");
|
||||
@ -1106,26 +1142,57 @@ displaysock(struct sock *s, int pos)
|
||||
if ((laddr == NULL) || (faddr == NULL))
|
||||
errx(1, "laddr = %p or faddr = %p is NULL",
|
||||
(void *)laddr, (void *)faddr);
|
||||
/* server */
|
||||
if (laddr->address.ss_len > 0) {
|
||||
pos += printaddr(&laddr->address);
|
||||
break;
|
||||
}
|
||||
/* client */
|
||||
p = *(kvaddr_t*)&(faddr->address);
|
||||
if (p == 0) {
|
||||
if (laddr->address.ss_len == 0 && faddr->conn == 0) {
|
||||
pos += xprintf("(not connected)");
|
||||
offset += opt_w ? 92 : 44;
|
||||
break;
|
||||
}
|
||||
pos += xprintf("-> ");
|
||||
s_tmp = RB_FIND(pcbs_t, &pcbs,
|
||||
&(struct sock){ .pcb = p });
|
||||
if (s_tmp == NULL || s_tmp->laddr == NULL ||
|
||||
s_tmp->laddr->address.ss_len == 0)
|
||||
/* Local bind(2) address, if any. */
|
||||
if (laddr->address.ss_len > 0)
|
||||
pos += printaddr(&laddr->address);
|
||||
/* Remote peer we connect(2) to, if any. */
|
||||
if (faddr->conn != 0) {
|
||||
struct sock *p;
|
||||
|
||||
pos += xprintf("%s-> ",
|
||||
laddr->address.ss_len > 0 ? " " : "");
|
||||
p = RB_FIND(pcbs_t, &pcbs,
|
||||
&(struct sock){ .pcb = faddr->conn });
|
||||
if (__predict_false(p == NULL)) {
|
||||
/* XXGL: can this happen at all? */
|
||||
pos += xprintf("??");
|
||||
else
|
||||
pos += printaddr(&s_tmp->laddr->address);
|
||||
} else if (p->laddr->address.ss_len == 0) {
|
||||
struct file *f;
|
||||
|
||||
f = RB_FIND(files_t, &ftree,
|
||||
&(struct file){ .xf_data =
|
||||
p->socket });
|
||||
pos += xprintf("[%lu %d]",
|
||||
(u_long)f->xf_pid, f->xf_fd);
|
||||
} else
|
||||
pos += printaddr(&p->laddr->address);
|
||||
}
|
||||
/* Remote peer(s) connect(2)ed to us, if any. */
|
||||
if (faddr->firstref != 0) {
|
||||
struct sock *p;
|
||||
struct file *f;
|
||||
kvaddr_t ref = faddr->firstref;
|
||||
bool fref = true;
|
||||
|
||||
pos += xprintf(" <- ");
|
||||
|
||||
while ((p = RB_FIND(pcbs_t, &pcbs,
|
||||
&(struct sock){ .pcb = ref })) != 0) {
|
||||
f = RB_FIND(files_t, &ftree,
|
||||
&(struct file){ .xf_data =
|
||||
p->socket });
|
||||
pos += xprintf("%s[%lu %d]",
|
||||
fref ? "" : ",",
|
||||
(u_long)f->xf_pid, f->xf_fd);
|
||||
ref = p->faddr->nextref;
|
||||
fref = false;
|
||||
}
|
||||
}
|
||||
offset += opt_w ? 92 : 44;
|
||||
break;
|
||||
default:
|
||||
@ -1228,7 +1295,7 @@ static void
|
||||
display(void)
|
||||
{
|
||||
struct passwd *pwd;
|
||||
struct xfile *xf;
|
||||
struct file *xf;
|
||||
struct sock *s;
|
||||
int n, pos;
|
||||
|
||||
@ -1253,7 +1320,7 @@ display(void)
|
||||
printf("\n");
|
||||
}
|
||||
cap_setpassent(cappwd, 1);
|
||||
for (xf = xfiles, n = 0; n < nxfiles; ++n, ++xf) {
|
||||
for (xf = files, n = 0; n < nfiles; ++n, ++xf) {
|
||||
if (xf->xf_data == 0)
|
||||
continue;
|
||||
if (opt_j >= 0 && opt_j != getprocjid(xf->xf_pid))
|
||||
|
Loading…
Reference in New Issue
Block a user