1ca007d91SDag-Erling Smørgrav /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 31de7b4b8SPedro F. Giffuni * 4e738085bSDag-Erling Smørgrav * Copyright (c) 2002 Dag-Erling Smørgrav 5ca007d91SDag-Erling Smørgrav * All rights reserved. 6ca007d91SDag-Erling Smørgrav * 7ca007d91SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 8ca007d91SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 9ca007d91SDag-Erling Smørgrav * are met: 10ca007d91SDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright 11ca007d91SDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer 12ca007d91SDag-Erling Smørgrav * in this position and unchanged. 13ca007d91SDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright 14ca007d91SDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the 15ca007d91SDag-Erling Smørgrav * documentation and/or other materials provided with the distribution. 16ca007d91SDag-Erling Smørgrav * 3. The name of the author may not be used to endorse or promote products 17ca007d91SDag-Erling Smørgrav * derived from this software without specific prior written permission. 18ca007d91SDag-Erling Smørgrav * 19ca007d91SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20ca007d91SDag-Erling Smørgrav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21ca007d91SDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22ca007d91SDag-Erling Smørgrav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23ca007d91SDag-Erling Smørgrav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24ca007d91SDag-Erling Smørgrav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25ca007d91SDag-Erling Smørgrav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26ca007d91SDag-Erling Smørgrav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27ca007d91SDag-Erling Smørgrav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28ca007d91SDag-Erling Smørgrav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29ca007d91SDag-Erling Smørgrav */ 30ca007d91SDag-Erling Smørgrav 31ca007d91SDag-Erling Smørgrav #include <sys/param.h> 32f1cd4902SRyan Moeller #include <sys/file.h> 33ca007d91SDag-Erling Smørgrav #include <sys/socket.h> 34ca007d91SDag-Erling Smørgrav #include <sys/socketvar.h> 35ca007d91SDag-Erling Smørgrav #include <sys/sysctl.h> 36f1cd4902SRyan Moeller #include <sys/jail.h> 37ca007d91SDag-Erling Smørgrav #include <sys/user.h> 38a83d596fSGleb Smirnoff #include <sys/queue.h> 39a83d596fSGleb Smirnoff #include <sys/tree.h> 40ca007d91SDag-Erling Smørgrav 41ca007d91SDag-Erling Smørgrav #include <sys/un.h> 42ca007d91SDag-Erling Smørgrav #include <sys/unpcb.h> 43ca007d91SDag-Erling Smørgrav 4402bd9db0SDag-Erling Smørgrav #include <net/route.h> 4502bd9db0SDag-Erling Smørgrav 46ca007d91SDag-Erling Smørgrav #include <netinet/in.h> 47ca007d91SDag-Erling Smørgrav #include <netinet/in_pcb.h> 48d5b4aa90SMichael Tuexen #include <netinet/sctp.h> 49ca007d91SDag-Erling Smørgrav #include <netinet/tcp.h> 507a5642b3SDag-Erling Smørgrav #define TCPSTATES /* load state names */ 517a5642b3SDag-Erling Smørgrav #include <netinet/tcp_fsm.h> 52ca007d91SDag-Erling Smørgrav #include <netinet/tcp_seq.h> 53ca007d91SDag-Erling Smørgrav #include <netinet/tcp_var.h> 54ca007d91SDag-Erling Smørgrav #include <arpa/inet.h> 55ca007d91SDag-Erling Smørgrav 56c5a2d8c5SRyan Moeller #include <capsicum_helpers.h> 57ca007d91SDag-Erling Smørgrav #include <ctype.h> 58ca007d91SDag-Erling Smørgrav #include <err.h> 59ca007d91SDag-Erling Smørgrav #include <errno.h> 605f64777aSMichael Tuexen #include <inttypes.h> 61de68a320SJamie Gritton #include <jail.h> 62ca007d91SDag-Erling Smørgrav #include <netdb.h> 63ca007d91SDag-Erling Smørgrav #include <pwd.h> 64ca007d91SDag-Erling Smørgrav #include <stdarg.h> 65ca007d91SDag-Erling Smørgrav #include <stdio.h> 66ca007d91SDag-Erling Smørgrav #include <stdlib.h> 67ca007d91SDag-Erling Smørgrav #include <string.h> 68ca007d91SDag-Erling Smørgrav #include <unistd.h> 69ca007d91SDag-Erling Smørgrav 70c5a2d8c5SRyan Moeller #include <libcasper.h> 71c5a2d8c5SRyan Moeller #include <casper/cap_net.h> 72c5a2d8c5SRyan Moeller #include <casper/cap_netdb.h> 737ad30f58SMariusz Zaborski #include <casper/cap_pwd.h> 74c5a2d8c5SRyan Moeller #include <casper/cap_sysctl.h> 75c5a2d8c5SRyan Moeller 76b8e20e2dSHiroki Sato #define sstosin(ss) ((struct sockaddr_in *)(ss)) 77b8e20e2dSHiroki Sato #define sstosin6(ss) ((struct sockaddr_in6 *)(ss)) 78b8e20e2dSHiroki Sato #define sstosun(ss) ((struct sockaddr_un *)(ss)) 79b8e20e2dSHiroki Sato #define sstosa(ss) ((struct sockaddr *)(ss)) 80b8e20e2dSHiroki Sato 81ca007d91SDag-Erling Smørgrav static int opt_4; /* Show IPv4 sockets */ 82ca007d91SDag-Erling Smørgrav static int opt_6; /* Show IPv6 sockets */ 832ac089d0SMichael Tuexen static int opt_C; /* Show congestion control */ 84ca007d91SDag-Erling Smørgrav static int opt_c; /* Show connected sockets */ 85*051a2132SMark Johnston static int opt_I; /* Show spliced socket addresses */ 865f64777aSMichael Tuexen static int opt_i; /* Show inp_gencnt */ 8700feaafdSAndrew Thompson static int opt_j; /* Show specified jail */ 889b6ca892SBruce M Simpson static int opt_L; /* Don't show IPv4 or IPv6 loopback sockets */ 89ca007d91SDag-Erling Smørgrav static int opt_l; /* Show listening sockets */ 90ccdd2b2bSAlexander Motin static int opt_n; /* Don't resolve UIDs to user names */ 91ee0afaa9SEmmanuel Vadot static int opt_q; /* Don't show header */ 92e5cccc35SMichael Tuexen static int opt_S; /* Show protocol stack if applicable */ 937a5642b3SDag-Erling Smørgrav static int opt_s; /* Show protocol state if applicable */ 9449b836f2SMichael Tuexen static int opt_U; /* Show remote UDP encapsulation port number */ 95ca007d91SDag-Erling Smørgrav static int opt_u; /* Show Unix domain sockets */ 96ca007d91SDag-Erling Smørgrav static int opt_v; /* Verbose mode */ 9783f60cb2SMichael Tuexen static int opt_w; /* Wide print area for addresses */ 98ca007d91SDag-Erling Smørgrav 991f3d67aaSGiorgos Keramidas /* 1001f3d67aaSGiorgos Keramidas * Default protocols to use if no -P was defined. 1011f3d67aaSGiorgos Keramidas */ 102d5b4aa90SMichael Tuexen static const char *default_protos[] = {"sctp", "tcp", "udp", "divert" }; 103b8e20e2dSHiroki Sato static size_t default_numprotos = nitems(default_protos); 1041f3d67aaSGiorgos Keramidas 1051f3d67aaSGiorgos Keramidas static int *protos; /* protocols to use */ 1061f3d67aaSGiorgos Keramidas static size_t numprotos; /* allocated size of protos[] */ 1071f3d67aaSGiorgos Keramidas 108ca007d91SDag-Erling Smørgrav static int *ports; 109ca007d91SDag-Erling Smørgrav 110ca007d91SDag-Erling Smørgrav #define INT_BIT (sizeof(int)*CHAR_BIT) 111ca007d91SDag-Erling Smørgrav #define SET_PORT(p) do { ports[p / INT_BIT] |= 1 << (p % INT_BIT); } while (0) 112ca007d91SDag-Erling Smørgrav #define CHK_PORT(p) (ports[p / INT_BIT] & (1 << (p % INT_BIT))) 113ca007d91SDag-Erling Smørgrav 114e6f718c7SMichael Tuexen struct addr { 1152c436d48SGleb Smirnoff union { 116e6f718c7SMichael Tuexen struct sockaddr_storage address; 1172c436d48SGleb Smirnoff struct { /* unix(4) faddr */ 1182c436d48SGleb Smirnoff kvaddr_t conn; 1192c436d48SGleb Smirnoff kvaddr_t firstref; 1202c436d48SGleb Smirnoff kvaddr_t nextref; 1212c436d48SGleb Smirnoff }; 1222c436d48SGleb Smirnoff }; 12349b836f2SMichael Tuexen unsigned int encaps_port; 124e389705eSMichael Tuexen int state; 125e6f718c7SMichael Tuexen struct addr *next; 126e6f718c7SMichael Tuexen }; 127e6f718c7SMichael Tuexen 128ca007d91SDag-Erling Smørgrav struct sock { 129a83d596fSGleb Smirnoff union { 130a83d596fSGleb Smirnoff RB_ENTRY(sock) socket_tree; /* tree of pcbs with socket */ 131a83d596fSGleb Smirnoff SLIST_ENTRY(sock) socket_list; /* list of pcbs w/o socket */ 132a83d596fSGleb Smirnoff }; 133a83d596fSGleb Smirnoff RB_ENTRY(sock) pcb_tree; 134f38b68aeSBrooks Davis kvaddr_t socket; 135f38b68aeSBrooks Davis kvaddr_t pcb; 136*051a2132SMark Johnston kvaddr_t splice_socket; 1375f64777aSMichael Tuexen uint64_t inp_gencnt; 13861149f8dSJilles Tjoelker int shown; 139ca007d91SDag-Erling Smørgrav int vflag; 140ca007d91SDag-Erling Smørgrav int family; 141ca007d91SDag-Erling Smørgrav int proto; 1427a5642b3SDag-Erling Smørgrav int state; 143ca007d91SDag-Erling Smørgrav const char *protoname; 144e5cccc35SMichael Tuexen char stack[TCP_FUNCTION_NAME_LEN_MAX]; 1452ac089d0SMichael Tuexen char cc[TCP_CA_NAME_MAX]; 146e6f718c7SMichael Tuexen struct addr *laddr; 147e6f718c7SMichael Tuexen struct addr *faddr; 148ca007d91SDag-Erling Smørgrav }; 149ca007d91SDag-Erling Smørgrav 150a83d596fSGleb Smirnoff static RB_HEAD(socks_t, sock) socks = RB_INITIALIZER(&socks); 151a83d596fSGleb Smirnoff static int64_t 152a83d596fSGleb Smirnoff socket_compare(const struct sock *a, const struct sock *b) 153a83d596fSGleb Smirnoff { 154a83d596fSGleb Smirnoff return ((int64_t)(a->socket/2 - b->socket/2)); 155a83d596fSGleb Smirnoff } 156a83d596fSGleb Smirnoff RB_GENERATE_STATIC(socks_t, sock, socket_tree, socket_compare); 157a83d596fSGleb Smirnoff 158a83d596fSGleb Smirnoff static RB_HEAD(pcbs_t, sock) pcbs = RB_INITIALIZER(&pcbs); 159a83d596fSGleb Smirnoff static int64_t 160a83d596fSGleb Smirnoff pcb_compare(const struct sock *a, const struct sock *b) 161a83d596fSGleb Smirnoff { 162a83d596fSGleb Smirnoff return ((int64_t)(a->pcb/2 - b->pcb/2)); 163a83d596fSGleb Smirnoff } 164a83d596fSGleb Smirnoff RB_GENERATE_STATIC(pcbs_t, sock, pcb_tree, pcb_compare); 165a83d596fSGleb Smirnoff 166a83d596fSGleb Smirnoff static SLIST_HEAD(, sock) nosocks = SLIST_HEAD_INITIALIZER(&nosocks); 167ca007d91SDag-Erling Smørgrav 1682c436d48SGleb Smirnoff struct file { 1692c436d48SGleb Smirnoff RB_ENTRY(file) file_tree; 1702c436d48SGleb Smirnoff kvaddr_t xf_data; 1712c436d48SGleb Smirnoff pid_t xf_pid; 1722c436d48SGleb Smirnoff uid_t xf_uid; 1732c436d48SGleb Smirnoff int xf_fd; 1742c436d48SGleb Smirnoff }; 1752c436d48SGleb Smirnoff 1762c436d48SGleb Smirnoff static RB_HEAD(files_t, file) ftree = RB_INITIALIZER(&ftree); 1772c436d48SGleb Smirnoff static int64_t 1782c436d48SGleb Smirnoff file_compare(const struct file *a, const struct file *b) 1792c436d48SGleb Smirnoff { 1802c436d48SGleb Smirnoff return ((int64_t)(a->xf_data/2 - b->xf_data/2)); 1812c436d48SGleb Smirnoff } 1822c436d48SGleb Smirnoff RB_GENERATE_STATIC(files_t, file, file_tree, file_compare); 1832c436d48SGleb Smirnoff 1842c436d48SGleb Smirnoff static struct file *files; 1852c436d48SGleb Smirnoff static int nfiles; 186ca007d91SDag-Erling Smørgrav 187c5a2d8c5SRyan Moeller static cap_channel_t *capnet; 188c5a2d8c5SRyan Moeller static cap_channel_t *capnetdb; 189c5a2d8c5SRyan Moeller static cap_channel_t *capsysctl; 1907ad30f58SMariusz Zaborski static cap_channel_t *cappwd; 191c5a2d8c5SRyan Moeller 192ca007d91SDag-Erling Smørgrav static int 193ca007d91SDag-Erling Smørgrav xprintf(const char *fmt, ...) 194ca007d91SDag-Erling Smørgrav { 195ca007d91SDag-Erling Smørgrav va_list ap; 196ca007d91SDag-Erling Smørgrav int len; 197ca007d91SDag-Erling Smørgrav 198ca007d91SDag-Erling Smørgrav va_start(ap, fmt); 199ca007d91SDag-Erling Smørgrav len = vprintf(fmt, ap); 200ca007d91SDag-Erling Smørgrav va_end(ap); 201ca007d91SDag-Erling Smørgrav if (len < 0) 202ca007d91SDag-Erling Smørgrav err(1, "printf()"); 203ca007d91SDag-Erling Smørgrav return (len); 204ca007d91SDag-Erling Smørgrav } 205ca007d91SDag-Erling Smørgrav 20608e77283SAlexander V. Chernikov static bool 20708e77283SAlexander V. Chernikov _check_ksize(size_t received_size, size_t expected_size, const char *struct_name) 20808e77283SAlexander V. Chernikov { 20908e77283SAlexander V. Chernikov if (received_size != expected_size) { 21008e77283SAlexander V. Chernikov warnx("%s size mismatch: expected %zd, received %zd", 21108e77283SAlexander V. Chernikov struct_name, expected_size, received_size); 21208e77283SAlexander V. Chernikov return false; 21308e77283SAlexander V. Chernikov } 21408e77283SAlexander V. Chernikov return true; 21508e77283SAlexander V. Chernikov } 21608e77283SAlexander V. Chernikov #define check_ksize(_sz, _struct) (_check_ksize(_sz, sizeof(_struct), #_struct)) 21708e77283SAlexander V. Chernikov 21808e77283SAlexander V. Chernikov static void 21908e77283SAlexander V. Chernikov _enforce_ksize(size_t received_size, size_t expected_size, const char *struct_name) 22008e77283SAlexander V. Chernikov { 22108e77283SAlexander V. Chernikov if (received_size != expected_size) { 22208e77283SAlexander V. Chernikov errx(1, "fatal: struct %s size mismatch: expected %zd, received %zd", 22308e77283SAlexander V. Chernikov struct_name, expected_size, received_size); 22408e77283SAlexander V. Chernikov } 22508e77283SAlexander V. Chernikov } 22608e77283SAlexander V. Chernikov #define enforce_ksize(_sz, _struct) (_enforce_ksize(_sz, sizeof(_struct), #_struct)) 22708e77283SAlexander V. Chernikov 2281f3d67aaSGiorgos Keramidas static int 2291f3d67aaSGiorgos Keramidas get_proto_type(const char *proto) 2301f3d67aaSGiorgos Keramidas { 2311f3d67aaSGiorgos Keramidas struct protoent *pent; 2321f3d67aaSGiorgos Keramidas 2331f3d67aaSGiorgos Keramidas if (strlen(proto) == 0) 2341f3d67aaSGiorgos Keramidas return (0); 235bfb5947bSMariusz Zaborski if (capnetdb != NULL) 236c5a2d8c5SRyan Moeller pent = cap_getprotobyname(capnetdb, proto); 237bfb5947bSMariusz Zaborski else 238bfb5947bSMariusz Zaborski pent = getprotobyname(proto); 2391f3d67aaSGiorgos Keramidas if (pent == NULL) { 240c5a2d8c5SRyan Moeller warn("cap_getprotobyname"); 2411f3d67aaSGiorgos Keramidas return (-1); 2421f3d67aaSGiorgos Keramidas } 2431f3d67aaSGiorgos Keramidas return (pent->p_proto); 2441f3d67aaSGiorgos Keramidas } 2451f3d67aaSGiorgos Keramidas 246b8e20e2dSHiroki Sato static void 247b8e20e2dSHiroki Sato init_protos(int num) 2481f3d67aaSGiorgos Keramidas { 2491f3d67aaSGiorgos Keramidas int proto_count = 0; 2501f3d67aaSGiorgos Keramidas 2511f3d67aaSGiorgos Keramidas if (num > 0) { 2521f3d67aaSGiorgos Keramidas proto_count = num; 2531f3d67aaSGiorgos Keramidas } else { 2541f3d67aaSGiorgos Keramidas /* Find the maximum number of possible protocols. */ 2551f3d67aaSGiorgos Keramidas while (getprotoent() != NULL) 2561f3d67aaSGiorgos Keramidas proto_count++; 2571f3d67aaSGiorgos Keramidas endprotoent(); 2581f3d67aaSGiorgos Keramidas } 2591f3d67aaSGiorgos Keramidas 2601f3d67aaSGiorgos Keramidas if ((protos = malloc(sizeof(int) * proto_count)) == NULL) 2611f3d67aaSGiorgos Keramidas err(1, "malloc"); 2621f3d67aaSGiorgos Keramidas numprotos = proto_count; 2631f3d67aaSGiorgos Keramidas } 2641f3d67aaSGiorgos Keramidas 2651f3d67aaSGiorgos Keramidas static int 2661f3d67aaSGiorgos Keramidas parse_protos(char *protospec) 2671f3d67aaSGiorgos Keramidas { 2681f3d67aaSGiorgos Keramidas char *prot; 2691f3d67aaSGiorgos Keramidas int proto_type, proto_index; 2701f3d67aaSGiorgos Keramidas 2711f3d67aaSGiorgos Keramidas if (protospec == NULL) 2721f3d67aaSGiorgos Keramidas return (-1); 2731f3d67aaSGiorgos Keramidas 2741f3d67aaSGiorgos Keramidas init_protos(0); 2751f3d67aaSGiorgos Keramidas proto_index = 0; 276b8e20e2dSHiroki Sato while ((prot = strsep(&protospec, ",")) != NULL) { 2771f3d67aaSGiorgos Keramidas if (strlen(prot) == 0) 2781f3d67aaSGiorgos Keramidas continue; 2791f3d67aaSGiorgos Keramidas proto_type = get_proto_type(prot); 2801f3d67aaSGiorgos Keramidas if (proto_type != -1) 2811f3d67aaSGiorgos Keramidas protos[proto_index++] = proto_type; 2821f3d67aaSGiorgos Keramidas } 2831f3d67aaSGiorgos Keramidas numprotos = proto_index; 2841f3d67aaSGiorgos Keramidas return (proto_index); 2851f3d67aaSGiorgos Keramidas } 2861f3d67aaSGiorgos Keramidas 287ca007d91SDag-Erling Smørgrav static void 288ca007d91SDag-Erling Smørgrav parse_ports(const char *portspec) 289ca007d91SDag-Erling Smørgrav { 290ca007d91SDag-Erling Smørgrav const char *p, *q; 291ca007d91SDag-Erling Smørgrav int port, end; 292ca007d91SDag-Erling Smørgrav 293ca007d91SDag-Erling Smørgrav if (ports == NULL) 2949efed1e6SRobert Drehmel if ((ports = calloc(65536 / INT_BIT, sizeof(int))) == NULL) 295ca007d91SDag-Erling Smørgrav err(1, "calloc()"); 296ca007d91SDag-Erling Smørgrav p = portspec; 297ca007d91SDag-Erling Smørgrav while (*p != '\0') { 298ca007d91SDag-Erling Smørgrav if (!isdigit(*p)) 299ca007d91SDag-Erling Smørgrav errx(1, "syntax error in port range"); 300ca007d91SDag-Erling Smørgrav for (q = p; *q != '\0' && isdigit(*q); ++q) 301ca007d91SDag-Erling Smørgrav /* nothing */ ; 302ca007d91SDag-Erling Smørgrav for (port = 0; p < q; ++p) 303ca007d91SDag-Erling Smørgrav port = port * 10 + digittoint(*p); 304ca007d91SDag-Erling Smørgrav if (port < 0 || port > 65535) 305ca007d91SDag-Erling Smørgrav errx(1, "invalid port number"); 306ca007d91SDag-Erling Smørgrav SET_PORT(port); 307ca007d91SDag-Erling Smørgrav switch (*p) { 308ca007d91SDag-Erling Smørgrav case '-': 309ca007d91SDag-Erling Smørgrav ++p; 310ca007d91SDag-Erling Smørgrav break; 311ca007d91SDag-Erling Smørgrav case ',': 312ca007d91SDag-Erling Smørgrav ++p; 313ca007d91SDag-Erling Smørgrav /* fall through */ 314ca007d91SDag-Erling Smørgrav case '\0': 315ca007d91SDag-Erling Smørgrav default: 316ca007d91SDag-Erling Smørgrav continue; 317ca007d91SDag-Erling Smørgrav } 318ca007d91SDag-Erling Smørgrav for (q = p; *q != '\0' && isdigit(*q); ++q) 319ca007d91SDag-Erling Smørgrav /* nothing */ ; 320ca007d91SDag-Erling Smørgrav for (end = 0; p < q; ++p) 321ca007d91SDag-Erling Smørgrav end = end * 10 + digittoint(*p); 322ca007d91SDag-Erling Smørgrav if (end < port || end > 65535) 323ca007d91SDag-Erling Smørgrav errx(1, "invalid port number"); 324ca007d91SDag-Erling Smørgrav while (port++ < end) 325ca007d91SDag-Erling Smørgrav SET_PORT(port); 326ca007d91SDag-Erling Smørgrav if (*p == ',') 327ca007d91SDag-Erling Smørgrav ++p; 328ca007d91SDag-Erling Smørgrav } 329ca007d91SDag-Erling Smørgrav } 330ca007d91SDag-Erling Smørgrav 331ca007d91SDag-Erling Smørgrav static void 332b8e20e2dSHiroki Sato sockaddr(struct sockaddr_storage *ss, int af, void *addr, int port) 333ca007d91SDag-Erling Smørgrav { 334ca007d91SDag-Erling Smørgrav struct sockaddr_in *sin4; 335ca007d91SDag-Erling Smørgrav struct sockaddr_in6 *sin6; 336ca007d91SDag-Erling Smørgrav 337b8e20e2dSHiroki Sato bzero(ss, sizeof(*ss)); 338ca007d91SDag-Erling Smørgrav switch (af) { 339ca007d91SDag-Erling Smørgrav case AF_INET: 340b8e20e2dSHiroki Sato sin4 = sstosin(ss); 341b8e20e2dSHiroki Sato sin4->sin_len = sizeof(*sin4); 342ca007d91SDag-Erling Smørgrav sin4->sin_family = af; 343ca007d91SDag-Erling Smørgrav sin4->sin_port = port; 344ca007d91SDag-Erling Smørgrav sin4->sin_addr = *(struct in_addr *)addr; 345ca007d91SDag-Erling Smørgrav break; 346ca007d91SDag-Erling Smørgrav case AF_INET6: 347b8e20e2dSHiroki Sato sin6 = sstosin6(ss); 348b8e20e2dSHiroki Sato sin6->sin6_len = sizeof(*sin6); 349ca007d91SDag-Erling Smørgrav sin6->sin6_family = af; 350ca007d91SDag-Erling Smørgrav sin6->sin6_port = port; 351ca007d91SDag-Erling Smørgrav sin6->sin6_addr = *(struct in6_addr *)addr; 352b8e20e2dSHiroki Sato #define s6_addr16 __u6_addr.__u6_addr16 353b8e20e2dSHiroki Sato if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 354b8e20e2dSHiroki Sato sin6->sin6_scope_id = 355b8e20e2dSHiroki Sato ntohs(sin6->sin6_addr.s6_addr16[1]); 356b8e20e2dSHiroki Sato sin6->sin6_addr.s6_addr16[1] = 0; 357b8e20e2dSHiroki Sato } 358ca007d91SDag-Erling Smørgrav break; 359ca007d91SDag-Erling Smørgrav default: 360ca007d91SDag-Erling Smørgrav abort(); 361ca007d91SDag-Erling Smørgrav } 362ca007d91SDag-Erling Smørgrav } 363ca007d91SDag-Erling Smørgrav 364ca007d91SDag-Erling Smørgrav static void 365bedcf91dSMichael Tuexen free_socket(struct sock *sock) 366bedcf91dSMichael Tuexen { 367bedcf91dSMichael Tuexen struct addr *cur, *next; 368bedcf91dSMichael Tuexen 369bedcf91dSMichael Tuexen cur = sock->laddr; 370bedcf91dSMichael Tuexen while (cur != NULL) { 371bedcf91dSMichael Tuexen next = cur->next; 372bedcf91dSMichael Tuexen free(cur); 373bedcf91dSMichael Tuexen cur = next; 374bedcf91dSMichael Tuexen } 375bedcf91dSMichael Tuexen cur = sock->faddr; 376bedcf91dSMichael Tuexen while (cur != NULL) { 377bedcf91dSMichael Tuexen next = cur->next; 378bedcf91dSMichael Tuexen free(cur); 379bedcf91dSMichael Tuexen cur = next; 380bedcf91dSMichael Tuexen } 381bedcf91dSMichael Tuexen free(sock); 382bedcf91dSMichael Tuexen } 383bedcf91dSMichael Tuexen 384bedcf91dSMichael Tuexen static void 385d5b4aa90SMichael Tuexen gather_sctp(void) 386d5b4aa90SMichael Tuexen { 387d5b4aa90SMichael Tuexen struct sock *sock; 388d5b4aa90SMichael Tuexen struct addr *laddr, *prev_laddr, *faddr, *prev_faddr; 389d5b4aa90SMichael Tuexen struct xsctp_inpcb *xinpcb; 390d5b4aa90SMichael Tuexen struct xsctp_tcb *xstcb; 391d5b4aa90SMichael Tuexen struct xsctp_raddr *xraddr; 392d5b4aa90SMichael Tuexen struct xsctp_laddr *xladdr; 393d5b4aa90SMichael Tuexen const char *varname; 394d5b4aa90SMichael Tuexen size_t len, offset; 395d5b4aa90SMichael Tuexen char *buf; 396a83d596fSGleb Smirnoff int vflag; 397d5b4aa90SMichael Tuexen int no_stcb, local_all_loopback, foreign_all_loopback; 398d5b4aa90SMichael Tuexen 399d5b4aa90SMichael Tuexen vflag = 0; 400d5b4aa90SMichael Tuexen if (opt_4) 401d5b4aa90SMichael Tuexen vflag |= INP_IPV4; 402d5b4aa90SMichael Tuexen if (opt_6) 403d5b4aa90SMichael Tuexen vflag |= INP_IPV6; 404d5b4aa90SMichael Tuexen 405d5b4aa90SMichael Tuexen varname = "net.inet.sctp.assoclist"; 406c5a2d8c5SRyan Moeller if (cap_sysctlbyname(capsysctl, varname, 0, &len, 0, 0) < 0) { 407d5b4aa90SMichael Tuexen if (errno != ENOENT) 408c5a2d8c5SRyan Moeller err(1, "cap_sysctlbyname()"); 409d5b4aa90SMichael Tuexen return; 410d5b4aa90SMichael Tuexen } 411d5b4aa90SMichael Tuexen if ((buf = (char *)malloc(len)) == NULL) { 412d5b4aa90SMichael Tuexen err(1, "malloc()"); 413d5b4aa90SMichael Tuexen return; 414d5b4aa90SMichael Tuexen } 415c5a2d8c5SRyan Moeller if (cap_sysctlbyname(capsysctl, varname, buf, &len, 0, 0) < 0) { 416c5a2d8c5SRyan Moeller err(1, "cap_sysctlbyname()"); 417d5b4aa90SMichael Tuexen free(buf); 418d5b4aa90SMichael Tuexen return; 419d5b4aa90SMichael Tuexen } 420d5b4aa90SMichael Tuexen xinpcb = (struct xsctp_inpcb *)(void *)buf; 421d5b4aa90SMichael Tuexen offset = sizeof(struct xsctp_inpcb); 422d5b4aa90SMichael Tuexen while ((offset < len) && (xinpcb->last == 0)) { 423d5b4aa90SMichael Tuexen if ((sock = calloc(1, sizeof *sock)) == NULL) 424d5b4aa90SMichael Tuexen err(1, "malloc()"); 425d5b4aa90SMichael Tuexen sock->socket = xinpcb->socket; 426d5b4aa90SMichael Tuexen sock->proto = IPPROTO_SCTP; 427d5b4aa90SMichael Tuexen sock->protoname = "sctp"; 428c1eb13c7SMichael Tuexen if (xinpcb->maxqlen == 0) 4296414db1bSMichael Tuexen sock->state = SCTP_CLOSED; 4306414db1bSMichael Tuexen else 4316414db1bSMichael Tuexen sock->state = SCTP_LISTEN; 432d5b4aa90SMichael Tuexen if (xinpcb->flags & SCTP_PCB_FLAGS_BOUND_V6) { 433d5b4aa90SMichael Tuexen sock->family = AF_INET6; 434edc9c7fcSMichael Tuexen /* 435edc9c7fcSMichael Tuexen * Currently there is no way to distinguish between 436edc9c7fcSMichael Tuexen * IPv6 only sockets or dual family sockets. 437edc9c7fcSMichael Tuexen * So mark it as dual socket. 438edc9c7fcSMichael Tuexen */ 439edc9c7fcSMichael Tuexen sock->vflag = INP_IPV6 | INP_IPV4; 440d5b4aa90SMichael Tuexen } else { 441d5b4aa90SMichael Tuexen sock->family = AF_INET; 442d5b4aa90SMichael Tuexen sock->vflag = INP_IPV4; 443d5b4aa90SMichael Tuexen } 444d5b4aa90SMichael Tuexen prev_laddr = NULL; 445d5b4aa90SMichael Tuexen local_all_loopback = 1; 446d5b4aa90SMichael Tuexen while (offset < len) { 447d5b4aa90SMichael Tuexen xladdr = (struct xsctp_laddr *)(void *)(buf + offset); 448d5b4aa90SMichael Tuexen offset += sizeof(struct xsctp_laddr); 449d5b4aa90SMichael Tuexen if (xladdr->last == 1) 450d5b4aa90SMichael Tuexen break; 451d5b4aa90SMichael Tuexen if ((laddr = calloc(1, sizeof(struct addr))) == NULL) 452d5b4aa90SMichael Tuexen err(1, "malloc()"); 453d5b4aa90SMichael Tuexen switch (xladdr->address.sa.sa_family) { 454d5b4aa90SMichael Tuexen case AF_INET: 455d5b4aa90SMichael Tuexen #define __IN_IS_ADDR_LOOPBACK(pina) \ 456d5b4aa90SMichael Tuexen ((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) 45727569d01SRenato Botelho if (!__IN_IS_ADDR_LOOPBACK( 45827569d01SRenato Botelho &xladdr->address.sin.sin_addr)) 459d5b4aa90SMichael Tuexen local_all_loopback = 0; 460d5b4aa90SMichael Tuexen #undef __IN_IS_ADDR_LOOPBACK 46127569d01SRenato Botelho sockaddr(&laddr->address, AF_INET, 462d5b4aa90SMichael Tuexen &xladdr->address.sin.sin_addr, 463d5b4aa90SMichael Tuexen htons(xinpcb->local_port)); 464d5b4aa90SMichael Tuexen break; 465d5b4aa90SMichael Tuexen case AF_INET6: 46627569d01SRenato Botelho if (!IN6_IS_ADDR_LOOPBACK( 46727569d01SRenato Botelho &xladdr->address.sin6.sin6_addr)) 468d5b4aa90SMichael Tuexen local_all_loopback = 0; 46927569d01SRenato Botelho sockaddr(&laddr->address, AF_INET6, 470d5b4aa90SMichael Tuexen &xladdr->address.sin6.sin6_addr, 471d5b4aa90SMichael Tuexen htons(xinpcb->local_port)); 472d5b4aa90SMichael Tuexen break; 473d5b4aa90SMichael Tuexen default: 474463a577bSEitan Adler errx(1, "address family %d not supported", 475d5b4aa90SMichael Tuexen xladdr->address.sa.sa_family); 476d5b4aa90SMichael Tuexen } 477d5b4aa90SMichael Tuexen laddr->next = NULL; 478d5b4aa90SMichael Tuexen if (prev_laddr == NULL) 479d5b4aa90SMichael Tuexen sock->laddr = laddr; 480d5b4aa90SMichael Tuexen else 481d5b4aa90SMichael Tuexen prev_laddr->next = laddr; 482d5b4aa90SMichael Tuexen prev_laddr = laddr; 483d5b4aa90SMichael Tuexen } 484d5b4aa90SMichael Tuexen if (sock->laddr == NULL) { 48527569d01SRenato Botelho if ((sock->laddr = 48627569d01SRenato Botelho calloc(1, sizeof(struct addr))) == NULL) 487d5b4aa90SMichael Tuexen err(1, "malloc()"); 488d5b4aa90SMichael Tuexen sock->laddr->address.ss_family = sock->family; 489d5b4aa90SMichael Tuexen if (sock->family == AF_INET) 49027569d01SRenato Botelho sock->laddr->address.ss_len = 49127569d01SRenato Botelho sizeof(struct sockaddr_in); 492d5b4aa90SMichael Tuexen else 49327569d01SRenato Botelho sock->laddr->address.ss_len = 49427569d01SRenato Botelho sizeof(struct sockaddr_in6); 495d5b4aa90SMichael Tuexen local_all_loopback = 0; 496d5b4aa90SMichael Tuexen } 497d5b4aa90SMichael Tuexen if ((sock->faddr = calloc(1, sizeof(struct addr))) == NULL) 498d5b4aa90SMichael Tuexen err(1, "malloc()"); 499d5b4aa90SMichael Tuexen sock->faddr->address.ss_family = sock->family; 500d5b4aa90SMichael Tuexen if (sock->family == AF_INET) 50127569d01SRenato Botelho sock->faddr->address.ss_len = 50227569d01SRenato Botelho sizeof(struct sockaddr_in); 503d5b4aa90SMichael Tuexen else 50427569d01SRenato Botelho sock->faddr->address.ss_len = 50527569d01SRenato Botelho sizeof(struct sockaddr_in6); 506d5b4aa90SMichael Tuexen no_stcb = 1; 507d5b4aa90SMichael Tuexen while (offset < len) { 508d5b4aa90SMichael Tuexen xstcb = (struct xsctp_tcb *)(void *)(buf + offset); 509d5b4aa90SMichael Tuexen offset += sizeof(struct xsctp_tcb); 510bedcf91dSMichael Tuexen if (no_stcb) { 51127569d01SRenato Botelho if (opt_l && (sock->vflag & vflag) && 512d5b4aa90SMichael Tuexen (!opt_L || !local_all_loopback) && 513d5b4aa90SMichael Tuexen ((xinpcb->flags & SCTP_PCB_FLAGS_UDPTYPE) || 514d5b4aa90SMichael Tuexen (xstcb->last == 1))) { 515a83d596fSGleb Smirnoff RB_INSERT(socks_t, &socks, sock); 516bedcf91dSMichael Tuexen } else { 517bedcf91dSMichael Tuexen free_socket(sock); 518bedcf91dSMichael Tuexen } 519d5b4aa90SMichael Tuexen } 520d5b4aa90SMichael Tuexen if (xstcb->last == 1) 521d5b4aa90SMichael Tuexen break; 522d5b4aa90SMichael Tuexen no_stcb = 0; 523d5b4aa90SMichael Tuexen if (opt_c) { 524d5b4aa90SMichael Tuexen if ((sock = calloc(1, sizeof *sock)) == NULL) 525d5b4aa90SMichael Tuexen err(1, "malloc()"); 526d5b4aa90SMichael Tuexen sock->socket = xinpcb->socket; 527d5b4aa90SMichael Tuexen sock->proto = IPPROTO_SCTP; 528d5b4aa90SMichael Tuexen sock->protoname = "sctp"; 5296414db1bSMichael Tuexen sock->state = (int)xstcb->state; 530d5b4aa90SMichael Tuexen if (xinpcb->flags & SCTP_PCB_FLAGS_BOUND_V6) { 531d5b4aa90SMichael Tuexen sock->family = AF_INET6; 532edc9c7fcSMichael Tuexen /* 533edc9c7fcSMichael Tuexen * Currently there is no way to distinguish 534edc9c7fcSMichael Tuexen * between IPv6 only sockets or dual family 535edc9c7fcSMichael Tuexen * sockets. So mark it as dual socket. 536edc9c7fcSMichael Tuexen */ 537edc9c7fcSMichael Tuexen sock->vflag = INP_IPV6 | INP_IPV4; 538d5b4aa90SMichael Tuexen } else { 539d5b4aa90SMichael Tuexen sock->family = AF_INET; 540d5b4aa90SMichael Tuexen sock->vflag = INP_IPV4; 541d5b4aa90SMichael Tuexen } 542d5b4aa90SMichael Tuexen } 543d5b4aa90SMichael Tuexen prev_laddr = NULL; 544d5b4aa90SMichael Tuexen local_all_loopback = 1; 545d5b4aa90SMichael Tuexen while (offset < len) { 54627569d01SRenato Botelho xladdr = (struct xsctp_laddr *)(void *)(buf + 54727569d01SRenato Botelho offset); 548d5b4aa90SMichael Tuexen offset += sizeof(struct xsctp_laddr); 549d5b4aa90SMichael Tuexen if (xladdr->last == 1) 550d5b4aa90SMichael Tuexen break; 551d5b4aa90SMichael Tuexen if (!opt_c) 552d5b4aa90SMichael Tuexen continue; 55327569d01SRenato Botelho laddr = calloc(1, sizeof(struct addr)); 55427569d01SRenato Botelho if (laddr == NULL) 555d5b4aa90SMichael Tuexen err(1, "malloc()"); 556d5b4aa90SMichael Tuexen switch (xladdr->address.sa.sa_family) { 557d5b4aa90SMichael Tuexen case AF_INET: 558d5b4aa90SMichael Tuexen #define __IN_IS_ADDR_LOOPBACK(pina) \ 559d5b4aa90SMichael Tuexen ((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) 56027569d01SRenato Botelho if (!__IN_IS_ADDR_LOOPBACK( 56127569d01SRenato Botelho &xladdr->address.sin.sin_addr)) 562d5b4aa90SMichael Tuexen local_all_loopback = 0; 563d5b4aa90SMichael Tuexen #undef __IN_IS_ADDR_LOOPBACK 56427569d01SRenato Botelho sockaddr(&laddr->address, AF_INET, 565d5b4aa90SMichael Tuexen &xladdr->address.sin.sin_addr, 566d5b4aa90SMichael Tuexen htons(xstcb->local_port)); 567d5b4aa90SMichael Tuexen break; 568d5b4aa90SMichael Tuexen case AF_INET6: 56927569d01SRenato Botelho if (!IN6_IS_ADDR_LOOPBACK( 57027569d01SRenato Botelho &xladdr->address.sin6.sin6_addr)) 571d5b4aa90SMichael Tuexen local_all_loopback = 0; 57227569d01SRenato Botelho sockaddr(&laddr->address, AF_INET6, 573d5b4aa90SMichael Tuexen &xladdr->address.sin6.sin6_addr, 574d5b4aa90SMichael Tuexen htons(xstcb->local_port)); 575d5b4aa90SMichael Tuexen break; 576d5b4aa90SMichael Tuexen default: 57727569d01SRenato Botelho errx(1, 57827569d01SRenato Botelho "address family %d not supported", 579d5b4aa90SMichael Tuexen xladdr->address.sa.sa_family); 580d5b4aa90SMichael Tuexen } 581d5b4aa90SMichael Tuexen laddr->next = NULL; 582d5b4aa90SMichael Tuexen if (prev_laddr == NULL) 583d5b4aa90SMichael Tuexen sock->laddr = laddr; 584d5b4aa90SMichael Tuexen else 585d5b4aa90SMichael Tuexen prev_laddr->next = laddr; 586d5b4aa90SMichael Tuexen prev_laddr = laddr; 587d5b4aa90SMichael Tuexen } 588d5b4aa90SMichael Tuexen prev_faddr = NULL; 589d5b4aa90SMichael Tuexen foreign_all_loopback = 1; 590d5b4aa90SMichael Tuexen while (offset < len) { 59127569d01SRenato Botelho xraddr = (struct xsctp_raddr *)(void *)(buf + 59227569d01SRenato Botelho offset); 593d5b4aa90SMichael Tuexen offset += sizeof(struct xsctp_raddr); 594d5b4aa90SMichael Tuexen if (xraddr->last == 1) 595d5b4aa90SMichael Tuexen break; 596d5b4aa90SMichael Tuexen if (!opt_c) 597d5b4aa90SMichael Tuexen continue; 59827569d01SRenato Botelho faddr = calloc(1, sizeof(struct addr)); 59927569d01SRenato Botelho if (faddr == NULL) 600d5b4aa90SMichael Tuexen err(1, "malloc()"); 601d5b4aa90SMichael Tuexen switch (xraddr->address.sa.sa_family) { 602d5b4aa90SMichael Tuexen case AF_INET: 603d5b4aa90SMichael Tuexen #define __IN_IS_ADDR_LOOPBACK(pina) \ 604d5b4aa90SMichael Tuexen ((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) 60527569d01SRenato Botelho if (!__IN_IS_ADDR_LOOPBACK( 60627569d01SRenato Botelho &xraddr->address.sin.sin_addr)) 607d5b4aa90SMichael Tuexen foreign_all_loopback = 0; 608d5b4aa90SMichael Tuexen #undef __IN_IS_ADDR_LOOPBACK 60927569d01SRenato Botelho sockaddr(&faddr->address, AF_INET, 610d5b4aa90SMichael Tuexen &xraddr->address.sin.sin_addr, 611d5b4aa90SMichael Tuexen htons(xstcb->remote_port)); 612d5b4aa90SMichael Tuexen break; 613d5b4aa90SMichael Tuexen case AF_INET6: 61427569d01SRenato Botelho if (!IN6_IS_ADDR_LOOPBACK( 61527569d01SRenato Botelho &xraddr->address.sin6.sin6_addr)) 616d5b4aa90SMichael Tuexen foreign_all_loopback = 0; 61727569d01SRenato Botelho sockaddr(&faddr->address, AF_INET6, 618d5b4aa90SMichael Tuexen &xraddr->address.sin6.sin6_addr, 619d5b4aa90SMichael Tuexen htons(xstcb->remote_port)); 620d5b4aa90SMichael Tuexen break; 621d5b4aa90SMichael Tuexen default: 62227569d01SRenato Botelho errx(1, 62327569d01SRenato Botelho "address family %d not supported", 624d5b4aa90SMichael Tuexen xraddr->address.sa.sa_family); 625d5b4aa90SMichael Tuexen } 62649b836f2SMichael Tuexen faddr->encaps_port = xraddr->encaps_port; 627e389705eSMichael Tuexen faddr->state = xraddr->state; 628d5b4aa90SMichael Tuexen faddr->next = NULL; 629d5b4aa90SMichael Tuexen if (prev_faddr == NULL) 630d5b4aa90SMichael Tuexen sock->faddr = faddr; 631d5b4aa90SMichael Tuexen else 632d5b4aa90SMichael Tuexen prev_faddr->next = faddr; 633d5b4aa90SMichael Tuexen prev_faddr = faddr; 634d5b4aa90SMichael Tuexen } 635bedcf91dSMichael Tuexen if (opt_c) { 636edc9c7fcSMichael Tuexen if ((sock->vflag & vflag) && 637edc9c7fcSMichael Tuexen (!opt_L || 63827569d01SRenato Botelho !(local_all_loopback || 63927569d01SRenato Botelho foreign_all_loopback))) { 640a83d596fSGleb Smirnoff RB_INSERT(socks_t, &socks, sock); 641bedcf91dSMichael Tuexen } else { 642bedcf91dSMichael Tuexen free_socket(sock); 643bedcf91dSMichael Tuexen } 644d5b4aa90SMichael Tuexen } 645d5b4aa90SMichael Tuexen } 646d5b4aa90SMichael Tuexen xinpcb = (struct xsctp_inpcb *)(void *)(buf + offset); 647d5b4aa90SMichael Tuexen offset += sizeof(struct xsctp_inpcb); 648d5b4aa90SMichael Tuexen } 649d5b4aa90SMichael Tuexen free(buf); 650d5b4aa90SMichael Tuexen } 651d5b4aa90SMichael Tuexen 652d5b4aa90SMichael Tuexen static void 653ca007d91SDag-Erling Smørgrav gather_inet(int proto) 654ca007d91SDag-Erling Smørgrav { 655ca007d91SDag-Erling Smørgrav struct xinpgen *xig, *exig; 656ca007d91SDag-Erling Smørgrav struct xinpcb *xip; 657bf40d2caSGleb Smirnoff struct xtcpcb *xtp = NULL; 658ca007d91SDag-Erling Smørgrav struct xsocket *so; 659ca007d91SDag-Erling Smørgrav struct sock *sock; 660e6f718c7SMichael Tuexen struct addr *laddr, *faddr; 661ca007d91SDag-Erling Smørgrav const char *varname, *protoname; 662ca007d91SDag-Erling Smørgrav size_t len, bufsize; 663ca007d91SDag-Erling Smørgrav void *buf; 664a83d596fSGleb Smirnoff int retry, vflag; 665ca007d91SDag-Erling Smørgrav 6666eb1d5baSMichael Tuexen vflag = 0; 667ca007d91SDag-Erling Smørgrav if (opt_4) 668ca007d91SDag-Erling Smørgrav vflag |= INP_IPV4; 669ca007d91SDag-Erling Smørgrav if (opt_6) 670ca007d91SDag-Erling Smørgrav vflag |= INP_IPV6; 671ca007d91SDag-Erling Smørgrav 672ca007d91SDag-Erling Smørgrav switch (proto) { 673ca007d91SDag-Erling Smørgrav case IPPROTO_TCP: 674ca007d91SDag-Erling Smørgrav varname = "net.inet.tcp.pcblist"; 675ca007d91SDag-Erling Smørgrav protoname = "tcp"; 676ca007d91SDag-Erling Smørgrav break; 677ca007d91SDag-Erling Smørgrav case IPPROTO_UDP: 678ca007d91SDag-Erling Smørgrav varname = "net.inet.udp.pcblist"; 679ca007d91SDag-Erling Smørgrav protoname = "udp"; 680ca007d91SDag-Erling Smørgrav break; 6812cfbdf89SRuslan Ermilov case IPPROTO_DIVERT: 6822cfbdf89SRuslan Ermilov varname = "net.inet.divert.pcblist"; 6832cfbdf89SRuslan Ermilov protoname = "div"; 6842cfbdf89SRuslan Ermilov break; 685ca007d91SDag-Erling Smørgrav default: 6861f3d67aaSGiorgos Keramidas errx(1, "protocol %d not supported", proto); 687ca007d91SDag-Erling Smørgrav } 688ca007d91SDag-Erling Smørgrav 689ca007d91SDag-Erling Smørgrav buf = NULL; 690ca007d91SDag-Erling Smørgrav bufsize = 8192; 691ca007d91SDag-Erling Smørgrav retry = 5; 692ca007d91SDag-Erling Smørgrav do { 693ca007d91SDag-Erling Smørgrav for (;;) { 694ca007d91SDag-Erling Smørgrav if ((buf = realloc(buf, bufsize)) == NULL) 695ca007d91SDag-Erling Smørgrav err(1, "realloc()"); 696ca007d91SDag-Erling Smørgrav len = bufsize; 697c5a2d8c5SRyan Moeller if (cap_sysctlbyname(capsysctl, varname, buf, &len, 698c5a2d8c5SRyan Moeller NULL, 0) == 0) 699ca007d91SDag-Erling Smørgrav break; 7004b2a3d41SRuslan Ermilov if (errno == ENOENT) 7014b2a3d41SRuslan Ermilov goto out; 702003e7e49SMikolaj Golub if (errno != ENOMEM || len != bufsize) 703c5a2d8c5SRyan Moeller err(1, "cap_sysctlbyname()"); 704ca007d91SDag-Erling Smørgrav bufsize *= 2; 705ca007d91SDag-Erling Smørgrav } 706ca007d91SDag-Erling Smørgrav xig = (struct xinpgen *)buf; 7076dbe8d53SRobert Drehmel exig = (struct xinpgen *)(void *) 7086dbe8d53SRobert Drehmel ((char *)buf + len - sizeof *exig); 70908e77283SAlexander V. Chernikov enforce_ksize(xig->xig_len, struct xinpgen); 71008e77283SAlexander V. Chernikov enforce_ksize(exig->xig_len, struct xinpgen); 711ca007d91SDag-Erling Smørgrav } while (xig->xig_gen != exig->xig_gen && retry--); 712ca007d91SDag-Erling Smørgrav 713ca007d91SDag-Erling Smørgrav if (xig->xig_gen != exig->xig_gen && opt_v) 714ca007d91SDag-Erling Smørgrav warnx("warning: data may be inconsistent"); 715ca007d91SDag-Erling Smørgrav 716ca007d91SDag-Erling Smørgrav for (;;) { 7176dbe8d53SRobert Drehmel xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len); 718ca007d91SDag-Erling Smørgrav if (xig >= exig) 719ca007d91SDag-Erling Smørgrav break; 720ca007d91SDag-Erling Smørgrav switch (proto) { 721ca007d91SDag-Erling Smørgrav case IPPROTO_TCP: 722cc65eb4eSGleb Smirnoff xtp = (struct xtcpcb *)xig; 723cc65eb4eSGleb Smirnoff xip = &xtp->xt_inp; 72408e77283SAlexander V. Chernikov if (!check_ksize(xtp->xt_len, struct xtcpcb)) 725ca007d91SDag-Erling Smørgrav goto out; 726cc65eb4eSGleb Smirnoff protoname = xtp->t_flags & TF_TOE ? "toe" : "tcp"; 727ca007d91SDag-Erling Smørgrav break; 728ca007d91SDag-Erling Smørgrav case IPPROTO_UDP: 7292cfbdf89SRuslan Ermilov case IPPROTO_DIVERT: 730cc65eb4eSGleb Smirnoff xip = (struct xinpcb *)xig; 73108e77283SAlexander V. Chernikov if (!check_ksize(xip->xi_len, struct xinpcb)) 732ca007d91SDag-Erling Smørgrav goto out; 733ca007d91SDag-Erling Smørgrav break; 734ca007d91SDag-Erling Smørgrav default: 7351f3d67aaSGiorgos Keramidas errx(1, "protocol %d not supported", proto); 736ca007d91SDag-Erling Smørgrav } 737cc65eb4eSGleb Smirnoff so = &xip->xi_socket; 738cc65eb4eSGleb Smirnoff if ((xip->inp_vflag & vflag) == 0) 739ca007d91SDag-Erling Smørgrav continue; 740cc65eb4eSGleb Smirnoff if (xip->inp_vflag & INP_IPV4) { 741cc65eb4eSGleb Smirnoff if ((xip->inp_fport == 0 && !opt_l) || 742cc65eb4eSGleb Smirnoff (xip->inp_fport != 0 && !opt_c)) 7431e6690e5SDag-Erling Smørgrav continue; 7449b6ca892SBruce M Simpson #define __IN_IS_ADDR_LOOPBACK(pina) \ 7459b6ca892SBruce M Simpson ((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) 7469b6ca892SBruce M Simpson if (opt_L && 747cc65eb4eSGleb Smirnoff (__IN_IS_ADDR_LOOPBACK(&xip->inp_faddr) || 748cc65eb4eSGleb Smirnoff __IN_IS_ADDR_LOOPBACK(&xip->inp_laddr))) 7499b6ca892SBruce M Simpson continue; 7509b6ca892SBruce M Simpson #undef __IN_IS_ADDR_LOOPBACK 751cc65eb4eSGleb Smirnoff } else if (xip->inp_vflag & INP_IPV6) { 752cc65eb4eSGleb Smirnoff if ((xip->inp_fport == 0 && !opt_l) || 753cc65eb4eSGleb Smirnoff (xip->inp_fport != 0 && !opt_c)) 7541e6690e5SDag-Erling Smørgrav continue; 7559b6ca892SBruce M Simpson if (opt_L && 756cc65eb4eSGleb Smirnoff (IN6_IS_ADDR_LOOPBACK(&xip->in6p_faddr) || 757cc65eb4eSGleb Smirnoff IN6_IS_ADDR_LOOPBACK(&xip->in6p_laddr))) 7589b6ca892SBruce M Simpson continue; 7591e6690e5SDag-Erling Smørgrav } else { 7601e6690e5SDag-Erling Smørgrav if (opt_v) 761cc65eb4eSGleb Smirnoff warnx("invalid vflag 0x%x", xip->inp_vflag); 7621e6690e5SDag-Erling Smørgrav continue; 7631e6690e5SDag-Erling Smørgrav } 764b8e20e2dSHiroki Sato if ((sock = calloc(1, sizeof(*sock))) == NULL) 765ca007d91SDag-Erling Smørgrav err(1, "malloc()"); 766e6f718c7SMichael Tuexen if ((laddr = calloc(1, sizeof *laddr)) == NULL) 767e6f718c7SMichael Tuexen err(1, "malloc()"); 768e6f718c7SMichael Tuexen if ((faddr = calloc(1, sizeof *faddr)) == NULL) 769e6f718c7SMichael Tuexen err(1, "malloc()"); 770ca007d91SDag-Erling Smørgrav sock->socket = so->xso_so; 771*051a2132SMark Johnston sock->splice_socket = so->so_splice_so; 772ca007d91SDag-Erling Smørgrav sock->proto = proto; 7735f64777aSMichael Tuexen sock->inp_gencnt = xip->inp_gencnt; 774cc65eb4eSGleb Smirnoff if (xip->inp_vflag & INP_IPV4) { 775ca007d91SDag-Erling Smørgrav sock->family = AF_INET; 776e6f718c7SMichael Tuexen sockaddr(&laddr->address, sock->family, 777cc65eb4eSGleb Smirnoff &xip->inp_laddr, xip->inp_lport); 778e6f718c7SMichael Tuexen sockaddr(&faddr->address, sock->family, 779cc65eb4eSGleb Smirnoff &xip->inp_faddr, xip->inp_fport); 780cc65eb4eSGleb Smirnoff } else if (xip->inp_vflag & INP_IPV6) { 781ca007d91SDag-Erling Smørgrav sock->family = AF_INET6; 782e6f718c7SMichael Tuexen sockaddr(&laddr->address, sock->family, 783cc65eb4eSGleb Smirnoff &xip->in6p_laddr, xip->inp_lport); 784e6f718c7SMichael Tuexen sockaddr(&faddr->address, sock->family, 785cc65eb4eSGleb Smirnoff &xip->in6p_faddr, xip->inp_fport); 786ca007d91SDag-Erling Smørgrav } 7879e644c23SMichael Tuexen if (proto == IPPROTO_TCP) 7889e644c23SMichael Tuexen faddr->encaps_port = xtp->xt_encaps_port; 789e6f718c7SMichael Tuexen laddr->next = NULL; 790e6f718c7SMichael Tuexen faddr->next = NULL; 791e6f718c7SMichael Tuexen sock->laddr = laddr; 792e6f718c7SMichael Tuexen sock->faddr = faddr; 793cc65eb4eSGleb Smirnoff sock->vflag = xip->inp_vflag; 794e5cccc35SMichael Tuexen if (proto == IPPROTO_TCP) { 795cc65eb4eSGleb Smirnoff sock->state = xtp->t_state; 796e5cccc35SMichael Tuexen memcpy(sock->stack, xtp->xt_stack, 797e5cccc35SMichael Tuexen TCP_FUNCTION_NAME_LEN_MAX); 7982ac089d0SMichael Tuexen memcpy(sock->cc, xtp->xt_cc, TCP_CA_NAME_MAX); 799e5cccc35SMichael Tuexen } 800ca007d91SDag-Erling Smørgrav sock->protoname = protoname; 801a83d596fSGleb Smirnoff if (sock->socket != 0) 802a83d596fSGleb Smirnoff RB_INSERT(socks_t, &socks, sock); 803a83d596fSGleb Smirnoff else 804a83d596fSGleb Smirnoff SLIST_INSERT_HEAD(&nosocks, sock, socket_list); 805ca007d91SDag-Erling Smørgrav } 806ca007d91SDag-Erling Smørgrav out: 807ca007d91SDag-Erling Smørgrav free(buf); 808ca007d91SDag-Erling Smørgrav } 809ca007d91SDag-Erling Smørgrav 810ca007d91SDag-Erling Smørgrav static void 811ca007d91SDag-Erling Smørgrav gather_unix(int proto) 812ca007d91SDag-Erling Smørgrav { 813ca007d91SDag-Erling Smørgrav struct xunpgen *xug, *exug; 814ca007d91SDag-Erling Smørgrav struct xunpcb *xup; 815ca007d91SDag-Erling Smørgrav struct sock *sock; 816e6f718c7SMichael Tuexen struct addr *laddr, *faddr; 817ca007d91SDag-Erling Smørgrav const char *varname, *protoname; 818ca007d91SDag-Erling Smørgrav size_t len, bufsize; 819ca007d91SDag-Erling Smørgrav void *buf; 820a83d596fSGleb Smirnoff int retry; 821ca007d91SDag-Erling Smørgrav 822ca007d91SDag-Erling Smørgrav switch (proto) { 823ca007d91SDag-Erling Smørgrav case SOCK_STREAM: 824ca007d91SDag-Erling Smørgrav varname = "net.local.stream.pcblist"; 825ca007d91SDag-Erling Smørgrav protoname = "stream"; 826ca007d91SDag-Erling Smørgrav break; 827ca007d91SDag-Erling Smørgrav case SOCK_DGRAM: 828ca007d91SDag-Erling Smørgrav varname = "net.local.dgram.pcblist"; 829ca007d91SDag-Erling Smørgrav protoname = "dgram"; 830ca007d91SDag-Erling Smørgrav break; 831b8e20e2dSHiroki Sato case SOCK_SEQPACKET: 832b8e20e2dSHiroki Sato varname = "net.local.seqpacket.pcblist"; 833b8e20e2dSHiroki Sato protoname = "seqpac"; 834b8e20e2dSHiroki Sato break; 835ca007d91SDag-Erling Smørgrav default: 836ca007d91SDag-Erling Smørgrav abort(); 837ca007d91SDag-Erling Smørgrav } 838ca007d91SDag-Erling Smørgrav buf = NULL; 839ca007d91SDag-Erling Smørgrav bufsize = 8192; 840ca007d91SDag-Erling Smørgrav retry = 5; 841ca007d91SDag-Erling Smørgrav do { 842ca007d91SDag-Erling Smørgrav for (;;) { 843ca007d91SDag-Erling Smørgrav if ((buf = realloc(buf, bufsize)) == NULL) 844ca007d91SDag-Erling Smørgrav err(1, "realloc()"); 845ca007d91SDag-Erling Smørgrav len = bufsize; 846c5a2d8c5SRyan Moeller if (cap_sysctlbyname(capsysctl, varname, buf, &len, 847c5a2d8c5SRyan Moeller NULL, 0) == 0) 848ca007d91SDag-Erling Smørgrav break; 849003e7e49SMikolaj Golub if (errno != ENOMEM || len != bufsize) 850c5a2d8c5SRyan Moeller err(1, "cap_sysctlbyname()"); 851ca007d91SDag-Erling Smørgrav bufsize *= 2; 852ca007d91SDag-Erling Smørgrav } 853ca007d91SDag-Erling Smørgrav xug = (struct xunpgen *)buf; 8546dbe8d53SRobert Drehmel exug = (struct xunpgen *)(void *) 855b8e20e2dSHiroki Sato ((char *)buf + len - sizeof(*exug)); 85608e77283SAlexander V. Chernikov if (!check_ksize(xug->xug_len, struct xunpgen) || 85708e77283SAlexander V. Chernikov !check_ksize(exug->xug_len, struct xunpgen)) 858ca007d91SDag-Erling Smørgrav goto out; 859ca007d91SDag-Erling Smørgrav } while (xug->xug_gen != exug->xug_gen && retry--); 860ca007d91SDag-Erling Smørgrav 861ca007d91SDag-Erling Smørgrav if (xug->xug_gen != exug->xug_gen && opt_v) 862ca007d91SDag-Erling Smørgrav warnx("warning: data may be inconsistent"); 863ca007d91SDag-Erling Smørgrav 864ca007d91SDag-Erling Smørgrav for (;;) { 8656dbe8d53SRobert Drehmel xug = (struct xunpgen *)(void *)((char *)xug + xug->xug_len); 866ca007d91SDag-Erling Smørgrav if (xug >= exug) 867ca007d91SDag-Erling Smørgrav break; 868ca007d91SDag-Erling Smørgrav xup = (struct xunpcb *)xug; 86908e77283SAlexander V. Chernikov if (!check_ksize(xup->xu_len, struct xunpcb)) 870ca007d91SDag-Erling Smørgrav goto out; 871f38b68aeSBrooks Davis if ((xup->unp_conn == 0 && !opt_l) || 872f38b68aeSBrooks Davis (xup->unp_conn != 0 && !opt_c)) 8731e6690e5SDag-Erling Smørgrav continue; 874b8e20e2dSHiroki Sato if ((sock = calloc(1, sizeof(*sock))) == NULL) 875ca007d91SDag-Erling Smørgrav err(1, "malloc()"); 876e6f718c7SMichael Tuexen if ((laddr = calloc(1, sizeof *laddr)) == NULL) 877e6f718c7SMichael Tuexen err(1, "malloc()"); 878e6f718c7SMichael Tuexen if ((faddr = calloc(1, sizeof *faddr)) == NULL) 879e6f718c7SMichael Tuexen err(1, "malloc()"); 880ca007d91SDag-Erling Smørgrav sock->socket = xup->xu_socket.xso_so; 881ca007d91SDag-Erling Smørgrav sock->pcb = xup->xu_unpp; 882ca007d91SDag-Erling Smørgrav sock->proto = proto; 883ca007d91SDag-Erling Smørgrav sock->family = AF_UNIX; 884ca007d91SDag-Erling Smørgrav sock->protoname = protoname; 8850e229f34SGleb Smirnoff if (xup->xu_addr.sun_family == AF_UNIX) 886e6f718c7SMichael Tuexen laddr->address = 8876dbe8d53SRobert Drehmel *(struct sockaddr_storage *)(void *)&xup->xu_addr; 8882c436d48SGleb Smirnoff faddr->conn = xup->unp_conn; 8892c436d48SGleb Smirnoff faddr->firstref = xup->xu_firstref; 8902c436d48SGleb Smirnoff faddr->nextref = xup->xu_nextref; 891e6f718c7SMichael Tuexen laddr->next = NULL; 892e6f718c7SMichael Tuexen faddr->next = NULL; 893e6f718c7SMichael Tuexen sock->laddr = laddr; 894e6f718c7SMichael Tuexen sock->faddr = faddr; 895a83d596fSGleb Smirnoff RB_INSERT(socks_t, &socks, sock); 896a83d596fSGleb Smirnoff RB_INSERT(pcbs_t, &pcbs, sock); 897ca007d91SDag-Erling Smørgrav } 898ca007d91SDag-Erling Smørgrav out: 899ca007d91SDag-Erling Smørgrav free(buf); 900ca007d91SDag-Erling Smørgrav } 901ca007d91SDag-Erling Smørgrav 902ca007d91SDag-Erling Smørgrav static void 903ca007d91SDag-Erling Smørgrav getfiles(void) 904ca007d91SDag-Erling Smørgrav { 9052c436d48SGleb Smirnoff struct xfile *xfiles; 906003e7e49SMikolaj Golub size_t len, olen; 907ca007d91SDag-Erling Smørgrav 908b8e20e2dSHiroki Sato olen = len = sizeof(*xfiles); 909003e7e49SMikolaj Golub if ((xfiles = malloc(len)) == NULL) 910ca007d91SDag-Erling Smørgrav err(1, "malloc()"); 911c5a2d8c5SRyan Moeller while (cap_sysctlbyname(capsysctl, "kern.file", xfiles, &len, 0, 0) 912c5a2d8c5SRyan Moeller == -1) { 913003e7e49SMikolaj Golub if (errno != ENOMEM || len != olen) 914c5a2d8c5SRyan Moeller err(1, "cap_sysctlbyname()"); 915003e7e49SMikolaj Golub olen = len *= 2; 916ca007d91SDag-Erling Smørgrav if ((xfiles = realloc(xfiles, len)) == NULL) 917ca007d91SDag-Erling Smørgrav err(1, "realloc()"); 918ca007d91SDag-Erling Smørgrav } 91908e77283SAlexander V. Chernikov if (len > 0) 92008e77283SAlexander V. Chernikov enforce_ksize(xfiles->xf_size, struct xfile); 9212c436d48SGleb Smirnoff nfiles = len / sizeof(*xfiles); 9222c436d48SGleb Smirnoff 9232c436d48SGleb Smirnoff if ((files = malloc(nfiles * sizeof(struct file))) == NULL) 9242c436d48SGleb Smirnoff err(1, "malloc()"); 9252c436d48SGleb Smirnoff 9262c436d48SGleb Smirnoff for (int i = 0; i < nfiles; i++) { 9272c436d48SGleb Smirnoff files[i].xf_data = xfiles[i].xf_data; 9282c436d48SGleb Smirnoff files[i].xf_pid = xfiles[i].xf_pid; 9292c436d48SGleb Smirnoff files[i].xf_uid = xfiles[i].xf_uid; 9302c436d48SGleb Smirnoff files[i].xf_fd = xfiles[i].xf_fd; 9312c436d48SGleb Smirnoff RB_INSERT(files_t, &ftree, &files[i]); 9322c436d48SGleb Smirnoff } 9332c436d48SGleb Smirnoff 9342c436d48SGleb Smirnoff free(xfiles); 935ca007d91SDag-Erling Smørgrav } 936ca007d91SDag-Erling Smørgrav 937ca007d91SDag-Erling Smørgrav static int 938baa7f281SMichael Tuexen printaddr(struct sockaddr_storage *ss) 939ca007d91SDag-Erling Smørgrav { 940ca007d91SDag-Erling Smørgrav struct sockaddr_un *sun; 941b8e20e2dSHiroki Sato char addrstr[NI_MAXHOST] = { '\0', '\0' }; 942b8e20e2dSHiroki Sato int error, off, port = 0; 943ca007d91SDag-Erling Smørgrav 944baa7f281SMichael Tuexen switch (ss->ss_family) { 945ca007d91SDag-Erling Smørgrav case AF_INET: 94664acb29bSMike Karels if (sstosin(ss)->sin_addr.s_addr == INADDR_ANY) 947ca007d91SDag-Erling Smørgrav addrstr[0] = '*'; 948b8e20e2dSHiroki Sato port = ntohs(sstosin(ss)->sin_port); 949ca007d91SDag-Erling Smørgrav break; 950ca007d91SDag-Erling Smørgrav case AF_INET6: 951b8e20e2dSHiroki Sato if (IN6_IS_ADDR_UNSPECIFIED(&sstosin6(ss)->sin6_addr)) 952ca007d91SDag-Erling Smørgrav addrstr[0] = '*'; 953b8e20e2dSHiroki Sato port = ntohs(sstosin6(ss)->sin6_port); 954ca007d91SDag-Erling Smørgrav break; 955ca007d91SDag-Erling Smørgrav case AF_UNIX: 956b8e20e2dSHiroki Sato sun = sstosun(ss); 957ca007d91SDag-Erling Smørgrav off = (int)((char *)&sun->sun_path - (char *)sun); 958ca007d91SDag-Erling Smørgrav return (xprintf("%.*s", sun->sun_len - off, sun->sun_path)); 959ca007d91SDag-Erling Smørgrav } 960b8e20e2dSHiroki Sato if (addrstr[0] == '\0') { 961c5a2d8c5SRyan Moeller error = cap_getnameinfo(capnet, sstosa(ss), ss->ss_len, 962c5a2d8c5SRyan Moeller addrstr, sizeof(addrstr), NULL, 0, NI_NUMERICHOST); 963b8e20e2dSHiroki Sato if (error) 964c5a2d8c5SRyan Moeller errx(1, "cap_getnameinfo()"); 965b8e20e2dSHiroki Sato } 966ca007d91SDag-Erling Smørgrav if (port == 0) 967ca007d91SDag-Erling Smørgrav return xprintf("%s:*", addrstr); 968ca007d91SDag-Erling Smørgrav else 969ca007d91SDag-Erling Smørgrav return xprintf("%s:%d", addrstr, port); 970ca007d91SDag-Erling Smørgrav } 971ca007d91SDag-Erling Smørgrav 972ca007d91SDag-Erling Smørgrav static const char * 973ca007d91SDag-Erling Smørgrav getprocname(pid_t pid) 974ca007d91SDag-Erling Smørgrav { 975ca007d91SDag-Erling Smørgrav static struct kinfo_proc proc; 976ca007d91SDag-Erling Smørgrav size_t len; 977ca007d91SDag-Erling Smørgrav int mib[4]; 978ca007d91SDag-Erling Smørgrav 979ca007d91SDag-Erling Smørgrav mib[0] = CTL_KERN; 980ca007d91SDag-Erling Smørgrav mib[1] = KERN_PROC; 981ca007d91SDag-Erling Smørgrav mib[2] = KERN_PROC_PID; 982ca007d91SDag-Erling Smørgrav mib[3] = (int)pid; 983b8e20e2dSHiroki Sato len = sizeof(proc); 984c5a2d8c5SRyan Moeller if (cap_sysctl(capsysctl, mib, nitems(mib), &proc, &len, NULL, 0) 985c5a2d8c5SRyan Moeller == -1) { 98648c513e0SMaxim Konovalov /* Do not warn if the process exits before we get its name. */ 98748c513e0SMaxim Konovalov if (errno != ESRCH) 988c5a2d8c5SRyan Moeller warn("cap_sysctl()"); 989ca007d91SDag-Erling Smørgrav return ("??"); 990ca007d91SDag-Erling Smørgrav } 991f487a6a8SEd Maste return (proc.ki_comm); 992ca007d91SDag-Erling Smørgrav } 993ca007d91SDag-Erling Smørgrav 994ae94787dSMaxime Henrion static int 99500feaafdSAndrew Thompson getprocjid(pid_t pid) 99600feaafdSAndrew Thompson { 99700feaafdSAndrew Thompson static struct kinfo_proc proc; 99800feaafdSAndrew Thompson size_t len; 99900feaafdSAndrew Thompson int mib[4]; 100000feaafdSAndrew Thompson 100100feaafdSAndrew Thompson mib[0] = CTL_KERN; 100200feaafdSAndrew Thompson mib[1] = KERN_PROC; 100300feaafdSAndrew Thompson mib[2] = KERN_PROC_PID; 100400feaafdSAndrew Thompson mib[3] = (int)pid; 1005b8e20e2dSHiroki Sato len = sizeof(proc); 1006c5a2d8c5SRyan Moeller if (cap_sysctl(capsysctl, mib, nitems(mib), &proc, &len, NULL, 0) 1007c5a2d8c5SRyan Moeller == -1) { 100800feaafdSAndrew Thompson /* Do not warn if the process exits before we get its jid. */ 100900feaafdSAndrew Thompson if (errno != ESRCH) 1010c5a2d8c5SRyan Moeller warn("cap_sysctl()"); 101100feaafdSAndrew Thompson return (-1); 101200feaafdSAndrew Thompson } 101300feaafdSAndrew Thompson return (proc.ki_jid); 101400feaafdSAndrew Thompson } 101500feaafdSAndrew Thompson 101600feaafdSAndrew Thompson static int 1017ae94787dSMaxime Henrion check_ports(struct sock *s) 1018ae94787dSMaxime Henrion { 1019ae94787dSMaxime Henrion int port; 1020e6f718c7SMichael Tuexen struct addr *addr; 1021ae94787dSMaxime Henrion 1022ae94787dSMaxime Henrion if (ports == NULL) 1023ae94787dSMaxime Henrion return (1); 1024ae94787dSMaxime Henrion if ((s->family != AF_INET) && (s->family != AF_INET6)) 1025ae94787dSMaxime Henrion return (1); 1026e6f718c7SMichael Tuexen for (addr = s->laddr; addr != NULL; addr = addr->next) { 1027b8e20e2dSHiroki Sato if (s->family == AF_INET) 1028b8e20e2dSHiroki Sato port = ntohs(sstosin(&addr->address)->sin_port); 1029ae94787dSMaxime Henrion else 1030b8e20e2dSHiroki Sato port = ntohs(sstosin6(&addr->address)->sin6_port); 1031ae94787dSMaxime Henrion if (CHK_PORT(port)) 1032ae94787dSMaxime Henrion return (1); 1033e6f718c7SMichael Tuexen } 1034e6f718c7SMichael Tuexen for (addr = s->faddr; addr != NULL; addr = addr->next) { 1035b8e20e2dSHiroki Sato if (s->family == AF_INET) 1036b8e20e2dSHiroki Sato port = ntohs(sstosin(&addr->address)->sin_port); 1037ae94787dSMaxime Henrion else 1038b8e20e2dSHiroki Sato port = ntohs(sstosin6(&addr->address)->sin6_port); 1039ae94787dSMaxime Henrion if (CHK_PORT(port)) 1040ae94787dSMaxime Henrion return (1); 1041e6f718c7SMichael Tuexen } 1042ae94787dSMaxime Henrion return (0); 1043ae94787dSMaxime Henrion } 1044ae94787dSMaxime Henrion 10456414db1bSMichael Tuexen static const char * 1046e389705eSMichael Tuexen sctp_conn_state(int state) 10476414db1bSMichael Tuexen { 10486414db1bSMichael Tuexen switch (state) { 10496414db1bSMichael Tuexen case SCTP_CLOSED: 10506414db1bSMichael Tuexen return "CLOSED"; 10516414db1bSMichael Tuexen break; 10526414db1bSMichael Tuexen case SCTP_BOUND: 10536414db1bSMichael Tuexen return "BOUND"; 10546414db1bSMichael Tuexen break; 10556414db1bSMichael Tuexen case SCTP_LISTEN: 10566414db1bSMichael Tuexen return "LISTEN"; 10576414db1bSMichael Tuexen break; 10586414db1bSMichael Tuexen case SCTP_COOKIE_WAIT: 10596414db1bSMichael Tuexen return "COOKIE_WAIT"; 10606414db1bSMichael Tuexen break; 10616414db1bSMichael Tuexen case SCTP_COOKIE_ECHOED: 10626414db1bSMichael Tuexen return "COOKIE_ECHOED"; 10636414db1bSMichael Tuexen break; 10646414db1bSMichael Tuexen case SCTP_ESTABLISHED: 10656414db1bSMichael Tuexen return "ESTABLISHED"; 10666414db1bSMichael Tuexen break; 10676414db1bSMichael Tuexen case SCTP_SHUTDOWN_SENT: 10686414db1bSMichael Tuexen return "SHUTDOWN_SENT"; 10696414db1bSMichael Tuexen break; 10706414db1bSMichael Tuexen case SCTP_SHUTDOWN_RECEIVED: 10716414db1bSMichael Tuexen return "SHUTDOWN_RECEIVED"; 10726414db1bSMichael Tuexen break; 10736414db1bSMichael Tuexen case SCTP_SHUTDOWN_ACK_SENT: 10746414db1bSMichael Tuexen return "SHUTDOWN_ACK_SENT"; 10756414db1bSMichael Tuexen break; 10766414db1bSMichael Tuexen case SCTP_SHUTDOWN_PENDING: 10776414db1bSMichael Tuexen return "SHUTDOWN_PENDING"; 10786414db1bSMichael Tuexen break; 10796414db1bSMichael Tuexen default: 10806414db1bSMichael Tuexen return "UNKNOWN"; 10816414db1bSMichael Tuexen break; 10826414db1bSMichael Tuexen } 10836414db1bSMichael Tuexen } 10846414db1bSMichael Tuexen 1085e389705eSMichael Tuexen static const char * 1086e389705eSMichael Tuexen sctp_path_state(int state) 1087e389705eSMichael Tuexen { 1088e389705eSMichael Tuexen switch (state) { 1089e389705eSMichael Tuexen case SCTP_UNCONFIRMED: 1090e389705eSMichael Tuexen return "UNCONFIRMED"; 1091e389705eSMichael Tuexen break; 1092e389705eSMichael Tuexen case SCTP_ACTIVE: 1093e389705eSMichael Tuexen return "ACTIVE"; 1094e389705eSMichael Tuexen break; 1095e389705eSMichael Tuexen case SCTP_INACTIVE: 1096e389705eSMichael Tuexen return "INACTIVE"; 1097e389705eSMichael Tuexen break; 1098e389705eSMichael Tuexen default: 1099e389705eSMichael Tuexen return "UNKNOWN"; 1100e389705eSMichael Tuexen break; 1101e389705eSMichael Tuexen } 1102e389705eSMichael Tuexen } 1103e389705eSMichael Tuexen 1104ca007d91SDag-Erling Smørgrav static void 110561149f8dSJilles Tjoelker displaysock(struct sock *s, int pos) 1106ca007d91SDag-Erling Smørgrav { 1107a83d596fSGleb Smirnoff int first, offset; 1108e6f718c7SMichael Tuexen struct addr *laddr, *faddr; 1109ca007d91SDag-Erling Smørgrav 1110c5bdcd1fSGleb Smirnoff while (pos < 30) 1111ca007d91SDag-Erling Smørgrav pos += xprintf(" "); 1112ca007d91SDag-Erling Smørgrav pos += xprintf("%s", s->protoname); 1113ca007d91SDag-Erling Smørgrav if (s->vflag & INP_IPV4) 1114ca007d91SDag-Erling Smørgrav pos += xprintf("4"); 1115ca007d91SDag-Erling Smørgrav if (s->vflag & INP_IPV6) 1116ca007d91SDag-Erling Smørgrav pos += xprintf("6"); 1117edc9c7fcSMichael Tuexen if (s->vflag & (INP_IPV4 | INP_IPV6)) 1118edc9c7fcSMichael Tuexen pos += xprintf(" "); 1119e6f718c7SMichael Tuexen laddr = s->laddr; 1120e6f718c7SMichael Tuexen faddr = s->faddr; 11214e13a5b0SMichael Tuexen first = 1; 1122e6f718c7SMichael Tuexen while (laddr != NULL || faddr != NULL) { 1123c5bdcd1fSGleb Smirnoff offset = 37; 112483f60cb2SMichael Tuexen while (pos < offset) 1125ca007d91SDag-Erling Smørgrav pos += xprintf(" "); 1126ca007d91SDag-Erling Smørgrav switch (s->family) { 1127ca007d91SDag-Erling Smørgrav case AF_INET: 1128ca007d91SDag-Erling Smørgrav case AF_INET6: 1129e6f718c7SMichael Tuexen if (laddr != NULL) { 1130e6f718c7SMichael Tuexen pos += printaddr(&laddr->address); 113109bbda21SMaxim Konovalov if (s->family == AF_INET6 && pos >= 58) 113209bbda21SMaxim Konovalov pos += xprintf(" "); 1133e6f718c7SMichael Tuexen } 113483f60cb2SMichael Tuexen offset += opt_w ? 46 : 22; 113583f60cb2SMichael Tuexen while (pos < offset) 1136ca007d91SDag-Erling Smørgrav pos += xprintf(" "); 1137e6f718c7SMichael Tuexen if (faddr != NULL) 1138e6f718c7SMichael Tuexen pos += printaddr(&faddr->address); 113983f60cb2SMichael Tuexen offset += opt_w ? 46 : 22; 1140ca007d91SDag-Erling Smørgrav break; 1141ca007d91SDag-Erling Smørgrav case AF_UNIX: 1142e6f718c7SMichael Tuexen if ((laddr == NULL) || (faddr == NULL)) 1143e6f718c7SMichael Tuexen errx(1, "laddr = %p or faddr = %p is NULL", 1144e6f718c7SMichael Tuexen (void *)laddr, (void *)faddr); 11452c436d48SGleb Smirnoff if (laddr->address.ss_len == 0 && faddr->conn == 0) { 1146b4eb37c6SJohn-Mark Gurney pos += xprintf("(not connected)"); 114783f60cb2SMichael Tuexen offset += opt_w ? 92 : 44; 1148b4eb37c6SJohn-Mark Gurney break; 1149b4eb37c6SJohn-Mark Gurney } 11502c436d48SGleb Smirnoff /* Local bind(2) address, if any. */ 11512c436d48SGleb Smirnoff if (laddr->address.ss_len > 0) 11522c436d48SGleb Smirnoff pos += printaddr(&laddr->address); 11532c436d48SGleb Smirnoff /* Remote peer we connect(2) to, if any. */ 11542c436d48SGleb Smirnoff if (faddr->conn != 0) { 11552c436d48SGleb Smirnoff struct sock *p; 11562c436d48SGleb Smirnoff 11572c436d48SGleb Smirnoff pos += xprintf("%s-> ", 11582c436d48SGleb Smirnoff laddr->address.ss_len > 0 ? " " : ""); 11592c436d48SGleb Smirnoff p = RB_FIND(pcbs_t, &pcbs, 11602c436d48SGleb Smirnoff &(struct sock){ .pcb = faddr->conn }); 11612c436d48SGleb Smirnoff if (__predict_false(p == NULL)) { 11622c436d48SGleb Smirnoff /* XXGL: can this happen at all? */ 1163ca007d91SDag-Erling Smørgrav pos += xprintf("??"); 11642c436d48SGleb Smirnoff } else if (p->laddr->address.ss_len == 0) { 11652c436d48SGleb Smirnoff struct file *f; 11662c436d48SGleb Smirnoff 11672c436d48SGleb Smirnoff f = RB_FIND(files_t, &ftree, 11682c436d48SGleb Smirnoff &(struct file){ .xf_data = 11692c436d48SGleb Smirnoff p->socket }); 117035f49843SKonstantin Belousov if (f != NULL) { 11712c436d48SGleb Smirnoff pos += xprintf("[%lu %d]", 117235f49843SKonstantin Belousov (u_long)f->xf_pid, 117335f49843SKonstantin Belousov f->xf_fd); 117435f49843SKonstantin Belousov } 11752c436d48SGleb Smirnoff } else 11762c436d48SGleb Smirnoff pos += printaddr(&p->laddr->address); 11772c436d48SGleb Smirnoff } 11782c436d48SGleb Smirnoff /* Remote peer(s) connect(2)ed to us, if any. */ 11792c436d48SGleb Smirnoff if (faddr->firstref != 0) { 11802c436d48SGleb Smirnoff struct sock *p; 11812c436d48SGleb Smirnoff struct file *f; 11822c436d48SGleb Smirnoff kvaddr_t ref = faddr->firstref; 11832c436d48SGleb Smirnoff bool fref = true; 11842c436d48SGleb Smirnoff 11852c436d48SGleb Smirnoff pos += xprintf(" <- "); 11862c436d48SGleb Smirnoff 11872c436d48SGleb Smirnoff while ((p = RB_FIND(pcbs_t, &pcbs, 11882c436d48SGleb Smirnoff &(struct sock){ .pcb = ref })) != 0) { 11892c436d48SGleb Smirnoff f = RB_FIND(files_t, &ftree, 11902c436d48SGleb Smirnoff &(struct file){ .xf_data = 11912c436d48SGleb Smirnoff p->socket }); 119235f49843SKonstantin Belousov if (f != NULL) { 11932c436d48SGleb Smirnoff pos += xprintf("%s[%lu %d]", 11942c436d48SGleb Smirnoff fref ? "" : ",", 119535f49843SKonstantin Belousov (u_long)f->xf_pid, 119635f49843SKonstantin Belousov f->xf_fd); 119735f49843SKonstantin Belousov } 11982c436d48SGleb Smirnoff ref = p->faddr->nextref; 11992c436d48SGleb Smirnoff fref = false; 12002c436d48SGleb Smirnoff } 12012c436d48SGleb Smirnoff } 120283f60cb2SMichael Tuexen offset += opt_w ? 92 : 44; 1203ca007d91SDag-Erling Smørgrav break; 1204ca007d91SDag-Erling Smørgrav default: 1205ca007d91SDag-Erling Smørgrav abort(); 1206ca007d91SDag-Erling Smørgrav } 1207*051a2132SMark Johnston if (opt_I) { 1208*051a2132SMark Johnston if (s->splice_socket != 0) { 1209*051a2132SMark Johnston struct sock *sp; 1210*051a2132SMark Johnston 1211*051a2132SMark Johnston sp = RB_FIND(socks_t, &socks, &(struct sock) 1212*051a2132SMark Johnston { .socket = s->splice_socket }); 1213*051a2132SMark Johnston if (sp != NULL) { 1214*051a2132SMark Johnston while (pos < offset) 1215*051a2132SMark Johnston pos += xprintf(" "); 1216*051a2132SMark Johnston pos += printaddr(&sp->laddr->address); 1217*051a2132SMark Johnston } else { 1218*051a2132SMark Johnston while (pos < offset) 1219*051a2132SMark Johnston pos += xprintf(" "); 1220*051a2132SMark Johnston pos += xprintf("??"); 1221*051a2132SMark Johnston offset += opt_w ? 46 : 22; 1222*051a2132SMark Johnston } 1223*051a2132SMark Johnston } 1224*051a2132SMark Johnston offset += opt_w ? 46 : 22; 1225*051a2132SMark Johnston } 12265f64777aSMichael Tuexen if (opt_i) { 12275f64777aSMichael Tuexen if (s->proto == IPPROTO_TCP || 12285f64777aSMichael Tuexen s->proto == IPPROTO_UDP) { 12295f64777aSMichael Tuexen while (pos < offset) 12305f64777aSMichael Tuexen pos += xprintf(" "); 12315f64777aSMichael Tuexen pos += xprintf("%" PRIu64, s->inp_gencnt); 12325f64777aSMichael Tuexen } 12335f64777aSMichael Tuexen offset += 9; 12345f64777aSMichael Tuexen } 123549b836f2SMichael Tuexen if (opt_U) { 123649b836f2SMichael Tuexen if (faddr != NULL && 12379e644c23SMichael Tuexen ((s->proto == IPPROTO_SCTP && 123849b836f2SMichael Tuexen s->state != SCTP_CLOSED && 123949b836f2SMichael Tuexen s->state != SCTP_BOUND && 12409e644c23SMichael Tuexen s->state != SCTP_LISTEN) || 12419e644c23SMichael Tuexen (s->proto == IPPROTO_TCP && 12429e644c23SMichael Tuexen s->state != TCPS_CLOSED && 12439e644c23SMichael Tuexen s->state != TCPS_LISTEN))) { 124449b836f2SMichael Tuexen while (pos < offset) 124549b836f2SMichael Tuexen pos += xprintf(" "); 124649b836f2SMichael Tuexen pos += xprintf("%u", 124749b836f2SMichael Tuexen ntohs(faddr->encaps_port)); 124849b836f2SMichael Tuexen } 124949b836f2SMichael Tuexen offset += 7; 125049b836f2SMichael Tuexen } 1251e389705eSMichael Tuexen if (opt_s) { 1252e389705eSMichael Tuexen if (faddr != NULL && 1253e389705eSMichael Tuexen s->proto == IPPROTO_SCTP && 1254e389705eSMichael Tuexen s->state != SCTP_CLOSED && 1255e389705eSMichael Tuexen s->state != SCTP_BOUND && 1256e389705eSMichael Tuexen s->state != SCTP_LISTEN) { 1257e389705eSMichael Tuexen while (pos < offset) 1258e389705eSMichael Tuexen pos += xprintf(" "); 1259e389705eSMichael Tuexen pos += xprintf("%s", 1260e389705eSMichael Tuexen sctp_path_state(faddr->state)); 1261e389705eSMichael Tuexen } 1262e389705eSMichael Tuexen offset += 13; 1263e389705eSMichael Tuexen } 1264e5cccc35SMichael Tuexen if (first) { 126549b836f2SMichael Tuexen if (opt_s) { 126649b836f2SMichael Tuexen if (s->proto == IPPROTO_SCTP || 126749b836f2SMichael Tuexen s->proto == IPPROTO_TCP) { 126849b836f2SMichael Tuexen while (pos < offset) 12694e13a5b0SMichael Tuexen pos += xprintf(" "); 12706414db1bSMichael Tuexen switch (s->proto) { 12716414db1bSMichael Tuexen case IPPROTO_SCTP: 1272e5cccc35SMichael Tuexen pos += xprintf("%s", 1273e389705eSMichael Tuexen sctp_conn_state(s->state)); 12746414db1bSMichael Tuexen break; 12756414db1bSMichael Tuexen case IPPROTO_TCP: 1276e5cccc35SMichael Tuexen if (s->state >= 0 && 1277e5cccc35SMichael Tuexen s->state < TCP_NSTATES) 127849b836f2SMichael Tuexen pos += xprintf("%s", 1279e5cccc35SMichael Tuexen tcpstates[s->state]); 12804e13a5b0SMichael Tuexen else 12814e13a5b0SMichael Tuexen pos += xprintf("?"); 12826414db1bSMichael Tuexen break; 12836414db1bSMichael Tuexen } 12844e13a5b0SMichael Tuexen } 128549b836f2SMichael Tuexen offset += 13; 128649b836f2SMichael Tuexen } 12872ac089d0SMichael Tuexen if (opt_S) { 12882ac089d0SMichael Tuexen if (s->proto == IPPROTO_TCP) { 128949b836f2SMichael Tuexen while (pos < offset) 1290e5cccc35SMichael Tuexen pos += xprintf(" "); 12912ac089d0SMichael Tuexen pos += xprintf("%.*s", 12922ac089d0SMichael Tuexen TCP_FUNCTION_NAME_LEN_MAX, 1293e5cccc35SMichael Tuexen s->stack); 1294e5cccc35SMichael Tuexen } 12952ac089d0SMichael Tuexen offset += TCP_FUNCTION_NAME_LEN_MAX + 1; 12962ac089d0SMichael Tuexen } 12972ac089d0SMichael Tuexen if (opt_C) { 12982ac089d0SMichael Tuexen if (s->proto == IPPROTO_TCP) { 12992ac089d0SMichael Tuexen while (pos < offset) 13002ac089d0SMichael Tuexen pos += xprintf(" "); 13012ac089d0SMichael Tuexen xprintf("%.*s", TCP_CA_NAME_MAX, s->cc); 13022ac089d0SMichael Tuexen } 13032ac089d0SMichael Tuexen offset += TCP_CA_NAME_MAX + 1; 13042ac089d0SMichael Tuexen } 1305e5cccc35SMichael Tuexen } 1306e6f718c7SMichael Tuexen if (laddr != NULL) 1307e6f718c7SMichael Tuexen laddr = laddr->next; 1308e6f718c7SMichael Tuexen if (faddr != NULL) 1309e6f718c7SMichael Tuexen faddr = faddr->next; 1310e6f718c7SMichael Tuexen if ((laddr != NULL) || (faddr != NULL)) { 1311e6f718c7SMichael Tuexen xprintf("\n"); 1312e6f718c7SMichael Tuexen pos = 0; 1313e6f718c7SMichael Tuexen } 13144e13a5b0SMichael Tuexen first = 0; 1315e6f718c7SMichael Tuexen } 13164e13a5b0SMichael Tuexen xprintf("\n"); 1317ca007d91SDag-Erling Smørgrav } 131861149f8dSJilles Tjoelker 131961149f8dSJilles Tjoelker static void 132061149f8dSJilles Tjoelker display(void) 132161149f8dSJilles Tjoelker { 132261149f8dSJilles Tjoelker struct passwd *pwd; 13232c436d48SGleb Smirnoff struct file *xf; 132461149f8dSJilles Tjoelker struct sock *s; 1325a83d596fSGleb Smirnoff int n, pos; 132661149f8dSJilles Tjoelker 1327ee0afaa9SEmmanuel Vadot if (opt_q != 1) { 1328c5bdcd1fSGleb Smirnoff printf("%-8s %-10s %-5s %-3s %-6s %-*s %-*s", 132961149f8dSJilles Tjoelker "USER", "COMMAND", "PID", "FD", "PROTO", 133083f60cb2SMichael Tuexen opt_w ? 45 : 21, "LOCAL ADDRESS", 133183f60cb2SMichael Tuexen opt_w ? 45 : 21, "FOREIGN ADDRESS"); 1332*051a2132SMark Johnston if (opt_I) 1333*051a2132SMark Johnston printf(" %-*s", opt_w ? 45 : 21, "SPLICE ADDRESS"); 13345f64777aSMichael Tuexen if (opt_i) 13355f64777aSMichael Tuexen printf(" %-8s", "ID"); 133649b836f2SMichael Tuexen if (opt_U) 133749b836f2SMichael Tuexen printf(" %-6s", "ENCAPS"); 1338e389705eSMichael Tuexen if (opt_s) { 1339e389705eSMichael Tuexen printf(" %-12s", "PATH STATE"); 1340e389705eSMichael Tuexen printf(" %-12s", "CONN STATE"); 1341e389705eSMichael Tuexen } 1342e5cccc35SMichael Tuexen if (opt_S) 13432ac089d0SMichael Tuexen printf(" %-*.*s", TCP_FUNCTION_NAME_LEN_MAX, 13442ac089d0SMichael Tuexen TCP_FUNCTION_NAME_LEN_MAX, "STACK"); 13452ac089d0SMichael Tuexen if (opt_C) 13462ac089d0SMichael Tuexen printf(" %-.*s", TCP_CA_NAME_MAX, "CC"); 13477a5642b3SDag-Erling Smørgrav printf("\n"); 1348ee0afaa9SEmmanuel Vadot } 13497ad30f58SMariusz Zaborski cap_setpassent(cappwd, 1); 13502c436d48SGleb Smirnoff for (xf = files, n = 0; n < nfiles; ++n, ++xf) { 1351f38b68aeSBrooks Davis if (xf->xf_data == 0) 135261149f8dSJilles Tjoelker continue; 135300feaafdSAndrew Thompson if (opt_j >= 0 && opt_j != getprocjid(xf->xf_pid)) 135400feaafdSAndrew Thompson continue; 1355a83d596fSGleb Smirnoff s = RB_FIND(socks_t, &socks, 1356a83d596fSGleb Smirnoff &(struct sock){ .socket = xf->xf_data}); 1357a83d596fSGleb Smirnoff if (s != NULL && check_ports(s)) { 135861149f8dSJilles Tjoelker s->shown = 1; 135961149f8dSJilles Tjoelker pos = 0; 13607ad30f58SMariusz Zaborski if (opt_n || 13617ad30f58SMariusz Zaborski (pwd = cap_getpwuid(cappwd, xf->xf_uid)) == NULL) 136261149f8dSJilles Tjoelker pos += xprintf("%lu ", (u_long)xf->xf_uid); 136361149f8dSJilles Tjoelker else 136461149f8dSJilles Tjoelker pos += xprintf("%s ", pwd->pw_name); 136561149f8dSJilles Tjoelker while (pos < 9) 136661149f8dSJilles Tjoelker pos += xprintf(" "); 136761149f8dSJilles Tjoelker pos += xprintf("%.10s", getprocname(xf->xf_pid)); 136861149f8dSJilles Tjoelker while (pos < 20) 136961149f8dSJilles Tjoelker pos += xprintf(" "); 1370d961ccd3SGleb Smirnoff pos += xprintf("%5lu ", (u_long)xf->xf_pid); 137161149f8dSJilles Tjoelker while (pos < 26) 137261149f8dSJilles Tjoelker pos += xprintf(" "); 1373c5bdcd1fSGleb Smirnoff pos += xprintf("%-3d ", xf->xf_fd); 137461149f8dSJilles Tjoelker displaysock(s, pos); 137561149f8dSJilles Tjoelker } 13767e80c6b0SMichael Tuexen } 137700feaafdSAndrew Thompson if (opt_j >= 0) 137800feaafdSAndrew Thompson return; 1379a83d596fSGleb Smirnoff SLIST_FOREACH(s, &nosocks, socket_list) { 1380a83d596fSGleb Smirnoff if (!check_ports(s)) 1381a83d596fSGleb Smirnoff continue; 1382a83d596fSGleb Smirnoff pos = xprintf("%-8s %-10s %-5s %-2s ", 1383a83d596fSGleb Smirnoff "?", "?", "?", "?"); 1384a83d596fSGleb Smirnoff displaysock(s, pos); 1385a83d596fSGleb Smirnoff } 1386a83d596fSGleb Smirnoff RB_FOREACH(s, socks_t, &socks) { 138761149f8dSJilles Tjoelker if (s->shown) 138861149f8dSJilles Tjoelker continue; 138961149f8dSJilles Tjoelker if (!check_ports(s)) 139061149f8dSJilles Tjoelker continue; 1391a83d596fSGleb Smirnoff pos = xprintf("%-8s %-10s %-5s %-2s ", 139261149f8dSJilles Tjoelker "?", "?", "?", "?"); 139361149f8dSJilles Tjoelker displaysock(s, pos); 139461149f8dSJilles Tjoelker } 139561149f8dSJilles Tjoelker } 1396ca007d91SDag-Erling Smørgrav 1397f1cd4902SRyan Moeller static int 1398f1cd4902SRyan Moeller set_default_protos(void) 13991f3d67aaSGiorgos Keramidas { 14001f3d67aaSGiorgos Keramidas struct protoent *prot; 14011f3d67aaSGiorgos Keramidas const char *pname; 14021f3d67aaSGiorgos Keramidas size_t pindex; 14031f3d67aaSGiorgos Keramidas 14041f3d67aaSGiorgos Keramidas init_protos(default_numprotos); 14051f3d67aaSGiorgos Keramidas 14061f3d67aaSGiorgos Keramidas for (pindex = 0; pindex < default_numprotos; pindex++) { 14071f3d67aaSGiorgos Keramidas pname = default_protos[pindex]; 1408c5a2d8c5SRyan Moeller prot = cap_getprotobyname(capnetdb, pname); 14091f3d67aaSGiorgos Keramidas if (prot == NULL) 1410c5a2d8c5SRyan Moeller err(1, "cap_getprotobyname: %s", pname); 14111f3d67aaSGiorgos Keramidas protos[pindex] = prot->p_proto; 14121f3d67aaSGiorgos Keramidas } 14131f3d67aaSGiorgos Keramidas numprotos = pindex; 14141f3d67aaSGiorgos Keramidas return (pindex); 14151f3d67aaSGiorgos Keramidas } 14161f3d67aaSGiorgos Keramidas 1417f1cd4902SRyan Moeller /* 1418f1cd4902SRyan Moeller * Return the vnet property of the jail, or -1 on error. 1419f1cd4902SRyan Moeller */ 1420f1cd4902SRyan Moeller static int 1421f1cd4902SRyan Moeller jail_getvnet(int jid) 1422f1cd4902SRyan Moeller { 1423f1cd4902SRyan Moeller struct iovec jiov[6]; 1424f1cd4902SRyan Moeller int vnet; 14251fec1fa8SGleb Smirnoff size_t len = sizeof(vnet); 14261fec1fa8SGleb Smirnoff 14271fec1fa8SGleb Smirnoff if (sysctlbyname("kern.features.vimage", &vnet, &len, NULL, 0) != 0) 14281fec1fa8SGleb Smirnoff return (0); 1429f1cd4902SRyan Moeller 1430f1cd4902SRyan Moeller vnet = -1; 1431f1cd4902SRyan Moeller jiov[0].iov_base = __DECONST(char *, "jid"); 1432f1cd4902SRyan Moeller jiov[0].iov_len = sizeof("jid"); 1433f1cd4902SRyan Moeller jiov[1].iov_base = &jid; 1434f1cd4902SRyan Moeller jiov[1].iov_len = sizeof(jid); 1435f1cd4902SRyan Moeller jiov[2].iov_base = __DECONST(char *, "vnet"); 1436f1cd4902SRyan Moeller jiov[2].iov_len = sizeof("vnet"); 1437f1cd4902SRyan Moeller jiov[3].iov_base = &vnet; 1438f1cd4902SRyan Moeller jiov[3].iov_len = sizeof(vnet); 1439f1cd4902SRyan Moeller jiov[4].iov_base = __DECONST(char *, "errmsg"); 1440f1cd4902SRyan Moeller jiov[4].iov_len = sizeof("errmsg"); 1441f1cd4902SRyan Moeller jiov[5].iov_base = jail_errmsg; 1442f1cd4902SRyan Moeller jiov[5].iov_len = JAIL_ERRMSGLEN; 1443f1cd4902SRyan Moeller jail_errmsg[0] = '\0'; 1444f1cd4902SRyan Moeller if (jail_get(jiov, nitems(jiov), 0) < 0) { 1445f1cd4902SRyan Moeller if (!jail_errmsg[0]) 1446f1cd4902SRyan Moeller snprintf(jail_errmsg, JAIL_ERRMSGLEN, 1447f1cd4902SRyan Moeller "jail_get: %s", strerror(errno)); 1448f1cd4902SRyan Moeller return (-1); 1449f1cd4902SRyan Moeller } 1450f1cd4902SRyan Moeller return (vnet); 1451f1cd4902SRyan Moeller } 1452f1cd4902SRyan Moeller 1453ca007d91SDag-Erling Smørgrav static void 1454ca007d91SDag-Erling Smørgrav usage(void) 1455ca007d91SDag-Erling Smørgrav { 14561f3d67aaSGiorgos Keramidas fprintf(stderr, 1457*051a2132SMark Johnston "usage: sockstat [-46CcIiLlnqSsUuvw] [-j jid] [-p ports] [-P protocols]\n"); 1458ca007d91SDag-Erling Smørgrav exit(1); 1459ca007d91SDag-Erling Smørgrav } 1460ca007d91SDag-Erling Smørgrav 1461ca007d91SDag-Erling Smørgrav int 1462ca007d91SDag-Erling Smørgrav main(int argc, char *argv[]) 1463ca007d91SDag-Erling Smørgrav { 1464c5a2d8c5SRyan Moeller cap_channel_t *capcas; 1465c5a2d8c5SRyan Moeller cap_net_limit_t *limit; 14667ad30f58SMariusz Zaborski const char *pwdcmds[] = { "setpassent", "getpwuid" }; 14677ad30f58SMariusz Zaborski const char *pwdfields[] = { "pw_name" }; 14681f3d67aaSGiorgos Keramidas int protos_defined = -1; 14691f3d67aaSGiorgos Keramidas int o, i; 1470ca007d91SDag-Erling Smørgrav 147100feaafdSAndrew Thompson opt_j = -1; 1472*051a2132SMark Johnston while ((o = getopt(argc, argv, "46CcIij:Llnp:P:qSsUuvw")) != -1) 1473ca007d91SDag-Erling Smørgrav switch (o) { 1474ca007d91SDag-Erling Smørgrav case '4': 1475ca007d91SDag-Erling Smørgrav opt_4 = 1; 1476ca007d91SDag-Erling Smørgrav break; 1477ca007d91SDag-Erling Smørgrav case '6': 1478ca007d91SDag-Erling Smørgrav opt_6 = 1; 1479ca007d91SDag-Erling Smørgrav break; 14802ac089d0SMichael Tuexen case 'C': 14812ac089d0SMichael Tuexen opt_C = 1; 14822ac089d0SMichael Tuexen break; 1483ca007d91SDag-Erling Smørgrav case 'c': 1484ca007d91SDag-Erling Smørgrav opt_c = 1; 1485ca007d91SDag-Erling Smørgrav break; 1486*051a2132SMark Johnston case 'I': 1487*051a2132SMark Johnston opt_I = 1; 1488*051a2132SMark Johnston break; 14895f64777aSMichael Tuexen case 'i': 14905f64777aSMichael Tuexen opt_i = 1; 14915f64777aSMichael Tuexen break; 149200feaafdSAndrew Thompson case 'j': 1493de68a320SJamie Gritton opt_j = jail_getid(optarg); 1494de68a320SJamie Gritton if (opt_j < 0) 149532723a3bSGleb Smirnoff errx(1, "jail_getid: %s", jail_errmsg); 149600feaafdSAndrew Thompson break; 14979b6ca892SBruce M Simpson case 'L': 14989b6ca892SBruce M Simpson opt_L = 1; 14999b6ca892SBruce M Simpson break; 1500ca007d91SDag-Erling Smørgrav case 'l': 1501ca007d91SDag-Erling Smørgrav opt_l = 1; 1502ca007d91SDag-Erling Smørgrav break; 1503ccdd2b2bSAlexander Motin case 'n': 1504ccdd2b2bSAlexander Motin opt_n = 1; 1505ccdd2b2bSAlexander Motin break; 1506ca007d91SDag-Erling Smørgrav case 'p': 1507ca007d91SDag-Erling Smørgrav parse_ports(optarg); 1508ca007d91SDag-Erling Smørgrav break; 15091f3d67aaSGiorgos Keramidas case 'P': 15101f3d67aaSGiorgos Keramidas protos_defined = parse_protos(optarg); 15111f3d67aaSGiorgos Keramidas break; 1512ee0afaa9SEmmanuel Vadot case 'q': 1513ee0afaa9SEmmanuel Vadot opt_q = 1; 151462de7037SEmmanuel Vadot break; 1515e5cccc35SMichael Tuexen case 'S': 1516e5cccc35SMichael Tuexen opt_S = 1; 1517e5cccc35SMichael Tuexen break; 15187a5642b3SDag-Erling Smørgrav case 's': 15197a5642b3SDag-Erling Smørgrav opt_s = 1; 15207a5642b3SDag-Erling Smørgrav break; 152149b836f2SMichael Tuexen case 'U': 152249b836f2SMichael Tuexen opt_U = 1; 152349b836f2SMichael Tuexen break; 1524ca007d91SDag-Erling Smørgrav case 'u': 1525ca007d91SDag-Erling Smørgrav opt_u = 1; 1526ca007d91SDag-Erling Smørgrav break; 1527ca007d91SDag-Erling Smørgrav case 'v': 1528ca007d91SDag-Erling Smørgrav ++opt_v; 1529ca007d91SDag-Erling Smørgrav break; 153083f60cb2SMichael Tuexen case 'w': 153183f60cb2SMichael Tuexen opt_w = 1; 153283f60cb2SMichael Tuexen break; 1533ca007d91SDag-Erling Smørgrav default: 1534ca007d91SDag-Erling Smørgrav usage(); 1535ca007d91SDag-Erling Smørgrav } 1536ca007d91SDag-Erling Smørgrav 1537ca007d91SDag-Erling Smørgrav argc -= optind; 1538ca007d91SDag-Erling Smørgrav argv += optind; 1539ca007d91SDag-Erling Smørgrav 1540ca007d91SDag-Erling Smørgrav if (argc > 0) 1541ca007d91SDag-Erling Smørgrav usage(); 1542ca007d91SDag-Erling Smørgrav 1543f1cd4902SRyan Moeller if (opt_j > 0) { 1544f1cd4902SRyan Moeller switch (jail_getvnet(opt_j)) { 1545f1cd4902SRyan Moeller case -1: 154632723a3bSGleb Smirnoff errx(2, "jail_getvnet: %s", jail_errmsg); 1547f1cd4902SRyan Moeller case JAIL_SYS_NEW: 1548f1cd4902SRyan Moeller if (jail_attach(opt_j) < 0) 1549ae37905bSRyan Moeller err(3, "jail_attach()"); 1550f1cd4902SRyan Moeller /* Set back to -1 for normal output in vnet jail. */ 1551f1cd4902SRyan Moeller opt_j = -1; 1552f1cd4902SRyan Moeller break; 1553f1cd4902SRyan Moeller default: 1554f1cd4902SRyan Moeller break; 1555f1cd4902SRyan Moeller } 1556f1cd4902SRyan Moeller } 1557f1cd4902SRyan Moeller 1558c5a2d8c5SRyan Moeller capcas = cap_init(); 1559c5a2d8c5SRyan Moeller if (capcas == NULL) 1560c5a2d8c5SRyan Moeller err(1, "Unable to contact Casper"); 1561c5a2d8c5SRyan Moeller if (caph_enter_casper() < 0) 1562c5a2d8c5SRyan Moeller err(1, "Unable to enter capability mode"); 1563c5a2d8c5SRyan Moeller capnet = cap_service_open(capcas, "system.net"); 1564c5a2d8c5SRyan Moeller if (capnet == NULL) 1565c5a2d8c5SRyan Moeller err(1, "Unable to open system.net service"); 1566c5a2d8c5SRyan Moeller capnetdb = cap_service_open(capcas, "system.netdb"); 1567c5a2d8c5SRyan Moeller if (capnetdb == NULL) 1568c5a2d8c5SRyan Moeller err(1, "Unable to open system.netdb service"); 1569c5a2d8c5SRyan Moeller capsysctl = cap_service_open(capcas, "system.sysctl"); 1570c5a2d8c5SRyan Moeller if (capsysctl == NULL) 1571c5a2d8c5SRyan Moeller err(1, "Unable to open system.sysctl service"); 15727ad30f58SMariusz Zaborski cappwd = cap_service_open(capcas, "system.pwd"); 15737ad30f58SMariusz Zaborski if (cappwd == NULL) 15747ad30f58SMariusz Zaborski err(1, "Unable to open system.pwd service"); 1575c5a2d8c5SRyan Moeller cap_close(capcas); 1576c5a2d8c5SRyan Moeller limit = cap_net_limit_init(capnet, CAPNET_ADDR2NAME); 1577c5a2d8c5SRyan Moeller if (limit == NULL) 1578c5a2d8c5SRyan Moeller err(1, "Unable to init cap_net limits"); 1579c5a2d8c5SRyan Moeller if (cap_net_limit(limit) < 0) 1580c5a2d8c5SRyan Moeller err(1, "Unable to apply limits"); 15817ad30f58SMariusz Zaborski if (cap_pwd_limit_cmds(cappwd, pwdcmds, nitems(pwdcmds)) < 0) 15827ad30f58SMariusz Zaborski err(1, "Unable to apply pwd commands limits"); 15837ad30f58SMariusz Zaborski if (cap_pwd_limit_fields(cappwd, pwdfields, nitems(pwdfields)) < 0) 15847ad30f58SMariusz Zaborski err(1, "Unable to apply pwd commands limits"); 1585c5a2d8c5SRyan Moeller 1586d2d77d2aSGiorgos Keramidas if ((!opt_4 && !opt_6) && protos_defined != -1) 15871f3d67aaSGiorgos Keramidas opt_4 = opt_6 = 1; 1588d2d77d2aSGiorgos Keramidas if (!opt_4 && !opt_6 && !opt_u) 1589d2d77d2aSGiorgos Keramidas opt_4 = opt_6 = opt_u = 1; 1590d2d77d2aSGiorgos Keramidas if ((opt_4 || opt_6) && protos_defined == -1) 1591d2d77d2aSGiorgos Keramidas protos_defined = set_default_protos(); 1592ca007d91SDag-Erling Smørgrav if (!opt_c && !opt_l) 1593ca007d91SDag-Erling Smørgrav opt_c = opt_l = 1; 1594ca007d91SDag-Erling Smørgrav 1595ca007d91SDag-Erling Smørgrav if (opt_4 || opt_6) { 15961f3d67aaSGiorgos Keramidas for (i = 0; i < protos_defined; i++) 1597d5b4aa90SMichael Tuexen if (protos[i] == IPPROTO_SCTP) 1598d5b4aa90SMichael Tuexen gather_sctp(); 1599d5b4aa90SMichael Tuexen else 16001f3d67aaSGiorgos Keramidas gather_inet(protos[i]); 1601ca007d91SDag-Erling Smørgrav } 16021f3d67aaSGiorgos Keramidas 16031f3d67aaSGiorgos Keramidas if (opt_u || (protos_defined == -1 && !opt_4 && !opt_6)) { 1604ca007d91SDag-Erling Smørgrav gather_unix(SOCK_STREAM); 1605ca007d91SDag-Erling Smørgrav gather_unix(SOCK_DGRAM); 1606b8e20e2dSHiroki Sato gather_unix(SOCK_SEQPACKET); 1607ca007d91SDag-Erling Smørgrav } 1608ca007d91SDag-Erling Smørgrav getfiles(); 1609ca007d91SDag-Erling Smørgrav display(); 1610ca007d91SDag-Erling Smørgrav exit(0); 1611ca007d91SDag-Erling Smørgrav } 1612