xref: /netbsd-src/usr.bin/sockstat/sockstat.c (revision 1fc70a086073edc070c746f34aca67b85b5838fe)
1*1fc70a08Sozaki-r /*	$NetBSD: sockstat.c,v 1.25 2022/10/28 05:24:07 ozaki-r Exp $ */
2724bd019Satatat 
3724bd019Satatat /*
4724bd019Satatat  * Copyright (c) 2005 The NetBSD Foundation, Inc.
5724bd019Satatat  * All rights reserved.
6724bd019Satatat  *
7724bd019Satatat  * This code is derived from software contributed to The NetBSD Foundation
8724bd019Satatat  * by Andrew Brown.
9724bd019Satatat  *
10724bd019Satatat  * Redistribution and use in source and binary forms, with or without
11724bd019Satatat  * modification, are permitted provided that the following conditions
12724bd019Satatat  * are met:
13724bd019Satatat  * 1. Redistributions of source code must retain the above copyright
14724bd019Satatat  *    notice, this list of conditions and the following disclaimer.
15724bd019Satatat  * 2. Redistributions in binary form must reproduce the above copyright
16724bd019Satatat  *    notice, this list of conditions and the following disclaimer in the
17724bd019Satatat  *    documentation and/or other materials provided with the distribution.
18724bd019Satatat  *
19724bd019Satatat  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20724bd019Satatat  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21724bd019Satatat  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22724bd019Satatat  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23724bd019Satatat  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24724bd019Satatat  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25724bd019Satatat  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26724bd019Satatat  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27724bd019Satatat  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28724bd019Satatat  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29724bd019Satatat  * POSSIBILITY OF SUCH DAMAGE.
30724bd019Satatat  */
31724bd019Satatat 
32724bd019Satatat #include <sys/cdefs.h>
33724bd019Satatat #ifndef lint
34*1fc70a08Sozaki-r __RCSID("$NetBSD: sockstat.c,v 1.25 2022/10/28 05:24:07 ozaki-r Exp $");
35724bd019Satatat #endif
36724bd019Satatat 
3731ed49d5Schristos #define _KMEMUSER
38f4b74dafSad #include <sys/types.h>
3931ed49d5Schristos #undef _KMEMUSER
40724bd019Satatat #include <sys/param.h>
41724bd019Satatat #include <sys/sysctl.h>
42724bd019Satatat #include <sys/socket.h>
43724bd019Satatat #include <sys/socketvar.h>
44724bd019Satatat #include <sys/un.h>
45724bd019Satatat #include <netinet/in.h>
46724bd019Satatat #include <net/route.h>
47724bd019Satatat #include <netinet/in_systm.h>
48724bd019Satatat #include <netinet/ip.h>
49724bd019Satatat #include <netinet/in_pcb.h>
50724bd019Satatat #include <netinet/tcp_fsm.h>
51724bd019Satatat 
52ea36f744Schristos #define _KMEMUSER
53724bd019Satatat /* want DTYPE_* defines */
54724bd019Satatat #include <sys/file.h>
55ea36f744Schristos #undef _KMEMUSER
56724bd019Satatat 
57724bd019Satatat #include <arpa/inet.h>
58724bd019Satatat 
59724bd019Satatat #include <bitstring.h>
60724bd019Satatat #include <ctype.h>
61724bd019Satatat #include <err.h>
62724bd019Satatat #include <errno.h>
63724bd019Satatat #include <netdb.h>
64724bd019Satatat #include <pwd.h>
65724bd019Satatat #include <stdio.h>
66724bd019Satatat #include <strings.h>
67724bd019Satatat #include <stdlib.h>
68724bd019Satatat #include <unistd.h>
69724bd019Satatat #include <util.h>
70724bd019Satatat 
716475f125Spooka #include "prog_ops.h"
726475f125Spooka 
73724bd019Satatat #define satosun(sa)	((struct sockaddr_un *)(sa))
74724bd019Satatat #define satosin(sa)	((struct sockaddr_in *)(sa))
75cccbf666Srpaulo #ifdef INET6
76724bd019Satatat #define satosin6(sa)	((struct sockaddr_in6 *)(sa))
77cccbf666Srpaulo #endif
78724bd019Satatat 
79724bd019Satatat void	parse_ports(const char *);
80724bd019Satatat int	get_num(const char *, const char **, const char **);
81724bd019Satatat void	get_sockets(const char *);
82724bd019Satatat void	get_files(void);
83724bd019Satatat int	sort_files(const void *, const void *);
84724bd019Satatat void	sysctl_sucker(int *, u_int, void **, size_t *);
85724bd019Satatat void	socket_add_hash(struct kinfo_pcb *, int);
86724bd019Satatat int	isconnected(struct kinfo_pcb *);
87724bd019Satatat int	islistening(struct kinfo_pcb *);
88724bd019Satatat struct kinfo_pcb *pick_socket(struct kinfo_file *);
89724bd019Satatat int	get_proc(struct kinfo_proc2 *, int);
90724bd019Satatat int	print_socket(struct kinfo_file *, struct kinfo_pcb *,
91724bd019Satatat 		     struct kinfo_proc2 *);
92724bd019Satatat void	print_addr(int, int, int, struct sockaddr *);
93724bd019Satatat 
94724bd019Satatat LIST_HEAD(socklist, sockitem);
95724bd019Satatat #define HASHSIZE 1009
96724bd019Satatat struct socklist sockhash[HASHSIZE];
97724bd019Satatat struct sockitem {
98724bd019Satatat 	LIST_ENTRY(sockitem) s_list;
99724bd019Satatat 	struct kinfo_pcb *s_sock;
100724bd019Satatat };
101724bd019Satatat 
102724bd019Satatat struct kinfo_file *flist;
103183f6d8aSlukem size_t flistc;
104724bd019Satatat 
105724bd019Satatat int pf_list, only, nonames;
106724bd019Satatat bitstr_t *portmap;
107724bd019Satatat 
108724bd019Satatat #define PF_LIST_INET	1
109cccbf666Srpaulo #ifdef INET6
110724bd019Satatat #define PF_LIST_INET6	2
111cccbf666Srpaulo #endif
112724bd019Satatat #define PF_LIST_LOCAL	4
113724bd019Satatat #define ONLY_CONNECTED	1
114724bd019Satatat #define ONLY_LISTEN	2
115724bd019Satatat 
116724bd019Satatat int
main(int argc,char * argv[])117724bd019Satatat main(int argc, char *argv[])
118724bd019Satatat {
119724bd019Satatat 	struct kinfo_pcb *kp;
120183f6d8aSlukem 	int ch;
121183f6d8aSlukem 	size_t i;
122724bd019Satatat 	struct kinfo_proc2 p;
123724bd019Satatat 
124724bd019Satatat 	pf_list = only = 0;
125724bd019Satatat 
126cccbf666Srpaulo #ifdef INET6
127724bd019Satatat 	while ((ch = getopt(argc, argv, "46cf:lnp:u")) != - 1) {
128cccbf666Srpaulo #else
129cccbf666Srpaulo 	while ((ch = getopt(argc, argv, "4cf:lnp:u")) != - 1) {
130cccbf666Srpaulo #endif
131724bd019Satatat 		switch (ch) {
132724bd019Satatat 		case '4':
133724bd019Satatat 			pf_list |= PF_LIST_INET;
134724bd019Satatat 			break;
135cccbf666Srpaulo #ifdef INET6
136724bd019Satatat 		case '6':
137724bd019Satatat 			pf_list |= PF_LIST_INET6;
138724bd019Satatat 			break;
139cccbf666Srpaulo #endif
140724bd019Satatat 		case 'c':
141724bd019Satatat 			only |= ONLY_CONNECTED;
142724bd019Satatat 			break;
143724bd019Satatat 		case 'f':
144724bd019Satatat 			if (strcasecmp(optarg, "inet") == 0)
145724bd019Satatat 				pf_list |= PF_LIST_INET;
146cccbf666Srpaulo #ifdef INET6
147724bd019Satatat 			else if (strcasecmp(optarg, "inet6") == 0)
148724bd019Satatat 				pf_list |= PF_LIST_INET6;
149cccbf666Srpaulo #endif
150724bd019Satatat 			else if (strcasecmp(optarg, "local") == 0)
151724bd019Satatat 				pf_list |= PF_LIST_LOCAL;
152724bd019Satatat 			else if (strcasecmp(optarg, "unix") == 0)
153724bd019Satatat 				pf_list |= PF_LIST_LOCAL;
154724bd019Satatat 			else
155cccbf666Srpaulo 				errx(1, "%s: unsupported protocol family",
156cccbf666Srpaulo 				    optarg);
157724bd019Satatat 			break;
158724bd019Satatat 		case 'l':
159724bd019Satatat 			only |= ONLY_LISTEN;
160724bd019Satatat 			break;
161724bd019Satatat 		case 'n':
162724bd019Satatat 			nonames++;
163724bd019Satatat 			break;
164724bd019Satatat 		case 'p':
165724bd019Satatat 			parse_ports(optarg);
166724bd019Satatat 			break;
167724bd019Satatat 		case 'u':
168724bd019Satatat 			pf_list |= PF_LIST_LOCAL;
169724bd019Satatat 			break;
170724bd019Satatat 		default:
171724bd019Satatat 			/* usage(); */
172724bd019Satatat 			exit(1);
173724bd019Satatat 		}
174724bd019Satatat 	}
175724bd019Satatat 	argc -= optind;
176724bd019Satatat 	argv += optind;
177724bd019Satatat 
1786475f125Spooka 	if (prog_init && prog_init() == -1)
1796475f125Spooka 		err(1, "init");
1806475f125Spooka 
181cccbf666Srpaulo 	if ((portmap != NULL) && (pf_list == 0)) {
182cccbf666Srpaulo 		pf_list = PF_LIST_INET;
183cccbf666Srpaulo #ifdef INET6
184cccbf666Srpaulo 		pf_list |= PF_LIST_INET6;
185cccbf666Srpaulo #endif
186cccbf666Srpaulo 	}
187cccbf666Srpaulo 	if (pf_list == 0) {
188cccbf666Srpaulo 		pf_list = PF_LIST_INET | PF_LIST_LOCAL;
189cccbf666Srpaulo #ifdef INET6
190cccbf666Srpaulo 		pf_list |= PF_LIST_INET6;
191cccbf666Srpaulo #endif
192cccbf666Srpaulo 	}
193724bd019Satatat 	if ((portmap != NULL) && (pf_list & PF_LIST_LOCAL))
194c36f9da9Speter 		errx(1, "local domain sockets do not have ports");
195724bd019Satatat 
196724bd019Satatat 	if (pf_list & PF_LIST_INET) {
197724bd019Satatat 		get_sockets("net.inet.tcp.pcblist");
198724bd019Satatat 		get_sockets("net.inet.udp.pcblist");
199724bd019Satatat 		if (portmap == NULL)
200724bd019Satatat 			get_sockets("net.inet.raw.pcblist");
201724bd019Satatat 	}
202724bd019Satatat 
203cccbf666Srpaulo #ifdef INET6
204724bd019Satatat 	if (pf_list & PF_LIST_INET6) {
205724bd019Satatat 		get_sockets("net.inet6.tcp6.pcblist");
206724bd019Satatat 		get_sockets("net.inet6.udp6.pcblist");
207724bd019Satatat 		if (portmap == NULL)
208724bd019Satatat 			get_sockets("net.inet6.raw6.pcblist");
209724bd019Satatat 	}
210cccbf666Srpaulo #endif
211724bd019Satatat 
212724bd019Satatat 	if (pf_list & PF_LIST_LOCAL) {
213724bd019Satatat 		get_sockets("net.local.stream.pcblist");
2141b0d8e31Smanu 		get_sockets("net.local.seqpacket.pcblist");
215724bd019Satatat 		get_sockets("net.local.dgram.pcblist");
216724bd019Satatat 	}
217724bd019Satatat 
218724bd019Satatat 	get_files();
219724bd019Satatat 
220900e40a9Satatat 	p.p_pid = 0;
221183f6d8aSlukem 	for (i = 0; i < flistc; i++)
222724bd019Satatat 		if ((kp = pick_socket(&flist[i])) != NULL &&
223724bd019Satatat 		    get_proc(&p, flist[i].ki_pid) == 0)
224724bd019Satatat 			print_socket(&flist[i], kp, &p);
225724bd019Satatat 
226724bd019Satatat 	return (0);
227724bd019Satatat }
228724bd019Satatat 
229724bd019Satatat void
230724bd019Satatat parse_ports(const char *l)
231724bd019Satatat {
232724bd019Satatat 	struct servent *srv;
233724bd019Satatat 	const char *s, *e;
234724bd019Satatat 	long i, j;
235724bd019Satatat 
236724bd019Satatat 	if (portmap == NULL) {
237724bd019Satatat 		portmap = bit_alloc(65536);
238724bd019Satatat 		if (portmap == NULL)
239724bd019Satatat 			err(1, "malloc");
240724bd019Satatat 	}
241724bd019Satatat 
242724bd019Satatat 	if ((srv = getservbyname(l, NULL)) != NULL) {
243724bd019Satatat 		bit_set(portmap, ntohs(srv->s_port));
244724bd019Satatat 		return;
245724bd019Satatat 	}
246724bd019Satatat 
247724bd019Satatat 	s = e = l;
248724bd019Satatat 	while (*s != '\0') {
249724bd019Satatat 		i = get_num(l, &s, &e);
250724bd019Satatat 		switch (*e) {
251724bd019Satatat 		case ',':
252724bd019Satatat 			e++;
253fbffadb9Smrg 			/* FALLTHROUGH */
254724bd019Satatat 		case '\0':
255724bd019Satatat 			bit_set(portmap, i);
256724bd019Satatat 			s = e;
257724bd019Satatat 			continue;
258724bd019Satatat 		case '-':
259724bd019Satatat 			s = ++e;
260724bd019Satatat 			j = get_num(l, &s, &e);
261724bd019Satatat 			for (; i <= j; i++)
262724bd019Satatat 				bit_set(portmap, i);
263724bd019Satatat 			break;
264724bd019Satatat 		default:
265724bd019Satatat 			errno = EINVAL;
266724bd019Satatat 			err(1, "%s", l);
267724bd019Satatat 		}
268724bd019Satatat 	}
269724bd019Satatat }
270724bd019Satatat 
271724bd019Satatat int
272724bd019Satatat get_num(const char *l, const char **s, const char **e)
273724bd019Satatat {
274724bd019Satatat 	long x;
275724bd019Satatat 	char *t;
276724bd019Satatat 
2770298690dSrillig 	while (isdigit((unsigned char)**e))
278724bd019Satatat 		(*e)++;
279724bd019Satatat 	if (*s != *e) {
280724bd019Satatat 		errno = 0;
281724bd019Satatat 		x = strtol(*s, &t, 0);
282724bd019Satatat 		if (errno == 0 && x >= 0 && x <= 65535 && t == *e)
283724bd019Satatat 			return (x);
284724bd019Satatat 	}
285724bd019Satatat 
286724bd019Satatat 	errno = EINVAL;
287724bd019Satatat 	err(1, "%s", l);
288724bd019Satatat }
289724bd019Satatat 
290724bd019Satatat void
291724bd019Satatat get_sockets(const char *mib)
292724bd019Satatat {
293724bd019Satatat 	void *v;
294724bd019Satatat 	size_t sz;
295724bd019Satatat 	int rc, n, name[CTL_MAXNAME];
296724bd019Satatat 	u_int namelen;
297724bd019Satatat 
298724bd019Satatat 	sz = CTL_MAXNAME;
299774dcce2Skamil 	rc = prog_sysctlnametomib(mib, &name[0], &sz);
300fcf2b555Srpaulo 	if (rc == -1) {
301fcf2b555Srpaulo 		if (errno == ENOENT)
302fcf2b555Srpaulo 			return;
303724bd019Satatat 		err(1, "sysctlnametomib: %s", mib);
304fcf2b555Srpaulo 	}
305724bd019Satatat 	namelen = sz;
306724bd019Satatat 
307724bd019Satatat 	name[namelen++] = PCB_ALL;
308724bd019Satatat 	name[namelen++] = 0;		/* XXX all pids */
309724bd019Satatat 	name[namelen++] = sizeof(struct kinfo_pcb);
310724bd019Satatat 	name[namelen++] = INT_MAX;	/* all of them */
311724bd019Satatat 
312724bd019Satatat 	sysctl_sucker(&name[0], namelen, &v, &sz);
313724bd019Satatat 	n = sz / sizeof(struct kinfo_pcb);
314724bd019Satatat 	socket_add_hash(v, n);
315724bd019Satatat }
316724bd019Satatat 
317724bd019Satatat void
318724bd019Satatat get_files(void)
319724bd019Satatat {
320724bd019Satatat 	void *v;
321724bd019Satatat 	size_t sz;
322724bd019Satatat 	int rc, name[CTL_MAXNAME];
323724bd019Satatat 	u_int namelen;
324724bd019Satatat 
325724bd019Satatat 	sz = CTL_MAXNAME;
326774dcce2Skamil 	rc = prog_sysctlnametomib("kern.file2", &name[0], &sz);
327724bd019Satatat 	if (rc == -1)
328724bd019Satatat 		err(1, "sysctlnametomib");
329724bd019Satatat 	namelen = sz;
330724bd019Satatat 
331724bd019Satatat 	name[namelen++] = KERN_FILE_BYPID;
332724bd019Satatat 	name[namelen++] = 0;		/* XXX all pids */
333724bd019Satatat 	name[namelen++] = sizeof(struct kinfo_file);
334724bd019Satatat 	name[namelen++] = INT_MAX;	/* all of them */
335724bd019Satatat 
336724bd019Satatat 	sysctl_sucker(&name[0], namelen, &v, &sz);
337724bd019Satatat 	flist = v;
338183f6d8aSlukem 	flistc = sz / sizeof(struct kinfo_file);
339724bd019Satatat 
340183f6d8aSlukem 	qsort(flist, flistc, sizeof(*flist), sort_files);
341724bd019Satatat }
342724bd019Satatat 
343724bd019Satatat int
344724bd019Satatat sort_files(const void *a, const void *b)
345724bd019Satatat {
346724bd019Satatat 	const struct kinfo_file *ka = a, *kb = b;
347724bd019Satatat 
348724bd019Satatat 	if (ka->ki_pid == kb->ki_pid)
349724bd019Satatat 		return (ka->ki_fd - kb->ki_fd);
350724bd019Satatat 
351724bd019Satatat 	return (ka->ki_pid - kb->ki_pid);
352724bd019Satatat }
353724bd019Satatat 
354724bd019Satatat void
355724bd019Satatat sysctl_sucker(int *name, u_int namelen, void **vp, size_t *szp)
356724bd019Satatat {
357724bd019Satatat 	int rc;
358724bd019Satatat 	void *v;
359724bd019Satatat 	size_t sz;
360724bd019Satatat 
361724bd019Satatat 	/* printf("name %p, namelen %u\n", name, namelen); */
362724bd019Satatat 
363724bd019Satatat 	v = NULL;
364724bd019Satatat 	sz = 0;
365724bd019Satatat 	do {
3666475f125Spooka 		rc = prog_sysctl(&name[0], namelen, v, &sz, NULL, 0);
367724bd019Satatat 		if (rc == -1 && errno != ENOMEM)
368724bd019Satatat 			err(1, "sysctl");
369724bd019Satatat 		if (rc == -1 && v != NULL) {
370724bd019Satatat 			free(v);
371724bd019Satatat 			v = NULL;
372724bd019Satatat 		}
373724bd019Satatat 		if (v == NULL) {
374724bd019Satatat 			v = malloc(sz);
375724bd019Satatat 			rc = -1;
376724bd019Satatat 		}
377724bd019Satatat 		if (v == NULL)
378724bd019Satatat 			err(1, "malloc");
379724bd019Satatat 	} while (rc == -1);
380724bd019Satatat 
381724bd019Satatat 	*vp = v;
382724bd019Satatat 	*szp = sz;
383724bd019Satatat 	/* printf("got %zu at %p\n", sz, v); */
384724bd019Satatat }
385724bd019Satatat 
386724bd019Satatat void
387724bd019Satatat socket_add_hash(struct kinfo_pcb *kp, int n)
388724bd019Satatat {
389724bd019Satatat 	struct sockitem *si;
390724bd019Satatat 	int hash, i;
391724bd019Satatat 
392724bd019Satatat 	if (n == 0)
393724bd019Satatat 		return;
394724bd019Satatat 
395724bd019Satatat 	si = malloc(sizeof(*si) * n);
396724bd019Satatat 	if (si== NULL)
397724bd019Satatat 		err(1, "malloc");
398724bd019Satatat 
399724bd019Satatat 	for (i = 0; i < n; i++) {
400724bd019Satatat 		si[i].s_sock = &kp[i];
401724bd019Satatat 		hash = (int)(kp[i].ki_sockaddr % HASHSIZE);
402724bd019Satatat 		LIST_INSERT_HEAD(&sockhash[hash], &si[i], s_list);
403724bd019Satatat 	}
404724bd019Satatat }
405724bd019Satatat 
406724bd019Satatat int
407724bd019Satatat isconnected(struct kinfo_pcb *kp)
408724bd019Satatat {
409724bd019Satatat 
410724bd019Satatat 	if ((kp->ki_sostate & SS_ISCONNECTED) ||
411724bd019Satatat 	    (kp->ki_prstate >= INP_CONNECTED) ||
412724bd019Satatat 	    (kp->ki_tstate > TCPS_LISTEN) ||
413724bd019Satatat 	    (kp->ki_conn != 0))
414724bd019Satatat 		return (1);
415724bd019Satatat 
416724bd019Satatat 	return (0);
417724bd019Satatat }
418724bd019Satatat 
419724bd019Satatat int
420724bd019Satatat islistening(struct kinfo_pcb *kp)
421724bd019Satatat {
422724bd019Satatat 
423724bd019Satatat 	if (isconnected(kp))
424724bd019Satatat 		return (0);
425724bd019Satatat 
426724bd019Satatat 	if (kp->ki_tstate == TCPS_LISTEN)
427724bd019Satatat 		return (1);
428724bd019Satatat 
429724bd019Satatat 	switch (kp->ki_family) {
430724bd019Satatat 	case PF_INET:
431724bd019Satatat 		if (kp->ki_type == SOCK_RAW ||
432724bd019Satatat 		    (kp->ki_type == SOCK_DGRAM &&
43304592855Srpaulo 		     ntohs(satosin(&kp->ki_src)->sin_port) != 0))
434724bd019Satatat 			return (1);
435724bd019Satatat 		break;
436cccbf666Srpaulo #ifdef INET6
437724bd019Satatat 	case PF_INET6:
438724bd019Satatat 		if (kp->ki_type == SOCK_RAW ||
439724bd019Satatat 		    (kp->ki_type == SOCK_DGRAM &&
44004592855Srpaulo 		     ntohs(satosin6(&kp->ki_src)->sin6_port) != 0))
441724bd019Satatat 			return (1);
442724bd019Satatat 		break;
443cccbf666Srpaulo #endif
444724bd019Satatat 	case PF_LOCAL:
445724bd019Satatat 		if (satosun(&kp->ki_src)->sun_path[0] != '\0')
446724bd019Satatat 			return (1);
447724bd019Satatat 		break;
448724bd019Satatat 	default:
449724bd019Satatat 		break;
450724bd019Satatat 	}
451724bd019Satatat 
452724bd019Satatat 	return (0);
453724bd019Satatat }
454724bd019Satatat 
455724bd019Satatat struct kinfo_pcb *
456724bd019Satatat pick_socket(struct kinfo_file *f)
457724bd019Satatat {
458724bd019Satatat 	struct sockitem *si;
459724bd019Satatat 	struct kinfo_pcb *kp;
460724bd019Satatat 	int hash;
461724bd019Satatat 
462724bd019Satatat 	if (f->ki_ftype != DTYPE_SOCKET)
463724bd019Satatat 		return (NULL);
464724bd019Satatat 
465724bd019Satatat 	hash = (int)(f->ki_fdata % HASHSIZE);
466724bd019Satatat 	LIST_FOREACH(si, &sockhash[hash], s_list) {
467724bd019Satatat 		if (si->s_sock->ki_sockaddr == f->ki_fdata)
468724bd019Satatat 			break;
469724bd019Satatat 	}
470724bd019Satatat 	if (si == NULL)
471724bd019Satatat 		return (NULL);
472724bd019Satatat 
473724bd019Satatat 	kp = si->s_sock;
474724bd019Satatat 
475724bd019Satatat 	if (only) {
476724bd019Satatat 		if (isconnected(kp)) {
477724bd019Satatat 			/*
478724bd019Satatat 			 * connected but you didn't say you wanted
479724bd019Satatat 			 * connected sockets
480724bd019Satatat 			 */
481724bd019Satatat 			if (!(only & ONLY_CONNECTED))
482724bd019Satatat 				return (NULL);
483724bd019Satatat 		}
484724bd019Satatat 		else if (islistening(kp)) {
485724bd019Satatat 			/*
486724bd019Satatat 			 * listening but you didn't ask for listening
487724bd019Satatat 			 * sockets
488724bd019Satatat 			 */
489724bd019Satatat 			if (!(only & ONLY_LISTEN))
490724bd019Satatat 				return (NULL);
491724bd019Satatat 		}
492724bd019Satatat 		else
493724bd019Satatat 			/*
494724bd019Satatat 			 * neither connected nor listening, so you
495724bd019Satatat 			 * don't get it
496724bd019Satatat 			 */
497724bd019Satatat 			return (NULL);
498724bd019Satatat 	}
499724bd019Satatat 
500724bd019Satatat 	if (portmap) {
501724bd019Satatat 		switch (kp->ki_family) {
502724bd019Satatat 		case AF_INET:
503724bd019Satatat 			if (!bit_test(portmap,
504724bd019Satatat 				      ntohs(satosin(&kp->ki_src)->sin_port)) &&
505724bd019Satatat 			    !bit_test(portmap,
506724bd019Satatat 				      ntohs(satosin(&kp->ki_dst)->sin_port)))
507724bd019Satatat 				return (NULL);
508724bd019Satatat 			break;
509cccbf666Srpaulo #ifdef INET6
510724bd019Satatat 		case AF_INET6:
511724bd019Satatat 			if (!bit_test(portmap,
512724bd019Satatat 			    ntohs(satosin6(&kp->ki_src)->sin6_port)) &&
513724bd019Satatat 			    !bit_test(portmap,
514724bd019Satatat 				      ntohs(satosin6(&kp->ki_dst)->sin6_port)))
515724bd019Satatat 				return (NULL);
516724bd019Satatat 			break;
517cccbf666Srpaulo #endif
518724bd019Satatat 		default:
519724bd019Satatat 			return (NULL);
520724bd019Satatat 		}
521724bd019Satatat 	}
522724bd019Satatat 
523724bd019Satatat 	return (kp);
524724bd019Satatat }
525724bd019Satatat 
526724bd019Satatat int
527724bd019Satatat get_proc(struct kinfo_proc2 *p, int pid)
528724bd019Satatat {
529724bd019Satatat 	int name[6];
530724bd019Satatat 	u_int namelen;
531724bd019Satatat 	size_t sz;
532724bd019Satatat 
533900e40a9Satatat 	if (p->p_pid == pid)
534900e40a9Satatat 		return (0);
535900e40a9Satatat 
536724bd019Satatat 	sz = sizeof(*p);
537724bd019Satatat 	namelen = 0;
538724bd019Satatat 	name[namelen++] = CTL_KERN;
539724bd019Satatat 	name[namelen++] = KERN_PROC2;
540724bd019Satatat 	name[namelen++] = KERN_PROC_PID;
541724bd019Satatat 	name[namelen++] = pid;
542724bd019Satatat 	name[namelen++] = sz;
543724bd019Satatat 	name[namelen++] = 1;
544724bd019Satatat 
5456475f125Spooka 	return (prog_sysctl(&name[0], namelen, p, &sz, NULL, 0));
546724bd019Satatat }
547724bd019Satatat 
548724bd019Satatat int
549724bd019Satatat print_socket(struct kinfo_file *kf, struct kinfo_pcb *kp, struct kinfo_proc2 *p)
550724bd019Satatat {
551724bd019Satatat 	static int first = 1;
552724bd019Satatat 	struct passwd *pw;
553724bd019Satatat 	const char *t;
554724bd019Satatat 	char proto[22];
555724bd019Satatat 
556724bd019Satatat 	if (first) {
557724bd019Satatat 		printf("%-8s " "%-10s "   "%-5s " "%-2s " "%-6s "
558724bd019Satatat 		       "%-21s "         "%s\n",
559724bd019Satatat 		       "USER", "COMMAND", "PID",  "FD",   "PROTO",
560724bd019Satatat 		       "LOCAL ADDRESS", "FOREIGN ADDRESS");
561724bd019Satatat 		first = 0;
562724bd019Satatat 	}
563724bd019Satatat 
564724bd019Satatat 	if ((pw = getpwuid(p->p_uid)) != NULL)
565724bd019Satatat 		printf("%-8s ", pw->pw_name);
566724bd019Satatat 	else
567724bd019Satatat 		printf("%-8d ", (int)p->p_uid);
568724bd019Satatat 
56904274e48Satatat 	printf("%-10.10s ", p->p_comm);
570724bd019Satatat 	printf("%-5d ", (int)kf->ki_pid);
571724bd019Satatat 	printf("%2d ", (int)kf->ki_fd);
572724bd019Satatat 
573724bd019Satatat 	snprintf(proto, sizeof(proto), "%d/%d", kp->ki_family, kp->ki_protocol);
574724bd019Satatat 
575724bd019Satatat 	switch (kp->ki_family) {
576724bd019Satatat 	case PF_INET:
577724bd019Satatat 		switch (kp->ki_protocol) {
578724bd019Satatat 		case IPPROTO_TCP:	t = "tcp";	break;
579724bd019Satatat 		case IPPROTO_UDP:	t = "udp";	break;
580724bd019Satatat 		case IPPROTO_RAW:	t = "raw";	break;
581724bd019Satatat 		default:		t = proto;	break;
582724bd019Satatat 		}
583724bd019Satatat 		break;
584cccbf666Srpaulo #ifdef INET6
585724bd019Satatat 	case PF_INET6:
586724bd019Satatat 		switch (kp->ki_protocol) {
587724bd019Satatat 		case IPPROTO_TCP:	t = "tcp6";	break;
588724bd019Satatat 		case IPPROTO_UDP:	t = "udp6";	break;
589724bd019Satatat 		case IPPROTO_RAW:	t = "raw6";	break;
590724bd019Satatat 		default:		t = proto;	break;
591724bd019Satatat 		}
592724bd019Satatat 		break;
593cccbf666Srpaulo #endif
594724bd019Satatat 	case PF_LOCAL:
595724bd019Satatat 		switch (kp->ki_type) {
596724bd019Satatat 		case SOCK_STREAM:	t = "stream";	break;
597724bd019Satatat 		case SOCK_DGRAM:	t = "dgram";	break;
598724bd019Satatat 		case SOCK_RAW:		t = "raw";	break;
599724bd019Satatat 		case SOCK_RDM:		t = "rdm";	break;
600724bd019Satatat 		case SOCK_SEQPACKET:	t = "seq";	break;
601724bd019Satatat 		default:		t = proto;	break;
602724bd019Satatat 		}
603724bd019Satatat 		break;
604724bd019Satatat 	default:
605724bd019Satatat 		snprintf(proto, sizeof(proto), "%d/%d/%d",
606724bd019Satatat 			 kp->ki_family, kp->ki_type, kp->ki_protocol);
607724bd019Satatat 		t = proto;
608724bd019Satatat 		break;
609724bd019Satatat 	}
610724bd019Satatat 
611724bd019Satatat 	printf("%-6s ", t);
612724bd019Satatat 
613724bd019Satatat /*
614724bd019Satatat 	if (kp->ki_family == PF_LOCAL) {
615724bd019Satatat 		if (kp->ki_src.sa_len > 2) {
616724bd019Satatat 			print_addr(0, kp->ki_type, kp->ki_pflags, &kp->ki_src);
617724bd019Satatat 			if (kp->ki_dst.sa_family == PF_LOCAL)
618724bd019Satatat 				printf(" ");
619724bd019Satatat 		}
620724bd019Satatat 		if (kp->ki_dst.sa_family == PF_LOCAL)
621724bd019Satatat 			printf("-> ");
622724bd019Satatat 	}
623724bd019Satatat 	else */{
624724bd019Satatat 		print_addr(21, kp->ki_type, kp->ki_pflags, &kp->ki_src);
625724bd019Satatat 		printf(" ");
626724bd019Satatat 	}
627724bd019Satatat 
628724bd019Satatat 	if (isconnected(kp))
629724bd019Satatat 		print_addr(0, kp->ki_type, kp->ki_pflags, &kp->ki_dst);
630cccbf666Srpaulo 	else if (kp->ki_family == PF_INET
631cccbf666Srpaulo #ifdef INET6
632cccbf666Srpaulo 	    || kp->ki_family == PF_INET6
633cccbf666Srpaulo #endif
634cccbf666Srpaulo 	    )
635724bd019Satatat 		printf("%-*s", 0, "*.*");
636724bd019Satatat 	/* else if (kp->ki_src.sa_len == 2)
637724bd019Satatat 	   printf("%-*s", 0, "-"); */
638724bd019Satatat 	else
639724bd019Satatat 		printf("-");
640724bd019Satatat 
641724bd019Satatat 	printf("\n");
642724bd019Satatat 
643724bd019Satatat 	return (0);
644724bd019Satatat }
645724bd019Satatat 
646724bd019Satatat void
647724bd019Satatat print_addr(int l, int t, int f, struct sockaddr *sa)
648724bd019Satatat {
649724bd019Satatat 	char sabuf[256], pbuf[32];
650ef454726Slukem 	int r = 0;
651724bd019Satatat 
652724bd019Satatat 	if (!(f & INP_ANONPORT))
653724bd019Satatat 		f = 0;
654724bd019Satatat 	else
655724bd019Satatat 		f = NI_NUMERICSERV;
656724bd019Satatat 	if (t == SOCK_DGRAM)
657724bd019Satatat 		f |= NI_DGRAM;
658724bd019Satatat 	if (nonames)
659724bd019Satatat 		f |= NI_NUMERICHOST|NI_NUMERICSERV;
660724bd019Satatat 
661724bd019Satatat 	getnameinfo(sa, sa->sa_len, sabuf, sizeof(sabuf),
662724bd019Satatat 		    pbuf, sizeof(pbuf), f);
663724bd019Satatat 
664724bd019Satatat 	switch (sa->sa_family) {
665724bd019Satatat 	case PF_UNSPEC:
666724bd019Satatat 		r = printf("(PF_UNSPEC)");
667724bd019Satatat 		break;
668724bd019Satatat 	case PF_INET: {
669724bd019Satatat 		struct sockaddr_in *si = satosin(sa);
670724bd019Satatat 		if (si->sin_addr.s_addr != INADDR_ANY)
671724bd019Satatat 			r = printf("%s.%s", sabuf, pbuf);
672724bd019Satatat 		else if (ntohs(si->sin_port) != 0)
673724bd019Satatat 			r = printf("*.%s", pbuf);
674724bd019Satatat 		else
675724bd019Satatat 			r = printf("*.*");
676724bd019Satatat 		break;
677724bd019Satatat 	}
678cccbf666Srpaulo #ifdef INET6
679724bd019Satatat 	case PF_INET6: {
680724bd019Satatat 		struct sockaddr_in6 *si6 = satosin6(sa);
681724bd019Satatat 		if (!IN6_IS_ADDR_UNSPECIFIED(&si6->sin6_addr))
682724bd019Satatat 			r = printf("%s.%s", sabuf, pbuf);
683724bd019Satatat 		else if (ntohs(si6->sin6_port) != 0)
684724bd019Satatat 			r = printf("*.%s", pbuf);
685724bd019Satatat 		else
686724bd019Satatat 			r = printf("*.*");
687724bd019Satatat 		break;
688724bd019Satatat 	}
689cccbf666Srpaulo #endif
690724bd019Satatat 	case PF_LOCAL: {
6911a773e1dSatatat 		struct sockaddr_un *sun = satosun(sa);
6921a773e1dSatatat 		r = printf("%s", sun->sun_path);
693724bd019Satatat 		if (r == 0)
694724bd019Satatat 			r = printf("-");
695724bd019Satatat 		break;
696724bd019Satatat 	}
697724bd019Satatat 	default:
698724bd019Satatat 		break;
699724bd019Satatat 	}
700724bd019Satatat 
701724bd019Satatat 	if (r > 0)
702724bd019Satatat 		l -= r;
703724bd019Satatat 	if (l > 0)
704724bd019Satatat 		printf("%*s", l, "");
705724bd019Satatat }
706