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 */ 85a471d2b4SMark Johnston static int opt_f; /* Show FIB numbers */ 86051a2132SMark Johnston static int opt_I; /* Show spliced socket addresses */ 875f64777aSMichael Tuexen static int opt_i; /* Show inp_gencnt */ 8800feaafdSAndrew Thompson static int opt_j; /* Show specified jail */ 899b6ca892SBruce M Simpson static int opt_L; /* Don't show IPv4 or IPv6 loopback sockets */ 90ca007d91SDag-Erling Smørgrav static int opt_l; /* Show listening sockets */ 91ccdd2b2bSAlexander Motin static int opt_n; /* Don't resolve UIDs to user names */ 92ee0afaa9SEmmanuel Vadot static int opt_q; /* Don't show header */ 93e5cccc35SMichael Tuexen static int opt_S; /* Show protocol stack if applicable */ 947a5642b3SDag-Erling Smørgrav static int opt_s; /* Show protocol state if applicable */ 9549b836f2SMichael Tuexen static int opt_U; /* Show remote UDP encapsulation port number */ 96ca007d91SDag-Erling Smørgrav static int opt_u; /* Show Unix domain sockets */ 97ca007d91SDag-Erling Smørgrav static int opt_v; /* Verbose mode */ 9883f60cb2SMichael Tuexen static int opt_w; /* Wide print area for addresses */ 99ca007d91SDag-Erling Smørgrav 1001f3d67aaSGiorgos Keramidas /* 1011f3d67aaSGiorgos Keramidas * Default protocols to use if no -P was defined. 1021f3d67aaSGiorgos Keramidas */ 103d5b4aa90SMichael Tuexen static const char *default_protos[] = {"sctp", "tcp", "udp", "divert" }; 104b8e20e2dSHiroki Sato static size_t default_numprotos = nitems(default_protos); 1051f3d67aaSGiorgos Keramidas 1061f3d67aaSGiorgos Keramidas static int *protos; /* protocols to use */ 1071f3d67aaSGiorgos Keramidas static size_t numprotos; /* allocated size of protos[] */ 1081f3d67aaSGiorgos Keramidas 109ca007d91SDag-Erling Smørgrav static int *ports; 110ca007d91SDag-Erling Smørgrav 111ca007d91SDag-Erling Smørgrav #define INT_BIT (sizeof(int)*CHAR_BIT) 112ca007d91SDag-Erling Smørgrav #define SET_PORT(p) do { ports[p / INT_BIT] |= 1 << (p % INT_BIT); } while (0) 113ca007d91SDag-Erling Smørgrav #define CHK_PORT(p) (ports[p / INT_BIT] & (1 << (p % INT_BIT))) 114ca007d91SDag-Erling Smørgrav 115e6f718c7SMichael Tuexen struct addr { 1162c436d48SGleb Smirnoff union { 117e6f718c7SMichael Tuexen struct sockaddr_storage address; 1182c436d48SGleb Smirnoff struct { /* unix(4) faddr */ 1192c436d48SGleb Smirnoff kvaddr_t conn; 1202c436d48SGleb Smirnoff kvaddr_t firstref; 1212c436d48SGleb Smirnoff kvaddr_t nextref; 1222c436d48SGleb Smirnoff }; 1232c436d48SGleb Smirnoff }; 12449b836f2SMichael Tuexen unsigned int encaps_port; 125e389705eSMichael Tuexen int state; 126e6f718c7SMichael Tuexen struct addr *next; 127e6f718c7SMichael Tuexen }; 128e6f718c7SMichael Tuexen 129ca007d91SDag-Erling Smørgrav struct sock { 130a83d596fSGleb Smirnoff union { 131a83d596fSGleb Smirnoff RB_ENTRY(sock) socket_tree; /* tree of pcbs with socket */ 132a83d596fSGleb Smirnoff SLIST_ENTRY(sock) socket_list; /* list of pcbs w/o socket */ 133a83d596fSGleb Smirnoff }; 134a83d596fSGleb Smirnoff RB_ENTRY(sock) pcb_tree; 135f38b68aeSBrooks Davis kvaddr_t socket; 136f38b68aeSBrooks Davis kvaddr_t pcb; 137051a2132SMark Johnston kvaddr_t splice_socket; 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; 144a471d2b4SMark Johnston int fibnum; 145ca007d91SDag-Erling Smørgrav const char *protoname; 146e5cccc35SMichael Tuexen char stack[TCP_FUNCTION_NAME_LEN_MAX]; 1472ac089d0SMichael Tuexen char cc[TCP_CA_NAME_MAX]; 148e6f718c7SMichael Tuexen struct addr *laddr; 149e6f718c7SMichael Tuexen struct addr *faddr; 150ca007d91SDag-Erling Smørgrav }; 151ca007d91SDag-Erling Smørgrav 152a83d596fSGleb Smirnoff static RB_HEAD(socks_t, sock) socks = RB_INITIALIZER(&socks); 153a83d596fSGleb Smirnoff static int64_t 154a83d596fSGleb Smirnoff socket_compare(const struct sock *a, const struct sock *b) 155a83d596fSGleb Smirnoff { 156a83d596fSGleb Smirnoff return ((int64_t)(a->socket/2 - b->socket/2)); 157a83d596fSGleb Smirnoff } 158a83d596fSGleb Smirnoff RB_GENERATE_STATIC(socks_t, sock, socket_tree, socket_compare); 159a83d596fSGleb Smirnoff 160a83d596fSGleb Smirnoff static RB_HEAD(pcbs_t, sock) pcbs = RB_INITIALIZER(&pcbs); 161a83d596fSGleb Smirnoff static int64_t 162a83d596fSGleb Smirnoff pcb_compare(const struct sock *a, const struct sock *b) 163a83d596fSGleb Smirnoff { 164a83d596fSGleb Smirnoff return ((int64_t)(a->pcb/2 - b->pcb/2)); 165a83d596fSGleb Smirnoff } 166a83d596fSGleb Smirnoff RB_GENERATE_STATIC(pcbs_t, sock, pcb_tree, pcb_compare); 167a83d596fSGleb Smirnoff 168a83d596fSGleb Smirnoff static SLIST_HEAD(, sock) nosocks = SLIST_HEAD_INITIALIZER(&nosocks); 169ca007d91SDag-Erling Smørgrav 1702c436d48SGleb Smirnoff struct file { 1712c436d48SGleb Smirnoff RB_ENTRY(file) file_tree; 1722c436d48SGleb Smirnoff kvaddr_t xf_data; 1732c436d48SGleb Smirnoff pid_t xf_pid; 1742c436d48SGleb Smirnoff uid_t xf_uid; 1752c436d48SGleb Smirnoff int xf_fd; 1762c436d48SGleb Smirnoff }; 1772c436d48SGleb Smirnoff 1782c436d48SGleb Smirnoff static RB_HEAD(files_t, file) ftree = RB_INITIALIZER(&ftree); 1792c436d48SGleb Smirnoff static int64_t 1802c436d48SGleb Smirnoff file_compare(const struct file *a, const struct file *b) 1812c436d48SGleb Smirnoff { 1822c436d48SGleb Smirnoff return ((int64_t)(a->xf_data/2 - b->xf_data/2)); 1832c436d48SGleb Smirnoff } 1842c436d48SGleb Smirnoff RB_GENERATE_STATIC(files_t, file, file_tree, file_compare); 1852c436d48SGleb Smirnoff 1862c436d48SGleb Smirnoff static struct file *files; 1872c436d48SGleb Smirnoff static int nfiles; 188ca007d91SDag-Erling Smørgrav 189c5a2d8c5SRyan Moeller static cap_channel_t *capnet; 190c5a2d8c5SRyan Moeller static cap_channel_t *capnetdb; 191c5a2d8c5SRyan Moeller static cap_channel_t *capsysctl; 1927ad30f58SMariusz Zaborski static cap_channel_t *cappwd; 193c5a2d8c5SRyan Moeller 194ca007d91SDag-Erling Smørgrav static int 195ca007d91SDag-Erling Smørgrav xprintf(const char *fmt, ...) 196ca007d91SDag-Erling Smørgrav { 197ca007d91SDag-Erling Smørgrav va_list ap; 198ca007d91SDag-Erling Smørgrav int len; 199ca007d91SDag-Erling Smørgrav 200ca007d91SDag-Erling Smørgrav va_start(ap, fmt); 201ca007d91SDag-Erling Smørgrav len = vprintf(fmt, ap); 202ca007d91SDag-Erling Smørgrav va_end(ap); 203ca007d91SDag-Erling Smørgrav if (len < 0) 204ca007d91SDag-Erling Smørgrav err(1, "printf()"); 205ca007d91SDag-Erling Smørgrav return (len); 206ca007d91SDag-Erling Smørgrav } 207ca007d91SDag-Erling Smørgrav 20808e77283SAlexander V. Chernikov static bool 20908e77283SAlexander V. Chernikov _check_ksize(size_t received_size, size_t expected_size, const char *struct_name) 21008e77283SAlexander V. Chernikov { 21108e77283SAlexander V. Chernikov if (received_size != expected_size) { 21208e77283SAlexander V. Chernikov warnx("%s size mismatch: expected %zd, received %zd", 21308e77283SAlexander V. Chernikov struct_name, expected_size, received_size); 21408e77283SAlexander V. Chernikov return false; 21508e77283SAlexander V. Chernikov } 21608e77283SAlexander V. Chernikov return true; 21708e77283SAlexander V. Chernikov } 21808e77283SAlexander V. Chernikov #define check_ksize(_sz, _struct) (_check_ksize(_sz, sizeof(_struct), #_struct)) 21908e77283SAlexander V. Chernikov 22008e77283SAlexander V. Chernikov static void 22108e77283SAlexander V. Chernikov _enforce_ksize(size_t received_size, size_t expected_size, const char *struct_name) 22208e77283SAlexander V. Chernikov { 22308e77283SAlexander V. Chernikov if (received_size != expected_size) { 22408e77283SAlexander V. Chernikov errx(1, "fatal: struct %s size mismatch: expected %zd, received %zd", 22508e77283SAlexander V. Chernikov struct_name, expected_size, received_size); 22608e77283SAlexander V. Chernikov } 22708e77283SAlexander V. Chernikov } 22808e77283SAlexander V. Chernikov #define enforce_ksize(_sz, _struct) (_enforce_ksize(_sz, sizeof(_struct), #_struct)) 22908e77283SAlexander V. Chernikov 2301f3d67aaSGiorgos Keramidas static int 2311f3d67aaSGiorgos Keramidas get_proto_type(const char *proto) 2321f3d67aaSGiorgos Keramidas { 2331f3d67aaSGiorgos Keramidas struct protoent *pent; 2341f3d67aaSGiorgos Keramidas 2351f3d67aaSGiorgos Keramidas if (strlen(proto) == 0) 2361f3d67aaSGiorgos Keramidas return (0); 237bfb5947bSMariusz Zaborski if (capnetdb != NULL) 238c5a2d8c5SRyan Moeller pent = cap_getprotobyname(capnetdb, proto); 239bfb5947bSMariusz Zaborski else 240bfb5947bSMariusz Zaborski pent = getprotobyname(proto); 2411f3d67aaSGiorgos Keramidas if (pent == NULL) { 242c5a2d8c5SRyan Moeller warn("cap_getprotobyname"); 2431f3d67aaSGiorgos Keramidas return (-1); 2441f3d67aaSGiorgos Keramidas } 2451f3d67aaSGiorgos Keramidas return (pent->p_proto); 2461f3d67aaSGiorgos Keramidas } 2471f3d67aaSGiorgos Keramidas 248b8e20e2dSHiroki Sato static void 249b8e20e2dSHiroki Sato init_protos(int num) 2501f3d67aaSGiorgos Keramidas { 2511f3d67aaSGiorgos Keramidas int proto_count = 0; 2521f3d67aaSGiorgos Keramidas 2531f3d67aaSGiorgos Keramidas if (num > 0) { 2541f3d67aaSGiorgos Keramidas proto_count = num; 2551f3d67aaSGiorgos Keramidas } else { 2561f3d67aaSGiorgos Keramidas /* Find the maximum number of possible protocols. */ 2571f3d67aaSGiorgos Keramidas while (getprotoent() != NULL) 2581f3d67aaSGiorgos Keramidas proto_count++; 2591f3d67aaSGiorgos Keramidas endprotoent(); 2601f3d67aaSGiorgos Keramidas } 2611f3d67aaSGiorgos Keramidas 2621f3d67aaSGiorgos Keramidas if ((protos = malloc(sizeof(int) * proto_count)) == NULL) 2631f3d67aaSGiorgos Keramidas err(1, "malloc"); 2641f3d67aaSGiorgos Keramidas numprotos = proto_count; 2651f3d67aaSGiorgos Keramidas } 2661f3d67aaSGiorgos Keramidas 2671f3d67aaSGiorgos Keramidas static int 2681f3d67aaSGiorgos Keramidas parse_protos(char *protospec) 2691f3d67aaSGiorgos Keramidas { 2701f3d67aaSGiorgos Keramidas char *prot; 2711f3d67aaSGiorgos Keramidas int proto_type, proto_index; 2721f3d67aaSGiorgos Keramidas 2731f3d67aaSGiorgos Keramidas if (protospec == NULL) 2741f3d67aaSGiorgos Keramidas return (-1); 2751f3d67aaSGiorgos Keramidas 2761f3d67aaSGiorgos Keramidas init_protos(0); 2771f3d67aaSGiorgos Keramidas proto_index = 0; 278b8e20e2dSHiroki Sato while ((prot = strsep(&protospec, ",")) != NULL) { 2791f3d67aaSGiorgos Keramidas if (strlen(prot) == 0) 2801f3d67aaSGiorgos Keramidas continue; 2811f3d67aaSGiorgos Keramidas proto_type = get_proto_type(prot); 2821f3d67aaSGiorgos Keramidas if (proto_type != -1) 2831f3d67aaSGiorgos Keramidas protos[proto_index++] = proto_type; 2841f3d67aaSGiorgos Keramidas } 2851f3d67aaSGiorgos Keramidas numprotos = proto_index; 2861f3d67aaSGiorgos Keramidas return (proto_index); 2871f3d67aaSGiorgos Keramidas } 2881f3d67aaSGiorgos Keramidas 289ca007d91SDag-Erling Smørgrav static void 290ca007d91SDag-Erling Smørgrav parse_ports(const char *portspec) 291ca007d91SDag-Erling Smørgrav { 292ca007d91SDag-Erling Smørgrav const char *p, *q; 293ca007d91SDag-Erling Smørgrav int port, end; 294ca007d91SDag-Erling Smørgrav 295ca007d91SDag-Erling Smørgrav if (ports == NULL) 2969efed1e6SRobert Drehmel if ((ports = calloc(65536 / INT_BIT, sizeof(int))) == NULL) 297ca007d91SDag-Erling Smørgrav err(1, "calloc()"); 298ca007d91SDag-Erling Smørgrav p = portspec; 299ca007d91SDag-Erling Smørgrav while (*p != '\0') { 300ca007d91SDag-Erling Smørgrav if (!isdigit(*p)) 301ca007d91SDag-Erling Smørgrav errx(1, "syntax error in port range"); 302ca007d91SDag-Erling Smørgrav for (q = p; *q != '\0' && isdigit(*q); ++q) 303ca007d91SDag-Erling Smørgrav /* nothing */ ; 304ca007d91SDag-Erling Smørgrav for (port = 0; p < q; ++p) 305ca007d91SDag-Erling Smørgrav port = port * 10 + digittoint(*p); 306ca007d91SDag-Erling Smørgrav if (port < 0 || port > 65535) 307ca007d91SDag-Erling Smørgrav errx(1, "invalid port number"); 308ca007d91SDag-Erling Smørgrav SET_PORT(port); 309ca007d91SDag-Erling Smørgrav switch (*p) { 310ca007d91SDag-Erling Smørgrav case '-': 311ca007d91SDag-Erling Smørgrav ++p; 312ca007d91SDag-Erling Smørgrav break; 313ca007d91SDag-Erling Smørgrav case ',': 314ca007d91SDag-Erling Smørgrav ++p; 315ca007d91SDag-Erling Smørgrav /* fall through */ 316ca007d91SDag-Erling Smørgrav case '\0': 317ca007d91SDag-Erling Smørgrav default: 318ca007d91SDag-Erling Smørgrav continue; 319ca007d91SDag-Erling Smørgrav } 320ca007d91SDag-Erling Smørgrav for (q = p; *q != '\0' && isdigit(*q); ++q) 321ca007d91SDag-Erling Smørgrav /* nothing */ ; 322ca007d91SDag-Erling Smørgrav for (end = 0; p < q; ++p) 323ca007d91SDag-Erling Smørgrav end = end * 10 + digittoint(*p); 324ca007d91SDag-Erling Smørgrav if (end < port || end > 65535) 325ca007d91SDag-Erling Smørgrav errx(1, "invalid port number"); 326ca007d91SDag-Erling Smørgrav while (port++ < end) 327ca007d91SDag-Erling Smørgrav SET_PORT(port); 328ca007d91SDag-Erling Smørgrav if (*p == ',') 329ca007d91SDag-Erling Smørgrav ++p; 330ca007d91SDag-Erling Smørgrav } 331ca007d91SDag-Erling Smørgrav } 332ca007d91SDag-Erling Smørgrav 333ca007d91SDag-Erling Smørgrav static void 334b8e20e2dSHiroki Sato sockaddr(struct sockaddr_storage *ss, int af, void *addr, int port) 335ca007d91SDag-Erling Smørgrav { 336ca007d91SDag-Erling Smørgrav struct sockaddr_in *sin4; 337ca007d91SDag-Erling Smørgrav struct sockaddr_in6 *sin6; 338ca007d91SDag-Erling Smørgrav 339b8e20e2dSHiroki Sato bzero(ss, sizeof(*ss)); 340ca007d91SDag-Erling Smørgrav switch (af) { 341ca007d91SDag-Erling Smørgrav case AF_INET: 342b8e20e2dSHiroki Sato sin4 = sstosin(ss); 343b8e20e2dSHiroki Sato sin4->sin_len = sizeof(*sin4); 344ca007d91SDag-Erling Smørgrav sin4->sin_family = af; 345ca007d91SDag-Erling Smørgrav sin4->sin_port = port; 346ca007d91SDag-Erling Smørgrav sin4->sin_addr = *(struct in_addr *)addr; 347ca007d91SDag-Erling Smørgrav break; 348ca007d91SDag-Erling Smørgrav case AF_INET6: 349b8e20e2dSHiroki Sato sin6 = sstosin6(ss); 350b8e20e2dSHiroki Sato sin6->sin6_len = sizeof(*sin6); 351ca007d91SDag-Erling Smørgrav sin6->sin6_family = af; 352ca007d91SDag-Erling Smørgrav sin6->sin6_port = port; 353ca007d91SDag-Erling Smørgrav sin6->sin6_addr = *(struct in6_addr *)addr; 354b8e20e2dSHiroki Sato #define s6_addr16 __u6_addr.__u6_addr16 355b8e20e2dSHiroki Sato if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 356b8e20e2dSHiroki Sato sin6->sin6_scope_id = 357b8e20e2dSHiroki Sato ntohs(sin6->sin6_addr.s6_addr16[1]); 358b8e20e2dSHiroki Sato sin6->sin6_addr.s6_addr16[1] = 0; 359b8e20e2dSHiroki Sato } 360ca007d91SDag-Erling Smørgrav break; 361ca007d91SDag-Erling Smørgrav default: 362ca007d91SDag-Erling Smørgrav abort(); 363ca007d91SDag-Erling Smørgrav } 364ca007d91SDag-Erling Smørgrav } 365ca007d91SDag-Erling Smørgrav 366ca007d91SDag-Erling Smørgrav static void 367bedcf91dSMichael Tuexen free_socket(struct sock *sock) 368bedcf91dSMichael Tuexen { 369bedcf91dSMichael Tuexen struct addr *cur, *next; 370bedcf91dSMichael Tuexen 371bedcf91dSMichael Tuexen cur = sock->laddr; 372bedcf91dSMichael Tuexen while (cur != NULL) { 373bedcf91dSMichael Tuexen next = cur->next; 374bedcf91dSMichael Tuexen free(cur); 375bedcf91dSMichael Tuexen cur = next; 376bedcf91dSMichael Tuexen } 377bedcf91dSMichael Tuexen cur = sock->faddr; 378bedcf91dSMichael Tuexen while (cur != NULL) { 379bedcf91dSMichael Tuexen next = cur->next; 380bedcf91dSMichael Tuexen free(cur); 381bedcf91dSMichael Tuexen cur = next; 382bedcf91dSMichael Tuexen } 383bedcf91dSMichael Tuexen free(sock); 384bedcf91dSMichael Tuexen } 385bedcf91dSMichael Tuexen 386bedcf91dSMichael Tuexen static void 387d5b4aa90SMichael Tuexen gather_sctp(void) 388d5b4aa90SMichael Tuexen { 389d5b4aa90SMichael Tuexen struct sock *sock; 390d5b4aa90SMichael Tuexen struct addr *laddr, *prev_laddr, *faddr, *prev_faddr; 391d5b4aa90SMichael Tuexen struct xsctp_inpcb *xinpcb; 392d5b4aa90SMichael Tuexen struct xsctp_tcb *xstcb; 393d5b4aa90SMichael Tuexen struct xsctp_raddr *xraddr; 394d5b4aa90SMichael Tuexen struct xsctp_laddr *xladdr; 395d5b4aa90SMichael Tuexen const char *varname; 396d5b4aa90SMichael Tuexen size_t len, offset; 397d5b4aa90SMichael Tuexen char *buf; 398a83d596fSGleb Smirnoff int vflag; 399d5b4aa90SMichael Tuexen int no_stcb, local_all_loopback, foreign_all_loopback; 400d5b4aa90SMichael Tuexen 401d5b4aa90SMichael Tuexen vflag = 0; 402d5b4aa90SMichael Tuexen if (opt_4) 403d5b4aa90SMichael Tuexen vflag |= INP_IPV4; 404d5b4aa90SMichael Tuexen if (opt_6) 405d5b4aa90SMichael Tuexen vflag |= INP_IPV6; 406d5b4aa90SMichael Tuexen 407d5b4aa90SMichael Tuexen varname = "net.inet.sctp.assoclist"; 408c5a2d8c5SRyan Moeller if (cap_sysctlbyname(capsysctl, varname, 0, &len, 0, 0) < 0) { 409d5b4aa90SMichael Tuexen if (errno != ENOENT) 410c5a2d8c5SRyan Moeller err(1, "cap_sysctlbyname()"); 411d5b4aa90SMichael Tuexen return; 412d5b4aa90SMichael Tuexen } 413d5b4aa90SMichael Tuexen if ((buf = (char *)malloc(len)) == NULL) { 414d5b4aa90SMichael Tuexen err(1, "malloc()"); 415d5b4aa90SMichael Tuexen return; 416d5b4aa90SMichael Tuexen } 417c5a2d8c5SRyan Moeller if (cap_sysctlbyname(capsysctl, varname, buf, &len, 0, 0) < 0) { 418c5a2d8c5SRyan Moeller err(1, "cap_sysctlbyname()"); 419d5b4aa90SMichael Tuexen free(buf); 420d5b4aa90SMichael Tuexen return; 421d5b4aa90SMichael Tuexen } 422d5b4aa90SMichael Tuexen xinpcb = (struct xsctp_inpcb *)(void *)buf; 423d5b4aa90SMichael Tuexen offset = sizeof(struct xsctp_inpcb); 424d5b4aa90SMichael Tuexen while ((offset < len) && (xinpcb->last == 0)) { 425d5b4aa90SMichael Tuexen if ((sock = calloc(1, sizeof *sock)) == NULL) 426d5b4aa90SMichael Tuexen err(1, "malloc()"); 427d5b4aa90SMichael Tuexen sock->socket = xinpcb->socket; 428d5b4aa90SMichael Tuexen sock->proto = IPPROTO_SCTP; 429d5b4aa90SMichael Tuexen sock->protoname = "sctp"; 430c1eb13c7SMichael Tuexen if (xinpcb->maxqlen == 0) 4316414db1bSMichael Tuexen sock->state = SCTP_CLOSED; 4326414db1bSMichael Tuexen else 4336414db1bSMichael Tuexen sock->state = SCTP_LISTEN; 434d5b4aa90SMichael Tuexen if (xinpcb->flags & SCTP_PCB_FLAGS_BOUND_V6) { 435d5b4aa90SMichael Tuexen sock->family = AF_INET6; 436edc9c7fcSMichael Tuexen /* 437edc9c7fcSMichael Tuexen * Currently there is no way to distinguish between 438edc9c7fcSMichael Tuexen * IPv6 only sockets or dual family sockets. 439edc9c7fcSMichael Tuexen * So mark it as dual socket. 440edc9c7fcSMichael Tuexen */ 441edc9c7fcSMichael Tuexen sock->vflag = INP_IPV6 | INP_IPV4; 442d5b4aa90SMichael Tuexen } else { 443d5b4aa90SMichael Tuexen sock->family = AF_INET; 444d5b4aa90SMichael Tuexen sock->vflag = INP_IPV4; 445d5b4aa90SMichael Tuexen } 446d5b4aa90SMichael Tuexen prev_laddr = NULL; 447d5b4aa90SMichael Tuexen local_all_loopback = 1; 448d5b4aa90SMichael Tuexen while (offset < len) { 449d5b4aa90SMichael Tuexen xladdr = (struct xsctp_laddr *)(void *)(buf + offset); 450d5b4aa90SMichael Tuexen offset += sizeof(struct xsctp_laddr); 451d5b4aa90SMichael Tuexen if (xladdr->last == 1) 452d5b4aa90SMichael Tuexen break; 453d5b4aa90SMichael Tuexen if ((laddr = calloc(1, sizeof(struct addr))) == NULL) 454d5b4aa90SMichael Tuexen err(1, "malloc()"); 455d5b4aa90SMichael Tuexen switch (xladdr->address.sa.sa_family) { 456d5b4aa90SMichael Tuexen case AF_INET: 457d5b4aa90SMichael Tuexen #define __IN_IS_ADDR_LOOPBACK(pina) \ 458d5b4aa90SMichael Tuexen ((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) 45927569d01SRenato Botelho if (!__IN_IS_ADDR_LOOPBACK( 46027569d01SRenato Botelho &xladdr->address.sin.sin_addr)) 461d5b4aa90SMichael Tuexen local_all_loopback = 0; 462d5b4aa90SMichael Tuexen #undef __IN_IS_ADDR_LOOPBACK 46327569d01SRenato Botelho sockaddr(&laddr->address, AF_INET, 464d5b4aa90SMichael Tuexen &xladdr->address.sin.sin_addr, 465d5b4aa90SMichael Tuexen htons(xinpcb->local_port)); 466d5b4aa90SMichael Tuexen break; 467d5b4aa90SMichael Tuexen case AF_INET6: 46827569d01SRenato Botelho if (!IN6_IS_ADDR_LOOPBACK( 46927569d01SRenato Botelho &xladdr->address.sin6.sin6_addr)) 470d5b4aa90SMichael Tuexen local_all_loopback = 0; 47127569d01SRenato Botelho sockaddr(&laddr->address, AF_INET6, 472d5b4aa90SMichael Tuexen &xladdr->address.sin6.sin6_addr, 473d5b4aa90SMichael Tuexen htons(xinpcb->local_port)); 474d5b4aa90SMichael Tuexen break; 475d5b4aa90SMichael Tuexen default: 476463a577bSEitan Adler errx(1, "address family %d not supported", 477d5b4aa90SMichael Tuexen xladdr->address.sa.sa_family); 478d5b4aa90SMichael Tuexen } 479d5b4aa90SMichael Tuexen laddr->next = NULL; 480d5b4aa90SMichael Tuexen if (prev_laddr == NULL) 481d5b4aa90SMichael Tuexen sock->laddr = laddr; 482d5b4aa90SMichael Tuexen else 483d5b4aa90SMichael Tuexen prev_laddr->next = laddr; 484d5b4aa90SMichael Tuexen prev_laddr = laddr; 485d5b4aa90SMichael Tuexen } 486d5b4aa90SMichael Tuexen if (sock->laddr == NULL) { 48727569d01SRenato Botelho if ((sock->laddr = 48827569d01SRenato Botelho calloc(1, sizeof(struct addr))) == NULL) 489d5b4aa90SMichael Tuexen err(1, "malloc()"); 490d5b4aa90SMichael Tuexen sock->laddr->address.ss_family = sock->family; 491d5b4aa90SMichael Tuexen if (sock->family == AF_INET) 49227569d01SRenato Botelho sock->laddr->address.ss_len = 49327569d01SRenato Botelho sizeof(struct sockaddr_in); 494d5b4aa90SMichael Tuexen else 49527569d01SRenato Botelho sock->laddr->address.ss_len = 49627569d01SRenato Botelho sizeof(struct sockaddr_in6); 497d5b4aa90SMichael Tuexen local_all_loopback = 0; 498d5b4aa90SMichael Tuexen } 499d5b4aa90SMichael Tuexen if ((sock->faddr = calloc(1, sizeof(struct addr))) == NULL) 500d5b4aa90SMichael Tuexen err(1, "malloc()"); 501d5b4aa90SMichael Tuexen sock->faddr->address.ss_family = sock->family; 502d5b4aa90SMichael Tuexen if (sock->family == AF_INET) 50327569d01SRenato Botelho sock->faddr->address.ss_len = 50427569d01SRenato Botelho sizeof(struct sockaddr_in); 505d5b4aa90SMichael Tuexen else 50627569d01SRenato Botelho sock->faddr->address.ss_len = 50727569d01SRenato Botelho sizeof(struct sockaddr_in6); 508d5b4aa90SMichael Tuexen no_stcb = 1; 509d5b4aa90SMichael Tuexen while (offset < len) { 510d5b4aa90SMichael Tuexen xstcb = (struct xsctp_tcb *)(void *)(buf + offset); 511d5b4aa90SMichael Tuexen offset += sizeof(struct xsctp_tcb); 512bedcf91dSMichael Tuexen if (no_stcb) { 51327569d01SRenato Botelho if (opt_l && (sock->vflag & vflag) && 514d5b4aa90SMichael Tuexen (!opt_L || !local_all_loopback) && 515d5b4aa90SMichael Tuexen ((xinpcb->flags & SCTP_PCB_FLAGS_UDPTYPE) || 516d5b4aa90SMichael Tuexen (xstcb->last == 1))) { 517a83d596fSGleb Smirnoff RB_INSERT(socks_t, &socks, sock); 518bedcf91dSMichael Tuexen } else { 519bedcf91dSMichael Tuexen free_socket(sock); 520bedcf91dSMichael Tuexen } 521d5b4aa90SMichael Tuexen } 522d5b4aa90SMichael Tuexen if (xstcb->last == 1) 523d5b4aa90SMichael Tuexen break; 524d5b4aa90SMichael Tuexen no_stcb = 0; 525d5b4aa90SMichael Tuexen if (opt_c) { 526d5b4aa90SMichael Tuexen if ((sock = calloc(1, sizeof *sock)) == NULL) 527d5b4aa90SMichael Tuexen err(1, "malloc()"); 528d5b4aa90SMichael Tuexen sock->socket = xinpcb->socket; 529d5b4aa90SMichael Tuexen sock->proto = IPPROTO_SCTP; 530d5b4aa90SMichael Tuexen sock->protoname = "sctp"; 5316414db1bSMichael Tuexen sock->state = (int)xstcb->state; 532d5b4aa90SMichael Tuexen if (xinpcb->flags & SCTP_PCB_FLAGS_BOUND_V6) { 533d5b4aa90SMichael Tuexen sock->family = AF_INET6; 534edc9c7fcSMichael Tuexen /* 535edc9c7fcSMichael Tuexen * Currently there is no way to distinguish 536edc9c7fcSMichael Tuexen * between IPv6 only sockets or dual family 537edc9c7fcSMichael Tuexen * sockets. So mark it as dual socket. 538edc9c7fcSMichael Tuexen */ 539edc9c7fcSMichael Tuexen sock->vflag = INP_IPV6 | INP_IPV4; 540d5b4aa90SMichael Tuexen } else { 541d5b4aa90SMichael Tuexen sock->family = AF_INET; 542d5b4aa90SMichael Tuexen sock->vflag = INP_IPV4; 543d5b4aa90SMichael Tuexen } 544d5b4aa90SMichael Tuexen } 545d5b4aa90SMichael Tuexen prev_laddr = NULL; 546d5b4aa90SMichael Tuexen local_all_loopback = 1; 547d5b4aa90SMichael Tuexen while (offset < len) { 54827569d01SRenato Botelho xladdr = (struct xsctp_laddr *)(void *)(buf + 54927569d01SRenato Botelho offset); 550d5b4aa90SMichael Tuexen offset += sizeof(struct xsctp_laddr); 551d5b4aa90SMichael Tuexen if (xladdr->last == 1) 552d5b4aa90SMichael Tuexen break; 553d5b4aa90SMichael Tuexen if (!opt_c) 554d5b4aa90SMichael Tuexen continue; 55527569d01SRenato Botelho laddr = calloc(1, sizeof(struct addr)); 55627569d01SRenato Botelho if (laddr == NULL) 557d5b4aa90SMichael Tuexen err(1, "malloc()"); 558d5b4aa90SMichael Tuexen switch (xladdr->address.sa.sa_family) { 559d5b4aa90SMichael Tuexen case AF_INET: 560d5b4aa90SMichael Tuexen #define __IN_IS_ADDR_LOOPBACK(pina) \ 561d5b4aa90SMichael Tuexen ((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) 56227569d01SRenato Botelho if (!__IN_IS_ADDR_LOOPBACK( 56327569d01SRenato Botelho &xladdr->address.sin.sin_addr)) 564d5b4aa90SMichael Tuexen local_all_loopback = 0; 565d5b4aa90SMichael Tuexen #undef __IN_IS_ADDR_LOOPBACK 56627569d01SRenato Botelho sockaddr(&laddr->address, AF_INET, 567d5b4aa90SMichael Tuexen &xladdr->address.sin.sin_addr, 568d5b4aa90SMichael Tuexen htons(xstcb->local_port)); 569d5b4aa90SMichael Tuexen break; 570d5b4aa90SMichael Tuexen case AF_INET6: 57127569d01SRenato Botelho if (!IN6_IS_ADDR_LOOPBACK( 57227569d01SRenato Botelho &xladdr->address.sin6.sin6_addr)) 573d5b4aa90SMichael Tuexen local_all_loopback = 0; 57427569d01SRenato Botelho sockaddr(&laddr->address, AF_INET6, 575d5b4aa90SMichael Tuexen &xladdr->address.sin6.sin6_addr, 576d5b4aa90SMichael Tuexen htons(xstcb->local_port)); 577d5b4aa90SMichael Tuexen break; 578d5b4aa90SMichael Tuexen default: 57927569d01SRenato Botelho errx(1, 58027569d01SRenato Botelho "address family %d not supported", 581d5b4aa90SMichael Tuexen xladdr->address.sa.sa_family); 582d5b4aa90SMichael Tuexen } 583d5b4aa90SMichael Tuexen laddr->next = NULL; 584d5b4aa90SMichael Tuexen if (prev_laddr == NULL) 585d5b4aa90SMichael Tuexen sock->laddr = laddr; 586d5b4aa90SMichael Tuexen else 587d5b4aa90SMichael Tuexen prev_laddr->next = laddr; 588d5b4aa90SMichael Tuexen prev_laddr = laddr; 589d5b4aa90SMichael Tuexen } 590d5b4aa90SMichael Tuexen prev_faddr = NULL; 591d5b4aa90SMichael Tuexen foreign_all_loopback = 1; 592d5b4aa90SMichael Tuexen while (offset < len) { 59327569d01SRenato Botelho xraddr = (struct xsctp_raddr *)(void *)(buf + 59427569d01SRenato Botelho offset); 595d5b4aa90SMichael Tuexen offset += sizeof(struct xsctp_raddr); 596d5b4aa90SMichael Tuexen if (xraddr->last == 1) 597d5b4aa90SMichael Tuexen break; 598d5b4aa90SMichael Tuexen if (!opt_c) 599d5b4aa90SMichael Tuexen continue; 60027569d01SRenato Botelho faddr = calloc(1, sizeof(struct addr)); 60127569d01SRenato Botelho if (faddr == NULL) 602d5b4aa90SMichael Tuexen err(1, "malloc()"); 603d5b4aa90SMichael Tuexen switch (xraddr->address.sa.sa_family) { 604d5b4aa90SMichael Tuexen case AF_INET: 605d5b4aa90SMichael Tuexen #define __IN_IS_ADDR_LOOPBACK(pina) \ 606d5b4aa90SMichael Tuexen ((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) 60727569d01SRenato Botelho if (!__IN_IS_ADDR_LOOPBACK( 60827569d01SRenato Botelho &xraddr->address.sin.sin_addr)) 609d5b4aa90SMichael Tuexen foreign_all_loopback = 0; 610d5b4aa90SMichael Tuexen #undef __IN_IS_ADDR_LOOPBACK 61127569d01SRenato Botelho sockaddr(&faddr->address, AF_INET, 612d5b4aa90SMichael Tuexen &xraddr->address.sin.sin_addr, 613d5b4aa90SMichael Tuexen htons(xstcb->remote_port)); 614d5b4aa90SMichael Tuexen break; 615d5b4aa90SMichael Tuexen case AF_INET6: 61627569d01SRenato Botelho if (!IN6_IS_ADDR_LOOPBACK( 61727569d01SRenato Botelho &xraddr->address.sin6.sin6_addr)) 618d5b4aa90SMichael Tuexen foreign_all_loopback = 0; 61927569d01SRenato Botelho sockaddr(&faddr->address, AF_INET6, 620d5b4aa90SMichael Tuexen &xraddr->address.sin6.sin6_addr, 621d5b4aa90SMichael Tuexen htons(xstcb->remote_port)); 622d5b4aa90SMichael Tuexen break; 623d5b4aa90SMichael Tuexen default: 62427569d01SRenato Botelho errx(1, 62527569d01SRenato Botelho "address family %d not supported", 626d5b4aa90SMichael Tuexen xraddr->address.sa.sa_family); 627d5b4aa90SMichael Tuexen } 62849b836f2SMichael Tuexen faddr->encaps_port = xraddr->encaps_port; 629e389705eSMichael Tuexen faddr->state = xraddr->state; 630d5b4aa90SMichael Tuexen faddr->next = NULL; 631d5b4aa90SMichael Tuexen if (prev_faddr == NULL) 632d5b4aa90SMichael Tuexen sock->faddr = faddr; 633d5b4aa90SMichael Tuexen else 634d5b4aa90SMichael Tuexen prev_faddr->next = faddr; 635d5b4aa90SMichael Tuexen prev_faddr = faddr; 636d5b4aa90SMichael Tuexen } 637bedcf91dSMichael Tuexen if (opt_c) { 638edc9c7fcSMichael Tuexen if ((sock->vflag & vflag) && 639edc9c7fcSMichael Tuexen (!opt_L || 64027569d01SRenato Botelho !(local_all_loopback || 64127569d01SRenato Botelho foreign_all_loopback))) { 642a83d596fSGleb Smirnoff RB_INSERT(socks_t, &socks, sock); 643bedcf91dSMichael Tuexen } else { 644bedcf91dSMichael Tuexen free_socket(sock); 645bedcf91dSMichael Tuexen } 646d5b4aa90SMichael Tuexen } 647d5b4aa90SMichael Tuexen } 648d5b4aa90SMichael Tuexen xinpcb = (struct xsctp_inpcb *)(void *)(buf + offset); 649d5b4aa90SMichael Tuexen offset += sizeof(struct xsctp_inpcb); 650d5b4aa90SMichael Tuexen } 651d5b4aa90SMichael Tuexen free(buf); 652d5b4aa90SMichael Tuexen } 653d5b4aa90SMichael Tuexen 654d5b4aa90SMichael Tuexen static void 655ca007d91SDag-Erling Smørgrav gather_inet(int proto) 656ca007d91SDag-Erling Smørgrav { 657ca007d91SDag-Erling Smørgrav struct xinpgen *xig, *exig; 658ca007d91SDag-Erling Smørgrav struct xinpcb *xip; 659bf40d2caSGleb Smirnoff struct xtcpcb *xtp = NULL; 660ca007d91SDag-Erling Smørgrav struct xsocket *so; 661ca007d91SDag-Erling Smørgrav struct sock *sock; 662e6f718c7SMichael Tuexen struct addr *laddr, *faddr; 663ca007d91SDag-Erling Smørgrav const char *varname, *protoname; 664ca007d91SDag-Erling Smørgrav size_t len, bufsize; 665ca007d91SDag-Erling Smørgrav void *buf; 666a83d596fSGleb Smirnoff int retry, vflag; 667ca007d91SDag-Erling Smørgrav 6686eb1d5baSMichael Tuexen vflag = 0; 669ca007d91SDag-Erling Smørgrav if (opt_4) 670ca007d91SDag-Erling Smørgrav vflag |= INP_IPV4; 671ca007d91SDag-Erling Smørgrav if (opt_6) 672ca007d91SDag-Erling Smørgrav vflag |= INP_IPV6; 673ca007d91SDag-Erling Smørgrav 674ca007d91SDag-Erling Smørgrav switch (proto) { 675ca007d91SDag-Erling Smørgrav case IPPROTO_TCP: 676ca007d91SDag-Erling Smørgrav varname = "net.inet.tcp.pcblist"; 677ca007d91SDag-Erling Smørgrav protoname = "tcp"; 678ca007d91SDag-Erling Smørgrav break; 679ca007d91SDag-Erling Smørgrav case IPPROTO_UDP: 680ca007d91SDag-Erling Smørgrav varname = "net.inet.udp.pcblist"; 681ca007d91SDag-Erling Smørgrav protoname = "udp"; 682ca007d91SDag-Erling Smørgrav break; 6832cfbdf89SRuslan Ermilov case IPPROTO_DIVERT: 6842cfbdf89SRuslan Ermilov varname = "net.inet.divert.pcblist"; 6852cfbdf89SRuslan Ermilov protoname = "div"; 6862cfbdf89SRuslan Ermilov break; 687ca007d91SDag-Erling Smørgrav default: 6881f3d67aaSGiorgos Keramidas errx(1, "protocol %d not supported", proto); 689ca007d91SDag-Erling Smørgrav } 690ca007d91SDag-Erling Smørgrav 691ca007d91SDag-Erling Smørgrav buf = NULL; 692ca007d91SDag-Erling Smørgrav bufsize = 8192; 693ca007d91SDag-Erling Smørgrav retry = 5; 694ca007d91SDag-Erling Smørgrav do { 695ca007d91SDag-Erling Smørgrav for (;;) { 696ca007d91SDag-Erling Smørgrav if ((buf = realloc(buf, bufsize)) == NULL) 697ca007d91SDag-Erling Smørgrav err(1, "realloc()"); 698ca007d91SDag-Erling Smørgrav len = bufsize; 699c5a2d8c5SRyan Moeller if (cap_sysctlbyname(capsysctl, varname, buf, &len, 700c5a2d8c5SRyan Moeller NULL, 0) == 0) 701ca007d91SDag-Erling Smørgrav break; 7024b2a3d41SRuslan Ermilov if (errno == ENOENT) 7034b2a3d41SRuslan Ermilov goto out; 704003e7e49SMikolaj Golub if (errno != ENOMEM || len != bufsize) 705c5a2d8c5SRyan Moeller err(1, "cap_sysctlbyname()"); 706ca007d91SDag-Erling Smørgrav bufsize *= 2; 707ca007d91SDag-Erling Smørgrav } 708ca007d91SDag-Erling Smørgrav xig = (struct xinpgen *)buf; 7096dbe8d53SRobert Drehmel exig = (struct xinpgen *)(void *) 7106dbe8d53SRobert Drehmel ((char *)buf + len - sizeof *exig); 71108e77283SAlexander V. Chernikov enforce_ksize(xig->xig_len, struct xinpgen); 71208e77283SAlexander V. Chernikov enforce_ksize(exig->xig_len, struct xinpgen); 713ca007d91SDag-Erling Smørgrav } while (xig->xig_gen != exig->xig_gen && retry--); 714ca007d91SDag-Erling Smørgrav 715ca007d91SDag-Erling Smørgrav if (xig->xig_gen != exig->xig_gen && opt_v) 716ca007d91SDag-Erling Smørgrav warnx("warning: data may be inconsistent"); 717ca007d91SDag-Erling Smørgrav 718ca007d91SDag-Erling Smørgrav for (;;) { 7196dbe8d53SRobert Drehmel xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len); 720ca007d91SDag-Erling Smørgrav if (xig >= exig) 721ca007d91SDag-Erling Smørgrav break; 722ca007d91SDag-Erling Smørgrav switch (proto) { 723ca007d91SDag-Erling Smørgrav case IPPROTO_TCP: 724cc65eb4eSGleb Smirnoff xtp = (struct xtcpcb *)xig; 725cc65eb4eSGleb Smirnoff xip = &xtp->xt_inp; 72608e77283SAlexander V. Chernikov if (!check_ksize(xtp->xt_len, struct xtcpcb)) 727ca007d91SDag-Erling Smørgrav goto out; 728cc65eb4eSGleb Smirnoff protoname = xtp->t_flags & TF_TOE ? "toe" : "tcp"; 729ca007d91SDag-Erling Smørgrav break; 730ca007d91SDag-Erling Smørgrav case IPPROTO_UDP: 7312cfbdf89SRuslan Ermilov case IPPROTO_DIVERT: 732cc65eb4eSGleb Smirnoff xip = (struct xinpcb *)xig; 73308e77283SAlexander V. Chernikov if (!check_ksize(xip->xi_len, struct xinpcb)) 734ca007d91SDag-Erling Smørgrav goto out; 735ca007d91SDag-Erling Smørgrav break; 736ca007d91SDag-Erling Smørgrav default: 7371f3d67aaSGiorgos Keramidas errx(1, "protocol %d not supported", proto); 738ca007d91SDag-Erling Smørgrav } 739cc65eb4eSGleb Smirnoff so = &xip->xi_socket; 740cc65eb4eSGleb Smirnoff if ((xip->inp_vflag & vflag) == 0) 741ca007d91SDag-Erling Smørgrav continue; 742cc65eb4eSGleb Smirnoff if (xip->inp_vflag & INP_IPV4) { 743cc65eb4eSGleb Smirnoff if ((xip->inp_fport == 0 && !opt_l) || 744cc65eb4eSGleb Smirnoff (xip->inp_fport != 0 && !opt_c)) 7451e6690e5SDag-Erling Smørgrav continue; 7469b6ca892SBruce M Simpson #define __IN_IS_ADDR_LOOPBACK(pina) \ 7479b6ca892SBruce M Simpson ((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) 7489b6ca892SBruce M Simpson if (opt_L && 749cc65eb4eSGleb Smirnoff (__IN_IS_ADDR_LOOPBACK(&xip->inp_faddr) || 750cc65eb4eSGleb Smirnoff __IN_IS_ADDR_LOOPBACK(&xip->inp_laddr))) 7519b6ca892SBruce M Simpson continue; 7529b6ca892SBruce M Simpson #undef __IN_IS_ADDR_LOOPBACK 753cc65eb4eSGleb Smirnoff } else if (xip->inp_vflag & INP_IPV6) { 754cc65eb4eSGleb Smirnoff if ((xip->inp_fport == 0 && !opt_l) || 755cc65eb4eSGleb Smirnoff (xip->inp_fport != 0 && !opt_c)) 7561e6690e5SDag-Erling Smørgrav continue; 7579b6ca892SBruce M Simpson if (opt_L && 758cc65eb4eSGleb Smirnoff (IN6_IS_ADDR_LOOPBACK(&xip->in6p_faddr) || 759cc65eb4eSGleb Smirnoff IN6_IS_ADDR_LOOPBACK(&xip->in6p_laddr))) 7609b6ca892SBruce M Simpson continue; 7611e6690e5SDag-Erling Smørgrav } else { 7621e6690e5SDag-Erling Smørgrav if (opt_v) 763cc65eb4eSGleb Smirnoff warnx("invalid vflag 0x%x", xip->inp_vflag); 7641e6690e5SDag-Erling Smørgrav continue; 7651e6690e5SDag-Erling Smørgrav } 766b8e20e2dSHiroki Sato if ((sock = calloc(1, sizeof(*sock))) == NULL) 767ca007d91SDag-Erling Smørgrav err(1, "malloc()"); 768e6f718c7SMichael Tuexen if ((laddr = calloc(1, sizeof *laddr)) == NULL) 769e6f718c7SMichael Tuexen err(1, "malloc()"); 770e6f718c7SMichael Tuexen if ((faddr = calloc(1, sizeof *faddr)) == NULL) 771e6f718c7SMichael Tuexen err(1, "malloc()"); 772ca007d91SDag-Erling Smørgrav sock->socket = so->xso_so; 773051a2132SMark Johnston sock->splice_socket = so->so_splice_so; 774ca007d91SDag-Erling Smørgrav sock->proto = proto; 7755f64777aSMichael Tuexen sock->inp_gencnt = xip->inp_gencnt; 776a471d2b4SMark Johnston sock->fibnum = so->so_fibnum; 777cc65eb4eSGleb Smirnoff if (xip->inp_vflag & INP_IPV4) { 778ca007d91SDag-Erling Smørgrav sock->family = AF_INET; 779e6f718c7SMichael Tuexen sockaddr(&laddr->address, sock->family, 780cc65eb4eSGleb Smirnoff &xip->inp_laddr, xip->inp_lport); 781e6f718c7SMichael Tuexen sockaddr(&faddr->address, sock->family, 782cc65eb4eSGleb Smirnoff &xip->inp_faddr, xip->inp_fport); 783cc65eb4eSGleb Smirnoff } else if (xip->inp_vflag & INP_IPV6) { 784ca007d91SDag-Erling Smørgrav sock->family = AF_INET6; 785e6f718c7SMichael Tuexen sockaddr(&laddr->address, sock->family, 786cc65eb4eSGleb Smirnoff &xip->in6p_laddr, xip->inp_lport); 787e6f718c7SMichael Tuexen sockaddr(&faddr->address, sock->family, 788cc65eb4eSGleb Smirnoff &xip->in6p_faddr, xip->inp_fport); 789ca007d91SDag-Erling Smørgrav } 7909e644c23SMichael Tuexen if (proto == IPPROTO_TCP) 7919e644c23SMichael Tuexen faddr->encaps_port = xtp->xt_encaps_port; 792e6f718c7SMichael Tuexen laddr->next = NULL; 793e6f718c7SMichael Tuexen faddr->next = NULL; 794e6f718c7SMichael Tuexen sock->laddr = laddr; 795e6f718c7SMichael Tuexen sock->faddr = faddr; 796cc65eb4eSGleb Smirnoff sock->vflag = xip->inp_vflag; 797e5cccc35SMichael Tuexen if (proto == IPPROTO_TCP) { 798cc65eb4eSGleb Smirnoff sock->state = xtp->t_state; 799e5cccc35SMichael Tuexen memcpy(sock->stack, xtp->xt_stack, 800e5cccc35SMichael Tuexen TCP_FUNCTION_NAME_LEN_MAX); 8012ac089d0SMichael Tuexen memcpy(sock->cc, xtp->xt_cc, TCP_CA_NAME_MAX); 802e5cccc35SMichael Tuexen } 803ca007d91SDag-Erling Smørgrav sock->protoname = protoname; 804a83d596fSGleb Smirnoff if (sock->socket != 0) 805a83d596fSGleb Smirnoff RB_INSERT(socks_t, &socks, sock); 806a83d596fSGleb Smirnoff else 807a83d596fSGleb Smirnoff SLIST_INSERT_HEAD(&nosocks, sock, socket_list); 808ca007d91SDag-Erling Smørgrav } 809ca007d91SDag-Erling Smørgrav out: 810ca007d91SDag-Erling Smørgrav free(buf); 811ca007d91SDag-Erling Smørgrav } 812ca007d91SDag-Erling Smørgrav 813ca007d91SDag-Erling Smørgrav static void 814ca007d91SDag-Erling Smørgrav gather_unix(int proto) 815ca007d91SDag-Erling Smørgrav { 816ca007d91SDag-Erling Smørgrav struct xunpgen *xug, *exug; 817ca007d91SDag-Erling Smørgrav struct xunpcb *xup; 818ca007d91SDag-Erling Smørgrav struct sock *sock; 819e6f718c7SMichael Tuexen struct addr *laddr, *faddr; 820ca007d91SDag-Erling Smørgrav const char *varname, *protoname; 821ca007d91SDag-Erling Smørgrav size_t len, bufsize; 822ca007d91SDag-Erling Smørgrav void *buf; 823a83d596fSGleb Smirnoff int retry; 824ca007d91SDag-Erling Smørgrav 825ca007d91SDag-Erling Smørgrav switch (proto) { 826ca007d91SDag-Erling Smørgrav case SOCK_STREAM: 827ca007d91SDag-Erling Smørgrav varname = "net.local.stream.pcblist"; 828ca007d91SDag-Erling Smørgrav protoname = "stream"; 829ca007d91SDag-Erling Smørgrav break; 830ca007d91SDag-Erling Smørgrav case SOCK_DGRAM: 831ca007d91SDag-Erling Smørgrav varname = "net.local.dgram.pcblist"; 832ca007d91SDag-Erling Smørgrav protoname = "dgram"; 833ca007d91SDag-Erling Smørgrav break; 834b8e20e2dSHiroki Sato case SOCK_SEQPACKET: 835b8e20e2dSHiroki Sato varname = "net.local.seqpacket.pcblist"; 836b8e20e2dSHiroki Sato protoname = "seqpac"; 837b8e20e2dSHiroki Sato break; 838ca007d91SDag-Erling Smørgrav default: 839ca007d91SDag-Erling Smørgrav abort(); 840ca007d91SDag-Erling Smørgrav } 841ca007d91SDag-Erling Smørgrav buf = NULL; 842ca007d91SDag-Erling Smørgrav bufsize = 8192; 843ca007d91SDag-Erling Smørgrav retry = 5; 844ca007d91SDag-Erling Smørgrav do { 845ca007d91SDag-Erling Smørgrav for (;;) { 846ca007d91SDag-Erling Smørgrav if ((buf = realloc(buf, bufsize)) == NULL) 847ca007d91SDag-Erling Smørgrav err(1, "realloc()"); 848ca007d91SDag-Erling Smørgrav len = bufsize; 849c5a2d8c5SRyan Moeller if (cap_sysctlbyname(capsysctl, varname, buf, &len, 850c5a2d8c5SRyan Moeller NULL, 0) == 0) 851ca007d91SDag-Erling Smørgrav break; 852003e7e49SMikolaj Golub if (errno != ENOMEM || len != bufsize) 853c5a2d8c5SRyan Moeller err(1, "cap_sysctlbyname()"); 854ca007d91SDag-Erling Smørgrav bufsize *= 2; 855ca007d91SDag-Erling Smørgrav } 856ca007d91SDag-Erling Smørgrav xug = (struct xunpgen *)buf; 8576dbe8d53SRobert Drehmel exug = (struct xunpgen *)(void *) 858b8e20e2dSHiroki Sato ((char *)buf + len - sizeof(*exug)); 85908e77283SAlexander V. Chernikov if (!check_ksize(xug->xug_len, struct xunpgen) || 86008e77283SAlexander V. Chernikov !check_ksize(exug->xug_len, struct xunpgen)) 861ca007d91SDag-Erling Smørgrav goto out; 862ca007d91SDag-Erling Smørgrav } while (xug->xug_gen != exug->xug_gen && retry--); 863ca007d91SDag-Erling Smørgrav 864ca007d91SDag-Erling Smørgrav if (xug->xug_gen != exug->xug_gen && opt_v) 865ca007d91SDag-Erling Smørgrav warnx("warning: data may be inconsistent"); 866ca007d91SDag-Erling Smørgrav 867ca007d91SDag-Erling Smørgrav for (;;) { 8686dbe8d53SRobert Drehmel xug = (struct xunpgen *)(void *)((char *)xug + xug->xug_len); 869ca007d91SDag-Erling Smørgrav if (xug >= exug) 870ca007d91SDag-Erling Smørgrav break; 871ca007d91SDag-Erling Smørgrav xup = (struct xunpcb *)xug; 87208e77283SAlexander V. Chernikov if (!check_ksize(xup->xu_len, struct xunpcb)) 873ca007d91SDag-Erling Smørgrav goto out; 874f38b68aeSBrooks Davis if ((xup->unp_conn == 0 && !opt_l) || 875f38b68aeSBrooks Davis (xup->unp_conn != 0 && !opt_c)) 8761e6690e5SDag-Erling Smørgrav continue; 877b8e20e2dSHiroki Sato if ((sock = calloc(1, sizeof(*sock))) == NULL) 878ca007d91SDag-Erling Smørgrav err(1, "malloc()"); 879e6f718c7SMichael Tuexen if ((laddr = calloc(1, sizeof *laddr)) == NULL) 880e6f718c7SMichael Tuexen err(1, "malloc()"); 881e6f718c7SMichael Tuexen if ((faddr = calloc(1, sizeof *faddr)) == NULL) 882e6f718c7SMichael Tuexen err(1, "malloc()"); 883ca007d91SDag-Erling Smørgrav sock->socket = xup->xu_socket.xso_so; 884ca007d91SDag-Erling Smørgrav sock->pcb = xup->xu_unpp; 885ca007d91SDag-Erling Smørgrav sock->proto = proto; 886ca007d91SDag-Erling Smørgrav sock->family = AF_UNIX; 887ca007d91SDag-Erling Smørgrav sock->protoname = protoname; 8880e229f34SGleb Smirnoff if (xup->xu_addr.sun_family == AF_UNIX) 889e6f718c7SMichael Tuexen laddr->address = 8906dbe8d53SRobert Drehmel *(struct sockaddr_storage *)(void *)&xup->xu_addr; 8912c436d48SGleb Smirnoff faddr->conn = xup->unp_conn; 8922c436d48SGleb Smirnoff faddr->firstref = xup->xu_firstref; 8932c436d48SGleb Smirnoff faddr->nextref = xup->xu_nextref; 894e6f718c7SMichael Tuexen laddr->next = NULL; 895e6f718c7SMichael Tuexen faddr->next = NULL; 896e6f718c7SMichael Tuexen sock->laddr = laddr; 897e6f718c7SMichael Tuexen sock->faddr = faddr; 898a83d596fSGleb Smirnoff RB_INSERT(socks_t, &socks, sock); 899a83d596fSGleb Smirnoff RB_INSERT(pcbs_t, &pcbs, sock); 900ca007d91SDag-Erling Smørgrav } 901ca007d91SDag-Erling Smørgrav out: 902ca007d91SDag-Erling Smørgrav free(buf); 903ca007d91SDag-Erling Smørgrav } 904ca007d91SDag-Erling Smørgrav 905ca007d91SDag-Erling Smørgrav static void 906ca007d91SDag-Erling Smørgrav getfiles(void) 907ca007d91SDag-Erling Smørgrav { 9082c436d48SGleb Smirnoff struct xfile *xfiles; 909003e7e49SMikolaj Golub size_t len, olen; 910ca007d91SDag-Erling Smørgrav 911b8e20e2dSHiroki Sato olen = len = sizeof(*xfiles); 912003e7e49SMikolaj Golub if ((xfiles = malloc(len)) == NULL) 913ca007d91SDag-Erling Smørgrav err(1, "malloc()"); 914c5a2d8c5SRyan Moeller while (cap_sysctlbyname(capsysctl, "kern.file", xfiles, &len, 0, 0) 915c5a2d8c5SRyan Moeller == -1) { 916003e7e49SMikolaj Golub if (errno != ENOMEM || len != olen) 917c5a2d8c5SRyan Moeller err(1, "cap_sysctlbyname()"); 918003e7e49SMikolaj Golub olen = len *= 2; 919ca007d91SDag-Erling Smørgrav if ((xfiles = realloc(xfiles, len)) == NULL) 920ca007d91SDag-Erling Smørgrav err(1, "realloc()"); 921ca007d91SDag-Erling Smørgrav } 92208e77283SAlexander V. Chernikov if (len > 0) 92308e77283SAlexander V. Chernikov enforce_ksize(xfiles->xf_size, struct xfile); 9242c436d48SGleb Smirnoff nfiles = len / sizeof(*xfiles); 9252c436d48SGleb Smirnoff 9262c436d48SGleb Smirnoff if ((files = malloc(nfiles * sizeof(struct file))) == NULL) 9272c436d48SGleb Smirnoff err(1, "malloc()"); 9282c436d48SGleb Smirnoff 9292c436d48SGleb Smirnoff for (int i = 0; i < nfiles; i++) { 9302c436d48SGleb Smirnoff files[i].xf_data = xfiles[i].xf_data; 9312c436d48SGleb Smirnoff files[i].xf_pid = xfiles[i].xf_pid; 9322c436d48SGleb Smirnoff files[i].xf_uid = xfiles[i].xf_uid; 9332c436d48SGleb Smirnoff files[i].xf_fd = xfiles[i].xf_fd; 9342c436d48SGleb Smirnoff RB_INSERT(files_t, &ftree, &files[i]); 9352c436d48SGleb Smirnoff } 9362c436d48SGleb Smirnoff 9372c436d48SGleb Smirnoff free(xfiles); 938ca007d91SDag-Erling Smørgrav } 939ca007d91SDag-Erling Smørgrav 940ca007d91SDag-Erling Smørgrav static int 941baa7f281SMichael Tuexen printaddr(struct sockaddr_storage *ss) 942ca007d91SDag-Erling Smørgrav { 943ca007d91SDag-Erling Smørgrav struct sockaddr_un *sun; 944b8e20e2dSHiroki Sato char addrstr[NI_MAXHOST] = { '\0', '\0' }; 945b8e20e2dSHiroki Sato int error, off, port = 0; 946ca007d91SDag-Erling Smørgrav 947baa7f281SMichael Tuexen switch (ss->ss_family) { 948ca007d91SDag-Erling Smørgrav case AF_INET: 94964acb29bSMike Karels if (sstosin(ss)->sin_addr.s_addr == INADDR_ANY) 950ca007d91SDag-Erling Smørgrav addrstr[0] = '*'; 951b8e20e2dSHiroki Sato port = ntohs(sstosin(ss)->sin_port); 952ca007d91SDag-Erling Smørgrav break; 953ca007d91SDag-Erling Smørgrav case AF_INET6: 954b8e20e2dSHiroki Sato if (IN6_IS_ADDR_UNSPECIFIED(&sstosin6(ss)->sin6_addr)) 955ca007d91SDag-Erling Smørgrav addrstr[0] = '*'; 956b8e20e2dSHiroki Sato port = ntohs(sstosin6(ss)->sin6_port); 957ca007d91SDag-Erling Smørgrav break; 958ca007d91SDag-Erling Smørgrav case AF_UNIX: 959b8e20e2dSHiroki Sato sun = sstosun(ss); 960ca007d91SDag-Erling Smørgrav off = (int)((char *)&sun->sun_path - (char *)sun); 961ca007d91SDag-Erling Smørgrav return (xprintf("%.*s", sun->sun_len - off, sun->sun_path)); 962ca007d91SDag-Erling Smørgrav } 963b8e20e2dSHiroki Sato if (addrstr[0] == '\0') { 964c5a2d8c5SRyan Moeller error = cap_getnameinfo(capnet, sstosa(ss), ss->ss_len, 965c5a2d8c5SRyan Moeller addrstr, sizeof(addrstr), NULL, 0, NI_NUMERICHOST); 966b8e20e2dSHiroki Sato if (error) 967c5a2d8c5SRyan Moeller errx(1, "cap_getnameinfo()"); 968b8e20e2dSHiroki Sato } 969ca007d91SDag-Erling Smørgrav if (port == 0) 970ca007d91SDag-Erling Smørgrav return xprintf("%s:*", addrstr); 971ca007d91SDag-Erling Smørgrav else 972ca007d91SDag-Erling Smørgrav return xprintf("%s:%d", addrstr, port); 973ca007d91SDag-Erling Smørgrav } 974ca007d91SDag-Erling Smørgrav 975ca007d91SDag-Erling Smørgrav static const char * 976ca007d91SDag-Erling Smørgrav getprocname(pid_t pid) 977ca007d91SDag-Erling Smørgrav { 978ca007d91SDag-Erling Smørgrav static struct kinfo_proc proc; 979ca007d91SDag-Erling Smørgrav size_t len; 980ca007d91SDag-Erling Smørgrav int mib[4]; 981ca007d91SDag-Erling Smørgrav 982ca007d91SDag-Erling Smørgrav mib[0] = CTL_KERN; 983ca007d91SDag-Erling Smørgrav mib[1] = KERN_PROC; 984ca007d91SDag-Erling Smørgrav mib[2] = KERN_PROC_PID; 985ca007d91SDag-Erling Smørgrav mib[3] = (int)pid; 986b8e20e2dSHiroki Sato len = sizeof(proc); 987c5a2d8c5SRyan Moeller if (cap_sysctl(capsysctl, mib, nitems(mib), &proc, &len, NULL, 0) 988c5a2d8c5SRyan Moeller == -1) { 98948c513e0SMaxim Konovalov /* Do not warn if the process exits before we get its name. */ 99048c513e0SMaxim Konovalov if (errno != ESRCH) 991c5a2d8c5SRyan Moeller warn("cap_sysctl()"); 992ca007d91SDag-Erling Smørgrav return ("??"); 993ca007d91SDag-Erling Smørgrav } 994f487a6a8SEd Maste return (proc.ki_comm); 995ca007d91SDag-Erling Smørgrav } 996ca007d91SDag-Erling Smørgrav 997ae94787dSMaxime Henrion static int 99800feaafdSAndrew Thompson getprocjid(pid_t pid) 99900feaafdSAndrew Thompson { 100000feaafdSAndrew Thompson static struct kinfo_proc proc; 100100feaafdSAndrew Thompson size_t len; 100200feaafdSAndrew Thompson int mib[4]; 100300feaafdSAndrew Thompson 100400feaafdSAndrew Thompson mib[0] = CTL_KERN; 100500feaafdSAndrew Thompson mib[1] = KERN_PROC; 100600feaafdSAndrew Thompson mib[2] = KERN_PROC_PID; 100700feaafdSAndrew Thompson mib[3] = (int)pid; 1008b8e20e2dSHiroki Sato len = sizeof(proc); 1009c5a2d8c5SRyan Moeller if (cap_sysctl(capsysctl, mib, nitems(mib), &proc, &len, NULL, 0) 1010c5a2d8c5SRyan Moeller == -1) { 101100feaafdSAndrew Thompson /* Do not warn if the process exits before we get its jid. */ 101200feaafdSAndrew Thompson if (errno != ESRCH) 1013c5a2d8c5SRyan Moeller warn("cap_sysctl()"); 101400feaafdSAndrew Thompson return (-1); 101500feaafdSAndrew Thompson } 101600feaafdSAndrew Thompson return (proc.ki_jid); 101700feaafdSAndrew Thompson } 101800feaafdSAndrew Thompson 101900feaafdSAndrew Thompson static int 1020ae94787dSMaxime Henrion check_ports(struct sock *s) 1021ae94787dSMaxime Henrion { 1022ae94787dSMaxime Henrion int port; 1023e6f718c7SMichael Tuexen struct addr *addr; 1024ae94787dSMaxime Henrion 1025ae94787dSMaxime Henrion if (ports == NULL) 1026ae94787dSMaxime Henrion return (1); 1027ae94787dSMaxime Henrion if ((s->family != AF_INET) && (s->family != AF_INET6)) 1028ae94787dSMaxime Henrion return (1); 1029e6f718c7SMichael Tuexen for (addr = s->laddr; addr != NULL; addr = addr->next) { 1030b8e20e2dSHiroki Sato if (s->family == AF_INET) 1031b8e20e2dSHiroki Sato port = ntohs(sstosin(&addr->address)->sin_port); 1032ae94787dSMaxime Henrion else 1033b8e20e2dSHiroki Sato port = ntohs(sstosin6(&addr->address)->sin6_port); 1034ae94787dSMaxime Henrion if (CHK_PORT(port)) 1035ae94787dSMaxime Henrion return (1); 1036e6f718c7SMichael Tuexen } 1037e6f718c7SMichael Tuexen for (addr = s->faddr; addr != NULL; addr = addr->next) { 1038b8e20e2dSHiroki Sato if (s->family == AF_INET) 1039b8e20e2dSHiroki Sato port = ntohs(sstosin(&addr->address)->sin_port); 1040ae94787dSMaxime Henrion else 1041b8e20e2dSHiroki Sato port = ntohs(sstosin6(&addr->address)->sin6_port); 1042ae94787dSMaxime Henrion if (CHK_PORT(port)) 1043ae94787dSMaxime Henrion return (1); 1044e6f718c7SMichael Tuexen } 1045ae94787dSMaxime Henrion return (0); 1046ae94787dSMaxime Henrion } 1047ae94787dSMaxime Henrion 10486414db1bSMichael Tuexen static const char * 1049e389705eSMichael Tuexen sctp_conn_state(int state) 10506414db1bSMichael Tuexen { 10516414db1bSMichael Tuexen switch (state) { 10526414db1bSMichael Tuexen case SCTP_CLOSED: 10536414db1bSMichael Tuexen return "CLOSED"; 10546414db1bSMichael Tuexen break; 10556414db1bSMichael Tuexen case SCTP_BOUND: 10566414db1bSMichael Tuexen return "BOUND"; 10576414db1bSMichael Tuexen break; 10586414db1bSMichael Tuexen case SCTP_LISTEN: 10596414db1bSMichael Tuexen return "LISTEN"; 10606414db1bSMichael Tuexen break; 10616414db1bSMichael Tuexen case SCTP_COOKIE_WAIT: 10626414db1bSMichael Tuexen return "COOKIE_WAIT"; 10636414db1bSMichael Tuexen break; 10646414db1bSMichael Tuexen case SCTP_COOKIE_ECHOED: 10656414db1bSMichael Tuexen return "COOKIE_ECHOED"; 10666414db1bSMichael Tuexen break; 10676414db1bSMichael Tuexen case SCTP_ESTABLISHED: 10686414db1bSMichael Tuexen return "ESTABLISHED"; 10696414db1bSMichael Tuexen break; 10706414db1bSMichael Tuexen case SCTP_SHUTDOWN_SENT: 10716414db1bSMichael Tuexen return "SHUTDOWN_SENT"; 10726414db1bSMichael Tuexen break; 10736414db1bSMichael Tuexen case SCTP_SHUTDOWN_RECEIVED: 10746414db1bSMichael Tuexen return "SHUTDOWN_RECEIVED"; 10756414db1bSMichael Tuexen break; 10766414db1bSMichael Tuexen case SCTP_SHUTDOWN_ACK_SENT: 10776414db1bSMichael Tuexen return "SHUTDOWN_ACK_SENT"; 10786414db1bSMichael Tuexen break; 10796414db1bSMichael Tuexen case SCTP_SHUTDOWN_PENDING: 10806414db1bSMichael Tuexen return "SHUTDOWN_PENDING"; 10816414db1bSMichael Tuexen break; 10826414db1bSMichael Tuexen default: 10836414db1bSMichael Tuexen return "UNKNOWN"; 10846414db1bSMichael Tuexen break; 10856414db1bSMichael Tuexen } 10866414db1bSMichael Tuexen } 10876414db1bSMichael Tuexen 1088e389705eSMichael Tuexen static const char * 1089e389705eSMichael Tuexen sctp_path_state(int state) 1090e389705eSMichael Tuexen { 1091e389705eSMichael Tuexen switch (state) { 1092e389705eSMichael Tuexen case SCTP_UNCONFIRMED: 1093e389705eSMichael Tuexen return "UNCONFIRMED"; 1094e389705eSMichael Tuexen break; 1095e389705eSMichael Tuexen case SCTP_ACTIVE: 1096e389705eSMichael Tuexen return "ACTIVE"; 1097e389705eSMichael Tuexen break; 1098e389705eSMichael Tuexen case SCTP_INACTIVE: 1099e389705eSMichael Tuexen return "INACTIVE"; 1100e389705eSMichael Tuexen break; 1101e389705eSMichael Tuexen default: 1102e389705eSMichael Tuexen return "UNKNOWN"; 1103e389705eSMichael Tuexen break; 1104e389705eSMichael Tuexen } 1105e389705eSMichael Tuexen } 1106e389705eSMichael Tuexen 1107ca007d91SDag-Erling Smørgrav static void 110861149f8dSJilles Tjoelker displaysock(struct sock *s, int pos) 1109ca007d91SDag-Erling Smørgrav { 1110a83d596fSGleb Smirnoff int first, offset; 1111e6f718c7SMichael Tuexen struct addr *laddr, *faddr; 1112ca007d91SDag-Erling Smørgrav 1113c5bdcd1fSGleb Smirnoff while (pos < 30) 1114ca007d91SDag-Erling Smørgrav pos += xprintf(" "); 1115ca007d91SDag-Erling Smørgrav pos += xprintf("%s", s->protoname); 1116ca007d91SDag-Erling Smørgrav if (s->vflag & INP_IPV4) 1117ca007d91SDag-Erling Smørgrav pos += xprintf("4"); 1118ca007d91SDag-Erling Smørgrav if (s->vflag & INP_IPV6) 1119ca007d91SDag-Erling Smørgrav pos += xprintf("6"); 1120edc9c7fcSMichael Tuexen if (s->vflag & (INP_IPV4 | INP_IPV6)) 1121edc9c7fcSMichael Tuexen pos += xprintf(" "); 1122e6f718c7SMichael Tuexen laddr = s->laddr; 1123e6f718c7SMichael Tuexen faddr = s->faddr; 11244e13a5b0SMichael Tuexen first = 1; 1125e6f718c7SMichael Tuexen while (laddr != NULL || faddr != NULL) { 1126c5bdcd1fSGleb Smirnoff offset = 37; 112783f60cb2SMichael Tuexen while (pos < offset) 1128ca007d91SDag-Erling Smørgrav pos += xprintf(" "); 1129ca007d91SDag-Erling Smørgrav switch (s->family) { 1130ca007d91SDag-Erling Smørgrav case AF_INET: 1131ca007d91SDag-Erling Smørgrav case AF_INET6: 1132*fbd34486SMark Johnston if (laddr != NULL) 1133e6f718c7SMichael Tuexen pos += printaddr(&laddr->address); 113483f60cb2SMichael Tuexen offset += opt_w ? 46 : 22; 1135*fbd34486SMark Johnston do 1136ca007d91SDag-Erling Smørgrav pos += xprintf(" "); 1137*fbd34486SMark Johnston while (pos < offset); 1138e6f718c7SMichael Tuexen if (faddr != NULL) 1139e6f718c7SMichael Tuexen pos += printaddr(&faddr->address); 114083f60cb2SMichael Tuexen offset += opt_w ? 46 : 22; 1141ca007d91SDag-Erling Smørgrav break; 1142ca007d91SDag-Erling Smørgrav case AF_UNIX: 1143e6f718c7SMichael Tuexen if ((laddr == NULL) || (faddr == NULL)) 1144e6f718c7SMichael Tuexen errx(1, "laddr = %p or faddr = %p is NULL", 1145e6f718c7SMichael Tuexen (void *)laddr, (void *)faddr); 11462c436d48SGleb Smirnoff if (laddr->address.ss_len == 0 && faddr->conn == 0) { 1147b4eb37c6SJohn-Mark Gurney pos += xprintf("(not connected)"); 114883f60cb2SMichael Tuexen offset += opt_w ? 92 : 44; 1149b4eb37c6SJohn-Mark Gurney break; 1150b4eb37c6SJohn-Mark Gurney } 11512c436d48SGleb Smirnoff /* Local bind(2) address, if any. */ 11522c436d48SGleb Smirnoff if (laddr->address.ss_len > 0) 11532c436d48SGleb Smirnoff pos += printaddr(&laddr->address); 11542c436d48SGleb Smirnoff /* Remote peer we connect(2) to, if any. */ 11552c436d48SGleb Smirnoff if (faddr->conn != 0) { 11562c436d48SGleb Smirnoff struct sock *p; 11572c436d48SGleb Smirnoff 11582c436d48SGleb Smirnoff pos += xprintf("%s-> ", 11592c436d48SGleb Smirnoff laddr->address.ss_len > 0 ? " " : ""); 11602c436d48SGleb Smirnoff p = RB_FIND(pcbs_t, &pcbs, 11612c436d48SGleb Smirnoff &(struct sock){ .pcb = faddr->conn }); 11622c436d48SGleb Smirnoff if (__predict_false(p == NULL)) { 11632c436d48SGleb Smirnoff /* XXGL: can this happen at all? */ 1164ca007d91SDag-Erling Smørgrav pos += xprintf("??"); 11652c436d48SGleb Smirnoff } else if (p->laddr->address.ss_len == 0) { 11662c436d48SGleb Smirnoff struct file *f; 11672c436d48SGleb Smirnoff 11682c436d48SGleb Smirnoff f = RB_FIND(files_t, &ftree, 11692c436d48SGleb Smirnoff &(struct file){ .xf_data = 11702c436d48SGleb Smirnoff p->socket }); 117135f49843SKonstantin Belousov if (f != NULL) { 11722c436d48SGleb Smirnoff pos += xprintf("[%lu %d]", 117335f49843SKonstantin Belousov (u_long)f->xf_pid, 117435f49843SKonstantin Belousov f->xf_fd); 117535f49843SKonstantin Belousov } 11762c436d48SGleb Smirnoff } else 11772c436d48SGleb Smirnoff pos += printaddr(&p->laddr->address); 11782c436d48SGleb Smirnoff } 11792c436d48SGleb Smirnoff /* Remote peer(s) connect(2)ed to us, if any. */ 11802c436d48SGleb Smirnoff if (faddr->firstref != 0) { 11812c436d48SGleb Smirnoff struct sock *p; 11822c436d48SGleb Smirnoff struct file *f; 11832c436d48SGleb Smirnoff kvaddr_t ref = faddr->firstref; 11842c436d48SGleb Smirnoff bool fref = true; 11852c436d48SGleb Smirnoff 11862c436d48SGleb Smirnoff pos += xprintf(" <- "); 11872c436d48SGleb Smirnoff 11882c436d48SGleb Smirnoff while ((p = RB_FIND(pcbs_t, &pcbs, 11892c436d48SGleb Smirnoff &(struct sock){ .pcb = ref })) != 0) { 11902c436d48SGleb Smirnoff f = RB_FIND(files_t, &ftree, 11912c436d48SGleb Smirnoff &(struct file){ .xf_data = 11922c436d48SGleb Smirnoff p->socket }); 119335f49843SKonstantin Belousov if (f != NULL) { 11942c436d48SGleb Smirnoff pos += xprintf("%s[%lu %d]", 11952c436d48SGleb Smirnoff fref ? "" : ",", 119635f49843SKonstantin Belousov (u_long)f->xf_pid, 119735f49843SKonstantin Belousov f->xf_fd); 119835f49843SKonstantin Belousov } 11992c436d48SGleb Smirnoff ref = p->faddr->nextref; 12002c436d48SGleb Smirnoff fref = false; 12012c436d48SGleb Smirnoff } 12022c436d48SGleb Smirnoff } 120383f60cb2SMichael Tuexen offset += opt_w ? 92 : 44; 1204ca007d91SDag-Erling Smørgrav break; 1205ca007d91SDag-Erling Smørgrav default: 1206ca007d91SDag-Erling Smørgrav abort(); 1207ca007d91SDag-Erling Smørgrav } 1208a471d2b4SMark Johnston if (opt_f) { 1209*fbd34486SMark Johnston do 1210a471d2b4SMark Johnston pos += xprintf(" "); 1211*fbd34486SMark Johnston while (pos < offset); 1212a471d2b4SMark Johnston pos += xprintf("%d", s->fibnum); 1213a471d2b4SMark Johnston offset += 7; 1214a471d2b4SMark Johnston } 1215051a2132SMark Johnston if (opt_I) { 1216051a2132SMark Johnston if (s->splice_socket != 0) { 1217051a2132SMark Johnston struct sock *sp; 1218051a2132SMark Johnston 1219051a2132SMark Johnston sp = RB_FIND(socks_t, &socks, &(struct sock) 1220051a2132SMark Johnston { .socket = s->splice_socket }); 1221051a2132SMark Johnston if (sp != NULL) { 1222*fbd34486SMark Johnston do 1223051a2132SMark Johnston pos += xprintf(" "); 1224*fbd34486SMark Johnston while (pos < offset); 1225051a2132SMark Johnston pos += printaddr(&sp->laddr->address); 1226051a2132SMark Johnston } else { 1227*fbd34486SMark Johnston do 1228051a2132SMark Johnston pos += xprintf(" "); 1229*fbd34486SMark Johnston while (pos < offset); 1230051a2132SMark Johnston pos += xprintf("??"); 1231051a2132SMark Johnston offset += opt_w ? 46 : 22; 1232051a2132SMark Johnston } 1233051a2132SMark Johnston } 1234051a2132SMark Johnston offset += opt_w ? 46 : 22; 1235051a2132SMark Johnston } 12365f64777aSMichael Tuexen if (opt_i) { 12375f64777aSMichael Tuexen if (s->proto == IPPROTO_TCP || 12385f64777aSMichael Tuexen s->proto == IPPROTO_UDP) { 1239*fbd34486SMark Johnston do 12405f64777aSMichael Tuexen pos += xprintf(" "); 1241*fbd34486SMark Johnston while (pos < offset); 12425f64777aSMichael Tuexen pos += xprintf("%" PRIu64, s->inp_gencnt); 12435f64777aSMichael Tuexen } 12445f64777aSMichael Tuexen offset += 9; 12455f64777aSMichael Tuexen } 124649b836f2SMichael Tuexen if (opt_U) { 124749b836f2SMichael Tuexen if (faddr != NULL && 12489e644c23SMichael Tuexen ((s->proto == IPPROTO_SCTP && 124949b836f2SMichael Tuexen s->state != SCTP_CLOSED && 125049b836f2SMichael Tuexen s->state != SCTP_BOUND && 12519e644c23SMichael Tuexen s->state != SCTP_LISTEN) || 12529e644c23SMichael Tuexen (s->proto == IPPROTO_TCP && 12539e644c23SMichael Tuexen s->state != TCPS_CLOSED && 12549e644c23SMichael Tuexen s->state != TCPS_LISTEN))) { 1255*fbd34486SMark Johnston do 125649b836f2SMichael Tuexen pos += xprintf(" "); 1257*fbd34486SMark Johnston while (pos < offset); 125849b836f2SMichael Tuexen pos += xprintf("%u", 125949b836f2SMichael Tuexen ntohs(faddr->encaps_port)); 126049b836f2SMichael Tuexen } 126149b836f2SMichael Tuexen offset += 7; 126249b836f2SMichael Tuexen } 1263e389705eSMichael Tuexen if (opt_s) { 1264e389705eSMichael Tuexen if (faddr != NULL && 1265e389705eSMichael Tuexen s->proto == IPPROTO_SCTP && 1266e389705eSMichael Tuexen s->state != SCTP_CLOSED && 1267e389705eSMichael Tuexen s->state != SCTP_BOUND && 1268e389705eSMichael Tuexen s->state != SCTP_LISTEN) { 1269*fbd34486SMark Johnston do 1270e389705eSMichael Tuexen pos += xprintf(" "); 1271*fbd34486SMark Johnston while (pos < offset); 1272e389705eSMichael Tuexen pos += xprintf("%s", 1273e389705eSMichael Tuexen sctp_path_state(faddr->state)); 1274e389705eSMichael Tuexen } 1275e389705eSMichael Tuexen offset += 13; 1276e389705eSMichael Tuexen } 1277e5cccc35SMichael Tuexen if (first) { 127849b836f2SMichael Tuexen if (opt_s) { 127949b836f2SMichael Tuexen if (s->proto == IPPROTO_SCTP || 128049b836f2SMichael Tuexen s->proto == IPPROTO_TCP) { 1281*fbd34486SMark Johnston do 12824e13a5b0SMichael Tuexen pos += xprintf(" "); 1283*fbd34486SMark Johnston while (pos < offset); 12846414db1bSMichael Tuexen switch (s->proto) { 12856414db1bSMichael Tuexen case IPPROTO_SCTP: 1286e5cccc35SMichael Tuexen pos += xprintf("%s", 1287e389705eSMichael Tuexen sctp_conn_state(s->state)); 12886414db1bSMichael Tuexen break; 12896414db1bSMichael Tuexen case IPPROTO_TCP: 1290e5cccc35SMichael Tuexen if (s->state >= 0 && 1291e5cccc35SMichael Tuexen s->state < TCP_NSTATES) 129249b836f2SMichael Tuexen pos += xprintf("%s", 1293e5cccc35SMichael Tuexen tcpstates[s->state]); 12944e13a5b0SMichael Tuexen else 12954e13a5b0SMichael Tuexen pos += xprintf("?"); 12966414db1bSMichael Tuexen break; 12976414db1bSMichael Tuexen } 12984e13a5b0SMichael Tuexen } 129949b836f2SMichael Tuexen offset += 13; 130049b836f2SMichael Tuexen } 13012ac089d0SMichael Tuexen if (opt_S) { 13022ac089d0SMichael Tuexen if (s->proto == IPPROTO_TCP) { 1303*fbd34486SMark Johnston do 1304e5cccc35SMichael Tuexen pos += xprintf(" "); 1305*fbd34486SMark Johnston while (pos < offset); 13062ac089d0SMichael Tuexen pos += xprintf("%.*s", 13072ac089d0SMichael Tuexen TCP_FUNCTION_NAME_LEN_MAX, 1308e5cccc35SMichael Tuexen s->stack); 1309e5cccc35SMichael Tuexen } 13102ac089d0SMichael Tuexen offset += TCP_FUNCTION_NAME_LEN_MAX + 1; 13112ac089d0SMichael Tuexen } 13122ac089d0SMichael Tuexen if (opt_C) { 13132ac089d0SMichael Tuexen if (s->proto == IPPROTO_TCP) { 1314*fbd34486SMark Johnston do 13152ac089d0SMichael Tuexen pos += xprintf(" "); 1316*fbd34486SMark Johnston while (pos < offset); 13172ac089d0SMichael Tuexen xprintf("%.*s", TCP_CA_NAME_MAX, s->cc); 13182ac089d0SMichael Tuexen } 13192ac089d0SMichael Tuexen offset += TCP_CA_NAME_MAX + 1; 13202ac089d0SMichael Tuexen } 1321e5cccc35SMichael Tuexen } 1322e6f718c7SMichael Tuexen if (laddr != NULL) 1323e6f718c7SMichael Tuexen laddr = laddr->next; 1324e6f718c7SMichael Tuexen if (faddr != NULL) 1325e6f718c7SMichael Tuexen faddr = faddr->next; 1326e6f718c7SMichael Tuexen if ((laddr != NULL) || (faddr != NULL)) { 1327e6f718c7SMichael Tuexen xprintf("\n"); 1328e6f718c7SMichael Tuexen pos = 0; 1329e6f718c7SMichael Tuexen } 13304e13a5b0SMichael Tuexen first = 0; 1331e6f718c7SMichael Tuexen } 13324e13a5b0SMichael Tuexen xprintf("\n"); 1333ca007d91SDag-Erling Smørgrav } 133461149f8dSJilles Tjoelker 133561149f8dSJilles Tjoelker static void 133661149f8dSJilles Tjoelker display(void) 133761149f8dSJilles Tjoelker { 133861149f8dSJilles Tjoelker struct passwd *pwd; 13392c436d48SGleb Smirnoff struct file *xf; 134061149f8dSJilles Tjoelker struct sock *s; 1341a83d596fSGleb Smirnoff int n, pos; 134261149f8dSJilles Tjoelker 1343ee0afaa9SEmmanuel Vadot if (opt_q != 1) { 1344c5bdcd1fSGleb Smirnoff printf("%-8s %-10s %-5s %-3s %-6s %-*s %-*s", 134561149f8dSJilles Tjoelker "USER", "COMMAND", "PID", "FD", "PROTO", 134683f60cb2SMichael Tuexen opt_w ? 45 : 21, "LOCAL ADDRESS", 134783f60cb2SMichael Tuexen opt_w ? 45 : 21, "FOREIGN ADDRESS"); 1348a471d2b4SMark Johnston if (opt_f) 1349a471d2b4SMark Johnston /* RT_MAXFIBS is 65535. */ 1350a471d2b4SMark Johnston printf(" %-6s", "FIB"); 1351051a2132SMark Johnston if (opt_I) 1352051a2132SMark Johnston printf(" %-*s", opt_w ? 45 : 21, "SPLICE ADDRESS"); 13535f64777aSMichael Tuexen if (opt_i) 13545f64777aSMichael Tuexen printf(" %-8s", "ID"); 135549b836f2SMichael Tuexen if (opt_U) 135649b836f2SMichael Tuexen printf(" %-6s", "ENCAPS"); 1357e389705eSMichael Tuexen if (opt_s) { 1358e389705eSMichael Tuexen printf(" %-12s", "PATH STATE"); 1359e389705eSMichael Tuexen printf(" %-12s", "CONN STATE"); 1360e389705eSMichael Tuexen } 1361e5cccc35SMichael Tuexen if (opt_S) 13622ac089d0SMichael Tuexen printf(" %-*.*s", TCP_FUNCTION_NAME_LEN_MAX, 13632ac089d0SMichael Tuexen TCP_FUNCTION_NAME_LEN_MAX, "STACK"); 13642ac089d0SMichael Tuexen if (opt_C) 13652ac089d0SMichael Tuexen printf(" %-.*s", TCP_CA_NAME_MAX, "CC"); 13667a5642b3SDag-Erling Smørgrav printf("\n"); 1367ee0afaa9SEmmanuel Vadot } 13687ad30f58SMariusz Zaborski cap_setpassent(cappwd, 1); 13692c436d48SGleb Smirnoff for (xf = files, n = 0; n < nfiles; ++n, ++xf) { 1370f38b68aeSBrooks Davis if (xf->xf_data == 0) 137161149f8dSJilles Tjoelker continue; 137200feaafdSAndrew Thompson if (opt_j >= 0 && opt_j != getprocjid(xf->xf_pid)) 137300feaafdSAndrew Thompson continue; 1374a83d596fSGleb Smirnoff s = RB_FIND(socks_t, &socks, 1375a83d596fSGleb Smirnoff &(struct sock){ .socket = xf->xf_data}); 1376a83d596fSGleb Smirnoff if (s != NULL && check_ports(s)) { 137761149f8dSJilles Tjoelker s->shown = 1; 137861149f8dSJilles Tjoelker pos = 0; 13797ad30f58SMariusz Zaborski if (opt_n || 13807ad30f58SMariusz Zaborski (pwd = cap_getpwuid(cappwd, xf->xf_uid)) == NULL) 138161149f8dSJilles Tjoelker pos += xprintf("%lu", (u_long)xf->xf_uid); 138261149f8dSJilles Tjoelker else 138361149f8dSJilles Tjoelker pos += xprintf("%s", pwd->pw_name); 1384*fbd34486SMark Johnston do 138561149f8dSJilles Tjoelker pos += xprintf(" "); 1386*fbd34486SMark Johnston while (pos < 9); 138761149f8dSJilles Tjoelker pos += xprintf("%.10s", getprocname(xf->xf_pid)); 1388*fbd34486SMark Johnston do 138961149f8dSJilles Tjoelker pos += xprintf(" "); 1390*fbd34486SMark Johnston while (pos < 20); 1391d961ccd3SGleb Smirnoff pos += xprintf("%5lu", (u_long)xf->xf_pid); 1392*fbd34486SMark Johnston do 139361149f8dSJilles Tjoelker pos += xprintf(" "); 1394*fbd34486SMark Johnston while (pos < 26); 1395c5bdcd1fSGleb Smirnoff pos += xprintf("%-3d", xf->xf_fd); 139661149f8dSJilles Tjoelker displaysock(s, pos); 139761149f8dSJilles Tjoelker } 13987e80c6b0SMichael Tuexen } 139900feaafdSAndrew Thompson if (opt_j >= 0) 140000feaafdSAndrew Thompson return; 1401a83d596fSGleb Smirnoff SLIST_FOREACH(s, &nosocks, socket_list) { 1402a83d596fSGleb Smirnoff if (!check_ports(s)) 1403a83d596fSGleb Smirnoff continue; 1404*fbd34486SMark Johnston pos = xprintf("%-8s %-10s %-5s %-3s", 1405a83d596fSGleb Smirnoff "?", "?", "?", "?"); 1406a83d596fSGleb Smirnoff displaysock(s, pos); 1407a83d596fSGleb Smirnoff } 1408a83d596fSGleb Smirnoff RB_FOREACH(s, socks_t, &socks) { 140961149f8dSJilles Tjoelker if (s->shown) 141061149f8dSJilles Tjoelker continue; 141161149f8dSJilles Tjoelker if (!check_ports(s)) 141261149f8dSJilles Tjoelker continue; 1413*fbd34486SMark Johnston pos = xprintf("%-8s %-10s %-5s %-3s", 141461149f8dSJilles Tjoelker "?", "?", "?", "?"); 141561149f8dSJilles Tjoelker displaysock(s, pos); 141661149f8dSJilles Tjoelker } 141761149f8dSJilles Tjoelker } 1418ca007d91SDag-Erling Smørgrav 1419f1cd4902SRyan Moeller static int 1420f1cd4902SRyan Moeller set_default_protos(void) 14211f3d67aaSGiorgos Keramidas { 14221f3d67aaSGiorgos Keramidas struct protoent *prot; 14231f3d67aaSGiorgos Keramidas const char *pname; 14241f3d67aaSGiorgos Keramidas size_t pindex; 14251f3d67aaSGiorgos Keramidas 14261f3d67aaSGiorgos Keramidas init_protos(default_numprotos); 14271f3d67aaSGiorgos Keramidas 14281f3d67aaSGiorgos Keramidas for (pindex = 0; pindex < default_numprotos; pindex++) { 14291f3d67aaSGiorgos Keramidas pname = default_protos[pindex]; 1430c5a2d8c5SRyan Moeller prot = cap_getprotobyname(capnetdb, pname); 14311f3d67aaSGiorgos Keramidas if (prot == NULL) 1432c5a2d8c5SRyan Moeller err(1, "cap_getprotobyname: %s", pname); 14331f3d67aaSGiorgos Keramidas protos[pindex] = prot->p_proto; 14341f3d67aaSGiorgos Keramidas } 14351f3d67aaSGiorgos Keramidas numprotos = pindex; 14361f3d67aaSGiorgos Keramidas return (pindex); 14371f3d67aaSGiorgos Keramidas } 14381f3d67aaSGiorgos Keramidas 1439f1cd4902SRyan Moeller /* 1440f1cd4902SRyan Moeller * Return the vnet property of the jail, or -1 on error. 1441f1cd4902SRyan Moeller */ 1442f1cd4902SRyan Moeller static int 1443f1cd4902SRyan Moeller jail_getvnet(int jid) 1444f1cd4902SRyan Moeller { 1445f1cd4902SRyan Moeller struct iovec jiov[6]; 1446f1cd4902SRyan Moeller int vnet; 14471fec1fa8SGleb Smirnoff size_t len = sizeof(vnet); 14481fec1fa8SGleb Smirnoff 14491fec1fa8SGleb Smirnoff if (sysctlbyname("kern.features.vimage", &vnet, &len, NULL, 0) != 0) 14501fec1fa8SGleb Smirnoff return (0); 1451f1cd4902SRyan Moeller 1452f1cd4902SRyan Moeller vnet = -1; 1453f1cd4902SRyan Moeller jiov[0].iov_base = __DECONST(char *, "jid"); 1454f1cd4902SRyan Moeller jiov[0].iov_len = sizeof("jid"); 1455f1cd4902SRyan Moeller jiov[1].iov_base = &jid; 1456f1cd4902SRyan Moeller jiov[1].iov_len = sizeof(jid); 1457f1cd4902SRyan Moeller jiov[2].iov_base = __DECONST(char *, "vnet"); 1458f1cd4902SRyan Moeller jiov[2].iov_len = sizeof("vnet"); 1459f1cd4902SRyan Moeller jiov[3].iov_base = &vnet; 1460f1cd4902SRyan Moeller jiov[3].iov_len = sizeof(vnet); 1461f1cd4902SRyan Moeller jiov[4].iov_base = __DECONST(char *, "errmsg"); 1462f1cd4902SRyan Moeller jiov[4].iov_len = sizeof("errmsg"); 1463f1cd4902SRyan Moeller jiov[5].iov_base = jail_errmsg; 1464f1cd4902SRyan Moeller jiov[5].iov_len = JAIL_ERRMSGLEN; 1465f1cd4902SRyan Moeller jail_errmsg[0] = '\0'; 1466f1cd4902SRyan Moeller if (jail_get(jiov, nitems(jiov), 0) < 0) { 1467f1cd4902SRyan Moeller if (!jail_errmsg[0]) 1468f1cd4902SRyan Moeller snprintf(jail_errmsg, JAIL_ERRMSGLEN, 1469f1cd4902SRyan Moeller "jail_get: %s", strerror(errno)); 1470f1cd4902SRyan Moeller return (-1); 1471f1cd4902SRyan Moeller } 1472f1cd4902SRyan Moeller return (vnet); 1473f1cd4902SRyan Moeller } 1474f1cd4902SRyan Moeller 1475ca007d91SDag-Erling Smørgrav static void 1476ca007d91SDag-Erling Smørgrav usage(void) 1477ca007d91SDag-Erling Smørgrav { 1478a471d2b4SMark Johnston errx(1, 1479a471d2b4SMark Johnston "usage: sockstat [-46CcfIiLlnqSsUuvw] [-j jid] [-p ports] [-P protocols]"); 1480ca007d91SDag-Erling Smørgrav } 1481ca007d91SDag-Erling Smørgrav 1482ca007d91SDag-Erling Smørgrav int 1483ca007d91SDag-Erling Smørgrav main(int argc, char *argv[]) 1484ca007d91SDag-Erling Smørgrav { 1485c5a2d8c5SRyan Moeller cap_channel_t *capcas; 1486c5a2d8c5SRyan Moeller cap_net_limit_t *limit; 14877ad30f58SMariusz Zaborski const char *pwdcmds[] = { "setpassent", "getpwuid" }; 14887ad30f58SMariusz Zaborski const char *pwdfields[] = { "pw_name" }; 14891f3d67aaSGiorgos Keramidas int protos_defined = -1; 14901f3d67aaSGiorgos Keramidas int o, i; 1491ca007d91SDag-Erling Smørgrav 149200feaafdSAndrew Thompson opt_j = -1; 1493a471d2b4SMark Johnston while ((o = getopt(argc, argv, "46CcfIij:Llnp:P:qSsUuvw")) != -1) 1494ca007d91SDag-Erling Smørgrav switch (o) { 1495ca007d91SDag-Erling Smørgrav case '4': 1496ca007d91SDag-Erling Smørgrav opt_4 = 1; 1497ca007d91SDag-Erling Smørgrav break; 1498ca007d91SDag-Erling Smørgrav case '6': 1499ca007d91SDag-Erling Smørgrav opt_6 = 1; 1500ca007d91SDag-Erling Smørgrav break; 15012ac089d0SMichael Tuexen case 'C': 15022ac089d0SMichael Tuexen opt_C = 1; 15032ac089d0SMichael Tuexen break; 1504ca007d91SDag-Erling Smørgrav case 'c': 1505ca007d91SDag-Erling Smørgrav opt_c = 1; 1506ca007d91SDag-Erling Smørgrav break; 1507a471d2b4SMark Johnston case 'f': 1508a471d2b4SMark Johnston opt_f = 1; 1509a471d2b4SMark Johnston break; 1510051a2132SMark Johnston case 'I': 1511051a2132SMark Johnston opt_I = 1; 1512051a2132SMark Johnston break; 15135f64777aSMichael Tuexen case 'i': 15145f64777aSMichael Tuexen opt_i = 1; 15155f64777aSMichael Tuexen break; 151600feaafdSAndrew Thompson case 'j': 1517de68a320SJamie Gritton opt_j = jail_getid(optarg); 1518de68a320SJamie Gritton if (opt_j < 0) 151932723a3bSGleb Smirnoff errx(1, "jail_getid: %s", jail_errmsg); 152000feaafdSAndrew Thompson break; 15219b6ca892SBruce M Simpson case 'L': 15229b6ca892SBruce M Simpson opt_L = 1; 15239b6ca892SBruce M Simpson break; 1524ca007d91SDag-Erling Smørgrav case 'l': 1525ca007d91SDag-Erling Smørgrav opt_l = 1; 1526ca007d91SDag-Erling Smørgrav break; 1527ccdd2b2bSAlexander Motin case 'n': 1528ccdd2b2bSAlexander Motin opt_n = 1; 1529ccdd2b2bSAlexander Motin break; 1530ca007d91SDag-Erling Smørgrav case 'p': 1531ca007d91SDag-Erling Smørgrav parse_ports(optarg); 1532ca007d91SDag-Erling Smørgrav break; 15331f3d67aaSGiorgos Keramidas case 'P': 15341f3d67aaSGiorgos Keramidas protos_defined = parse_protos(optarg); 15351f3d67aaSGiorgos Keramidas break; 1536ee0afaa9SEmmanuel Vadot case 'q': 1537ee0afaa9SEmmanuel Vadot opt_q = 1; 153862de7037SEmmanuel Vadot break; 1539e5cccc35SMichael Tuexen case 'S': 1540e5cccc35SMichael Tuexen opt_S = 1; 1541e5cccc35SMichael Tuexen break; 15427a5642b3SDag-Erling Smørgrav case 's': 15437a5642b3SDag-Erling Smørgrav opt_s = 1; 15447a5642b3SDag-Erling Smørgrav break; 154549b836f2SMichael Tuexen case 'U': 154649b836f2SMichael Tuexen opt_U = 1; 154749b836f2SMichael Tuexen break; 1548ca007d91SDag-Erling Smørgrav case 'u': 1549ca007d91SDag-Erling Smørgrav opt_u = 1; 1550ca007d91SDag-Erling Smørgrav break; 1551ca007d91SDag-Erling Smørgrav case 'v': 1552ca007d91SDag-Erling Smørgrav ++opt_v; 1553ca007d91SDag-Erling Smørgrav break; 155483f60cb2SMichael Tuexen case 'w': 155583f60cb2SMichael Tuexen opt_w = 1; 155683f60cb2SMichael Tuexen break; 1557ca007d91SDag-Erling Smørgrav default: 1558ca007d91SDag-Erling Smørgrav usage(); 1559ca007d91SDag-Erling Smørgrav } 1560ca007d91SDag-Erling Smørgrav 1561ca007d91SDag-Erling Smørgrav argc -= optind; 1562ca007d91SDag-Erling Smørgrav argv += optind; 1563ca007d91SDag-Erling Smørgrav 1564ca007d91SDag-Erling Smørgrav if (argc > 0) 1565ca007d91SDag-Erling Smørgrav usage(); 1566ca007d91SDag-Erling Smørgrav 1567f1cd4902SRyan Moeller if (opt_j > 0) { 1568f1cd4902SRyan Moeller switch (jail_getvnet(opt_j)) { 1569f1cd4902SRyan Moeller case -1: 157032723a3bSGleb Smirnoff errx(2, "jail_getvnet: %s", jail_errmsg); 1571f1cd4902SRyan Moeller case JAIL_SYS_NEW: 1572f1cd4902SRyan Moeller if (jail_attach(opt_j) < 0) 1573ae37905bSRyan Moeller err(3, "jail_attach()"); 1574f1cd4902SRyan Moeller /* Set back to -1 for normal output in vnet jail. */ 1575f1cd4902SRyan Moeller opt_j = -1; 1576f1cd4902SRyan Moeller break; 1577f1cd4902SRyan Moeller default: 1578f1cd4902SRyan Moeller break; 1579f1cd4902SRyan Moeller } 1580f1cd4902SRyan Moeller } 1581f1cd4902SRyan Moeller 1582c5a2d8c5SRyan Moeller capcas = cap_init(); 1583c5a2d8c5SRyan Moeller if (capcas == NULL) 1584c5a2d8c5SRyan Moeller err(1, "Unable to contact Casper"); 1585c5a2d8c5SRyan Moeller if (caph_enter_casper() < 0) 1586c5a2d8c5SRyan Moeller err(1, "Unable to enter capability mode"); 1587c5a2d8c5SRyan Moeller capnet = cap_service_open(capcas, "system.net"); 1588c5a2d8c5SRyan Moeller if (capnet == NULL) 1589c5a2d8c5SRyan Moeller err(1, "Unable to open system.net service"); 1590c5a2d8c5SRyan Moeller capnetdb = cap_service_open(capcas, "system.netdb"); 1591c5a2d8c5SRyan Moeller if (capnetdb == NULL) 1592c5a2d8c5SRyan Moeller err(1, "Unable to open system.netdb service"); 1593c5a2d8c5SRyan Moeller capsysctl = cap_service_open(capcas, "system.sysctl"); 1594c5a2d8c5SRyan Moeller if (capsysctl == NULL) 1595c5a2d8c5SRyan Moeller err(1, "Unable to open system.sysctl service"); 15967ad30f58SMariusz Zaborski cappwd = cap_service_open(capcas, "system.pwd"); 15977ad30f58SMariusz Zaborski if (cappwd == NULL) 15987ad30f58SMariusz Zaborski err(1, "Unable to open system.pwd service"); 1599c5a2d8c5SRyan Moeller cap_close(capcas); 1600c5a2d8c5SRyan Moeller limit = cap_net_limit_init(capnet, CAPNET_ADDR2NAME); 1601c5a2d8c5SRyan Moeller if (limit == NULL) 1602c5a2d8c5SRyan Moeller err(1, "Unable to init cap_net limits"); 1603c5a2d8c5SRyan Moeller if (cap_net_limit(limit) < 0) 1604c5a2d8c5SRyan Moeller err(1, "Unable to apply limits"); 16057ad30f58SMariusz Zaborski if (cap_pwd_limit_cmds(cappwd, pwdcmds, nitems(pwdcmds)) < 0) 16067ad30f58SMariusz Zaborski err(1, "Unable to apply pwd commands limits"); 16077ad30f58SMariusz Zaborski if (cap_pwd_limit_fields(cappwd, pwdfields, nitems(pwdfields)) < 0) 16087ad30f58SMariusz Zaborski err(1, "Unable to apply pwd commands limits"); 1609c5a2d8c5SRyan Moeller 1610d2d77d2aSGiorgos Keramidas if ((!opt_4 && !opt_6) && protos_defined != -1) 16111f3d67aaSGiorgos Keramidas opt_4 = opt_6 = 1; 1612d2d77d2aSGiorgos Keramidas if (!opt_4 && !opt_6 && !opt_u) 1613d2d77d2aSGiorgos Keramidas opt_4 = opt_6 = opt_u = 1; 1614d2d77d2aSGiorgos Keramidas if ((opt_4 || opt_6) && protos_defined == -1) 1615d2d77d2aSGiorgos Keramidas protos_defined = set_default_protos(); 1616ca007d91SDag-Erling Smørgrav if (!opt_c && !opt_l) 1617ca007d91SDag-Erling Smørgrav opt_c = opt_l = 1; 1618ca007d91SDag-Erling Smørgrav 1619ca007d91SDag-Erling Smørgrav if (opt_4 || opt_6) { 16201f3d67aaSGiorgos Keramidas for (i = 0; i < protos_defined; i++) 1621d5b4aa90SMichael Tuexen if (protos[i] == IPPROTO_SCTP) 1622d5b4aa90SMichael Tuexen gather_sctp(); 1623d5b4aa90SMichael Tuexen else 16241f3d67aaSGiorgos Keramidas gather_inet(protos[i]); 1625ca007d91SDag-Erling Smørgrav } 16261f3d67aaSGiorgos Keramidas 16271f3d67aaSGiorgos Keramidas if (opt_u || (protos_defined == -1 && !opt_4 && !opt_6)) { 1628ca007d91SDag-Erling Smørgrav gather_unix(SOCK_STREAM); 1629ca007d91SDag-Erling Smørgrav gather_unix(SOCK_DGRAM); 1630b8e20e2dSHiroki Sato gather_unix(SOCK_SEQPACKET); 1631ca007d91SDag-Erling Smørgrav } 1632ca007d91SDag-Erling Smørgrav getfiles(); 1633ca007d91SDag-Erling Smørgrav display(); 1634ca007d91SDag-Erling Smørgrav exit(0); 1635ca007d91SDag-Erling Smørgrav } 1636