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 <stdbool.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 #include "nl_defs.h" 71 72 /* 73 * Definitions for showing gateway flags. 74 */ 75 static struct bits { 76 u_long b_mask; 77 char b_val; 78 const char *b_name; 79 } bits[] = { 80 { RTF_UP, 'U', "up" }, 81 { RTF_GATEWAY, 'G', "gateway" }, 82 { RTF_HOST, 'H', "host" }, 83 { RTF_REJECT, 'R', "reject" }, 84 { RTF_DYNAMIC, 'D', "dynamic" }, 85 { RTF_MODIFIED, 'M', "modified" }, 86 { RTF_DONE, 'd', "done" }, /* Completed -- for routing msgs only */ 87 { RTF_XRESOLVE, 'X', "xresolve" }, 88 { RTF_STATIC, 'S', "static" }, 89 { RTF_PROTO1, '1', "proto1" }, 90 { RTF_PROTO2, '2', "proto2" }, 91 { RTF_PROTO3, '3', "proto3" }, 92 { RTF_BLACKHOLE,'B', "blackhole" }, 93 { RTF_BROADCAST,'b', "broadcast" }, 94 #ifdef RTF_LLINFO 95 { RTF_LLINFO, 'L', "llinfo" }, 96 #endif 97 { 0 , 0, NULL } 98 }; 99 100 struct ifmap_entry { 101 char ifname[IFNAMSIZ]; 102 }; 103 static struct ifmap_entry *ifmap; 104 static int ifmap_size; 105 static struct timespec uptime; 106 107 static const char *netname4(in_addr_t, in_addr_t); 108 #ifdef INET6 109 static const char *netname6(struct sockaddr_in6 *, struct sockaddr_in6 *); 110 #endif 111 static void p_rtable_sysctl(int, int); 112 static void p_rtentry_sysctl(const char *name, struct rt_msghdr *); 113 static int p_sockaddr(const char *name, struct sockaddr *, struct sockaddr *, 114 int, int); 115 static const char *fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, 116 int flags); 117 static void p_flags(int, const char *); 118 static const char *fmt_flags(int f); 119 static void domask(char *, size_t, u_long); 120 121 122 /* 123 * Print routing tables. 124 */ 125 void 126 routepr(int fibnum, int af) 127 { 128 size_t intsize; 129 int numfibs; 130 131 if (live == 0) 132 return; 133 134 intsize = sizeof(int); 135 if (fibnum == -1 && 136 sysctlbyname("net.my_fibnum", &fibnum, &intsize, NULL, 0) == -1) 137 fibnum = 0; 138 if (sysctlbyname("net.fibs", &numfibs, &intsize, NULL, 0) == -1) 139 numfibs = 1; 140 if (fibnum < 0 || fibnum > numfibs - 1) 141 errx(EX_USAGE, "%d: invalid fib", fibnum); 142 /* 143 * Since kernel & userland use different timebase 144 * (time_uptime vs time_second) and we are reading kernel memory 145 * directly we should do rt_expire --> expire_time conversion. 146 */ 147 if (clock_gettime(CLOCK_UPTIME, &uptime) < 0) 148 err(EX_OSERR, "clock_gettime() failed"); 149 150 xo_open_container("route-information"); 151 xo_emit("{T:Routing tables}"); 152 if (fibnum) 153 xo_emit(" ({L:fib}: {:fib/%d})", fibnum); 154 xo_emit("\n"); 155 p_rtable_sysctl(fibnum, af); 156 xo_close_container("route-information"); 157 } 158 159 160 /* 161 * Print address family header before a section of the routing table. 162 */ 163 void 164 pr_family(int af1) 165 { 166 const char *afname; 167 168 switch (af1) { 169 case AF_INET: 170 afname = "Internet"; 171 break; 172 #ifdef INET6 173 case AF_INET6: 174 afname = "Internet6"; 175 break; 176 #endif /*INET6*/ 177 case AF_ISO: 178 afname = "ISO"; 179 break; 180 case AF_CCITT: 181 afname = "X.25"; 182 break; 183 case AF_NETGRAPH: 184 afname = "Netgraph"; 185 break; 186 default: 187 afname = NULL; 188 break; 189 } 190 if (afname) 191 xo_emit("\n{k:address-family/%s}:\n", afname); 192 else 193 xo_emit("\n{L:Protocol Family} {k:address-family/%d}:\n", af1); 194 } 195 196 /* column widths; each followed by one space */ 197 #ifndef INET6 198 #define WID_DST_DEFAULT(af) 18 /* width of destination column */ 199 #define WID_GW_DEFAULT(af) 18 /* width of gateway column */ 200 #define WID_IF_DEFAULT(af) (Wflag ? 10 : 8) /* width of netif column */ 201 #else 202 #define WID_DST_DEFAULT(af) \ 203 ((af) == AF_INET6 ? (numeric_addr ? 33: 18) : 18) 204 #define WID_GW_DEFAULT(af) \ 205 ((af) == AF_INET6 ? (numeric_addr ? 29 : 18) : 18) 206 #define WID_IF_DEFAULT(af) ((af) == AF_INET6 ? 8 : (Wflag ? 10 : 8)) 207 #endif /*INET6*/ 208 209 static int wid_dst; 210 static int wid_gw; 211 static int wid_flags; 212 static int wid_pksent; 213 static int wid_mtu; 214 static int wid_if; 215 static int wid_expire; 216 217 /* 218 * Print header for routing table columns. 219 */ 220 static void 221 pr_rthdr(int af1 __unused) 222 { 223 224 if (Wflag) { 225 xo_emit("{T:/%-*.*s} {T:/%-*.*s} {T:/%-*.*s} {T:/%*.*s} " 226 "{T:/%*.*s} {T:/%*.*s} {T:/%*s}\n", 227 wid_dst, wid_dst, "Destination", 228 wid_gw, wid_gw, "Gateway", 229 wid_flags, wid_flags, "Flags", 230 wid_pksent, wid_pksent, "Use", 231 wid_mtu, wid_mtu, "Mtu", 232 wid_if, wid_if, "Netif", 233 wid_expire, "Expire"); 234 } else { 235 xo_emit("{T:/%-*.*s} {T:/%-*.*s} {T:/%-*.*s} {T:/%*.*s} " 236 "{T:/%*s}\n", 237 wid_dst, wid_dst, "Destination", 238 wid_gw, wid_gw, "Gateway", 239 wid_flags, wid_flags, "Flags", 240 wid_if, wid_if, "Netif", 241 wid_expire, "Expire"); 242 } 243 } 244 245 static void 246 p_rtable_sysctl(int fibnum, int af) 247 { 248 size_t needed; 249 int mib[7]; 250 char *buf, *next, *lim; 251 struct rt_msghdr *rtm; 252 struct sockaddr *sa; 253 int fam = AF_UNSPEC, ifindex = 0, size; 254 int need_table_close = false; 255 256 struct ifaddrs *ifap, *ifa; 257 struct sockaddr_dl *sdl; 258 259 /* 260 * Retrieve interface list at first 261 * since we need #ifindex -> if_xname match 262 */ 263 if (getifaddrs(&ifap) != 0) 264 err(EX_OSERR, "getifaddrs"); 265 266 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 267 268 if (ifa->ifa_addr->sa_family != AF_LINK) 269 continue; 270 271 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 272 ifindex = sdl->sdl_index; 273 274 if (ifindex >= ifmap_size) { 275 size = roundup(ifindex + 1, 32) * 276 sizeof(struct ifmap_entry); 277 if ((ifmap = realloc(ifmap, size)) == NULL) 278 errx(2, "realloc(%d) failed", size); 279 memset(&ifmap[ifmap_size], 0, 280 size - ifmap_size * 281 sizeof(struct ifmap_entry)); 282 283 ifmap_size = roundup(ifindex + 1, 32); 284 } 285 286 if (*ifmap[ifindex].ifname != '\0') 287 continue; 288 289 strlcpy(ifmap[ifindex].ifname, ifa->ifa_name, IFNAMSIZ); 290 } 291 292 freeifaddrs(ifap); 293 294 mib[0] = CTL_NET; 295 mib[1] = PF_ROUTE; 296 mib[2] = 0; 297 mib[3] = af; 298 mib[4] = NET_RT_DUMP; 299 mib[5] = 0; 300 mib[6] = fibnum; 301 if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0) 302 err(EX_OSERR, "sysctl: net.route.0.%d.dump.%d estimate", af, 303 fibnum); 304 if ((buf = malloc(needed)) == NULL) 305 errx(2, "malloc(%lu)", (unsigned long)needed); 306 if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) 307 err(1, "sysctl: net.route.0.%d.dump.%d", af, fibnum); 308 lim = buf + needed; 309 xo_open_container("route-table"); 310 xo_open_list("rt-family"); 311 for (next = buf; next < lim; next += rtm->rtm_msglen) { 312 rtm = (struct rt_msghdr *)next; 313 if (rtm->rtm_version != RTM_VERSION) 314 continue; 315 /* 316 * Peek inside header to determine AF 317 */ 318 sa = (struct sockaddr *)(rtm + 1); 319 /* Only print family first time. */ 320 if (fam != sa->sa_family) { 321 if (need_table_close) { 322 xo_close_list("rt-entry"); 323 xo_close_instance("rt-family"); 324 } 325 need_table_close = true; 326 327 fam = sa->sa_family; 328 wid_dst = WID_DST_DEFAULT(fam); 329 wid_gw = WID_GW_DEFAULT(fam); 330 wid_flags = 6; 331 wid_pksent = 8; 332 wid_mtu = 6; 333 wid_if = WID_IF_DEFAULT(fam); 334 wid_expire = 6; 335 xo_open_instance("rt-family"); 336 pr_family(fam); 337 xo_open_list("rt-entry"); 338 339 pr_rthdr(fam); 340 } 341 p_rtentry_sysctl("rt-entry", rtm); 342 } 343 if (need_table_close) { 344 xo_close_list("rt-entry"); 345 xo_close_instance("rt-family"); 346 } 347 xo_close_list("rt-family"); 348 xo_close_container("route-table"); 349 free(buf); 350 } 351 352 static void 353 p_rtentry_sysctl(const char *name, struct rt_msghdr *rtm) 354 { 355 struct sockaddr *sa, *addr[RTAX_MAX]; 356 char buffer[128]; 357 char prettyname[128]; 358 int i, protrusion; 359 360 xo_open_instance(name); 361 sa = (struct sockaddr *)(rtm + 1); 362 for (i = 0; i < RTAX_MAX; i++) { 363 if (rtm->rtm_addrs & (1 << i)) 364 addr[i] = sa; 365 sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa)); 366 } 367 368 protrusion = p_sockaddr("destination", addr[RTAX_DST], 369 addr[RTAX_NETMASK], 370 rtm->rtm_flags, wid_dst); 371 protrusion = p_sockaddr("gateway", addr[RTAX_GATEWAY], NULL, RTF_HOST, 372 wid_gw - protrusion); 373 snprintf(buffer, sizeof(buffer), "{[:-%d}{:flags/%%s}{]:} ", 374 wid_flags - protrusion); 375 p_flags(rtm->rtm_flags, buffer); 376 if (Wflag) { 377 xo_emit("{t:use/%*lu} ", wid_pksent, rtm->rtm_rmx.rmx_pksent); 378 379 if (rtm->rtm_rmx.rmx_mtu != 0) 380 xo_emit("{t:mtu/%*lu} ", wid_mtu, rtm->rtm_rmx.rmx_mtu); 381 else 382 xo_emit("{P:/%*s} ", wid_mtu, ""); 383 } 384 385 memset(prettyname, 0, sizeof(prettyname)); 386 if (rtm->rtm_index < ifmap_size) { 387 strlcpy(prettyname, ifmap[rtm->rtm_index].ifname, 388 sizeof(prettyname)); 389 if (*prettyname == '\0') 390 strlcpy(prettyname, "---", sizeof(prettyname)); 391 } 392 393 if (Wflag) 394 xo_emit("{t:interface-name/%*s}", wid_if, prettyname); 395 else 396 xo_emit("{t:interface-name/%*.*s}", wid_if, wid_if, 397 prettyname); 398 if (rtm->rtm_rmx.rmx_expire) { 399 time_t expire_time; 400 401 if ((expire_time = rtm->rtm_rmx.rmx_expire - uptime.tv_sec) > 0) 402 xo_emit(" {:expire-time/%*d}", wid_expire, 403 (int)expire_time); 404 } 405 406 xo_emit("\n"); 407 xo_close_instance(name); 408 } 409 410 static int 411 p_sockaddr(const char *name, struct sockaddr *sa, struct sockaddr *mask, 412 int flags, int width) 413 { 414 const char *cp; 415 char buf[128]; 416 int protrusion; 417 418 cp = fmt_sockaddr(sa, mask, flags); 419 420 if (width < 0) { 421 snprintf(buf, sizeof(buf), "{:%s/%%s} ", name); 422 xo_emit(buf, cp); 423 protrusion = 0; 424 } else { 425 if (Wflag != 0 || numeric_addr) { 426 snprintf(buf, sizeof(buf), "{[:%d}{:%s/%%s}{]:} ", 427 -width, name); 428 xo_emit(buf, cp); 429 protrusion = strlen(cp) - width; 430 if (protrusion < 0) 431 protrusion = 0; 432 } else { 433 snprintf(buf, sizeof(buf), "{[:%d}{:%s/%%-.*s}{]:} ", 434 -width, name); 435 xo_emit(buf, width, cp); 436 protrusion = 0; 437 } 438 } 439 return (protrusion); 440 } 441 442 static const char * 443 fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags) 444 { 445 static char buf[128]; 446 const char *cp; 447 448 if (sa == NULL) 449 return ("null"); 450 451 switch(sa->sa_family) { 452 #ifdef INET6 453 case AF_INET6: 454 /* 455 * The sa6->sin6_scope_id must be filled here because 456 * this sockaddr is extracted from kmem(4) directly 457 * and has KAME-specific embedded scope id in 458 * sa6->sin6_addr.s6_addr[2]. 459 */ 460 in6_fillscopeid(satosin6(sa)); 461 /* FALLTHROUGH */ 462 #endif /*INET6*/ 463 case AF_INET: 464 if (flags & RTF_HOST) 465 cp = routename(sa, numeric_addr); 466 else if (mask) 467 cp = netname(sa, mask); 468 else 469 cp = netname(sa, NULL); 470 break; 471 case AF_NETGRAPH: 472 { 473 strlcpy(buf, ((struct sockaddr_ng *)sa)->sg_data, 474 sizeof(buf)); 475 cp = buf; 476 break; 477 } 478 case AF_LINK: 479 { 480 #if 0 481 struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; 482 483 /* Interface route. */ 484 if (sdl->sdl_nlen) 485 cp = sdl->sdl_data; 486 else 487 #endif 488 cp = routename(sa, 1); 489 break; 490 } 491 default: 492 { 493 u_char *s = (u_char *)sa->sa_data, *slim; 494 char *cq, *cqlim; 495 496 cq = buf; 497 slim = sa->sa_len + (u_char *) sa; 498 cqlim = cq + sizeof(buf) - sizeof(" ffff"); 499 snprintf(cq, sizeof(buf), "(%d)", sa->sa_family); 500 cq += strlen(cq); 501 while (s < slim && cq < cqlim) { 502 snprintf(cq, sizeof(" ff"), " %02x", *s++); 503 cq += strlen(cq); 504 if (s < slim) { 505 snprintf(cq, sizeof("ff"), "%02x", *s++); 506 cq += strlen(cq); 507 } 508 } 509 cp = buf; 510 } 511 } 512 513 return (cp); 514 } 515 516 static void 517 p_flags(int f, const char *format) 518 { 519 struct bits *p; 520 521 xo_emit(format, fmt_flags(f)); 522 523 xo_open_list("flags_pretty"); 524 for (p = bits; p->b_mask; p++) 525 if (p->b_mask & f) 526 xo_emit("{le:flags_pretty/%s}", p->b_name); 527 xo_close_list("flags_pretty"); 528 } 529 530 static const char * 531 fmt_flags(int f) 532 { 533 static char name[33]; 534 char *flags; 535 struct bits *p = bits; 536 537 for (flags = name; p->b_mask; p++) 538 if (p->b_mask & f) 539 *flags++ = p->b_val; 540 *flags = '\0'; 541 return (name); 542 } 543 544 char * 545 routename(struct sockaddr *sa, int flags) 546 { 547 static char line[NI_MAXHOST]; 548 int error, f; 549 550 f = (flags) ? NI_NUMERICHOST : 0; 551 error = getnameinfo(sa, sa->sa_len, line, sizeof(line), 552 NULL, 0, f); 553 if (error) { 554 const void *src; 555 switch (sa->sa_family) { 556 #ifdef INET 557 case AF_INET: 558 src = &satosin(sa)->sin_addr; 559 break; 560 #endif /* INET */ 561 #ifdef INET6 562 case AF_INET6: 563 src = &satosin6(sa)->sin6_addr; 564 break; 565 #endif /* INET6 */ 566 default: 567 return(line); 568 } 569 inet_ntop(sa->sa_family, src, line, sizeof(line) - 1); 570 return (line); 571 } 572 trimdomain(line, strlen(line)); 573 574 return (line); 575 } 576 577 #define NSHIFT(m) ( \ 578 (m) == IN_CLASSA_NET ? IN_CLASSA_NSHIFT : \ 579 (m) == IN_CLASSB_NET ? IN_CLASSB_NSHIFT : \ 580 (m) == IN_CLASSC_NET ? IN_CLASSC_NSHIFT : \ 581 0) 582 583 static void 584 domask(char *dst, size_t buflen, u_long mask) 585 { 586 int b, i; 587 588 if (mask == 0) { 589 *dst = '\0'; 590 return; 591 } 592 i = 0; 593 for (b = 0; b < 32; b++) 594 if (mask & (1 << b)) { 595 int bb; 596 597 i = b; 598 for (bb = b+1; bb < 32; bb++) 599 if (!(mask & (1 << bb))) { 600 i = -1; /* noncontig */ 601 break; 602 } 603 break; 604 } 605 if (i == -1) 606 snprintf(dst, buflen, "&0x%lx", mask); 607 else 608 snprintf(dst, buflen, "/%d", 32-i); 609 } 610 611 /* 612 * Return the name of the network whose address is given. 613 */ 614 const char * 615 netname(struct sockaddr *sa, struct sockaddr *mask) 616 { 617 switch (sa->sa_family) { 618 case AF_INET: 619 if (mask != NULL) 620 return (netname4(satosin(sa)->sin_addr.s_addr, 621 satosin(mask)->sin_addr.s_addr)); 622 else 623 return (netname4(satosin(sa)->sin_addr.s_addr, 624 INADDR_ANY)); 625 break; 626 #ifdef INET6 627 case AF_INET6: 628 return (netname6(satosin6(sa), satosin6(mask))); 629 #endif /* INET6 */ 630 default: 631 return (NULL); 632 } 633 } 634 635 static const char * 636 netname4(in_addr_t in, in_addr_t mask) 637 { 638 char *cp = 0; 639 static char line[MAXHOSTNAMELEN + sizeof("&0xffffffff")]; 640 char nline[INET_ADDRSTRLEN]; 641 struct netent *np = 0; 642 in_addr_t i; 643 644 if (in == INADDR_ANY && mask == 0) { 645 strlcpy(line, "default", sizeof(line)); 646 return (line); 647 } 648 649 /* It is ok to supply host address. */ 650 in &= mask; 651 652 i = ntohl(in); 653 if (!numeric_addr && i) { 654 np = getnetbyaddr(i >> NSHIFT(ntohl(mask)), AF_INET); 655 if (np != NULL) { 656 cp = np->n_name; 657 trimdomain(cp, strlen(cp)); 658 } 659 } 660 if (cp != NULL) 661 strlcpy(line, cp, sizeof(line)); 662 else { 663 inet_ntop(AF_INET, &in, nline, sizeof(nline)); 664 strlcpy(line, nline, sizeof(line)); 665 domask(line + strlen(line), sizeof(line) - strlen(line), ntohl(mask)); 666 } 667 668 return (line); 669 } 670 671 #undef NSHIFT 672 673 #ifdef INET6 674 void 675 in6_fillscopeid(struct sockaddr_in6 *sa6) 676 { 677 #if defined(__KAME__) 678 /* 679 * XXX: This is a special workaround for KAME kernels. 680 * sin6_scope_id field of SA should be set in the future. 681 */ 682 if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) || 683 IN6_IS_ADDR_MC_NODELOCAL(&sa6->sin6_addr) || 684 IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr)) { 685 if (sa6->sin6_scope_id == 0) 686 sa6->sin6_scope_id = 687 ntohs(*(u_int16_t *)&sa6->sin6_addr.s6_addr[2]); 688 sa6->sin6_addr.s6_addr[2] = sa6->sin6_addr.s6_addr[3] = 0; 689 } 690 #endif 691 } 692 693 /* Mask to length table. To check an invalid value, (length + 1) is used. */ 694 static const u_char masktolen[256] = { 695 [0xff] = 8 + 1, 696 [0xfe] = 7 + 1, 697 [0xfc] = 6 + 1, 698 [0xf8] = 5 + 1, 699 [0xf0] = 4 + 1, 700 [0xe0] = 3 + 1, 701 [0xc0] = 2 + 1, 702 [0x80] = 1 + 1, 703 [0x00] = 0 + 1, 704 }; 705 706 static const char * 707 netname6(struct sockaddr_in6 *sa6, struct sockaddr_in6 *mask) 708 { 709 static char line[NI_MAXHOST + sizeof("/xxx") - 1]; 710 struct sockaddr_in6 addr; 711 char nline[NI_MAXHOST]; 712 char maskbuf[sizeof("/xxx")]; 713 u_char *p, *lim; 714 u_char masklen; 715 int i; 716 bool illegal = false; 717 718 if (mask) { 719 p = (u_char *)&mask->sin6_addr; 720 for (masklen = 0, lim = p + 16; p < lim; p++) { 721 if (masktolen[*p] > 0) { 722 /* -1 is required. */ 723 masklen += (masktolen[*p] - 1); 724 } else 725 illegal = true; 726 } 727 if (illegal) 728 xo_error("illegal prefixlen\n"); 729 730 memcpy(&addr, sa6, sizeof(addr)); 731 for (i = 0; i < 16; ++i) 732 addr.sin6_addr.s6_addr[i] &= 733 mask->sin6_addr.s6_addr[i]; 734 sa6 = &addr; 735 } 736 else 737 masklen = 128; 738 739 if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr)) 740 return("default"); 741 742 getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, nline, sizeof(nline), 743 NULL, 0, NI_NUMERICHOST); 744 if (numeric_addr) 745 strlcpy(line, nline, sizeof(line)); 746 else 747 getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, 748 sizeof(line), NULL, 0, 0); 749 if (numeric_addr || strcmp(line, nline) == 0) { 750 snprintf(maskbuf, sizeof(maskbuf), "/%d", masklen); 751 strlcat(line, maskbuf, sizeof(line)); 752 } 753 754 return (line); 755 } 756 #endif /*INET6*/ 757 758 /* 759 * Print routing statistics 760 */ 761 void 762 rt_stats(void) 763 { 764 struct rtstat rtstat; 765 u_long rtsaddr, rttaddr; 766 int rttrash; 767 768 if ((rtsaddr = nl[N_RTSTAT].n_value) == 0) { 769 xo_emit("{W:rtstat: symbol not in namelist}\n"); 770 return; 771 } 772 if ((rttaddr = nl[N_RTTRASH].n_value) == 0) { 773 xo_emit("{W:rttrash: symbol not in namelist}\n"); 774 return; 775 } 776 kread(rtsaddr, (char *)&rtstat, sizeof (rtstat)); 777 kread(rttaddr, (char *)&rttrash, sizeof (rttrash)); 778 xo_emit("{T:routing}:\n"); 779 780 #define p(f, m) if (rtstat.f || sflag <= 1) \ 781 xo_emit(m, rtstat.f, plural(rtstat.f)) 782 783 p(rts_badredirect, "\t{:bad-redirects/%hu} " 784 "{N:/bad routing redirect%s}\n"); 785 p(rts_dynamic, "\t{:dynamically-created/%hu} " 786 "{N:/dynamically created route%s}\n"); 787 p(rts_newgateway, "\t{:new-gateways/%hu} " 788 "{N:/new gateway%s due to redirects}\n"); 789 p(rts_unreach, "\t{:unreachable-destination/%hu} " 790 "{N:/destination%s found unreachable}\n"); 791 p(rts_wildcard, "\t{:wildcard-uses/%hu} " 792 "{N:/use%s of a wildcard route}\n"); 793 #undef p 794 795 if (rttrash || sflag <= 1) 796 xo_emit("\t{:unused-but-not-freed/%u} " 797 "{N:/route%s not in table but not freed}\n", 798 rttrash, plural(rttrash)); 799 } 800