1 /*- 2 * Copyright (c) 2002 Dag-Erling Co�dan Sm�rgrav 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/socket.h> 34 #include <sys/socketvar.h> 35 #include <sys/sysctl.h> 36 #include <sys/file.h> 37 #include <sys/user.h> 38 39 #include <sys/un.h> 40 #include <sys/unpcb.h> 41 42 #include <net/route.h> 43 44 #include <netinet/in.h> 45 #include <netinet/in_pcb.h> 46 #include <netinet/tcp.h> 47 #include <netinet/tcp_seq.h> 48 #include <netinet/tcp_var.h> 49 #include <arpa/inet.h> 50 51 #include <ctype.h> 52 #include <err.h> 53 #include <errno.h> 54 #include <netdb.h> 55 #include <pwd.h> 56 #include <stdarg.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <unistd.h> 61 62 static int opt_4; /* Show IPv4 sockets */ 63 static int opt_6; /* Show IPv6 sockets */ 64 static int opt_c; /* Show connected sockets */ 65 static int opt_L; /* Don't show IPv4 or IPv6 loopback sockets */ 66 static int opt_l; /* Show listening sockets */ 67 static int opt_u; /* Show Unix domain sockets */ 68 static int opt_v; /* Verbose mode */ 69 70 /* 71 * Default protocols to use if no -P was defined. 72 */ 73 static const char *default_protos[] = {"tcp", "udp", "divert" }; 74 static size_t default_numprotos = 75 sizeof(default_protos) / sizeof(default_protos[0]); 76 77 static int *protos; /* protocols to use */ 78 static size_t numprotos; /* allocated size of protos[] */ 79 80 static int *ports; 81 82 #define INT_BIT (sizeof(int)*CHAR_BIT) 83 #define SET_PORT(p) do { ports[p / INT_BIT] |= 1 << (p % INT_BIT); } while (0) 84 #define CHK_PORT(p) (ports[p / INT_BIT] & (1 << (p % INT_BIT))) 85 86 struct sock { 87 void *socket; 88 void *pcb; 89 int vflag; 90 int family; 91 int proto; 92 const char *protoname; 93 struct sockaddr_storage laddr; 94 struct sockaddr_storage faddr; 95 struct sock *next; 96 }; 97 98 #define HASHSIZE 1009 99 static struct sock *sockhash[HASHSIZE]; 100 101 static struct xfile *xfiles; 102 static int nxfiles; 103 104 static int 105 xprintf(const char *fmt, ...) 106 { 107 va_list ap; 108 int len; 109 110 va_start(ap, fmt); 111 len = vprintf(fmt, ap); 112 va_end(ap); 113 if (len < 0) 114 err(1, "printf()"); 115 return (len); 116 } 117 118 119 static int 120 get_proto_type(const char *proto) 121 { 122 struct protoent *pent; 123 124 if (strlen(proto) == 0) 125 return (0); 126 pent = getprotobyname(proto); 127 if (pent == NULL) { 128 warn("getprotobyname"); 129 return (-1); 130 } 131 return (pent->p_proto); 132 } 133 134 135 static void init_protos(int num) 136 { 137 int proto_count = 0; 138 139 if (num > 0) { 140 proto_count = num; 141 } else { 142 /* Find the maximum number of possible protocols. */ 143 while (getprotoent() != NULL) 144 proto_count++; 145 endprotoent(); 146 } 147 148 if ((protos = malloc(sizeof(int) * proto_count)) == NULL) 149 err(1, "malloc"); 150 numprotos = proto_count; 151 } 152 153 154 static int 155 parse_protos(char *protospec) 156 { 157 char *prot; 158 char *tmp = protospec; 159 int proto_type, proto_index; 160 161 if (protospec == NULL) 162 return (-1); 163 164 init_protos(0); 165 proto_index = 0; 166 while ((prot = strsep(&tmp, ",")) != NULL) { 167 if (strlen(prot) == 0) 168 continue; 169 proto_type = get_proto_type(prot); 170 if (proto_type != -1) 171 protos[proto_index++] = proto_type; 172 } 173 numprotos = proto_index; 174 return (proto_index); 175 } 176 177 178 static void 179 parse_ports(const char *portspec) 180 { 181 const char *p, *q; 182 int port, end; 183 184 if (ports == NULL) 185 if ((ports = calloc(65536 / INT_BIT, sizeof(int))) == NULL) 186 err(1, "calloc()"); 187 p = portspec; 188 while (*p != '\0') { 189 if (!isdigit(*p)) 190 errx(1, "syntax error in port range"); 191 for (q = p; *q != '\0' && isdigit(*q); ++q) 192 /* nothing */ ; 193 for (port = 0; p < q; ++p) 194 port = port * 10 + digittoint(*p); 195 if (port < 0 || port > 65535) 196 errx(1, "invalid port number"); 197 SET_PORT(port); 198 switch (*p) { 199 case '-': 200 ++p; 201 break; 202 case ',': 203 ++p; 204 /* fall through */ 205 case '\0': 206 default: 207 continue; 208 } 209 for (q = p; *q != '\0' && isdigit(*q); ++q) 210 /* nothing */ ; 211 for (end = 0; p < q; ++p) 212 end = end * 10 + digittoint(*p); 213 if (end < port || end > 65535) 214 errx(1, "invalid port number"); 215 while (port++ < end) 216 SET_PORT(port); 217 if (*p == ',') 218 ++p; 219 } 220 } 221 222 static void 223 sockaddr(struct sockaddr_storage *sa, int af, void *addr, int port) 224 { 225 struct sockaddr_in *sin4; 226 struct sockaddr_in6 *sin6; 227 228 bzero(sa, sizeof *sa); 229 switch (af) { 230 case AF_INET: 231 sin4 = (struct sockaddr_in *)sa; 232 sin4->sin_len = sizeof *sin4; 233 sin4->sin_family = af; 234 sin4->sin_port = port; 235 sin4->sin_addr = *(struct in_addr *)addr; 236 break; 237 case AF_INET6: 238 sin6 = (struct sockaddr_in6 *)sa; 239 sin6->sin6_len = sizeof *sin6; 240 sin6->sin6_family = af; 241 sin6->sin6_port = port; 242 sin6->sin6_addr = *(struct in6_addr *)addr; 243 break; 244 default: 245 abort(); 246 } 247 } 248 249 static void 250 gather_inet(int proto) 251 { 252 struct xinpgen *xig, *exig; 253 struct xinpcb *xip; 254 struct xtcpcb *xtp; 255 struct inpcb *inp; 256 struct xsocket *so; 257 struct sock *sock; 258 const char *varname, *protoname; 259 size_t len, bufsize; 260 void *buf; 261 int hash, retry, vflag; 262 263 vflag = 0; 264 if (opt_4) 265 vflag |= INP_IPV4; 266 if (opt_6) 267 vflag |= INP_IPV6; 268 269 switch (proto) { 270 case IPPROTO_TCP: 271 varname = "net.inet.tcp.pcblist"; 272 protoname = "tcp"; 273 break; 274 case IPPROTO_UDP: 275 varname = "net.inet.udp.pcblist"; 276 protoname = "udp"; 277 break; 278 case IPPROTO_DIVERT: 279 varname = "net.inet.divert.pcblist"; 280 protoname = "div"; 281 break; 282 default: 283 errx(1, "protocol %d not supported", proto); 284 } 285 286 buf = NULL; 287 bufsize = 8192; 288 retry = 5; 289 do { 290 for (;;) { 291 if ((buf = realloc(buf, bufsize)) == NULL) 292 err(1, "realloc()"); 293 len = bufsize; 294 if (sysctlbyname(varname, buf, &len, NULL, 0) == 0) 295 break; 296 if (errno == ENOENT) 297 goto out; 298 if (errno != ENOMEM) 299 err(1, "sysctlbyname()"); 300 bufsize *= 2; 301 } 302 xig = (struct xinpgen *)buf; 303 exig = (struct xinpgen *)(void *) 304 ((char *)buf + len - sizeof *exig); 305 if (xig->xig_len != sizeof *xig || 306 exig->xig_len != sizeof *exig) 307 errx(1, "struct xinpgen size mismatch"); 308 } while (xig->xig_gen != exig->xig_gen && retry--); 309 310 if (xig->xig_gen != exig->xig_gen && opt_v) 311 warnx("warning: data may be inconsistent"); 312 313 for (;;) { 314 xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len); 315 if (xig >= exig) 316 break; 317 switch (proto) { 318 case IPPROTO_TCP: 319 xtp = (struct xtcpcb *)xig; 320 if (xtp->xt_len != sizeof *xtp) { 321 warnx("struct xtcpcb size mismatch"); 322 goto out; 323 } 324 inp = &xtp->xt_inp; 325 so = &xtp->xt_socket; 326 break; 327 case IPPROTO_UDP: 328 case IPPROTO_DIVERT: 329 xip = (struct xinpcb *)xig; 330 if (xip->xi_len != sizeof *xip) { 331 warnx("struct xinpcb size mismatch"); 332 goto out; 333 } 334 inp = &xip->xi_inp; 335 so = &xip->xi_socket; 336 break; 337 default: 338 errx(1, "protocol %d not supported", proto); 339 } 340 if ((inp->inp_vflag & vflag) == 0) 341 continue; 342 if (inp->inp_vflag & INP_IPV4) { 343 if ((inp->inp_fport == 0 && !opt_l) || 344 (inp->inp_fport != 0 && !opt_c)) 345 continue; 346 #define __IN_IS_ADDR_LOOPBACK(pina) \ 347 ((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) 348 if (opt_L && 349 (__IN_IS_ADDR_LOOPBACK(&inp->inp_faddr) || 350 __IN_IS_ADDR_LOOPBACK(&inp->inp_laddr))) 351 continue; 352 #undef __IN_IS_ADDR_LOOPBACK 353 } else if (inp->inp_vflag & INP_IPV6) { 354 if ((inp->inp_fport == 0 && !opt_l) || 355 (inp->inp_fport != 0 && !opt_c)) 356 continue; 357 if (opt_L && 358 (IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr) || 359 IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr))) 360 continue; 361 } else { 362 if (opt_v) 363 warnx("invalid vflag 0x%x", inp->inp_vflag); 364 continue; 365 } 366 if ((sock = calloc(1, sizeof *sock)) == NULL) 367 err(1, "malloc()"); 368 sock->socket = so->xso_so; 369 sock->proto = proto; 370 if (inp->inp_vflag & INP_IPV4) { 371 sock->family = AF_INET; 372 sockaddr(&sock->laddr, sock->family, 373 &inp->inp_laddr, inp->inp_lport); 374 sockaddr(&sock->faddr, sock->family, 375 &inp->inp_faddr, inp->inp_fport); 376 } else if (inp->inp_vflag & INP_IPV6) { 377 sock->family = AF_INET6; 378 sockaddr(&sock->laddr, sock->family, 379 &inp->in6p_laddr, inp->inp_lport); 380 sockaddr(&sock->faddr, sock->family, 381 &inp->in6p_faddr, inp->inp_fport); 382 } 383 sock->vflag = inp->inp_vflag; 384 sock->protoname = protoname; 385 hash = (int)((uintptr_t)sock->socket % HASHSIZE); 386 sock->next = sockhash[hash]; 387 sockhash[hash] = sock; 388 } 389 out: 390 free(buf); 391 } 392 393 static void 394 gather_unix(int proto) 395 { 396 struct xunpgen *xug, *exug; 397 struct xunpcb *xup; 398 struct sock *sock; 399 const char *varname, *protoname; 400 size_t len, bufsize; 401 void *buf; 402 int hash, retry; 403 404 switch (proto) { 405 case SOCK_STREAM: 406 varname = "net.local.stream.pcblist"; 407 protoname = "stream"; 408 break; 409 case SOCK_DGRAM: 410 varname = "net.local.dgram.pcblist"; 411 protoname = "dgram"; 412 break; 413 default: 414 abort(); 415 } 416 buf = NULL; 417 bufsize = 8192; 418 retry = 5; 419 do { 420 for (;;) { 421 if ((buf = realloc(buf, bufsize)) == NULL) 422 err(1, "realloc()"); 423 len = bufsize; 424 if (sysctlbyname(varname, buf, &len, NULL, 0) == 0) 425 break; 426 if (errno != ENOMEM) 427 err(1, "sysctlbyname()"); 428 bufsize *= 2; 429 } 430 xug = (struct xunpgen *)buf; 431 exug = (struct xunpgen *)(void *) 432 ((char *)buf + len - sizeof *exug); 433 if (xug->xug_len != sizeof *xug || 434 exug->xug_len != sizeof *exug) { 435 warnx("struct xinpgen size mismatch"); 436 goto out; 437 } 438 } while (xug->xug_gen != exug->xug_gen && retry--); 439 440 if (xug->xug_gen != exug->xug_gen && opt_v) 441 warnx("warning: data may be inconsistent"); 442 443 for (;;) { 444 xug = (struct xunpgen *)(void *)((char *)xug + xug->xug_len); 445 if (xug >= exug) 446 break; 447 xup = (struct xunpcb *)xug; 448 if (xup->xu_len != sizeof *xup) { 449 warnx("struct xunpcb size mismatch"); 450 goto out; 451 } 452 if ((xup->xu_unp.unp_conn == NULL && !opt_l) || 453 (xup->xu_unp.unp_conn != NULL && !opt_c)) 454 continue; 455 if ((sock = calloc(1, sizeof *sock)) == NULL) 456 err(1, "malloc()"); 457 sock->socket = xup->xu_socket.xso_so; 458 sock->pcb = xup->xu_unpp; 459 sock->proto = proto; 460 sock->family = AF_UNIX; 461 sock->protoname = protoname; 462 if (xup->xu_unp.unp_addr != NULL) 463 sock->laddr = 464 *(struct sockaddr_storage *)(void *)&xup->xu_addr; 465 else if (xup->xu_unp.unp_conn != NULL) 466 *(void **)&sock->faddr = xup->xu_unp.unp_conn; 467 hash = (int)((uintptr_t)sock->socket % HASHSIZE); 468 sock->next = sockhash[hash]; 469 sockhash[hash] = sock; 470 } 471 out: 472 free(buf); 473 } 474 475 static void 476 getfiles(void) 477 { 478 size_t len; 479 480 if ((xfiles = malloc(len = sizeof *xfiles)) == NULL) 481 err(1, "malloc()"); 482 while (sysctlbyname("kern.file", xfiles, &len, 0, 0) == -1) { 483 if (errno != ENOMEM) 484 err(1, "sysctlbyname()"); 485 len *= 2; 486 if ((xfiles = realloc(xfiles, len)) == NULL) 487 err(1, "realloc()"); 488 } 489 if (len > 0 && xfiles->xf_size != sizeof *xfiles) 490 errx(1, "struct xfile size mismatch"); 491 nxfiles = len / sizeof *xfiles; 492 } 493 494 static int 495 printaddr(int af, struct sockaddr_storage *ss) 496 { 497 char addrstr[INET6_ADDRSTRLEN] = { '\0', '\0' }; 498 struct sockaddr_un *sun; 499 void *addr = NULL; /* Keep compiler happy. */ 500 int off, port = 0; 501 502 switch (af) { 503 case AF_INET: 504 addr = &((struct sockaddr_in *)ss)->sin_addr; 505 if (inet_lnaof(*(struct in_addr *)addr) == INADDR_ANY) 506 addrstr[0] = '*'; 507 port = ntohs(((struct sockaddr_in *)ss)->sin_port); 508 break; 509 case AF_INET6: 510 addr = &((struct sockaddr_in6 *)ss)->sin6_addr; 511 if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)addr)) 512 addrstr[0] = '*'; 513 port = ntohs(((struct sockaddr_in6 *)ss)->sin6_port); 514 break; 515 case AF_UNIX: 516 sun = (struct sockaddr_un *)ss; 517 off = (int)((char *)&sun->sun_path - (char *)sun); 518 return (xprintf("%.*s", sun->sun_len - off, sun->sun_path)); 519 } 520 if (addrstr[0] == '\0') 521 inet_ntop(af, addr, addrstr, sizeof addrstr); 522 if (port == 0) 523 return xprintf("%s:*", addrstr); 524 else 525 return xprintf("%s:%d", addrstr, port); 526 } 527 528 static const char * 529 getprocname(pid_t pid) 530 { 531 static struct kinfo_proc proc; 532 size_t len; 533 int mib[4]; 534 535 mib[0] = CTL_KERN; 536 mib[1] = KERN_PROC; 537 mib[2] = KERN_PROC_PID; 538 mib[3] = (int)pid; 539 len = sizeof proc; 540 if (sysctl(mib, 4, &proc, &len, NULL, 0) == -1) { 541 /* Do not warn if the process exits before we get its name. */ 542 if (errno != ESRCH) 543 warn("sysctl()"); 544 return ("??"); 545 } 546 return (proc.ki_comm); 547 } 548 549 static int 550 check_ports(struct sock *s) 551 { 552 int port; 553 554 if (ports == NULL) 555 return (1); 556 if ((s->family != AF_INET) && (s->family != AF_INET6)) 557 return (1); 558 if (s->family == AF_INET) 559 port = ntohs(((struct sockaddr_in *)(&s->laddr))->sin_port); 560 else 561 port = ntohs(((struct sockaddr_in6 *)(&s->laddr))->sin6_port); 562 if (CHK_PORT(port)) 563 return (1); 564 if (s->family == AF_INET) 565 port = ntohs(((struct sockaddr_in *)(&s->faddr))->sin_port); 566 else 567 port = ntohs(((struct sockaddr_in6 *)(&s->faddr))->sin6_port); 568 if (CHK_PORT(port)) 569 return (1); 570 return (0); 571 } 572 573 static void 574 display(void) 575 { 576 struct passwd *pwd; 577 struct xfile *xf; 578 struct sock *s; 579 void *p; 580 int hash, n, pos; 581 582 printf("%-8s %-10s %-5s %-2s %-6s %-21s %-21s\n", 583 "USER", "COMMAND", "PID", "FD", "PROTO", 584 "LOCAL ADDRESS", "FOREIGN ADDRESS"); 585 setpassent(1); 586 for (xf = xfiles, n = 0; n < nxfiles; ++n, ++xf) { 587 if (xf->xf_data == NULL) 588 continue; 589 hash = (int)((uintptr_t)xf->xf_data % HASHSIZE); 590 for (s = sockhash[hash]; s != NULL; s = s->next) 591 if ((void *)s->socket == xf->xf_data) 592 break; 593 if (s == NULL) 594 continue; 595 if (!check_ports(s)) 596 continue; 597 pos = 0; 598 if ((pwd = getpwuid(xf->xf_uid)) == NULL) 599 pos += xprintf("%lu ", (u_long)xf->xf_uid); 600 else 601 pos += xprintf("%s ", pwd->pw_name); 602 while (pos < 9) 603 pos += xprintf(" "); 604 pos += xprintf("%.10s", getprocname(xf->xf_pid)); 605 while (pos < 20) 606 pos += xprintf(" "); 607 pos += xprintf("%lu ", (u_long)xf->xf_pid); 608 while (pos < 26) 609 pos += xprintf(" "); 610 pos += xprintf("%d ", xf->xf_fd); 611 while (pos < 29) 612 pos += xprintf(" "); 613 pos += xprintf("%s", s->protoname); 614 if (s->vflag & INP_IPV4) 615 pos += xprintf("4 "); 616 if (s->vflag & INP_IPV6) 617 pos += xprintf("6 "); 618 while (pos < 36) 619 pos += xprintf(" "); 620 switch (s->family) { 621 case AF_INET: 622 case AF_INET6: 623 pos += printaddr(s->family, &s->laddr); 624 if (s->family == AF_INET6 && pos >= 58) 625 pos += xprintf(" "); 626 while (pos < 58) 627 pos += xprintf(" "); 628 pos += printaddr(s->family, &s->faddr); 629 break; 630 case AF_UNIX: 631 /* server */ 632 if (s->laddr.ss_len > 0) { 633 pos += printaddr(s->family, &s->laddr); 634 break; 635 } 636 /* client */ 637 p = *(void **)&s->faddr; 638 if (p == NULL) { 639 pos += xprintf("(not connected)"); 640 break; 641 } 642 pos += xprintf("-> "); 643 for (hash = 0; hash < HASHSIZE; ++hash) { 644 for (s = sockhash[hash]; s != NULL; s = s->next) 645 if (s->pcb == p) 646 break; 647 if (s != NULL) 648 break; 649 } 650 if (s == NULL || s->laddr.ss_len == 0) 651 pos += xprintf("??"); 652 else 653 pos += printaddr(s->family, &s->laddr); 654 break; 655 default: 656 abort(); 657 } 658 xprintf("\n"); 659 } 660 } 661 662 static int set_default_protos(void) 663 { 664 struct protoent *prot; 665 const char *pname; 666 size_t pindex; 667 668 init_protos(default_numprotos); 669 670 for (pindex = 0; pindex < default_numprotos; pindex++) { 671 pname = default_protos[pindex]; 672 prot = getprotobyname(pname); 673 if (prot == NULL) 674 err(1, "getprotobyname: %s", pname); 675 protos[pindex] = prot->p_proto; 676 } 677 numprotos = pindex; 678 return (pindex); 679 } 680 681 682 static void 683 usage(void) 684 { 685 fprintf(stderr, 686 "Usage: sockstat [-46cLlu] [-p ports] [-P protocols]\n"); 687 exit(1); 688 } 689 690 int 691 main(int argc, char *argv[]) 692 { 693 int protos_defined = -1; 694 int o, i; 695 696 while ((o = getopt(argc, argv, "46cLlp:P:uv")) != -1) 697 switch (o) { 698 case '4': 699 opt_4 = 1; 700 break; 701 case '6': 702 opt_6 = 1; 703 break; 704 case 'c': 705 opt_c = 1; 706 break; 707 case 'L': 708 opt_L = 1; 709 break; 710 case 'l': 711 opt_l = 1; 712 break; 713 case 'p': 714 parse_ports(optarg); 715 break; 716 case 'P': 717 protos_defined = parse_protos(optarg); 718 break; 719 case 'u': 720 opt_u = 1; 721 break; 722 case 'v': 723 ++opt_v; 724 break; 725 default: 726 usage(); 727 } 728 729 argc -= optind; 730 argv += optind; 731 732 if (argc > 0) 733 usage(); 734 735 if ((!opt_4 && !opt_6) && protos_defined != -1) 736 opt_4 = opt_6 = 1; 737 if (!opt_4 && !opt_6 && !opt_u) 738 opt_4 = opt_6 = opt_u = 1; 739 if ((opt_4 || opt_6) && protos_defined == -1) 740 protos_defined = set_default_protos(); 741 if (!opt_c && !opt_l) 742 opt_c = opt_l = 1; 743 744 if (opt_4 || opt_6) { 745 for (i = 0; i < protos_defined; i++) 746 gather_inet(protos[i]); 747 } 748 749 if (opt_u || (protos_defined == -1 && !opt_4 && !opt_6)) { 750 gather_unix(SOCK_STREAM); 751 gather_unix(SOCK_DGRAM); 752 } 753 getfiles(); 754 display(); 755 exit(0); 756 } 757