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/time.h> 44 45 #include <net/ethernet.h> 46 #include <net/if.h> 47 #include <net/if_var.h> 48 #include <net/if_dl.h> 49 #include <net/if_types.h> 50 #include <net/radix.h> 51 #include <net/route.h> 52 53 #include <netinet/in.h> 54 #include <netipx/ipx.h> 55 #include <netatalk/at.h> 56 #include <netgraph/ng_socket.h> 57 58 #include <sys/sysctl.h> 59 60 #include <arpa/inet.h> 61 #include <ifaddrs.h> 62 #include <libutil.h> 63 #include <netdb.h> 64 #include <nlist.h> 65 #include <stdint.h> 66 #include <stdio.h> 67 #include <stdlib.h> 68 #include <string.h> 69 #include <sysexits.h> 70 #include <unistd.h> 71 #include <err.h> 72 #include "netstat.h" 73 74 #define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d))) 75 76 /* 77 * Definitions for showing gateway flags. 78 */ 79 struct bits { 80 u_long b_mask; 81 char b_val; 82 } bits[] = { 83 { RTF_UP, 'U' }, 84 { RTF_GATEWAY, 'G' }, 85 { RTF_HOST, 'H' }, 86 { RTF_REJECT, 'R' }, 87 { RTF_DYNAMIC, 'D' }, 88 { RTF_MODIFIED, 'M' }, 89 { RTF_DONE, 'd' }, /* Completed -- for routing messages only */ 90 { RTF_XRESOLVE, 'X' }, 91 { RTF_STATIC, 'S' }, 92 { RTF_PROTO1, '1' }, 93 { RTF_PROTO2, '2' }, 94 { RTF_PRCLONING,'c' }, 95 { RTF_PROTO3, '3' }, 96 { RTF_BLACKHOLE,'B' }, 97 { RTF_BROADCAST,'b' }, 98 #ifdef RTF_LLINFO 99 { RTF_LLINFO, 'L' }, 100 #endif 101 #ifdef RTF_WASCLONED 102 { RTF_WASCLONED,'W' }, 103 #endif 104 #ifdef RTF_CLONING 105 { RTF_CLONING, 'C' }, 106 #endif 107 { 0 , 0 } 108 }; 109 110 /* 111 * kvm(3) bindings for every needed symbol 112 */ 113 static struct nlist rl[] = { 114 #define N_RTSTAT 0 115 { .n_name = "_rtstat" }, 116 #define N_RTREE 1 117 { .n_name = "_rt_tables"}, 118 #define N_RTTRASH 2 119 { .n_name = "_rttrash" }, 120 { .n_name = NULL }, 121 }; 122 123 typedef union { 124 long dummy; /* Helps align structure. */ 125 struct sockaddr u_sa; 126 u_short u_data[128]; 127 } sa_u; 128 129 static sa_u pt_u; 130 131 struct ifmap_entry { 132 char ifname[IFNAMSIZ]; 133 }; 134 135 static struct ifmap_entry *ifmap; 136 static int ifmap_size; 137 138 int do_rtent = 0; 139 struct rtentry rtentry; 140 struct radix_node rnode; 141 struct radix_mask rmask; 142 143 int NewTree = 1; 144 145 struct timespec uptime; 146 147 static struct sockaddr *kgetsa(struct sockaddr *); 148 static void size_cols(int ef, struct radix_node *rn); 149 static void size_cols_tree(struct radix_node *rn); 150 static void size_cols_rtentry(struct rtentry *rt); 151 static void p_rtnode_kvm(void); 152 static void p_rtable_sysctl(int, int); 153 static void p_rtable_kvm(int, int ); 154 static void p_rtree_kvm(struct radix_node *); 155 static void p_rtentry_sysctl(struct rt_msghdr *); 156 static void p_sockaddr(struct sockaddr *, struct sockaddr *, int, int); 157 static const char *fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, 158 int flags); 159 static void p_flags(int, const char *); 160 static const char *fmt_flags(int f); 161 static void p_rtentry_kvm(struct rtentry *); 162 static void domask(char *, in_addr_t, u_long); 163 164 /* 165 * Print routing tables. 166 */ 167 void 168 routepr(int fibnum, int af) 169 { 170 size_t intsize; 171 int numfibs; 172 173 intsize = sizeof(int); 174 if (fibnum == -1 && 175 sysctlbyname("net.my_fibnum", &fibnum, &intsize, NULL, 0) == -1) 176 fibnum = 0; 177 if (sysctlbyname("net.fibs", &numfibs, &intsize, NULL, 0) == -1) 178 numfibs = 1; 179 if (fibnum < 0 || fibnum > numfibs - 1) 180 errx(EX_USAGE, "%d: invalid fib", fibnum); 181 /* 182 * Since kernel & userland use different timebase 183 * (time_uptime vs time_second) and we are reading kernel memory 184 * directly we should do rt_expire --> expire_time conversion. 185 */ 186 if (clock_gettime(CLOCK_UPTIME, &uptime) < 0) 187 err(EX_OSERR, "clock_gettime() failed"); 188 189 printf("Routing tables"); 190 if (fibnum) 191 printf(" (fib: %d)", fibnum); 192 printf("\n"); 193 194 if (Aflag == 0 && live != 0 && NewTree) 195 p_rtable_sysctl(fibnum, af); 196 else 197 p_rtable_kvm(fibnum, af); 198 } 199 200 201 /* 202 * Print address family header before a section of the routing table. 203 */ 204 void 205 pr_family(int af1) 206 { 207 const char *afname; 208 209 switch (af1) { 210 case AF_INET: 211 afname = "Internet"; 212 break; 213 #ifdef INET6 214 case AF_INET6: 215 afname = "Internet6"; 216 break; 217 #endif /*INET6*/ 218 case AF_IPX: 219 afname = "IPX"; 220 break; 221 case AF_ISO: 222 afname = "ISO"; 223 break; 224 case AF_APPLETALK: 225 afname = "AppleTalk"; 226 break; 227 case AF_CCITT: 228 afname = "X.25"; 229 break; 230 case AF_NETGRAPH: 231 afname = "Netgraph"; 232 break; 233 default: 234 afname = NULL; 235 break; 236 } 237 if (afname) 238 printf("\n%s:\n", afname); 239 else 240 printf("\nProtocol Family %d:\n", af1); 241 } 242 243 /* column widths; each followed by one space */ 244 #ifndef INET6 245 #define WID_DST_DEFAULT(af) 18 /* width of destination column */ 246 #define WID_GW_DEFAULT(af) 18 /* width of gateway column */ 247 #define WID_IF_DEFAULT(af) (Wflag ? 8 : 6) /* width of netif column */ 248 #else 249 #define WID_DST_DEFAULT(af) \ 250 ((af) == AF_INET6 ? (numeric_addr ? 33: 18) : 18) 251 #define WID_GW_DEFAULT(af) \ 252 ((af) == AF_INET6 ? (numeric_addr ? 29 : 18) : 18) 253 #define WID_IF_DEFAULT(af) ((af) == AF_INET6 ? 8 : (Wflag ? 8 : 6)) 254 #endif /*INET6*/ 255 256 static int wid_dst; 257 static int wid_gw; 258 static int wid_flags; 259 static int wid_pksent; 260 static int wid_mtu; 261 static int wid_if; 262 static int wid_expire; 263 264 static void 265 size_cols(int ef, struct radix_node *rn) 266 { 267 wid_dst = WID_DST_DEFAULT(ef); 268 wid_gw = WID_GW_DEFAULT(ef); 269 wid_flags = 6; 270 wid_pksent = 8; 271 wid_mtu = 6; 272 wid_if = WID_IF_DEFAULT(ef); 273 wid_expire = 6; 274 275 if (Wflag && rn != NULL) 276 size_cols_tree(rn); 277 } 278 279 static void 280 size_cols_tree(struct radix_node *rn) 281 { 282 again: 283 if (kget(rn, rnode) != 0) 284 return; 285 if (!(rnode.rn_flags & RNF_ACTIVE)) 286 return; 287 if (rnode.rn_bit < 0) { 288 if ((rnode.rn_flags & RNF_ROOT) == 0) { 289 if (kget(rn, rtentry) != 0) 290 return; 291 size_cols_rtentry(&rtentry); 292 } 293 if ((rn = rnode.rn_dupedkey)) 294 goto again; 295 } else { 296 rn = rnode.rn_right; 297 size_cols_tree(rnode.rn_left); 298 size_cols_tree(rn); 299 } 300 } 301 302 static void 303 size_cols_rtentry(struct rtentry *rt) 304 { 305 static struct ifnet ifnet, *lastif; 306 static char buffer[100]; 307 const char *bp; 308 struct sockaddr *sa; 309 sa_u addr, mask; 310 int len; 311 312 bzero(&addr, sizeof(addr)); 313 if ((sa = kgetsa(rt_key(rt)))) 314 bcopy(sa, &addr, sa->sa_len); 315 bzero(&mask, sizeof(mask)); 316 if (rt_mask(rt) && (sa = kgetsa(rt_mask(rt)))) 317 bcopy(sa, &mask, sa->sa_len); 318 bp = fmt_sockaddr(&addr.u_sa, &mask.u_sa, rt->rt_flags); 319 len = strlen(bp); 320 wid_dst = MAX(len, wid_dst); 321 322 bp = fmt_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST); 323 len = strlen(bp); 324 wid_gw = MAX(len, wid_gw); 325 326 bp = fmt_flags(rt->rt_flags); 327 len = strlen(bp); 328 wid_flags = MAX(len, wid_flags); 329 330 if (Wflag) { 331 len = snprintf(buffer, sizeof(buffer), "%lu", 332 kread_counter((u_long )rt->rt_pksent)); 333 wid_pksent = MAX(len, wid_pksent); 334 } 335 if (rt->rt_ifp) { 336 if (rt->rt_ifp != lastif) { 337 if (kget(rt->rt_ifp, ifnet) == 0) 338 len = strlen(ifnet.if_xname); 339 else 340 len = strlen("---"); 341 lastif = rt->rt_ifp; 342 wid_if = MAX(len, wid_if); 343 } 344 if (rt->rt_expire) { 345 time_t expire_time; 346 347 if ((expire_time = 348 rt->rt_expire - uptime.tv_sec) > 0) { 349 len = snprintf(buffer, sizeof(buffer), "%d", 350 (int)expire_time); 351 wid_expire = MAX(len, wid_expire); 352 } 353 } 354 } 355 } 356 357 358 /* 359 * Print header for routing table columns. 360 */ 361 void 362 pr_rthdr(int af1) 363 { 364 365 if (Aflag) 366 printf("%-8.8s ","Address"); 367 if (Wflag) { 368 printf("%-*.*s %-*.*s %-*.*s %*.*s %*.*s %*.*s %*s\n", 369 wid_dst, wid_dst, "Destination", 370 wid_gw, wid_gw, "Gateway", 371 wid_flags, wid_flags, "Flags", 372 wid_pksent, wid_pksent, "Use", 373 wid_mtu, wid_mtu, "Mtu", 374 wid_if, wid_if, "Netif", 375 wid_expire, "Expire"); 376 } else { 377 printf("%-*.*s %-*.*s %-*.*s %*.*s %*s\n", 378 wid_dst, wid_dst, "Destination", 379 wid_gw, wid_gw, "Gateway", 380 wid_flags, wid_flags, "Flags", 381 wid_if, wid_if, "Netif", 382 wid_expire, "Expire"); 383 } 384 } 385 386 static struct sockaddr * 387 kgetsa(struct sockaddr *dst) 388 { 389 390 if (kget(dst, pt_u.u_sa) != 0) 391 return (NULL); 392 if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa)) 393 kread((u_long)dst, (char *)pt_u.u_data, pt_u.u_sa.sa_len); 394 return (&pt_u.u_sa); 395 } 396 397 /* 398 * Print kernel routing tables for given fib 399 * using debugging kvm(3) interface. 400 */ 401 static void 402 p_rtable_kvm(int fibnum, int af) 403 { 404 struct radix_node_head **rnhp, *rnh, head; 405 struct radix_node_head **rt_tables; 406 u_long rtree; 407 int fam, af_size; 408 409 kresolve_list(rl); 410 if ((rtree = rl[N_RTREE].n_value) == 0) { 411 printf("rt_tables: symbol not in namelist\n"); 412 return; 413 } 414 415 af_size = (AF_MAX + 1) * sizeof(struct radix_node_head *); 416 rt_tables = calloc(1, af_size); 417 if (rt_tables == NULL) 418 err(EX_OSERR, "memory allocation failed"); 419 420 if (kread((u_long)(rtree), (char *)(rt_tables) + fibnum * af_size, 421 af_size) != 0) 422 err(EX_OSERR, "error retrieving radix pointers"); 423 for (fam = 0; fam <= AF_MAX; fam++) { 424 int tmpfib; 425 426 switch (fam) { 427 case AF_INET6: 428 case AF_INET: 429 tmpfib = fibnum; 430 break; 431 default: 432 tmpfib = 0; 433 } 434 rnhp = (struct radix_node_head **)*rt_tables; 435 /* Calculate the in-kernel address. */ 436 rnhp += tmpfib * (AF_MAX + 1) + fam; 437 /* Read the in kernel rhn pointer. */ 438 if (kget(rnhp, rnh) != 0) 439 continue; 440 if (rnh == NULL) 441 continue; 442 /* Read the rnh data. */ 443 if (kget(rnh, head) != 0) 444 continue; 445 if (fam == AF_UNSPEC) { 446 if (Aflag && af == 0) { 447 printf("Netmasks:\n"); 448 p_rtree_kvm(head.rnh_treetop); 449 } 450 } else if (af == AF_UNSPEC || af == fam) { 451 size_cols(fam, head.rnh_treetop); 452 pr_family(fam); 453 do_rtent = 1; 454 pr_rthdr(fam); 455 p_rtree_kvm(head.rnh_treetop); 456 } 457 } 458 459 free(rt_tables); 460 } 461 462 /* 463 * Print given kernel radix tree using 464 * debugging kvm(3) interface. 465 */ 466 static void 467 p_rtree_kvm(struct radix_node *rn) 468 { 469 470 again: 471 if (kget(rn, rnode) != 0) 472 return; 473 if (!(rnode.rn_flags & RNF_ACTIVE)) 474 return; 475 if (rnode.rn_bit < 0) { 476 if (Aflag) 477 printf("%-8.8lx ", (u_long)rn); 478 if (rnode.rn_flags & RNF_ROOT) { 479 if (Aflag) 480 printf("(root node)%s", 481 rnode.rn_dupedkey ? " =>\n" : "\n"); 482 } else if (do_rtent) { 483 if (kget(rn, rtentry) == 0) { 484 p_rtentry_kvm(&rtentry); 485 if (Aflag) 486 p_rtnode_kvm(); 487 } 488 } else { 489 p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key), 490 NULL, 0, 44); 491 putchar('\n'); 492 } 493 if ((rn = rnode.rn_dupedkey)) 494 goto again; 495 } else { 496 if (Aflag && do_rtent) { 497 printf("%-8.8lx ", (u_long)rn); 498 p_rtnode_kvm(); 499 } 500 rn = rnode.rn_right; 501 p_rtree_kvm(rnode.rn_left); 502 p_rtree_kvm(rn); 503 } 504 } 505 506 char nbuf[20]; 507 508 static void 509 p_rtnode_kvm(void) 510 { 511 struct radix_mask *rm = rnode.rn_mklist; 512 513 if (rnode.rn_bit < 0) { 514 if (rnode.rn_mask) { 515 printf("\t mask "); 516 p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask), 517 NULL, 0, -1); 518 } else if (rm == 0) 519 return; 520 } else { 521 sprintf(nbuf, "(%d)", rnode.rn_bit); 522 printf("%6.6s %8.8lx : %8.8lx", nbuf, (u_long)rnode.rn_left, (u_long)rnode.rn_right); 523 } 524 while (rm) { 525 if (kget(rm, rmask) != 0) 526 break; 527 sprintf(nbuf, " %d refs, ", rmask.rm_refs); 528 printf(" mk = %8.8lx {(%d),%s", 529 (u_long)rm, -1 - rmask.rm_bit, rmask.rm_refs ? nbuf : " "); 530 if (rmask.rm_flags & RNF_NORMAL) { 531 struct radix_node rnode_aux; 532 printf(" <normal>, "); 533 if (kget(rmask.rm_leaf, rnode_aux) == 0) 534 p_sockaddr(kgetsa((struct sockaddr *)rnode_aux.rn_mask), 535 NULL, 0, -1); 536 else 537 p_sockaddr(NULL, NULL, 0, -1); 538 } else 539 p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask), 540 NULL, 0, -1); 541 putchar('}'); 542 if ((rm = rmask.rm_mklist)) 543 printf(" ->"); 544 } 545 putchar('\n'); 546 } 547 548 static void 549 p_rtable_sysctl(int fibnum, int af) 550 { 551 size_t needed; 552 int mib[7]; 553 char *buf, *next, *lim; 554 struct rt_msghdr *rtm; 555 struct sockaddr *sa; 556 int fam = 0, ifindex = 0, size; 557 558 struct ifaddrs *ifap, *ifa; 559 struct sockaddr_dl *sdl; 560 561 /* 562 * Retrieve interface list at first 563 * since we need #ifindex -> if_xname match 564 */ 565 if (getifaddrs(&ifap) != 0) 566 err(EX_OSERR, "getifaddrs"); 567 568 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 569 570 if (ifa->ifa_addr->sa_family != AF_LINK) 571 continue; 572 573 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 574 ifindex = sdl->sdl_index; 575 576 if (ifindex >= ifmap_size) { 577 size = roundup(ifindex + 1, 32) * 578 sizeof(struct ifmap_entry); 579 if ((ifmap = realloc(ifmap, size)) == NULL) 580 errx(2, "realloc(%d) failed", size); 581 memset(&ifmap[ifmap_size], 0, 582 size - ifmap_size * 583 sizeof(struct ifmap_entry)); 584 585 ifmap_size = roundup(ifindex + 1, 32); 586 } 587 588 if (*ifmap[ifindex].ifname != '\0') 589 continue; 590 591 strlcpy(ifmap[ifindex].ifname, ifa->ifa_name, IFNAMSIZ); 592 } 593 594 freeifaddrs(ifap); 595 596 mib[0] = CTL_NET; 597 mib[1] = PF_ROUTE; 598 mib[2] = 0; 599 mib[3] = af; 600 mib[4] = NET_RT_DUMP; 601 mib[5] = 0; 602 mib[6] = fibnum; 603 if (sysctl(mib, 7, NULL, &needed, NULL, 0) < 0) { 604 err(1, "sysctl: net.route.0.%d.dump.%d estimate", af, fibnum); 605 } 606 607 if ((buf = malloc(needed)) == 0) { 608 errx(2, "malloc(%lu)", (unsigned long)needed); 609 } 610 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 611 err(1, "sysctl: net.route.0.%d.dump.%d", af, fibnum); 612 } 613 lim = buf + needed; 614 for (next = buf; next < lim; next += rtm->rtm_msglen) { 615 rtm = (struct rt_msghdr *)next; 616 /* 617 * Peek inside header to determine AF 618 */ 619 sa = (struct sockaddr *)(rtm + 1); 620 if (fam != sa->sa_family) { 621 fam = sa->sa_family; 622 size_cols(fam, NULL); 623 pr_family(fam); 624 pr_rthdr(fam); 625 } 626 p_rtentry_sysctl(rtm); 627 } 628 } 629 630 static void 631 p_rtentry_sysctl(struct rt_msghdr *rtm) 632 { 633 struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 634 char buffer[128]; 635 char prettyname[128]; 636 sa_u addr, mask, gw; 637 unsigned int l; 638 639 #define GETSA(_s, _f) { \ 640 bzero(&(_s), sizeof(_s)); \ 641 if (rtm->rtm_addrs & _f) { \ 642 l = roundup(sa->sa_len, sizeof(long)); \ 643 memcpy(&(_s), sa, (l > sizeof(_s)) ? sizeof(_s) : l); \ 644 sa = (struct sockaddr *)((char *)sa + l); \ 645 } \ 646 } 647 648 GETSA(addr, RTA_DST); 649 GETSA(gw, RTA_GATEWAY); 650 GETSA(mask, RTA_NETMASK); 651 p_sockaddr(&addr.u_sa, &mask.u_sa, rtm->rtm_flags, wid_dst); 652 p_sockaddr(&gw.u_sa, NULL, RTF_HOST, wid_gw); 653 654 snprintf(buffer, sizeof(buffer), "%%-%d.%ds ", wid_flags, wid_flags); 655 p_flags(rtm->rtm_flags, buffer); 656 if (Wflag) { 657 printf("%*lu ", wid_pksent, rtm->rtm_rmx.rmx_pksent); 658 659 if (rtm->rtm_rmx.rmx_mtu != 0) 660 printf("%*lu ", wid_mtu, rtm->rtm_rmx.rmx_mtu); 661 else 662 printf("%*s ", wid_mtu, ""); 663 } 664 665 memset(prettyname, 0, sizeof(prettyname)); 666 if (rtm->rtm_index < ifmap_size) { 667 strlcpy(prettyname, ifmap[rtm->rtm_index].ifname, 668 sizeof(prettyname)); 669 if (*prettyname == '\0') 670 strlcpy(prettyname, "---", sizeof(prettyname)); 671 } 672 673 printf("%*.*s", wid_if, wid_if, prettyname); 674 if (rtm->rtm_rmx.rmx_expire) { 675 time_t expire_time; 676 677 if ((expire_time = 678 rtm->rtm_rmx.rmx_expire - uptime.tv_sec) > 0) 679 printf(" %*d", wid_expire, (int)expire_time); 680 } 681 682 putchar('\n'); 683 } 684 685 static void 686 p_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags, int width) 687 { 688 const char *cp; 689 690 cp = fmt_sockaddr(sa, mask, flags); 691 692 if (width < 0 ) 693 printf("%s ", cp); 694 else { 695 if (numeric_addr) 696 printf("%-*s ", width, cp); 697 else 698 printf("%-*.*s ", width, width, cp); 699 } 700 } 701 702 static const char * 703 fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags) 704 { 705 static char workbuf[128]; 706 const char *cp; 707 708 if (sa == NULL) 709 return ("null"); 710 711 switch(sa->sa_family) { 712 case AF_INET: 713 { 714 struct sockaddr_in *sockin = (struct sockaddr_in *)sa; 715 716 if ((sockin->sin_addr.s_addr == INADDR_ANY) && 717 mask && 718 ntohl(((struct sockaddr_in *)mask)->sin_addr.s_addr) 719 ==0L) 720 cp = "default" ; 721 else if (flags & RTF_HOST) 722 cp = routename(sockin->sin_addr.s_addr); 723 else if (mask) 724 cp = netname(sockin->sin_addr.s_addr, 725 ((struct sockaddr_in *)mask)->sin_addr.s_addr); 726 else 727 cp = netname(sockin->sin_addr.s_addr, INADDR_ANY); 728 break; 729 } 730 731 #ifdef INET6 732 case AF_INET6: 733 { 734 struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; 735 736 /* 737 * The sa6->sin6_scope_id must be filled here because 738 * this sockaddr is extracted from kmem(4) directly 739 * and has KAME-specific embedded scope id in 740 * sa6->sin6_addr.s6_addr[2]. 741 */ 742 in6_fillscopeid(sa6); 743 744 if (flags & RTF_HOST) 745 cp = routename6(sa6); 746 else if (mask) 747 cp = netname6(sa6, 748 &((struct sockaddr_in6 *)mask)->sin6_addr); 749 else { 750 cp = netname6(sa6, NULL); 751 } 752 break; 753 } 754 #endif /*INET6*/ 755 756 case AF_IPX: 757 { 758 struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr; 759 if (ipx_nullnet(satoipx_addr(work))) 760 cp = "default"; 761 else 762 cp = ipx_print(sa); 763 break; 764 } 765 case AF_APPLETALK: 766 { 767 if (!(flags & RTF_HOST) && mask) 768 cp = atalk_print2(sa,mask,9); 769 else 770 cp = atalk_print(sa,11); 771 break; 772 } 773 case AF_NETGRAPH: 774 { 775 strlcpy(workbuf, ((struct sockaddr_ng *)sa)->sg_data, 776 sizeof(workbuf)); 777 cp = workbuf; 778 break; 779 } 780 781 case AF_LINK: 782 { 783 struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; 784 785 if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && 786 sdl->sdl_slen == 0) { 787 (void) sprintf(workbuf, "link#%d", sdl->sdl_index); 788 cp = workbuf; 789 } else 790 switch (sdl->sdl_type) { 791 792 case IFT_ETHER: 793 case IFT_L2VLAN: 794 case IFT_BRIDGE: 795 if (sdl->sdl_alen == ETHER_ADDR_LEN) { 796 cp = ether_ntoa((struct ether_addr *) 797 (sdl->sdl_data + sdl->sdl_nlen)); 798 break; 799 } 800 /* FALLTHROUGH */ 801 default: 802 cp = link_ntoa(sdl); 803 break; 804 } 805 break; 806 } 807 808 default: 809 { 810 u_char *s = (u_char *)sa->sa_data, *slim; 811 char *cq, *cqlim; 812 813 cq = workbuf; 814 slim = sa->sa_len + (u_char *) sa; 815 cqlim = cq + sizeof(workbuf) - 6; 816 cq += sprintf(cq, "(%d)", sa->sa_family); 817 while (s < slim && cq < cqlim) { 818 cq += sprintf(cq, " %02x", *s++); 819 if (s < slim) 820 cq += sprintf(cq, "%02x", *s++); 821 } 822 cp = workbuf; 823 } 824 } 825 826 return (cp); 827 } 828 829 static void 830 p_flags(int f, const char *format) 831 { 832 printf(format, fmt_flags(f)); 833 } 834 835 static const char * 836 fmt_flags(int f) 837 { 838 static char name[33]; 839 char *flags; 840 struct bits *p = bits; 841 842 for (flags = name; p->b_mask; p++) 843 if (p->b_mask & f) 844 *flags++ = p->b_val; 845 *flags = '\0'; 846 return (name); 847 } 848 849 static void 850 p_rtentry_kvm(struct rtentry *rt) 851 { 852 static struct ifnet ifnet, *lastif; 853 static char buffer[128]; 854 static char prettyname[128]; 855 struct sockaddr *sa; 856 sa_u addr, mask; 857 858 bzero(&addr, sizeof(addr)); 859 if ((sa = kgetsa(rt_key(rt)))) 860 bcopy(sa, &addr, sa->sa_len); 861 bzero(&mask, sizeof(mask)); 862 if (rt_mask(rt) && (sa = kgetsa(rt_mask(rt)))) 863 bcopy(sa, &mask, sa->sa_len); 864 p_sockaddr(&addr.u_sa, &mask.u_sa, rt->rt_flags, wid_dst); 865 p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, wid_gw); 866 snprintf(buffer, sizeof(buffer), "%%-%d.%ds ", wid_flags, wid_flags); 867 p_flags(rt->rt_flags, buffer); 868 if (Wflag) { 869 printf("%*lu ", wid_pksent, 870 kread_counter((u_long )rt->rt_pksent)); 871 872 if (rt->rt_mtu != 0) 873 printf("%*lu ", wid_mtu, rt->rt_mtu); 874 else 875 printf("%*s ", wid_mtu, ""); 876 } 877 if (rt->rt_ifp) { 878 if (rt->rt_ifp != lastif) { 879 if (kget(rt->rt_ifp, ifnet) == 0) 880 strlcpy(prettyname, ifnet.if_xname, 881 sizeof(prettyname)); 882 else 883 strlcpy(prettyname, "---", sizeof(prettyname)); 884 lastif = rt->rt_ifp; 885 } 886 printf("%*.*s", wid_if, wid_if, prettyname); 887 if (rt->rt_expire) { 888 time_t expire_time; 889 890 if ((expire_time = 891 rt->rt_expire - uptime.tv_sec) > 0) 892 printf(" %*d", wid_expire, (int)expire_time); 893 } 894 if (rt->rt_nodes[0].rn_dupedkey) 895 printf(" =>"); 896 } 897 putchar('\n'); 898 } 899 900 char * 901 routename(in_addr_t in) 902 { 903 char *cp; 904 static char line[MAXHOSTNAMELEN]; 905 struct hostent *hp; 906 907 cp = 0; 908 if (!numeric_addr) { 909 hp = gethostbyaddr(&in, sizeof (struct in_addr), AF_INET); 910 if (hp) { 911 cp = hp->h_name; 912 trimdomain(cp, strlen(cp)); 913 } 914 } 915 if (cp) { 916 strlcpy(line, cp, sizeof(line)); 917 } else { 918 #define C(x) ((x) & 0xff) 919 in = ntohl(in); 920 sprintf(line, "%u.%u.%u.%u", 921 C(in >> 24), C(in >> 16), C(in >> 8), C(in)); 922 } 923 return (line); 924 } 925 926 #define NSHIFT(m) ( \ 927 (m) == IN_CLASSA_NET ? IN_CLASSA_NSHIFT : \ 928 (m) == IN_CLASSB_NET ? IN_CLASSB_NSHIFT : \ 929 (m) == IN_CLASSC_NET ? IN_CLASSC_NSHIFT : \ 930 0) 931 932 static void 933 domask(char *dst, in_addr_t addr __unused, u_long mask) 934 { 935 int b, i; 936 937 if (mask == 0 || (!numeric_addr && NSHIFT(mask) != 0)) { 938 *dst = '\0'; 939 return; 940 } 941 i = 0; 942 for (b = 0; b < 32; b++) 943 if (mask & (1 << b)) { 944 int bb; 945 946 i = b; 947 for (bb = b+1; bb < 32; bb++) 948 if (!(mask & (1 << bb))) { 949 i = -1; /* noncontig */ 950 break; 951 } 952 break; 953 } 954 if (i == -1) 955 sprintf(dst, "&0x%lx", mask); 956 else 957 sprintf(dst, "/%d", 32-i); 958 } 959 960 /* 961 * Return the name of the network whose address is given. 962 */ 963 char * 964 netname(in_addr_t in, in_addr_t mask) 965 { 966 char *cp = 0; 967 static char line[MAXHOSTNAMELEN]; 968 struct netent *np = 0; 969 in_addr_t i; 970 971 /* It is ok to supply host address. */ 972 in &= mask; 973 974 i = ntohl(in); 975 if (!numeric_addr && i) { 976 np = getnetbyaddr(i >> NSHIFT(ntohl(mask)), AF_INET); 977 if (np != NULL) { 978 cp = np->n_name; 979 trimdomain(cp, strlen(cp)); 980 } 981 } 982 if (cp != NULL) { 983 strlcpy(line, cp, sizeof(line)); 984 } else { 985 inet_ntop(AF_INET, &in, line, sizeof(line) - 1); 986 } 987 domask(line + strlen(line), i, ntohl(mask)); 988 return (line); 989 } 990 991 #undef NSHIFT 992 993 #ifdef INET6 994 void 995 in6_fillscopeid(struct sockaddr_in6 *sa6) 996 { 997 #if defined(__KAME__) 998 /* 999 * XXX: This is a special workaround for KAME kernels. 1000 * sin6_scope_id field of SA should be set in the future. 1001 */ 1002 if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) || 1003 IN6_IS_ADDR_MC_NODELOCAL(&sa6->sin6_addr) || 1004 IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr)) { 1005 /* XXX: override is ok? */ 1006 sa6->sin6_scope_id = 1007 ntohs(*(u_int16_t *)&sa6->sin6_addr.s6_addr[2]); 1008 sa6->sin6_addr.s6_addr[2] = sa6->sin6_addr.s6_addr[3] = 0; 1009 } 1010 #endif 1011 } 1012 1013 const char * 1014 netname6(struct sockaddr_in6 *sa6, struct in6_addr *mask) 1015 { 1016 static char line[MAXHOSTNAMELEN]; 1017 u_char *p = (u_char *)mask; 1018 u_char *lim; 1019 int masklen, illegal = 0, flag = 0; 1020 1021 if (mask) { 1022 for (masklen = 0, lim = p + 16; p < lim; p++) { 1023 switch (*p) { 1024 case 0xff: 1025 masklen += 8; 1026 break; 1027 case 0xfe: 1028 masklen += 7; 1029 break; 1030 case 0xfc: 1031 masklen += 6; 1032 break; 1033 case 0xf8: 1034 masklen += 5; 1035 break; 1036 case 0xf0: 1037 masklen += 4; 1038 break; 1039 case 0xe0: 1040 masklen += 3; 1041 break; 1042 case 0xc0: 1043 masklen += 2; 1044 break; 1045 case 0x80: 1046 masklen += 1; 1047 break; 1048 case 0x00: 1049 break; 1050 default: 1051 illegal ++; 1052 break; 1053 } 1054 } 1055 if (illegal) 1056 fprintf(stderr, "illegal prefixlen\n"); 1057 } 1058 else 1059 masklen = 128; 1060 1061 if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr)) 1062 return("default"); 1063 1064 if (numeric_addr) 1065 flag |= NI_NUMERICHOST; 1066 getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line), 1067 NULL, 0, flag); 1068 1069 if (numeric_addr) 1070 sprintf(&line[strlen(line)], "/%d", masklen); 1071 1072 return line; 1073 } 1074 1075 char * 1076 routename6(struct sockaddr_in6 *sa6) 1077 { 1078 static char line[MAXHOSTNAMELEN]; 1079 int flag = 0; 1080 /* use local variable for safety */ 1081 struct sockaddr_in6 sa6_local; 1082 1083 sa6_local.sin6_family = AF_INET6; 1084 sa6_local.sin6_len = sizeof(sa6_local); 1085 sa6_local.sin6_addr = sa6->sin6_addr; 1086 sa6_local.sin6_scope_id = sa6->sin6_scope_id; 1087 1088 if (numeric_addr) 1089 flag |= NI_NUMERICHOST; 1090 1091 getnameinfo((struct sockaddr *)&sa6_local, sa6_local.sin6_len, 1092 line, sizeof(line), NULL, 0, flag); 1093 1094 return line; 1095 } 1096 #endif /*INET6*/ 1097 1098 /* 1099 * Print routing statistics 1100 */ 1101 void 1102 rt_stats(void) 1103 { 1104 struct rtstat rtstat; 1105 u_long rtsaddr, rttaddr; 1106 int rttrash; 1107 1108 kresolve_list(rl); 1109 1110 if ((rtsaddr = rl[N_RTSTAT].n_value) == 0) { 1111 printf("rtstat: symbol not in namelist\n"); 1112 return; 1113 } 1114 if ((rttaddr = rl[N_RTTRASH].n_value) == 0) { 1115 printf("rttrash: symbol not in namelist\n"); 1116 return; 1117 } 1118 kread(rtsaddr, (char *)&rtstat, sizeof (rtstat)); 1119 kread(rttaddr, (char *)&rttrash, sizeof (rttrash)); 1120 printf("routing:\n"); 1121 1122 #define p(f, m) if (rtstat.f || sflag <= 1) \ 1123 printf(m, rtstat.f, plural(rtstat.f)) 1124 1125 p(rts_badredirect, "\t%hu bad routing redirect%s\n"); 1126 p(rts_dynamic, "\t%hu dynamically created route%s\n"); 1127 p(rts_newgateway, "\t%hu new gateway%s due to redirects\n"); 1128 p(rts_unreach, "\t%hu destination%s found unreachable\n"); 1129 p(rts_wildcard, "\t%hu use%s of a wildcard route\n"); 1130 #undef p 1131 1132 if (rttrash || sflag <= 1) 1133 printf("\t%u route%s not in table but not freed\n", 1134 rttrash, plural(rttrash)); 1135 } 1136 1137 char * 1138 ipx_print(struct sockaddr *sa) 1139 { 1140 u_short port; 1141 struct servent *sp = 0; 1142 const char *net = "", *host = ""; 1143 char *p; 1144 u_char *q; 1145 struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr; 1146 static char mybuf[50]; 1147 char cport[10], chost[15], cnet[15]; 1148 1149 port = ntohs(work.x_port); 1150 1151 if (ipx_nullnet(work) && ipx_nullhost(work)) { 1152 1153 if (port) { 1154 if (sp) 1155 sprintf(mybuf, "*.%s", sp->s_name); 1156 else 1157 sprintf(mybuf, "*.%x", port); 1158 } else 1159 sprintf(mybuf, "*.*"); 1160 1161 return (mybuf); 1162 } 1163 1164 if (ipx_wildnet(work)) 1165 net = "any"; 1166 else if (ipx_nullnet(work)) 1167 net = "*"; 1168 else { 1169 q = work.x_net.c_net; 1170 sprintf(cnet, "%02x%02x%02x%02x", 1171 q[0], q[1], q[2], q[3]); 1172 for (p = cnet; *p == '0' && p < cnet + 8; p++) 1173 continue; 1174 net = p; 1175 } 1176 1177 if (ipx_wildhost(work)) 1178 host = "any"; 1179 else if (ipx_nullhost(work)) 1180 host = "*"; 1181 else { 1182 q = work.x_host.c_host; 1183 sprintf(chost, "%02x%02x%02x%02x%02x%02x", 1184 q[0], q[1], q[2], q[3], q[4], q[5]); 1185 for (p = chost; *p == '0' && p < chost + 12; p++) 1186 continue; 1187 host = p; 1188 } 1189 1190 if (port) { 1191 if (strcmp(host, "*") == 0) 1192 host = ""; 1193 if (sp) 1194 snprintf(cport, sizeof(cport), 1195 "%s%s", *host ? "." : "", sp->s_name); 1196 else 1197 snprintf(cport, sizeof(cport), 1198 "%s%x", *host ? "." : "", port); 1199 } else 1200 *cport = 0; 1201 1202 snprintf(mybuf, sizeof(mybuf), "%s.%s%s", net, host, cport); 1203 return(mybuf); 1204 } 1205 1206 char * 1207 ipx_phost(struct sockaddr *sa) 1208 { 1209 struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)sa; 1210 struct sockaddr_ipx work; 1211 static union ipx_net ipx_zeronet; 1212 char *p; 1213 1214 work = *sipx; 1215 1216 work.sipx_addr.x_port = 0; 1217 work.sipx_addr.x_net = ipx_zeronet; 1218 p = ipx_print((struct sockaddr *)&work); 1219 if (strncmp("*.", p, 2) == 0) p += 2; 1220 1221 return(p); 1222 } 1223 1224 void 1225 upHex(char *p0) 1226 { 1227 char *p = p0; 1228 1229 for (; *p; p++) 1230 switch (*p) { 1231 1232 case 'a': 1233 case 'b': 1234 case 'c': 1235 case 'd': 1236 case 'e': 1237 case 'f': 1238 *p += ('A' - 'a'); 1239 break; 1240 } 1241 } 1242