xref: /f-stack/tools/netstat/unix.c (revision d4a07e70)
11eaf0ac3Slogwang /*-
222ce4affSfengbojiang  * SPDX-License-Identifier: BSD-3-Clause
322ce4affSfengbojiang  *
41eaf0ac3Slogwang  * Copyright (c) 1983, 1988, 1993
51eaf0ac3Slogwang  *	The Regents of the University of California.  All rights reserved.
61eaf0ac3Slogwang  *
71eaf0ac3Slogwang  * Redistribution and use in source and binary forms, with or without
81eaf0ac3Slogwang  * modification, are permitted provided that the following conditions
91eaf0ac3Slogwang  * are met:
101eaf0ac3Slogwang  * 1. Redistributions of source code must retain the above copyright
111eaf0ac3Slogwang  *    notice, this list of conditions and the following disclaimer.
121eaf0ac3Slogwang  * 2. Redistributions in binary form must reproduce the above copyright
131eaf0ac3Slogwang  *    notice, this list of conditions and the following disclaimer in the
141eaf0ac3Slogwang  *    documentation and/or other materials provided with the distribution.
1522ce4affSfengbojiang  * 3. Neither the name of the University nor the names of its contributors
161eaf0ac3Slogwang  *    may be used to endorse or promote products derived from this software
171eaf0ac3Slogwang  *    without specific prior written permission.
181eaf0ac3Slogwang  *
191eaf0ac3Slogwang  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
201eaf0ac3Slogwang  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
211eaf0ac3Slogwang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
221eaf0ac3Slogwang  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
231eaf0ac3Slogwang  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
241eaf0ac3Slogwang  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
251eaf0ac3Slogwang  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
261eaf0ac3Slogwang  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
271eaf0ac3Slogwang  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
281eaf0ac3Slogwang  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
291eaf0ac3Slogwang  * SUCH DAMAGE.
301eaf0ac3Slogwang  */
311eaf0ac3Slogwang 
321eaf0ac3Slogwang #if 0
331eaf0ac3Slogwang #ifndef lint
341eaf0ac3Slogwang static char sccsid[] = "@(#)unix.c	8.1 (Berkeley) 6/6/93";
351eaf0ac3Slogwang #endif /* not lint */
361eaf0ac3Slogwang #endif
371eaf0ac3Slogwang 
381eaf0ac3Slogwang #include <sys/cdefs.h>
391eaf0ac3Slogwang __FBSDID("$FreeBSD$");
401eaf0ac3Slogwang 
411eaf0ac3Slogwang /*
421eaf0ac3Slogwang  * Display protocol blocks in the unix domain.
431eaf0ac3Slogwang  */
441eaf0ac3Slogwang #include <sys/param.h>
451eaf0ac3Slogwang #include <sys/queue.h>
461eaf0ac3Slogwang #include <sys/protosw.h>
471eaf0ac3Slogwang #include <sys/socket.h>
4822ce4affSfengbojiang #define	_WANT_SOCKET
491eaf0ac3Slogwang #include <sys/socketvar.h>
501eaf0ac3Slogwang #include <sys/mbuf.h>
511eaf0ac3Slogwang #include <sys/sysctl.h>
521eaf0ac3Slogwang #include <sys/un.h>
5322ce4affSfengbojiang #define	_WANT_UNPCB
541eaf0ac3Slogwang #include <sys/unpcb.h>
551eaf0ac3Slogwang 
561eaf0ac3Slogwang #include <netinet/in.h>
571eaf0ac3Slogwang 
581eaf0ac3Slogwang #include <errno.h>
591eaf0ac3Slogwang #include <err.h>
601eaf0ac3Slogwang #include <stddef.h>
611eaf0ac3Slogwang #include <stdint.h>
621eaf0ac3Slogwang #include <stdio.h>
631eaf0ac3Slogwang #include <stdlib.h>
641eaf0ac3Slogwang #include <stdbool.h>
651eaf0ac3Slogwang #include <strings.h>
66*d4a07e70Sfengbojiang #ifndef FSTACK
671eaf0ac3Slogwang #include <kvm.h>
68*d4a07e70Sfengbojiang #endif
691eaf0ac3Slogwang #include <libxo/xo.h>
701eaf0ac3Slogwang #include "netstat.h"
711eaf0ac3Slogwang 
721eaf0ac3Slogwang static	void unixdomainpr(struct xunpcb *, struct xsocket *);
731eaf0ac3Slogwang 
741eaf0ac3Slogwang static	const char *const socktype[] =
751eaf0ac3Slogwang     { "#0", "stream", "dgram", "raw", "rdm", "seqpacket" };
761eaf0ac3Slogwang 
771eaf0ac3Slogwang static int
pcblist_sysctl(int type,char ** bufp)781eaf0ac3Slogwang pcblist_sysctl(int type, char **bufp)
791eaf0ac3Slogwang {
801eaf0ac3Slogwang 	char 	*buf;
811eaf0ac3Slogwang 	size_t	len;
821eaf0ac3Slogwang 	char mibvar[sizeof "net.local.seqpacket.pcblist"];
831eaf0ac3Slogwang 
8422ce4affSfengbojiang 	snprintf(mibvar, sizeof(mibvar), "net.local.%s.pcblist", socktype[type]);
851eaf0ac3Slogwang 
861eaf0ac3Slogwang 	len = 0;
871eaf0ac3Slogwang 	if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
881eaf0ac3Slogwang 		if (errno != ENOENT)
891eaf0ac3Slogwang 			xo_warn("sysctl: %s", mibvar);
901eaf0ac3Slogwang 		return (-1);
911eaf0ac3Slogwang 	}
921eaf0ac3Slogwang 	if ((buf = malloc(len)) == NULL) {
931eaf0ac3Slogwang 		xo_warnx("malloc %lu bytes", (u_long)len);
941eaf0ac3Slogwang 		return (-2);
951eaf0ac3Slogwang 	}
961eaf0ac3Slogwang 	if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
971eaf0ac3Slogwang 		xo_warn("sysctl: %s", mibvar);
981eaf0ac3Slogwang 		free(buf);
991eaf0ac3Slogwang 		return (-2);
1001eaf0ac3Slogwang 	}
1011eaf0ac3Slogwang 	*bufp = buf;
1021eaf0ac3Slogwang 	return (0);
1031eaf0ac3Slogwang }
1041eaf0ac3Slogwang 
105*d4a07e70Sfengbojiang #ifndef FSTACK
1061eaf0ac3Slogwang static int
pcblist_kvm(u_long count_off,u_long gencnt_off,u_long head_off,char ** bufp)1071eaf0ac3Slogwang pcblist_kvm(u_long count_off, u_long gencnt_off, u_long head_off, char **bufp)
1081eaf0ac3Slogwang {
1091eaf0ac3Slogwang 	struct unp_head head;
11022ce4affSfengbojiang 	struct unpcb *unp, unp0, unp_conn;
1111eaf0ac3Slogwang 	u_char sun_len;
1121eaf0ac3Slogwang 	struct socket so;
1131eaf0ac3Slogwang 	struct xunpgen xug;
1141eaf0ac3Slogwang 	struct xunpcb xu;
1151eaf0ac3Slogwang 	unp_gen_t unp_gencnt;
1161eaf0ac3Slogwang 	u_int	unp_count;
1171eaf0ac3Slogwang 	char 	*buf, *p;
1181eaf0ac3Slogwang 	size_t	len;
1191eaf0ac3Slogwang 
1201eaf0ac3Slogwang 	if (count_off == 0 || gencnt_off == 0)
1211eaf0ac3Slogwang 		return (-2);
1221eaf0ac3Slogwang 	if (head_off == 0)
1231eaf0ac3Slogwang 		return (-1);
1241eaf0ac3Slogwang 	kread(count_off, &unp_count, sizeof(unp_count));
1251eaf0ac3Slogwang 	len = 2 * sizeof(xug) + (unp_count + unp_count / 8) * sizeof(xu);
1261eaf0ac3Slogwang 	if ((buf = malloc(len)) == NULL) {
1271eaf0ac3Slogwang 		xo_warnx("malloc %lu bytes", (u_long)len);
1281eaf0ac3Slogwang 		return (-2);
1291eaf0ac3Slogwang 	}
1301eaf0ac3Slogwang 	p = buf;
1311eaf0ac3Slogwang 
1321eaf0ac3Slogwang #define	COPYOUT(obj, size) do {						\
1331eaf0ac3Slogwang 	if (len < (size)) {						\
1341eaf0ac3Slogwang 		xo_warnx("buffer size exceeded");			\
1351eaf0ac3Slogwang 		goto fail;						\
1361eaf0ac3Slogwang 	}								\
1371eaf0ac3Slogwang 	bcopy((obj), p, (size));					\
1381eaf0ac3Slogwang 	len -= (size);							\
1391eaf0ac3Slogwang 	p += (size);							\
1401eaf0ac3Slogwang } while (0)
1411eaf0ac3Slogwang 
1421eaf0ac3Slogwang #define	KREAD(off, buf, len) do {					\
1431eaf0ac3Slogwang 	if (kread((uintptr_t)(off), (buf), (len)) != 0)			\
1441eaf0ac3Slogwang 		goto fail;						\
1451eaf0ac3Slogwang } while (0)
1461eaf0ac3Slogwang 
1471eaf0ac3Slogwang 	/* Write out header. */
1481eaf0ac3Slogwang 	kread(gencnt_off, &unp_gencnt, sizeof(unp_gencnt));
1491eaf0ac3Slogwang 	xug.xug_len = sizeof xug;
1501eaf0ac3Slogwang 	xug.xug_count = unp_count;
1511eaf0ac3Slogwang 	xug.xug_gen = unp_gencnt;
1521eaf0ac3Slogwang 	xug.xug_sogen = 0;
1531eaf0ac3Slogwang 	COPYOUT(&xug, sizeof xug);
1541eaf0ac3Slogwang 
1551eaf0ac3Slogwang 	/* Walk the PCB list. */
1561eaf0ac3Slogwang 	xu.xu_len = sizeof xu;
1571eaf0ac3Slogwang 	KREAD(head_off, &head, sizeof(head));
1581eaf0ac3Slogwang 	LIST_FOREACH(unp, &head, unp_link) {
15922ce4affSfengbojiang 		xu.xu_unpp = (uintptr_t)unp;
16022ce4affSfengbojiang 		KREAD(unp, &unp0, sizeof (*unp));
16122ce4affSfengbojiang 		unp = &unp0;
1621eaf0ac3Slogwang 
1631eaf0ac3Slogwang 		if (unp->unp_gencnt > unp_gencnt)
1641eaf0ac3Slogwang 			continue;
1651eaf0ac3Slogwang 		if (unp->unp_addr != NULL) {
1661eaf0ac3Slogwang 			KREAD(unp->unp_addr, &sun_len, sizeof(sun_len));
1671eaf0ac3Slogwang 			KREAD(unp->unp_addr, &xu.xu_addr, sun_len);
1681eaf0ac3Slogwang 		}
1691eaf0ac3Slogwang 		if (unp->unp_conn != NULL) {
1701eaf0ac3Slogwang 			KREAD(unp->unp_conn, &unp_conn, sizeof(unp_conn));
1711eaf0ac3Slogwang 			if (unp_conn.unp_addr != NULL) {
1721eaf0ac3Slogwang 				KREAD(unp_conn.unp_addr, &sun_len,
1731eaf0ac3Slogwang 				    sizeof(sun_len));
1741eaf0ac3Slogwang 				KREAD(unp_conn.unp_addr, &xu.xu_caddr, sun_len);
1751eaf0ac3Slogwang 			}
1761eaf0ac3Slogwang 		}
1771eaf0ac3Slogwang 		KREAD(unp->unp_socket, &so, sizeof(so));
1781eaf0ac3Slogwang 		if (sotoxsocket(&so, &xu.xu_socket) != 0)
1791eaf0ac3Slogwang 			goto fail;
1801eaf0ac3Slogwang 		COPYOUT(&xu, sizeof(xu));
1811eaf0ac3Slogwang 	}
1821eaf0ac3Slogwang 
1831eaf0ac3Slogwang 	/* Reread the counts and write the footer. */
1841eaf0ac3Slogwang 	kread(count_off, &unp_count, sizeof(unp_count));
1851eaf0ac3Slogwang 	kread(gencnt_off, &unp_gencnt, sizeof(unp_gencnt));
1861eaf0ac3Slogwang 	xug.xug_count = unp_count;
1871eaf0ac3Slogwang 	xug.xug_gen = unp_gencnt;
1881eaf0ac3Slogwang 	COPYOUT(&xug, sizeof xug);
1891eaf0ac3Slogwang 
1901eaf0ac3Slogwang 	*bufp = buf;
1911eaf0ac3Slogwang 	return (0);
1921eaf0ac3Slogwang 
1931eaf0ac3Slogwang fail:
1941eaf0ac3Slogwang 	free(buf);
1951eaf0ac3Slogwang 	return (-1);
1961eaf0ac3Slogwang #undef COPYOUT
1971eaf0ac3Slogwang #undef KREAD
1981eaf0ac3Slogwang }
199*d4a07e70Sfengbojiang #endif
2001eaf0ac3Slogwang 
2011eaf0ac3Slogwang void
unixpr(u_long count_off,u_long gencnt_off,u_long dhead_off,u_long shead_off,u_long sphead_off,bool * first)2021eaf0ac3Slogwang unixpr(u_long count_off, u_long gencnt_off, u_long dhead_off, u_long shead_off,
2031eaf0ac3Slogwang     u_long sphead_off, bool *first)
2041eaf0ac3Slogwang {
2051eaf0ac3Slogwang 	char 	*buf;
2061eaf0ac3Slogwang 	int	ret, type;
2071eaf0ac3Slogwang 	struct	xsocket *so;
2081eaf0ac3Slogwang 	struct	xunpgen *xug, *oxug;
2091eaf0ac3Slogwang 	struct	xunpcb *xunp;
210*d4a07e70Sfengbojiang #ifndef FSTACK
2111eaf0ac3Slogwang 	u_long	head_off;
212*d4a07e70Sfengbojiang #endif
2131eaf0ac3Slogwang 
2141eaf0ac3Slogwang 	buf = NULL;
2151eaf0ac3Slogwang 	for (type = SOCK_STREAM; type <= SOCK_SEQPACKET; type++) {
2161eaf0ac3Slogwang 		if (live)
2171eaf0ac3Slogwang 			ret = pcblist_sysctl(type, &buf);
2181eaf0ac3Slogwang 		else {
219*d4a07e70Sfengbojiang #ifndef FSTACK
2201eaf0ac3Slogwang 			head_off = 0;
2211eaf0ac3Slogwang 			switch (type) {
2221eaf0ac3Slogwang 			case SOCK_STREAM:
2231eaf0ac3Slogwang 				head_off = shead_off;
2241eaf0ac3Slogwang 				break;
2251eaf0ac3Slogwang 
2261eaf0ac3Slogwang 			case SOCK_DGRAM:
2271eaf0ac3Slogwang 				head_off = dhead_off;
2281eaf0ac3Slogwang 				break;
2291eaf0ac3Slogwang 
2301eaf0ac3Slogwang 			case SOCK_SEQPACKET:
2311eaf0ac3Slogwang 				head_off = sphead_off;
2321eaf0ac3Slogwang 				break;
2331eaf0ac3Slogwang 			}
2341eaf0ac3Slogwang 			ret = pcblist_kvm(count_off, gencnt_off, head_off,
2351eaf0ac3Slogwang 			    &buf);
236*d4a07e70Sfengbojiang #endif
2371eaf0ac3Slogwang 		}
2381eaf0ac3Slogwang 		if (ret == -1)
2391eaf0ac3Slogwang 			continue;
2401eaf0ac3Slogwang 		if (ret < 0)
2411eaf0ac3Slogwang 			return;
2421eaf0ac3Slogwang 
2431eaf0ac3Slogwang 		oxug = xug = (struct xunpgen *)buf;
2441eaf0ac3Slogwang 		for (xug = (struct xunpgen *)((char *)xug + xug->xug_len);
2451eaf0ac3Slogwang 		    xug->xug_len > sizeof(struct xunpgen);
2461eaf0ac3Slogwang 		    xug = (struct xunpgen *)((char *)xug + xug->xug_len)) {
2471eaf0ac3Slogwang 			xunp = (struct xunpcb *)xug;
2481eaf0ac3Slogwang 			so = &xunp->xu_socket;
2491eaf0ac3Slogwang 
2501eaf0ac3Slogwang 			/* Ignore PCBs which were freed during copyout. */
25122ce4affSfengbojiang 			if (xunp->unp_gencnt > oxug->xug_gen)
2521eaf0ac3Slogwang 				continue;
2531eaf0ac3Slogwang 			if (*first) {
2541eaf0ac3Slogwang 				xo_open_list("socket");
2551eaf0ac3Slogwang 				*first = false;
2561eaf0ac3Slogwang 			}
2571eaf0ac3Slogwang 			xo_open_instance("socket");
2581eaf0ac3Slogwang 			unixdomainpr(xunp, so);
2591eaf0ac3Slogwang 			xo_close_instance("socket");
2601eaf0ac3Slogwang 		}
2611eaf0ac3Slogwang 		if (xug != oxug && xug->xug_gen != oxug->xug_gen) {
2621eaf0ac3Slogwang 			if (oxug->xug_count > xug->xug_count) {
2631eaf0ac3Slogwang 				xo_emit("Some {:type/%s} sockets may have "
2641eaf0ac3Slogwang 				    "been {:action/deleted}.\n",
2651eaf0ac3Slogwang 				    socktype[type]);
2661eaf0ac3Slogwang 			} else if (oxug->xug_count < xug->xug_count) {
2671eaf0ac3Slogwang 				xo_emit("Some {:type/%s} sockets may have "
2681eaf0ac3Slogwang 				    "been {:action/created}.\n",
2691eaf0ac3Slogwang 				    socktype[type]);
2701eaf0ac3Slogwang 			} else {
2711eaf0ac3Slogwang 				xo_emit("Some {:type/%s} sockets may have "
2721eaf0ac3Slogwang 				    "been {:action/created or deleted}",
2731eaf0ac3Slogwang 				    socktype[type]);
2741eaf0ac3Slogwang 			}
2751eaf0ac3Slogwang 		}
2761eaf0ac3Slogwang 		free(buf);
2771eaf0ac3Slogwang 	}
2781eaf0ac3Slogwang }
2791eaf0ac3Slogwang 
2801eaf0ac3Slogwang static void
unixdomainpr(struct xunpcb * xunp,struct xsocket * so)2811eaf0ac3Slogwang unixdomainpr(struct xunpcb *xunp, struct xsocket *so)
2821eaf0ac3Slogwang {
2831eaf0ac3Slogwang 	struct sockaddr_un *sa;
2841eaf0ac3Slogwang 	static int first = 1;
2851eaf0ac3Slogwang 	char buf1[33];
2861eaf0ac3Slogwang 	static const char *titles[2] = {
2871eaf0ac3Slogwang 	    "{T:/%-8.8s} {T:/%-6.6s} {T:/%-6.6s} {T:/%-6.6s} {T:/%8.8s} "
2881eaf0ac3Slogwang 	    "{T:/%8.8s} {T:/%8.8s} {T:/%8.8s} {T:Addr}\n",
2891eaf0ac3Slogwang 	    "{T:/%-16.16s} {T:/%-6.6s} {T:/%-6.6s} {T:/%-6.6s} {T:/%16.16s} "
2901eaf0ac3Slogwang 	    "{T:/%16.16s} {T:/%16.16s} {T:/%16.16s} {T:Addr}\n"
2911eaf0ac3Slogwang 	};
2921eaf0ac3Slogwang 	static const char *format[2] = {
2931eaf0ac3Slogwang 	    "{q:address/%8lx} {t:type/%-6.6s} "
2941eaf0ac3Slogwang 	    "{:receive-bytes-waiting/%6u} "
2951eaf0ac3Slogwang 	    "{:send-bytes-waiting/%6u} "
2961eaf0ac3Slogwang 	    "{q:vnode/%8lx} {q:connection/%8lx} "
2971eaf0ac3Slogwang 	    "{q:first-reference/%8lx} {q:next-reference/%8lx}",
2981eaf0ac3Slogwang 	    "{q:address/%16lx} {t:type/%-6.6s} "
2991eaf0ac3Slogwang 	    "{:receive-bytes-waiting/%6u} "
3001eaf0ac3Slogwang 	    "{:send-bytes-waiting/%6u} "
3011eaf0ac3Slogwang 	    "{q:vnode/%16lx} {q:connection/%16lx} "
3021eaf0ac3Slogwang 	    "{q:first-reference/%16lx} {q:next-reference/%16lx}"
3031eaf0ac3Slogwang 	};
3041eaf0ac3Slogwang 	int fmt = (sizeof(void *) == 8) ? 1 : 0;
3051eaf0ac3Slogwang 
30622ce4affSfengbojiang 	sa = (xunp->xu_addr.sun_family == AF_UNIX) ? &xunp->xu_addr : NULL;
3071eaf0ac3Slogwang 
3081eaf0ac3Slogwang 	if (first && !Lflag) {
3091eaf0ac3Slogwang 		xo_emit("{T:Active UNIX domain sockets}\n");
3101eaf0ac3Slogwang 		xo_emit(titles[fmt],
3111eaf0ac3Slogwang 		    "Address", "Type", "Recv-Q", "Send-Q",
3121eaf0ac3Slogwang 		    "Inode", "Conn", "Refs", "Nextref");
3131eaf0ac3Slogwang 		first = 0;
3141eaf0ac3Slogwang 	}
3151eaf0ac3Slogwang 
3161eaf0ac3Slogwang 	if (Lflag && so->so_qlimit == 0)
3171eaf0ac3Slogwang 		return;
3181eaf0ac3Slogwang 
3191eaf0ac3Slogwang 	if (Lflag) {
3201eaf0ac3Slogwang 		snprintf(buf1, sizeof buf1, "%u/%u/%u", so->so_qlen,
3211eaf0ac3Slogwang 		    so->so_incqlen, so->so_qlimit);
3221eaf0ac3Slogwang 		xo_emit("unix  {d:socket/%-32.32s}{e:queue-length/%u}"
3231eaf0ac3Slogwang 		    "{e:incomplete-queue-length/%u}{e:queue-limit/%u}",
3241eaf0ac3Slogwang 		    buf1, so->so_qlen, so->so_incqlen, so->so_qlimit);
3251eaf0ac3Slogwang 	} else {
3261eaf0ac3Slogwang 		xo_emit(format[fmt],
3271eaf0ac3Slogwang 		    (long)so->so_pcb, socktype[so->so_type], so->so_rcv.sb_cc,
32822ce4affSfengbojiang 		    so->so_snd.sb_cc, (long)xunp->unp_vnode,
32922ce4affSfengbojiang 		    (long)xunp->unp_conn, (long)xunp->xu_firstref,
33022ce4affSfengbojiang 		    (long)xunp->xu_nextref);
3311eaf0ac3Slogwang 	}
3321eaf0ac3Slogwang 	if (sa)
3331eaf0ac3Slogwang 		xo_emit(" {:path/%.*s}",
3341eaf0ac3Slogwang 		    (int)(sa->sun_len - offsetof(struct sockaddr_un, sun_path)),
3351eaf0ac3Slogwang 		    sa->sun_path);
3361eaf0ac3Slogwang 	xo_emit("\n");
3371eaf0ac3Slogwang }
338