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