Home | History | Annotate | Line # | Download | only in sockstat
sockstat.c revision 1.20.2.2
      1 /*	$NetBSD: sockstat.c,v 1.20.2.2 2020/09/13 12:00:45 martin Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2005 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Andrew Brown.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #ifndef lint
     34 __RCSID("$NetBSD: sockstat.c,v 1.20.2.2 2020/09/13 12:00:45 martin Exp $");
     35 #endif
     36 
     37 #define _KMEMUSER
     38 #include <sys/types.h>
     39 #undef _KMEMUSER
     40 #include <sys/param.h>
     41 #include <sys/sysctl.h>
     42 #include <sys/socket.h>
     43 #include <sys/socketvar.h>
     44 #include <sys/un.h>
     45 #include <netinet/in.h>
     46 #include <net/route.h>
     47 #include <netinet/in_systm.h>
     48 #include <netinet/ip.h>
     49 #include <netinet/in_pcb.h>
     50 #include <netinet/in_pcb_hdr.h>
     51 #include <netinet/tcp_fsm.h>
     52 
     53 #define _KMEMUSER
     54 /* want DTYPE_* defines */
     55 #include <sys/file.h>
     56 #undef _KMEMUSER
     57 
     58 #include <arpa/inet.h>
     59 
     60 #include <bitstring.h>
     61 #include <ctype.h>
     62 #include <err.h>
     63 #include <errno.h>
     64 #include <netdb.h>
     65 #include <pwd.h>
     66 #include <stdio.h>
     67 #include <strings.h>
     68 #include <stdlib.h>
     69 #include <unistd.h>
     70 #include <util.h>
     71 
     72 #include "prog_ops.h"
     73 
     74 #define satosun(sa)	((struct sockaddr_un *)(sa))
     75 #define satosin(sa)	((struct sockaddr_in *)(sa))
     76 #ifdef INET6
     77 #define satosin6(sa)	((struct sockaddr_in6 *)(sa))
     78 #endif
     79 
     80 void	parse_ports(const char *);
     81 int	get_num(const char *, const char **, const char **);
     82 void	get_sockets(const char *);
     83 void	get_files(void);
     84 int	sort_files(const void *, const void *);
     85 void	sysctl_sucker(int *, u_int, void **, size_t *);
     86 void	socket_add_hash(struct kinfo_pcb *, int);
     87 int	isconnected(struct kinfo_pcb *);
     88 int	islistening(struct kinfo_pcb *);
     89 struct kinfo_pcb *pick_socket(struct kinfo_file *);
     90 int	get_proc(struct kinfo_proc2 *, int);
     91 int	print_socket(struct kinfo_file *, struct kinfo_pcb *,
     92 		     struct kinfo_proc2 *);
     93 void	print_addr(int, int, int, struct sockaddr *);
     94 
     95 LIST_HEAD(socklist, sockitem);
     96 #define HASHSIZE 1009
     97 struct socklist sockhash[HASHSIZE];
     98 struct sockitem {
     99 	LIST_ENTRY(sockitem) s_list;
    100 	struct kinfo_pcb *s_sock;
    101 };
    102 
    103 struct kinfo_file *flist;
    104 size_t flistc;
    105 
    106 int pf_list, only, nonames;
    107 bitstr_t *portmap;
    108 
    109 #define PF_LIST_INET	1
    110 #ifdef INET6
    111 #define PF_LIST_INET6	2
    112 #endif
    113 #define PF_LIST_LOCAL	4
    114 #define ONLY_CONNECTED	1
    115 #define ONLY_LISTEN	2
    116 
    117 int
    118 main(int argc, char *argv[])
    119 {
    120 	struct kinfo_pcb *kp;
    121 	int ch;
    122 	size_t i;
    123 	struct kinfo_proc2 p;
    124 
    125 	pf_list = only = 0;
    126 
    127 #ifdef INET6
    128 	while ((ch = getopt(argc, argv, "46cf:lnp:u")) != - 1) {
    129 #else
    130 	while ((ch = getopt(argc, argv, "4cf:lnp:u")) != - 1) {
    131 #endif
    132 		switch (ch) {
    133 		case '4':
    134 			pf_list |= PF_LIST_INET;
    135 			break;
    136 #ifdef INET6
    137 		case '6':
    138 			pf_list |= PF_LIST_INET6;
    139 			break;
    140 #endif
    141 		case 'c':
    142 			only |= ONLY_CONNECTED;
    143 			break;
    144 		case 'f':
    145 			if (strcasecmp(optarg, "inet") == 0)
    146 				pf_list |= PF_LIST_INET;
    147 #ifdef INET6
    148 			else if (strcasecmp(optarg, "inet6") == 0)
    149 				pf_list |= PF_LIST_INET6;
    150 #endif
    151 			else if (strcasecmp(optarg, "local") == 0)
    152 				pf_list |= PF_LIST_LOCAL;
    153 			else if (strcasecmp(optarg, "unix") == 0)
    154 				pf_list |= PF_LIST_LOCAL;
    155 			else
    156 				errx(1, "%s: unsupported protocol family",
    157 				    optarg);
    158 			break;
    159 		case 'l':
    160 			only |= ONLY_LISTEN;
    161 			break;
    162 		case 'n':
    163 			nonames++;
    164 			break;
    165 		case 'p':
    166 			parse_ports(optarg);
    167 			break;
    168 		case 'u':
    169 			pf_list |= PF_LIST_LOCAL;
    170 			break;
    171 		default:
    172 			/* usage(); */
    173 			exit(1);
    174 		}
    175 	}
    176 	argc -= optind;
    177 	argv += optind;
    178 
    179 	if (prog_init && prog_init() == -1)
    180 		err(1, "init");
    181 
    182 	/* Not used, but we set the PK_KMEM flag like this */
    183 	int fd = open("/dev/mem", O_RDONLY);
    184 	if (fd == -1)
    185 		err(EXIT_FAILURE, "Can't open `/dev/mem'");
    186 	close(fd);
    187 	if ((portmap != NULL) && (pf_list == 0)) {
    188 		pf_list = PF_LIST_INET;
    189 #ifdef INET6
    190 		pf_list |= PF_LIST_INET6;
    191 #endif
    192 	}
    193 	if (pf_list == 0) {
    194 		pf_list = PF_LIST_INET | PF_LIST_LOCAL;
    195 #ifdef INET6
    196 		pf_list |= PF_LIST_INET6;
    197 #endif
    198 	}
    199 	if ((portmap != NULL) && (pf_list & PF_LIST_LOCAL))
    200 		errx(1, "local domain sockets do not have ports");
    201 
    202 	if (pf_list & PF_LIST_INET) {
    203 		get_sockets("net.inet.tcp.pcblist");
    204 		get_sockets("net.inet.udp.pcblist");
    205 		if (portmap == NULL)
    206 			get_sockets("net.inet.raw.pcblist");
    207 	}
    208 
    209 #ifdef INET6
    210 	if (pf_list & PF_LIST_INET6) {
    211 		get_sockets("net.inet6.tcp6.pcblist");
    212 		get_sockets("net.inet6.udp6.pcblist");
    213 		if (portmap == NULL)
    214 			get_sockets("net.inet6.raw6.pcblist");
    215 	}
    216 #endif
    217 
    218 	if (pf_list & PF_LIST_LOCAL) {
    219 		get_sockets("net.local.stream.pcblist");
    220 		get_sockets("net.local.seqpacket.pcblist");
    221 		get_sockets("net.local.dgram.pcblist");
    222 	}
    223 
    224 	get_files();
    225 
    226 	p.p_pid = 0;
    227 	for (i = 0; i < flistc; i++)
    228 		if ((kp = pick_socket(&flist[i])) != NULL &&
    229 		    get_proc(&p, flist[i].ki_pid) == 0)
    230 			print_socket(&flist[i], kp, &p);
    231 
    232 	return (0);
    233 }
    234 
    235 void
    236 parse_ports(const char *l)
    237 {
    238 	struct servent *srv;
    239 	const char *s, *e;
    240 	long i, j;
    241 
    242 	if (portmap == NULL) {
    243 		portmap = bit_alloc(65536);
    244 		if (portmap == NULL)
    245 			err(1, "malloc");
    246 	}
    247 
    248 	if ((srv = getservbyname(l, NULL)) != NULL) {
    249 		bit_set(portmap, ntohs(srv->s_port));
    250 		return;
    251 	}
    252 
    253 	s = e = l;
    254 	while (*s != '\0') {
    255 		i = get_num(l, &s, &e);
    256 		switch (*e) {
    257 		case ',':
    258 			e++;
    259 			/* FALLTHROUGH */
    260 		case '\0':
    261 			bit_set(portmap, i);
    262 			s = e;
    263 			continue;
    264 		case '-':
    265 			s = ++e;
    266 			j = get_num(l, &s, &e);
    267 			for (; i <= j; i++)
    268 				bit_set(portmap, i);
    269 			break;
    270 		default:
    271 			errno = EINVAL;
    272 			err(1, "%s", l);
    273 		}
    274 	}
    275 }
    276 
    277 int
    278 get_num(const char *l, const char **s, const char **e)
    279 {
    280 	long x;
    281 	char *t;
    282 
    283 	while (isdigit((u_int)**e))
    284 		(*e)++;
    285 	if (*s != *e) {
    286 		errno = 0;
    287 		x = strtol(*s, &t, 0);
    288 		if (errno == 0 && x >= 0 && x <= 65535 && t == *e)
    289 			return (x);
    290 	}
    291 
    292 	errno = EINVAL;
    293 	err(1, "%s", l);
    294 }
    295 
    296 void
    297 get_sockets(const char *mib)
    298 {
    299 	void *v;
    300 	size_t sz;
    301 	int rc, n, name[CTL_MAXNAME];
    302 	u_int namelen;
    303 
    304 	sz = CTL_MAXNAME;
    305 	rc = prog_sysctlnametomib(mib, &name[0], &sz);
    306 	if (rc == -1) {
    307 		if (errno == ENOENT)
    308 			return;
    309 		err(1, "sysctlnametomib: %s", mib);
    310 	}
    311 	namelen = sz;
    312 
    313 	name[namelen++] = PCB_ALL;
    314 	name[namelen++] = 0;		/* XXX all pids */
    315 	name[namelen++] = sizeof(struct kinfo_pcb);
    316 	name[namelen++] = INT_MAX;	/* all of them */
    317 
    318 	sysctl_sucker(&name[0], namelen, &v, &sz);
    319 	n = sz / sizeof(struct kinfo_pcb);
    320 	socket_add_hash(v, n);
    321 }
    322 
    323 void
    324 get_files(void)
    325 {
    326 	void *v;
    327 	size_t sz;
    328 	int rc, name[CTL_MAXNAME];
    329 	u_int namelen;
    330 
    331 	sz = CTL_MAXNAME;
    332 	rc = prog_sysctlnametomib("kern.file2", &name[0], &sz);
    333 	if (rc == -1)
    334 		err(1, "sysctlnametomib");
    335 	namelen = sz;
    336 
    337 	name[namelen++] = KERN_FILE_BYPID;
    338 	name[namelen++] = 0;		/* XXX all pids */
    339 	name[namelen++] = sizeof(struct kinfo_file);
    340 	name[namelen++] = INT_MAX;	/* all of them */
    341 
    342 	sysctl_sucker(&name[0], namelen, &v, &sz);
    343 	flist = v;
    344 	flistc = sz / sizeof(struct kinfo_file);
    345 
    346 	qsort(flist, flistc, sizeof(*flist), sort_files);
    347 }
    348 
    349 int
    350 sort_files(const void *a, const void *b)
    351 {
    352 	const struct kinfo_file *ka = a, *kb = b;
    353 
    354 	if (ka->ki_pid == kb->ki_pid)
    355 		return (ka->ki_fd - kb->ki_fd);
    356 
    357 	return (ka->ki_pid - kb->ki_pid);
    358 }
    359 
    360 void
    361 sysctl_sucker(int *name, u_int namelen, void **vp, size_t *szp)
    362 {
    363 	int rc;
    364 	void *v;
    365 	size_t sz;
    366 
    367 	/* printf("name %p, namelen %u\n", name, namelen); */
    368 
    369 	v = NULL;
    370 	sz = 0;
    371 	do {
    372 		rc = prog_sysctl(&name[0], namelen, v, &sz, NULL, 0);
    373 		if (rc == -1 && errno != ENOMEM)
    374 			err(1, "sysctl");
    375 		if (rc == -1 && v != NULL) {
    376 			free(v);
    377 			v = NULL;
    378 		}
    379 		if (v == NULL) {
    380 			v = malloc(sz);
    381 			rc = -1;
    382 		}
    383 		if (v == NULL)
    384 			err(1, "malloc");
    385 	} while (rc == -1);
    386 
    387 	*vp = v;
    388 	*szp = sz;
    389 	/* printf("got %zu at %p\n", sz, v); */
    390 }
    391 
    392 void
    393 socket_add_hash(struct kinfo_pcb *kp, int n)
    394 {
    395 	struct sockitem *si;
    396 	int hash, i;
    397 
    398 	if (n == 0)
    399 		return;
    400 
    401 	si = malloc(sizeof(*si) * n);
    402 	if (si== NULL)
    403 		err(1, "malloc");
    404 
    405 	for (i = 0; i < n; i++) {
    406 		si[i].s_sock = &kp[i];
    407 		hash = (int)(kp[i].ki_sockaddr % HASHSIZE);
    408 		LIST_INSERT_HEAD(&sockhash[hash], &si[i], s_list);
    409 	}
    410 }
    411 
    412 int
    413 isconnected(struct kinfo_pcb *kp)
    414 {
    415 
    416 	if ((kp->ki_sostate & SS_ISCONNECTED) ||
    417 	    (kp->ki_prstate >= INP_CONNECTED) ||
    418 	    (kp->ki_tstate > TCPS_LISTEN) ||
    419 	    (kp->ki_conn != 0))
    420 		return (1);
    421 
    422 	return (0);
    423 }
    424 
    425 int
    426 islistening(struct kinfo_pcb *kp)
    427 {
    428 
    429 	if (isconnected(kp))
    430 		return (0);
    431 
    432 	if (kp->ki_tstate == TCPS_LISTEN)
    433 		return (1);
    434 
    435 	switch (kp->ki_family) {
    436 	case PF_INET:
    437 		if (kp->ki_type == SOCK_RAW ||
    438 		    (kp->ki_type == SOCK_DGRAM &&
    439 		     ntohs(satosin(&kp->ki_src)->sin_port) != 0))
    440 			return (1);
    441 		break;
    442 #ifdef INET6
    443 	case PF_INET6:
    444 		if (kp->ki_type == SOCK_RAW ||
    445 		    (kp->ki_type == SOCK_DGRAM &&
    446 		     ntohs(satosin6(&kp->ki_src)->sin6_port) != 0))
    447 			return (1);
    448 		break;
    449 #endif
    450 	case PF_LOCAL:
    451 		if (satosun(&kp->ki_src)->sun_path[0] != '\0')
    452 			return (1);
    453 		break;
    454 	default:
    455 		break;
    456 	}
    457 
    458 	return (0);
    459 }
    460 
    461 struct kinfo_pcb *
    462 pick_socket(struct kinfo_file *f)
    463 {
    464 	struct sockitem *si;
    465 	struct kinfo_pcb *kp;
    466 	int hash;
    467 
    468 	if (f->ki_ftype != DTYPE_SOCKET)
    469 		return (NULL);
    470 
    471 	hash = (int)(f->ki_fdata % HASHSIZE);
    472 	LIST_FOREACH(si, &sockhash[hash], s_list) {
    473 		if (si->s_sock->ki_sockaddr == f->ki_fdata)
    474 			break;
    475 	}
    476 	if (si == NULL)
    477 		return (NULL);
    478 
    479 	kp = si->s_sock;
    480 
    481 	if (only) {
    482 		if (isconnected(kp)) {
    483 			/*
    484 			 * connected but you didn't say you wanted
    485 			 * connected sockets
    486 			 */
    487 			if (!(only & ONLY_CONNECTED))
    488 				return (NULL);
    489 		}
    490 		else if (islistening(kp)) {
    491 			/*
    492 			 * listening but you didn't ask for listening
    493 			 * sockets
    494 			 */
    495 			if (!(only & ONLY_LISTEN))
    496 				return (NULL);
    497 		}
    498 		else
    499 			/*
    500 			 * neither connected nor listening, so you
    501 			 * don't get it
    502 			 */
    503 			return (NULL);
    504 	}
    505 
    506 	if (portmap) {
    507 		switch (kp->ki_family) {
    508 		case AF_INET:
    509 			if (!bit_test(portmap,
    510 				      ntohs(satosin(&kp->ki_src)->sin_port)) &&
    511 			    !bit_test(portmap,
    512 				      ntohs(satosin(&kp->ki_dst)->sin_port)))
    513 				return (NULL);
    514 			break;
    515 #ifdef INET6
    516 		case AF_INET6:
    517 			if (!bit_test(portmap,
    518 			    ntohs(satosin6(&kp->ki_src)->sin6_port)) &&
    519 			    !bit_test(portmap,
    520 				      ntohs(satosin6(&kp->ki_dst)->sin6_port)))
    521 				return (NULL);
    522 			break;
    523 #endif
    524 		default:
    525 			return (NULL);
    526 		}
    527 	}
    528 
    529 	return (kp);
    530 }
    531 
    532 int
    533 get_proc(struct kinfo_proc2 *p, int pid)
    534 {
    535 	int name[6];
    536 	u_int namelen;
    537 	size_t sz;
    538 
    539 	if (p->p_pid == pid)
    540 		return (0);
    541 
    542 	sz = sizeof(*p);
    543 	namelen = 0;
    544 	name[namelen++] = CTL_KERN;
    545 	name[namelen++] = KERN_PROC2;
    546 	name[namelen++] = KERN_PROC_PID;
    547 	name[namelen++] = pid;
    548 	name[namelen++] = sz;
    549 	name[namelen++] = 1;
    550 
    551 	return (prog_sysctl(&name[0], namelen, p, &sz, NULL, 0));
    552 }
    553 
    554 int
    555 print_socket(struct kinfo_file *kf, struct kinfo_pcb *kp, struct kinfo_proc2 *p)
    556 {
    557 	static int first = 1;
    558 	struct passwd *pw;
    559 	const char *t;
    560 	char proto[22];
    561 
    562 	if (first) {
    563 		printf("%-8s " "%-10s "   "%-5s " "%-2s " "%-6s "
    564 		       "%-21s "         "%s\n",
    565 		       "USER", "COMMAND", "PID",  "FD",   "PROTO",
    566 		       "LOCAL ADDRESS", "FOREIGN ADDRESS");
    567 		first = 0;
    568 	}
    569 
    570 	if ((pw = getpwuid(p->p_uid)) != NULL)
    571 		printf("%-8s ", pw->pw_name);
    572 	else
    573 		printf("%-8d ", (int)p->p_uid);
    574 
    575 	printf("%-10.10s ", p->p_comm);
    576 	printf("%-5d ", (int)kf->ki_pid);
    577 	printf("%2d ", (int)kf->ki_fd);
    578 
    579 	snprintf(proto, sizeof(proto), "%d/%d", kp->ki_family, kp->ki_protocol);
    580 
    581 	switch (kp->ki_family) {
    582 	case PF_INET:
    583 		switch (kp->ki_protocol) {
    584 		case IPPROTO_TCP:	t = "tcp";	break;
    585 		case IPPROTO_UDP:	t = "udp";	break;
    586 		case IPPROTO_RAW:	t = "raw";	break;
    587 		default:		t = proto;	break;
    588 		}
    589 		break;
    590 #ifdef INET6
    591 	case PF_INET6:
    592 		switch (kp->ki_protocol) {
    593 		case IPPROTO_TCP:	t = "tcp6";	break;
    594 		case IPPROTO_UDP:	t = "udp6";	break;
    595 		case IPPROTO_RAW:	t = "raw6";	break;
    596 		default:		t = proto;	break;
    597 		}
    598 		break;
    599 #endif
    600 	case PF_LOCAL:
    601 		switch (kp->ki_type) {
    602 		case SOCK_STREAM:	t = "stream";	break;
    603 		case SOCK_DGRAM:	t = "dgram";	break;
    604 		case SOCK_RAW:		t = "raw";	break;
    605 		case SOCK_RDM:		t = "rdm";	break;
    606 		case SOCK_SEQPACKET:	t = "seq";	break;
    607 		default:		t = proto;	break;
    608 		}
    609 		break;
    610 	default:
    611 		snprintf(proto, sizeof(proto), "%d/%d/%d",
    612 			 kp->ki_family, kp->ki_type, kp->ki_protocol);
    613 		t = proto;
    614 		break;
    615 	}
    616 
    617 	printf("%-6s ", t);
    618 
    619 /*
    620 	if (kp->ki_family == PF_LOCAL) {
    621 		if (kp->ki_src.sa_len > 2) {
    622 			print_addr(0, kp->ki_type, kp->ki_pflags, &kp->ki_src);
    623 			if (kp->ki_dst.sa_family == PF_LOCAL)
    624 				printf(" ");
    625 		}
    626 		if (kp->ki_dst.sa_family == PF_LOCAL)
    627 			printf("-> ");
    628 	}
    629 	else */{
    630 		print_addr(21, kp->ki_type, kp->ki_pflags, &kp->ki_src);
    631 		printf(" ");
    632 	}
    633 
    634 	if (isconnected(kp))
    635 		print_addr(0, kp->ki_type, kp->ki_pflags, &kp->ki_dst);
    636 	else if (kp->ki_family == PF_INET
    637 #ifdef INET6
    638 	    || kp->ki_family == PF_INET6
    639 #endif
    640 	    )
    641 		printf("%-*s", 0, "*.*");
    642 	/* else if (kp->ki_src.sa_len == 2)
    643 	   printf("%-*s", 0, "-"); */
    644 	else
    645 		printf("-");
    646 
    647 	printf("\n");
    648 
    649 	return (0);
    650 }
    651 
    652 void
    653 print_addr(int l, int t, int f, struct sockaddr *sa)
    654 {
    655 	char sabuf[256], pbuf[32];
    656 	int r = 0;
    657 
    658 	if (!(f & INP_ANONPORT))
    659 		f = 0;
    660 	else
    661 		f = NI_NUMERICSERV;
    662 	if (t == SOCK_DGRAM)
    663 		f |= NI_DGRAM;
    664 	if (nonames)
    665 		f |= NI_NUMERICHOST|NI_NUMERICSERV;
    666 
    667 	getnameinfo(sa, sa->sa_len, sabuf, sizeof(sabuf),
    668 		    pbuf, sizeof(pbuf), f);
    669 
    670 	switch (sa->sa_family) {
    671 	case PF_UNSPEC:
    672 		r = printf("(PF_UNSPEC)");
    673 		break;
    674 	case PF_INET: {
    675 		struct sockaddr_in *si = satosin(sa);
    676 		if (si->sin_addr.s_addr != INADDR_ANY)
    677 			r = printf("%s.%s", sabuf, pbuf);
    678 		else if (ntohs(si->sin_port) != 0)
    679 			r = printf("*.%s", pbuf);
    680 		else
    681 			r = printf("*.*");
    682 		break;
    683 	}
    684 #ifdef INET6
    685 	case PF_INET6: {
    686 		struct sockaddr_in6 *si6 = satosin6(sa);
    687 		if (!IN6_IS_ADDR_UNSPECIFIED(&si6->sin6_addr))
    688 			r = printf("%s.%s", sabuf, pbuf);
    689 		else if (ntohs(si6->sin6_port) != 0)
    690 			r = printf("*.%s", pbuf);
    691 		else
    692 			r = printf("*.*");
    693 		break;
    694 	}
    695 #endif
    696 	case PF_LOCAL: {
    697 		struct sockaddr_un *sun = satosun(sa);
    698 		r = printf("%s", sun->sun_path);
    699 		if (r == 0)
    700 			r = printf("-");
    701 		break;
    702 	}
    703 	default:
    704 		break;
    705 	}
    706 
    707 	if (r > 0)
    708 		l -= r;
    709 	if (l > 0)
    710 		printf("%*s", l, "");
    711 }
    712