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