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