1101043Sdes/*- 2228991Suqs * Copyright (c) 2002 Dag-Erling Co��dan Sm��rgrav 3101043Sdes * All rights reserved. 4101043Sdes * 5101043Sdes * Redistribution and use in source and binary forms, with or without 6101043Sdes * modification, are permitted provided that the following conditions 7101043Sdes * are met: 8101043Sdes * 1. Redistributions of source code must retain the above copyright 9101043Sdes * notice, this list of conditions and the following disclaimer 10101043Sdes * in this position and unchanged. 11101043Sdes * 2. Redistributions in binary form must reproduce the above copyright 12101043Sdes * notice, this list of conditions and the following disclaimer in the 13101043Sdes * documentation and/or other materials provided with the distribution. 14101043Sdes * 3. The name of the author may not be used to endorse or promote products 15101043Sdes * derived from this software without specific prior written permission. 16101043Sdes * 17101043Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18101043Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19101043Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20101043Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21101043Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22101043Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23101043Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24101043Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25101043Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26101043Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27101043Sdes */ 28101043Sdes 29101043Sdes#include <sys/cdefs.h> 30101043Sdes__FBSDID("$FreeBSD$"); 31101043Sdes 32101043Sdes#include <sys/param.h> 33101043Sdes#include <sys/socket.h> 34101043Sdes#include <sys/socketvar.h> 35101043Sdes#include <sys/sysctl.h> 36101043Sdes#include <sys/file.h> 37101043Sdes#include <sys/user.h> 38101043Sdes 39101043Sdes#include <sys/un.h> 40101043Sdes#include <sys/unpcb.h> 41101043Sdes 42101163Sdes#include <net/route.h> 43101163Sdes 44101043Sdes#include <netinet/in.h> 45101043Sdes#include <netinet/in_pcb.h> 46101043Sdes#include <netinet/tcp.h> 47101043Sdes#include <netinet/tcp_seq.h> 48101043Sdes#include <netinet/tcp_var.h> 49101043Sdes#include <arpa/inet.h> 50101043Sdes 51101043Sdes#include <ctype.h> 52101043Sdes#include <err.h> 53101043Sdes#include <errno.h> 54101043Sdes#include <netdb.h> 55101043Sdes#include <pwd.h> 56101043Sdes#include <stdarg.h> 57101043Sdes#include <stdio.h> 58101043Sdes#include <stdlib.h> 59101043Sdes#include <string.h> 60101043Sdes#include <unistd.h> 61101043Sdes 62101043Sdesstatic int opt_4; /* Show IPv4 sockets */ 63101043Sdesstatic int opt_6; /* Show IPv6 sockets */ 64101043Sdesstatic int opt_c; /* Show connected sockets */ 65235870Sthompsastatic int opt_j; /* Show specified jail */ 66179115Sbmsstatic int opt_L; /* Don't show IPv4 or IPv6 loopback sockets */ 67101043Sdesstatic int opt_l; /* Show listening sockets */ 68101043Sdesstatic int opt_u; /* Show Unix domain sockets */ 69101043Sdesstatic int opt_v; /* Verbose mode */ 70101043Sdes 71164201Skeramida/* 72164201Skeramida * Default protocols to use if no -P was defined. 73164201Skeramida */ 74164201Skeramidastatic const char *default_protos[] = {"tcp", "udp", "divert" }; 75164201Skeramidastatic size_t default_numprotos = 76164201Skeramida sizeof(default_protos) / sizeof(default_protos[0]); 77164201Skeramida 78164201Skeramidastatic int *protos; /* protocols to use */ 79164201Skeramidastatic size_t numprotos; /* allocated size of protos[] */ 80164201Skeramida 81101043Sdesstatic int *ports; 82101043Sdes 83101043Sdes#define INT_BIT (sizeof(int)*CHAR_BIT) 84101043Sdes#define SET_PORT(p) do { ports[p / INT_BIT] |= 1 << (p % INT_BIT); } while (0) 85101043Sdes#define CHK_PORT(p) (ports[p / INT_BIT] & (1 << (p % INT_BIT))) 86101043Sdes 87101043Sdesstruct sock { 88101043Sdes void *socket; 89101043Sdes void *pcb; 90230512Sjilles int shown; 91101043Sdes int vflag; 92101043Sdes int family; 93101043Sdes int proto; 94101043Sdes const char *protoname; 95101043Sdes struct sockaddr_storage laddr; 96101043Sdes struct sockaddr_storage faddr; 97101043Sdes struct sock *next; 98101043Sdes}; 99101043Sdes 100101043Sdes#define HASHSIZE 1009 101101043Sdesstatic struct sock *sockhash[HASHSIZE]; 102101043Sdes 103101043Sdesstatic struct xfile *xfiles; 104101043Sdesstatic int nxfiles; 105101043Sdes 106101043Sdesstatic int 107101043Sdesxprintf(const char *fmt, ...) 108101043Sdes{ 109101043Sdes va_list ap; 110101043Sdes int len; 111101043Sdes 112101043Sdes va_start(ap, fmt); 113101043Sdes len = vprintf(fmt, ap); 114101043Sdes va_end(ap); 115101043Sdes if (len < 0) 116101043Sdes err(1, "printf()"); 117101043Sdes return (len); 118101043Sdes} 119101043Sdes 120164201Skeramida 121164201Skeramidastatic int 122164201Skeramidaget_proto_type(const char *proto) 123164201Skeramida{ 124164201Skeramida struct protoent *pent; 125164201Skeramida 126164201Skeramida if (strlen(proto) == 0) 127164201Skeramida return (0); 128164201Skeramida pent = getprotobyname(proto); 129164201Skeramida if (pent == NULL) { 130164201Skeramida warn("getprotobyname"); 131164201Skeramida return (-1); 132164201Skeramida } 133164201Skeramida return (pent->p_proto); 134164201Skeramida} 135164201Skeramida 136164201Skeramida 137164201Skeramidastatic void init_protos(int num) 138164201Skeramida{ 139164201Skeramida int proto_count = 0; 140164201Skeramida 141164201Skeramida if (num > 0) { 142164201Skeramida proto_count = num; 143164201Skeramida } else { 144164201Skeramida /* Find the maximum number of possible protocols. */ 145164201Skeramida while (getprotoent() != NULL) 146164201Skeramida proto_count++; 147164201Skeramida endprotoent(); 148164201Skeramida } 149164201Skeramida 150164201Skeramida if ((protos = malloc(sizeof(int) * proto_count)) == NULL) 151164201Skeramida err(1, "malloc"); 152164201Skeramida numprotos = proto_count; 153164201Skeramida} 154164201Skeramida 155164201Skeramida 156164201Skeramidastatic int 157164201Skeramidaparse_protos(char *protospec) 158164201Skeramida{ 159164201Skeramida char *prot; 160164201Skeramida char *tmp = protospec; 161164201Skeramida int proto_type, proto_index; 162164201Skeramida 163164201Skeramida if (protospec == NULL) 164164201Skeramida return (-1); 165164201Skeramida 166164201Skeramida init_protos(0); 167164201Skeramida proto_index = 0; 168164201Skeramida while ((prot = strsep(&tmp, ",")) != NULL) { 169164201Skeramida if (strlen(prot) == 0) 170164201Skeramida continue; 171164201Skeramida proto_type = get_proto_type(prot); 172164201Skeramida if (proto_type != -1) 173164201Skeramida protos[proto_index++] = proto_type; 174164201Skeramida } 175164201Skeramida numprotos = proto_index; 176164201Skeramida return (proto_index); 177164201Skeramida} 178164201Skeramida 179164201Skeramida 180101043Sdesstatic void 181101043Sdesparse_ports(const char *portspec) 182101043Sdes{ 183101043Sdes const char *p, *q; 184101043Sdes int port, end; 185101043Sdes 186101043Sdes if (ports == NULL) 187114853Srobert if ((ports = calloc(65536 / INT_BIT, sizeof(int))) == NULL) 188101043Sdes err(1, "calloc()"); 189101043Sdes p = portspec; 190101043Sdes while (*p != '\0') { 191101043Sdes if (!isdigit(*p)) 192101043Sdes errx(1, "syntax error in port range"); 193101043Sdes for (q = p; *q != '\0' && isdigit(*q); ++q) 194101043Sdes /* nothing */ ; 195101043Sdes for (port = 0; p < q; ++p) 196101043Sdes port = port * 10 + digittoint(*p); 197101043Sdes if (port < 0 || port > 65535) 198101043Sdes errx(1, "invalid port number"); 199101043Sdes SET_PORT(port); 200101043Sdes switch (*p) { 201101043Sdes case '-': 202101043Sdes ++p; 203101043Sdes break; 204101043Sdes case ',': 205101043Sdes ++p; 206101043Sdes /* fall through */ 207101043Sdes case '\0': 208101043Sdes default: 209101043Sdes continue; 210101043Sdes } 211101043Sdes for (q = p; *q != '\0' && isdigit(*q); ++q) 212101043Sdes /* nothing */ ; 213101043Sdes for (end = 0; p < q; ++p) 214101043Sdes end = end * 10 + digittoint(*p); 215101043Sdes if (end < port || end > 65535) 216101043Sdes errx(1, "invalid port number"); 217101043Sdes while (port++ < end) 218101043Sdes SET_PORT(port); 219101043Sdes if (*p == ',') 220101043Sdes ++p; 221101043Sdes } 222101043Sdes} 223101043Sdes 224101043Sdesstatic void 225101043Sdessockaddr(struct sockaddr_storage *sa, int af, void *addr, int port) 226101043Sdes{ 227101043Sdes struct sockaddr_in *sin4; 228101043Sdes struct sockaddr_in6 *sin6; 229101043Sdes 230101043Sdes bzero(sa, sizeof *sa); 231101043Sdes switch (af) { 232101043Sdes case AF_INET: 233101043Sdes sin4 = (struct sockaddr_in *)sa; 234101043Sdes sin4->sin_len = sizeof *sin4; 235101043Sdes sin4->sin_family = af; 236101043Sdes sin4->sin_port = port; 237101043Sdes sin4->sin_addr = *(struct in_addr *)addr; 238101043Sdes break; 239101043Sdes case AF_INET6: 240101043Sdes sin6 = (struct sockaddr_in6 *)sa; 241101043Sdes sin6->sin6_len = sizeof *sin6; 242101043Sdes sin6->sin6_family = af; 243101043Sdes sin6->sin6_port = port; 244101043Sdes sin6->sin6_addr = *(struct in6_addr *)addr; 245101043Sdes break; 246101043Sdes default: 247101043Sdes abort(); 248101043Sdes } 249101043Sdes} 250101043Sdes 251101043Sdesstatic void 252101043Sdesgather_inet(int proto) 253101043Sdes{ 254101043Sdes struct xinpgen *xig, *exig; 255101043Sdes struct xinpcb *xip; 256101043Sdes struct xtcpcb *xtp; 257101043Sdes struct inpcb *inp; 258101043Sdes struct xsocket *so; 259101043Sdes struct sock *sock; 260101043Sdes const char *varname, *protoname; 261101043Sdes size_t len, bufsize; 262101043Sdes void *buf; 263101043Sdes int hash, retry, vflag; 264101043Sdes 265101043Sdes vflag = 0; 266101043Sdes if (opt_4) 267101043Sdes vflag |= INP_IPV4; 268101043Sdes if (opt_6) 269101043Sdes vflag |= INP_IPV6; 270101043Sdes 271101043Sdes switch (proto) { 272101043Sdes case IPPROTO_TCP: 273101043Sdes varname = "net.inet.tcp.pcblist"; 274101043Sdes protoname = "tcp"; 275101043Sdes break; 276101043Sdes case IPPROTO_UDP: 277101043Sdes varname = "net.inet.udp.pcblist"; 278101043Sdes protoname = "udp"; 279101043Sdes break; 280138391Sru case IPPROTO_DIVERT: 281138391Sru varname = "net.inet.divert.pcblist"; 282138391Sru protoname = "div"; 283138391Sru break; 284101043Sdes default: 285164201Skeramida errx(1, "protocol %d not supported", proto); 286101043Sdes } 287101043Sdes 288101043Sdes buf = NULL; 289101043Sdes bufsize = 8192; 290101043Sdes retry = 5; 291101043Sdes do { 292101043Sdes for (;;) { 293101043Sdes if ((buf = realloc(buf, bufsize)) == NULL) 294101043Sdes err(1, "realloc()"); 295101043Sdes len = bufsize; 296101043Sdes if (sysctlbyname(varname, buf, &len, NULL, 0) == 0) 297101043Sdes break; 298138437Sru if (errno == ENOENT) 299138437Sru goto out; 300230874Strociny if (errno != ENOMEM || len != bufsize) 301101043Sdes err(1, "sysctlbyname()"); 302101043Sdes bufsize *= 2; 303101043Sdes } 304101043Sdes xig = (struct xinpgen *)buf; 305101220Srobert exig = (struct xinpgen *)(void *) 306101220Srobert ((char *)buf + len - sizeof *exig); 307101043Sdes if (xig->xig_len != sizeof *xig || 308101043Sdes exig->xig_len != sizeof *exig) 309101043Sdes errx(1, "struct xinpgen size mismatch"); 310101043Sdes } while (xig->xig_gen != exig->xig_gen && retry--); 311101043Sdes 312101043Sdes if (xig->xig_gen != exig->xig_gen && opt_v) 313101043Sdes warnx("warning: data may be inconsistent"); 314101043Sdes 315101043Sdes for (;;) { 316101220Srobert xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len); 317101043Sdes if (xig >= exig) 318101043Sdes break; 319101043Sdes switch (proto) { 320101043Sdes case IPPROTO_TCP: 321101043Sdes xtp = (struct xtcpcb *)xig; 322101043Sdes if (xtp->xt_len != sizeof *xtp) { 323101043Sdes warnx("struct xtcpcb size mismatch"); 324101043Sdes goto out; 325101043Sdes } 326101043Sdes inp = &xtp->xt_inp; 327101043Sdes so = &xtp->xt_socket; 328237263Snp protoname = xtp->xt_tp.t_flags & TF_TOE ? "toe" : "tcp"; 329101043Sdes break; 330101043Sdes case IPPROTO_UDP: 331138391Sru case IPPROTO_DIVERT: 332101043Sdes xip = (struct xinpcb *)xig; 333101043Sdes if (xip->xi_len != sizeof *xip) { 334101043Sdes warnx("struct xinpcb size mismatch"); 335101043Sdes goto out; 336101043Sdes } 337101043Sdes inp = &xip->xi_inp; 338101043Sdes so = &xip->xi_socket; 339101043Sdes break; 340101043Sdes default: 341164201Skeramida errx(1, "protocol %d not supported", proto); 342101043Sdes } 343101043Sdes if ((inp->inp_vflag & vflag) == 0) 344101043Sdes continue; 345101144Sdes if (inp->inp_vflag & INP_IPV4) { 346101144Sdes if ((inp->inp_fport == 0 && !opt_l) || 347101144Sdes (inp->inp_fport != 0 && !opt_c)) 348101144Sdes continue; 349179115Sbms#define __IN_IS_ADDR_LOOPBACK(pina) \ 350179115Sbms ((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) 351179115Sbms if (opt_L && 352179115Sbms (__IN_IS_ADDR_LOOPBACK(&inp->inp_faddr) || 353179115Sbms __IN_IS_ADDR_LOOPBACK(&inp->inp_laddr))) 354179115Sbms continue; 355179115Sbms#undef __IN_IS_ADDR_LOOPBACK 356101144Sdes } else if (inp->inp_vflag & INP_IPV6) { 357189637Srwatson if ((inp->inp_fport == 0 && !opt_l) || 358189637Srwatson (inp->inp_fport != 0 && !opt_c)) 359101144Sdes continue; 360179115Sbms if (opt_L && 361179115Sbms (IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr) || 362179115Sbms IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr))) 363179115Sbms continue; 364101144Sdes } else { 365101144Sdes if (opt_v) 366101144Sdes warnx("invalid vflag 0x%x", inp->inp_vflag); 367101144Sdes continue; 368101144Sdes } 369101043Sdes if ((sock = calloc(1, sizeof *sock)) == NULL) 370101043Sdes err(1, "malloc()"); 371101043Sdes sock->socket = so->xso_so; 372101043Sdes sock->proto = proto; 373101043Sdes if (inp->inp_vflag & INP_IPV4) { 374101043Sdes sock->family = AF_INET; 375101043Sdes sockaddr(&sock->laddr, sock->family, 376101043Sdes &inp->inp_laddr, inp->inp_lport); 377101043Sdes sockaddr(&sock->faddr, sock->family, 378101043Sdes &inp->inp_faddr, inp->inp_fport); 379101043Sdes } else if (inp->inp_vflag & INP_IPV6) { 380101043Sdes sock->family = AF_INET6; 381101043Sdes sockaddr(&sock->laddr, sock->family, 382189637Srwatson &inp->in6p_laddr, inp->inp_lport); 383101043Sdes sockaddr(&sock->faddr, sock->family, 384189637Srwatson &inp->in6p_faddr, inp->inp_fport); 385101043Sdes } 386101043Sdes sock->vflag = inp->inp_vflag; 387101043Sdes sock->protoname = protoname; 388101043Sdes hash = (int)((uintptr_t)sock->socket % HASHSIZE); 389101043Sdes sock->next = sockhash[hash]; 390101043Sdes sockhash[hash] = sock; 391101043Sdes } 392101043Sdesout: 393101043Sdes free(buf); 394101043Sdes} 395101043Sdes 396101043Sdesstatic void 397101043Sdesgather_unix(int proto) 398101043Sdes{ 399101043Sdes struct xunpgen *xug, *exug; 400101043Sdes struct xunpcb *xup; 401101043Sdes struct sock *sock; 402101043Sdes const char *varname, *protoname; 403101043Sdes size_t len, bufsize; 404101043Sdes void *buf; 405101043Sdes int hash, retry; 406101043Sdes 407101043Sdes switch (proto) { 408101043Sdes case SOCK_STREAM: 409101043Sdes varname = "net.local.stream.pcblist"; 410101043Sdes protoname = "stream"; 411101043Sdes break; 412101043Sdes case SOCK_DGRAM: 413101043Sdes varname = "net.local.dgram.pcblist"; 414101043Sdes protoname = "dgram"; 415101043Sdes break; 416101043Sdes default: 417101043Sdes abort(); 418101043Sdes } 419101043Sdes buf = NULL; 420101043Sdes bufsize = 8192; 421101043Sdes retry = 5; 422101043Sdes do { 423101043Sdes for (;;) { 424101043Sdes if ((buf = realloc(buf, bufsize)) == NULL) 425101043Sdes err(1, "realloc()"); 426101043Sdes len = bufsize; 427101043Sdes if (sysctlbyname(varname, buf, &len, NULL, 0) == 0) 428101043Sdes break; 429230874Strociny if (errno != ENOMEM || len != bufsize) 430101043Sdes err(1, "sysctlbyname()"); 431101043Sdes bufsize *= 2; 432101043Sdes } 433101043Sdes xug = (struct xunpgen *)buf; 434101220Srobert exug = (struct xunpgen *)(void *) 435101220Srobert ((char *)buf + len - sizeof *exug); 436101043Sdes if (xug->xug_len != sizeof *xug || 437101043Sdes exug->xug_len != sizeof *exug) { 438101043Sdes warnx("struct xinpgen size mismatch"); 439101043Sdes goto out; 440101043Sdes } 441101043Sdes } while (xug->xug_gen != exug->xug_gen && retry--); 442101043Sdes 443101043Sdes if (xug->xug_gen != exug->xug_gen && opt_v) 444101043Sdes warnx("warning: data may be inconsistent"); 445101043Sdes 446101043Sdes for (;;) { 447101220Srobert xug = (struct xunpgen *)(void *)((char *)xug + xug->xug_len); 448101043Sdes if (xug >= exug) 449101043Sdes break; 450101043Sdes xup = (struct xunpcb *)xug; 451101043Sdes if (xup->xu_len != sizeof *xup) { 452101043Sdes warnx("struct xunpcb size mismatch"); 453101043Sdes goto out; 454101043Sdes } 455101144Sdes if ((xup->xu_unp.unp_conn == NULL && !opt_l) || 456101144Sdes (xup->xu_unp.unp_conn != NULL && !opt_c)) 457101144Sdes continue; 458101043Sdes if ((sock = calloc(1, sizeof *sock)) == NULL) 459101043Sdes err(1, "malloc()"); 460101043Sdes sock->socket = xup->xu_socket.xso_so; 461101043Sdes sock->pcb = xup->xu_unpp; 462101043Sdes sock->proto = proto; 463101043Sdes sock->family = AF_UNIX; 464101043Sdes sock->protoname = protoname; 465101043Sdes if (xup->xu_unp.unp_addr != NULL) 466101220Srobert sock->laddr = 467101220Srobert *(struct sockaddr_storage *)(void *)&xup->xu_addr; 468101043Sdes else if (xup->xu_unp.unp_conn != NULL) 469101043Sdes *(void **)&sock->faddr = xup->xu_unp.unp_conn; 470101043Sdes hash = (int)((uintptr_t)sock->socket % HASHSIZE); 471101043Sdes sock->next = sockhash[hash]; 472101043Sdes sockhash[hash] = sock; 473101043Sdes } 474101043Sdesout: 475101043Sdes free(buf); 476101043Sdes} 477101043Sdes 478101043Sdesstatic void 479101043Sdesgetfiles(void) 480101043Sdes{ 481230874Strociny size_t len, olen; 482101043Sdes 483230874Strociny olen = len = sizeof *xfiles; 484230874Strociny if ((xfiles = malloc(len)) == NULL) 485101043Sdes err(1, "malloc()"); 486101043Sdes while (sysctlbyname("kern.file", xfiles, &len, 0, 0) == -1) { 487230874Strociny if (errno != ENOMEM || len != olen) 488101043Sdes err(1, "sysctlbyname()"); 489230874Strociny olen = len *= 2; 490101043Sdes if ((xfiles = realloc(xfiles, len)) == NULL) 491101043Sdes err(1, "realloc()"); 492101043Sdes } 493101043Sdes if (len > 0 && xfiles->xf_size != sizeof *xfiles) 494101043Sdes errx(1, "struct xfile size mismatch"); 495101043Sdes nxfiles = len / sizeof *xfiles; 496101043Sdes} 497101043Sdes 498101043Sdesstatic int 499101043Sdesprintaddr(int af, struct sockaddr_storage *ss) 500101043Sdes{ 501101043Sdes char addrstr[INET6_ADDRSTRLEN] = { '\0', '\0' }; 502101043Sdes struct sockaddr_un *sun; 503201385Sed void *addr = NULL; /* Keep compiler happy. */ 504201385Sed int off, port = 0; 505101043Sdes 506101043Sdes switch (af) { 507101043Sdes case AF_INET: 508101043Sdes addr = &((struct sockaddr_in *)ss)->sin_addr; 509101043Sdes if (inet_lnaof(*(struct in_addr *)addr) == INADDR_ANY) 510101043Sdes addrstr[0] = '*'; 511101043Sdes port = ntohs(((struct sockaddr_in *)ss)->sin_port); 512101043Sdes break; 513101043Sdes case AF_INET6: 514101043Sdes addr = &((struct sockaddr_in6 *)ss)->sin6_addr; 515101043Sdes if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)addr)) 516101043Sdes addrstr[0] = '*'; 517101043Sdes port = ntohs(((struct sockaddr_in6 *)ss)->sin6_port); 518101043Sdes break; 519101043Sdes case AF_UNIX: 520101043Sdes sun = (struct sockaddr_un *)ss; 521101043Sdes off = (int)((char *)&sun->sun_path - (char *)sun); 522101043Sdes return (xprintf("%.*s", sun->sun_len - off, sun->sun_path)); 523101043Sdes } 524101043Sdes if (addrstr[0] == '\0') 525101043Sdes inet_ntop(af, addr, addrstr, sizeof addrstr); 526101043Sdes if (port == 0) 527101043Sdes return xprintf("%s:*", addrstr); 528101043Sdes else 529101043Sdes return xprintf("%s:%d", addrstr, port); 530101043Sdes} 531101043Sdes 532101043Sdesstatic const char * 533101043Sdesgetprocname(pid_t pid) 534101043Sdes{ 535101043Sdes static struct kinfo_proc proc; 536101043Sdes size_t len; 537101043Sdes int mib[4]; 538101043Sdes 539101043Sdes mib[0] = CTL_KERN; 540101043Sdes mib[1] = KERN_PROC; 541101043Sdes mib[2] = KERN_PROC_PID; 542101043Sdes mib[3] = (int)pid; 543101043Sdes len = sizeof proc; 544101043Sdes if (sysctl(mib, 4, &proc, &len, NULL, 0) == -1) { 545170833Smaxim /* Do not warn if the process exits before we get its name. */ 546170833Smaxim if (errno != ESRCH) 547170833Smaxim warn("sysctl()"); 548101043Sdes return ("??"); 549101043Sdes } 550167810Semaste return (proc.ki_comm); 551101043Sdes} 552101043Sdes 553115955Smuxstatic int 554235870Sthompsagetprocjid(pid_t pid) 555235870Sthompsa{ 556235870Sthompsa static struct kinfo_proc proc; 557235870Sthompsa size_t len; 558235870Sthompsa int mib[4]; 559235870Sthompsa 560235870Sthompsa mib[0] = CTL_KERN; 561235870Sthompsa mib[1] = KERN_PROC; 562235870Sthompsa mib[2] = KERN_PROC_PID; 563235870Sthompsa mib[3] = (int)pid; 564235870Sthompsa len = sizeof proc; 565235870Sthompsa if (sysctl(mib, 4, &proc, &len, NULL, 0) == -1) { 566235870Sthompsa /* Do not warn if the process exits before we get its jid. */ 567235870Sthompsa if (errno != ESRCH) 568235870Sthompsa warn("sysctl()"); 569235870Sthompsa return (-1); 570235870Sthompsa } 571235870Sthompsa return (proc.ki_jid); 572235870Sthompsa} 573235870Sthompsa 574235870Sthompsastatic int 575115955Smuxcheck_ports(struct sock *s) 576115955Smux{ 577115955Smux int port; 578115955Smux 579115955Smux if (ports == NULL) 580115955Smux return (1); 581115955Smux if ((s->family != AF_INET) && (s->family != AF_INET6)) 582115955Smux return (1); 583115955Smux if (s->family == AF_INET) 584115955Smux port = ntohs(((struct sockaddr_in *)(&s->laddr))->sin_port); 585115955Smux else 586115955Smux port = ntohs(((struct sockaddr_in6 *)(&s->laddr))->sin6_port); 587115955Smux if (CHK_PORT(port)) 588115955Smux return (1); 589115955Smux if (s->family == AF_INET) 590115955Smux port = ntohs(((struct sockaddr_in *)(&s->faddr))->sin_port); 591115955Smux else 592115955Smux port = ntohs(((struct sockaddr_in6 *)(&s->faddr))->sin6_port); 593115955Smux if (CHK_PORT(port)) 594115955Smux return (1); 595115955Smux return (0); 596115955Smux} 597115955Smux 598101043Sdesstatic void 599230512Sjillesdisplaysock(struct sock *s, int pos) 600230512Sjilles{ 601230512Sjilles void *p; 602230512Sjilles int hash; 603230512Sjilles 604230512Sjilles while (pos < 29) 605230512Sjilles pos += xprintf(" "); 606230512Sjilles pos += xprintf("%s", s->protoname); 607230512Sjilles if (s->vflag & INP_IPV4) 608230512Sjilles pos += xprintf("4 "); 609230512Sjilles if (s->vflag & INP_IPV6) 610230512Sjilles pos += xprintf("6 "); 611230512Sjilles while (pos < 36) 612230512Sjilles pos += xprintf(" "); 613230512Sjilles switch (s->family) { 614230512Sjilles case AF_INET: 615230512Sjilles case AF_INET6: 616230512Sjilles pos += printaddr(s->family, &s->laddr); 617230512Sjilles if (s->family == AF_INET6 && pos >= 58) 618230512Sjilles pos += xprintf(" "); 619230512Sjilles while (pos < 58) 620230512Sjilles pos += xprintf(" "); 621230512Sjilles pos += printaddr(s->family, &s->faddr); 622230512Sjilles break; 623230512Sjilles case AF_UNIX: 624230512Sjilles /* server */ 625230512Sjilles if (s->laddr.ss_len > 0) { 626230512Sjilles pos += printaddr(s->family, &s->laddr); 627230512Sjilles break; 628230512Sjilles } 629230512Sjilles /* client */ 630230512Sjilles p = *(void **)&s->faddr; 631230512Sjilles if (p == NULL) { 632230512Sjilles pos += xprintf("(not connected)"); 633230512Sjilles break; 634230512Sjilles } 635230512Sjilles pos += xprintf("-> "); 636230512Sjilles for (hash = 0; hash < HASHSIZE; ++hash) { 637230512Sjilles for (s = sockhash[hash]; s != NULL; s = s->next) 638230512Sjilles if (s->pcb == p) 639230512Sjilles break; 640230512Sjilles if (s != NULL) 641230512Sjilles break; 642230512Sjilles } 643230512Sjilles if (s == NULL || s->laddr.ss_len == 0) 644230512Sjilles pos += xprintf("??"); 645230512Sjilles else 646230512Sjilles pos += printaddr(s->family, &s->laddr); 647230512Sjilles break; 648230512Sjilles default: 649230512Sjilles abort(); 650230512Sjilles } 651230512Sjilles xprintf("\n"); 652230512Sjilles} 653230512Sjilles 654230512Sjillesstatic void 655101043Sdesdisplay(void) 656101043Sdes{ 657101043Sdes struct passwd *pwd; 658101043Sdes struct xfile *xf; 659101043Sdes struct sock *s; 660101043Sdes int hash, n, pos; 661101043Sdes 662101043Sdes printf("%-8s %-10s %-5s %-2s %-6s %-21s %-21s\n", 663101043Sdes "USER", "COMMAND", "PID", "FD", "PROTO", 664101043Sdes "LOCAL ADDRESS", "FOREIGN ADDRESS"); 665101043Sdes setpassent(1); 666101043Sdes for (xf = xfiles, n = 0; n < nxfiles; ++n, ++xf) { 667134295Sroam if (xf->xf_data == NULL) 668134295Sroam continue; 669235870Sthompsa if (opt_j >= 0 && opt_j != getprocjid(xf->xf_pid)) 670235870Sthompsa continue; 671109153Sdillon hash = (int)((uintptr_t)xf->xf_data % HASHSIZE); 672101043Sdes for (s = sockhash[hash]; s != NULL; s = s->next) 673109153Sdillon if ((void *)s->socket == xf->xf_data) 674101043Sdes break; 675101043Sdes if (s == NULL) 676101043Sdes continue; 677115955Smux if (!check_ports(s)) 678115955Smux continue; 679230512Sjilles s->shown = 1; 680101043Sdes pos = 0; 681101043Sdes if ((pwd = getpwuid(xf->xf_uid)) == NULL) 682187915Sdes pos += xprintf("%lu ", (u_long)xf->xf_uid); 683101043Sdes else 684187915Sdes pos += xprintf("%s ", pwd->pw_name); 685101043Sdes while (pos < 9) 686101043Sdes pos += xprintf(" "); 687101043Sdes pos += xprintf("%.10s", getprocname(xf->xf_pid)); 688101043Sdes while (pos < 20) 689101043Sdes pos += xprintf(" "); 690187915Sdes pos += xprintf("%lu ", (u_long)xf->xf_pid); 691101043Sdes while (pos < 26) 692101043Sdes pos += xprintf(" "); 693187915Sdes pos += xprintf("%d ", xf->xf_fd); 694230512Sjilles displaysock(s, pos); 695230512Sjilles } 696235870Sthompsa if (opt_j >= 0) 697235870Sthompsa return; 698230512Sjilles for (hash = 0; hash < HASHSIZE; hash++) { 699230512Sjilles for (s = sockhash[hash]; s != NULL; s = s->next) { 700230512Sjilles if (s->shown) 701230512Sjilles continue; 702230512Sjilles if (!check_ports(s)) 703230512Sjilles continue; 704230512Sjilles pos = 0; 705230512Sjilles pos += xprintf("%-8s %-10s %-5s %-2s ", 706230512Sjilles "?", "?", "?", "?"); 707230512Sjilles displaysock(s, pos); 708101043Sdes } 709101043Sdes } 710101043Sdes} 711101043Sdes 712164201Skeramidastatic int set_default_protos(void) 713164201Skeramida{ 714164201Skeramida struct protoent *prot; 715164201Skeramida const char *pname; 716164201Skeramida size_t pindex; 717164201Skeramida 718164201Skeramida init_protos(default_numprotos); 719164201Skeramida 720164201Skeramida for (pindex = 0; pindex < default_numprotos; pindex++) { 721164201Skeramida pname = default_protos[pindex]; 722164201Skeramida prot = getprotobyname(pname); 723164201Skeramida if (prot == NULL) 724164201Skeramida err(1, "getprotobyname: %s", pname); 725164201Skeramida protos[pindex] = prot->p_proto; 726164201Skeramida } 727164201Skeramida numprotos = pindex; 728164201Skeramida return (pindex); 729164201Skeramida} 730164201Skeramida 731164201Skeramida 732101043Sdesstatic void 733101043Sdesusage(void) 734101043Sdes{ 735164201Skeramida fprintf(stderr, 736237674Sthompsa "Usage: sockstat [-46cLlu] [-j jid] [-p ports] [-P protocols]\n"); 737101043Sdes exit(1); 738101043Sdes} 739101043Sdes 740101043Sdesint 741101043Sdesmain(int argc, char *argv[]) 742101043Sdes{ 743164201Skeramida int protos_defined = -1; 744164201Skeramida int o, i; 745101043Sdes 746235870Sthompsa opt_j = -1; 747235870Sthompsa while ((o = getopt(argc, argv, "46cj:Llp:P:uv")) != -1) 748101043Sdes switch (o) { 749101043Sdes case '4': 750101043Sdes opt_4 = 1; 751101043Sdes break; 752101043Sdes case '6': 753101043Sdes opt_6 = 1; 754101043Sdes break; 755101043Sdes case 'c': 756101043Sdes opt_c = 1; 757101043Sdes break; 758235870Sthompsa case 'j': 759235870Sthompsa opt_j = atoi(optarg); 760235870Sthompsa break; 761179115Sbms case 'L': 762179115Sbms opt_L = 1; 763179115Sbms break; 764101043Sdes case 'l': 765101043Sdes opt_l = 1; 766101043Sdes break; 767101043Sdes case 'p': 768101043Sdes parse_ports(optarg); 769101043Sdes break; 770164201Skeramida case 'P': 771164201Skeramida protos_defined = parse_protos(optarg); 772164201Skeramida break; 773101043Sdes case 'u': 774101043Sdes opt_u = 1; 775101043Sdes break; 776101043Sdes case 'v': 777101043Sdes ++opt_v; 778101043Sdes break; 779101043Sdes default: 780101043Sdes usage(); 781101043Sdes } 782101043Sdes 783101043Sdes argc -= optind; 784101043Sdes argv += optind; 785101043Sdes 786101043Sdes if (argc > 0) 787101043Sdes usage(); 788101043Sdes 789164226Skeramida if ((!opt_4 && !opt_6) && protos_defined != -1) 790164226Skeramida opt_4 = opt_6 = 1; 791164226Skeramida if (!opt_4 && !opt_6 && !opt_u) 792164226Skeramida opt_4 = opt_6 = opt_u = 1; 793164226Skeramida if ((opt_4 || opt_6) && protos_defined == -1) 794164201Skeramida protos_defined = set_default_protos(); 795101043Sdes if (!opt_c && !opt_l) 796101043Sdes opt_c = opt_l = 1; 797101043Sdes 798101043Sdes if (opt_4 || opt_6) { 799164201Skeramida for (i = 0; i < protos_defined; i++) 800164201Skeramida gather_inet(protos[i]); 801101043Sdes } 802164201Skeramida 803164201Skeramida if (opt_u || (protos_defined == -1 && !opt_4 && !opt_6)) { 804101043Sdes gather_unix(SOCK_STREAM); 805101043Sdes gather_unix(SOCK_DGRAM); 806101043Sdes } 807101043Sdes getfiles(); 808101043Sdes display(); 809101043Sdes exit(0); 810101043Sdes} 811