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 shown; 90 int vflag; 91 int family; 92 int proto; 93 const char *protoname; 94 struct sockaddr_storage laddr; 95 struct sockaddr_storage faddr; 96 struct sock *next; 97 }; 98 99 #define HASHSIZE 1009 100 static struct sock *sockhash[HASHSIZE]; 101 102 static struct xfile *xfiles; 103 static int nxfiles; 104 105 static int 106 xprintf(const char *fmt, ...) 107 { 108 va_list ap; 109 int len; 110 111 va_start(ap, fmt); 112 len = vprintf(fmt, ap); 113 va_end(ap); 114 if (len < 0) 115 err(1, "printf()"); 116 return (len); 117 } 118 119 120 static int 121 get_proto_type(const char *proto) 122 { 123 struct protoent *pent; 124 125 if (strlen(proto) == 0) 126 return (0); 127 pent = getprotobyname(proto); 128 if (pent == NULL) { 129 warn("getprotobyname"); 130 return (-1); 131 } 132 return (pent->p_proto); 133 } 134 135 136 static void init_protos(int num) 137 { 138 int proto_count = 0; 139 140 if (num > 0) { 141 proto_count = num; 142 } else { 143 /* Find the maximum number of possible protocols. */ 144 while (getprotoent() != NULL) 145 proto_count++; 146 endprotoent(); 147 } 148 149 if ((protos = malloc(sizeof(int) * proto_count)) == NULL) 150 err(1, "malloc"); 151 numprotos = proto_count; 152 } 153 154 155 static int 156 parse_protos(char *protospec) 157 { 158 char *prot; 159 char *tmp = protospec; 160 int proto_type, proto_index; 161 162 if (protospec == NULL) 163 return (-1); 164 165 init_protos(0); 166 proto_index = 0; 167 while ((prot = strsep(&tmp, ",")) != NULL) { 168 if (strlen(prot) == 0) 169 continue; 170 proto_type = get_proto_type(prot); 171 if (proto_type != -1) 172 protos[proto_index++] = proto_type; 173 } 174 numprotos = proto_index; 175 return (proto_index); 176 } 177 178 179 static void 180 parse_ports(const char *portspec) 181 { 182 const char *p, *q; 183 int port, end; 184 185 if (ports == NULL) 186 if ((ports = calloc(65536 / INT_BIT, sizeof(int))) == NULL) 187 err(1, "calloc()"); 188 p = portspec; 189 while (*p != '\0') { 190 if (!isdigit(*p)) 191 errx(1, "syntax error in port range"); 192 for (q = p; *q != '\0' && isdigit(*q); ++q) 193 /* nothing */ ; 194 for (port = 0; p < q; ++p) 195 port = port * 10 + digittoint(*p); 196 if (port < 0 || port > 65535) 197 errx(1, "invalid port number"); 198 SET_PORT(port); 199 switch (*p) { 200 case '-': 201 ++p; 202 break; 203 case ',': 204 ++p; 205 /* fall through */ 206 case '\0': 207 default: 208 continue; 209 } 210 for (q = p; *q != '\0' && isdigit(*q); ++q) 211 /* nothing */ ; 212 for (end = 0; p < q; ++p) 213 end = end * 10 + digittoint(*p); 214 if (end < port || end > 65535) 215 errx(1, "invalid port number"); 216 while (port++ < end) 217 SET_PORT(port); 218 if (*p == ',') 219 ++p; 220 } 221 } 222 223 static void 224 sockaddr(struct sockaddr_storage *sa, int af, void *addr, int port) 225 { 226 struct sockaddr_in *sin4; 227 struct sockaddr_in6 *sin6; 228 229 bzero(sa, sizeof *sa); 230 switch (af) { 231 case AF_INET: 232 sin4 = (struct sockaddr_in *)sa; 233 sin4->sin_len = sizeof *sin4; 234 sin4->sin_family = af; 235 sin4->sin_port = port; 236 sin4->sin_addr = *(struct in_addr *)addr; 237 break; 238 case AF_INET6: 239 sin6 = (struct sockaddr_in6 *)sa; 240 sin6->sin6_len = sizeof *sin6; 241 sin6->sin6_family = af; 242 sin6->sin6_port = port; 243 sin6->sin6_addr = *(struct in6_addr *)addr; 244 break; 245 default: 246 abort(); 247 } 248 } 249 250 static void 251 gather_inet(int proto) 252 { 253 struct xinpgen *xig, *exig; 254 struct xinpcb *xip; 255 struct xtcpcb *xtp; 256 struct inpcb *inp; 257 struct xsocket *so; 258 struct sock *sock; 259 const char *varname, *protoname; 260 size_t len, bufsize; 261 void *buf; 262 int hash, retry, vflag; 263 264 vflag = 0; 265 if (opt_4) 266 vflag |= INP_IPV4; 267 if (opt_6) 268 vflag |= INP_IPV6; 269 270 switch (proto) { 271 case IPPROTO_TCP: 272 varname = "net.inet.tcp.pcblist"; 273 protoname = "tcp"; 274 break; 275 case IPPROTO_UDP: 276 varname = "net.inet.udp.pcblist"; 277 protoname = "udp"; 278 break; 279 case IPPROTO_DIVERT: 280 varname = "net.inet.divert.pcblist"; 281 protoname = "div"; 282 break; 283 default: 284 errx(1, "protocol %d not supported", proto); 285 } 286 287 buf = NULL; 288 bufsize = 8192; 289 retry = 5; 290 do { 291 for (;;) { 292 if ((buf = realloc(buf, bufsize)) == NULL) 293 err(1, "realloc()"); 294 len = bufsize; 295 if (sysctlbyname(varname, buf, &len, NULL, 0) == 0) 296 break; 297 if (errno == ENOENT) 298 goto out; 299 if (errno != ENOMEM || len != bufsize) 300 err(1, "sysctlbyname()"); 301 bufsize *= 2; 302 } 303 xig = (struct xinpgen *)buf; 304 exig = (struct xinpgen *)(void *) 305 ((char *)buf + len - sizeof *exig); 306 if (xig->xig_len != sizeof *xig || 307 exig->xig_len != sizeof *exig) 308 errx(1, "struct xinpgen size mismatch"); 309 } while (xig->xig_gen != exig->xig_gen && retry--); 310 311 if (xig->xig_gen != exig->xig_gen && opt_v) 312 warnx("warning: data may be inconsistent"); 313 314 for (;;) { 315 xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len); 316 if (xig >= exig) 317 break; 318 switch (proto) { 319 case IPPROTO_TCP: 320 xtp = (struct xtcpcb *)xig; 321 if (xtp->xt_len != sizeof *xtp) { 322 warnx("struct xtcpcb size mismatch"); 323 goto out; 324 } 325 inp = &xtp->xt_inp; 326 so = &xtp->xt_socket; 327 break; 328 case IPPROTO_UDP: 329 case IPPROTO_DIVERT: 330 xip = (struct xinpcb *)xig; 331 if (xip->xi_len != sizeof *xip) { 332 warnx("struct xinpcb size mismatch"); 333 goto out; 334 } 335 inp = &xip->xi_inp; 336 so = &xip->xi_socket; 337 break; 338 default: 339 errx(1, "protocol %d not supported", proto); 340 } 341 if ((inp->inp_vflag & vflag) == 0) 342 continue; 343 if (inp->inp_vflag & INP_IPV4) { 344 if ((inp->inp_fport == 0 && !opt_l) || 345 (inp->inp_fport != 0 && !opt_c)) 346 continue; 347 #define __IN_IS_ADDR_LOOPBACK(pina) \ 348 ((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) 349 if (opt_L && 350 (__IN_IS_ADDR_LOOPBACK(&inp->inp_faddr) || 351 __IN_IS_ADDR_LOOPBACK(&inp->inp_laddr))) 352 continue; 353 #undef __IN_IS_ADDR_LOOPBACK 354 } else if (inp->inp_vflag & INP_IPV6) { 355 if ((inp->inp_fport == 0 && !opt_l) || 356 (inp->inp_fport != 0 && !opt_c)) 357 continue; 358 if (opt_L && 359 (IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr) || 360 IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr))) 361 continue; 362 } else { 363 if (opt_v) 364 warnx("invalid vflag 0x%x", inp->inp_vflag); 365 continue; 366 } 367 if ((sock = calloc(1, sizeof *sock)) == NULL) 368 err(1, "malloc()"); 369 sock->socket = so->xso_so; 370 sock->proto = proto; 371 if (inp->inp_vflag & INP_IPV4) { 372 sock->family = AF_INET; 373 sockaddr(&sock->laddr, sock->family, 374 &inp->inp_laddr, inp->inp_lport); 375 sockaddr(&sock->faddr, sock->family, 376 &inp->inp_faddr, inp->inp_fport); 377 } else if (inp->inp_vflag & INP_IPV6) { 378 sock->family = AF_INET6; 379 sockaddr(&sock->laddr, sock->family, 380 &inp->in6p_laddr, inp->inp_lport); 381 sockaddr(&sock->faddr, sock->family, 382 &inp->in6p_faddr, inp->inp_fport); 383 } 384 sock->vflag = inp->inp_vflag; 385 sock->protoname = protoname; 386 hash = (int)((uintptr_t)sock->socket % HASHSIZE); 387 sock->next = sockhash[hash]; 388 sockhash[hash] = sock; 389 } 390 out: 391 free(buf); 392 } 393 394 static void 395 gather_unix(int proto) 396 { 397 struct xunpgen *xug, *exug; 398 struct xunpcb *xup; 399 struct sock *sock; 400 const char *varname, *protoname; 401 size_t len, bufsize; 402 void *buf; 403 int hash, retry; 404 405 switch (proto) { 406 case SOCK_STREAM: 407 varname = "net.local.stream.pcblist"; 408 protoname = "stream"; 409 break; 410 case SOCK_DGRAM: 411 varname = "net.local.dgram.pcblist"; 412 protoname = "dgram"; 413 break; 414 default: 415 abort(); 416 } 417 buf = NULL; 418 bufsize = 8192; 419 retry = 5; 420 do { 421 for (;;) { 422 if ((buf = realloc(buf, bufsize)) == NULL) 423 err(1, "realloc()"); 424 len = bufsize; 425 if (sysctlbyname(varname, buf, &len, NULL, 0) == 0) 426 break; 427 if (errno != ENOMEM || len != bufsize) 428 err(1, "sysctlbyname()"); 429 bufsize *= 2; 430 } 431 xug = (struct xunpgen *)buf; 432 exug = (struct xunpgen *)(void *) 433 ((char *)buf + len - sizeof *exug); 434 if (xug->xug_len != sizeof *xug || 435 exug->xug_len != sizeof *exug) { 436 warnx("struct xinpgen size mismatch"); 437 goto out; 438 } 439 } while (xug->xug_gen != exug->xug_gen && retry--); 440 441 if (xug->xug_gen != exug->xug_gen && opt_v) 442 warnx("warning: data may be inconsistent"); 443 444 for (;;) { 445 xug = (struct xunpgen *)(void *)((char *)xug + xug->xug_len); 446 if (xug >= exug) 447 break; 448 xup = (struct xunpcb *)xug; 449 if (xup->xu_len != sizeof *xup) { 450 warnx("struct xunpcb size mismatch"); 451 goto out; 452 } 453 if ((xup->xu_unp.unp_conn == NULL && !opt_l) || 454 (xup->xu_unp.unp_conn != NULL && !opt_c)) 455 continue; 456 if ((sock = calloc(1, sizeof *sock)) == NULL) 457 err(1, "malloc()"); 458 sock->socket = xup->xu_socket.xso_so; 459 sock->pcb = xup->xu_unpp; 460 sock->proto = proto; 461 sock->family = AF_UNIX; 462 sock->protoname = protoname; 463 if (xup->xu_unp.unp_addr != NULL) 464 sock->laddr = 465 *(struct sockaddr_storage *)(void *)&xup->xu_addr; 466 else if (xup->xu_unp.unp_conn != NULL) 467 *(void **)&sock->faddr = xup->xu_unp.unp_conn; 468 hash = (int)((uintptr_t)sock->socket % HASHSIZE); 469 sock->next = sockhash[hash]; 470 sockhash[hash] = sock; 471 } 472 out: 473 free(buf); 474 } 475 476 static void 477 getfiles(void) 478 { 479 size_t len, olen; 480 481 olen = len = sizeof *xfiles; 482 if ((xfiles = malloc(len)) == NULL) 483 err(1, "malloc()"); 484 while (sysctlbyname("kern.file", xfiles, &len, 0, 0) == -1) { 485 if (errno != ENOMEM || len != olen) 486 err(1, "sysctlbyname()"); 487 olen = len *= 2; 488 if ((xfiles = realloc(xfiles, len)) == NULL) 489 err(1, "realloc()"); 490 } 491 if (len > 0 && xfiles->xf_size != sizeof *xfiles) 492 errx(1, "struct xfile size mismatch"); 493 nxfiles = len / sizeof *xfiles; 494 } 495 496 static int 497 printaddr(int af, struct sockaddr_storage *ss) 498 { 499 char addrstr[INET6_ADDRSTRLEN] = { '\0', '\0' }; 500 struct sockaddr_un *sun; 501 void *addr = NULL; /* Keep compiler happy. */ 502 int off, port = 0; 503 504 switch (af) { 505 case AF_INET: 506 addr = &((struct sockaddr_in *)ss)->sin_addr; 507 if (inet_lnaof(*(struct in_addr *)addr) == INADDR_ANY) 508 addrstr[0] = '*'; 509 port = ntohs(((struct sockaddr_in *)ss)->sin_port); 510 break; 511 case AF_INET6: 512 addr = &((struct sockaddr_in6 *)ss)->sin6_addr; 513 if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)addr)) 514 addrstr[0] = '*'; 515 port = ntohs(((struct sockaddr_in6 *)ss)->sin6_port); 516 break; 517 case AF_UNIX: 518 sun = (struct sockaddr_un *)ss; 519 off = (int)((char *)&sun->sun_path - (char *)sun); 520 return (xprintf("%.*s", sun->sun_len - off, sun->sun_path)); 521 } 522 if (addrstr[0] == '\0') 523 inet_ntop(af, addr, addrstr, sizeof addrstr); 524 if (port == 0) 525 return xprintf("%s:*", addrstr); 526 else 527 return xprintf("%s:%d", addrstr, port); 528 } 529 530 static const char * 531 getprocname(pid_t pid) 532 { 533 static struct kinfo_proc proc; 534 size_t len; 535 int mib[4]; 536 537 mib[0] = CTL_KERN; 538 mib[1] = KERN_PROC; 539 mib[2] = KERN_PROC_PID; 540 mib[3] = (int)pid; 541 len = sizeof proc; 542 if (sysctl(mib, 4, &proc, &len, NULL, 0) == -1) { 543 /* Do not warn if the process exits before we get its name. */ 544 if (errno != ESRCH) 545 warn("sysctl()"); 546 return ("??"); 547 } 548 return (proc.ki_comm); 549 } 550 551 static int 552 check_ports(struct sock *s) 553 { 554 int port; 555 556 if (ports == NULL) 557 return (1); 558 if ((s->family != AF_INET) && (s->family != AF_INET6)) 559 return (1); 560 if (s->family == AF_INET) 561 port = ntohs(((struct sockaddr_in *)(&s->laddr))->sin_port); 562 else 563 port = ntohs(((struct sockaddr_in6 *)(&s->laddr))->sin6_port); 564 if (CHK_PORT(port)) 565 return (1); 566 if (s->family == AF_INET) 567 port = ntohs(((struct sockaddr_in *)(&s->faddr))->sin_port); 568 else 569 port = ntohs(((struct sockaddr_in6 *)(&s->faddr))->sin6_port); 570 if (CHK_PORT(port)) 571 return (1); 572 return (0); 573 } 574 575 static void 576 displaysock(struct sock *s, int pos) 577 { 578 void *p; 579 int hash; 580 581 while (pos < 29) 582 pos += xprintf(" "); 583 pos += xprintf("%s", s->protoname); 584 if (s->vflag & INP_IPV4) 585 pos += xprintf("4 "); 586 if (s->vflag & INP_IPV6) 587 pos += xprintf("6 "); 588 while (pos < 36) 589 pos += xprintf(" "); 590 switch (s->family) { 591 case AF_INET: 592 case AF_INET6: 593 pos += printaddr(s->family, &s->laddr); 594 if (s->family == AF_INET6 && pos >= 58) 595 pos += xprintf(" "); 596 while (pos < 58) 597 pos += xprintf(" "); 598 pos += printaddr(s->family, &s->faddr); 599 break; 600 case AF_UNIX: 601 /* server */ 602 if (s->laddr.ss_len > 0) { 603 pos += printaddr(s->family, &s->laddr); 604 break; 605 } 606 /* client */ 607 p = *(void **)&s->faddr; 608 if (p == NULL) { 609 pos += xprintf("(not connected)"); 610 break; 611 } 612 pos += xprintf("-> "); 613 for (hash = 0; hash < HASHSIZE; ++hash) { 614 for (s = sockhash[hash]; s != NULL; s = s->next) 615 if (s->pcb == p) 616 break; 617 if (s != NULL) 618 break; 619 } 620 if (s == NULL || s->laddr.ss_len == 0) 621 pos += xprintf("??"); 622 else 623 pos += printaddr(s->family, &s->laddr); 624 break; 625 default: 626 abort(); 627 } 628 xprintf("\n"); 629 } 630 631 static void 632 display(void) 633 { 634 struct passwd *pwd; 635 struct xfile *xf; 636 struct sock *s; 637 int hash, n, pos; 638 639 printf("%-8s %-10s %-5s %-2s %-6s %-21s %-21s\n", 640 "USER", "COMMAND", "PID", "FD", "PROTO", 641 "LOCAL ADDRESS", "FOREIGN ADDRESS"); 642 setpassent(1); 643 for (xf = xfiles, n = 0; n < nxfiles; ++n, ++xf) { 644 if (xf->xf_data == NULL) 645 continue; 646 hash = (int)((uintptr_t)xf->xf_data % HASHSIZE); 647 for (s = sockhash[hash]; s != NULL; s = s->next) 648 if ((void *)s->socket == xf->xf_data) 649 break; 650 if (s == NULL) 651 continue; 652 if (!check_ports(s)) 653 continue; 654 s->shown = 1; 655 pos = 0; 656 if ((pwd = getpwuid(xf->xf_uid)) == NULL) 657 pos += xprintf("%lu ", (u_long)xf->xf_uid); 658 else 659 pos += xprintf("%s ", pwd->pw_name); 660 while (pos < 9) 661 pos += xprintf(" "); 662 pos += xprintf("%.10s", getprocname(xf->xf_pid)); 663 while (pos < 20) 664 pos += xprintf(" "); 665 pos += xprintf("%lu ", (u_long)xf->xf_pid); 666 while (pos < 26) 667 pos += xprintf(" "); 668 pos += xprintf("%d ", xf->xf_fd); 669 displaysock(s, pos); 670 } 671 for (hash = 0; hash < HASHSIZE; hash++) { 672 for (s = sockhash[hash]; s != NULL; s = s->next) { 673 if (s->shown) 674 continue; 675 if (!check_ports(s)) 676 continue; 677 pos = 0; 678 pos += xprintf("%-8s %-10s %-5s %-2s ", 679 "?", "?", "?", "?"); 680 displaysock(s, pos); 681 } 682 } 683 } 684 685 static int set_default_protos(void) 686 { 687 struct protoent *prot; 688 const char *pname; 689 size_t pindex; 690 691 init_protos(default_numprotos); 692 693 for (pindex = 0; pindex < default_numprotos; pindex++) { 694 pname = default_protos[pindex]; 695 prot = getprotobyname(pname); 696 if (prot == NULL) 697 err(1, "getprotobyname: %s", pname); 698 protos[pindex] = prot->p_proto; 699 } 700 numprotos = pindex; 701 return (pindex); 702 } 703 704 705 static void 706 usage(void) 707 { 708 fprintf(stderr, 709 "Usage: sockstat [-46cLlu] [-p ports] [-P protocols]\n"); 710 exit(1); 711 } 712 713 int 714 main(int argc, char *argv[]) 715 { 716 int protos_defined = -1; 717 int o, i; 718 719 while ((o = getopt(argc, argv, "46cLlp:P:uv")) != -1) 720 switch (o) { 721 case '4': 722 opt_4 = 1; 723 break; 724 case '6': 725 opt_6 = 1; 726 break; 727 case 'c': 728 opt_c = 1; 729 break; 730 case 'L': 731 opt_L = 1; 732 break; 733 case 'l': 734 opt_l = 1; 735 break; 736 case 'p': 737 parse_ports(optarg); 738 break; 739 case 'P': 740 protos_defined = parse_protos(optarg); 741 break; 742 case 'u': 743 opt_u = 1; 744 break; 745 case 'v': 746 ++opt_v; 747 break; 748 default: 749 usage(); 750 } 751 752 argc -= optind; 753 argv += optind; 754 755 if (argc > 0) 756 usage(); 757 758 if ((!opt_4 && !opt_6) && protos_defined != -1) 759 opt_4 = opt_6 = 1; 760 if (!opt_4 && !opt_6 && !opt_u) 761 opt_4 = opt_6 = opt_u = 1; 762 if ((opt_4 || opt_6) && protos_defined == -1) 763 protos_defined = set_default_protos(); 764 if (!opt_c && !opt_l) 765 opt_c = opt_l = 1; 766 767 if (opt_4 || opt_6) { 768 for (i = 0; i < protos_defined; i++) 769 gather_inet(protos[i]); 770 } 771 772 if (opt_u || (protos_defined == -1 && !opt_4 && !opt_6)) { 773 gather_unix(SOCK_STREAM); 774 gather_unix(SOCK_DGRAM); 775 } 776 getfiles(); 777 display(); 778 exit(0); 779 } 780