1 /* $NetBSD: main.c,v 1.101 2021/03/10 00:32:15 simonb Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1988, 1993 5 * Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993\ 35 Regents of the University of California. All rights reserved."); 36 #endif /* not lint */ 37 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "from: @(#)main.c 8.4 (Berkeley) 3/1/94"; 41 #else 42 __RCSID("$NetBSD: main.c,v 1.101 2021/03/10 00:32:15 simonb Exp $"); 43 #endif 44 #endif /* not lint */ 45 46 #include <sys/param.h> 47 #include <sys/file.h> 48 #include <sys/protosw.h> 49 #include <sys/socket.h> 50 51 #include <net/if.h> 52 #include <netinet/in.h> 53 54 #include <ctype.h> 55 #include <err.h> 56 #include <errno.h> 57 #include <kvm.h> 58 #include <limits.h> 59 #include <netdb.h> 60 #include <nlist.h> 61 #include <paths.h> 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <string.h> 65 #include <unistd.h> 66 #include "netstat.h" 67 #include "rtutil.h" 68 #include "prog_ops.h" 69 70 int Aflag; 71 int aflag; 72 int Bflag; 73 int bflag; 74 int dflag; 75 #ifndef SMALL 76 int gflag; 77 #endif 78 int hflag; 79 int iflag; 80 int Lflag; 81 int lflag; 82 int mflag; 83 int numeric_addr; 84 int numeric_port; 85 int nflag; 86 int Pflag; 87 int pflag; 88 int qflag; 89 int rflag; 90 int sflag; 91 int tagflag; 92 int tflag; 93 int Vflag; 94 int vflag; 95 96 char *interface; 97 98 int af; 99 int use_sysctl; 100 int force_sysctl; 101 102 struct nlist nl[] = { 103 #define N_MBSTAT 0 104 { "_mbstat", 0, 0, 0, 0 }, 105 #define N_IPSTAT 1 106 { "_ipstat", 0, 0, 0, 0 }, /* not available via kvm */ 107 #define N_TCBTABLE 2 108 { "_tcbtable", 0, 0, 0, 0 }, 109 #define N_TCPSTAT 3 110 { "_tcpstat", 0, 0, 0, 0 }, /* not available via kvm */ 111 #define N_UDBTABLE 4 112 { "_udbtable", 0, 0, 0, 0 }, 113 #define N_UDPSTAT 5 114 { "_udpstat", 0, 0, 0, 0 }, /* not available via kvm */ 115 #define N_IFNET_LIST 6 116 { "_ifnet_list", 0, 0, 0, 0 }, 117 #define N_ICMPSTAT 7 118 { "_icmpstat", 0, 0, 0, 0 }, /* not available via kvm */ 119 #define N_RTSTAT 8 120 { "_rtstat", 0, 0, 0, 0 }, 121 #define N_UNIXSW 9 122 { "_unixsw", 0, 0, 0, 0 }, 123 #define N_RTREE 10 124 { "_rt_tables", 0, 0, 0, 0 }, 125 #define N_NFILE 11 126 { "_nfile", 0, 0, 0, 0 }, 127 #define N_IGMPSTAT 12 128 { "_igmpstat", 0, 0, 0, 0 }, /* not available via kvm */ 129 #define N_MRTPROTO 13 130 { "_ip_mrtproto", 0, 0, 0, 0 }, 131 #define N_MRTSTAT 14 132 { "_mrtstat", 0, 0, 0, 0 }, 133 #define N_MFCHASHTBL 15 134 { "_mfchashtbl", 0, 0, 0, 0 }, 135 #define N_MFCHASH 16 136 { "_mfchash", 0, 0, 0, 0 }, 137 #define N_VIFTABLE 17 138 { "_viftable", 0, 0, 0, 0 }, 139 #define N_MSIZE 18 140 { "_msize", 0, 0, 0, 0 }, 141 #define N_MCLBYTES 19 142 { "_mclbytes", 0, 0, 0, 0 }, 143 #define N_DDPSTAT 20 144 { "_ddpstat", 0, 0, 0, 0 }, /* not available via kvm */ 145 #define N_DDPCB 21 146 { "_ddpcb", 0, 0, 0, 0 }, 147 #define N_MBPOOL 22 148 { "_mbpool", 0, 0, 0, 0 }, 149 #define N_MCLPOOL 23 150 { "_mclpool", 0, 0, 0, 0 }, 151 #define N_IP6STAT 24 152 { "_ip6stat", 0, 0, 0, 0 }, /* not available via kvm */ 153 #define N_TCP6STAT 25 154 { "_tcp6stat", 0, 0, 0, 0 }, /* not available via kvm */ 155 #define N_UDP6STAT 26 156 { "_udp6stat", 0, 0, 0, 0 }, /* not available via kvm */ 157 #define N_ICMP6STAT 27 158 { "_icmp6stat", 0, 0, 0, 0 }, /* not available via kvm */ 159 #define N_IPSECSTAT 28 160 { "_ipsecstat", 0, 0, 0, 0 }, /* not available via kvm */ 161 #define N_IPSEC6STAT 29 162 { "_ipsec6stat", 0, 0, 0, 0 }, /* not available via kvm */ 163 #define N_PIM6STAT 30 164 { "_pim6stat", 0, 0, 0, 0 }, /* not available via kvm */ 165 #define N_MRT6PROTO 31 166 { "_ip6_mrtproto", 0, 0, 0, 0 }, 167 #define N_MRT6STAT 32 168 { "_mrt6stat", 0, 0, 0, 0 }, 169 #define N_MF6CTABLE 33 170 { "_mf6ctable", 0, 0, 0, 0 }, 171 #define N_MIF6TABLE 34 172 { "_mif6table", 0, 0, 0, 0 }, 173 #define N_PFKEYSTAT 35 174 { "_pfkeystat", 0, 0, 0, 0 }, /* not available via kvm */ 175 #define N_ARPSTAT 36 176 { "_arpstat", 0, 0, 0, 0 }, /* not available via kvm */ 177 #define N_RIP6STAT 37 178 { "_rip6stat", 0, 0, 0, 0 }, /* not available via kvm */ 179 #define N_ARPINTRQ 38 180 { "_arpintrq", 0, 0, 0, 0 }, 181 #define N_ATINTRQ1 39 182 { "_atintrq1", 0, 0, 0, 0 }, 183 #define N_ATINTRQ2 40 184 { "_atintrq2", 0, 0, 0, 0 }, 185 #define N_PPPOEDISCINQ 41 186 { "_ppoediscinq", 0, 0, 0, 0 }, 187 #define N_PPPOEINQ 42 188 { "_ppoeinq", 0, 0, 0, 0 }, 189 #define N_HARDCLOCK_TICKS 43 190 { "_hardclock_ticks", 0, 0, 0, 0 }, 191 #define N_PIMSTAT 44 192 { "_pimstat", 0, 0, 0, 0 }, 193 #define N_CARPSTAT 45 194 { "_carpstats", 0, 0, 0, 0 }, /* not available via kvm */ 195 #define N_PFSYNCSTAT 46 196 { "_pfsyncstats", 0, 0, 0, 0}, /* not available via kvm */ 197 { "", 0, 0, 0, 0 }, 198 }; 199 200 struct protox { 201 u_char pr_index; /* index into nlist of cb head */ 202 u_char pr_sindex; /* index into nlist of stat block */ 203 u_char pr_wanted; /* 1 if wanted, 0 otherwise */ 204 void (*pr_cblocks) /* control blocks printing routine */ 205 (u_long, const char *); 206 void (*pr_stats) /* statistics printing routine */ 207 (u_long, const char *); 208 void (*pr_istats) 209 (const char *); /* per/if statistics printing routine */ 210 void (*pr_dump) /* PCB state dump routine */ 211 (u_long, const char *, u_long); 212 const char *pr_name; /* well-known name */ 213 } protox[] = { 214 { N_TCBTABLE, N_TCPSTAT, 1, protopr, 215 tcp_stats, NULL, tcp_dump, "tcp" }, 216 { N_UDBTABLE, N_UDPSTAT, 1, protopr, 217 udp_stats, NULL, 0, "udp" }, 218 { -1, N_IPSTAT, 1, 0, 219 ip_stats, NULL, 0, "ip" }, 220 { -1, N_ICMPSTAT, 1, 0, 221 icmp_stats, NULL, 0, "icmp" }, 222 { -1, N_IGMPSTAT, 1, 0, 223 igmp_stats, NULL, 0, "igmp" }, 224 { -1, N_CARPSTAT, 1, 0, 225 carp_stats, NULL, 0, "carp" }, 226 #ifdef IPSEC 227 { -1, N_IPSECSTAT, 1, 0, 228 fast_ipsec_stats, NULL, 0, "ipsec" }, 229 #endif 230 { -1, N_PIMSTAT, 1, 0, 231 pim_stats, NULL, 0, "pim" }, 232 { -1, N_PFSYNCSTAT, 1, 0, 233 pfsync_stats, NULL, 0, "pfsync" }, 234 { -1, -1, 0, 0, 235 0, NULL, 0, 0 } 236 }; 237 238 #ifdef INET6 239 struct protox ip6protox[] = { 240 { -1, N_IP6STAT, 1, 0, 241 ip6_stats, ip6_ifstats, 0, "ip6" }, 242 { -1, N_ICMP6STAT, 1, 0, 243 icmp6_stats, icmp6_ifstats, 0, "icmp6" }, 244 #ifdef TCP6 245 { N_TCBTABLE, N_TCP6STAT, 1, ip6protopr, 246 tcp6_stats, NULL, tcp6_dump, "tcp6" }, 247 #else 248 { N_TCBTABLE, N_TCP6STAT, 1, ip6protopr, 249 tcp_stats, NULL, tcp6_dump, "tcp6" }, 250 #endif 251 { N_UDBTABLE, N_UDP6STAT, 1, ip6protopr, 252 udp6_stats, NULL, 0, "udp6" }, 253 #ifdef IPSEC 254 { -1, N_IPSEC6STAT, 1, 0, 255 fast_ipsec_stats, NULL, 0, "ipsec6" }, 256 #endif 257 { -1, N_PIM6STAT, 1, 0, 258 pim6_stats, NULL, 0, "pim6" }, 259 { -1, N_RIP6STAT, 1, 0, 260 rip6_stats, NULL, 0, "rip6" }, 261 { -1, -1, 0, 0, 262 0, NULL, 0, 0 } 263 }; 264 #endif 265 266 struct protox arpprotox[] = { 267 { -1, N_ARPSTAT, 1, 0, 268 arp_stats, NULL, 0, "arp" }, 269 { -1, -1, 0, 0, 270 0, NULL, 0, 0 } 271 }; 272 273 #ifdef IPSEC 274 struct protox pfkeyprotox[] = { 275 { -1, N_PFKEYSTAT, 1, 0, 276 pfkey_stats, NULL, 0, "pfkey" }, 277 { -1, -1, 0, 0, 278 0, NULL, 0, 0 } 279 }; 280 #endif 281 282 #ifndef SMALL 283 struct protox atalkprotox[] = { 284 { N_DDPCB, N_DDPSTAT, 1, atalkprotopr, 285 ddp_stats, NULL, 0, "ddp" }, 286 { -1, -1, 0, 0, 287 0, NULL, 0, NULL } 288 }; 289 #endif 290 291 struct protox *protoprotox[] = { protox, 292 #ifdef INET6 293 ip6protox, 294 #endif 295 arpprotox, 296 #ifdef IPSEC 297 pfkeyprotox, 298 #endif 299 #ifndef SMALL 300 atalkprotox, 301 #endif 302 NULL }; 303 304 const struct softintrq { 305 const char *siq_name; 306 int siq_index; 307 } softintrq[] = { 308 { "arpintrq", N_ARPINTRQ }, 309 { "atintrq1", N_ATINTRQ1 }, 310 { "atintrq2", N_ATINTRQ2 }, 311 { "ppoediscinq", N_PPPOEDISCINQ }, 312 { "ppoeinq", N_PPPOEINQ }, 313 { NULL, -1 }, 314 }; 315 316 static void printproto(struct protox *, const char *); 317 static void print_softintrq(void); 318 __dead static void usage(void); 319 static struct protox *name2protox(const char *); 320 static struct protox *knownname(const char *); 321 static void prepare(const char *, const char *, struct protox *tp); 322 static kvm_t *prepare_kvmd(const char *, const char *, char *); 323 324 static kvm_t *kvmd = NULL; 325 gid_t egid; 326 int interval; /* repeat interval for i/f stats */ 327 static const char *nlistf = NULL, *memf = NULL; 328 329 kvm_t * 330 get_kvmd(void) 331 { 332 char buf[_POSIX2_LINE_MAX]; 333 334 if (kvmd != NULL) 335 return kvmd; 336 if ((kvmd = prepare_kvmd(nlistf, memf, buf)) == NULL) 337 errx(1, "kvm error: %s", buf); 338 return kvmd; 339 } 340 341 static kvm_t * 342 prepare_kvmd(const char *nf, const char *mf, char *errbuf) 343 { 344 kvm_t *k; 345 346 (void)setegid(egid); 347 k = kvm_openfiles(nf, mf, NULL, O_RDONLY, errbuf); 348 (void)setgid(getgid()); 349 return k; 350 } 351 352 void 353 prepare(const char *nf, const char *mf, struct protox *tp) 354 { 355 char buf[_POSIX2_LINE_MAX]; 356 /* 357 * Try to figure out if we can use sysctl or not. 358 */ 359 if (nf != NULL || mf != NULL) { 360 /* Of course, we can't use sysctl with dumps. */ 361 if (force_sysctl) 362 errx(EXIT_FAILURE, "can't use sysctl with dumps"); 363 364 /* 365 * If we have -M or -N, we're not dealing with live memory 366 * or want to use kvm interface explicitly. It is sometimes 367 * useful to dig inside of kernel without extending 368 * sysctl interface (i.e., without rebuilding kernel). 369 */ 370 use_sysctl = 0; 371 } else if (qflag || 372 #ifndef SMALL 373 gflag || 374 #endif 375 (pflag && tp->pr_sindex == N_PIMSTAT) || 376 Pflag) { 377 /* These flags are not yet supported via sysctl(3). */ 378 use_sysctl = 0; 379 } else { 380 /* We can use sysctl(3). */ 381 use_sysctl = 1; 382 } 383 384 if (force_sysctl && !use_sysctl) { 385 /* Let the user know what's about to happen. */ 386 warnx("forcing sysctl usage even though it might not be "\ 387 "supported"); 388 use_sysctl = 1; 389 } 390 391 kvmd = prepare_kvmd(nf, mf, buf); 392 393 if (!use_sysctl) { 394 395 if (kvmd == NULL) 396 errx(1, "kvm error: %s", buf); 397 if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) { 398 if (nf) 399 errx(1, "%s: no namelist", nf); 400 else 401 errx(1, "no namelist"); 402 } 403 } else 404 (void)setgid(getgid()); 405 } 406 407 int 408 main(int argc, char *argv[]) 409 { 410 struct protoent *p; 411 struct protox *tp; /* for printing cblocks & stats */ 412 int ch; 413 char *cp; 414 char *afname, *afnames; 415 u_long pcbaddr; 416 417 if (prog_init) { 418 if (prog_init() == -1) 419 err(1, "init failed"); 420 force_sysctl = 1; /* cheap trick */ 421 } 422 423 egid = getegid(); 424 (void)setegid(getgid()); 425 tp = NULL; 426 af = AF_UNSPEC; 427 afnames = NULL; 428 pcbaddr = 0; 429 430 while ((ch = getopt(argc, argv, 431 "AabBdf:ghI:LliM:mN:nP:p:qrsStTuVvw:X")) != -1) 432 switch (ch) { 433 case 'A': 434 Aflag = RT_AFLAG; 435 break; 436 case 'a': 437 aflag = 1; 438 break; 439 case 'b': 440 bflag = 1; 441 break; 442 case 'B': 443 Bflag = 1; 444 break; 445 case 'd': 446 dflag = 1; 447 break; 448 case 'f': 449 afnames = optarg; 450 break; 451 #ifndef SMALL 452 case 'g': 453 gflag = 1; 454 break; 455 #endif 456 case 'h': 457 hflag = 1; 458 break; 459 case 'I': 460 iflag = 1; 461 interface = optarg; 462 break; 463 case 'i': 464 iflag = 1; 465 break; 466 case 'L': 467 Lflag = RT_LFLAG; 468 break; 469 case 'l': 470 lflag = 1; 471 break; 472 case 'M': 473 memf = optarg; 474 break; 475 case 'm': 476 mflag = 1; 477 break; 478 case 'N': 479 nlistf = optarg; 480 break; 481 case 'n': 482 numeric_addr = numeric_port = nflag = RT_NFLAG; 483 break; 484 case 'P': 485 errno = 0; 486 pcbaddr = strtoul(optarg, &cp, 16); 487 if (*cp != '\0' || errno == ERANGE) 488 errx(1, "invalid PCB address %s", 489 optarg); 490 Pflag = 1; 491 break; 492 case 'p': 493 if ((tp = name2protox(optarg)) == NULL) 494 errx(1, "%s: unknown or uninstrumented protocol", 495 optarg); 496 pflag = 1; 497 break; 498 case 'q': 499 qflag = 1; 500 break; 501 case 'r': 502 rflag = 1; 503 break; 504 case 's': 505 ++sflag; 506 break; 507 case 'S': 508 numeric_addr = 1; 509 break; 510 case 't': 511 tflag = 1; 512 break; 513 case 'T': 514 tagflag = RT_TFLAG; 515 break; 516 case 'u': 517 af = AF_LOCAL; 518 break; 519 case 'V': 520 Vflag++; 521 break; 522 case 'v': 523 vflag = RT_VFLAG; 524 break; 525 case 'w': 526 interval = atoi(optarg); 527 iflag = 1; 528 break; 529 case 'X': 530 force_sysctl = 1; 531 break; 532 case '?': 533 default: 534 usage(); 535 } 536 argv += optind; 537 argc -= optind; 538 539 #define BACKWARD_COMPATIBILITY 540 #ifdef BACKWARD_COMPATIBILITY 541 if (*argv) { 542 if (isdigit((unsigned char)**argv)) { 543 interval = atoi(*argv); 544 if (interval <= 0) 545 usage(); 546 ++argv; 547 iflag = 1; 548 } 549 if (*argv) { 550 nlistf = *argv; 551 if (*++argv) 552 memf = *argv; 553 } 554 } 555 #endif 556 557 prepare(nlistf, memf, tp); 558 559 #ifndef SMALL 560 if (Bflag) { 561 if (sflag) 562 bpf_stats(); 563 else 564 bpf_dump(interface); 565 exit(0); 566 } 567 #endif 568 569 if (mflag) { 570 mbpr(nl[N_MBSTAT].n_value, nl[N_MSIZE].n_value, 571 nl[N_MCLBYTES].n_value, nl[N_MBPOOL].n_value, 572 nl[N_MCLPOOL].n_value); 573 exit(0); 574 } 575 if (Pflag) { 576 if (tp == NULL) { 577 /* Default to TCP. */ 578 tp = name2protox("tcp"); 579 } 580 if (tp->pr_dump) 581 (*tp->pr_dump)(nl[tp->pr_index].n_value, tp->pr_name, 582 pcbaddr); 583 else 584 printf("%s: no PCB dump routine\n", tp->pr_name); 585 exit(0); 586 } 587 if (pflag) { 588 if (iflag && tp->pr_istats) 589 intpr(interval, nl[N_IFNET_LIST].n_value, tp->pr_istats); 590 else if (tp->pr_stats) 591 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 592 tp->pr_name); 593 else 594 printf("%s: no stats routine\n", tp->pr_name); 595 exit(0); 596 } 597 if (qflag) { 598 print_softintrq(); 599 exit(0); 600 } 601 /* 602 * Keep file descriptors open to avoid overhead 603 * of open/close on each call to get* routines. 604 */ 605 sethostent(1); 606 setnetent(1); 607 /* 608 * If -f was used afnames != NULL, loop over the address families. 609 * Otherwise do this at least once (with af == AF_UNSPEC). 610 */ 611 afname = NULL; 612 do { 613 if (afnames != NULL) { 614 afname = strsep(&afnames, ","); 615 if (afname == NULL) 616 break; /* Exit early */ 617 if (strcmp(afname, "inet") == 0) 618 af = AF_INET; 619 else if (strcmp(afname, "inet6") == 0) 620 af = AF_INET6; 621 else if (strcmp(afname, "arp") == 0) 622 af = AF_ARP; 623 else if (strcmp(afname, "pfkey") == 0) 624 af = PF_KEY; 625 else if (strcmp(afname, "unix") == 0 626 || strcmp(afname, "local") == 0) 627 af = AF_LOCAL; 628 else if (strcmp(afname, "atalk") == 0) 629 af = AF_APPLETALK; 630 else if (strcmp(afname, "mpls") == 0) 631 af = AF_MPLS; 632 else { 633 warnx("%s: unknown address family", 634 afname); 635 continue; 636 } 637 } 638 639 if (iflag) { 640 if (af != AF_UNSPEC) 641 goto protostat; 642 643 intpr(interval, nl[N_IFNET_LIST].n_value, NULL); 644 break; 645 } 646 if (rflag) { 647 if (sflag) 648 rt_stats(use_sysctl ? 0 : nl[N_RTSTAT].n_value); 649 else { 650 if (use_sysctl) 651 p_rttables(af, 652 nflag|tagflag|vflag|Lflag, 0, ~0); 653 else 654 routepr(nl[N_RTREE].n_value); 655 } 656 break; 657 } 658 #ifndef SMALL 659 if (gflag) { 660 if (sflag) { 661 if (af == AF_INET || af == AF_UNSPEC) 662 mrt_stats(nl[N_MRTPROTO].n_value, 663 nl[N_MRTSTAT].n_value); 664 #ifdef INET6 665 if (af == AF_INET6 || af == AF_UNSPEC) 666 mrt6_stats(nl[N_MRT6PROTO].n_value, 667 nl[N_MRT6STAT].n_value); 668 #endif 669 } 670 else { 671 if (af == AF_INET || af == AF_UNSPEC) 672 mroutepr(nl[N_MRTPROTO].n_value, 673 nl[N_MFCHASHTBL].n_value, 674 nl[N_MFCHASH].n_value, 675 nl[N_VIFTABLE].n_value); 676 #ifdef INET6 677 if (af == AF_INET6 || af == AF_UNSPEC) 678 mroute6pr(nl[N_MRT6PROTO].n_value, 679 nl[N_MF6CTABLE].n_value, 680 nl[N_MIF6TABLE].n_value); 681 #endif 682 } 683 break; 684 } 685 #endif 686 protostat: 687 if (af == AF_INET || af == AF_UNSPEC) { 688 setprotoent(1); 689 setservent(1); 690 /* ugh, this is O(MN) ... why do we do this? */ 691 while ((p = getprotoent()) != NULL) { 692 for (tp = protox; tp->pr_name; tp++) 693 if (strcmp(tp->pr_name, p->p_name) == 0) 694 break; 695 if (tp->pr_name == 0 || tp->pr_wanted == 0) 696 continue; 697 printproto(tp, p->p_name); 698 tp->pr_wanted = 0; 699 } 700 endprotoent(); 701 for (tp = protox; tp->pr_name; tp++) 702 if (tp->pr_wanted) 703 printproto(tp, tp->pr_name); 704 } 705 #ifdef INET6 706 if (af == AF_INET6 || af == AF_UNSPEC) 707 for (tp = ip6protox; tp->pr_name; tp++) 708 printproto(tp, tp->pr_name); 709 #endif 710 if (af == AF_ARP || af == AF_UNSPEC) 711 for (tp = arpprotox; tp->pr_name; tp++) 712 printproto(tp, tp->pr_name); 713 #ifdef IPSEC 714 if (af == PF_KEY || af == AF_UNSPEC) 715 for (tp = pfkeyprotox; tp->pr_name; tp++) 716 printproto(tp, tp->pr_name); 717 #endif 718 #ifndef SMALL 719 if (af == AF_APPLETALK || af == AF_UNSPEC) 720 for (tp = atalkprotox; tp->pr_name; tp++) 721 printproto(tp, tp->pr_name); 722 if ((af == AF_LOCAL || af == AF_UNSPEC) && !sflag) 723 unixpr(nl[N_UNIXSW].n_value); 724 #endif 725 } while (afnames != NULL && afname != NULL); 726 exit(0); 727 } 728 729 /* 730 * Print out protocol statistics or control blocks (per sflag). 731 * If the interface was not specifically requested, and the symbol 732 * is not in the namelist, ignore this one. 733 */ 734 static void 735 printproto(struct protox *tp, const char *name) 736 { 737 void (*pr)(u_long, const char *); 738 u_long off; 739 740 if (sflag) { 741 if (iflag) { 742 if (tp->pr_istats) 743 intpr(interval, nl[N_IFNET_LIST].n_value, 744 tp->pr_istats); 745 return; 746 } 747 else { 748 pr = tp->pr_stats; 749 off = nl[tp->pr_sindex].n_value; 750 } 751 } else { 752 pr = tp->pr_cblocks; 753 off = nl[tp->pr_index].n_value; 754 } 755 if (pr != NULL && ((off || af != AF_UNSPEC) || use_sysctl)) { 756 (*pr)(off, name); 757 } 758 } 759 760 /* 761 * Print softintrq status. 762 */ 763 void 764 print_softintrq(void) 765 { 766 struct ifqueue intrq, *ifq = &intrq; 767 const struct softintrq *siq; 768 u_long off; 769 770 for (siq = softintrq; siq->siq_name != NULL; siq++) { 771 off = nl[siq->siq_index].n_value; 772 if (off == 0) 773 continue; 774 775 kread(off, (char *)ifq, sizeof(*ifq)); 776 printf("%s:\n", siq->siq_name); 777 printf("\tqueue length: %d\n", ifq->ifq_len); 778 printf("\tmaximum queue length: %d\n", ifq->ifq_maxlen); 779 printf("\tpackets dropped: %d\n", ifq->ifq_drops); 780 } 781 } 782 783 /* 784 * Read kernel memory, return 0 on success. 785 */ 786 int 787 kread(u_long addr, char *buf, int size) 788 { 789 790 if (kvm_read(kvmd, addr, buf, size) != size) { 791 warnx("%s", kvm_geterr(kvmd)); 792 return (-1); 793 } 794 return (0); 795 } 796 797 const char * 798 plural(int n) 799 { 800 801 return (n != 1 ? "s" : ""); 802 } 803 804 const char * 805 plurales(int n) 806 { 807 808 return (n != 1 ? "es" : ""); 809 } 810 811 int 812 get_hardticks(void) 813 { 814 int hardticks; 815 816 kread(nl[N_HARDCLOCK_TICKS].n_value, (char *)&hardticks, 817 sizeof(hardticks)); 818 return (hardticks); 819 } 820 821 /* 822 * Find the protox for the given "well-known" name. 823 */ 824 static struct protox * 825 knownname(const char *name) 826 { 827 struct protox **tpp, *tp; 828 829 for (tpp = protoprotox; *tpp; tpp++) 830 for (tp = *tpp; tp->pr_name; tp++) 831 if (strcmp(tp->pr_name, name) == 0) 832 return (tp); 833 return (NULL); 834 } 835 836 /* 837 * Find the protox corresponding to name. 838 */ 839 static struct protox * 840 name2protox(const char *name) 841 { 842 struct protox *tp; 843 char **alias; /* alias from p->aliases */ 844 struct protoent *p; 845 846 /* 847 * Try to find the name in the list of "well-known" names. If that 848 * fails, check if name is an alias for an Internet protocol. 849 */ 850 if ((tp = knownname(name)) != NULL) 851 return (tp); 852 853 setprotoent(1); /* make protocol lookup cheaper */ 854 while ((p = getprotoent()) != NULL) { 855 /* assert: name not same as p->name */ 856 for (alias = p->p_aliases; *alias; alias++) 857 if (strcmp(name, *alias) == 0) { 858 endprotoent(); 859 return (knownname(p->p_name)); 860 } 861 } 862 endprotoent(); 863 return (NULL); 864 } 865 866 static void 867 usage(void) 868 { 869 const char *progname = getprogname(); 870 871 (void)fprintf(stderr, 872 "usage: %s [-Aan] [-f address_family[,family ...]] [-M core] [-N system]\n", progname); 873 (void)fprintf(stderr, 874 " %s [-bdgiLmnqrsSv] [-f address_family[,family ...]] [-M core] [-N system]\n", 875 progname); 876 (void)fprintf(stderr, 877 " %s [-dn] [-I interface] [-M core] [-N system] [-w wait]\n", progname); 878 (void)fprintf(stderr, 879 " %s [-p protocol] [-M core] [-N system]\n", progname); 880 (void)fprintf(stderr, 881 " %s [-p protocol] [-M core] [-N system] -P pcbaddr\n", progname); 882 (void)fprintf(stderr, 883 " %s [-p protocol] [-i] [-I Interface] \n", progname); 884 (void)fprintf(stderr, 885 " %s [-s] [-f address_family[,family ...]] [-i] [-I Interface]\n", progname); 886 (void)fprintf(stderr, 887 " %s [-s] [-B] [-I interface]\n", progname); 888 exit(1); 889 } 890