1/* $NetBSD: main.c,v 1.105 2023/08/18 13:18:17 martin 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 40static char sccsid[] = "from: @(#)main.c 8.4 (Berkeley) 3/1/94"; 41#else 42__RCSID("$NetBSD: main.c,v 1.105 2023/08/18 13:18:17 martin 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 70int Aflag; 71int aflag; 72int Bflag; 73int bflag; 74int dflag; 75#ifndef SMALL 76int gflag; 77#endif 78int hflag; 79int iflag; 80int Lflag; 81int lflag; 82int mflag; 83int numeric_addr; 84int numeric_port; 85int nflag; 86int Pflag; 87int pflag; 88int qflag; 89int rflag; 90int sflag; 91int tagflag; 92int tflag; 93int Vflag; 94int vflag; 95 96char *interface; 97 98int af; 99int use_sysctl; 100int force_sysctl; 101 102struct 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 200struct 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) /* per/if statistics printing routine */ 209 (const char *); 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 239struct 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 266struct 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 274struct 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 283struct 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 291struct 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 304const 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 316static void printproto(struct protox *, const char *); 317static void print_softintrq(void); 318__dead static void usage(void); 319static struct protox *name2protox(const char *); 320static struct protox *knownname(const char *); 321static void prepare(const char *, const char *, struct protox *tp); 322static kvm_t *prepare_kvmd(const char *, const char *, char *); 323 324static kvm_t *kvmd = NULL; 325gid_t egid; 326int interval; /* repeat interval for i/f stats */ 327static const char *nlistf = NULL, *memf = NULL; 328 329kvm_t * 330get_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 341static kvm_t * 342prepare_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 352void 353prepare(const char *nf, const char *mf, struct protox *tp) 354{ 355 char buf[_POSIX2_LINE_MAX]; 356 357 /* 358 * Try to figure out if we can use sysctl or not. 359 */ 360 if (nf != NULL || mf != NULL) { 361 /* Of course, we can't use sysctl with dumps. */ 362 if (force_sysctl) 363 errx(EXIT_FAILURE, "can't use sysctl with dumps"); 364 365 /* 366 * If we have -M or -N, we're not dealing with live memory 367 * or want to use kvm interface explicitly. It is sometimes 368 * useful to dig inside of kernel without extending 369 * sysctl interface (i.e., without rebuilding kernel). 370 */ 371 use_sysctl = 0; 372 } else if (qflag || 373#ifndef SMALL 374 gflag || 375#endif 376 (pflag && tp->pr_sindex == N_PIMSTAT) || 377 Pflag) { 378 /* These flags are not yet supported via sysctl(3). */ 379 use_sysctl = 0; 380 } else { 381 /* We can use sysctl(3). */ 382 use_sysctl = 1; 383 } 384 385 if (force_sysctl && !use_sysctl) { 386 /* Let the user know what's about to happen. */ 387 warnx("forcing sysctl usage even though it might not be " 388 "supported"); 389 use_sysctl = 1; 390 } 391 392 kvmd = prepare_kvmd(nf, mf, buf); 393 394 if (!use_sysctl) { 395 396 if (kvmd == NULL) 397 errx(1, "kvm error: %s", buf); 398 if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) { 399 if (nf) 400 errx(1, "%s: no namelist", nf); 401 else 402 errx(1, "no namelist"); 403 } 404 } else 405 (void)setgid(getgid()); 406} 407 408int 409main(int argc, char *argv[]) 410{ 411 struct protoent *p; 412 struct protox *tp; /* for printing cblocks & stats */ 413 int ch; 414 char *cp; 415 char *afname, *afnames; 416 u_long pcbaddr; 417 418 if (prog_init) { 419 if (prog_init() == -1) 420 err(1, "init failed"); 421 force_sysctl = 1; /* cheap trick */ 422 } 423 424 egid = getegid(); 425 (void)setegid(getgid()); 426 tp = NULL; 427 af = AF_UNSPEC; 428 afnames = NULL; 429 pcbaddr = 0; 430 431 while ((ch = getopt(argc, argv, 432 "AabBdf:ghI:LliM:mN:nP:p:qrsStTuVvw:X")) != -1) 433 switch (ch) { 434 case 'A': 435 Aflag = RT_AFLAG; 436 break; 437 case 'a': 438 aflag = 1; 439 break; 440 case 'b': 441 bflag = 1; 442 break; 443 case 'B': 444 Bflag = 1; 445 break; 446 case 'd': 447 dflag = 1; 448 break; 449 case 'f': 450 afnames = optarg; 451 break; 452#ifndef SMALL 453 case 'g': 454 gflag = 1; 455 break; 456#endif 457 case 'h': 458 hflag = 1; 459 break; 460 case 'I': 461 iflag = 1; 462 interface = optarg; 463 break; 464 case 'i': 465 iflag = 1; 466 break; 467 case 'L': 468 Lflag = RT_LFLAG; 469 break; 470 case 'l': 471 lflag = 1; 472 break; 473 case 'M': 474 memf = optarg; 475 break; 476 case 'm': 477 mflag = 1; 478 break; 479 case 'N': 480 nlistf = optarg; 481 break; 482 case 'n': 483 numeric_addr = numeric_port = nflag = RT_NFLAG; 484 break; 485 case 'P': 486 errno = 0; 487 pcbaddr = strtoul(optarg, &cp, 16); 488 if (*cp != '\0' || errno == ERANGE) 489 errx(1, "invalid PCB address %s", optarg); 490 Pflag = 1; 491 break; 492 case 'p': 493 if ((tp = name2protox(optarg)) == NULL) 494 errx(1, 495 "%s: unknown or uninstrumented protocol", 496 optarg); 497 pflag = 1; 498 break; 499 case 'q': 500 qflag = 1; 501 break; 502 case 'r': 503 rflag = 1; 504 break; 505 case 's': 506 ++sflag; 507 break; 508 case 'S': 509 numeric_addr = 1; 510 break; 511 case 't': 512 tflag = 1; 513 break; 514 case 'T': 515 tagflag = RT_TFLAG; 516 break; 517 case 'u': 518 af = AF_LOCAL; 519 break; 520 case 'V': 521 Vflag++; 522 break; 523 case 'v': 524 vflag = RT_VFLAG; 525 break; 526 case 'w': 527 interval = atoi(optarg); 528 iflag = 1; 529 break; 530 case 'X': 531 force_sysctl = 1; 532 break; 533 case '?': 534 default: 535 usage(); 536 } 537 argv += optind; 538 argc -= optind; 539 540#define BACKWARD_COMPATIBILITY 541#ifdef BACKWARD_COMPATIBILITY 542 if (*argv) { 543 if (isdigit((unsigned char)**argv)) { 544 interval = atoi(*argv); 545 if (interval <= 0) 546 usage(); 547 ++argv; 548 iflag = 1; 549 } 550 if (*argv) { 551 nlistf = *argv; 552 if (*++argv) 553 memf = *argv; 554 } 555 } 556#endif 557 558 prepare(nlistf, memf, tp); 559 560#ifndef SMALL 561 if (Bflag) { 562 if (sflag) 563 nsbpf_stats(); 564 else 565 nsbpf_dump(interface); 566 exit(0); 567 } 568#endif 569 570 if (mflag) { 571 mbpr(nl[N_MBSTAT].n_value, nl[N_MSIZE].n_value, 572 nl[N_MCLBYTES].n_value, nl[N_MBPOOL].n_value, 573 nl[N_MCLPOOL].n_value); 574 exit(0); 575 } 576 if (Pflag) { 577 if (tp == NULL) { 578 /* Default to TCP. */ 579 tp = name2protox("tcp"); 580 } 581 if (tp->pr_dump) 582 (*tp->pr_dump)(nl[tp->pr_index].n_value, tp->pr_name, 583 pcbaddr); 584 else 585 printf("%s: no PCB dump routine\n", tp->pr_name); 586 exit(0); 587 } 588 if (pflag) { 589 if (iflag && tp->pr_istats) 590 intpr(interval, nl[N_IFNET_LIST].n_value, 591 tp->pr_istats); 592 else if (tp->pr_stats) 593 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 594 tp->pr_name); 595 else 596 printf("%s: no stats routine\n", tp->pr_name); 597 exit(0); 598 } 599 if (qflag) { 600 print_softintrq(); 601 exit(0); 602 } 603 /* 604 * Keep file descriptors open to avoid overhead 605 * of open/close on each call to get* routines. 606 */ 607 sethostent(1); 608 setnetent(1); 609 /* 610 * If -f was used afnames != NULL, loop over the address families. 611 * Otherwise do this at least once (with af == AF_UNSPEC). 612 */ 613 afname = NULL; 614 do { 615 if (afnames != NULL) { 616 afname = strsep(&afnames, ","); 617 if (afname == NULL) 618 break; /* Exit early */ 619 if (strcmp(afname, "inet") == 0) 620 af = AF_INET; 621 else if (strcmp(afname, "inet6") == 0) 622 af = AF_INET6; 623 else if (strcmp(afname, "arp") == 0) 624 af = AF_ARP; 625 else if (strcmp(afname, "pfkey") == 0) 626 af = PF_KEY; 627 else if (strcmp(afname, "unix") == 0 628 || strcmp(afname, "local") == 0) 629 af = AF_LOCAL; 630 else if (strcmp(afname, "atalk") == 0) 631 af = AF_APPLETALK; 632 else if (strcmp(afname, "mpls") == 0) 633 af = AF_MPLS; 634 else { 635 warnx("%s: unknown address family", 636 afname); 637 continue; 638 } 639 } 640 641 if (iflag) { 642 if (af != AF_UNSPEC) 643 goto protostat; 644 645 intpr(interval, nl[N_IFNET_LIST].n_value, NULL); 646 break; 647 } 648 if (rflag) { 649 if (sflag) 650 rt_stats(use_sysctl ? 0 : 651 nl[N_RTSTAT].n_value); 652 else { 653 if (use_sysctl) 654 p_rttables(af, 655 nflag|tagflag|vflag|Lflag, 0, ~0); 656 else 657 routepr(nl[N_RTREE].n_value); 658 } 659 break; 660 } 661#ifndef SMALL 662 if (gflag) { 663 if (sflag) { 664 if (af == AF_INET || af == AF_UNSPEC) 665 mrt_stats(nl[N_MRTPROTO].n_value, 666 nl[N_MRTSTAT].n_value); 667#ifdef INET6 668 if (af == AF_INET6 || af == AF_UNSPEC) 669 mrt6_stats(nl[N_MRT6PROTO].n_value, 670 nl[N_MRT6STAT].n_value); 671#endif 672 } 673 else { 674 if (af == AF_INET || af == AF_UNSPEC) 675 mroutepr(nl[N_MRTPROTO].n_value, 676 nl[N_MFCHASHTBL].n_value, 677 nl[N_MFCHASH].n_value, 678 nl[N_VIFTABLE].n_value); 679#ifdef INET6 680 if (af == AF_INET6 || af == AF_UNSPEC) 681 mroute6pr(nl[N_MRT6PROTO].n_value, 682 nl[N_MF6CTABLE].n_value, 683 nl[N_MIF6TABLE].n_value); 684#endif 685 } 686 break; 687 } 688#endif 689 protostat: 690 if (af == AF_INET || af == AF_UNSPEC) { 691 setprotoent(1); 692 setservent(1); 693 /* ugh, this is O(MN) ... why do we do this? */ 694 while ((p = getprotoent()) != NULL) { 695 for (tp = protox; tp->pr_name; tp++) 696 if (strcmp(tp->pr_name, p->p_name) == 0) 697 break; 698 if (tp->pr_name == 0 || tp->pr_wanted == 0) 699 continue; 700 printproto(tp, p->p_name); 701 tp->pr_wanted = 0; 702 } 703 endprotoent(); 704 for (tp = protox; tp->pr_name; tp++) 705 if (tp->pr_wanted) 706 printproto(tp, tp->pr_name); 707 } 708#ifdef INET6 709 if (af == AF_INET6 || af == AF_UNSPEC) 710 for (tp = ip6protox; tp->pr_name; tp++) 711 printproto(tp, tp->pr_name); 712#endif 713 if (af == AF_ARP || af == AF_UNSPEC) 714 for (tp = arpprotox; tp->pr_name; tp++) 715 printproto(tp, tp->pr_name); 716#ifdef IPSEC 717 if (af == PF_KEY || af == AF_UNSPEC) 718 for (tp = pfkeyprotox; tp->pr_name; tp++) 719 printproto(tp, tp->pr_name); 720#endif 721#ifndef SMALL 722 if (af == AF_APPLETALK || af == AF_UNSPEC) 723 for (tp = atalkprotox; tp->pr_name; tp++) 724 printproto(tp, tp->pr_name); 725 if ((af == AF_LOCAL || af == AF_UNSPEC) && !sflag) 726 unixpr(nl[N_UNIXSW].n_value); 727#endif 728 } while (afnames != NULL && afname != NULL); 729 exit(0); 730} 731 732/* 733 * Print out protocol statistics or control blocks (per sflag). 734 * If the interface was not specifically requested, and the symbol 735 * is not in the namelist, ignore this one. 736 */ 737static void 738printproto(struct protox *tp, const char *name) 739{ 740 void (*pr)(u_long, const char *); 741 u_long off; 742 743 if (sflag) { 744 if (iflag) { 745 if (tp->pr_istats) 746 intpr(interval, nl[N_IFNET_LIST].n_value, 747 tp->pr_istats); 748 return; 749 } 750 else { 751 pr = tp->pr_stats; 752 off = nl[tp->pr_sindex].n_value; 753 } 754 } else { 755 pr = tp->pr_cblocks; 756 off = nl[tp->pr_index].n_value; 757 } 758 if (pr != NULL && ((off || af != AF_UNSPEC) || use_sysctl)) 759 (*pr)(off, name); 760} 761 762/* 763 * Print softintrq status. 764 */ 765void 766print_softintrq(void) 767{ 768 struct ifqueue intrq, *ifq = &intrq; 769 const struct softintrq *siq; 770 u_long off; 771 772 for (siq = softintrq; siq->siq_name != NULL; siq++) { 773 off = nl[siq->siq_index].n_value; 774 if (off == 0) 775 continue; 776 777 kread(off, (char *)ifq, sizeof(*ifq)); 778 printf("%s:\n", siq->siq_name); 779 printf("\tqueue length: %d\n", ifq->ifq_len); 780 printf("\tmaximum queue length: %d\n", ifq->ifq_maxlen); 781 printf("\tpackets dropped: %" PRIu64 "\n", ifq->ifq_drops); 782 } 783} 784 785/* 786 * Read kernel memory, return 0 on success. 787 */ 788int 789kread(u_long addr, char *buf, int size) 790{ 791 792 if (kvm_read(kvmd, addr, buf, size) != size) { 793 warnx("%s", kvm_geterr(kvmd)); 794 return -1; 795 } 796 return 0; 797} 798 799const char * 800plural(int n) 801{ 802 803 return (n != 1 ? "s" : ""); 804} 805 806const char * 807plurales(int n) 808{ 809 810 return (n != 1 ? "es" : ""); 811} 812 813int 814get_hardticks(void) 815{ 816 int hardticks; 817 818 kread(nl[N_HARDCLOCK_TICKS].n_value, (char *)&hardticks, 819 sizeof(hardticks)); 820 return hardticks; 821} 822 823/* 824 * Find the protox for the given "well-known" name. 825 */ 826static struct protox * 827knownname(const char *name) 828{ 829 struct protox **tpp, *tp; 830 831 for (tpp = protoprotox; *tpp; tpp++) 832 for (tp = *tpp; tp->pr_name; tp++) 833 if (strcmp(tp->pr_name, name) == 0) 834 return tp; 835 return NULL; 836} 837 838/* 839 * Find the protox corresponding to name. 840 */ 841static struct protox * 842name2protox(const char *name) 843{ 844 struct protox *tp; 845 char **alias; /* alias from p->aliases */ 846 struct protoent *p; 847 848 /* 849 * Try to find the name in the list of "well-known" names. If that 850 * fails, check if name is an alias for an Internet protocol. 851 */ 852 if ((tp = knownname(name)) != NULL) 853 return tp; 854 855 setprotoent(1); /* make protocol lookup cheaper */ 856 while ((p = getprotoent()) != NULL) { 857 /* assert: name not same as p->name */ 858 for (alias = p->p_aliases; *alias; alias++) 859 if (strcmp(name, *alias) == 0) { 860 endprotoent(); 861 return knownname(p->p_name); 862 } 863 } 864 endprotoent(); 865 return NULL; 866} 867 868static void 869usage(void) 870{ 871 const char *progname = getprogname(); 872 873 (void)fprintf(stderr, 874"usage: %s [-Aan] [-f address_family[,family ...]] [-M core] [-N system]\n", progname); 875 (void)fprintf(stderr, 876" %s [-bdgiLmnqrsSv] [-f address_family[,family ...]] [-M core] [-N system]\n", 877 progname); 878 (void)fprintf(stderr, 879" %s [-dn] [-I interface] [-M core] [-N system] [-w wait]\n", progname); 880 (void)fprintf(stderr, 881" %s [-p protocol] [-M core] [-N system]\n", progname); 882 (void)fprintf(stderr, 883" %s [-p protocol] [-M core] [-N system] -P pcbaddr\n", progname); 884 (void)fprintf(stderr, 885" %s [-p protocol] [-i] [-I Interface] \n", progname); 886 (void)fprintf(stderr, 887" %s [-s] [-f address_family[,family ...]] [-i] [-I Interface]\n", progname); 888 (void)fprintf(stderr, 889" %s [-s] [-B] [-I interface]\n", progname); 890 exit(1); 891} 892