sockstat.c revision 284441
1/*-
2 * Copyright (c) 2002 Dag-Erling Co��dan Sm��rgrav
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer
10 *    in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/10/usr.bin/sockstat/sockstat.c 284441 2015-06-16 08:36:57Z tuexen $");
31
32#include <sys/param.h>
33#include <sys/socket.h>
34#include <sys/socketvar.h>
35#include <sys/sysctl.h>
36#include <sys/file.h>
37#include <sys/user.h>
38
39#include <sys/un.h>
40#include <sys/unpcb.h>
41
42#include <net/route.h>
43
44#include <netinet/in.h>
45#include <netinet/in_pcb.h>
46#include <netinet/sctp.h>
47#include <netinet/tcp.h>
48#include <netinet/tcp_seq.h>
49#include <netinet/tcp_var.h>
50#include <arpa/inet.h>
51
52#include <ctype.h>
53#include <err.h>
54#include <errno.h>
55#include <netdb.h>
56#include <pwd.h>
57#include <stdarg.h>
58#include <stdio.h>
59#include <stdlib.h>
60#include <string.h>
61#include <unistd.h>
62
63static int	 opt_4;		/* Show IPv4 sockets */
64static int	 opt_6;		/* Show IPv6 sockets */
65static int	 opt_c;		/* Show connected sockets */
66static int	 opt_j;		/* Show specified jail */
67static int	 opt_L;		/* Don't show IPv4 or IPv6 loopback sockets */
68static int	 opt_l;		/* Show listening sockets */
69static int	 opt_u;		/* Show Unix domain sockets */
70static int	 opt_v;		/* Verbose mode */
71
72/*
73 * Default protocols to use if no -P was defined.
74 */
75static const char *default_protos[] = {"sctp", "tcp", "udp", "divert" };
76static size_t	   default_numprotos =
77    sizeof(default_protos) / sizeof(default_protos[0]);
78
79static int	*protos;	/* protocols to use */
80static size_t	 numprotos;	/* allocated size of protos[] */
81
82static int	*ports;
83
84#define INT_BIT (sizeof(int)*CHAR_BIT)
85#define SET_PORT(p) do { ports[p / INT_BIT] |= 1 << (p % INT_BIT); } while (0)
86#define CHK_PORT(p) (ports[p / INT_BIT] & (1 << (p % INT_BIT)))
87
88struct addr {
89	struct sockaddr_storage address;
90	struct addr *next;
91};
92
93struct sock {
94	void *socket;
95	void *pcb;
96	int shown;
97	int vflag;
98	int family;
99	int proto;
100	const char *protoname;
101	struct addr *laddr;
102	struct addr *faddr;
103	struct sock *next;
104};
105
106#define HASHSIZE 1009
107static struct sock *sockhash[HASHSIZE];
108
109static struct xfile *xfiles;
110static int nxfiles;
111
112static int
113xprintf(const char *fmt, ...)
114{
115	va_list ap;
116	int len;
117
118	va_start(ap, fmt);
119	len = vprintf(fmt, ap);
120	va_end(ap);
121	if (len < 0)
122		err(1, "printf()");
123	return (len);
124}
125
126
127static int
128get_proto_type(const char *proto)
129{
130	struct protoent *pent;
131
132	if (strlen(proto) == 0)
133		return (0);
134	pent = getprotobyname(proto);
135	if (pent == NULL) {
136		warn("getprotobyname");
137		return (-1);
138	}
139	return (pent->p_proto);
140}
141
142
143static void init_protos(int num)
144{
145	int proto_count = 0;
146
147	if (num > 0) {
148		proto_count = num;
149	} else {
150		/* Find the maximum number of possible protocols. */
151		while (getprotoent() != NULL)
152			proto_count++;
153		endprotoent();
154	}
155
156	if ((protos = malloc(sizeof(int) * proto_count)) == NULL)
157		err(1, "malloc");
158	numprotos = proto_count;
159}
160
161
162static int
163parse_protos(char *protospec)
164{
165	char *prot;
166	char *tmp = protospec;
167	int proto_type, proto_index;
168
169	if (protospec == NULL)
170		return (-1);
171
172	init_protos(0);
173	proto_index = 0;
174	while ((prot = strsep(&tmp, ",")) != NULL) {
175		if (strlen(prot) == 0)
176			continue;
177		proto_type = get_proto_type(prot);
178		if (proto_type != -1)
179			protos[proto_index++] = proto_type;
180	}
181	numprotos = proto_index;
182	return (proto_index);
183}
184
185
186static void
187parse_ports(const char *portspec)
188{
189	const char *p, *q;
190	int port, end;
191
192	if (ports == NULL)
193		if ((ports = calloc(65536 / INT_BIT, sizeof(int))) == NULL)
194			err(1, "calloc()");
195	p = portspec;
196	while (*p != '\0') {
197		if (!isdigit(*p))
198			errx(1, "syntax error in port range");
199		for (q = p; *q != '\0' && isdigit(*q); ++q)
200			/* nothing */ ;
201		for (port = 0; p < q; ++p)
202			port = port * 10 + digittoint(*p);
203		if (port < 0 || port > 65535)
204			errx(1, "invalid port number");
205		SET_PORT(port);
206		switch (*p) {
207		case '-':
208			++p;
209			break;
210		case ',':
211			++p;
212			/* fall through */
213		case '\0':
214		default:
215			continue;
216		}
217		for (q = p; *q != '\0' && isdigit(*q); ++q)
218			/* nothing */ ;
219		for (end = 0; p < q; ++p)
220			end = end * 10 + digittoint(*p);
221		if (end < port || end > 65535)
222			errx(1, "invalid port number");
223		while (port++ < end)
224			SET_PORT(port);
225		if (*p == ',')
226			++p;
227	}
228}
229
230static void
231sockaddr(struct sockaddr_storage *sa, int af, void *addr, int port)
232{
233	struct sockaddr_in *sin4;
234	struct sockaddr_in6 *sin6;
235
236	bzero(sa, sizeof *sa);
237	switch (af) {
238	case AF_INET:
239		sin4 = (struct sockaddr_in *)sa;
240		sin4->sin_len = sizeof *sin4;
241		sin4->sin_family = af;
242		sin4->sin_port = port;
243		sin4->sin_addr = *(struct in_addr *)addr;
244		break;
245	case AF_INET6:
246		sin6 = (struct sockaddr_in6 *)sa;
247		sin6->sin6_len = sizeof *sin6;
248		sin6->sin6_family = af;
249		sin6->sin6_port = port;
250		sin6->sin6_addr = *(struct in6_addr *)addr;
251		break;
252	default:
253		abort();
254	}
255}
256
257static void
258gather_sctp(void)
259{
260	struct sock *sock;
261	struct addr *laddr, *prev_laddr, *faddr, *prev_faddr;
262	struct xsctp_inpcb *xinpcb;
263	struct xsctp_tcb *xstcb;
264	struct xsctp_raddr *xraddr;
265	struct xsctp_laddr *xladdr;
266	const char *varname;
267	size_t len, offset;
268	char *buf;
269	int hash, vflag;
270	int no_stcb, local_all_loopback, foreign_all_loopback;
271
272	vflag = 0;
273	if (opt_4)
274		vflag |= INP_IPV4;
275	if (opt_6)
276		vflag |= INP_IPV6;
277
278	varname = "net.inet.sctp.assoclist";
279	if (sysctlbyname(varname, 0, &len, 0, 0) < 0) {
280		if (errno != ENOENT)
281			err(1, "sysctlbyname()");
282		return;
283	}
284	if ((buf = (char *)malloc(len)) == NULL) {
285		err(1, "malloc()");
286		return;
287	}
288	if (sysctlbyname(varname, buf, &len, 0, 0) < 0) {
289		err(1, "sysctlbyname()");
290		free(buf);
291		return;
292	}
293	xinpcb = (struct xsctp_inpcb *)(void *)buf;
294	offset = sizeof(struct xsctp_inpcb);
295	while ((offset < len) && (xinpcb->last == 0)) {
296		if ((sock = calloc(1, sizeof *sock)) == NULL)
297			err(1, "malloc()");
298		sock->socket = xinpcb->socket;
299		sock->proto = IPPROTO_SCTP;
300		sock->protoname = "sctp";
301		if (xinpcb->flags & SCTP_PCB_FLAGS_BOUND_V6) {
302			sock->family = AF_INET6;
303			sock->vflag = INP_IPV6;
304		} else {
305			sock->family = AF_INET;
306			sock->vflag = INP_IPV4;
307		}
308		prev_laddr = NULL;
309		local_all_loopback = 1;
310		while (offset < len) {
311			xladdr = (struct xsctp_laddr *)(void *)(buf + offset);
312			offset += sizeof(struct xsctp_laddr);
313			if (xladdr->last == 1)
314				break;
315			if ((laddr = calloc(1, sizeof(struct addr))) == NULL)
316				err(1, "malloc()");
317			switch (xladdr->address.sa.sa_family) {
318			case AF_INET:
319#define __IN_IS_ADDR_LOOPBACK(pina) \
320	((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
321				if (!__IN_IS_ADDR_LOOPBACK(&xladdr->address.sin.sin_addr))
322					local_all_loopback = 0;
323#undef __IN_IS_ADDR_LOOPBACK
324				sockaddr(&laddr->address,
325				         AF_INET,
326				         &xladdr->address.sin.sin_addr,
327				         htons(xinpcb->local_port));
328				break;
329			case AF_INET6:
330				if (!IN6_IS_ADDR_LOOPBACK(&xladdr->address.sin6.sin6_addr))
331					local_all_loopback = 0;
332				sockaddr(&laddr->address,
333				         AF_INET6,
334				         &xladdr->address.sin6.sin6_addr,
335				         htons(xinpcb->local_port));
336				break;
337			default:
338				errx(1, "adress family %d not supported",
339				     xladdr->address.sa.sa_family);
340			}
341			laddr->next = NULL;
342			if (prev_laddr == NULL)
343				sock->laddr = laddr;
344			else
345				prev_laddr->next = laddr;
346			prev_laddr = laddr;
347		}
348		if (sock->laddr == NULL) {
349			if ((sock->laddr = calloc(1, sizeof(struct addr))) == NULL)
350				err(1, "malloc()");
351			sock->laddr->address.ss_family = sock->family;
352			if (sock->family == AF_INET)
353				sock->laddr->address.ss_len = sizeof(struct sockaddr_in);
354			else
355				sock->laddr->address.ss_len = sizeof(struct sockaddr_in);
356			local_all_loopback = 0;
357		}
358		if ((sock->faddr = calloc(1, sizeof(struct addr))) == NULL)
359			err(1, "malloc()");
360		sock->faddr->address.ss_family = sock->family;
361		if (sock->family == AF_INET)
362			sock->faddr->address.ss_len = sizeof(struct sockaddr_in);
363		else
364			sock->faddr->address.ss_len = sizeof(struct sockaddr_in);
365		no_stcb = 1;
366		while (offset < len) {
367			xstcb = (struct xsctp_tcb *)(void *)(buf + offset);
368			offset += sizeof(struct xsctp_tcb);
369			if (no_stcb &&
370			    opt_l &&
371			    (!opt_L || !local_all_loopback) &&
372			    ((xinpcb->flags & SCTP_PCB_FLAGS_UDPTYPE) ||
373			     (xstcb->last == 1))) {
374				hash = (int)((uintptr_t)sock->socket % HASHSIZE);
375				sock->next = sockhash[hash];
376				sockhash[hash] = sock;
377			}
378			if (xstcb->last == 1)
379				break;
380			no_stcb = 0;
381			if (opt_c) {
382				if ((sock = calloc(1, sizeof *sock)) == NULL)
383					err(1, "malloc()");
384				sock->socket = xinpcb->socket;
385				sock->proto = IPPROTO_SCTP;
386				sock->protoname = "sctp";
387				if (xinpcb->flags & SCTP_PCB_FLAGS_BOUND_V6) {
388					sock->family = AF_INET6;
389					sock->vflag = INP_IPV6;
390				} else {
391					sock->family = AF_INET;
392					sock->vflag = INP_IPV4;
393				}
394			}
395			prev_laddr = NULL;
396			local_all_loopback = 1;
397			while (offset < len) {
398				xladdr = (struct xsctp_laddr *)(void *)(buf + offset);
399				offset += sizeof(struct xsctp_laddr);
400				if (xladdr->last == 1)
401					break;
402				if (!opt_c)
403					continue;
404				if ((laddr = calloc(1, sizeof(struct addr))) == NULL)
405					err(1, "malloc()");
406				switch (xladdr->address.sa.sa_family) {
407				case AF_INET:
408#define __IN_IS_ADDR_LOOPBACK(pina) \
409	((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
410					if (!__IN_IS_ADDR_LOOPBACK(&xladdr->address.sin.sin_addr))
411						local_all_loopback = 0;
412#undef __IN_IS_ADDR_LOOPBACK
413					sockaddr(&laddr->address,
414						 AF_INET,
415						 &xladdr->address.sin.sin_addr,
416						 htons(xstcb->local_port));
417					break;
418				case AF_INET6:
419					if (!IN6_IS_ADDR_LOOPBACK(&xladdr->address.sin6.sin6_addr))
420						local_all_loopback = 0;
421					sockaddr(&laddr->address,
422						 AF_INET6,
423						 &xladdr->address.sin6.sin6_addr,
424						 htons(xstcb->local_port));
425					break;
426				default:
427					errx(1, "adress family %d not supported",
428					     xladdr->address.sa.sa_family);
429				}
430				laddr->next = NULL;
431				if (prev_laddr == NULL)
432					sock->laddr = laddr;
433				else
434					prev_laddr->next = laddr;
435				prev_laddr = laddr;
436			}
437			prev_faddr = NULL;
438			foreign_all_loopback = 1;
439			while (offset < len) {
440				xraddr = (struct xsctp_raddr *)(void *)(buf + offset);
441				offset += sizeof(struct xsctp_raddr);
442				if (xraddr->last == 1)
443					break;
444				if (!opt_c)
445					continue;
446				if ((faddr = calloc(1, sizeof(struct addr))) == NULL)
447					err(1, "malloc()");
448				switch (xraddr->address.sa.sa_family) {
449				case AF_INET:
450#define __IN_IS_ADDR_LOOPBACK(pina) \
451	((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
452					if (!__IN_IS_ADDR_LOOPBACK(&xraddr->address.sin.sin_addr))
453						foreign_all_loopback = 0;
454#undef __IN_IS_ADDR_LOOPBACK
455					sockaddr(&faddr->address,
456						 AF_INET,
457						 &xraddr->address.sin.sin_addr,
458						 htons(xstcb->remote_port));
459					break;
460				case AF_INET6:
461					if (!IN6_IS_ADDR_LOOPBACK(&xraddr->address.sin6.sin6_addr))
462						foreign_all_loopback = 0;
463					sockaddr(&faddr->address,
464						 AF_INET6,
465						 &xraddr->address.sin6.sin6_addr,
466						 htons(xstcb->remote_port));
467					break;
468				default:
469					errx(1, "adress family %d not supported",
470					     xraddr->address.sa.sa_family);
471				}
472				faddr->next = NULL;
473				if (prev_faddr == NULL)
474					sock->faddr = faddr;
475				else
476					prev_faddr->next = faddr;
477				prev_faddr = faddr;
478			}
479			if (opt_c &&
480			    (!opt_L || !(local_all_loopback || foreign_all_loopback))) {
481				hash = (int)((uintptr_t)sock->socket % HASHSIZE);
482				sock->next = sockhash[hash];
483				sockhash[hash] = sock;
484			}
485		}
486		xinpcb = (struct xsctp_inpcb *)(void *)(buf + offset);
487		offset += sizeof(struct xsctp_inpcb);
488	}
489	free(buf);
490}
491
492static void
493gather_inet(int proto)
494{
495	struct xinpgen *xig, *exig;
496	struct xinpcb *xip;
497	struct xtcpcb *xtp;
498	struct inpcb *inp;
499	struct xsocket *so;
500	struct sock *sock;
501	struct addr *laddr, *faddr;
502	const char *varname, *protoname;
503	size_t len, bufsize;
504	void *buf;
505	int hash, retry, vflag;
506
507	vflag = 0;
508	if (opt_4)
509		vflag |= INP_IPV4;
510	if (opt_6)
511		vflag |= INP_IPV6;
512
513	switch (proto) {
514	case IPPROTO_TCP:
515		varname = "net.inet.tcp.pcblist";
516		protoname = "tcp";
517		break;
518	case IPPROTO_UDP:
519		varname = "net.inet.udp.pcblist";
520		protoname = "udp";
521		break;
522	case IPPROTO_DIVERT:
523		varname = "net.inet.divert.pcblist";
524		protoname = "div";
525		break;
526	default:
527		errx(1, "protocol %d not supported", proto);
528	}
529
530	buf = NULL;
531	bufsize = 8192;
532	retry = 5;
533	do {
534		for (;;) {
535			if ((buf = realloc(buf, bufsize)) == NULL)
536				err(1, "realloc()");
537			len = bufsize;
538			if (sysctlbyname(varname, buf, &len, NULL, 0) == 0)
539				break;
540			if (errno == ENOENT)
541				goto out;
542			if (errno != ENOMEM || len != bufsize)
543				err(1, "sysctlbyname()");
544			bufsize *= 2;
545		}
546		xig = (struct xinpgen *)buf;
547		exig = (struct xinpgen *)(void *)
548		    ((char *)buf + len - sizeof *exig);
549		if (xig->xig_len != sizeof *xig ||
550		    exig->xig_len != sizeof *exig)
551			errx(1, "struct xinpgen size mismatch");
552	} while (xig->xig_gen != exig->xig_gen && retry--);
553
554	if (xig->xig_gen != exig->xig_gen && opt_v)
555		warnx("warning: data may be inconsistent");
556
557	for (;;) {
558		xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len);
559		if (xig >= exig)
560			break;
561		switch (proto) {
562		case IPPROTO_TCP:
563			xtp = (struct xtcpcb *)xig;
564			if (xtp->xt_len != sizeof *xtp) {
565				warnx("struct xtcpcb size mismatch");
566				goto out;
567			}
568			inp = &xtp->xt_inp;
569			so = &xtp->xt_socket;
570			protoname = xtp->xt_tp.t_flags & TF_TOE ? "toe" : "tcp";
571			break;
572		case IPPROTO_UDP:
573		case IPPROTO_DIVERT:
574			xip = (struct xinpcb *)xig;
575			if (xip->xi_len != sizeof *xip) {
576				warnx("struct xinpcb size mismatch");
577				goto out;
578			}
579			inp = &xip->xi_inp;
580			so = &xip->xi_socket;
581			break;
582		default:
583			errx(1, "protocol %d not supported", proto);
584		}
585		if ((inp->inp_vflag & vflag) == 0)
586			continue;
587		if (inp->inp_vflag & INP_IPV4) {
588			if ((inp->inp_fport == 0 && !opt_l) ||
589			    (inp->inp_fport != 0 && !opt_c))
590				continue;
591#define __IN_IS_ADDR_LOOPBACK(pina) \
592	((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
593			if (opt_L &&
594			    (__IN_IS_ADDR_LOOPBACK(&inp->inp_faddr) ||
595			     __IN_IS_ADDR_LOOPBACK(&inp->inp_laddr)))
596				continue;
597#undef __IN_IS_ADDR_LOOPBACK
598		} else if (inp->inp_vflag & INP_IPV6) {
599			if ((inp->inp_fport == 0 && !opt_l) ||
600			    (inp->inp_fport != 0 && !opt_c))
601				continue;
602			if (opt_L &&
603			    (IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr) ||
604			     IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr)))
605				continue;
606		} else {
607			if (opt_v)
608				warnx("invalid vflag 0x%x", inp->inp_vflag);
609			continue;
610		}
611		if ((sock = calloc(1, sizeof *sock)) == NULL)
612			err(1, "malloc()");
613		if ((laddr = calloc(1, sizeof *laddr)) == NULL)
614			err(1, "malloc()");
615		if ((faddr = calloc(1, sizeof *faddr)) == NULL)
616			err(1, "malloc()");
617		sock->socket = so->xso_so;
618		sock->proto = proto;
619		if (inp->inp_vflag & INP_IPV4) {
620			sock->family = AF_INET;
621			sockaddr(&laddr->address, sock->family,
622			    &inp->inp_laddr, inp->inp_lport);
623			sockaddr(&faddr->address, sock->family,
624			    &inp->inp_faddr, inp->inp_fport);
625		} else if (inp->inp_vflag & INP_IPV6) {
626			sock->family = AF_INET6;
627			sockaddr(&laddr->address, sock->family,
628			    &inp->in6p_laddr, inp->inp_lport);
629			sockaddr(&faddr->address, sock->family,
630			    &inp->in6p_faddr, inp->inp_fport);
631		}
632		laddr->next = NULL;
633		faddr->next = NULL;
634		sock->laddr = laddr;
635		sock->faddr = faddr;
636		sock->vflag = inp->inp_vflag;
637		sock->protoname = protoname;
638		hash = (int)((uintptr_t)sock->socket % HASHSIZE);
639		sock->next = sockhash[hash];
640		sockhash[hash] = sock;
641	}
642out:
643	free(buf);
644}
645
646static void
647gather_unix(int proto)
648{
649	struct xunpgen *xug, *exug;
650	struct xunpcb *xup;
651	struct sock *sock;
652	struct addr *laddr, *faddr;
653	const char *varname, *protoname;
654	size_t len, bufsize;
655	void *buf;
656	int hash, retry;
657
658	switch (proto) {
659	case SOCK_STREAM:
660		varname = "net.local.stream.pcblist";
661		protoname = "stream";
662		break;
663	case SOCK_DGRAM:
664		varname = "net.local.dgram.pcblist";
665		protoname = "dgram";
666		break;
667	default:
668		abort();
669	}
670	buf = NULL;
671	bufsize = 8192;
672	retry = 5;
673	do {
674		for (;;) {
675			if ((buf = realloc(buf, bufsize)) == NULL)
676				err(1, "realloc()");
677			len = bufsize;
678			if (sysctlbyname(varname, buf, &len, NULL, 0) == 0)
679				break;
680			if (errno != ENOMEM || len != bufsize)
681				err(1, "sysctlbyname()");
682			bufsize *= 2;
683		}
684		xug = (struct xunpgen *)buf;
685		exug = (struct xunpgen *)(void *)
686		    ((char *)buf + len - sizeof *exug);
687		if (xug->xug_len != sizeof *xug ||
688		    exug->xug_len != sizeof *exug) {
689			warnx("struct xinpgen size mismatch");
690			goto out;
691		}
692	} while (xug->xug_gen != exug->xug_gen && retry--);
693
694	if (xug->xug_gen != exug->xug_gen && opt_v)
695		warnx("warning: data may be inconsistent");
696
697	for (;;) {
698		xug = (struct xunpgen *)(void *)((char *)xug + xug->xug_len);
699		if (xug >= exug)
700			break;
701		xup = (struct xunpcb *)xug;
702		if (xup->xu_len != sizeof *xup) {
703			warnx("struct xunpcb size mismatch");
704			goto out;
705		}
706		if ((xup->xu_unp.unp_conn == NULL && !opt_l) ||
707		    (xup->xu_unp.unp_conn != NULL && !opt_c))
708			continue;
709		if ((sock = calloc(1, sizeof *sock)) == NULL)
710			err(1, "malloc()");
711		if ((laddr = calloc(1, sizeof *laddr)) == NULL)
712			err(1, "malloc()");
713		if ((faddr = calloc(1, sizeof *faddr)) == NULL)
714			err(1, "malloc()");
715		sock->socket = xup->xu_socket.xso_so;
716		sock->pcb = xup->xu_unpp;
717		sock->proto = proto;
718		sock->family = AF_UNIX;
719		sock->protoname = protoname;
720		if (xup->xu_unp.unp_addr != NULL)
721			laddr->address =
722			    *(struct sockaddr_storage *)(void *)&xup->xu_addr;
723		else if (xup->xu_unp.unp_conn != NULL)
724			*(void **)&(faddr->address) = xup->xu_unp.unp_conn;
725		laddr->next = NULL;
726		faddr->next = NULL;
727		sock->laddr = laddr;
728		sock->faddr = faddr;
729		hash = (int)((uintptr_t)sock->socket % HASHSIZE);
730		sock->next = sockhash[hash];
731		sockhash[hash] = sock;
732	}
733out:
734	free(buf);
735}
736
737static void
738getfiles(void)
739{
740	size_t len, olen;
741
742	olen = len = sizeof *xfiles;
743	if ((xfiles = malloc(len)) == NULL)
744		err(1, "malloc()");
745	while (sysctlbyname("kern.file", xfiles, &len, 0, 0) == -1) {
746		if (errno != ENOMEM || len != olen)
747			err(1, "sysctlbyname()");
748		olen = len *= 2;
749		if ((xfiles = realloc(xfiles, len)) == NULL)
750			err(1, "realloc()");
751	}
752	if (len > 0 && xfiles->xf_size != sizeof *xfiles)
753		errx(1, "struct xfile size mismatch");
754	nxfiles = len / sizeof *xfiles;
755}
756
757static int
758printaddr(struct sockaddr_storage *ss)
759{
760	char addrstr[INET6_ADDRSTRLEN] = { '\0', '\0' };
761	struct sockaddr_un *sun;
762	void *addr = NULL; /* Keep compiler happy. */
763	int off, port = 0;
764
765	switch (ss->ss_family) {
766	case AF_INET:
767		addr = &((struct sockaddr_in *)ss)->sin_addr;
768		if (inet_lnaof(*(struct in_addr *)addr) == INADDR_ANY)
769			addrstr[0] = '*';
770		port = ntohs(((struct sockaddr_in *)ss)->sin_port);
771		break;
772	case AF_INET6:
773		addr = &((struct sockaddr_in6 *)ss)->sin6_addr;
774		if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)addr))
775			addrstr[0] = '*';
776		port = ntohs(((struct sockaddr_in6 *)ss)->sin6_port);
777		break;
778	case AF_UNIX:
779		sun = (struct sockaddr_un *)ss;
780		off = (int)((char *)&sun->sun_path - (char *)sun);
781		return (xprintf("%.*s", sun->sun_len - off, sun->sun_path));
782	}
783	if (addrstr[0] == '\0')
784		inet_ntop(ss->ss_family, addr, addrstr, sizeof addrstr);
785	if (port == 0)
786		return xprintf("%s:*", addrstr);
787	else
788		return xprintf("%s:%d", addrstr, port);
789}
790
791static const char *
792getprocname(pid_t pid)
793{
794	static struct kinfo_proc proc;
795	size_t len;
796	int mib[4];
797
798	mib[0] = CTL_KERN;
799	mib[1] = KERN_PROC;
800	mib[2] = KERN_PROC_PID;
801	mib[3] = (int)pid;
802	len = sizeof proc;
803	if (sysctl(mib, 4, &proc, &len, NULL, 0) == -1) {
804		/* Do not warn if the process exits before we get its name. */
805		if (errno != ESRCH)
806			warn("sysctl()");
807		return ("??");
808	}
809	return (proc.ki_comm);
810}
811
812static int
813getprocjid(pid_t pid)
814{
815	static struct kinfo_proc proc;
816	size_t len;
817	int mib[4];
818
819	mib[0] = CTL_KERN;
820	mib[1] = KERN_PROC;
821	mib[2] = KERN_PROC_PID;
822	mib[3] = (int)pid;
823	len = sizeof proc;
824	if (sysctl(mib, 4, &proc, &len, NULL, 0) == -1) {
825		/* Do not warn if the process exits before we get its jid. */
826		if (errno != ESRCH)
827			warn("sysctl()");
828		return (-1);
829	}
830	return (proc.ki_jid);
831}
832
833static int
834check_ports(struct sock *s)
835{
836	int port;
837	struct addr *addr;
838
839	if (ports == NULL)
840		return (1);
841	if ((s->family != AF_INET) && (s->family != AF_INET6))
842		return (1);
843	for (addr = s->laddr; addr != NULL; addr = addr->next) {
844		if (addr->address.ss_family == AF_INET)
845			port = ntohs(((struct sockaddr_in *)(&addr->address))->sin_port);
846		else
847			port = ntohs(((struct sockaddr_in6 *)(&addr->address))->sin6_port);
848		if (CHK_PORT(port))
849			return (1);
850	}
851	for (addr = s->faddr; addr != NULL; addr = addr->next) {
852		if (addr->address.ss_family == AF_INET)
853			port = ntohs(((struct sockaddr_in *)&(addr->address))->sin_port);
854		else
855			port = ntohs(((struct sockaddr_in6 *)&(addr->address))->sin6_port);
856		if (CHK_PORT(port))
857			return (1);
858	}
859	return (0);
860}
861
862static void
863displaysock(struct sock *s, int pos)
864{
865	void *p;
866	int hash;
867	struct addr *laddr, *faddr;
868
869	while (pos < 29)
870		pos += xprintf(" ");
871	pos += xprintf("%s", s->protoname);
872	if (s->vflag & INP_IPV4)
873		pos += xprintf("4 ");
874	if (s->vflag & INP_IPV6)
875		pos += xprintf("6 ");
876	laddr = s->laddr;
877	faddr = s->faddr;
878	while (laddr != NULL || faddr != NULL) {
879		while (pos < 36)
880			pos += xprintf(" ");
881		switch (s->family) {
882		case AF_INET:
883		case AF_INET6:
884			if (laddr != NULL) {
885				pos += printaddr(&laddr->address);
886				if (s->family == AF_INET6 && pos >= 58)
887					pos += xprintf(" ");
888			}
889			while (pos < 58)
890				pos += xprintf(" ");
891			if (faddr != NULL)
892				pos += printaddr(&faddr->address);
893			break;
894		case AF_UNIX:
895			if ((laddr == NULL) || (faddr == NULL))
896				errx(1, "laddr = %p or faddr = %p is NULL",
897				     (void *)laddr, (void *)faddr);
898			/* server */
899			if (laddr->address.ss_len > 0) {
900				pos += printaddr(&laddr->address);
901				break;
902			}
903			/* client */
904			p = *(void **)&(faddr->address);
905			if (p == NULL) {
906				pos += xprintf("(not connected)");
907				break;
908			}
909			pos += xprintf("-> ");
910			for (hash = 0; hash < HASHSIZE; ++hash) {
911				for (s = sockhash[hash]; s != NULL; s = s->next)
912					if (s->pcb == p)
913						break;
914				if (s != NULL)
915					break;
916			}
917			if (s == NULL ||
918			    s->laddr == NULL ||
919			    s->laddr->address.ss_len == 0)
920				pos += xprintf("??");
921			else
922				pos += printaddr(&s->laddr->address);
923			break;
924		default:
925			abort();
926		}
927		if (laddr != NULL)
928			laddr = laddr->next;
929		if (faddr != NULL)
930			faddr = faddr->next;
931		if ((laddr != NULL) || (faddr != NULL)) {
932			xprintf("\n");
933			pos = 0;
934		}
935	}
936	xprintf("\n");
937}
938
939static void
940display(void)
941{
942	struct passwd *pwd;
943	struct xfile *xf;
944	struct sock *s;
945	int hash, n, pos;
946
947	printf("%-8s %-10s %-5s %-2s %-6s %-21s %-21s\n",
948	    "USER", "COMMAND", "PID", "FD", "PROTO",
949	    "LOCAL ADDRESS", "FOREIGN ADDRESS");
950	setpassent(1);
951	for (xf = xfiles, n = 0; n < nxfiles; ++n, ++xf) {
952		if (xf->xf_data == NULL)
953			continue;
954		if (opt_j >= 0 && opt_j != getprocjid(xf->xf_pid))
955			continue;
956		hash = (int)((uintptr_t)xf->xf_data % HASHSIZE);
957		for (s = sockhash[hash]; s != NULL; s = s->next) {
958			if ((void *)s->socket != xf->xf_data)
959				continue;
960			if (!check_ports(s))
961				continue;
962			s->shown = 1;
963			pos = 0;
964			if ((pwd = getpwuid(xf->xf_uid)) == NULL)
965				pos += xprintf("%lu ", (u_long)xf->xf_uid);
966			else
967				pos += xprintf("%s ", pwd->pw_name);
968			while (pos < 9)
969				pos += xprintf(" ");
970			pos += xprintf("%.10s", getprocname(xf->xf_pid));
971			while (pos < 20)
972				pos += xprintf(" ");
973			pos += xprintf("%lu ", (u_long)xf->xf_pid);
974			while (pos < 26)
975				pos += xprintf(" ");
976			pos += xprintf("%d ", xf->xf_fd);
977			displaysock(s, pos);
978		}
979	}
980	if (opt_j >= 0)
981		return;
982	for (hash = 0; hash < HASHSIZE; hash++) {
983		for (s = sockhash[hash]; s != NULL; s = s->next) {
984			if (s->shown)
985				continue;
986			if (!check_ports(s))
987				continue;
988			pos = 0;
989			pos += xprintf("%-8s %-10s %-5s %-2s ",
990			    "?", "?", "?", "?");
991			displaysock(s, pos);
992		}
993	}
994}
995
996static int set_default_protos(void)
997{
998	struct protoent *prot;
999	const char *pname;
1000	size_t pindex;
1001
1002	init_protos(default_numprotos);
1003
1004	for (pindex = 0; pindex < default_numprotos; pindex++) {
1005		pname = default_protos[pindex];
1006		prot = getprotobyname(pname);
1007		if (prot == NULL)
1008			err(1, "getprotobyname: %s", pname);
1009		protos[pindex] = prot->p_proto;
1010	}
1011	numprotos = pindex;
1012	return (pindex);
1013}
1014
1015
1016static void
1017usage(void)
1018{
1019	fprintf(stderr,
1020	    "Usage: sockstat [-46cLlu] [-j jid] [-p ports] [-P protocols]\n");
1021	exit(1);
1022}
1023
1024int
1025main(int argc, char *argv[])
1026{
1027	int protos_defined = -1;
1028	int o, i;
1029
1030	opt_j = -1;
1031	while ((o = getopt(argc, argv, "46cj:Llp:P:uv")) != -1)
1032		switch (o) {
1033		case '4':
1034			opt_4 = 1;
1035			break;
1036		case '6':
1037			opt_6 = 1;
1038			break;
1039		case 'c':
1040			opt_c = 1;
1041			break;
1042		case 'j':
1043			opt_j = atoi(optarg);
1044			break;
1045		case 'L':
1046			opt_L = 1;
1047			break;
1048		case 'l':
1049			opt_l = 1;
1050			break;
1051		case 'p':
1052			parse_ports(optarg);
1053			break;
1054		case 'P':
1055			protos_defined = parse_protos(optarg);
1056			break;
1057		case 'u':
1058			opt_u = 1;
1059			break;
1060		case 'v':
1061			++opt_v;
1062			break;
1063		default:
1064			usage();
1065		}
1066
1067	argc -= optind;
1068	argv += optind;
1069
1070	if (argc > 0)
1071		usage();
1072
1073	if ((!opt_4 && !opt_6) && protos_defined != -1)
1074		opt_4 = opt_6 = 1;
1075	if (!opt_4 && !opt_6 && !opt_u)
1076		opt_4 = opt_6 = opt_u = 1;
1077	if ((opt_4 || opt_6) && protos_defined == -1)
1078		protos_defined = set_default_protos();
1079	if (!opt_c && !opt_l)
1080		opt_c = opt_l = 1;
1081
1082	if (opt_4 || opt_6) {
1083		for (i = 0; i < protos_defined; i++)
1084			if (protos[i] == IPPROTO_SCTP)
1085				gather_sctp();
1086			else
1087				gather_inet(protos[i]);
1088	}
1089
1090	if (opt_u || (protos_defined == -1 && !opt_4 && !opt_6)) {
1091		gather_unix(SOCK_STREAM);
1092		gather_unix(SOCK_DGRAM);
1093	}
1094	getfiles();
1095	display();
1096	exit(0);
1097}
1098