11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1983, 1988, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 4. Neither the name of the University nor the names of its contributors
141590Srgrimes *    may be used to endorse or promote products derived from this software
151590Srgrimes *    without specific prior written permission.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271590Srgrimes * SUCH DAMAGE.
281590Srgrimes */
291590Srgrimes
30132671Scharnier#if 0
311590Srgrimes#ifndef lint
321590Srgrimesstatic char sccsid[] = "@(#)unix.c	8.1 (Berkeley) 6/6/93";
33132671Scharnier#endif /* not lint */
3427753Scharnier#endif
351590Srgrimes
36132671Scharnier#include <sys/cdefs.h>
37132671Scharnier__FBSDID("$FreeBSD: releng/11.0/usr.bin/netstat/unix.c 298182 2016-04-18 05:46:18Z araujo $");
38132671Scharnier
391590Srgrimes/*
401590Srgrimes * Display protocol blocks in the unix domain.
411590Srgrimes */
421590Srgrimes#include <sys/param.h>
4314543Sdg#include <sys/queue.h>
441590Srgrimes#include <sys/protosw.h>
451590Srgrimes#include <sys/socket.h>
461590Srgrimes#include <sys/socketvar.h>
471590Srgrimes#include <sys/mbuf.h>
481590Srgrimes#include <sys/sysctl.h>
491590Srgrimes#include <sys/un.h>
501590Srgrimes#include <sys/unpcb.h>
511590Srgrimes
521590Srgrimes#include <netinet/in.h>
531590Srgrimes
5436080Swollman#include <errno.h>
5538185Sphk#include <err.h>
5636103Swollman#include <stddef.h>
57160787Syar#include <stdint.h>
581590Srgrimes#include <stdio.h>
591590Srgrimes#include <stdlib.h>
60279122Smarcel#include <stdbool.h>
61171465Sjhb#include <strings.h>
6236080Swollman#include <kvm.h>
63279122Smarcel#include <libxo/xo.h>
641590Srgrimes#include "netstat.h"
651590Srgrimes
66175061Sobrienstatic	void unixdomainpr(struct xunpcb *, struct xsocket *);
671590Srgrimes
6836080Swollmanstatic	const char *const socktype[] =
6936080Swollman    { "#0", "stream", "dgram", "raw", "rdm", "seqpacket" };
701590Srgrimes
71171465Sjhbstatic int
72171465Sjhbpcblist_sysctl(int type, char **bufp)
73171465Sjhb{
74171465Sjhb	char 	*buf;
75171465Sjhb	size_t	len;
76171465Sjhb	char mibvar[sizeof "net.local.seqpacket.pcblist"];
77171465Sjhb
78171465Sjhb	sprintf(mibvar, "net.local.%s.pcblist", socktype[type]);
79171465Sjhb
80171465Sjhb	len = 0;
81171465Sjhb	if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
82171465Sjhb		if (errno != ENOENT)
83279122Smarcel			xo_warn("sysctl: %s", mibvar);
84171465Sjhb		return (-1);
85171465Sjhb	}
86298182Saraujo	if ((buf = malloc(len)) == NULL) {
87279122Smarcel		xo_warnx("malloc %lu bytes", (u_long)len);
88171465Sjhb		return (-2);
89171465Sjhb	}
90171465Sjhb	if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
91279122Smarcel		xo_warn("sysctl: %s", mibvar);
92171465Sjhb		free(buf);
93171465Sjhb		return (-2);
94171465Sjhb	}
95171465Sjhb	*bufp = buf;
96171465Sjhb	return (0);
97171465Sjhb}
98171465Sjhb
99171465Sjhbstatic int
100171465Sjhbpcblist_kvm(u_long count_off, u_long gencnt_off, u_long head_off, char **bufp)
101171465Sjhb{
102171465Sjhb	struct unp_head head;
103171465Sjhb	struct unpcb *unp, unp_conn;
104171465Sjhb	u_char sun_len;
105171465Sjhb	struct socket so;
106171465Sjhb	struct xunpgen xug;
107171465Sjhb	struct xunpcb xu;
108171465Sjhb	unp_gen_t unp_gencnt;
109171465Sjhb	u_int	unp_count;
110171465Sjhb	char 	*buf, *p;
111171465Sjhb	size_t	len;
112171465Sjhb
113171465Sjhb	if (count_off == 0 || gencnt_off == 0)
114171465Sjhb		return (-2);
115171465Sjhb	if (head_off == 0)
116171465Sjhb		return (-1);
117171465Sjhb	kread(count_off, &unp_count, sizeof(unp_count));
118171465Sjhb	len = 2 * sizeof(xug) + (unp_count + unp_count / 8) * sizeof(xu);
119298182Saraujo	if ((buf = malloc(len)) == NULL) {
120279122Smarcel		xo_warnx("malloc %lu bytes", (u_long)len);
121171465Sjhb		return (-2);
122171465Sjhb	}
123171465Sjhb	p = buf;
124171465Sjhb
125175061Sobrien#define	COPYOUT(obj, size) do {						\
126171465Sjhb	if (len < (size)) {						\
127279122Smarcel		xo_warnx("buffer size exceeded");			\
128171465Sjhb		goto fail;						\
129171465Sjhb	}								\
130171465Sjhb	bcopy((obj), p, (size));					\
131171465Sjhb	len -= (size);							\
132171465Sjhb	p += (size);							\
133171465Sjhb} while (0)
134171465Sjhb
135175061Sobrien#define	KREAD(off, buf, len) do {					\
136171465Sjhb	if (kread((uintptr_t)(off), (buf), (len)) != 0)			\
137171465Sjhb		goto fail;						\
138171465Sjhb} while (0)
139171465Sjhb
140171465Sjhb	/* Write out header. */
141171465Sjhb	kread(gencnt_off, &unp_gencnt, sizeof(unp_gencnt));
142171465Sjhb	xug.xug_len = sizeof xug;
143171465Sjhb	xug.xug_count = unp_count;
144171465Sjhb	xug.xug_gen = unp_gencnt;
145171465Sjhb	xug.xug_sogen = 0;
146171465Sjhb	COPYOUT(&xug, sizeof xug);
147171465Sjhb
148171465Sjhb	/* Walk the PCB list. */
149171465Sjhb	xu.xu_len = sizeof xu;
150171465Sjhb	KREAD(head_off, &head, sizeof(head));
151171465Sjhb	LIST_FOREACH(unp, &head, unp_link) {
152171465Sjhb		xu.xu_unpp = unp;
153171465Sjhb		KREAD(unp, &xu.xu_unp, sizeof (*unp));
154171465Sjhb		unp = &xu.xu_unp;
155171465Sjhb
156171465Sjhb		if (unp->unp_gencnt > unp_gencnt)
157171465Sjhb			continue;
158171465Sjhb		if (unp->unp_addr != NULL) {
159171465Sjhb			KREAD(unp->unp_addr, &sun_len, sizeof(sun_len));
160171465Sjhb			KREAD(unp->unp_addr, &xu.xu_addr, sun_len);
161171465Sjhb		}
162171465Sjhb		if (unp->unp_conn != NULL) {
163171465Sjhb			KREAD(unp->unp_conn, &unp_conn, sizeof(unp_conn));
164171465Sjhb			if (unp_conn.unp_addr != NULL) {
165171465Sjhb				KREAD(unp_conn.unp_addr, &sun_len,
166171465Sjhb				    sizeof(sun_len));
167171465Sjhb				KREAD(unp_conn.unp_addr, &xu.xu_caddr, sun_len);
168171465Sjhb			}
169171465Sjhb		}
170171465Sjhb		KREAD(unp->unp_socket, &so, sizeof(so));
171171465Sjhb		if (sotoxsocket(&so, &xu.xu_socket) != 0)
172171465Sjhb			goto fail;
173171465Sjhb		COPYOUT(&xu, sizeof(xu));
174171465Sjhb	}
175171465Sjhb
176171465Sjhb	/* Reread the counts and write the footer. */
177171465Sjhb	kread(count_off, &unp_count, sizeof(unp_count));
178171465Sjhb	kread(gencnt_off, &unp_gencnt, sizeof(unp_gencnt));
179171465Sjhb	xug.xug_count = unp_count;
180171465Sjhb	xug.xug_gen = unp_gencnt;
181171465Sjhb	COPYOUT(&xug, sizeof xug);
182171465Sjhb
183171465Sjhb	*bufp = buf;
184171465Sjhb	return (0);
185171465Sjhb
186171465Sjhbfail:
187171465Sjhb	free(buf);
188171465Sjhb	return (-1);
189171465Sjhb#undef COPYOUT
190171465Sjhb#undef KREAD
191171465Sjhb}
192171465Sjhb
1931590Srgrimesvoid
194197777Srwatsonunixpr(u_long count_off, u_long gencnt_off, u_long dhead_off, u_long shead_off,
195279122Smarcel    u_long sphead_off, bool *first)
1961590Srgrimes{
19736080Swollman	char 	*buf;
198171465Sjhb	int	ret, type;
19936080Swollman	struct	xsocket *so;
20036080Swollman	struct	xunpgen *xug, *oxug;
20136080Swollman	struct	xunpcb *xunp;
202197777Srwatson	u_long	head_off;
2031590Srgrimes
204246988Scharnier	buf = NULL;
20544091Sfenner	for (type = SOCK_STREAM; type <= SOCK_SEQPACKET; type++) {
206171465Sjhb		if (live)
207171465Sjhb			ret = pcblist_sysctl(type, &buf);
208197777Srwatson		else {
209197777Srwatson			head_off = 0;
210197777Srwatson			switch (type) {
211197777Srwatson			case SOCK_STREAM:
212197777Srwatson				head_off = shead_off;
213197777Srwatson				break;
214197777Srwatson
215197777Srwatson			case SOCK_DGRAM:
216197777Srwatson				head_off = dhead_off;
217197777Srwatson				break;
218197777Srwatson
219197777Srwatson			case SOCK_SEQPACKET:
220197777Srwatson				head_off = sphead_off;
221197777Srwatson				break;
222197777Srwatson			}
223197777Srwatson			ret = pcblist_kvm(count_off, gencnt_off, head_off,
224197777Srwatson			    &buf);
225197777Srwatson		}
226171465Sjhb		if (ret == -1)
2271590Srgrimes			continue;
228171465Sjhb		if (ret < 0)
22936080Swollman			return;
23036080Swollman
23136080Swollman		oxug = xug = (struct xunpgen *)buf;
23236080Swollman		for (xug = (struct xunpgen *)((char *)xug + xug->xug_len);
233279122Smarcel		    xug->xug_len > sizeof(struct xunpgen);
234279122Smarcel		    xug = (struct xunpgen *)((char *)xug + xug->xug_len)) {
23536080Swollman			xunp = (struct xunpcb *)xug;
23636080Swollman			so = &xunp->xu_socket;
23736080Swollman
23836080Swollman			/* Ignore PCBs which were freed during copyout. */
23936080Swollman			if (xunp->xu_unp.unp_gencnt > oxug->xug_gen)
24036080Swollman				continue;
241279122Smarcel			if (*first) {
242279122Smarcel				xo_open_list("socket");
243279122Smarcel				*first = false;
244279122Smarcel			}
245279122Smarcel			xo_open_instance("socket");
24636080Swollman			unixdomainpr(xunp, so);
247279122Smarcel			xo_close_instance("socket");
24836080Swollman		}
24936080Swollman		if (xug != oxug && xug->xug_gen != oxug->xug_gen) {
25036080Swollman			if (oxug->xug_count > xug->xug_count) {
251279122Smarcel				xo_emit("Some {:type/%s} sockets may have "
252279122Smarcel				    "been {:action/deleted}.\n",
253279122Smarcel				    socktype[type]);
25436080Swollman			} else if (oxug->xug_count < xug->xug_count) {
255279122Smarcel				xo_emit("Some {:type/%s} sockets may have "
256279122Smarcel				    "been {:action/created}.\n",
257279122Smarcel				    socktype[type]);
25836080Swollman			} else {
259279122Smarcel				xo_emit("Some {:type/%s} sockets may have "
260279122Smarcel				    "been {:action/created or deleted}",
261279122Smarcel				    socktype[type]);
26236080Swollman			}
26336080Swollman		}
26436080Swollman		free(buf);
2651590Srgrimes	}
2661590Srgrimes}
2671590Srgrimes
2681590Srgrimesstatic void
26978314Sassarunixdomainpr(struct xunpcb *xunp, struct xsocket *so)
2701590Srgrimes{
27136080Swollman	struct unpcb *unp;
27236080Swollman	struct sockaddr_un *sa;
2731590Srgrimes	static int first = 1;
274295136Salfred	char buf1[33];
275279122Smarcel	static const char *titles[2] = {
276279122Smarcel	    "{T:/%-8.8s} {T:/%-6.6s} {T:/%-6.6s} {T:/%-6.6s} {T:/%8.8s} "
277279122Smarcel	    "{T:/%8.8s} {T:/%8.8s} {T:/%8.8s} {T:Addr}\n",
278279122Smarcel	    "{T:/%-16.16s} {T:/%-6.6s} {T:/%-6.6s} {T:/%-6.6s} {T:/%16.16s} "
279279122Smarcel	    "{T:/%16.16s} {T:/%16.16s} {T:/%16.16s} {T:Addr}\n"
280279122Smarcel	};
281279122Smarcel	static const char *format[2] = {
282279122Smarcel	    "{q:address/%8lx} {t:type/%-6.6s} "
283279122Smarcel	    "{:receive-bytes-waiting/%6u} "
284279122Smarcel	    "{:send-bytes-waiting/%6u} "
285279122Smarcel	    "{q:vnode/%8lx} {q:connection/%8lx} "
286279122Smarcel	    "{q:first-reference/%8lx} {q:next-reference/%8lx}",
287279122Smarcel	    "{q:address/%16lx} {t:type/%-6.6s} "
288279122Smarcel	    "{:receive-bytes-waiting/%6u} "
289279122Smarcel	    "{:send-bytes-waiting/%6u} "
290279122Smarcel	    "{q:vnode/%16lx} {q:connection/%16lx} "
291279122Smarcel	    "{q:first-reference/%16lx} {q:next-reference/%16lx}"
292279122Smarcel	};
293279122Smarcel	int fmt = (sizeof(void *) == 8) ? 1 : 0;
2941590Srgrimes
29536080Swollman	unp = &xunp->xu_unp;
29636080Swollman	if (unp->unp_addr)
29736080Swollman		sa = &xunp->xu_addr;
29836080Swollman	else
29928726Swollman		sa = (struct sockaddr_un *)0;
30036080Swollman
301186644Smaxim	if (first && !Lflag) {
302279122Smarcel		xo_emit("{T:Active UNIX domain sockets}\n");
303279122Smarcel		xo_emit(titles[fmt],
3041590Srgrimes		    "Address", "Type", "Recv-Q", "Send-Q",
3051590Srgrimes		    "Inode", "Conn", "Refs", "Nextref");
3061590Srgrimes		first = 0;
3071590Srgrimes	}
308186644Smaxim
309186644Smaxim	if (Lflag && so->so_qlimit == 0)
310186644Smaxim		return;
311186644Smaxim
312186644Smaxim	if (Lflag) {
313295136Salfred		snprintf(buf1, sizeof buf1, "%u/%u/%u", so->so_qlen,
314186644Smaxim		    so->so_incqlen, so->so_qlimit);
315295136Salfred		xo_emit("unix  {d:socket/%-32.32s}{e:queue-length/%u}"
316295136Salfred		    "{e:incomplete-queue-length/%u}{e:queue-limit/%u}",
317279122Smarcel		    buf1, so->so_qlen, so->so_incqlen, so->so_qlimit);
318186644Smaxim	} else {
319279122Smarcel		xo_emit(format[fmt],
320186644Smaxim		    (long)so->so_pcb, socktype[so->so_type], so->so_rcv.sb_cc,
321275326Sglebius		    so->so_snd.sb_cc, (long)unp->unp_vnode,
322275326Sglebius		    (long)unp->unp_conn,
323186644Smaxim		    (long)LIST_FIRST(&unp->unp_refs),
324186644Smaxim		    (long)LIST_NEXT(unp, unp_reflink));
325186644Smaxim	}
32628726Swollman	if (sa)
327279122Smarcel		xo_emit(" {:path/%.*s}",
32837453Sbde		    (int)(sa->sun_len - offsetof(struct sockaddr_un, sun_path)),
32936091Sache		    sa->sun_path);
330279122Smarcel	xo_emit("\n");
3311590Srgrimes}
332