1 /* BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp */ 2 /*- 3 * Copyright (c) 1983, 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 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 * 4. Neither the name of the University nor the names of its contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #if 0 32 #ifndef lint 33 static char sccsid[] = "@(#)inet6.c 8.4 (Berkeley) 4/20/94"; 34 #endif /* not lint */ 35 #endif 36 37 #include <sys/cdefs.h> 38 __FBSDID("$FreeBSD$"); 39 40 #ifdef INET6 41 #include <sys/param.h> 42 #include <sys/socket.h> 43 #include <sys/socketvar.h> 44 #include <sys/ioctl.h> 45 #include <sys/mbuf.h> 46 #include <sys/protosw.h> 47 #include <sys/sysctl.h> 48 49 #include <net/route.h> 50 #include <net/if.h> 51 #include <net/if_var.h> 52 #include <netinet/in.h> 53 #include <netinet/ip6.h> 54 #include <netinet/icmp6.h> 55 #include <netinet/in_systm.h> 56 #include <netinet6/in6_pcb.h> 57 #include <netinet6/in6_var.h> 58 #include <netinet6/ip6_var.h> 59 #include <netinet6/pim6_var.h> 60 #include <netinet6/raw_ip6.h> 61 62 #include <arpa/inet.h> 63 #include <netdb.h> 64 65 #include <err.h> 66 #include <stdint.h> 67 #include <stdio.h> 68 #include <stdbool.h> 69 #include <errno.h> 70 #include <string.h> 71 #include <unistd.h> 72 #include <libxo/xo.h> 73 #include "netstat.h" 74 75 struct socket sockb; 76 77 char *inet6name(struct in6_addr *); 78 79 static char ntop_buf[INET6_ADDRSTRLEN]; 80 81 static const char *ip6nh[] = { 82 "hop by hop", 83 "ICMP", 84 "IGMP", 85 "#3", 86 "IP", 87 "#5", 88 "TCP", 89 "#7", 90 "#8", 91 "#9", 92 "#10", 93 "#11", 94 "#12", 95 "#13", 96 "#14", 97 "#15", 98 "#16", 99 "UDP", 100 "#18", 101 "#19", 102 "#20", 103 "#21", 104 "IDP", 105 "#23", 106 "#24", 107 "#25", 108 "#26", 109 "#27", 110 "#28", 111 "TP", 112 "#30", 113 "#31", 114 "#32", 115 "#33", 116 "#34", 117 "#35", 118 "#36", 119 "#37", 120 "#38", 121 "#39", 122 "#40", 123 "IP6", 124 "#42", 125 "routing", 126 "fragment", 127 "#45", 128 "#46", 129 "#47", 130 "#48", 131 "#49", 132 "ESP", 133 "AH", 134 "#52", 135 "#53", 136 "#54", 137 "#55", 138 "#56", 139 "#57", 140 "ICMP6", 141 "no next header", 142 "destination option", 143 "#61", 144 "mobility", 145 "#63", 146 "#64", 147 "#65", 148 "#66", 149 "#67", 150 "#68", 151 "#69", 152 "#70", 153 "#71", 154 "#72", 155 "#73", 156 "#74", 157 "#75", 158 "#76", 159 "#77", 160 "#78", 161 "#79", 162 "ISOIP", 163 "#81", 164 "#82", 165 "#83", 166 "#84", 167 "#85", 168 "#86", 169 "#87", 170 "#88", 171 "OSPF", 172 "#80", 173 "#91", 174 "#92", 175 "#93", 176 "#94", 177 "#95", 178 "#96", 179 "Ethernet", 180 "#98", 181 "#99", 182 "#100", 183 "#101", 184 "#102", 185 "PIM", 186 "#104", 187 "#105", 188 "#106", 189 "#107", 190 "#108", 191 "#109", 192 "#110", 193 "#111", 194 "#112", 195 "#113", 196 "#114", 197 "#115", 198 "#116", 199 "#117", 200 "#118", 201 "#119", 202 "#120", 203 "#121", 204 "#122", 205 "#123", 206 "#124", 207 "#125", 208 "#126", 209 "#127", 210 "#128", 211 "#129", 212 "#130", 213 "#131", 214 "#132", 215 "#133", 216 "#134", 217 "#135", 218 "#136", 219 "#137", 220 "#138", 221 "#139", 222 "#140", 223 "#141", 224 "#142", 225 "#143", 226 "#144", 227 "#145", 228 "#146", 229 "#147", 230 "#148", 231 "#149", 232 "#150", 233 "#151", 234 "#152", 235 "#153", 236 "#154", 237 "#155", 238 "#156", 239 "#157", 240 "#158", 241 "#159", 242 "#160", 243 "#161", 244 "#162", 245 "#163", 246 "#164", 247 "#165", 248 "#166", 249 "#167", 250 "#168", 251 "#169", 252 "#170", 253 "#171", 254 "#172", 255 "#173", 256 "#174", 257 "#175", 258 "#176", 259 "#177", 260 "#178", 261 "#179", 262 "#180", 263 "#181", 264 "#182", 265 "#183", 266 "#184", 267 "#185", 268 "#186", 269 "#187", 270 "#188", 271 "#189", 272 "#180", 273 "#191", 274 "#192", 275 "#193", 276 "#194", 277 "#195", 278 "#196", 279 "#197", 280 "#198", 281 "#199", 282 "#200", 283 "#201", 284 "#202", 285 "#203", 286 "#204", 287 "#205", 288 "#206", 289 "#207", 290 "#208", 291 "#209", 292 "#210", 293 "#211", 294 "#212", 295 "#213", 296 "#214", 297 "#215", 298 "#216", 299 "#217", 300 "#218", 301 "#219", 302 "#220", 303 "#221", 304 "#222", 305 "#223", 306 "#224", 307 "#225", 308 "#226", 309 "#227", 310 "#228", 311 "#229", 312 "#230", 313 "#231", 314 "#232", 315 "#233", 316 "#234", 317 "#235", 318 "#236", 319 "#237", 320 "#238", 321 "#239", 322 "#240", 323 "#241", 324 "#242", 325 "#243", 326 "#244", 327 "#245", 328 "#246", 329 "#247", 330 "#248", 331 "#249", 332 "#250", 333 "#251", 334 "#252", 335 "#253", 336 "#254", 337 "#255", 338 }; 339 340 static const char *srcrule_str[] = { 341 "first candidate", 342 "same address", 343 "appropriate scope", 344 "deprecated address", 345 "home address", 346 "outgoing interface", 347 "matching label", 348 "public/temporary address", 349 "alive interface", 350 "better virtual status", 351 "preferred source", 352 "rule #11", 353 "rule #12", 354 "rule #13", 355 "longest match", 356 "rule #15", 357 }; 358 359 /* 360 * Dump IP6 statistics structure. 361 */ 362 void 363 ip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) 364 { 365 struct ip6stat ip6stat, zerostat; 366 int first, i; 367 size_t len; 368 369 len = sizeof ip6stat; 370 if (live) { 371 memset(&ip6stat, 0, len); 372 if (zflag) 373 memset(&zerostat, 0, len); 374 if (sysctlbyname("net.inet6.ip6.stats", &ip6stat, &len, 375 zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { 376 if (errno != ENOENT) 377 xo_warn("sysctl: net.inet6.ip6.stats"); 378 return; 379 } 380 } else 381 kread_counters(off, &ip6stat, len); 382 xo_open_container(name); 383 xo_emit("{T:/%s}:\n", name); 384 385 #define p(f, m) if (ip6stat.f || sflag <= 1) \ 386 xo_emit(m, (uintmax_t)ip6stat.f, plural(ip6stat.f)) 387 #define p1a(f, m) if (ip6stat.f || sflag <= 1) \ 388 xo_emit(m, (uintmax_t)ip6stat.f) 389 390 p(ip6s_total, "\t{:received-packets/%ju} " 391 "{N:/total packet%s received}\n"); 392 p1a(ip6s_toosmall, "\t{:dropped-below-minimum-size/%ju} " 393 "{N:/with size smaller than minimum}\n"); 394 p1a(ip6s_tooshort, "\t{:dropped-short-packets/%ju} " 395 "{N:/with data size < data length}\n"); 396 p1a(ip6s_badoptions, "\t{:dropped-bad-options/%ju} " 397 "{N:/with bad options}\n"); 398 p1a(ip6s_badvers, "\t{:dropped-bad-version/%ju} " 399 "{N:/with incorrect version number}\n"); 400 p(ip6s_fragments, "\t{:received-fragments/%ju} " 401 "{N:/fragment%s received}\n"); 402 p(ip6s_fragdropped, "\t{:dropped-fragment/%ju} " 403 "{N:/fragment%s dropped (dup or out of space)}\n"); 404 p(ip6s_fragtimeout, "\t{:dropped-fragment-after-timeout/%ju} " 405 "{N:/fragment%s dropped after timeout}\n"); 406 p(ip6s_fragoverflow, "\t{:dropped-fragments-overflow/%ju} " 407 "{N:/fragment%s that exceeded limit}\n"); 408 p(ip6s_reassembled, "\t{:reassembled-packets/%ju} " 409 "{N:/packet%s reassembled ok}\n"); 410 p(ip6s_delivered, "\t{:received-local-packets/%ju} " 411 "{N:/packet%s for this host}\n"); 412 p(ip6s_forward, "\t{:forwarded-packets/%ju} " 413 "{N:/packet%s forwarded}\n"); 414 p(ip6s_cantforward, "\t{:packets-not-forwardable/%ju} " 415 "{N:/packet%s not forwardable}\n"); 416 p(ip6s_redirectsent, "\t{:sent-redirects/%ju} " 417 "{N:/redirect%s sent}\n"); 418 p(ip6s_localout, "\t{:sent-packets/%ju} " 419 "{N:/packet%s sent from this host}\n"); 420 p(ip6s_rawout, "\t{:send-packets-fabricated-header/%ju} " 421 "{N:/packet%s sent with fabricated ip header}\n"); 422 p(ip6s_odropped, "\t{:discard-no-mbufs/%ju} " 423 "{N:/output packet%s dropped due to no bufs, etc.}\n"); 424 p(ip6s_noroute, "\t{:discard-no-route/%ju} " 425 "{N:/output packet%s discarded due to no route}\n"); 426 p(ip6s_fragmented, "\t{:sent-fragments/%ju} " 427 "{N:/output datagram%s fragmented}\n"); 428 p(ip6s_ofragments, "\t{:fragments-created/%ju} " 429 "{N:/fragment%s created}\n"); 430 p(ip6s_cantfrag, "\t{:discard-cannot-fragment/%ju} " 431 "{N:/datagram%s that can't be fragmented}\n"); 432 p(ip6s_badscope, "\t{:discard-scope-violations/%ju} " 433 "{N:/packet%s that violated scope rules}\n"); 434 p(ip6s_notmember, "\t{:multicast-no-join-packets/%ju} " 435 "{N:/multicast packet%s which we don't join}\n"); 436 for (first = 1, i = 0; i < IP6S_HDRCNT; i++) 437 if (ip6stat.ip6s_nxthist[i] != 0) { 438 if (first) { 439 xo_emit("\t{T:Input histogram}:\n"); 440 xo_open_list("input-histogram"); 441 first = 0; 442 } 443 xo_open_instance("input-histogram"); 444 xo_emit("\t\t{k:name/%s}: {:count/%ju}\n", ip6nh[i], 445 (uintmax_t)ip6stat.ip6s_nxthist[i]); 446 xo_close_instance("input-histogram"); 447 } 448 if (!first) 449 xo_close_list("input-histogram"); 450 451 xo_open_container("mbuf-statistics"); 452 xo_emit("\t{T:Mbuf statistics}:\n"); 453 xo_emit("\t\t{:one-mbuf/%ju} {N:/one mbuf}\n", 454 (uintmax_t)ip6stat.ip6s_m1); 455 for (first = 1, i = 0; i < IP6S_M2MMAX; i++) { 456 char ifbuf[IFNAMSIZ]; 457 if (ip6stat.ip6s_m2m[i] != 0) { 458 if (first) { 459 xo_emit("\t\t{N:two or more mbuf}:\n"); 460 xo_open_list("mbuf-data"); 461 first = 0; 462 } 463 xo_open_instance("mbuf-data"); 464 xo_emit("\t\t\t{k:name/%s}= {:count/%ju}\n", 465 if_indextoname(i, ifbuf), 466 (uintmax_t)ip6stat.ip6s_m2m[i]); 467 xo_close_instance("mbuf-data"); 468 } 469 } 470 if (!first) 471 xo_close_list("mbuf-data"); 472 xo_emit("\t\t{:one-extra-mbuf/%ju} {N:one ext mbuf}\n", 473 (uintmax_t)ip6stat.ip6s_mext1); 474 xo_emit("\t\t{:two-or-more-extra-mbufs/%ju} " 475 "{N:/two or more ext mbuf}\n", (uintmax_t)ip6stat.ip6s_mext2m); 476 xo_close_container("mbuf-statistics"); 477 478 p(ip6s_exthdrtoolong, "\t{:dropped-header-too-long/%ju} " 479 "{N:/packet%s whose headers are not contiguous}\n"); 480 p(ip6s_nogif, "\t{:discard-tunnel-no-gif/%ju} " 481 "{N:/tunneling packet%s that can't find gif}\n"); 482 p(ip6s_toomanyhdr, "\t{:dropped-too-many-headers/%ju} " 483 "{N:/packet%s discarded because of too many headers}\n"); 484 485 /* for debugging source address selection */ 486 #define PRINT_SCOPESTAT(s,i) do {\ 487 switch(i) { /* XXX hardcoding in each case */\ 488 case 1:\ 489 p(s, "\t\t{ke:name/interface-locals}{:count/%ju} " \ 490 "{N:/interface-local%s}\n"); \ 491 break;\ 492 case 2:\ 493 p(s,"\t\t{ke:name/link-locals}{:count/%ju} " \ 494 "{N:/link-local%s}\n"); \ 495 break;\ 496 case 5:\ 497 p(s,"\t\t{ke:name/site-locals}{:count/%ju} " \ 498 "{N:/site-local%s}\n");\ 499 break;\ 500 case 14:\ 501 p(s,"\t\t{ke:name/globals}{:count/%ju} " \ 502 "{N:/global%s}\n");\ 503 break;\ 504 default:\ 505 xo_emit("\t\t{qke:name/%x}{:count/%ju} " \ 506 "addresses scope=%x\n",\ 507 i, (uintmax_t)ip6stat.s, i); \ 508 }\ 509 } while (0); 510 511 xo_open_container("source-address-selection"); 512 p(ip6s_sources_none, "\t{:address-selection-failures/%ju} " 513 "{N:/failure%s of source address selection}\n"); 514 515 for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) { 516 if (ip6stat.ip6s_sources_sameif[i]) { 517 if (first) { 518 xo_open_list("outgoing-interface"); 519 xo_emit("\tsource addresses on an outgoing " 520 "I/F\n"); 521 first = 0; 522 } 523 xo_open_instance("outgoing-interface"); 524 PRINT_SCOPESTAT(ip6s_sources_sameif[i], i); 525 xo_close_instance("outgoing-interface"); 526 } 527 } 528 if (!first) 529 xo_close_list("outgoing-interface"); 530 531 for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) { 532 if (ip6stat.ip6s_sources_otherif[i]) { 533 if (first) { 534 xo_open_list("non-outgoing-interface"); 535 xo_emit("\tsource addresses on a non-outgoing " 536 "I/F\n"); 537 first = 0; 538 } 539 xo_open_instance("non-outgoing-interface"); 540 PRINT_SCOPESTAT(ip6s_sources_otherif[i], i); 541 xo_close_instance("non-outgoing-interface"); 542 } 543 } 544 if (!first) 545 xo_close_list("non-outgoing-interface"); 546 547 for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) { 548 if (ip6stat.ip6s_sources_samescope[i]) { 549 if (first) { 550 xo_open_list("same-source"); 551 xo_emit("\tsource addresses of same scope\n"); 552 first = 0; 553 } 554 xo_open_instance("same-source"); 555 PRINT_SCOPESTAT(ip6s_sources_samescope[i], i); 556 xo_close_instance("same-source"); 557 } 558 } 559 if (!first) 560 xo_close_list("same-source"); 561 562 for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) { 563 if (ip6stat.ip6s_sources_otherscope[i]) { 564 if (first) { 565 xo_open_list("different-scope"); 566 xo_emit("\tsource addresses of a different " 567 "scope\n"); 568 first = 0; 569 } 570 xo_open_instance("different-scope"); 571 PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i); 572 xo_close_instance("different-scope"); 573 } 574 } 575 if (!first) 576 xo_close_list("different-scope"); 577 578 for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) { 579 if (ip6stat.ip6s_sources_deprecated[i]) { 580 if (first) { 581 xo_open_list("deprecated-source"); 582 xo_emit("\tdeprecated source addresses\n"); 583 first = 0; 584 } 585 xo_open_instance("deprecated-source"); 586 PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i); 587 xo_close_instance("deprecated-source"); 588 } 589 } 590 if (!first) 591 xo_close_list("deprecated-source"); 592 593 for (first = 1, i = 0; i < IP6S_RULESMAX; i++) { 594 if (ip6stat.ip6s_sources_rule[i]) { 595 if (first) { 596 xo_open_list("rules-applied"); 597 xo_emit("\t{T:Source addresses selection " 598 "rule applied}:\n"); 599 first = 0; 600 } 601 xo_open_instance("rules-applied"); 602 xo_emit("\t\t{ke:name/%s}{:count/%ju} {d:name/%s}\n", 603 srcrule_str[i], 604 (uintmax_t)ip6stat.ip6s_sources_rule[i], 605 srcrule_str[i]); 606 xo_close_instance("rules-applied"); 607 } 608 } 609 if (!first) 610 xo_close_list("rules-applied"); 611 612 xo_close_container("source-address-selection"); 613 614 #undef p 615 #undef p1a 616 xo_close_container(name); 617 } 618 619 /* 620 * Dump IPv6 per-interface statistics based on RFC 2465. 621 */ 622 void 623 ip6_ifstats(char *ifname) 624 { 625 struct in6_ifreq ifr; 626 int s; 627 628 #define p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \ 629 xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_stat.f, \ 630 plural(ifr.ifr_ifru.ifru_stat.f)) 631 632 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 633 xo_warn("Warning: socket(AF_INET6)"); 634 return; 635 } 636 637 strcpy(ifr.ifr_name, ifname); 638 if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) { 639 if (errno != EPFNOSUPPORT) 640 xo_warn("Warning: ioctl(SIOCGIFSTAT_IN6)"); 641 goto end; 642 } 643 644 xo_emit("{T:/ip6 on %s}:\n", ifr.ifr_name); 645 646 xo_open_instance("ip6-interface-statistics"); 647 xo_emit("{ke:name/%s}", ifr.ifr_name); 648 649 p(ifs6_in_receive, "\t{:received-packets/%ju} " 650 "{N:/total input datagram%s}\n"); 651 p(ifs6_in_hdrerr, "\t{:dropped-invalid-header/%ju} " 652 "{N:/datagram%s with invalid header received}\n"); 653 p(ifs6_in_toobig, "\t{:dropped-mtu-exceeded/%ju} " 654 "{N:/datagram%s exceeded MTU received}\n"); 655 p(ifs6_in_noroute, "\t{:dropped-no-route/%ju} " 656 "{N:/datagram%s with no route received}\n"); 657 p(ifs6_in_addrerr, "\t{:dropped-invalid-destination/%ju} " 658 "{N:/datagram%s with invalid dst received}\n"); 659 p(ifs6_in_protounknown, "\t{:dropped-unknown-protocol/%ju} " 660 "{N:/datagram%s with unknown proto received}\n"); 661 p(ifs6_in_truncated, "\t{:dropped-truncated/%ju} " 662 "{N:/truncated datagram%s received}\n"); 663 p(ifs6_in_discard, "\t{:dropped-discarded/%ju} " 664 "{N:/input datagram%s discarded}\n"); 665 p(ifs6_in_deliver, "\t{:received-valid-packets/%ju} " 666 "{N:/datagram%s delivered to an upper layer protocol}\n"); 667 p(ifs6_out_forward, "\t{:sent-forwarded/%ju} " 668 "{N:/datagram%s forwarded to this interface}\n"); 669 p(ifs6_out_request, "\t{:sent-packets/%ju} " 670 "{N:/datagram%s sent from an upper layer protocol}\n"); 671 p(ifs6_out_discard, "\t{:discard-packets/%ju} " 672 "{N:/total discarded output datagram%s}\n"); 673 p(ifs6_out_fragok, "\t{:discard-fragments/%ju} " 674 "{N:/output datagram%s fragmented}\n"); 675 p(ifs6_out_fragfail, "\t{:fragments-failed/%ju} " 676 "{N:/output datagram%s failed on fragment}\n"); 677 p(ifs6_out_fragcreat, "\t{:fragments-created/%ju} " 678 "{N:/output datagram%s succeeded on fragment}\n"); 679 p(ifs6_reass_reqd, "\t{:reassembly-required/%ju} " 680 "{N:/incoming datagram%s fragmented}\n"); 681 p(ifs6_reass_ok, "\t{:reassembled-packets/%ju} " 682 "{N:/datagram%s reassembled}\n"); 683 p(ifs6_reass_fail, "\t{:reassembly-failed/%ju} " 684 "{N:/datagram%s failed on reassembly}\n"); 685 p(ifs6_in_mcast, "\t{:received-multicast/%ju} " 686 "{N:/multicast datagram%s received}\n"); 687 p(ifs6_out_mcast, "\t{:sent-multicast/%ju} " 688 "{N:/multicast datagram%s sent}\n"); 689 690 end: 691 xo_close_instance("ip6-interface-statistics"); 692 close(s); 693 694 #undef p 695 } 696 697 static const char *icmp6names[] = { 698 "#0", 699 "unreach", 700 "packet too big", 701 "time exceed", 702 "parameter problem", 703 "#5", 704 "#6", 705 "#7", 706 "#8", 707 "#9", 708 "#10", 709 "#11", 710 "#12", 711 "#13", 712 "#14", 713 "#15", 714 "#16", 715 "#17", 716 "#18", 717 "#19", 718 "#20", 719 "#21", 720 "#22", 721 "#23", 722 "#24", 723 "#25", 724 "#26", 725 "#27", 726 "#28", 727 "#29", 728 "#30", 729 "#31", 730 "#32", 731 "#33", 732 "#34", 733 "#35", 734 "#36", 735 "#37", 736 "#38", 737 "#39", 738 "#40", 739 "#41", 740 "#42", 741 "#43", 742 "#44", 743 "#45", 744 "#46", 745 "#47", 746 "#48", 747 "#49", 748 "#50", 749 "#51", 750 "#52", 751 "#53", 752 "#54", 753 "#55", 754 "#56", 755 "#57", 756 "#58", 757 "#59", 758 "#60", 759 "#61", 760 "#62", 761 "#63", 762 "#64", 763 "#65", 764 "#66", 765 "#67", 766 "#68", 767 "#69", 768 "#70", 769 "#71", 770 "#72", 771 "#73", 772 "#74", 773 "#75", 774 "#76", 775 "#77", 776 "#78", 777 "#79", 778 "#80", 779 "#81", 780 "#82", 781 "#83", 782 "#84", 783 "#85", 784 "#86", 785 "#87", 786 "#88", 787 "#89", 788 "#80", 789 "#91", 790 "#92", 791 "#93", 792 "#94", 793 "#95", 794 "#96", 795 "#97", 796 "#98", 797 "#99", 798 "#100", 799 "#101", 800 "#102", 801 "#103", 802 "#104", 803 "#105", 804 "#106", 805 "#107", 806 "#108", 807 "#109", 808 "#110", 809 "#111", 810 "#112", 811 "#113", 812 "#114", 813 "#115", 814 "#116", 815 "#117", 816 "#118", 817 "#119", 818 "#120", 819 "#121", 820 "#122", 821 "#123", 822 "#124", 823 "#125", 824 "#126", 825 "#127", 826 "echo", 827 "echo reply", 828 "multicast listener query", 829 "MLDv1 listener report", 830 "MLDv1 listener done", 831 "router solicitation", 832 "router advertisement", 833 "neighbor solicitation", 834 "neighbor advertisement", 835 "redirect", 836 "router renumbering", 837 "node information request", 838 "node information reply", 839 "inverse neighbor solicitation", 840 "inverse neighbor advertisement", 841 "MLDv2 listener report", 842 "#144", 843 "#145", 844 "#146", 845 "#147", 846 "#148", 847 "#149", 848 "#150", 849 "#151", 850 "#152", 851 "#153", 852 "#154", 853 "#155", 854 "#156", 855 "#157", 856 "#158", 857 "#159", 858 "#160", 859 "#161", 860 "#162", 861 "#163", 862 "#164", 863 "#165", 864 "#166", 865 "#167", 866 "#168", 867 "#169", 868 "#170", 869 "#171", 870 "#172", 871 "#173", 872 "#174", 873 "#175", 874 "#176", 875 "#177", 876 "#178", 877 "#179", 878 "#180", 879 "#181", 880 "#182", 881 "#183", 882 "#184", 883 "#185", 884 "#186", 885 "#187", 886 "#188", 887 "#189", 888 "#180", 889 "#191", 890 "#192", 891 "#193", 892 "#194", 893 "#195", 894 "#196", 895 "#197", 896 "#198", 897 "#199", 898 "#200", 899 "#201", 900 "#202", 901 "#203", 902 "#204", 903 "#205", 904 "#206", 905 "#207", 906 "#208", 907 "#209", 908 "#210", 909 "#211", 910 "#212", 911 "#213", 912 "#214", 913 "#215", 914 "#216", 915 "#217", 916 "#218", 917 "#219", 918 "#220", 919 "#221", 920 "#222", 921 "#223", 922 "#224", 923 "#225", 924 "#226", 925 "#227", 926 "#228", 927 "#229", 928 "#230", 929 "#231", 930 "#232", 931 "#233", 932 "#234", 933 "#235", 934 "#236", 935 "#237", 936 "#238", 937 "#239", 938 "#240", 939 "#241", 940 "#242", 941 "#243", 942 "#244", 943 "#245", 944 "#246", 945 "#247", 946 "#248", 947 "#249", 948 "#250", 949 "#251", 950 "#252", 951 "#253", 952 "#254", 953 "#255", 954 }; 955 956 /* 957 * Dump ICMP6 statistics. 958 */ 959 void 960 icmp6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) 961 { 962 struct icmp6stat icmp6stat, zerostat; 963 int i, first; 964 size_t len; 965 966 len = sizeof icmp6stat; 967 if (live) { 968 memset(&icmp6stat, 0, len); 969 if (zflag) 970 memset(&zerostat, 0, len); 971 if (sysctlbyname("net.inet6.icmp6.stats", &icmp6stat, &len, 972 zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { 973 if (errno != ENOENT) 974 xo_warn("sysctl: net.inet6.icmp6.stats"); 975 return; 976 } 977 } else 978 kread_counters(off, &icmp6stat, len); 979 980 xo_emit("{T:/%s}:\n", name); 981 xo_open_container(name); 982 983 #define p(f, m) if (icmp6stat.f || sflag <= 1) \ 984 xo_emit(m, (uintmax_t)icmp6stat.f, plural(icmp6stat.f)) 985 #define p_5(f, m) if (icmp6stat.f || sflag <= 1) \ 986 xo_emit(m, (uintmax_t)icmp6stat.f) 987 988 p(icp6s_error, "\t{:icmp6-calls/%ju} " 989 "{N:/call%s to icmp6_error}\n"); 990 p(icp6s_canterror, "\t{:errors-not-generated-from-message/%ju} " 991 "{N:/error%s not generated in response to an icmp6 message}\n"); 992 p(icp6s_toofreq, "\t{:errors-discarded-by-rate-limitation/%ju} " 993 "{N:/error%s not generated because of rate limitation}\n"); 994 #define NELEM (int)(sizeof(icmp6stat.icp6s_outhist)/sizeof(icmp6stat.icp6s_outhist[0])) 995 for (first = 1, i = 0; i < NELEM; i++) 996 if (icmp6stat.icp6s_outhist[i] != 0) { 997 if (first) { 998 xo_open_list("output-histogram"); 999 xo_emit("\t{T:Output histogram}:\n"); 1000 first = 0; 1001 } 1002 xo_open_instance("output-histogram"); 1003 xo_emit("\t\t{k:name/%s}: {:count/%ju}\n", 1004 icmp6names[i], 1005 (uintmax_t)icmp6stat.icp6s_outhist[i]); 1006 xo_close_instance("output-histogram"); 1007 } 1008 if (!first) 1009 xo_close_list("output-histogram"); 1010 #undef NELEM 1011 1012 p(icp6s_badcode, "\t{:dropped-bad-code/%ju} " 1013 "{N:/message%s with bad code fields}\n"); 1014 p(icp6s_tooshort, "\t{:dropped-too-short/%ju} " 1015 "{N:/message%s < minimum length}\n"); 1016 p(icp6s_checksum, "\t{:dropped-bad-checksum/%ju} " 1017 "{N:/bad checksum%s}\n"); 1018 p(icp6s_badlen, "\t{:dropped-bad-length/%ju} " 1019 "{N:/message%s with bad length}\n"); 1020 #define NELEM (int)(sizeof(icmp6stat.icp6s_inhist)/sizeof(icmp6stat.icp6s_inhist[0])) 1021 for (first = 1, i = 0; i < NELEM; i++) 1022 if (icmp6stat.icp6s_inhist[i] != 0) { 1023 if (first) { 1024 xo_open_list("input-histogram"); 1025 xo_emit("\t{T:Input histogram}:\n"); 1026 first = 0; 1027 } 1028 xo_open_instance("input-histogram"); 1029 xo_emit("\t\t{k:name/%s}: {:count/%ju}\n", 1030 icmp6names[i], 1031 (uintmax_t)icmp6stat.icp6s_inhist[i]); 1032 xo_close_instance("input-histogram"); 1033 } 1034 if (!first) 1035 xo_close_list("input-histogram"); 1036 #undef NELEM 1037 xo_emit("\t{T:Histogram of error messages to be generated}:\n"); 1038 xo_open_container("errors"); 1039 p_5(icp6s_odst_unreach_noroute, "\t\t{:no-route/%ju} " 1040 "{N:/no route}\n"); 1041 p_5(icp6s_odst_unreach_admin, "\t\t{:admin-prohibited/%ju} " 1042 "{N:/administratively prohibited}\n"); 1043 p_5(icp6s_odst_unreach_beyondscope, "\t\t{:beyond-scope/%ju} " 1044 "{N:/beyond scope}\n"); 1045 p_5(icp6s_odst_unreach_addr, "\t\t{:address-unreachable/%ju} " 1046 "{N:/address unreachable}\n"); 1047 p_5(icp6s_odst_unreach_noport, "\t\t{:port-unreachable/%ju} " 1048 "{N:/port unreachable}\n"); 1049 p_5(icp6s_opacket_too_big, "\t\t{:packet-too-big/%ju} " 1050 "{N:/packet too big}\n"); 1051 p_5(icp6s_otime_exceed_transit, "\t\t{:time-exceed-transmit/%ju} " 1052 "{N:/time exceed transit}\n"); 1053 p_5(icp6s_otime_exceed_reassembly, "\t\t{:time-exceed-reassembly/%ju} " 1054 "{N:/time exceed reassembly}\n"); 1055 p_5(icp6s_oparamprob_header, "\t\t{:bad-header/%ju} " 1056 "{N:/erroneous header field}\n"); 1057 p_5(icp6s_oparamprob_nextheader, "\t\t{:bad-next-header/%ju} " 1058 "{N:/unrecognized next header}\n"); 1059 p_5(icp6s_oparamprob_option, "\t\t{:bad-option/%ju} " 1060 "{N:/unrecognized option}\n"); 1061 p_5(icp6s_oredirect, "\t\t{:redirects/%ju} " 1062 "{N:/redirect}\n"); 1063 p_5(icp6s_ounknown, "\t\t{:unknown/%ju} {N:unknown}\n"); 1064 1065 p(icp6s_reflect, "\t{:reflect/%ju} " 1066 "{N:/message response%s generated}\n"); 1067 p(icp6s_nd_toomanyopt, "\t{:too-many-nd-options/%ju} " 1068 "{N:/message%s with too many ND options}\n"); 1069 p(icp6s_nd_badopt, "\t{:bad-nd-options/%ju} " 1070 "{N:/message%s with bad ND options}\n"); 1071 p(icp6s_badns, "\t{:bad-neighbor-solicitation/%ju} " 1072 "{N:/bad neighbor solicitation message%s}\n"); 1073 p(icp6s_badna, "\t{:bad-neighbor-advertisement/%ju} " 1074 "{N:/bad neighbor advertisement message%s}\n"); 1075 p(icp6s_badrs, "\t{:bad-router-solicitation/%ju} " 1076 "{N:/bad router solicitation message%s}\n"); 1077 p(icp6s_badra, "\t{:bad-router-advertisement/%ju} " 1078 "{N:/bad router advertisement message%s}\n"); 1079 p(icp6s_badredirect, "\t{:bad-redirect/%ju} " 1080 "{N:/bad redirect message%s}\n"); 1081 xo_close_container("errors"); 1082 p(icp6s_pmtuchg, "\t{:path-mtu-changes/%ju} {N:/path MTU change%s}\n"); 1083 #undef p 1084 #undef p_5 1085 xo_close_container(name); 1086 } 1087 1088 /* 1089 * Dump ICMPv6 per-interface statistics based on RFC 2466. 1090 */ 1091 void 1092 icmp6_ifstats(char *ifname) 1093 { 1094 struct in6_ifreq ifr; 1095 int s; 1096 1097 #define p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \ 1098 xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f, \ 1099 plural(ifr.ifr_ifru.ifru_icmp6stat.f)) 1100 #define p2(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \ 1101 xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f, \ 1102 pluralies(ifr.ifr_ifru.ifru_icmp6stat.f)) 1103 1104 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1105 xo_warn("Warning: socket(AF_INET6)"); 1106 return; 1107 } 1108 1109 strcpy(ifr.ifr_name, ifname); 1110 if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) { 1111 if (errno != EPFNOSUPPORT) 1112 xo_warn("Warning: ioctl(SIOCGIFSTAT_ICMP6)"); 1113 goto end; 1114 } 1115 1116 xo_emit("{T:/icmp6 on %s}:\n", ifr.ifr_name); 1117 1118 xo_open_instance("icmp6-interface-statistics"); 1119 xo_emit("{ke:name/%s}", ifr.ifr_name); 1120 p(ifs6_in_msg, "\t{:received-packets/%ju} " 1121 "{N:/total input message%s}\n"); 1122 p(ifs6_in_error, "\t{:received-errors/%ju} " 1123 "{N:/total input error message%s}\n"); 1124 p(ifs6_in_dstunreach, "\t{:received-destination-unreachable/%ju} " 1125 "{N:/input destination unreachable error%s}\n"); 1126 p(ifs6_in_adminprohib, "\t{:received-admin-prohibited/%ju} " 1127 "{N:/input administratively prohibited error%s}\n"); 1128 p(ifs6_in_timeexceed, "\t{:received-time-exceeded/%ju} " 1129 "{N:/input time exceeded error%s}\n"); 1130 p(ifs6_in_paramprob, "\t{:received-bad-parameter/%ju} " 1131 "{N:/input parameter problem error%s}\n"); 1132 p(ifs6_in_pkttoobig, "\t{:received-packet-too-big/%ju} " 1133 "{N:/input packet too big error%s}\n"); 1134 p(ifs6_in_echo, "\t{:received-echo-requests/%ju} " 1135 "{N:/input echo request%s}\n"); 1136 p2(ifs6_in_echoreply, "\t{:received-echo-replies/%ju} " 1137 "{N:/input echo repl%s}\n"); 1138 p(ifs6_in_routersolicit, "\t{:received-router-solicitation/%ju} " 1139 "{N:/input router solicitation%s}\n"); 1140 p(ifs6_in_routeradvert, "\t{:received-router-advertisement/%ju} " 1141 "{N:/input router advertisement%s}\n"); 1142 p(ifs6_in_neighborsolicit, "\t{:received-neighbor-solicitation/%ju} " 1143 "{N:/input neighbor solicitation%s}\n"); 1144 p(ifs6_in_neighboradvert, "\t{:received-neighbor-advertisement/%ju} " 1145 "{N:/input neighbor advertisement%s}\n"); 1146 p(ifs6_in_redirect, "\t{received-redirects/%ju} " 1147 "{N:/input redirect%s}\n"); 1148 p2(ifs6_in_mldquery, "\t{:received-mld-queries/%ju} " 1149 "{N:/input MLD quer%s}\n"); 1150 p(ifs6_in_mldreport, "\t{:received-mld-reports/%ju} " 1151 "{N:/input MLD report%s}\n"); 1152 p(ifs6_in_mlddone, "\t{:received-mld-done/%ju} " 1153 "{N:/input MLD done%s}\n"); 1154 1155 p(ifs6_out_msg, "\t{:sent-packets/%ju} " 1156 "{N:/total output message%s}\n"); 1157 p(ifs6_out_error, "\t{:sent-errors/%ju} " 1158 "{N:/total output error message%s}\n"); 1159 p(ifs6_out_dstunreach, "\t{:sent-destination-unreachable/%ju} " 1160 "{N:/output destination unreachable error%s}\n"); 1161 p(ifs6_out_adminprohib, "\t{:sent-admin-prohibited/%ju} " 1162 "{N:/output administratively prohibited error%s}\n"); 1163 p(ifs6_out_timeexceed, "\t{:sent-time-exceeded/%ju} " 1164 "{N:/output time exceeded error%s}\n"); 1165 p(ifs6_out_paramprob, "\t{:sent-bad-parameter/%ju} " 1166 "{N:/output parameter problem error%s}\n"); 1167 p(ifs6_out_pkttoobig, "\t{:sent-packet-too-big/%ju} " 1168 "{N:/output packet too big error%s}\n"); 1169 p(ifs6_out_echo, "\t{:sent-echo-requests/%ju} " 1170 "{N:/output echo request%s}\n"); 1171 p2(ifs6_out_echoreply, "\t{:sent-echo-replies/%ju} " 1172 "{N:/output echo repl%s}\n"); 1173 p(ifs6_out_routersolicit, "\t{:sent-router-solicitation/%ju} " 1174 "{N:/output router solicitation%s}\n"); 1175 p(ifs6_out_routeradvert, "\t{:sent-router-advertisement/%ju} " 1176 "{N:/output router advertisement%s}\n"); 1177 p(ifs6_out_neighborsolicit, "\t{:sent-neighbor-solicitation/%ju} " 1178 "{N:/output neighbor solicitation%s}\n"); 1179 p(ifs6_out_neighboradvert, "\t{:sent-neighbor-advertisement/%ju} " 1180 "{N:/output neighbor advertisement%s}\n"); 1181 p(ifs6_out_redirect, "\t{:sent-redirects/%ju} " 1182 "{N:/output redirect%s}\n"); 1183 p2(ifs6_out_mldquery, "\t{:sent-mld-queries/%ju} " 1184 "{N:/output MLD quer%s}\n"); 1185 p(ifs6_out_mldreport, "\t{:sent-mld-reports/%ju} " 1186 "{N:/output MLD report%s}\n"); 1187 p(ifs6_out_mlddone, "\t{:sent-mld-dones/%ju} " 1188 "{N:/output MLD done%s}\n"); 1189 1190 end: 1191 xo_close_instance("icmp6-interface-statistics"); 1192 close(s); 1193 #undef p 1194 } 1195 1196 /* 1197 * Dump PIM statistics structure. 1198 */ 1199 void 1200 pim6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) 1201 { 1202 struct pim6stat pim6stat, zerostat; 1203 size_t len = sizeof pim6stat; 1204 1205 if (live) { 1206 if (zflag) 1207 memset(&zerostat, 0, len); 1208 if (sysctlbyname("net.inet6.pim.stats", &pim6stat, &len, 1209 zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { 1210 if (errno != ENOENT) 1211 xo_warn("sysctl: net.inet6.pim.stats"); 1212 return; 1213 } 1214 } else { 1215 if (off == 0) 1216 return; 1217 kread(off, &pim6stat, len); 1218 } 1219 1220 xo_emit("{T:/%s}:\n", name); 1221 xo_open_container(name); 1222 1223 #define p(f, m) if (pim6stat.f || sflag <= 1) \ 1224 xo_emit(m, (uintmax_t)pim6stat.f, plural(pim6stat.f)) 1225 1226 p(pim6s_rcv_total, "\t{:received-packets/%ju} " 1227 "{N:/message%s received}\n"); 1228 p(pim6s_rcv_tooshort, "\t{:dropped-too-short/%ju} " 1229 "{N:/message%s received with too few bytes}\n"); 1230 p(pim6s_rcv_badsum, "\t{:dropped-bad-checksum/%ju} " 1231 "{N:/message%s received with bad checksum}\n"); 1232 p(pim6s_rcv_badversion, "\t{:dropped-bad-version/%ju} " 1233 "{N:/message%s received with bad version}\n"); 1234 p(pim6s_rcv_registers, "\t{:received-registers/%ju} " 1235 "{N:/register%s received}\n"); 1236 p(pim6s_rcv_badregisters, "\t{:received-bad-registers/%ju} " 1237 "{N:/bad register%s received}\n"); 1238 p(pim6s_snd_registers, "\t{:sent-registers/%ju} " 1239 "{N:/register%s sent}\n"); 1240 #undef p 1241 xo_close_container(name); 1242 } 1243 1244 /* 1245 * Dump raw ip6 statistics structure. 1246 */ 1247 void 1248 rip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) 1249 { 1250 struct rip6stat rip6stat, zerostat; 1251 u_quad_t delivered; 1252 size_t len; 1253 1254 len = sizeof(rip6stat); 1255 if (live) { 1256 if (zflag) 1257 memset(&zerostat, 0, len); 1258 if (sysctlbyname("net.inet6.ip6.rip6stats", &rip6stat, &len, 1259 zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { 1260 if (errno != ENOENT) 1261 xo_warn("sysctl: net.inet6.ip6.rip6stats"); 1262 return; 1263 } 1264 } else 1265 kread_counters(off, &rip6stat, len); 1266 1267 xo_emit("{T:/%s}:\n", name); 1268 xo_open_container(name); 1269 1270 #define p(f, m) if (rip6stat.f || sflag <= 1) \ 1271 xo_emit(m, (uintmax_t)rip6stat.f, plural(rip6stat.f)) 1272 1273 p(rip6s_ipackets, "\t{:received-packets/%ju} " 1274 "{N:/message%s received}\n"); 1275 p(rip6s_isum, "\t{:input-checksum-computation/%ju} " 1276 "{N:/checksum calculation%s on inbound}\n"); 1277 p(rip6s_badsum, "\t{:received-bad-checksum/%ju} " 1278 "{N:/message%s with bad checksum}\n"); 1279 p(rip6s_nosock, "\t{:dropped-no-socket/%ju} " 1280 "{N:/message%s dropped due to no socket}\n"); 1281 p(rip6s_nosockmcast, "\t{:dropped-multicast-no-socket/%ju} " 1282 "{N:/multicast message%s dropped due to no socket}\n"); 1283 p(rip6s_fullsock, "\t{:dropped-full-socket-buffer/%ju} " 1284 "{N:/message%s dropped due to full socket buffers}\n"); 1285 delivered = rip6stat.rip6s_ipackets - 1286 rip6stat.rip6s_badsum - 1287 rip6stat.rip6s_nosock - 1288 rip6stat.rip6s_nosockmcast - 1289 rip6stat.rip6s_fullsock; 1290 if (delivered || sflag <= 1) 1291 xo_emit("\t{:delivered-packets/%ju} {N:/delivered}\n", 1292 (uintmax_t)delivered); 1293 p(rip6s_opackets, "\t{:sent-packets/%ju} " 1294 "{N:/datagram%s output}\n"); 1295 #undef p 1296 xo_close_container(name); 1297 } 1298 1299 /* 1300 * Pretty print an Internet address (net address + port). 1301 * Take numeric_addr and numeric_port into consideration. 1302 */ 1303 #define GETSERVBYPORT6(port, proto, ret)\ 1304 {\ 1305 if (strcmp((proto), "tcp6") == 0)\ 1306 (ret) = getservbyport((int)(port), "tcp");\ 1307 else if (strcmp((proto), "udp6") == 0)\ 1308 (ret) = getservbyport((int)(port), "udp");\ 1309 else\ 1310 (ret) = getservbyport((int)(port), (proto));\ 1311 }; 1312 1313 void 1314 inet6print(const char *container, struct in6_addr *in6, int port, 1315 const char *proto, int numeric) 1316 { 1317 struct servent *sp = 0; 1318 char line[80], *cp; 1319 int width; 1320 1321 if (container) 1322 xo_open_container(container); 1323 1324 sprintf(line, "%.*s.", Wflag ? 39 : (Aflag && !numeric) ? 12 : 16, 1325 inet6name(in6)); 1326 cp = strchr(line, '\0'); 1327 if (!numeric && port) 1328 GETSERVBYPORT6(port, proto, sp); 1329 if (sp || port == 0) 1330 sprintf(cp, "%.15s", sp ? sp->s_name : "*"); 1331 else 1332 sprintf(cp, "%d", ntohs((u_short)port)); 1333 width = Wflag ? 45 : Aflag ? 18 : 22; 1334 1335 xo_emit("{d:target/%-*.*s} ", width, width, line); 1336 1337 int alen = cp - line - 1, plen = strlen(cp) - 1; 1338 xo_emit("{e:address/%*.*s}{e:port/%*.*s}", alen, alen, line, plen, 1339 plen, cp); 1340 1341 if (container) 1342 xo_close_container(container); 1343 } 1344 1345 /* 1346 * Construct an Internet address representation. 1347 * If the numeric_addr has been supplied, give 1348 * numeric value, otherwise try for symbolic name. 1349 */ 1350 1351 char * 1352 inet6name(struct in6_addr *in6p) 1353 { 1354 struct sockaddr_in6 sin6; 1355 char hbuf[NI_MAXHOST], *cp; 1356 static char line[50]; 1357 static char domain[MAXHOSTNAMELEN]; 1358 static int first = 1; 1359 int flags, error; 1360 1361 if (IN6_IS_ADDR_UNSPECIFIED(in6p)) { 1362 strcpy(line, "*"); 1363 return (line); 1364 } 1365 if (first && !numeric_addr) { 1366 first = 0; 1367 if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 1368 (cp = strchr(domain, '.'))) 1369 (void) strcpy(domain, cp + 1); 1370 else 1371 domain[0] = 0; 1372 } 1373 memset(&sin6, 0, sizeof(sin6)); 1374 memcpy(&sin6.sin6_addr, in6p, sizeof(*in6p)); 1375 sin6.sin6_family = AF_INET6; 1376 /* XXX: in6p.s6_addr[2] can contain scopeid. */ 1377 in6_fillscopeid(&sin6); 1378 flags = (numeric_addr) ? NI_NUMERICHOST : 0; 1379 error = getnameinfo((struct sockaddr *)&sin6, sizeof(sin6), hbuf, 1380 sizeof(hbuf), NULL, 0, flags); 1381 if (error == 0) { 1382 if ((flags & NI_NUMERICHOST) == 0 && 1383 (cp = strchr(hbuf, '.')) && 1384 !strcmp(cp + 1, domain)) 1385 *cp = 0; 1386 strcpy(line, hbuf); 1387 } else { 1388 /* XXX: this should not happen. */ 1389 sprintf(line, "%s", 1390 inet_ntop(AF_INET6, (void *)&sin6.sin6_addr, ntop_buf, 1391 sizeof(ntop_buf))); 1392 } 1393 return (line); 1394 } 1395 #endif /*INET6*/ 1396