]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - usr.bin/sockstat/sockstat.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / usr.bin / sockstat / sockstat.c
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$");
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
68 static int       opt_4;         /* Show IPv4 sockets */
69 static int       opt_6;         /* Show IPv6 sockets */
70 static int       opt_c;         /* Show connected sockets */
71 static int       opt_j;         /* Show specified jail */
72 static int       opt_L;         /* Don't show IPv4 or IPv6 loopback sockets */
73 static int       opt_l;         /* Show listening sockets */
74 static int       opt_u;         /* Show Unix domain sockets */
75 static int       opt_v;         /* Verbose mode */
76
77 /*
78  * Default protocols to use if no -P was defined.
79  */
80 static const char *default_protos[] = {"sctp", "tcp", "udp", "divert" };
81 static size_t      default_numprotos = nitems(default_protos);
82
83 static int      *protos;        /* protocols to use */
84 static size_t    numprotos;     /* allocated size of protos[] */
85
86 static 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
92 struct addr {
93         struct sockaddr_storage address;
94         struct addr *next;
95 };
96
97 struct 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
111 static struct sock *sockhash[HASHSIZE];
112
113 static struct xfile *xfiles;
114 static int nxfiles;
115
116 static int
117 xprintf(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
131 static int
132 get_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
147 static void
148 init_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
167 static int
168 parse_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
190 static void
191 parse_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
234 static void
235 sockaddr(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
267 static void
268 free_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
287 static void
288 gather_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, "adress 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, "adress 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, "adress 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
528 static void
529 gather_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         }
678 out:
679         free(buf);
680 }
681
682 static void
683 gather_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         }
773 out:
774         free(buf);
775 }
776
777 static void
778 getfiles(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
797 static int
798 printaddr(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
832 static const char *
833 getprocname(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
853 static int
854 getprocjid(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
874 static int
875 check_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
903 static void
904 displaysock(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
983 static void
984 display(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
1040 static 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
1060 static void
1061 usage(void)
1062 {
1063         fprintf(stderr,
1064             "Usage: sockstat [-46cLlu] [-j jid] [-p ports] [-P protocols]\n");
1065         exit(1);
1066 }
1067
1068 int
1069 main(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 }