1 /* $NetBSD: main.c,v 1.100 2020/04/23 00:24:50 joerg 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.100 2020/04/23 00:24:50 joerg 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_NATMINTRQ 41 186 { "_natmintrq", 0, 0, 0, 0 }, 187 #define N_PPPOEDISCINQ 42 188 { "_ppoediscinq", 0, 0, 0, 0 }, 189 #define N_PPPOEINQ 43 190 { "_ppoeinq", 0, 0, 0, 0 }, 191 #define N_HARDCLOCK_TICKS 44 192 { "_hardclock_ticks", 0, 0, 0, 0 }, 193 #define N_PIMSTAT 45 194 { "_pimstat", 0, 0, 0, 0 }, 195 #define N_CARPSTAT 46 196 { "_carpstats", 0, 0, 0, 0 }, /* not available via kvm */ 197 #define N_PFSYNCSTAT 47 198 { "_pfsyncstats", 0, 0, 0, 0}, /* not available via kvm */ 199 { "", 0, 0, 0, 0 }, 200 }; 201 202 struct protox { 203 u_char pr_index; /* index into nlist of cb head */ 204 u_char pr_sindex; /* index into nlist of stat block */ 205 u_char pr_wanted; /* 1 if wanted, 0 otherwise */ 206 void (*pr_cblocks) /* control blocks printing routine */ 207 (u_long, const char *); 208 void (*pr_stats) /* statistics printing routine */ 209 (u_long, const char *); 210 void (*pr_istats) 211 (const char *); /* per/if statistics printing routine */ 212 void (*pr_dump) /* PCB state dump routine */ 213 (u_long, const char *, u_long); 214 const char *pr_name; /* well-known name */ 215 } protox[] = { 216 { N_TCBTABLE, N_TCPSTAT, 1, protopr, 217 tcp_stats, NULL, tcp_dump, "tcp" }, 218 { N_UDBTABLE, N_UDPSTAT, 1, protopr, 219 udp_stats, NULL, 0, "udp" }, 220 { -1, N_IPSTAT, 1, 0, 221 ip_stats, NULL, 0, "ip" }, 222 { -1, N_ICMPSTAT, 1, 0, 223 icmp_stats, NULL, 0, "icmp" }, 224 { -1, N_IGMPSTAT, 1, 0, 225 igmp_stats, NULL, 0, "igmp" }, 226 { -1, N_CARPSTAT, 1, 0, 227 carp_stats, NULL, 0, "carp" }, 228 #ifdef IPSEC 229 { -1, N_IPSECSTAT, 1, 0, 230 fast_ipsec_stats, NULL, 0, "ipsec" }, 231 #endif 232 { -1, N_PIMSTAT, 1, 0, 233 pim_stats, NULL, 0, "pim" }, 234 { -1, N_PFSYNCSTAT, 1, 0, 235 pfsync_stats, NULL, 0, "pfsync" }, 236 { -1, -1, 0, 0, 237 0, NULL, 0, 0 } 238 }; 239 240 #ifdef INET6 241 struct protox ip6protox[] = { 242 { -1, N_IP6STAT, 1, 0, 243 ip6_stats, ip6_ifstats, 0, "ip6" }, 244 { -1, N_ICMP6STAT, 1, 0, 245 icmp6_stats, icmp6_ifstats, 0, "icmp6" }, 246 #ifdef TCP6 247 { N_TCBTABLE, N_TCP6STAT, 1, ip6protopr, 248 tcp6_stats, NULL, tcp6_dump, "tcp6" }, 249 #else 250 { N_TCBTABLE, N_TCP6STAT, 1, ip6protopr, 251 tcp_stats, NULL, tcp6_dump, "tcp6" }, 252 #endif 253 { N_UDBTABLE, N_UDP6STAT, 1, ip6protopr, 254 udp6_stats, NULL, 0, "udp6" }, 255 #ifdef IPSEC 256 { -1, N_IPSEC6STAT, 1, 0, 257 fast_ipsec_stats, NULL, 0, "ipsec6" }, 258 #endif 259 { -1, N_PIM6STAT, 1, 0, 260 pim6_stats, NULL, 0, "pim6" }, 261 { -1, N_RIP6STAT, 1, 0, 262 rip6_stats, NULL, 0, "rip6" }, 263 { -1, -1, 0, 0, 264 0, NULL, 0, 0 } 265 }; 266 #endif 267 268 struct protox arpprotox[] = { 269 { -1, N_ARPSTAT, 1, 0, 270 arp_stats, NULL, 0, "arp" }, 271 { -1, -1, 0, 0, 272 0, NULL, 0, 0 } 273 }; 274 275 #ifdef IPSEC 276 struct protox pfkeyprotox[] = { 277 { -1, N_PFKEYSTAT, 1, 0, 278 pfkey_stats, NULL, 0, "pfkey" }, 279 { -1, -1, 0, 0, 280 0, NULL, 0, 0 } 281 }; 282 #endif 283 284 #ifndef SMALL 285 struct protox atalkprotox[] = { 286 { N_DDPCB, N_DDPSTAT, 1, atalkprotopr, 287 ddp_stats, NULL, 0, "ddp" }, 288 { -1, -1, 0, 0, 289 0, NULL, 0, NULL } 290 }; 291 #endif 292 293 struct protox *protoprotox[] = { protox, 294 #ifdef INET6 295 ip6protox, 296 #endif 297 arpprotox, 298 #ifdef IPSEC 299 pfkeyprotox, 300 #endif 301 #ifndef SMALL 302 atalkprotox, 303 #endif 304 NULL }; 305 306 const struct softintrq { 307 const char *siq_name; 308 int siq_index; 309 } softintrq[] = { 310 { "arpintrq", N_ARPINTRQ }, 311 { "atintrq1", N_ATINTRQ1 }, 312 { "atintrq2", N_ATINTRQ2 }, 313 { "natmintrq", N_NATMINTRQ }, 314 { "ppoediscinq", N_PPPOEDISCINQ }, 315 { "ppoeinq", N_PPPOEINQ }, 316 { NULL, -1 }, 317 }; 318 319 static void printproto(struct protox *, const char *); 320 static void print_softintrq(void); 321 __dead static void usage(void); 322 static struct protox *name2protox(const char *); 323 static struct protox *knownname(const char *); 324 static void prepare(const char *, const char *, struct protox *tp); 325 static kvm_t *prepare_kvmd(const char *, const char *, char *); 326 327 static kvm_t *kvmd = NULL; 328 gid_t egid; 329 int interval; /* repeat interval for i/f stats */ 330 static const char *nlistf = NULL, *memf = NULL; 331 332 kvm_t * 333 get_kvmd(void) 334 { 335 char buf[_POSIX2_LINE_MAX]; 336 337 if (kvmd != NULL) 338 return kvmd; 339 if ((kvmd = prepare_kvmd(nlistf, memf, buf)) == NULL) 340 errx(1, "kvm error: %s", buf); 341 return kvmd; 342 } 343 344 static kvm_t * 345 prepare_kvmd(const char *nf, const char *mf, char *errbuf) 346 { 347 kvm_t *k; 348 349 (void)setegid(egid); 350 k = kvm_openfiles(nf, mf, NULL, O_RDONLY, errbuf); 351 (void)setgid(getgid()); 352 return k; 353 } 354 355 void 356 prepare(const char *nf, const char *mf, struct protox *tp) 357 { 358 char buf[_POSIX2_LINE_MAX]; 359 /* 360 * Try to figure out if we can use sysctl or not. 361 */ 362 if (nf != NULL || mf != NULL) { 363 /* Of course, we can't use sysctl with dumps. */ 364 if (force_sysctl) 365 errx(EXIT_FAILURE, "can't use sysctl with dumps"); 366 367 /* 368 * If we have -M or -N, we're not dealing with live memory 369 * or want to use kvm interface explicitly. It is sometimes 370 * useful to dig inside of kernel without extending 371 * sysctl interface (i.e., without rebuilding kernel). 372 */ 373 use_sysctl = 0; 374 } else if (qflag || 375 #ifndef SMALL 376 gflag || 377 #endif 378 (pflag && tp->pr_sindex == N_PIMSTAT) || 379 Pflag) { 380 /* These flags are not yet supported via sysctl(3). */ 381 use_sysctl = 0; 382 } else { 383 /* We can use sysctl(3). */ 384 use_sysctl = 1; 385 } 386 387 if (force_sysctl && !use_sysctl) { 388 /* Let the user know what's about to happen. */ 389 warnx("forcing sysctl usage even though it might not be "\ 390 "supported"); 391 use_sysctl = 1; 392 } 393 394 kvmd = prepare_kvmd(nf, mf, buf); 395 396 if (!use_sysctl) { 397 398 if (kvmd == NULL) 399 errx(1, "kvm error: %s", buf); 400 if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) { 401 if (nf) 402 errx(1, "%s: no namelist", nf); 403 else 404 errx(1, "no namelist"); 405 } 406 } else 407 (void)setgid(getgid()); 408 } 409 410 int 411 main(int argc, char *argv[]) 412 { 413 struct protoent *p; 414 struct protox *tp; /* for printing cblocks & stats */ 415 int ch; 416 char *cp; 417 char *afname, *afnames; 418 u_long pcbaddr; 419 420 if (prog_init) { 421 if (prog_init() == -1) 422 err(1, "init failed"); 423 force_sysctl = 1; /* cheap trick */ 424 } 425 426 egid = getegid(); 427 (void)setegid(getgid()); 428 tp = NULL; 429 af = AF_UNSPEC; 430 afnames = NULL; 431 pcbaddr = 0; 432 433 while ((ch = getopt(argc, argv, 434 "AabBdf:ghI:LliM:mN:nP:p:qrsStTuVvw:X")) != -1) 435 switch (ch) { 436 case 'A': 437 Aflag = RT_AFLAG; 438 break; 439 case 'a': 440 aflag = 1; 441 break; 442 case 'b': 443 bflag = 1; 444 break; 445 case 'B': 446 Bflag = 1; 447 break; 448 case 'd': 449 dflag = 1; 450 break; 451 case 'f': 452 afnames = optarg; 453 break; 454 #ifndef SMALL 455 case 'g': 456 gflag = 1; 457 break; 458 #endif 459 case 'h': 460 hflag = 1; 461 break; 462 case 'I': 463 iflag = 1; 464 interface = optarg; 465 break; 466 case 'i': 467 iflag = 1; 468 break; 469 case 'L': 470 Lflag = RT_LFLAG; 471 break; 472 case 'l': 473 lflag = 1; 474 break; 475 case 'M': 476 memf = optarg; 477 break; 478 case 'm': 479 mflag = 1; 480 break; 481 case 'N': 482 nlistf = optarg; 483 break; 484 case 'n': 485 numeric_addr = numeric_port = nflag = RT_NFLAG; 486 break; 487 case 'P': 488 errno = 0; 489 pcbaddr = strtoul(optarg, &cp, 16); 490 if (*cp != '\0' || errno == ERANGE) 491 errx(1, "invalid PCB address %s", 492 optarg); 493 Pflag = 1; 494 break; 495 case 'p': 496 if ((tp = name2protox(optarg)) == NULL) 497 errx(1, "%s: unknown or uninstrumented protocol", 498 optarg); 499 pflag = 1; 500 break; 501 case 'q': 502 qflag = 1; 503 break; 504 case 'r': 505 rflag = 1; 506 break; 507 case 's': 508 ++sflag; 509 break; 510 case 'S': 511 numeric_addr = 1; 512 break; 513 case 't': 514 tflag = 1; 515 break; 516 case 'T': 517 tagflag = RT_TFLAG; 518 break; 519 case 'u': 520 af = AF_LOCAL; 521 break; 522 case 'V': 523 Vflag++; 524 break; 525 case 'v': 526 vflag = RT_VFLAG; 527 break; 528 case 'w': 529 interval = atoi(optarg); 530 iflag = 1; 531 break; 532 case 'X': 533 force_sysctl = 1; 534 break; 535 case '?': 536 default: 537 usage(); 538 } 539 argv += optind; 540 argc -= optind; 541 542 #define BACKWARD_COMPATIBILITY 543 #ifdef BACKWARD_COMPATIBILITY 544 if (*argv) { 545 if (isdigit((unsigned char)**argv)) { 546 interval = atoi(*argv); 547 if (interval <= 0) 548 usage(); 549 ++argv; 550 iflag = 1; 551 } 552 if (*argv) { 553 nlistf = *argv; 554 if (*++argv) 555 memf = *argv; 556 } 557 } 558 #endif 559 560 prepare(nlistf, memf, tp); 561 562 #ifndef SMALL 563 if (Bflag) { 564 if (sflag) 565 bpf_stats(); 566 else 567 bpf_dump(interface); 568 exit(0); 569 } 570 #endif 571 572 if (mflag) { 573 mbpr(nl[N_MBSTAT].n_value, nl[N_MSIZE].n_value, 574 nl[N_MCLBYTES].n_value, nl[N_MBPOOL].n_value, 575 nl[N_MCLPOOL].n_value); 576 exit(0); 577 } 578 if (Pflag) { 579 if (tp == NULL) { 580 /* Default to TCP. */ 581 tp = name2protox("tcp"); 582 } 583 if (tp->pr_dump) 584 (*tp->pr_dump)(nl[tp->pr_index].n_value, tp->pr_name, 585 pcbaddr); 586 else 587 printf("%s: no PCB dump routine\n", tp->pr_name); 588 exit(0); 589 } 590 if (pflag) { 591 if (iflag && tp->pr_istats) 592 intpr(interval, nl[N_IFNET_LIST].n_value, tp->pr_istats); 593 else if (tp->pr_stats) 594 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 595 tp->pr_name); 596 else 597 printf("%s: no stats routine\n", tp->pr_name); 598 exit(0); 599 } 600 if (qflag) { 601 print_softintrq(); 602 exit(0); 603 } 604 /* 605 * Keep file descriptors open to avoid overhead 606 * of open/close on each call to get* routines. 607 */ 608 sethostent(1); 609 setnetent(1); 610 /* 611 * If -f was used afnames != NULL, loop over the address families. 612 * Otherwise do this at least once (with af == AF_UNSPEC). 613 */ 614 afname = NULL; 615 do { 616 if (afnames != NULL) { 617 afname = strsep(&afnames, ","); 618 if (afname == NULL) 619 break; /* Exit early */ 620 if (strcmp(afname, "inet") == 0) 621 af = AF_INET; 622 else if (strcmp(afname, "inet6") == 0) 623 af = AF_INET6; 624 else if (strcmp(afname, "arp") == 0) 625 af = AF_ARP; 626 else if (strcmp(afname, "pfkey") == 0) 627 af = PF_KEY; 628 else if (strcmp(afname, "unix") == 0 629 || strcmp(afname, "local") == 0) 630 af = AF_LOCAL; 631 else if (strcmp(afname, "atalk") == 0) 632 af = AF_APPLETALK; 633 else if (strcmp(afname, "mpls") == 0) 634 af = AF_MPLS; 635 else { 636 warnx("%s: unknown address family", 637 afname); 638 continue; 639 } 640 } 641 642 if (iflag) { 643 if (af != AF_UNSPEC) 644 goto protostat; 645 646 intpr(interval, nl[N_IFNET_LIST].n_value, NULL); 647 break; 648 } 649 if (rflag) { 650 if (sflag) 651 rt_stats(use_sysctl ? 0 : 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 */ 737 static void 738 printproto(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 /* 764 * Print softintrq status. 765 */ 766 void 767 print_softintrq(void) 768 { 769 struct ifqueue intrq, *ifq = &intrq; 770 const struct softintrq *siq; 771 u_long off; 772 773 for (siq = softintrq; siq->siq_name != NULL; siq++) { 774 off = nl[siq->siq_index].n_value; 775 if (off == 0) 776 continue; 777 778 kread(off, (char *)ifq, sizeof(*ifq)); 779 printf("%s:\n", siq->siq_name); 780 printf("\tqueue length: %d\n", ifq->ifq_len); 781 printf("\tmaximum queue length: %d\n", ifq->ifq_maxlen); 782 printf("\tpackets dropped: %d\n", ifq->ifq_drops); 783 } 784 } 785 786 /* 787 * Read kernel memory, return 0 on success. 788 */ 789 int 790 kread(u_long addr, char *buf, int size) 791 { 792 793 if (kvm_read(kvmd, addr, buf, size) != size) { 794 warnx("%s", kvm_geterr(kvmd)); 795 return (-1); 796 } 797 return (0); 798 } 799 800 const char * 801 plural(int n) 802 { 803 804 return (n != 1 ? "s" : ""); 805 } 806 807 const char * 808 plurales(int n) 809 { 810 811 return (n != 1 ? "es" : ""); 812 } 813 814 int 815 get_hardticks(void) 816 { 817 int hardticks; 818 819 kread(nl[N_HARDCLOCK_TICKS].n_value, (char *)&hardticks, 820 sizeof(hardticks)); 821 return (hardticks); 822 } 823 824 /* 825 * Find the protox for the given "well-known" name. 826 */ 827 static struct protox * 828 knownname(const char *name) 829 { 830 struct protox **tpp, *tp; 831 832 for (tpp = protoprotox; *tpp; tpp++) 833 for (tp = *tpp; tp->pr_name; tp++) 834 if (strcmp(tp->pr_name, name) == 0) 835 return (tp); 836 return (NULL); 837 } 838 839 /* 840 * Find the protox corresponding to name. 841 */ 842 static struct protox * 843 name2protox(const char *name) 844 { 845 struct protox *tp; 846 char **alias; /* alias from p->aliases */ 847 struct protoent *p; 848 849 /* 850 * Try to find the name in the list of "well-known" names. If that 851 * fails, check if name is an alias for an Internet protocol. 852 */ 853 if ((tp = knownname(name)) != NULL) 854 return (tp); 855 856 setprotoent(1); /* make protocol lookup cheaper */ 857 while ((p = getprotoent()) != NULL) { 858 /* assert: name not same as p->name */ 859 for (alias = p->p_aliases; *alias; alias++) 860 if (strcmp(name, *alias) == 0) { 861 endprotoent(); 862 return (knownname(p->p_name)); 863 } 864 } 865 endprotoent(); 866 return (NULL); 867 } 868 869 static void 870 usage(void) 871 { 872 const char *progname = getprogname(); 873 874 (void)fprintf(stderr, 875 "usage: %s [-Aan] [-f address_family[,family ...]] [-M core] [-N system]\n", progname); 876 (void)fprintf(stderr, 877 " %s [-bdgiLmnqrsSv] [-f address_family[,family ...]] [-M core] [-N system]\n", 878 progname); 879 (void)fprintf(stderr, 880 " %s [-dn] [-I interface] [-M core] [-N system] [-w wait]\n", progname); 881 (void)fprintf(stderr, 882 " %s [-p protocol] [-M core] [-N system]\n", progname); 883 (void)fprintf(stderr, 884 " %s [-p protocol] [-M core] [-N system] -P pcbaddr\n", progname); 885 (void)fprintf(stderr, 886 " %s [-p protocol] [-i] [-I Interface] \n", progname); 887 (void)fprintf(stderr, 888 " %s [-s] [-f address_family[,family ...]] [-i] [-I Interface]\n", progname); 889 (void)fprintf(stderr, 890 " %s [-s] [-B] [-I interface]\n", progname); 891 exit(1); 892 } 893