1 /*- 2 * Copyright (c) 1983, 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #if 0 31 #ifndef lint 32 static char sccsid[] = "From: @(#)route.c 8.6 (Berkeley) 4/28/95"; 33 #endif /* not lint */ 34 #endif 35 36 #include <sys/cdefs.h> 37 __FBSDID("$FreeBSD$"); 38 39 #include <sys/param.h> 40 #include <sys/protosw.h> 41 #include <sys/socket.h> 42 #include <sys/socketvar.h> 43 #include <sys/sysctl.h> 44 #include <sys/time.h> 45 46 #include <net/ethernet.h> 47 #include <net/if.h> 48 #include <net/if_dl.h> 49 #include <net/if_types.h> 50 #include <net/route.h> 51 52 #include <netinet/in.h> 53 #include <netgraph/ng_socket.h> 54 55 #include <arpa/inet.h> 56 #include <ifaddrs.h> 57 #include <libutil.h> 58 #include <netdb.h> 59 #include <nlist.h> 60 #include <stdint.h> 61 #include <stdio.h> 62 #include <stdlib.h> 63 #include <stdbool.h> 64 #include <string.h> 65 #include <sysexits.h> 66 #include <unistd.h> 67 #include <err.h> 68 #include <libxo/xo.h> 69 #include "netstat.h" 70 71 /* 72 * Definitions for showing gateway flags. 73 */ 74 struct bits { 75 u_long b_mask; 76 char b_val; 77 const char *b_name; 78 } bits[] = { 79 { RTF_UP, 'U', "up" }, 80 { RTF_GATEWAY, 'G', "gateway" }, 81 { RTF_HOST, 'H', "host" }, 82 { RTF_REJECT, 'R', "reject" }, 83 { RTF_DYNAMIC, 'D', "dynamic" }, 84 { RTF_MODIFIED, 'M', "modified" }, 85 { RTF_DONE, 'd', "done" }, /* Completed -- for routing msgs only */ 86 { RTF_XRESOLVE, 'X', "xresolve" }, 87 { RTF_STATIC, 'S', "static" }, 88 { RTF_PROTO1, '1', "proto1" }, 89 { RTF_PROTO2, '2', "proto2" }, 90 { RTF_PROTO3, '3', "proto3" }, 91 { RTF_BLACKHOLE,'B', "blackhole" }, 92 { RTF_BROADCAST,'b', "broadcast" }, 93 #ifdef RTF_LLINFO 94 { RTF_LLINFO, 'L', "llinfo" }, 95 #endif 96 { 0 , 0, NULL } 97 }; 98 99 /* 100 * kvm(3) bindings for every needed symbol 101 */ 102 static struct nlist rl[] = { 103 #define N_RTSTAT 0 104 { .n_name = "_rtstat" }, 105 #define N_RTTRASH 1 106 { .n_name = "_rttrash" }, 107 { .n_name = NULL }, 108 }; 109 110 typedef union { 111 long dummy; /* Helps align structure. */ 112 struct sockaddr u_sa; 113 u_short u_data[128]; 114 } sa_u; 115 116 struct ifmap_entry { 117 char ifname[IFNAMSIZ]; 118 }; 119 static struct ifmap_entry *ifmap; 120 static int ifmap_size; 121 struct timespec uptime; 122 123 static void p_rtable_sysctl(int, int); 124 static void p_rtentry_sysctl(const char *name, struct rt_msghdr *); 125 static void p_sockaddr(const char *name, struct sockaddr *, struct sockaddr *, 126 int, int); 127 static const char *fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, 128 int flags); 129 static void p_flags(int, const char *); 130 static const char *fmt_flags(int f); 131 static void domask(char *, in_addr_t, u_long); 132 133 /* 134 * Print routing tables. 135 */ 136 void 137 routepr(int fibnum, int af) 138 { 139 size_t intsize; 140 int numfibs; 141 142 if (live == 0) 143 return; 144 145 intsize = sizeof(int); 146 if (fibnum == -1 && 147 sysctlbyname("net.my_fibnum", &fibnum, &intsize, NULL, 0) == -1) 148 fibnum = 0; 149 if (sysctlbyname("net.fibs", &numfibs, &intsize, NULL, 0) == -1) 150 numfibs = 1; 151 if (fibnum < 0 || fibnum > numfibs - 1) 152 errx(EX_USAGE, "%d: invalid fib", fibnum); 153 /* 154 * Since kernel & userland use different timebase 155 * (time_uptime vs time_second) and we are reading kernel memory 156 * directly we should do rt_expire --> expire_time conversion. 157 */ 158 if (clock_gettime(CLOCK_UPTIME, &uptime) < 0) 159 err(EX_OSERR, "clock_gettime() failed"); 160 161 xo_open_container("route-information"); 162 xo_emit("{T:Routing tables}"); 163 if (fibnum) 164 xo_emit(" ({L:fib}: {:fib/%d})", fibnum); 165 xo_emit("\n"); 166 p_rtable_sysctl(fibnum, af); 167 xo_close_container("route-information"); 168 } 169 170 171 /* 172 * Print address family header before a section of the routing table. 173 */ 174 void 175 pr_family(int af1) 176 { 177 const char *afname; 178 179 switch (af1) { 180 case AF_INET: 181 afname = "Internet"; 182 break; 183 #ifdef INET6 184 case AF_INET6: 185 afname = "Internet6"; 186 break; 187 #endif /*INET6*/ 188 case AF_ISO: 189 afname = "ISO"; 190 break; 191 case AF_CCITT: 192 afname = "X.25"; 193 break; 194 case AF_NETGRAPH: 195 afname = "Netgraph"; 196 break; 197 default: 198 afname = NULL; 199 break; 200 } 201 if (afname) 202 xo_emit("\n{k:address-family/%s}:\n", afname); 203 else 204 xo_emit("\n{L:Protocol Family} {k:address-family/%d}:\n", af1); 205 } 206 207 /* column widths; each followed by one space */ 208 #ifndef INET6 209 #define WID_DST_DEFAULT(af) 18 /* width of destination column */ 210 #define WID_GW_DEFAULT(af) 18 /* width of gateway column */ 211 #define WID_IF_DEFAULT(af) (Wflag ? 10 : 8) /* width of netif column */ 212 #else 213 #define WID_DST_DEFAULT(af) \ 214 ((af) == AF_INET6 ? (numeric_addr ? 33: 18) : 18) 215 #define WID_GW_DEFAULT(af) \ 216 ((af) == AF_INET6 ? (numeric_addr ? 29 : 18) : 18) 217 #define WID_IF_DEFAULT(af) ((af) == AF_INET6 ? 8 : (Wflag ? 10 : 8)) 218 #endif /*INET6*/ 219 220 static int wid_dst; 221 static int wid_gw; 222 static int wid_flags; 223 static int wid_pksent; 224 static int wid_mtu; 225 static int wid_if; 226 static int wid_expire; 227 228 /* 229 * Print header for routing table columns. 230 */ 231 void 232 pr_rthdr(int af1) 233 { 234 235 if (Aflag) 236 xo_emit("{T:/%-8.8s} ","Address"); 237 if (Wflag) { 238 xo_emit("{T:/%-*.*s} {T:/%-*.*s} {T:/%-*.*s} {T:/%*.*s} " 239 "{T:/%*.*s} {T:/%*.*s} {T:/%*s}\n", 240 wid_dst, wid_dst, "Destination", 241 wid_gw, wid_gw, "Gateway", 242 wid_flags, wid_flags, "Flags", 243 wid_pksent, wid_pksent, "Use", 244 wid_mtu, wid_mtu, "Mtu", 245 wid_if, wid_if, "Netif", 246 wid_expire, "Expire"); 247 } else { 248 xo_emit("{T:/%-*.*s} {T:/%-*.*s} {T:/%-*.*s} {T:/%*.*s} " 249 "{T:/%*s}\n", 250 wid_dst, wid_dst, "Destination", 251 wid_gw, wid_gw, "Gateway", 252 wid_flags, wid_flags, "Flags", 253 wid_if, wid_if, "Netif", 254 wid_expire, "Expire"); 255 } 256 } 257 258 static void 259 p_rtable_sysctl(int fibnum, int af) 260 { 261 size_t needed; 262 int mib[7]; 263 char *buf, *next, *lim; 264 struct rt_msghdr *rtm; 265 struct sockaddr *sa; 266 int fam = AF_UNSPEC, ifindex = 0, size; 267 int need_table_close = false; 268 269 struct ifaddrs *ifap, *ifa; 270 struct sockaddr_dl *sdl; 271 272 /* 273 * Retrieve interface list at first 274 * since we need #ifindex -> if_xname match 275 */ 276 if (getifaddrs(&ifap) != 0) 277 err(EX_OSERR, "getifaddrs"); 278 279 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 280 281 if (ifa->ifa_addr->sa_family != AF_LINK) 282 continue; 283 284 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 285 ifindex = sdl->sdl_index; 286 287 if (ifindex >= ifmap_size) { 288 size = roundup(ifindex + 1, 32) * 289 sizeof(struct ifmap_entry); 290 if ((ifmap = realloc(ifmap, size)) == NULL) 291 errx(2, "realloc(%d) failed", size); 292 memset(&ifmap[ifmap_size], 0, 293 size - ifmap_size * 294 sizeof(struct ifmap_entry)); 295 296 ifmap_size = roundup(ifindex + 1, 32); 297 } 298 299 if (*ifmap[ifindex].ifname != '\0') 300 continue; 301 302 strlcpy(ifmap[ifindex].ifname, ifa->ifa_name, IFNAMSIZ); 303 } 304 305 freeifaddrs(ifap); 306 307 mib[0] = CTL_NET; 308 mib[1] = PF_ROUTE; 309 mib[2] = 0; 310 mib[3] = af; 311 mib[4] = NET_RT_DUMP; 312 mib[5] = 0; 313 mib[6] = fibnum; 314 if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0) 315 err(EX_OSERR, "sysctl: net.route.0.%d.dump.%d estimate", af, 316 fibnum); 317 if ((buf = malloc(needed)) == NULL) 318 errx(2, "malloc(%lu)", (unsigned long)needed); 319 if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) 320 err(1, "sysctl: net.route.0.%d.dump.%d", af, fibnum); 321 lim = buf + needed; 322 xo_open_container("route-table"); 323 xo_open_list("rt-family"); 324 for (next = buf; next < lim; next += rtm->rtm_msglen) { 325 rtm = (struct rt_msghdr *)next; 326 if (rtm->rtm_version != RTM_VERSION) 327 continue; 328 /* 329 * Peek inside header to determine AF 330 */ 331 sa = (struct sockaddr *)(rtm + 1); 332 /* Only print family first time. */ 333 if (fam != sa->sa_family) { 334 if (need_table_close) { 335 xo_close_list("rt-entry"); 336 xo_close_instance("rt-family"); 337 } 338 need_table_close = true; 339 340 fam = sa->sa_family; 341 wid_dst = WID_DST_DEFAULT(fam); 342 wid_gw = WID_GW_DEFAULT(fam); 343 wid_flags = 6; 344 wid_pksent = 8; 345 wid_mtu = 6; 346 wid_if = WID_IF_DEFAULT(fam); 347 wid_expire = 6; 348 xo_open_instance("rt-family"); 349 pr_family(fam); 350 xo_open_list("rt-entry"); 351 352 pr_rthdr(fam); 353 } 354 p_rtentry_sysctl("rt-entry", rtm); 355 } 356 if (need_table_close) { 357 xo_close_list("rt-entry"); 358 xo_close_instance("rt-family"); 359 } 360 xo_close_list("rt-family"); 361 xo_close_container("route-table"); 362 free(buf); 363 } 364 365 static void 366 p_rtentry_sysctl(const char *name, struct rt_msghdr *rtm) 367 { 368 struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 369 char buffer[128]; 370 char prettyname[128]; 371 sa_u addr, mask, gw; 372 unsigned int l; 373 374 xo_open_instance(name); 375 376 #define GETSA(_s, _f) { \ 377 bzero(&(_s), sizeof(_s)); \ 378 if (rtm->rtm_addrs & _f) { \ 379 l = roundup(sa->sa_len, sizeof(long)); \ 380 memcpy(&(_s), sa, (l > sizeof(_s)) ? sizeof(_s) : l); \ 381 sa = (struct sockaddr *)((char *)sa + l); \ 382 } \ 383 } 384 385 GETSA(addr, RTA_DST); 386 GETSA(gw, RTA_GATEWAY); 387 GETSA(mask, RTA_NETMASK); 388 389 p_sockaddr("destination", &addr.u_sa, &mask.u_sa, rtm->rtm_flags, 390 wid_dst); 391 p_sockaddr("gateway", &gw.u_sa, NULL, RTF_HOST, wid_gw); 392 snprintf(buffer, sizeof(buffer), "{[:-%d}{:flags/%%s}{]:} ", 393 wid_flags); 394 p_flags(rtm->rtm_flags, buffer); 395 if (Wflag) { 396 xo_emit("{t:use/%*lu} ", wid_pksent, rtm->rtm_rmx.rmx_pksent); 397 398 if (rtm->rtm_rmx.rmx_mtu != 0) 399 xo_emit("{t:mtu/%*lu} ", wid_mtu, rtm->rtm_rmx.rmx_mtu); 400 else 401 xo_emit("{P:/%*s} ", wid_mtu, ""); 402 } 403 404 memset(prettyname, 0, sizeof(prettyname)); 405 if (rtm->rtm_index < ifmap_size) { 406 strlcpy(prettyname, ifmap[rtm->rtm_index].ifname, 407 sizeof(prettyname)); 408 if (*prettyname == '\0') 409 strlcpy(prettyname, "---", sizeof(prettyname)); 410 } 411 412 xo_emit("{t:interface-name/%*.*s}", wid_if, wid_if, prettyname); 413 if (rtm->rtm_rmx.rmx_expire) { 414 time_t expire_time; 415 416 if ((expire_time = rtm->rtm_rmx.rmx_expire - uptime.tv_sec) > 0) 417 xo_emit(" {:expire-time/%*d}", wid_expire, 418 (int)expire_time); 419 } 420 421 xo_emit("\n"); 422 xo_close_instance(name); 423 } 424 425 static void 426 p_sockaddr(const char *name, struct sockaddr *sa, struct sockaddr *mask, 427 int flags, int width) 428 { 429 const char *cp; 430 char buf[128]; 431 432 cp = fmt_sockaddr(sa, mask, flags); 433 434 if (width < 0) { 435 snprintf(buf, sizeof(buf), "{:%s/%%s} ", name); 436 xo_emit(buf, cp); 437 } else { 438 if (numeric_addr) { 439 snprintf(buf, sizeof(buf), "{[:%d}{:%s/%%s}{]:} ", 440 -width, name); 441 xo_emit(buf, cp); 442 } else { 443 snprintf(buf, sizeof(buf), "{[:%d}{:%s/%%-.*s}{]:} ", 444 -width, name); 445 xo_emit(buf, width, cp); 446 } 447 } 448 } 449 450 static const char * 451 fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags) 452 { 453 static char workbuf[128]; 454 const char *cp; 455 456 if (sa == NULL) 457 return ("null"); 458 459 switch(sa->sa_family) { 460 case AF_INET: 461 { 462 struct sockaddr_in *sockin = (struct sockaddr_in *)sa; 463 464 if ((sockin->sin_addr.s_addr == INADDR_ANY) && 465 mask && 466 ntohl(((struct sockaddr_in *)mask)->sin_addr.s_addr) 467 ==0L) 468 cp = "default" ; 469 else if (flags & RTF_HOST) 470 cp = routename(sockin->sin_addr.s_addr); 471 else if (mask) 472 cp = netname(sockin->sin_addr.s_addr, 473 ((struct sockaddr_in *)mask)->sin_addr.s_addr); 474 else 475 cp = netname(sockin->sin_addr.s_addr, INADDR_ANY); 476 break; 477 } 478 479 #ifdef INET6 480 case AF_INET6: 481 { 482 struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; 483 484 /* 485 * The sa6->sin6_scope_id must be filled here because 486 * this sockaddr is extracted from kmem(4) directly 487 * and has KAME-specific embedded scope id in 488 * sa6->sin6_addr.s6_addr[2]. 489 */ 490 in6_fillscopeid(sa6); 491 492 if (flags & RTF_HOST) 493 cp = routename6(sa6); 494 else if (mask) 495 cp = netname6(sa6, 496 &((struct sockaddr_in6 *)mask)->sin6_addr); 497 else { 498 cp = netname6(sa6, NULL); 499 } 500 break; 501 } 502 #endif /*INET6*/ 503 504 case AF_NETGRAPH: 505 { 506 strlcpy(workbuf, ((struct sockaddr_ng *)sa)->sg_data, 507 sizeof(workbuf)); 508 cp = workbuf; 509 break; 510 } 511 512 case AF_LINK: 513 { 514 struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; 515 516 if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && 517 sdl->sdl_slen == 0) { 518 (void) sprintf(workbuf, "link#%d", sdl->sdl_index); 519 cp = workbuf; 520 } else 521 switch (sdl->sdl_type) { 522 523 case IFT_ETHER: 524 case IFT_L2VLAN: 525 case IFT_BRIDGE: 526 if (sdl->sdl_alen == ETHER_ADDR_LEN) { 527 cp = ether_ntoa((struct ether_addr *) 528 (sdl->sdl_data + sdl->sdl_nlen)); 529 break; 530 } 531 /* FALLTHROUGH */ 532 default: 533 cp = link_ntoa(sdl); 534 break; 535 } 536 break; 537 } 538 539 default: 540 { 541 u_char *s = (u_char *)sa->sa_data, *slim; 542 char *cq, *cqlim; 543 544 cq = workbuf; 545 slim = sa->sa_len + (u_char *) sa; 546 cqlim = cq + sizeof(workbuf) - 6; 547 cq += sprintf(cq, "(%d)", sa->sa_family); 548 while (s < slim && cq < cqlim) { 549 cq += sprintf(cq, " %02x", *s++); 550 if (s < slim) 551 cq += sprintf(cq, "%02x", *s++); 552 } 553 cp = workbuf; 554 } 555 } 556 557 return (cp); 558 } 559 560 static void 561 p_flags(int f, const char *format) 562 { 563 struct bits *p; 564 565 xo_emit(format, fmt_flags(f)); 566 567 xo_open_list("flags_pretty"); 568 for (p = bits; p->b_mask; p++) 569 if (p->b_mask & f) 570 xo_emit("{le:flags_pretty/%s}", p->b_name); 571 xo_close_list("flags_pretty"); 572 } 573 574 static const char * 575 fmt_flags(int f) 576 { 577 static char name[33]; 578 char *flags; 579 struct bits *p = bits; 580 581 for (flags = name; p->b_mask; p++) 582 if (p->b_mask & f) 583 *flags++ = p->b_val; 584 *flags = '\0'; 585 return (name); 586 } 587 588 char * 589 routename(in_addr_t in) 590 { 591 char *cp; 592 static char line[MAXHOSTNAMELEN]; 593 struct hostent *hp; 594 595 cp = 0; 596 if (!numeric_addr) { 597 hp = gethostbyaddr(&in, sizeof (struct in_addr), AF_INET); 598 if (hp) { 599 cp = hp->h_name; 600 trimdomain(cp, strlen(cp)); 601 } 602 } 603 if (cp) { 604 strlcpy(line, cp, sizeof(line)); 605 } else { 606 #define C(x) ((x) & 0xff) 607 in = ntohl(in); 608 sprintf(line, "%u.%u.%u.%u", 609 C(in >> 24), C(in >> 16), C(in >> 8), C(in)); 610 } 611 return (line); 612 } 613 614 #define NSHIFT(m) ( \ 615 (m) == IN_CLASSA_NET ? IN_CLASSA_NSHIFT : \ 616 (m) == IN_CLASSB_NET ? IN_CLASSB_NSHIFT : \ 617 (m) == IN_CLASSC_NET ? IN_CLASSC_NSHIFT : \ 618 0) 619 620 static void 621 domask(char *dst, in_addr_t addr __unused, u_long mask) 622 { 623 int b, i; 624 625 if (mask == 0 || (!numeric_addr && NSHIFT(mask) != 0)) { 626 *dst = '\0'; 627 return; 628 } 629 i = 0; 630 for (b = 0; b < 32; b++) 631 if (mask & (1 << b)) { 632 int bb; 633 634 i = b; 635 for (bb = b+1; bb < 32; bb++) 636 if (!(mask & (1 << bb))) { 637 i = -1; /* noncontig */ 638 break; 639 } 640 break; 641 } 642 if (i == -1) 643 sprintf(dst, "&0x%lx", mask); 644 else 645 sprintf(dst, "/%d", 32-i); 646 } 647 648 /* 649 * Return the name of the network whose address is given. 650 */ 651 char * 652 netname(in_addr_t in, in_addr_t mask) 653 { 654 char *cp = 0; 655 static char line[MAXHOSTNAMELEN]; 656 struct netent *np = 0; 657 in_addr_t i; 658 659 /* It is ok to supply host address. */ 660 in &= mask; 661 662 i = ntohl(in); 663 if (!numeric_addr && i) { 664 np = getnetbyaddr(i >> NSHIFT(ntohl(mask)), AF_INET); 665 if (np != NULL) { 666 cp = np->n_name; 667 trimdomain(cp, strlen(cp)); 668 } 669 } 670 if (cp != NULL) { 671 strlcpy(line, cp, sizeof(line)); 672 } else { 673 inet_ntop(AF_INET, &in, line, sizeof(line) - 1); 674 } 675 domask(line + strlen(line), i, ntohl(mask)); 676 return (line); 677 } 678 679 #undef NSHIFT 680 681 #ifdef INET6 682 void 683 in6_fillscopeid(struct sockaddr_in6 *sa6) 684 { 685 #if defined(__KAME__) 686 /* 687 * XXX: This is a special workaround for KAME kernels. 688 * sin6_scope_id field of SA should be set in the future. 689 */ 690 if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) || 691 IN6_IS_ADDR_MC_NODELOCAL(&sa6->sin6_addr) || 692 IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr)) { 693 if (sa6->sin6_scope_id == 0) 694 sa6->sin6_scope_id = 695 ntohs(*(u_int16_t *)&sa6->sin6_addr.s6_addr[2]); 696 sa6->sin6_addr.s6_addr[2] = sa6->sin6_addr.s6_addr[3] = 0; 697 } 698 #endif 699 } 700 701 const char * 702 netname6(struct sockaddr_in6 *sa6, struct in6_addr *mask) 703 { 704 static char line[MAXHOSTNAMELEN]; 705 u_char *p = (u_char *)mask; 706 u_char *lim; 707 int masklen, illegal = 0, flag = 0; 708 709 if (mask) { 710 for (masklen = 0, lim = p + 16; p < lim; p++) { 711 switch (*p) { 712 case 0xff: 713 masklen += 8; 714 break; 715 case 0xfe: 716 masklen += 7; 717 break; 718 case 0xfc: 719 masklen += 6; 720 break; 721 case 0xf8: 722 masklen += 5; 723 break; 724 case 0xf0: 725 masklen += 4; 726 break; 727 case 0xe0: 728 masklen += 3; 729 break; 730 case 0xc0: 731 masklen += 2; 732 break; 733 case 0x80: 734 masklen += 1; 735 break; 736 case 0x00: 737 break; 738 default: 739 illegal ++; 740 break; 741 } 742 } 743 if (illegal) 744 xo_error("illegal prefixlen\n"); 745 } 746 else 747 masklen = 128; 748 749 if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr)) 750 return("default"); 751 752 if (numeric_addr) 753 flag |= NI_NUMERICHOST; 754 getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line), 755 NULL, 0, flag); 756 757 if (numeric_addr) 758 sprintf(&line[strlen(line)], "/%d", masklen); 759 760 return line; 761 } 762 763 char * 764 routename6(struct sockaddr_in6 *sa6) 765 { 766 static char line[MAXHOSTNAMELEN]; 767 int flag = 0; 768 /* use local variable for safety */ 769 struct sockaddr_in6 sa6_local; 770 771 sa6_local.sin6_family = AF_INET6; 772 sa6_local.sin6_len = sizeof(sa6_local); 773 sa6_local.sin6_addr = sa6->sin6_addr; 774 sa6_local.sin6_scope_id = sa6->sin6_scope_id; 775 776 if (numeric_addr) 777 flag |= NI_NUMERICHOST; 778 779 getnameinfo((struct sockaddr *)&sa6_local, sa6_local.sin6_len, 780 line, sizeof(line), NULL, 0, flag); 781 782 return line; 783 } 784 #endif /*INET6*/ 785 786 /* 787 * Print routing statistics 788 */ 789 void 790 rt_stats(void) 791 { 792 struct rtstat rtstat; 793 u_long rtsaddr, rttaddr; 794 int rttrash; 795 796 kresolve_list(rl); 797 798 if ((rtsaddr = rl[N_RTSTAT].n_value) == 0) { 799 xo_emit("{W:rtstat: symbol not in namelist}\n"); 800 return; 801 } 802 if ((rttaddr = rl[N_RTTRASH].n_value) == 0) { 803 xo_emit("{W:rttrash: symbol not in namelist}\n"); 804 return; 805 } 806 kread(rtsaddr, (char *)&rtstat, sizeof (rtstat)); 807 kread(rttaddr, (char *)&rttrash, sizeof (rttrash)); 808 xo_emit("{T:routing}:\n"); 809 810 #define p(f, m) if (rtstat.f || sflag <= 1) \ 811 xo_emit(m, rtstat.f, plural(rtstat.f)) 812 813 p(rts_badredirect, "\t{:bad-redirects/%hu} " 814 "{N:/bad routing redirect%s}\n"); 815 p(rts_dynamic, "\t{:dynamically-created/%hu} " 816 "{N:/dynamically created route%s}\n"); 817 p(rts_newgateway, "\t{:new-gateways/%hu} " 818 "{N:/new gateway%s due to redirects}\n"); 819 p(rts_unreach, "\t{:unreachable-destination/%hu} " 820 "{N:/destination%s found unreachable}\n"); 821 p(rts_wildcard, "\t{:wildcard-uses/%hu} " 822 "{N:/use%s of a wildcard route}\n"); 823 #undef p 824 825 if (rttrash || sflag <= 1) 826 xo_emit("\t{:unused-but-not-freed/%u} " 827 "{N:/route%s not in table but not freed}\n", 828 rttrash, plural(rttrash)); 829 } 830