1ca007d91SDag-Erling Smørgrav /*- 21de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 31de7b4b8SPedro F. Giffuni * 4fb2ad9d3SUlrich Spörlein * Copyright (c) 2002 Dag-Erling Coïdan 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/cdefs.h> 32ca007d91SDag-Erling Smørgrav __FBSDID("$FreeBSD$"); 33ca007d91SDag-Erling Smørgrav 34ca007d91SDag-Erling Smørgrav #include <sys/param.h> 35f1cd4902SRyan Moeller #include <sys/file.h> 36ca007d91SDag-Erling Smørgrav #include <sys/socket.h> 37ca007d91SDag-Erling Smørgrav #include <sys/socketvar.h> 38ca007d91SDag-Erling Smørgrav #include <sys/sysctl.h> 39f1cd4902SRyan Moeller #include <sys/jail.h> 40ca007d91SDag-Erling Smørgrav #include <sys/user.h> 41a83d596fSGleb Smirnoff #include <sys/queue.h> 42a83d596fSGleb Smirnoff #include <sys/tree.h> 43ca007d91SDag-Erling Smørgrav 44ca007d91SDag-Erling Smørgrav #include <sys/un.h> 45ca007d91SDag-Erling Smørgrav #include <sys/unpcb.h> 46ca007d91SDag-Erling Smørgrav 4702bd9db0SDag-Erling Smørgrav #include <net/route.h> 4802bd9db0SDag-Erling Smørgrav 49ca007d91SDag-Erling Smørgrav #include <netinet/in.h> 50ca007d91SDag-Erling Smørgrav #include <netinet/in_pcb.h> 51d5b4aa90SMichael Tuexen #include <netinet/sctp.h> 52ca007d91SDag-Erling Smørgrav #include <netinet/tcp.h> 537a5642b3SDag-Erling Smørgrav #define TCPSTATES /* load state names */ 547a5642b3SDag-Erling Smørgrav #include <netinet/tcp_fsm.h> 55ca007d91SDag-Erling Smørgrav #include <netinet/tcp_seq.h> 56ca007d91SDag-Erling Smørgrav #include <netinet/tcp_var.h> 57ca007d91SDag-Erling Smørgrav #include <arpa/inet.h> 58ca007d91SDag-Erling Smørgrav 59c5a2d8c5SRyan Moeller #include <capsicum_helpers.h> 60ca007d91SDag-Erling Smørgrav #include <ctype.h> 61ca007d91SDag-Erling Smørgrav #include <err.h> 62ca007d91SDag-Erling Smørgrav #include <errno.h> 635f64777aSMichael Tuexen #include <inttypes.h> 64de68a320SJamie Gritton #include <jail.h> 65ca007d91SDag-Erling Smørgrav #include <netdb.h> 66ca007d91SDag-Erling Smørgrav #include <pwd.h> 67ca007d91SDag-Erling Smørgrav #include <stdarg.h> 68ca007d91SDag-Erling Smørgrav #include <stdio.h> 69ca007d91SDag-Erling Smørgrav #include <stdlib.h> 70ca007d91SDag-Erling Smørgrav #include <string.h> 71ca007d91SDag-Erling Smørgrav #include <unistd.h> 72ca007d91SDag-Erling Smørgrav 73c5a2d8c5SRyan Moeller #include <libcasper.h> 74c5a2d8c5SRyan Moeller #include <casper/cap_net.h> 75c5a2d8c5SRyan Moeller #include <casper/cap_netdb.h> 767ad30f58SMariusz Zaborski #include <casper/cap_pwd.h> 77c5a2d8c5SRyan Moeller #include <casper/cap_sysctl.h> 78c5a2d8c5SRyan Moeller 79b8e20e2dSHiroki Sato #define sstosin(ss) ((struct sockaddr_in *)(ss)) 80b8e20e2dSHiroki Sato #define sstosin6(ss) ((struct sockaddr_in6 *)(ss)) 81b8e20e2dSHiroki Sato #define sstosun(ss) ((struct sockaddr_un *)(ss)) 82b8e20e2dSHiroki Sato #define sstosa(ss) ((struct sockaddr *)(ss)) 83b8e20e2dSHiroki Sato 84ca007d91SDag-Erling Smørgrav static int opt_4; /* Show IPv4 sockets */ 85ca007d91SDag-Erling Smørgrav static int opt_6; /* Show IPv6 sockets */ 862ac089d0SMichael Tuexen static int opt_C; /* Show congestion control */ 87ca007d91SDag-Erling Smørgrav static int opt_c; /* Show connected sockets */ 885f64777aSMichael Tuexen static int opt_i; /* Show inp_gencnt */ 8900feaafdSAndrew Thompson static int opt_j; /* Show specified jail */ 909b6ca892SBruce M Simpson static int opt_L; /* Don't show IPv4 or IPv6 loopback sockets */ 91ca007d91SDag-Erling Smørgrav static int opt_l; /* Show listening sockets */ 92ccdd2b2bSAlexander Motin static int opt_n; /* Don't resolve UIDs to user names */ 93ee0afaa9SEmmanuel Vadot static int opt_q; /* Don't show header */ 94e5cccc35SMichael Tuexen static int opt_S; /* Show protocol stack if applicable */ 957a5642b3SDag-Erling Smørgrav static int opt_s; /* Show protocol state if applicable */ 9649b836f2SMichael Tuexen static int opt_U; /* Show remote UDP encapsulation port number */ 97ca007d91SDag-Erling Smørgrav static int opt_u; /* Show Unix domain sockets */ 98ca007d91SDag-Erling Smørgrav static int opt_v; /* Verbose mode */ 9983f60cb2SMichael Tuexen static int opt_w; /* Wide print area for addresses */ 100ca007d91SDag-Erling Smørgrav 1011f3d67aaSGiorgos Keramidas /* 1021f3d67aaSGiorgos Keramidas * Default protocols to use if no -P was defined. 1031f3d67aaSGiorgos Keramidas */ 104d5b4aa90SMichael Tuexen static const char *default_protos[] = {"sctp", "tcp", "udp", "divert" }; 105b8e20e2dSHiroki Sato static size_t default_numprotos = nitems(default_protos); 1061f3d67aaSGiorgos Keramidas 1071f3d67aaSGiorgos Keramidas static int *protos; /* protocols to use */ 1081f3d67aaSGiorgos Keramidas static size_t numprotos; /* allocated size of protos[] */ 1091f3d67aaSGiorgos Keramidas 110ca007d91SDag-Erling Smørgrav static int *ports; 111ca007d91SDag-Erling Smørgrav 112ca007d91SDag-Erling Smørgrav #define INT_BIT (sizeof(int)*CHAR_BIT) 113ca007d91SDag-Erling Smørgrav #define SET_PORT(p) do { ports[p / INT_BIT] |= 1 << (p % INT_BIT); } while (0) 114ca007d91SDag-Erling Smørgrav #define CHK_PORT(p) (ports[p / INT_BIT] & (1 << (p % INT_BIT))) 115ca007d91SDag-Erling Smørgrav 116e6f718c7SMichael Tuexen struct addr { 117*2c436d48SGleb Smirnoff union { 118e6f718c7SMichael Tuexen struct sockaddr_storage address; 119*2c436d48SGleb Smirnoff struct { /* unix(4) faddr */ 120*2c436d48SGleb Smirnoff kvaddr_t conn; 121*2c436d48SGleb Smirnoff kvaddr_t firstref; 122*2c436d48SGleb Smirnoff kvaddr_t nextref; 123*2c436d48SGleb Smirnoff }; 124*2c436d48SGleb Smirnoff }; 12549b836f2SMichael Tuexen unsigned int encaps_port; 126e389705eSMichael Tuexen int state; 127e6f718c7SMichael Tuexen struct addr *next; 128e6f718c7SMichael Tuexen }; 129e6f718c7SMichael Tuexen 130ca007d91SDag-Erling Smørgrav struct sock { 131a83d596fSGleb Smirnoff union { 132a83d596fSGleb Smirnoff RB_ENTRY(sock) socket_tree; /* tree of pcbs with socket */ 133a83d596fSGleb Smirnoff SLIST_ENTRY(sock) socket_list; /* list of pcbs w/o socket */ 134a83d596fSGleb Smirnoff }; 135a83d596fSGleb Smirnoff RB_ENTRY(sock) pcb_tree; 136f38b68aeSBrooks Davis kvaddr_t socket; 137f38b68aeSBrooks Davis kvaddr_t pcb; 1385f64777aSMichael Tuexen uint64_t inp_gencnt; 13961149f8dSJilles Tjoelker int shown; 140ca007d91SDag-Erling Smørgrav int vflag; 141ca007d91SDag-Erling Smørgrav int family; 142ca007d91SDag-Erling Smørgrav int proto; 1437a5642b3SDag-Erling Smørgrav int state; 144ca007d91SDag-Erling Smørgrav const char *protoname; 145e5cccc35SMichael Tuexen char stack[TCP_FUNCTION_NAME_LEN_MAX]; 1462ac089d0SMichael Tuexen char cc[TCP_CA_NAME_MAX]; 147e6f718c7SMichael Tuexen struct addr *laddr; 148e6f718c7SMichael Tuexen struct addr *faddr; 149ca007d91SDag-Erling Smørgrav }; 150ca007d91SDag-Erling Smørgrav 151a83d596fSGleb Smirnoff static RB_HEAD(socks_t, sock) socks = RB_INITIALIZER(&socks); 152a83d596fSGleb Smirnoff static int64_t 153a83d596fSGleb Smirnoff socket_compare(const struct sock *a, const struct sock *b) 154a83d596fSGleb Smirnoff { 155a83d596fSGleb Smirnoff return ((int64_t)(a->socket/2 - b->socket/2)); 156a83d596fSGleb Smirnoff } 157a83d596fSGleb Smirnoff RB_GENERATE_STATIC(socks_t, sock, socket_tree, socket_compare); 158a83d596fSGleb Smirnoff 159a83d596fSGleb Smirnoff static RB_HEAD(pcbs_t, sock) pcbs = RB_INITIALIZER(&pcbs); 160a83d596fSGleb Smirnoff static int64_t 161a83d596fSGleb Smirnoff pcb_compare(const struct sock *a, const struct sock *b) 162a83d596fSGleb Smirnoff { 163a83d596fSGleb Smirnoff return ((int64_t)(a->pcb/2 - b->pcb/2)); 164a83d596fSGleb Smirnoff } 165a83d596fSGleb Smirnoff RB_GENERATE_STATIC(pcbs_t, sock, pcb_tree, pcb_compare); 166a83d596fSGleb Smirnoff 167a83d596fSGleb Smirnoff static SLIST_HEAD(, sock) nosocks = SLIST_HEAD_INITIALIZER(&nosocks); 168ca007d91SDag-Erling Smørgrav 169*2c436d48SGleb Smirnoff struct file { 170*2c436d48SGleb Smirnoff RB_ENTRY(file) file_tree; 171*2c436d48SGleb Smirnoff kvaddr_t xf_data; 172*2c436d48SGleb Smirnoff pid_t xf_pid; 173*2c436d48SGleb Smirnoff uid_t xf_uid; 174*2c436d48SGleb Smirnoff int xf_fd; 175*2c436d48SGleb Smirnoff }; 176*2c436d48SGleb Smirnoff 177*2c436d48SGleb Smirnoff static RB_HEAD(files_t, file) ftree = RB_INITIALIZER(&ftree); 178*2c436d48SGleb Smirnoff static int64_t 179*2c436d48SGleb Smirnoff file_compare(const struct file *a, const struct file *b) 180*2c436d48SGleb Smirnoff { 181*2c436d48SGleb Smirnoff return ((int64_t)(a->xf_data/2 - b->xf_data/2)); 182*2c436d48SGleb Smirnoff } 183*2c436d48SGleb Smirnoff RB_GENERATE_STATIC(files_t, file, file_tree, file_compare); 184*2c436d48SGleb Smirnoff 185*2c436d48SGleb Smirnoff static struct file *files; 186*2c436d48SGleb Smirnoff static int nfiles; 187ca007d91SDag-Erling Smørgrav 188c5a2d8c5SRyan Moeller static cap_channel_t *capnet; 189c5a2d8c5SRyan Moeller static cap_channel_t *capnetdb; 190c5a2d8c5SRyan Moeller static cap_channel_t *capsysctl; 1917ad30f58SMariusz Zaborski static cap_channel_t *cappwd; 192c5a2d8c5SRyan Moeller 193ca007d91SDag-Erling Smørgrav static int 194ca007d91SDag-Erling Smørgrav xprintf(const char *fmt, ...) 195ca007d91SDag-Erling Smørgrav { 196ca007d91SDag-Erling Smørgrav va_list ap; 197ca007d91SDag-Erling Smørgrav int len; 198ca007d91SDag-Erling Smørgrav 199ca007d91SDag-Erling Smørgrav va_start(ap, fmt); 200ca007d91SDag-Erling Smørgrav len = vprintf(fmt, ap); 201ca007d91SDag-Erling Smørgrav va_end(ap); 202ca007d91SDag-Erling Smørgrav if (len < 0) 203ca007d91SDag-Erling Smørgrav err(1, "printf()"); 204ca007d91SDag-Erling Smørgrav return (len); 205ca007d91SDag-Erling Smørgrav } 206ca007d91SDag-Erling Smørgrav 20708e77283SAlexander V. Chernikov static bool 20808e77283SAlexander V. Chernikov _check_ksize(size_t received_size, size_t expected_size, const char *struct_name) 20908e77283SAlexander V. Chernikov { 21008e77283SAlexander V. Chernikov if (received_size != expected_size) { 21108e77283SAlexander V. Chernikov warnx("%s size mismatch: expected %zd, received %zd", 21208e77283SAlexander V. Chernikov struct_name, expected_size, received_size); 21308e77283SAlexander V. Chernikov return false; 21408e77283SAlexander V. Chernikov } 21508e77283SAlexander V. Chernikov return true; 21608e77283SAlexander V. Chernikov } 21708e77283SAlexander V. Chernikov #define check_ksize(_sz, _struct) (_check_ksize(_sz, sizeof(_struct), #_struct)) 21808e77283SAlexander V. Chernikov 21908e77283SAlexander V. Chernikov static void 22008e77283SAlexander V. Chernikov _enforce_ksize(size_t received_size, size_t expected_size, const char *struct_name) 22108e77283SAlexander V. Chernikov { 22208e77283SAlexander V. Chernikov if (received_size != expected_size) { 22308e77283SAlexander V. Chernikov errx(1, "fatal: struct %s size mismatch: expected %zd, received %zd", 22408e77283SAlexander V. Chernikov struct_name, expected_size, received_size); 22508e77283SAlexander V. Chernikov } 22608e77283SAlexander V. Chernikov } 22708e77283SAlexander V. Chernikov #define enforce_ksize(_sz, _struct) (_enforce_ksize(_sz, sizeof(_struct), #_struct)) 22808e77283SAlexander V. Chernikov 2291f3d67aaSGiorgos Keramidas static int 2301f3d67aaSGiorgos Keramidas get_proto_type(const char *proto) 2311f3d67aaSGiorgos Keramidas { 2321f3d67aaSGiorgos Keramidas struct protoent *pent; 2331f3d67aaSGiorgos Keramidas 2341f3d67aaSGiorgos Keramidas if (strlen(proto) == 0) 2351f3d67aaSGiorgos Keramidas return (0); 236bfb5947bSMariusz Zaborski if (capnetdb != NULL) 237c5a2d8c5SRyan Moeller pent = cap_getprotobyname(capnetdb, proto); 238bfb5947bSMariusz Zaborski else 239bfb5947bSMariusz Zaborski pent = getprotobyname(proto); 2401f3d67aaSGiorgos Keramidas if (pent == NULL) { 241c5a2d8c5SRyan Moeller warn("cap_getprotobyname"); 2421f3d67aaSGiorgos Keramidas return (-1); 2431f3d67aaSGiorgos Keramidas } 2441f3d67aaSGiorgos Keramidas return (pent->p_proto); 2451f3d67aaSGiorgos Keramidas } 2461f3d67aaSGiorgos Keramidas 247b8e20e2dSHiroki Sato static void 248b8e20e2dSHiroki Sato init_protos(int num) 2491f3d67aaSGiorgos Keramidas { 2501f3d67aaSGiorgos Keramidas int proto_count = 0; 2511f3d67aaSGiorgos Keramidas 2521f3d67aaSGiorgos Keramidas if (num > 0) { 2531f3d67aaSGiorgos Keramidas proto_count = num; 2541f3d67aaSGiorgos Keramidas } else { 2551f3d67aaSGiorgos Keramidas /* Find the maximum number of possible protocols. */ 2561f3d67aaSGiorgos Keramidas while (getprotoent() != NULL) 2571f3d67aaSGiorgos Keramidas proto_count++; 2581f3d67aaSGiorgos Keramidas endprotoent(); 2591f3d67aaSGiorgos Keramidas } 2601f3d67aaSGiorgos Keramidas 2611f3d67aaSGiorgos Keramidas if ((protos = malloc(sizeof(int) * proto_count)) == NULL) 2621f3d67aaSGiorgos Keramidas err(1, "malloc"); 2631f3d67aaSGiorgos Keramidas numprotos = proto_count; 2641f3d67aaSGiorgos Keramidas } 2651f3d67aaSGiorgos Keramidas 2661f3d67aaSGiorgos Keramidas static int 2671f3d67aaSGiorgos Keramidas parse_protos(char *protospec) 2681f3d67aaSGiorgos Keramidas { 2691f3d67aaSGiorgos Keramidas char *prot; 2701f3d67aaSGiorgos Keramidas int proto_type, proto_index; 2711f3d67aaSGiorgos Keramidas 2721f3d67aaSGiorgos Keramidas if (protospec == NULL) 2731f3d67aaSGiorgos Keramidas return (-1); 2741f3d67aaSGiorgos Keramidas 2751f3d67aaSGiorgos Keramidas init_protos(0); 2761f3d67aaSGiorgos Keramidas proto_index = 0; 277b8e20e2dSHiroki Sato while ((prot = strsep(&protospec, ",")) != NULL) { 2781f3d67aaSGiorgos Keramidas if (strlen(prot) == 0) 2791f3d67aaSGiorgos Keramidas continue; 2801f3d67aaSGiorgos Keramidas proto_type = get_proto_type(prot); 2811f3d67aaSGiorgos Keramidas if (proto_type != -1) 2821f3d67aaSGiorgos Keramidas protos[proto_index++] = proto_type; 2831f3d67aaSGiorgos Keramidas } 2841f3d67aaSGiorgos Keramidas numprotos = proto_index; 2851f3d67aaSGiorgos Keramidas return (proto_index); 2861f3d67aaSGiorgos Keramidas } 2871f3d67aaSGiorgos Keramidas 288ca007d91SDag-Erling Smørgrav static void 289ca007d91SDag-Erling Smørgrav parse_ports(const char *portspec) 290ca007d91SDag-Erling Smørgrav { 291ca007d91SDag-Erling Smørgrav const char *p, *q; 292ca007d91SDag-Erling Smørgrav int port, end; 293ca007d91SDag-Erling Smørgrav 294ca007d91SDag-Erling Smørgrav if (ports == NULL) 2959efed1e6SRobert Drehmel if ((ports = calloc(65536 / INT_BIT, sizeof(int))) == NULL) 296ca007d91SDag-Erling Smørgrav err(1, "calloc()"); 297ca007d91SDag-Erling Smørgrav p = portspec; 298ca007d91SDag-Erling Smørgrav while (*p != '\0') { 299ca007d91SDag-Erling Smørgrav if (!isdigit(*p)) 300ca007d91SDag-Erling Smørgrav errx(1, "syntax error in port range"); 301ca007d91SDag-Erling Smørgrav for (q = p; *q != '\0' && isdigit(*q); ++q) 302ca007d91SDag-Erling Smørgrav /* nothing */ ; 303ca007d91SDag-Erling Smørgrav for (port = 0; p < q; ++p) 304ca007d91SDag-Erling Smørgrav port = port * 10 + digittoint(*p); 305ca007d91SDag-Erling Smørgrav if (port < 0 || port > 65535) 306ca007d91SDag-Erling Smørgrav errx(1, "invalid port number"); 307ca007d91SDag-Erling Smørgrav SET_PORT(port); 308ca007d91SDag-Erling Smørgrav switch (*p) { 309ca007d91SDag-Erling Smørgrav case '-': 310ca007d91SDag-Erling Smørgrav ++p; 311ca007d91SDag-Erling Smørgrav break; 312ca007d91SDag-Erling Smørgrav case ',': 313ca007d91SDag-Erling Smørgrav ++p; 314ca007d91SDag-Erling Smørgrav /* fall through */ 315ca007d91SDag-Erling Smørgrav case '\0': 316ca007d91SDag-Erling Smørgrav default: 317ca007d91SDag-Erling Smørgrav continue; 318ca007d91SDag-Erling Smørgrav } 319ca007d91SDag-Erling Smørgrav for (q = p; *q != '\0' && isdigit(*q); ++q) 320ca007d91SDag-Erling Smørgrav /* nothing */ ; 321ca007d91SDag-Erling Smørgrav for (end = 0; p < q; ++p) 322ca007d91SDag-Erling Smørgrav end = end * 10 + digittoint(*p); 323ca007d91SDag-Erling Smørgrav if (end < port || end > 65535) 324ca007d91SDag-Erling Smørgrav errx(1, "invalid port number"); 325ca007d91SDag-Erling Smørgrav while (port++ < end) 326ca007d91SDag-Erling Smørgrav SET_PORT(port); 327ca007d91SDag-Erling Smørgrav if (*p == ',') 328ca007d91SDag-Erling Smørgrav ++p; 329ca007d91SDag-Erling Smørgrav } 330ca007d91SDag-Erling Smørgrav } 331ca007d91SDag-Erling Smørgrav 332ca007d91SDag-Erling Smørgrav static void 333b8e20e2dSHiroki Sato sockaddr(struct sockaddr_storage *ss, int af, void *addr, int port) 334ca007d91SDag-Erling Smørgrav { 335ca007d91SDag-Erling Smørgrav struct sockaddr_in *sin4; 336ca007d91SDag-Erling Smørgrav struct sockaddr_in6 *sin6; 337ca007d91SDag-Erling Smørgrav 338b8e20e2dSHiroki Sato bzero(ss, sizeof(*ss)); 339ca007d91SDag-Erling Smørgrav switch (af) { 340ca007d91SDag-Erling Smørgrav case AF_INET: 341b8e20e2dSHiroki Sato sin4 = sstosin(ss); 342b8e20e2dSHiroki Sato sin4->sin_len = sizeof(*sin4); 343ca007d91SDag-Erling Smørgrav sin4->sin_family = af; 344ca007d91SDag-Erling Smørgrav sin4->sin_port = port; 345ca007d91SDag-Erling Smørgrav sin4->sin_addr = *(struct in_addr *)addr; 346ca007d91SDag-Erling Smørgrav break; 347ca007d91SDag-Erling Smørgrav case AF_INET6: 348b8e20e2dSHiroki Sato sin6 = sstosin6(ss); 349b8e20e2dSHiroki Sato sin6->sin6_len = sizeof(*sin6); 350ca007d91SDag-Erling Smørgrav sin6->sin6_family = af; 351ca007d91SDag-Erling Smørgrav sin6->sin6_port = port; 352ca007d91SDag-Erling Smørgrav sin6->sin6_addr = *(struct in6_addr *)addr; 353b8e20e2dSHiroki Sato #define s6_addr16 __u6_addr.__u6_addr16 354b8e20e2dSHiroki Sato if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 355b8e20e2dSHiroki Sato sin6->sin6_scope_id = 356b8e20e2dSHiroki Sato ntohs(sin6->sin6_addr.s6_addr16[1]); 357b8e20e2dSHiroki Sato sin6->sin6_addr.s6_addr16[1] = 0; 358b8e20e2dSHiroki Sato } 359ca007d91SDag-Erling Smørgrav break; 360ca007d91SDag-Erling Smørgrav default: 361ca007d91SDag-Erling Smørgrav abort(); 362ca007d91SDag-Erling Smørgrav } 363ca007d91SDag-Erling Smørgrav } 364ca007d91SDag-Erling Smørgrav 365ca007d91SDag-Erling Smørgrav static void 366bedcf91dSMichael Tuexen free_socket(struct sock *sock) 367bedcf91dSMichael Tuexen { 368bedcf91dSMichael Tuexen struct addr *cur, *next; 369bedcf91dSMichael Tuexen 370bedcf91dSMichael Tuexen cur = sock->laddr; 371bedcf91dSMichael Tuexen while (cur != NULL) { 372bedcf91dSMichael Tuexen next = cur->next; 373bedcf91dSMichael Tuexen free(cur); 374bedcf91dSMichael Tuexen cur = next; 375bedcf91dSMichael Tuexen } 376bedcf91dSMichael Tuexen cur = sock->faddr; 377bedcf91dSMichael Tuexen while (cur != NULL) { 378bedcf91dSMichael Tuexen next = cur->next; 379bedcf91dSMichael Tuexen free(cur); 380bedcf91dSMichael Tuexen cur = next; 381bedcf91dSMichael Tuexen } 382bedcf91dSMichael Tuexen free(sock); 383bedcf91dSMichael Tuexen } 384bedcf91dSMichael Tuexen 385bedcf91dSMichael Tuexen static void 386d5b4aa90SMichael Tuexen gather_sctp(void) 387d5b4aa90SMichael Tuexen { 388d5b4aa90SMichael Tuexen struct sock *sock; 389d5b4aa90SMichael Tuexen struct addr *laddr, *prev_laddr, *faddr, *prev_faddr; 390d5b4aa90SMichael Tuexen struct xsctp_inpcb *xinpcb; 391d5b4aa90SMichael Tuexen struct xsctp_tcb *xstcb; 392d5b4aa90SMichael Tuexen struct xsctp_raddr *xraddr; 393d5b4aa90SMichael Tuexen struct xsctp_laddr *xladdr; 394d5b4aa90SMichael Tuexen const char *varname; 395d5b4aa90SMichael Tuexen size_t len, offset; 396d5b4aa90SMichael Tuexen char *buf; 397a83d596fSGleb Smirnoff int vflag; 398d5b4aa90SMichael Tuexen int no_stcb, local_all_loopback, foreign_all_loopback; 399d5b4aa90SMichael Tuexen 400d5b4aa90SMichael Tuexen vflag = 0; 401d5b4aa90SMichael Tuexen if (opt_4) 402d5b4aa90SMichael Tuexen vflag |= INP_IPV4; 403d5b4aa90SMichael Tuexen if (opt_6) 404d5b4aa90SMichael Tuexen vflag |= INP_IPV6; 405d5b4aa90SMichael Tuexen 406d5b4aa90SMichael Tuexen varname = "net.inet.sctp.assoclist"; 407c5a2d8c5SRyan Moeller if (cap_sysctlbyname(capsysctl, varname, 0, &len, 0, 0) < 0) { 408d5b4aa90SMichael Tuexen if (errno != ENOENT) 409c5a2d8c5SRyan Moeller err(1, "cap_sysctlbyname()"); 410d5b4aa90SMichael Tuexen return; 411d5b4aa90SMichael Tuexen } 412d5b4aa90SMichael Tuexen if ((buf = (char *)malloc(len)) == NULL) { 413d5b4aa90SMichael Tuexen err(1, "malloc()"); 414d5b4aa90SMichael Tuexen return; 415d5b4aa90SMichael Tuexen } 416c5a2d8c5SRyan Moeller if (cap_sysctlbyname(capsysctl, varname, buf, &len, 0, 0) < 0) { 417c5a2d8c5SRyan Moeller err(1, "cap_sysctlbyname()"); 418d5b4aa90SMichael Tuexen free(buf); 419d5b4aa90SMichael Tuexen return; 420d5b4aa90SMichael Tuexen } 421d5b4aa90SMichael Tuexen xinpcb = (struct xsctp_inpcb *)(void *)buf; 422d5b4aa90SMichael Tuexen offset = sizeof(struct xsctp_inpcb); 423d5b4aa90SMichael Tuexen while ((offset < len) && (xinpcb->last == 0)) { 424d5b4aa90SMichael Tuexen if ((sock = calloc(1, sizeof *sock)) == NULL) 425d5b4aa90SMichael Tuexen err(1, "malloc()"); 426d5b4aa90SMichael Tuexen sock->socket = xinpcb->socket; 427d5b4aa90SMichael Tuexen sock->proto = IPPROTO_SCTP; 428d5b4aa90SMichael Tuexen sock->protoname = "sctp"; 429c1eb13c7SMichael Tuexen if (xinpcb->maxqlen == 0) 4306414db1bSMichael Tuexen sock->state = SCTP_CLOSED; 4316414db1bSMichael Tuexen else 4326414db1bSMichael Tuexen sock->state = SCTP_LISTEN; 433d5b4aa90SMichael Tuexen if (xinpcb->flags & SCTP_PCB_FLAGS_BOUND_V6) { 434d5b4aa90SMichael Tuexen sock->family = AF_INET6; 435edc9c7fcSMichael Tuexen /* 436edc9c7fcSMichael Tuexen * Currently there is no way to distinguish between 437edc9c7fcSMichael Tuexen * IPv6 only sockets or dual family sockets. 438edc9c7fcSMichael Tuexen * So mark it as dual socket. 439edc9c7fcSMichael Tuexen */ 440edc9c7fcSMichael Tuexen sock->vflag = INP_IPV6 | INP_IPV4; 441d5b4aa90SMichael Tuexen } else { 442d5b4aa90SMichael Tuexen sock->family = AF_INET; 443d5b4aa90SMichael Tuexen sock->vflag = INP_IPV4; 444d5b4aa90SMichael Tuexen } 445d5b4aa90SMichael Tuexen prev_laddr = NULL; 446d5b4aa90SMichael Tuexen local_all_loopback = 1; 447d5b4aa90SMichael Tuexen while (offset < len) { 448d5b4aa90SMichael Tuexen xladdr = (struct xsctp_laddr *)(void *)(buf + offset); 449d5b4aa90SMichael Tuexen offset += sizeof(struct xsctp_laddr); 450d5b4aa90SMichael Tuexen if (xladdr->last == 1) 451d5b4aa90SMichael Tuexen break; 452d5b4aa90SMichael Tuexen if ((laddr = calloc(1, sizeof(struct addr))) == NULL) 453d5b4aa90SMichael Tuexen err(1, "malloc()"); 454d5b4aa90SMichael Tuexen switch (xladdr->address.sa.sa_family) { 455d5b4aa90SMichael Tuexen case AF_INET: 456d5b4aa90SMichael Tuexen #define __IN_IS_ADDR_LOOPBACK(pina) \ 457d5b4aa90SMichael Tuexen ((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) 45827569d01SRenato Botelho if (!__IN_IS_ADDR_LOOPBACK( 45927569d01SRenato Botelho &xladdr->address.sin.sin_addr)) 460d5b4aa90SMichael Tuexen local_all_loopback = 0; 461d5b4aa90SMichael Tuexen #undef __IN_IS_ADDR_LOOPBACK 46227569d01SRenato Botelho sockaddr(&laddr->address, AF_INET, 463d5b4aa90SMichael Tuexen &xladdr->address.sin.sin_addr, 464d5b4aa90SMichael Tuexen htons(xinpcb->local_port)); 465d5b4aa90SMichael Tuexen break; 466d5b4aa90SMichael Tuexen case AF_INET6: 46727569d01SRenato Botelho if (!IN6_IS_ADDR_LOOPBACK( 46827569d01SRenato Botelho &xladdr->address.sin6.sin6_addr)) 469d5b4aa90SMichael Tuexen local_all_loopback = 0; 47027569d01SRenato Botelho sockaddr(&laddr->address, AF_INET6, 471d5b4aa90SMichael Tuexen &xladdr->address.sin6.sin6_addr, 472d5b4aa90SMichael Tuexen htons(xinpcb->local_port)); 473d5b4aa90SMichael Tuexen break; 474d5b4aa90SMichael Tuexen default: 475463a577bSEitan Adler errx(1, "address family %d not supported", 476d5b4aa90SMichael Tuexen xladdr->address.sa.sa_family); 477d5b4aa90SMichael Tuexen } 478d5b4aa90SMichael Tuexen laddr->next = NULL; 479d5b4aa90SMichael Tuexen if (prev_laddr == NULL) 480d5b4aa90SMichael Tuexen sock->laddr = laddr; 481d5b4aa90SMichael Tuexen else 482d5b4aa90SMichael Tuexen prev_laddr->next = laddr; 483d5b4aa90SMichael Tuexen prev_laddr = laddr; 484d5b4aa90SMichael Tuexen } 485d5b4aa90SMichael Tuexen if (sock->laddr == NULL) { 48627569d01SRenato Botelho if ((sock->laddr = 48727569d01SRenato Botelho calloc(1, sizeof(struct addr))) == NULL) 488d5b4aa90SMichael Tuexen err(1, "malloc()"); 489d5b4aa90SMichael Tuexen sock->laddr->address.ss_family = sock->family; 490d5b4aa90SMichael Tuexen if (sock->family == AF_INET) 49127569d01SRenato Botelho sock->laddr->address.ss_len = 49227569d01SRenato Botelho sizeof(struct sockaddr_in); 493d5b4aa90SMichael Tuexen else 49427569d01SRenato Botelho sock->laddr->address.ss_len = 49527569d01SRenato Botelho sizeof(struct sockaddr_in6); 496d5b4aa90SMichael Tuexen local_all_loopback = 0; 497d5b4aa90SMichael Tuexen } 498d5b4aa90SMichael Tuexen if ((sock->faddr = calloc(1, sizeof(struct addr))) == NULL) 499d5b4aa90SMichael Tuexen err(1, "malloc()"); 500d5b4aa90SMichael Tuexen sock->faddr->address.ss_family = sock->family; 501d5b4aa90SMichael Tuexen if (sock->family == AF_INET) 50227569d01SRenato Botelho sock->faddr->address.ss_len = 50327569d01SRenato Botelho sizeof(struct sockaddr_in); 504d5b4aa90SMichael Tuexen else 50527569d01SRenato Botelho sock->faddr->address.ss_len = 50627569d01SRenato Botelho sizeof(struct sockaddr_in6); 507d5b4aa90SMichael Tuexen no_stcb = 1; 508d5b4aa90SMichael Tuexen while (offset < len) { 509d5b4aa90SMichael Tuexen xstcb = (struct xsctp_tcb *)(void *)(buf + offset); 510d5b4aa90SMichael Tuexen offset += sizeof(struct xsctp_tcb); 511bedcf91dSMichael Tuexen if (no_stcb) { 51227569d01SRenato Botelho if (opt_l && (sock->vflag & vflag) && 513d5b4aa90SMichael Tuexen (!opt_L || !local_all_loopback) && 514d5b4aa90SMichael Tuexen ((xinpcb->flags & SCTP_PCB_FLAGS_UDPTYPE) || 515d5b4aa90SMichael Tuexen (xstcb->last == 1))) { 516a83d596fSGleb Smirnoff RB_INSERT(socks_t, &socks, sock); 517bedcf91dSMichael Tuexen } else { 518bedcf91dSMichael Tuexen free_socket(sock); 519bedcf91dSMichael Tuexen } 520d5b4aa90SMichael Tuexen } 521d5b4aa90SMichael Tuexen if (xstcb->last == 1) 522d5b4aa90SMichael Tuexen break; 523d5b4aa90SMichael Tuexen no_stcb = 0; 524d5b4aa90SMichael Tuexen if (opt_c) { 525d5b4aa90SMichael Tuexen if ((sock = calloc(1, sizeof *sock)) == NULL) 526d5b4aa90SMichael Tuexen err(1, "malloc()"); 527d5b4aa90SMichael Tuexen sock->socket = xinpcb->socket; 528d5b4aa90SMichael Tuexen sock->proto = IPPROTO_SCTP; 529d5b4aa90SMichael Tuexen sock->protoname = "sctp"; 5306414db1bSMichael Tuexen sock->state = (int)xstcb->state; 531d5b4aa90SMichael Tuexen if (xinpcb->flags & SCTP_PCB_FLAGS_BOUND_V6) { 532d5b4aa90SMichael Tuexen sock->family = AF_INET6; 533edc9c7fcSMichael Tuexen /* 534edc9c7fcSMichael Tuexen * Currently there is no way to distinguish 535edc9c7fcSMichael Tuexen * between IPv6 only sockets or dual family 536edc9c7fcSMichael Tuexen * sockets. So mark it as dual socket. 537edc9c7fcSMichael Tuexen */ 538edc9c7fcSMichael Tuexen sock->vflag = INP_IPV6 | INP_IPV4; 539d5b4aa90SMichael Tuexen } else { 540d5b4aa90SMichael Tuexen sock->family = AF_INET; 541d5b4aa90SMichael Tuexen sock->vflag = INP_IPV4; 542d5b4aa90SMichael Tuexen } 543d5b4aa90SMichael Tuexen } 544d5b4aa90SMichael Tuexen prev_laddr = NULL; 545d5b4aa90SMichael Tuexen local_all_loopback = 1; 546d5b4aa90SMichael Tuexen while (offset < len) { 54727569d01SRenato Botelho xladdr = (struct xsctp_laddr *)(void *)(buf + 54827569d01SRenato Botelho offset); 549d5b4aa90SMichael Tuexen offset += sizeof(struct xsctp_laddr); 550d5b4aa90SMichael Tuexen if (xladdr->last == 1) 551d5b4aa90SMichael Tuexen break; 552d5b4aa90SMichael Tuexen if (!opt_c) 553d5b4aa90SMichael Tuexen continue; 55427569d01SRenato Botelho laddr = calloc(1, sizeof(struct addr)); 55527569d01SRenato Botelho if (laddr == NULL) 556d5b4aa90SMichael Tuexen err(1, "malloc()"); 557d5b4aa90SMichael Tuexen switch (xladdr->address.sa.sa_family) { 558d5b4aa90SMichael Tuexen case AF_INET: 559d5b4aa90SMichael Tuexen #define __IN_IS_ADDR_LOOPBACK(pina) \ 560d5b4aa90SMichael Tuexen ((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) 56127569d01SRenato Botelho if (!__IN_IS_ADDR_LOOPBACK( 56227569d01SRenato Botelho &xladdr->address.sin.sin_addr)) 563d5b4aa90SMichael Tuexen local_all_loopback = 0; 564d5b4aa90SMichael Tuexen #undef __IN_IS_ADDR_LOOPBACK 56527569d01SRenato Botelho sockaddr(&laddr->address, AF_INET, 566d5b4aa90SMichael Tuexen &xladdr->address.sin.sin_addr, 567d5b4aa90SMichael Tuexen htons(xstcb->local_port)); 568d5b4aa90SMichael Tuexen break; 569d5b4aa90SMichael Tuexen case AF_INET6: 57027569d01SRenato Botelho if (!IN6_IS_ADDR_LOOPBACK( 57127569d01SRenato Botelho &xladdr->address.sin6.sin6_addr)) 572d5b4aa90SMichael Tuexen local_all_loopback = 0; 57327569d01SRenato Botelho sockaddr(&laddr->address, AF_INET6, 574d5b4aa90SMichael Tuexen &xladdr->address.sin6.sin6_addr, 575d5b4aa90SMichael Tuexen htons(xstcb->local_port)); 576d5b4aa90SMichael Tuexen break; 577d5b4aa90SMichael Tuexen default: 57827569d01SRenato Botelho errx(1, 57927569d01SRenato Botelho "address family %d not supported", 580d5b4aa90SMichael Tuexen xladdr->address.sa.sa_family); 581d5b4aa90SMichael Tuexen } 582d5b4aa90SMichael Tuexen laddr->next = NULL; 583d5b4aa90SMichael Tuexen if (prev_laddr == NULL) 584d5b4aa90SMichael Tuexen sock->laddr = laddr; 585d5b4aa90SMichael Tuexen else 586d5b4aa90SMichael Tuexen prev_laddr->next = laddr; 587d5b4aa90SMichael Tuexen prev_laddr = laddr; 588d5b4aa90SMichael Tuexen } 589d5b4aa90SMichael Tuexen prev_faddr = NULL; 590d5b4aa90SMichael Tuexen foreign_all_loopback = 1; 591d5b4aa90SMichael Tuexen while (offset < len) { 59227569d01SRenato Botelho xraddr = (struct xsctp_raddr *)(void *)(buf + 59327569d01SRenato Botelho offset); 594d5b4aa90SMichael Tuexen offset += sizeof(struct xsctp_raddr); 595d5b4aa90SMichael Tuexen if (xraddr->last == 1) 596d5b4aa90SMichael Tuexen break; 597d5b4aa90SMichael Tuexen if (!opt_c) 598d5b4aa90SMichael Tuexen continue; 59927569d01SRenato Botelho faddr = calloc(1, sizeof(struct addr)); 60027569d01SRenato Botelho if (faddr == NULL) 601d5b4aa90SMichael Tuexen err(1, "malloc()"); 602d5b4aa90SMichael Tuexen switch (xraddr->address.sa.sa_family) { 603d5b4aa90SMichael Tuexen case AF_INET: 604d5b4aa90SMichael Tuexen #define __IN_IS_ADDR_LOOPBACK(pina) \ 605d5b4aa90SMichael Tuexen ((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) 60627569d01SRenato Botelho if (!__IN_IS_ADDR_LOOPBACK( 60727569d01SRenato Botelho &xraddr->address.sin.sin_addr)) 608d5b4aa90SMichael Tuexen foreign_all_loopback = 0; 609d5b4aa90SMichael Tuexen #undef __IN_IS_ADDR_LOOPBACK 61027569d01SRenato Botelho sockaddr(&faddr->address, AF_INET, 611d5b4aa90SMichael Tuexen &xraddr->address.sin.sin_addr, 612d5b4aa90SMichael Tuexen htons(xstcb->remote_port)); 613d5b4aa90SMichael Tuexen break; 614d5b4aa90SMichael Tuexen case AF_INET6: 61527569d01SRenato Botelho if (!IN6_IS_ADDR_LOOPBACK( 61627569d01SRenato Botelho &xraddr->address.sin6.sin6_addr)) 617d5b4aa90SMichael Tuexen foreign_all_loopback = 0; 61827569d01SRenato Botelho sockaddr(&faddr->address, AF_INET6, 619d5b4aa90SMichael Tuexen &xraddr->address.sin6.sin6_addr, 620d5b4aa90SMichael Tuexen htons(xstcb->remote_port)); 621d5b4aa90SMichael Tuexen break; 622d5b4aa90SMichael Tuexen default: 62327569d01SRenato Botelho errx(1, 62427569d01SRenato Botelho "address family %d not supported", 625d5b4aa90SMichael Tuexen xraddr->address.sa.sa_family); 626d5b4aa90SMichael Tuexen } 62749b836f2SMichael Tuexen faddr->encaps_port = xraddr->encaps_port; 628e389705eSMichael Tuexen faddr->state = xraddr->state; 629d5b4aa90SMichael Tuexen faddr->next = NULL; 630d5b4aa90SMichael Tuexen if (prev_faddr == NULL) 631d5b4aa90SMichael Tuexen sock->faddr = faddr; 632d5b4aa90SMichael Tuexen else 633d5b4aa90SMichael Tuexen prev_faddr->next = faddr; 634d5b4aa90SMichael Tuexen prev_faddr = faddr; 635d5b4aa90SMichael Tuexen } 636bedcf91dSMichael Tuexen if (opt_c) { 637edc9c7fcSMichael Tuexen if ((sock->vflag & vflag) && 638edc9c7fcSMichael Tuexen (!opt_L || 63927569d01SRenato Botelho !(local_all_loopback || 64027569d01SRenato Botelho foreign_all_loopback))) { 641a83d596fSGleb Smirnoff RB_INSERT(socks_t, &socks, sock); 642bedcf91dSMichael Tuexen } else { 643bedcf91dSMichael Tuexen free_socket(sock); 644bedcf91dSMichael Tuexen } 645d5b4aa90SMichael Tuexen } 646d5b4aa90SMichael Tuexen } 647d5b4aa90SMichael Tuexen xinpcb = (struct xsctp_inpcb *)(void *)(buf + offset); 648d5b4aa90SMichael Tuexen offset += sizeof(struct xsctp_inpcb); 649d5b4aa90SMichael Tuexen } 650d5b4aa90SMichael Tuexen free(buf); 651d5b4aa90SMichael Tuexen } 652d5b4aa90SMichael Tuexen 653d5b4aa90SMichael Tuexen static void 654ca007d91SDag-Erling Smørgrav gather_inet(int proto) 655ca007d91SDag-Erling Smørgrav { 656ca007d91SDag-Erling Smørgrav struct xinpgen *xig, *exig; 657ca007d91SDag-Erling Smørgrav struct xinpcb *xip; 658bf40d2caSGleb Smirnoff struct xtcpcb *xtp = NULL; 659ca007d91SDag-Erling Smørgrav struct xsocket *so; 660ca007d91SDag-Erling Smørgrav struct sock *sock; 661e6f718c7SMichael Tuexen struct addr *laddr, *faddr; 662ca007d91SDag-Erling Smørgrav const char *varname, *protoname; 663ca007d91SDag-Erling Smørgrav size_t len, bufsize; 664ca007d91SDag-Erling Smørgrav void *buf; 665a83d596fSGleb Smirnoff int retry, vflag; 666ca007d91SDag-Erling Smørgrav 6676eb1d5baSMichael Tuexen vflag = 0; 668ca007d91SDag-Erling Smørgrav if (opt_4) 669ca007d91SDag-Erling Smørgrav vflag |= INP_IPV4; 670ca007d91SDag-Erling Smørgrav if (opt_6) 671ca007d91SDag-Erling Smørgrav vflag |= INP_IPV6; 672ca007d91SDag-Erling Smørgrav 673ca007d91SDag-Erling Smørgrav switch (proto) { 674ca007d91SDag-Erling Smørgrav case IPPROTO_TCP: 675ca007d91SDag-Erling Smørgrav varname = "net.inet.tcp.pcblist"; 676ca007d91SDag-Erling Smørgrav protoname = "tcp"; 677ca007d91SDag-Erling Smørgrav break; 678ca007d91SDag-Erling Smørgrav case IPPROTO_UDP: 679ca007d91SDag-Erling Smørgrav varname = "net.inet.udp.pcblist"; 680ca007d91SDag-Erling Smørgrav protoname = "udp"; 681ca007d91SDag-Erling Smørgrav break; 6822cfbdf89SRuslan Ermilov case IPPROTO_DIVERT: 6832cfbdf89SRuslan Ermilov varname = "net.inet.divert.pcblist"; 6842cfbdf89SRuslan Ermilov protoname = "div"; 6852cfbdf89SRuslan Ermilov break; 686ca007d91SDag-Erling Smørgrav default: 6871f3d67aaSGiorgos Keramidas errx(1, "protocol %d not supported", proto); 688ca007d91SDag-Erling Smørgrav } 689ca007d91SDag-Erling Smørgrav 690ca007d91SDag-Erling Smørgrav buf = NULL; 691ca007d91SDag-Erling Smørgrav bufsize = 8192; 692ca007d91SDag-Erling Smørgrav retry = 5; 693ca007d91SDag-Erling Smørgrav do { 694ca007d91SDag-Erling Smørgrav for (;;) { 695ca007d91SDag-Erling Smørgrav if ((buf = realloc(buf, bufsize)) == NULL) 696ca007d91SDag-Erling Smørgrav err(1, "realloc()"); 697ca007d91SDag-Erling Smørgrav len = bufsize; 698c5a2d8c5SRyan Moeller if (cap_sysctlbyname(capsysctl, varname, buf, &len, 699c5a2d8c5SRyan Moeller NULL, 0) == 0) 700ca007d91SDag-Erling Smørgrav break; 7014b2a3d41SRuslan Ermilov if (errno == ENOENT) 7024b2a3d41SRuslan Ermilov goto out; 703003e7e49SMikolaj Golub if (errno != ENOMEM || len != bufsize) 704c5a2d8c5SRyan Moeller err(1, "cap_sysctlbyname()"); 705ca007d91SDag-Erling Smørgrav bufsize *= 2; 706ca007d91SDag-Erling Smørgrav } 707ca007d91SDag-Erling Smørgrav xig = (struct xinpgen *)buf; 7086dbe8d53SRobert Drehmel exig = (struct xinpgen *)(void *) 7096dbe8d53SRobert Drehmel ((char *)buf + len - sizeof *exig); 71008e77283SAlexander V. Chernikov enforce_ksize(xig->xig_len, struct xinpgen); 71108e77283SAlexander V. Chernikov enforce_ksize(exig->xig_len, struct xinpgen); 712ca007d91SDag-Erling Smørgrav } while (xig->xig_gen != exig->xig_gen && retry--); 713ca007d91SDag-Erling Smørgrav 714ca007d91SDag-Erling Smørgrav if (xig->xig_gen != exig->xig_gen && opt_v) 715ca007d91SDag-Erling Smørgrav warnx("warning: data may be inconsistent"); 716ca007d91SDag-Erling Smørgrav 717ca007d91SDag-Erling Smørgrav for (;;) { 7186dbe8d53SRobert Drehmel xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len); 719ca007d91SDag-Erling Smørgrav if (xig >= exig) 720ca007d91SDag-Erling Smørgrav break; 721ca007d91SDag-Erling Smørgrav switch (proto) { 722ca007d91SDag-Erling Smørgrav case IPPROTO_TCP: 723cc65eb4eSGleb Smirnoff xtp = (struct xtcpcb *)xig; 724cc65eb4eSGleb Smirnoff xip = &xtp->xt_inp; 72508e77283SAlexander V. Chernikov if (!check_ksize(xtp->xt_len, struct xtcpcb)) 726ca007d91SDag-Erling Smørgrav goto out; 727cc65eb4eSGleb Smirnoff protoname = xtp->t_flags & TF_TOE ? "toe" : "tcp"; 728ca007d91SDag-Erling Smørgrav break; 729ca007d91SDag-Erling Smørgrav case IPPROTO_UDP: 7302cfbdf89SRuslan Ermilov case IPPROTO_DIVERT: 731cc65eb4eSGleb Smirnoff xip = (struct xinpcb *)xig; 73208e77283SAlexander V. Chernikov if (!check_ksize(xip->xi_len, struct xinpcb)) 733ca007d91SDag-Erling Smørgrav goto out; 734ca007d91SDag-Erling Smørgrav break; 735ca007d91SDag-Erling Smørgrav default: 7361f3d67aaSGiorgos Keramidas errx(1, "protocol %d not supported", proto); 737ca007d91SDag-Erling Smørgrav } 738cc65eb4eSGleb Smirnoff so = &xip->xi_socket; 739cc65eb4eSGleb Smirnoff if ((xip->inp_vflag & vflag) == 0) 740ca007d91SDag-Erling Smørgrav continue; 741cc65eb4eSGleb Smirnoff if (xip->inp_vflag & INP_IPV4) { 742cc65eb4eSGleb Smirnoff if ((xip->inp_fport == 0 && !opt_l) || 743cc65eb4eSGleb Smirnoff (xip->inp_fport != 0 && !opt_c)) 7441e6690e5SDag-Erling Smørgrav continue; 7459b6ca892SBruce M Simpson #define __IN_IS_ADDR_LOOPBACK(pina) \ 7469b6ca892SBruce M Simpson ((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) 7479b6ca892SBruce M Simpson if (opt_L && 748cc65eb4eSGleb Smirnoff (__IN_IS_ADDR_LOOPBACK(&xip->inp_faddr) || 749cc65eb4eSGleb Smirnoff __IN_IS_ADDR_LOOPBACK(&xip->inp_laddr))) 7509b6ca892SBruce M Simpson continue; 7519b6ca892SBruce M Simpson #undef __IN_IS_ADDR_LOOPBACK 752cc65eb4eSGleb Smirnoff } else if (xip->inp_vflag & INP_IPV6) { 753cc65eb4eSGleb Smirnoff if ((xip->inp_fport == 0 && !opt_l) || 754cc65eb4eSGleb Smirnoff (xip->inp_fport != 0 && !opt_c)) 7551e6690e5SDag-Erling Smørgrav continue; 7569b6ca892SBruce M Simpson if (opt_L && 757cc65eb4eSGleb Smirnoff (IN6_IS_ADDR_LOOPBACK(&xip->in6p_faddr) || 758cc65eb4eSGleb Smirnoff IN6_IS_ADDR_LOOPBACK(&xip->in6p_laddr))) 7599b6ca892SBruce M Simpson continue; 7601e6690e5SDag-Erling Smørgrav } else { 7611e6690e5SDag-Erling Smørgrav if (opt_v) 762cc65eb4eSGleb Smirnoff warnx("invalid vflag 0x%x", xip->inp_vflag); 7631e6690e5SDag-Erling Smørgrav continue; 7641e6690e5SDag-Erling Smørgrav } 765b8e20e2dSHiroki Sato if ((sock = calloc(1, sizeof(*sock))) == NULL) 766ca007d91SDag-Erling Smørgrav err(1, "malloc()"); 767e6f718c7SMichael Tuexen if ((laddr = calloc(1, sizeof *laddr)) == NULL) 768e6f718c7SMichael Tuexen err(1, "malloc()"); 769e6f718c7SMichael Tuexen if ((faddr = calloc(1, sizeof *faddr)) == NULL) 770e6f718c7SMichael Tuexen err(1, "malloc()"); 771ca007d91SDag-Erling Smørgrav sock->socket = so->xso_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; 888*2c436d48SGleb Smirnoff faddr->conn = xup->unp_conn; 889*2c436d48SGleb Smirnoff faddr->firstref = xup->xu_firstref; 890*2c436d48SGleb 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 { 905*2c436d48SGleb 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); 921*2c436d48SGleb Smirnoff nfiles = len / sizeof(*xfiles); 922*2c436d48SGleb Smirnoff 923*2c436d48SGleb Smirnoff if ((files = malloc(nfiles * sizeof(struct file))) == NULL) 924*2c436d48SGleb Smirnoff err(1, "malloc()"); 925*2c436d48SGleb Smirnoff 926*2c436d48SGleb Smirnoff for (int i = 0; i < nfiles; i++) { 927*2c436d48SGleb Smirnoff files[i].xf_data = xfiles[i].xf_data; 928*2c436d48SGleb Smirnoff files[i].xf_pid = xfiles[i].xf_pid; 929*2c436d48SGleb Smirnoff files[i].xf_uid = xfiles[i].xf_uid; 930*2c436d48SGleb Smirnoff files[i].xf_fd = xfiles[i].xf_fd; 931*2c436d48SGleb Smirnoff RB_INSERT(files_t, &ftree, &files[i]); 932*2c436d48SGleb Smirnoff } 933*2c436d48SGleb Smirnoff 934*2c436d48SGleb 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); 1145*2c436d48SGleb 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 } 1150*2c436d48SGleb Smirnoff /* Local bind(2) address, if any. */ 1151*2c436d48SGleb Smirnoff if (laddr->address.ss_len > 0) 1152*2c436d48SGleb Smirnoff pos += printaddr(&laddr->address); 1153*2c436d48SGleb Smirnoff /* Remote peer we connect(2) to, if any. */ 1154*2c436d48SGleb Smirnoff if (faddr->conn != 0) { 1155*2c436d48SGleb Smirnoff struct sock *p; 1156*2c436d48SGleb Smirnoff 1157*2c436d48SGleb Smirnoff pos += xprintf("%s-> ", 1158*2c436d48SGleb Smirnoff laddr->address.ss_len > 0 ? " " : ""); 1159*2c436d48SGleb Smirnoff p = RB_FIND(pcbs_t, &pcbs, 1160*2c436d48SGleb Smirnoff &(struct sock){ .pcb = faddr->conn }); 1161*2c436d48SGleb Smirnoff if (__predict_false(p == NULL)) { 1162*2c436d48SGleb Smirnoff /* XXGL: can this happen at all? */ 1163ca007d91SDag-Erling Smørgrav pos += xprintf("??"); 1164*2c436d48SGleb Smirnoff } else if (p->laddr->address.ss_len == 0) { 1165*2c436d48SGleb Smirnoff struct file *f; 1166*2c436d48SGleb Smirnoff 1167*2c436d48SGleb Smirnoff f = RB_FIND(files_t, &ftree, 1168*2c436d48SGleb Smirnoff &(struct file){ .xf_data = 1169*2c436d48SGleb Smirnoff p->socket }); 1170*2c436d48SGleb Smirnoff pos += xprintf("[%lu %d]", 1171*2c436d48SGleb Smirnoff (u_long)f->xf_pid, f->xf_fd); 1172*2c436d48SGleb Smirnoff } else 1173*2c436d48SGleb Smirnoff pos += printaddr(&p->laddr->address); 1174*2c436d48SGleb Smirnoff } 1175*2c436d48SGleb Smirnoff /* Remote peer(s) connect(2)ed to us, if any. */ 1176*2c436d48SGleb Smirnoff if (faddr->firstref != 0) { 1177*2c436d48SGleb Smirnoff struct sock *p; 1178*2c436d48SGleb Smirnoff struct file *f; 1179*2c436d48SGleb Smirnoff kvaddr_t ref = faddr->firstref; 1180*2c436d48SGleb Smirnoff bool fref = true; 1181*2c436d48SGleb Smirnoff 1182*2c436d48SGleb Smirnoff pos += xprintf(" <- "); 1183*2c436d48SGleb Smirnoff 1184*2c436d48SGleb Smirnoff while ((p = RB_FIND(pcbs_t, &pcbs, 1185*2c436d48SGleb Smirnoff &(struct sock){ .pcb = ref })) != 0) { 1186*2c436d48SGleb Smirnoff f = RB_FIND(files_t, &ftree, 1187*2c436d48SGleb Smirnoff &(struct file){ .xf_data = 1188*2c436d48SGleb Smirnoff p->socket }); 1189*2c436d48SGleb Smirnoff pos += xprintf("%s[%lu %d]", 1190*2c436d48SGleb Smirnoff fref ? "" : ",", 1191*2c436d48SGleb Smirnoff (u_long)f->xf_pid, f->xf_fd); 1192*2c436d48SGleb Smirnoff ref = p->faddr->nextref; 1193*2c436d48SGleb Smirnoff fref = false; 1194*2c436d48SGleb Smirnoff } 1195*2c436d48SGleb Smirnoff } 119683f60cb2SMichael Tuexen offset += opt_w ? 92 : 44; 1197ca007d91SDag-Erling Smørgrav break; 1198ca007d91SDag-Erling Smørgrav default: 1199ca007d91SDag-Erling Smørgrav abort(); 1200ca007d91SDag-Erling Smørgrav } 12015f64777aSMichael Tuexen if (opt_i) { 12025f64777aSMichael Tuexen if (s->proto == IPPROTO_TCP || 12035f64777aSMichael Tuexen s->proto == IPPROTO_UDP) { 12045f64777aSMichael Tuexen while (pos < offset) 12055f64777aSMichael Tuexen pos += xprintf(" "); 12065f64777aSMichael Tuexen pos += xprintf("%" PRIu64, s->inp_gencnt); 12075f64777aSMichael Tuexen } 12085f64777aSMichael Tuexen offset += 9; 12095f64777aSMichael Tuexen } 121049b836f2SMichael Tuexen if (opt_U) { 121149b836f2SMichael Tuexen if (faddr != NULL && 12129e644c23SMichael Tuexen ((s->proto == IPPROTO_SCTP && 121349b836f2SMichael Tuexen s->state != SCTP_CLOSED && 121449b836f2SMichael Tuexen s->state != SCTP_BOUND && 12159e644c23SMichael Tuexen s->state != SCTP_LISTEN) || 12169e644c23SMichael Tuexen (s->proto == IPPROTO_TCP && 12179e644c23SMichael Tuexen s->state != TCPS_CLOSED && 12189e644c23SMichael Tuexen s->state != TCPS_LISTEN))) { 121949b836f2SMichael Tuexen while (pos < offset) 122049b836f2SMichael Tuexen pos += xprintf(" "); 122149b836f2SMichael Tuexen pos += xprintf("%u", 122249b836f2SMichael Tuexen ntohs(faddr->encaps_port)); 122349b836f2SMichael Tuexen } 122449b836f2SMichael Tuexen offset += 7; 122549b836f2SMichael Tuexen } 1226e389705eSMichael Tuexen if (opt_s) { 1227e389705eSMichael Tuexen if (faddr != NULL && 1228e389705eSMichael Tuexen s->proto == IPPROTO_SCTP && 1229e389705eSMichael Tuexen s->state != SCTP_CLOSED && 1230e389705eSMichael Tuexen s->state != SCTP_BOUND && 1231e389705eSMichael Tuexen s->state != SCTP_LISTEN) { 1232e389705eSMichael Tuexen while (pos < offset) 1233e389705eSMichael Tuexen pos += xprintf(" "); 1234e389705eSMichael Tuexen pos += xprintf("%s", 1235e389705eSMichael Tuexen sctp_path_state(faddr->state)); 1236e389705eSMichael Tuexen } 1237e389705eSMichael Tuexen offset += 13; 1238e389705eSMichael Tuexen } 1239e5cccc35SMichael Tuexen if (first) { 124049b836f2SMichael Tuexen if (opt_s) { 124149b836f2SMichael Tuexen if (s->proto == IPPROTO_SCTP || 124249b836f2SMichael Tuexen s->proto == IPPROTO_TCP) { 124349b836f2SMichael Tuexen while (pos < offset) 12444e13a5b0SMichael Tuexen pos += xprintf(" "); 12456414db1bSMichael Tuexen switch (s->proto) { 12466414db1bSMichael Tuexen case IPPROTO_SCTP: 1247e5cccc35SMichael Tuexen pos += xprintf("%s", 1248e389705eSMichael Tuexen sctp_conn_state(s->state)); 12496414db1bSMichael Tuexen break; 12506414db1bSMichael Tuexen case IPPROTO_TCP: 1251e5cccc35SMichael Tuexen if (s->state >= 0 && 1252e5cccc35SMichael Tuexen s->state < TCP_NSTATES) 125349b836f2SMichael Tuexen pos += xprintf("%s", 1254e5cccc35SMichael Tuexen tcpstates[s->state]); 12554e13a5b0SMichael Tuexen else 12564e13a5b0SMichael Tuexen pos += xprintf("?"); 12576414db1bSMichael Tuexen break; 12586414db1bSMichael Tuexen } 12594e13a5b0SMichael Tuexen } 126049b836f2SMichael Tuexen offset += 13; 126149b836f2SMichael Tuexen } 12622ac089d0SMichael Tuexen if (opt_S) { 12632ac089d0SMichael Tuexen if (s->proto == IPPROTO_TCP) { 126449b836f2SMichael Tuexen while (pos < offset) 1265e5cccc35SMichael Tuexen pos += xprintf(" "); 12662ac089d0SMichael Tuexen pos += xprintf("%.*s", 12672ac089d0SMichael Tuexen TCP_FUNCTION_NAME_LEN_MAX, 1268e5cccc35SMichael Tuexen s->stack); 1269e5cccc35SMichael Tuexen } 12702ac089d0SMichael Tuexen offset += TCP_FUNCTION_NAME_LEN_MAX + 1; 12712ac089d0SMichael Tuexen } 12722ac089d0SMichael Tuexen if (opt_C) { 12732ac089d0SMichael Tuexen if (s->proto == IPPROTO_TCP) { 12742ac089d0SMichael Tuexen while (pos < offset) 12752ac089d0SMichael Tuexen pos += xprintf(" "); 12762ac089d0SMichael Tuexen xprintf("%.*s", TCP_CA_NAME_MAX, s->cc); 12772ac089d0SMichael Tuexen } 12782ac089d0SMichael Tuexen offset += TCP_CA_NAME_MAX + 1; 12792ac089d0SMichael Tuexen } 1280e5cccc35SMichael Tuexen } 1281e6f718c7SMichael Tuexen if (laddr != NULL) 1282e6f718c7SMichael Tuexen laddr = laddr->next; 1283e6f718c7SMichael Tuexen if (faddr != NULL) 1284e6f718c7SMichael Tuexen faddr = faddr->next; 1285e6f718c7SMichael Tuexen if ((laddr != NULL) || (faddr != NULL)) { 1286e6f718c7SMichael Tuexen xprintf("\n"); 1287e6f718c7SMichael Tuexen pos = 0; 1288e6f718c7SMichael Tuexen } 12894e13a5b0SMichael Tuexen first = 0; 1290e6f718c7SMichael Tuexen } 12914e13a5b0SMichael Tuexen xprintf("\n"); 1292ca007d91SDag-Erling Smørgrav } 129361149f8dSJilles Tjoelker 129461149f8dSJilles Tjoelker static void 129561149f8dSJilles Tjoelker display(void) 129661149f8dSJilles Tjoelker { 129761149f8dSJilles Tjoelker struct passwd *pwd; 1298*2c436d48SGleb Smirnoff struct file *xf; 129961149f8dSJilles Tjoelker struct sock *s; 1300a83d596fSGleb Smirnoff int n, pos; 130161149f8dSJilles Tjoelker 1302ee0afaa9SEmmanuel Vadot if (opt_q != 1) { 1303c5bdcd1fSGleb Smirnoff printf("%-8s %-10s %-5s %-3s %-6s %-*s %-*s", 130461149f8dSJilles Tjoelker "USER", "COMMAND", "PID", "FD", "PROTO", 130583f60cb2SMichael Tuexen opt_w ? 45 : 21, "LOCAL ADDRESS", 130683f60cb2SMichael Tuexen opt_w ? 45 : 21, "FOREIGN ADDRESS"); 13075f64777aSMichael Tuexen if (opt_i) 13085f64777aSMichael Tuexen printf(" %-8s", "ID"); 130949b836f2SMichael Tuexen if (opt_U) 131049b836f2SMichael Tuexen printf(" %-6s", "ENCAPS"); 1311e389705eSMichael Tuexen if (opt_s) { 1312e389705eSMichael Tuexen printf(" %-12s", "PATH STATE"); 1313e389705eSMichael Tuexen printf(" %-12s", "CONN STATE"); 1314e389705eSMichael Tuexen } 1315e5cccc35SMichael Tuexen if (opt_S) 13162ac089d0SMichael Tuexen printf(" %-*.*s", TCP_FUNCTION_NAME_LEN_MAX, 13172ac089d0SMichael Tuexen TCP_FUNCTION_NAME_LEN_MAX, "STACK"); 13182ac089d0SMichael Tuexen if (opt_C) 13192ac089d0SMichael Tuexen printf(" %-.*s", TCP_CA_NAME_MAX, "CC"); 13207a5642b3SDag-Erling Smørgrav printf("\n"); 1321ee0afaa9SEmmanuel Vadot } 13227ad30f58SMariusz Zaborski cap_setpassent(cappwd, 1); 1323*2c436d48SGleb Smirnoff for (xf = files, n = 0; n < nfiles; ++n, ++xf) { 1324f38b68aeSBrooks Davis if (xf->xf_data == 0) 132561149f8dSJilles Tjoelker continue; 132600feaafdSAndrew Thompson if (opt_j >= 0 && opt_j != getprocjid(xf->xf_pid)) 132700feaafdSAndrew Thompson continue; 1328a83d596fSGleb Smirnoff s = RB_FIND(socks_t, &socks, 1329a83d596fSGleb Smirnoff &(struct sock){ .socket = xf->xf_data}); 1330a83d596fSGleb Smirnoff if (s != NULL && check_ports(s)) { 133161149f8dSJilles Tjoelker s->shown = 1; 133261149f8dSJilles Tjoelker pos = 0; 13337ad30f58SMariusz Zaborski if (opt_n || 13347ad30f58SMariusz Zaborski (pwd = cap_getpwuid(cappwd, xf->xf_uid)) == NULL) 133561149f8dSJilles Tjoelker pos += xprintf("%lu ", (u_long)xf->xf_uid); 133661149f8dSJilles Tjoelker else 133761149f8dSJilles Tjoelker pos += xprintf("%s ", pwd->pw_name); 133861149f8dSJilles Tjoelker while (pos < 9) 133961149f8dSJilles Tjoelker pos += xprintf(" "); 134061149f8dSJilles Tjoelker pos += xprintf("%.10s", getprocname(xf->xf_pid)); 134161149f8dSJilles Tjoelker while (pos < 20) 134261149f8dSJilles Tjoelker pos += xprintf(" "); 134361149f8dSJilles Tjoelker pos += xprintf("%lu ", (u_long)xf->xf_pid); 134461149f8dSJilles Tjoelker while (pos < 26) 134561149f8dSJilles Tjoelker pos += xprintf(" "); 1346c5bdcd1fSGleb Smirnoff pos += xprintf("%-3d ", xf->xf_fd); 134761149f8dSJilles Tjoelker displaysock(s, pos); 134861149f8dSJilles Tjoelker } 13497e80c6b0SMichael Tuexen } 135000feaafdSAndrew Thompson if (opt_j >= 0) 135100feaafdSAndrew Thompson return; 1352a83d596fSGleb Smirnoff SLIST_FOREACH(s, &nosocks, socket_list) { 1353a83d596fSGleb Smirnoff if (!check_ports(s)) 1354a83d596fSGleb Smirnoff continue; 1355a83d596fSGleb Smirnoff pos = xprintf("%-8s %-10s %-5s %-2s ", 1356a83d596fSGleb Smirnoff "?", "?", "?", "?"); 1357a83d596fSGleb Smirnoff displaysock(s, pos); 1358a83d596fSGleb Smirnoff } 1359a83d596fSGleb Smirnoff RB_FOREACH(s, socks_t, &socks) { 136061149f8dSJilles Tjoelker if (s->shown) 136161149f8dSJilles Tjoelker continue; 136261149f8dSJilles Tjoelker if (!check_ports(s)) 136361149f8dSJilles Tjoelker continue; 1364a83d596fSGleb Smirnoff pos = xprintf("%-8s %-10s %-5s %-2s ", 136561149f8dSJilles Tjoelker "?", "?", "?", "?"); 136661149f8dSJilles Tjoelker displaysock(s, pos); 136761149f8dSJilles Tjoelker } 136861149f8dSJilles Tjoelker } 1369ca007d91SDag-Erling Smørgrav 1370f1cd4902SRyan Moeller static int 1371f1cd4902SRyan Moeller set_default_protos(void) 13721f3d67aaSGiorgos Keramidas { 13731f3d67aaSGiorgos Keramidas struct protoent *prot; 13741f3d67aaSGiorgos Keramidas const char *pname; 13751f3d67aaSGiorgos Keramidas size_t pindex; 13761f3d67aaSGiorgos Keramidas 13771f3d67aaSGiorgos Keramidas init_protos(default_numprotos); 13781f3d67aaSGiorgos Keramidas 13791f3d67aaSGiorgos Keramidas for (pindex = 0; pindex < default_numprotos; pindex++) { 13801f3d67aaSGiorgos Keramidas pname = default_protos[pindex]; 1381c5a2d8c5SRyan Moeller prot = cap_getprotobyname(capnetdb, pname); 13821f3d67aaSGiorgos Keramidas if (prot == NULL) 1383c5a2d8c5SRyan Moeller err(1, "cap_getprotobyname: %s", pname); 13841f3d67aaSGiorgos Keramidas protos[pindex] = prot->p_proto; 13851f3d67aaSGiorgos Keramidas } 13861f3d67aaSGiorgos Keramidas numprotos = pindex; 13871f3d67aaSGiorgos Keramidas return (pindex); 13881f3d67aaSGiorgos Keramidas } 13891f3d67aaSGiorgos Keramidas 1390f1cd4902SRyan Moeller /* 1391f1cd4902SRyan Moeller * Return the vnet property of the jail, or -1 on error. 1392f1cd4902SRyan Moeller */ 1393f1cd4902SRyan Moeller static int 1394f1cd4902SRyan Moeller jail_getvnet(int jid) 1395f1cd4902SRyan Moeller { 1396f1cd4902SRyan Moeller struct iovec jiov[6]; 1397f1cd4902SRyan Moeller int vnet; 13981fec1fa8SGleb Smirnoff size_t len = sizeof(vnet); 13991fec1fa8SGleb Smirnoff 14001fec1fa8SGleb Smirnoff if (sysctlbyname("kern.features.vimage", &vnet, &len, NULL, 0) != 0) 14011fec1fa8SGleb Smirnoff return (0); 1402f1cd4902SRyan Moeller 1403f1cd4902SRyan Moeller vnet = -1; 1404f1cd4902SRyan Moeller jiov[0].iov_base = __DECONST(char *, "jid"); 1405f1cd4902SRyan Moeller jiov[0].iov_len = sizeof("jid"); 1406f1cd4902SRyan Moeller jiov[1].iov_base = &jid; 1407f1cd4902SRyan Moeller jiov[1].iov_len = sizeof(jid); 1408f1cd4902SRyan Moeller jiov[2].iov_base = __DECONST(char *, "vnet"); 1409f1cd4902SRyan Moeller jiov[2].iov_len = sizeof("vnet"); 1410f1cd4902SRyan Moeller jiov[3].iov_base = &vnet; 1411f1cd4902SRyan Moeller jiov[3].iov_len = sizeof(vnet); 1412f1cd4902SRyan Moeller jiov[4].iov_base = __DECONST(char *, "errmsg"); 1413f1cd4902SRyan Moeller jiov[4].iov_len = sizeof("errmsg"); 1414f1cd4902SRyan Moeller jiov[5].iov_base = jail_errmsg; 1415f1cd4902SRyan Moeller jiov[5].iov_len = JAIL_ERRMSGLEN; 1416f1cd4902SRyan Moeller jail_errmsg[0] = '\0'; 1417f1cd4902SRyan Moeller if (jail_get(jiov, nitems(jiov), 0) < 0) { 1418f1cd4902SRyan Moeller if (!jail_errmsg[0]) 1419f1cd4902SRyan Moeller snprintf(jail_errmsg, JAIL_ERRMSGLEN, 1420f1cd4902SRyan Moeller "jail_get: %s", strerror(errno)); 1421f1cd4902SRyan Moeller return (-1); 1422f1cd4902SRyan Moeller } 1423f1cd4902SRyan Moeller return (vnet); 1424f1cd4902SRyan Moeller } 1425f1cd4902SRyan Moeller 1426ca007d91SDag-Erling Smørgrav static void 1427ca007d91SDag-Erling Smørgrav usage(void) 1428ca007d91SDag-Erling Smørgrav { 14291f3d67aaSGiorgos Keramidas fprintf(stderr, 14306ad26abcSMichael Tuexen "usage: sockstat [-46CciLlnqSsUuvw] [-j jid] [-p ports] [-P protocols]\n"); 1431ca007d91SDag-Erling Smørgrav exit(1); 1432ca007d91SDag-Erling Smørgrav } 1433ca007d91SDag-Erling Smørgrav 1434ca007d91SDag-Erling Smørgrav int 1435ca007d91SDag-Erling Smørgrav main(int argc, char *argv[]) 1436ca007d91SDag-Erling Smørgrav { 1437c5a2d8c5SRyan Moeller cap_channel_t *capcas; 1438c5a2d8c5SRyan Moeller cap_net_limit_t *limit; 14397ad30f58SMariusz Zaborski const char *pwdcmds[] = { "setpassent", "getpwuid" }; 14407ad30f58SMariusz Zaborski const char *pwdfields[] = { "pw_name" }; 14411f3d67aaSGiorgos Keramidas int protos_defined = -1; 14421f3d67aaSGiorgos Keramidas int o, i; 1443ca007d91SDag-Erling Smørgrav 144400feaafdSAndrew Thompson opt_j = -1; 14455f64777aSMichael Tuexen while ((o = getopt(argc, argv, "46Ccij:Llnp:P:qSsUuvw")) != -1) 1446ca007d91SDag-Erling Smørgrav switch (o) { 1447ca007d91SDag-Erling Smørgrav case '4': 1448ca007d91SDag-Erling Smørgrav opt_4 = 1; 1449ca007d91SDag-Erling Smørgrav break; 1450ca007d91SDag-Erling Smørgrav case '6': 1451ca007d91SDag-Erling Smørgrav opt_6 = 1; 1452ca007d91SDag-Erling Smørgrav break; 14532ac089d0SMichael Tuexen case 'C': 14542ac089d0SMichael Tuexen opt_C = 1; 14552ac089d0SMichael Tuexen break; 1456ca007d91SDag-Erling Smørgrav case 'c': 1457ca007d91SDag-Erling Smørgrav opt_c = 1; 1458ca007d91SDag-Erling Smørgrav break; 14595f64777aSMichael Tuexen case 'i': 14605f64777aSMichael Tuexen opt_i = 1; 14615f64777aSMichael Tuexen break; 146200feaafdSAndrew Thompson case 'j': 1463de68a320SJamie Gritton opt_j = jail_getid(optarg); 1464de68a320SJamie Gritton if (opt_j < 0) 146532723a3bSGleb Smirnoff errx(1, "jail_getid: %s", jail_errmsg); 146600feaafdSAndrew Thompson break; 14679b6ca892SBruce M Simpson case 'L': 14689b6ca892SBruce M Simpson opt_L = 1; 14699b6ca892SBruce M Simpson break; 1470ca007d91SDag-Erling Smørgrav case 'l': 1471ca007d91SDag-Erling Smørgrav opt_l = 1; 1472ca007d91SDag-Erling Smørgrav break; 1473ccdd2b2bSAlexander Motin case 'n': 1474ccdd2b2bSAlexander Motin opt_n = 1; 1475ccdd2b2bSAlexander Motin break; 1476ca007d91SDag-Erling Smørgrav case 'p': 1477ca007d91SDag-Erling Smørgrav parse_ports(optarg); 1478ca007d91SDag-Erling Smørgrav break; 14791f3d67aaSGiorgos Keramidas case 'P': 14801f3d67aaSGiorgos Keramidas protos_defined = parse_protos(optarg); 14811f3d67aaSGiorgos Keramidas break; 1482ee0afaa9SEmmanuel Vadot case 'q': 1483ee0afaa9SEmmanuel Vadot opt_q = 1; 148462de7037SEmmanuel Vadot break; 1485e5cccc35SMichael Tuexen case 'S': 1486e5cccc35SMichael Tuexen opt_S = 1; 1487e5cccc35SMichael Tuexen break; 14887a5642b3SDag-Erling Smørgrav case 's': 14897a5642b3SDag-Erling Smørgrav opt_s = 1; 14907a5642b3SDag-Erling Smørgrav break; 149149b836f2SMichael Tuexen case 'U': 149249b836f2SMichael Tuexen opt_U = 1; 149349b836f2SMichael Tuexen break; 1494ca007d91SDag-Erling Smørgrav case 'u': 1495ca007d91SDag-Erling Smørgrav opt_u = 1; 1496ca007d91SDag-Erling Smørgrav break; 1497ca007d91SDag-Erling Smørgrav case 'v': 1498ca007d91SDag-Erling Smørgrav ++opt_v; 1499ca007d91SDag-Erling Smørgrav break; 150083f60cb2SMichael Tuexen case 'w': 150183f60cb2SMichael Tuexen opt_w = 1; 150283f60cb2SMichael Tuexen break; 1503ca007d91SDag-Erling Smørgrav default: 1504ca007d91SDag-Erling Smørgrav usage(); 1505ca007d91SDag-Erling Smørgrav } 1506ca007d91SDag-Erling Smørgrav 1507ca007d91SDag-Erling Smørgrav argc -= optind; 1508ca007d91SDag-Erling Smørgrav argv += optind; 1509ca007d91SDag-Erling Smørgrav 1510ca007d91SDag-Erling Smørgrav if (argc > 0) 1511ca007d91SDag-Erling Smørgrav usage(); 1512ca007d91SDag-Erling Smørgrav 1513f1cd4902SRyan Moeller if (opt_j > 0) { 1514f1cd4902SRyan Moeller switch (jail_getvnet(opt_j)) { 1515f1cd4902SRyan Moeller case -1: 151632723a3bSGleb Smirnoff errx(2, "jail_getvnet: %s", jail_errmsg); 1517f1cd4902SRyan Moeller case JAIL_SYS_NEW: 1518f1cd4902SRyan Moeller if (jail_attach(opt_j) < 0) 1519ae37905bSRyan Moeller err(3, "jail_attach()"); 1520f1cd4902SRyan Moeller /* Set back to -1 for normal output in vnet jail. */ 1521f1cd4902SRyan Moeller opt_j = -1; 1522f1cd4902SRyan Moeller break; 1523f1cd4902SRyan Moeller default: 1524f1cd4902SRyan Moeller break; 1525f1cd4902SRyan Moeller } 1526f1cd4902SRyan Moeller } 1527f1cd4902SRyan Moeller 1528c5a2d8c5SRyan Moeller capcas = cap_init(); 1529c5a2d8c5SRyan Moeller if (capcas == NULL) 1530c5a2d8c5SRyan Moeller err(1, "Unable to contact Casper"); 1531c5a2d8c5SRyan Moeller if (caph_enter_casper() < 0) 1532c5a2d8c5SRyan Moeller err(1, "Unable to enter capability mode"); 1533c5a2d8c5SRyan Moeller capnet = cap_service_open(capcas, "system.net"); 1534c5a2d8c5SRyan Moeller if (capnet == NULL) 1535c5a2d8c5SRyan Moeller err(1, "Unable to open system.net service"); 1536c5a2d8c5SRyan Moeller capnetdb = cap_service_open(capcas, "system.netdb"); 1537c5a2d8c5SRyan Moeller if (capnetdb == NULL) 1538c5a2d8c5SRyan Moeller err(1, "Unable to open system.netdb service"); 1539c5a2d8c5SRyan Moeller capsysctl = cap_service_open(capcas, "system.sysctl"); 1540c5a2d8c5SRyan Moeller if (capsysctl == NULL) 1541c5a2d8c5SRyan Moeller err(1, "Unable to open system.sysctl service"); 15427ad30f58SMariusz Zaborski cappwd = cap_service_open(capcas, "system.pwd"); 15437ad30f58SMariusz Zaborski if (cappwd == NULL) 15447ad30f58SMariusz Zaborski err(1, "Unable to open system.pwd service"); 1545c5a2d8c5SRyan Moeller cap_close(capcas); 1546c5a2d8c5SRyan Moeller limit = cap_net_limit_init(capnet, CAPNET_ADDR2NAME); 1547c5a2d8c5SRyan Moeller if (limit == NULL) 1548c5a2d8c5SRyan Moeller err(1, "Unable to init cap_net limits"); 1549c5a2d8c5SRyan Moeller if (cap_net_limit(limit) < 0) 1550c5a2d8c5SRyan Moeller err(1, "Unable to apply limits"); 15517ad30f58SMariusz Zaborski if (cap_pwd_limit_cmds(cappwd, pwdcmds, nitems(pwdcmds)) < 0) 15527ad30f58SMariusz Zaborski err(1, "Unable to apply pwd commands limits"); 15537ad30f58SMariusz Zaborski if (cap_pwd_limit_fields(cappwd, pwdfields, nitems(pwdfields)) < 0) 15547ad30f58SMariusz Zaborski err(1, "Unable to apply pwd commands limits"); 1555c5a2d8c5SRyan Moeller 1556d2d77d2aSGiorgos Keramidas if ((!opt_4 && !opt_6) && protos_defined != -1) 15571f3d67aaSGiorgos Keramidas opt_4 = opt_6 = 1; 1558d2d77d2aSGiorgos Keramidas if (!opt_4 && !opt_6 && !opt_u) 1559d2d77d2aSGiorgos Keramidas opt_4 = opt_6 = opt_u = 1; 1560d2d77d2aSGiorgos Keramidas if ((opt_4 || opt_6) && protos_defined == -1) 1561d2d77d2aSGiorgos Keramidas protos_defined = set_default_protos(); 1562ca007d91SDag-Erling Smørgrav if (!opt_c && !opt_l) 1563ca007d91SDag-Erling Smørgrav opt_c = opt_l = 1; 1564ca007d91SDag-Erling Smørgrav 1565ca007d91SDag-Erling Smørgrav if (opt_4 || opt_6) { 15661f3d67aaSGiorgos Keramidas for (i = 0; i < protos_defined; i++) 1567d5b4aa90SMichael Tuexen if (protos[i] == IPPROTO_SCTP) 1568d5b4aa90SMichael Tuexen gather_sctp(); 1569d5b4aa90SMichael Tuexen else 15701f3d67aaSGiorgos Keramidas gather_inet(protos[i]); 1571ca007d91SDag-Erling Smørgrav } 15721f3d67aaSGiorgos Keramidas 15731f3d67aaSGiorgos Keramidas if (opt_u || (protos_defined == -1 && !opt_4 && !opt_6)) { 1574ca007d91SDag-Erling Smørgrav gather_unix(SOCK_STREAM); 1575ca007d91SDag-Erling Smørgrav gather_unix(SOCK_DGRAM); 1576b8e20e2dSHiroki Sato gather_unix(SOCK_SEQPACKET); 1577ca007d91SDag-Erling Smørgrav } 1578ca007d91SDag-Erling Smørgrav getfiles(); 1579ca007d91SDag-Erling Smørgrav display(); 1580ca007d91SDag-Erling Smørgrav exit(0); 1581ca007d91SDag-Erling Smørgrav } 1582