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$");
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>
60171465Sjhb#include <strings.h>
6136080Swollman#include <kvm.h>
621590Srgrimes#include "netstat.h"
631590Srgrimes
64175061Sobrienstatic	void unixdomainpr(struct xunpcb *, struct xsocket *);
651590Srgrimes
6636080Swollmanstatic	const char *const socktype[] =
6736080Swollman    { "#0", "stream", "dgram", "raw", "rdm", "seqpacket" };
681590Srgrimes
69171465Sjhbstatic int
70171465Sjhbpcblist_sysctl(int type, char **bufp)
71171465Sjhb{
72171465Sjhb	char 	*buf;
73171465Sjhb	size_t	len;
74171465Sjhb	char mibvar[sizeof "net.local.seqpacket.pcblist"];
75171465Sjhb
76171465Sjhb	sprintf(mibvar, "net.local.%s.pcblist", socktype[type]);
77171465Sjhb
78171465Sjhb	len = 0;
79171465Sjhb	if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
80171465Sjhb		if (errno != ENOENT)
81171465Sjhb			warn("sysctl: %s", mibvar);
82171465Sjhb		return (-1);
83171465Sjhb	}
84171465Sjhb	if ((buf = malloc(len)) == 0) {
85171465Sjhb		warnx("malloc %lu bytes", (u_long)len);
86171465Sjhb		return (-2);
87171465Sjhb	}
88171465Sjhb	if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
89171465Sjhb		warn("sysctl: %s", mibvar);
90171465Sjhb		free(buf);
91171465Sjhb		return (-2);
92171465Sjhb	}
93171465Sjhb	*bufp = buf;
94171465Sjhb	return (0);
95171465Sjhb}
96171465Sjhb
97171465Sjhbstatic int
98171465Sjhbpcblist_kvm(u_long count_off, u_long gencnt_off, u_long head_off, char **bufp)
99171465Sjhb{
100171465Sjhb	struct unp_head head;
101171465Sjhb	struct unpcb *unp, unp_conn;
102171465Sjhb	u_char sun_len;
103171465Sjhb	struct socket so;
104171465Sjhb	struct xunpgen xug;
105171465Sjhb	struct xunpcb xu;
106171465Sjhb	unp_gen_t unp_gencnt;
107171465Sjhb	u_int	unp_count;
108171465Sjhb	char 	*buf, *p;
109171465Sjhb	size_t	len;
110171465Sjhb
111171465Sjhb	if (count_off == 0 || gencnt_off == 0)
112171465Sjhb		return (-2);
113171465Sjhb	if (head_off == 0)
114171465Sjhb		return (-1);
115171465Sjhb	kread(count_off, &unp_count, sizeof(unp_count));
116171465Sjhb	len = 2 * sizeof(xug) + (unp_count + unp_count / 8) * sizeof(xu);
117171465Sjhb	if ((buf = malloc(len)) == 0) {
118171465Sjhb		warnx("malloc %lu bytes", (u_long)len);
119171465Sjhb		return (-2);
120171465Sjhb	}
121171465Sjhb	p = buf;
122171465Sjhb
123175061Sobrien#define	COPYOUT(obj, size) do {						\
124171465Sjhb	if (len < (size)) {						\
125171465Sjhb		warnx("buffer size exceeded");				\
126171465Sjhb		goto fail;						\
127171465Sjhb	}								\
128171465Sjhb	bcopy((obj), p, (size));					\
129171465Sjhb	len -= (size);							\
130171465Sjhb	p += (size);							\
131171465Sjhb} while (0)
132171465Sjhb
133175061Sobrien#define	KREAD(off, buf, len) do {					\
134171465Sjhb	if (kread((uintptr_t)(off), (buf), (len)) != 0)			\
135171465Sjhb		goto fail;						\
136171465Sjhb} while (0)
137171465Sjhb
138171465Sjhb	/* Write out header. */
139171465Sjhb	kread(gencnt_off, &unp_gencnt, sizeof(unp_gencnt));
140171465Sjhb	xug.xug_len = sizeof xug;
141171465Sjhb	xug.xug_count = unp_count;
142171465Sjhb	xug.xug_gen = unp_gencnt;
143171465Sjhb	xug.xug_sogen = 0;
144171465Sjhb	COPYOUT(&xug, sizeof xug);
145171465Sjhb
146171465Sjhb	/* Walk the PCB list. */
147171465Sjhb	xu.xu_len = sizeof xu;
148171465Sjhb	KREAD(head_off, &head, sizeof(head));
149171465Sjhb	LIST_FOREACH(unp, &head, unp_link) {
150171465Sjhb		xu.xu_unpp = unp;
151171465Sjhb		KREAD(unp, &xu.xu_unp, sizeof (*unp));
152171465Sjhb		unp = &xu.xu_unp;
153171465Sjhb
154171465Sjhb		if (unp->unp_gencnt > unp_gencnt)
155171465Sjhb			continue;
156171465Sjhb		if (unp->unp_addr != NULL) {
157171465Sjhb			KREAD(unp->unp_addr, &sun_len, sizeof(sun_len));
158171465Sjhb			KREAD(unp->unp_addr, &xu.xu_addr, sun_len);
159171465Sjhb		}
160171465Sjhb		if (unp->unp_conn != NULL) {
161171465Sjhb			KREAD(unp->unp_conn, &unp_conn, sizeof(unp_conn));
162171465Sjhb			if (unp_conn.unp_addr != NULL) {
163171465Sjhb				KREAD(unp_conn.unp_addr, &sun_len,
164171465Sjhb				    sizeof(sun_len));
165171465Sjhb				KREAD(unp_conn.unp_addr, &xu.xu_caddr, sun_len);
166171465Sjhb			}
167171465Sjhb		}
168171465Sjhb		KREAD(unp->unp_socket, &so, sizeof(so));
169171465Sjhb		if (sotoxsocket(&so, &xu.xu_socket) != 0)
170171465Sjhb			goto fail;
171171465Sjhb		COPYOUT(&xu, sizeof(xu));
172171465Sjhb	}
173171465Sjhb
174171465Sjhb	/* Reread the counts and write the footer. */
175171465Sjhb	kread(count_off, &unp_count, sizeof(unp_count));
176171465Sjhb	kread(gencnt_off, &unp_gencnt, sizeof(unp_gencnt));
177171465Sjhb	xug.xug_count = unp_count;
178171465Sjhb	xug.xug_gen = unp_gencnt;
179171465Sjhb	COPYOUT(&xug, sizeof xug);
180171465Sjhb
181171465Sjhb	*bufp = buf;
182171465Sjhb	return (0);
183171465Sjhb
184171465Sjhbfail:
185171465Sjhb	free(buf);
186171465Sjhb	return (-1);
187171465Sjhb#undef COPYOUT
188171465Sjhb#undef KREAD
189171465Sjhb}
190171465Sjhb
1911590Srgrimesvoid
192197777Srwatsonunixpr(u_long count_off, u_long gencnt_off, u_long dhead_off, u_long shead_off,
193197777Srwatson    u_long sphead_off)
1941590Srgrimes{
19536080Swollman	char 	*buf;
196171465Sjhb	int	ret, type;
19736080Swollman	struct	xsocket *so;
19836080Swollman	struct	xunpgen *xug, *oxug;
19936080Swollman	struct	xunpcb *xunp;
200197777Srwatson	u_long	head_off;
2011590Srgrimes
202246988Scharnier	buf = NULL;
20344091Sfenner	for (type = SOCK_STREAM; type <= SOCK_SEQPACKET; type++) {
204171465Sjhb		if (live)
205171465Sjhb			ret = pcblist_sysctl(type, &buf);
206197777Srwatson		else {
207197777Srwatson			head_off = 0;
208197777Srwatson			switch (type) {
209197777Srwatson			case SOCK_STREAM:
210197777Srwatson				head_off = shead_off;
211197777Srwatson				break;
212197777Srwatson
213197777Srwatson			case SOCK_DGRAM:
214197777Srwatson				head_off = dhead_off;
215197777Srwatson				break;
216197777Srwatson
217197777Srwatson			case SOCK_SEQPACKET:
218197777Srwatson				head_off = sphead_off;
219197777Srwatson				break;
220197777Srwatson			}
221197777Srwatson			ret = pcblist_kvm(count_off, gencnt_off, head_off,
222197777Srwatson			    &buf);
223197777Srwatson		}
224171465Sjhb		if (ret == -1)
2251590Srgrimes			continue;
226171465Sjhb		if (ret < 0)
22736080Swollman			return;
22836080Swollman
22936080Swollman		oxug = xug = (struct xunpgen *)buf;
23036080Swollman		for (xug = (struct xunpgen *)((char *)xug + xug->xug_len);
23136080Swollman		     xug->xug_len > sizeof(struct xunpgen);
23236080Swollman		     xug = (struct xunpgen *)((char *)xug + xug->xug_len)) {
23336080Swollman			xunp = (struct xunpcb *)xug;
23436080Swollman			so = &xunp->xu_socket;
23536080Swollman
23636080Swollman			/* Ignore PCBs which were freed during copyout. */
23736080Swollman			if (xunp->xu_unp.unp_gencnt > oxug->xug_gen)
23836080Swollman				continue;
23936080Swollman			unixdomainpr(xunp, so);
24036080Swollman		}
24136080Swollman		if (xug != oxug && xug->xug_gen != oxug->xug_gen) {
24236080Swollman			if (oxug->xug_count > xug->xug_count) {
24336080Swollman				printf("Some %s sockets may have been deleted.\n",
24436080Swollman				       socktype[type]);
24536080Swollman			} else if (oxug->xug_count < xug->xug_count) {
24636080Swollman				printf("Some %s sockets may have been created.\n",
24736080Swollman			       socktype[type]);
24836080Swollman			} else {
24936080Swollman				printf("Some %s sockets may have been created or deleted",
25036080Swollman			       socktype[type]);
25136080Swollman			}
25236080Swollman		}
25336080Swollman		free(buf);
2541590Srgrimes	}
2551590Srgrimes}
2561590Srgrimes
2571590Srgrimesstatic void
25878314Sassarunixdomainpr(struct xunpcb *xunp, struct xsocket *so)
2591590Srgrimes{
26036080Swollman	struct unpcb *unp;
26136080Swollman	struct sockaddr_un *sa;
2621590Srgrimes	static int first = 1;
263186644Smaxim	char buf1[15];
2641590Srgrimes
26536080Swollman	unp = &xunp->xu_unp;
26636080Swollman	if (unp->unp_addr)
26736080Swollman		sa = &xunp->xu_addr;
26836080Swollman	else
26928726Swollman		sa = (struct sockaddr_un *)0;
27036080Swollman
271186644Smaxim	if (first && !Lflag) {
2721590Srgrimes		printf("Active UNIX domain sockets\n");
2731590Srgrimes		printf(
2741590Srgrimes"%-8.8s %-6.6s %-6.6s %-6.6s %8.8s %8.8s %8.8s %8.8s Addr\n",
2751590Srgrimes		    "Address", "Type", "Recv-Q", "Send-Q",
2761590Srgrimes		    "Inode", "Conn", "Refs", "Nextref");
2771590Srgrimes		first = 0;
2781590Srgrimes	}
279186644Smaxim
280186644Smaxim	if (Lflag && so->so_qlimit == 0)
281186644Smaxim		return;
282186644Smaxim
283186644Smaxim	if (Lflag) {
284186644Smaxim		snprintf(buf1, 15, "%d/%d/%d", so->so_qlen,
285186644Smaxim		    so->so_incqlen, so->so_qlimit);
286186644Smaxim		printf("unix  %-14.14s", buf1);
287186644Smaxim	} else {
288186644Smaxim		printf("%8lx %-6.6s %6u %6u %8lx %8lx %8lx %8lx",
289186644Smaxim		    (long)so->so_pcb, socktype[so->so_type], so->so_rcv.sb_cc,
290186644Smaxim		    so->so_snd.sb_cc, (long)unp->unp_vnode, (long)unp->unp_conn,
291186644Smaxim		    (long)LIST_FIRST(&unp->unp_refs),
292186644Smaxim		    (long)LIST_NEXT(unp, unp_reflink));
293186644Smaxim	}
29428726Swollman	if (sa)
29536091Sache		printf(" %.*s",
29637453Sbde		    (int)(sa->sun_len - offsetof(struct sockaddr_un, sun_path)),
29736091Sache		    sa->sun_path);
2981590Srgrimes	putchar('\n');
2991590Srgrimes}
300