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 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 #if 0 36 static char sccsid[] = "From: @(#)route.c 8.6 (Berkeley) 4/28/95"; 37 #endif 38 static const char rcsid[] = 39 "$FreeBSD$"; 40 #endif /* not lint */ 41 42 #include <sys/param.h> 43 #include <sys/protosw.h> 44 #include <sys/socket.h> 45 #include <sys/time.h> 46 47 #include <net/if.h> 48 #include <net/if_var.h> 49 #include <net/if_dl.h> 50 #include <net/if_types.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 #ifdef NS 59 #include <netns/ns.h> 60 #endif 61 62 #include <sys/sysctl.h> 63 64 #include <arpa/inet.h> 65 #include <netdb.h> 66 #include <stdio.h> 67 #include <stdlib.h> 68 #include <string.h> 69 #include <unistd.h> 70 #include <err.h> 71 #include <time.h> 72 #include "netstat.h" 73 74 #define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d))) 75 76 77 /* alignment constraint for routing socket */ 78 #define ROUNDUP(a) \ 79 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 80 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 81 82 /* 83 * Definitions for showing gateway flags. 84 */ 85 struct bits { 86 u_long b_mask; 87 char b_val; 88 } bits[] = { 89 { RTF_UP, 'U' }, 90 { RTF_GATEWAY, 'G' }, 91 { RTF_HOST, 'H' }, 92 { RTF_REJECT, 'R' }, 93 { RTF_DYNAMIC, 'D' }, 94 { RTF_MODIFIED, 'M' }, 95 { RTF_DONE, 'd' }, /* Completed -- for routing messages only */ 96 { RTF_CLONING, 'C' }, 97 { RTF_XRESOLVE, 'X' }, 98 { RTF_LLINFO, 'L' }, 99 { RTF_STATIC, 'S' }, 100 { RTF_PROTO1, '1' }, 101 { RTF_PROTO2, '2' }, 102 { RTF_WASCLONED,'W' }, 103 { RTF_PRCLONING,'c' }, 104 { RTF_PROTO3, '3' }, 105 { RTF_BLACKHOLE,'B' }, 106 { RTF_BROADCAST,'b' }, 107 { 0 } 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 static sa_u pt_u; 117 118 int do_rtent = 0; 119 struct rtentry rtentry; 120 struct radix_node rnode; 121 struct radix_mask rmask; 122 struct radix_node_head *rt_tables[AF_MAX+1]; 123 124 int NewTree = 0; 125 126 static struct sockaddr *kgetsa __P((struct sockaddr *)); 127 static void p_tree __P((struct radix_node *)); 128 static void p_rtnode __P((void)); 129 static void ntreestuff __P((void)); 130 static void np_rtentry __P((struct rt_msghdr *)); 131 static void p_sockaddr __P((struct sockaddr *, struct sockaddr *, int, int)); 132 static void p_flags __P((int, char *)); 133 static void p_rtentry __P((struct rtentry *)); 134 static u_long forgemask __P((u_long)); 135 static void domask __P((char *, u_long, u_long)); 136 137 #ifdef INET6 138 char *routename6 __P((struct sockaddr_in6 *)); 139 char *netname6 __P((struct sockaddr_in6 *, struct in6_addr *)); 140 #endif /*INET6*/ 141 142 /* 143 * Print routing tables. 144 */ 145 void 146 routepr(rtree) 147 u_long rtree; 148 { 149 struct radix_node_head *rnh, head; 150 int i; 151 152 printf("Routing tables\n"); 153 154 if (Aflag == 0 && NewTree) 155 ntreestuff(); 156 else { 157 if (rtree == 0) { 158 printf("rt_tables: symbol not in namelist\n"); 159 return; 160 } 161 162 kget(rtree, rt_tables); 163 for (i = 0; i <= AF_MAX; i++) { 164 if ((rnh = rt_tables[i]) == 0) 165 continue; 166 kget(rnh, head); 167 if (i == AF_UNSPEC) { 168 if (Aflag && af == 0) { 169 printf("Netmasks:\n"); 170 p_tree(head.rnh_treetop); 171 } 172 } else if (af == AF_UNSPEC || af == i) { 173 pr_family(i); 174 do_rtent = 1; 175 pr_rthdr(i); 176 p_tree(head.rnh_treetop); 177 } 178 } 179 } 180 } 181 182 /* 183 * Print address family header before a section of the routing table. 184 */ 185 void 186 pr_family(af) 187 int af; 188 { 189 char *afname; 190 191 switch (af) { 192 case AF_INET: 193 afname = "Internet"; 194 break; 195 #ifdef INET6 196 case AF_INET6: 197 afname = "Internet6"; 198 break; 199 #endif /*INET6*/ 200 case AF_IPX: 201 afname = "IPX"; 202 break; 203 #ifdef NS 204 case AF_NS: 205 afname = "XNS"; 206 break; 207 #endif 208 case AF_ISO: 209 afname = "ISO"; 210 break; 211 case AF_APPLETALK: 212 afname = "AppleTalk"; 213 break; 214 case AF_CCITT: 215 afname = "X.25"; 216 break; 217 case AF_NETGRAPH: 218 afname = "Netgraph"; 219 break; 220 default: 221 afname = NULL; 222 break; 223 } 224 if (afname) 225 printf("\n%s:\n", afname); 226 else 227 printf("\nProtocol Family %d:\n", af); 228 } 229 230 /* column widths; each followed by one space */ 231 #ifndef INET6 232 #define WID_DST(af) 18 /* width of destination column */ 233 #define WID_GW(af) 18 /* width of gateway column */ 234 #else 235 #define WID_DST(af) \ 236 ((af) == AF_INET6 ? (lflag ? 39 : (nflag ? 33: 18)) : 18) 237 #define WID_GW(af) \ 238 ((af) == AF_INET6 ? (lflag ? 31 : (nflag ? 29 : 18)) : 18) 239 #endif /*INET6*/ 240 241 /* 242 * Print header for routing table columns. 243 */ 244 void 245 pr_rthdr(af) 246 int af; 247 { 248 249 if (Aflag) 250 printf("%-8.8s ","Address"); 251 if (lflag) 252 printf("%-*.*s %-*.*s %-6.6s %6.6s%8.8s %8.8s %6s\n", 253 WID_DST(af), WID_DST(af), "Destination", 254 WID_GW(af), WID_GW(af), "Gateway", 255 "Flags", "Refs", "Use", "Netif", "Expire"); 256 else 257 printf("%-*.*s %-*.*s %-6.6s %8.8s %6s\n", 258 WID_DST(af), WID_DST(af), "Destination", 259 WID_GW(af), WID_GW(af), "Gateway", 260 "Flags", "Netif", "Expire"); 261 } 262 263 static struct sockaddr * 264 kgetsa(dst) 265 register struct sockaddr *dst; 266 { 267 268 kget(dst, pt_u.u_sa); 269 if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa)) 270 kread((u_long)dst, (char *)pt_u.u_data, pt_u.u_sa.sa_len); 271 return (&pt_u.u_sa); 272 } 273 274 static void 275 p_tree(rn) 276 struct radix_node *rn; 277 { 278 279 again: 280 kget(rn, rnode); 281 if (rnode.rn_bit < 0) { 282 if (Aflag) 283 printf("%-8.8lx ", (u_long)rn); 284 if (rnode.rn_flags & RNF_ROOT) { 285 if (Aflag) 286 printf("(root node)%s", 287 rnode.rn_dupedkey ? " =>\n" : "\n"); 288 } else if (do_rtent) { 289 kget(rn, rtentry); 290 p_rtentry(&rtentry); 291 if (Aflag) 292 p_rtnode(); 293 } else { 294 p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key), 295 NULL, 0, 44); 296 putchar('\n'); 297 } 298 if ((rn = rnode.rn_dupedkey)) 299 goto again; 300 } else { 301 if (Aflag && do_rtent) { 302 printf("%-8.8lx ", (u_long)rn); 303 p_rtnode(); 304 } 305 rn = rnode.rn_right; 306 p_tree(rnode.rn_left); 307 p_tree(rn); 308 } 309 } 310 311 char nbuf[20]; 312 313 static void 314 p_rtnode() 315 { 316 struct radix_mask *rm = rnode.rn_mklist; 317 318 if (rnode.rn_bit < 0) { 319 if (rnode.rn_mask) { 320 printf("\t mask "); 321 p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask), 322 NULL, 0, -1); 323 } else if (rm == 0) 324 return; 325 } else { 326 sprintf(nbuf, "(%d)", rnode.rn_bit); 327 printf("%6.6s %8.8lx : %8.8lx", nbuf, (u_long)rnode.rn_left, (u_long)rnode.rn_right); 328 } 329 while (rm) { 330 kget(rm, rmask); 331 sprintf(nbuf, " %d refs, ", rmask.rm_refs); 332 printf(" mk = %8.8lx {(%d),%s", 333 (u_long)rm, -1 - rmask.rm_bit, rmask.rm_refs ? nbuf : " "); 334 if (rmask.rm_flags & RNF_NORMAL) { 335 struct radix_node rnode_aux; 336 printf(" <normal>, "); 337 kget(rmask.rm_leaf, rnode_aux); 338 p_sockaddr(kgetsa((struct sockaddr *)rnode_aux.rn_mask), 339 NULL, 0, -1); 340 } else 341 p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask), 342 NULL, 0, -1); 343 putchar('}'); 344 if ((rm = rmask.rm_mklist)) 345 printf(" ->"); 346 } 347 putchar('\n'); 348 } 349 350 static void 351 ntreestuff() 352 { 353 size_t needed; 354 int mib[6]; 355 char *buf, *next, *lim; 356 register struct rt_msghdr *rtm; 357 358 mib[0] = CTL_NET; 359 mib[1] = PF_ROUTE; 360 mib[2] = 0; 361 mib[3] = 0; 362 mib[4] = NET_RT_DUMP; 363 mib[5] = 0; 364 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 365 err(1, "sysctl: net.route.0.0.dump estimate"); 366 } 367 368 if ((buf = malloc(needed)) == 0) { 369 err(2, "malloc(%lu)", (unsigned long)needed); 370 } 371 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 372 err(1, "sysctl: net.route.0.0.dump"); 373 } 374 lim = buf + needed; 375 for (next = buf; next < lim; next += rtm->rtm_msglen) { 376 rtm = (struct rt_msghdr *)next; 377 np_rtentry(rtm); 378 } 379 } 380 381 static void 382 np_rtentry(rtm) 383 register struct rt_msghdr *rtm; 384 { 385 register struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 386 #ifdef notdef 387 static int masks_done, banner_printed; 388 #endif 389 static int old_af; 390 int af = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST; 391 392 #ifdef notdef 393 /* for the moment, netmasks are skipped over */ 394 if (!banner_printed) { 395 printf("Netmasks:\n"); 396 banner_printed = 1; 397 } 398 if (masks_done == 0) { 399 if (rtm->rtm_addrs != RTA_DST ) { 400 masks_done = 1; 401 af = sa->sa_family; 402 } 403 } else 404 #endif 405 af = sa->sa_family; 406 if (af != old_af) { 407 pr_family(af); 408 old_af = af; 409 } 410 if (rtm->rtm_addrs == RTA_DST) 411 p_sockaddr(sa, NULL, 0, 36); 412 else { 413 p_sockaddr(sa, NULL, rtm->rtm_flags, 16); 414 sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa); 415 p_sockaddr(sa, NULL, 0, 18); 416 } 417 p_flags(rtm->rtm_flags & interesting, "%-6.6s "); 418 putchar('\n'); 419 } 420 421 static void 422 p_sockaddr(sa, mask, flags, width) 423 struct sockaddr *sa, *mask; 424 int flags, width; 425 { 426 char workbuf[128], *cplim; 427 register char *cp = workbuf; 428 429 switch(sa->sa_family) { 430 case AF_INET: 431 { 432 register struct sockaddr_in *sin = (struct sockaddr_in *)sa; 433 434 if ((sin->sin_addr.s_addr == INADDR_ANY) && 435 mask && 436 ntohl(((struct sockaddr_in *)mask)->sin_addr.s_addr) 437 ==0L) 438 cp = "default" ; 439 else if (flags & RTF_HOST) 440 cp = routename(sin->sin_addr.s_addr); 441 else if (mask) 442 cp = netname(sin->sin_addr.s_addr, 443 ntohl(((struct sockaddr_in *)mask) 444 ->sin_addr.s_addr)); 445 else 446 cp = netname(sin->sin_addr.s_addr, 0L); 447 break; 448 } 449 450 #ifdef INET6 451 case AF_INET6: 452 { 453 struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; 454 struct in6_addr *in6 = &sa6->sin6_addr; 455 456 /* 457 * XXX: This is a special workaround for KAME kernels. 458 * sin6_scope_id field of SA should be set in the future. 459 */ 460 if (IN6_IS_ADDR_LINKLOCAL(in6) || 461 IN6_IS_ADDR_MC_LINKLOCAL(in6)) { 462 /* XXX: override is ok? */ 463 sa6->sin6_scope_id = (u_int32_t)ntohs(*(u_short *)&in6->s6_addr[2]); 464 *(u_short *)&in6->s6_addr[2] = 0; 465 } 466 467 if (flags & RTF_HOST) 468 cp = routename6(sa6); 469 else if (mask) 470 cp = netname6(sa6, 471 &((struct sockaddr_in6 *)mask)->sin6_addr); 472 else { 473 cp = netname6(sa6, NULL); 474 } 475 break; 476 } 477 #endif /*INET6*/ 478 479 case AF_IPX: 480 { 481 struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr; 482 if (ipx_nullnet(satoipx_addr(work))) 483 cp = "default"; 484 else 485 cp = ipx_print(sa); 486 break; 487 } 488 case AF_APPLETALK: 489 { 490 if (!(flags & RTF_HOST) && mask) 491 cp = atalk_print2(sa,mask,9); 492 else 493 cp = atalk_print(sa,11); 494 break; 495 } 496 case AF_NETGRAPH: 497 { 498 printf("%s", ((struct sockaddr_ng *)sa)->sg_data); 499 break; 500 } 501 #ifdef NS 502 case AF_NS: 503 cp = ns_print(sa); 504 break; 505 #endif 506 507 case AF_LINK: 508 { 509 register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; 510 511 if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && 512 sdl->sdl_slen == 0) 513 (void) sprintf(workbuf, "link#%d", sdl->sdl_index); 514 else 515 switch (sdl->sdl_type) { 516 517 case IFT_ETHER: 518 { 519 register int i; 520 register u_char *lla = (u_char *)sdl->sdl_data + 521 sdl->sdl_nlen; 522 523 cplim = ""; 524 for (i = 0; i < sdl->sdl_alen; i++, lla++) { 525 cp += sprintf(cp, "%s%x", cplim, *lla); 526 cplim = ":"; 527 } 528 cp = workbuf; 529 break; 530 } 531 532 default: 533 cp = link_ntoa(sdl); 534 break; 535 } 536 break; 537 } 538 539 default: 540 { 541 register u_char *s = (u_char *)sa->sa_data, *slim; 542 543 slim = sa->sa_len + (u_char *) sa; 544 cplim = cp + sizeof(workbuf) - 6; 545 cp += sprintf(cp, "(%d)", sa->sa_family); 546 while (s < slim && cp < cplim) { 547 cp += sprintf(cp, " %02x", *s++); 548 if (s < slim) 549 cp += sprintf(cp, "%02x", *s++); 550 } 551 cp = workbuf; 552 } 553 } 554 if (width < 0 ) 555 printf("%s ", cp); 556 else { 557 if (nflag) 558 printf("%-*s ", width, cp); 559 else 560 printf("%-*.*s ", width, width, cp); 561 } 562 } 563 564 static void 565 p_flags(f, format) 566 register int f; 567 char *format; 568 { 569 char name[33], *flags; 570 register struct bits *p = bits; 571 572 for (flags = name; p->b_mask; p++) 573 if (p->b_mask & f) 574 *flags++ = p->b_val; 575 *flags = '\0'; 576 printf(format, name); 577 } 578 579 static void 580 p_rtentry(rt) 581 register struct rtentry *rt; 582 { 583 static struct ifnet ifnet, *lastif; 584 static char name[16]; 585 static char prettyname[9]; 586 struct sockaddr *sa; 587 sa_u addr, mask; 588 589 /* 590 * Don't print protocol-cloned routes unless -a. 591 */ 592 if (rt->rt_parent && !aflag) 593 return; 594 595 bzero(&addr, sizeof(addr)); 596 if ((sa = kgetsa(rt_key(rt)))) 597 bcopy(sa, &addr, sa->sa_len); 598 bzero(&mask, sizeof(mask)); 599 if (rt_mask(rt) && (sa = kgetsa(rt_mask(rt)))) 600 bcopy(sa, &mask, sa->sa_len); 601 p_sockaddr(&addr.u_sa, &mask.u_sa, rt->rt_flags, 602 WID_DST(addr.u_sa.sa_family)); 603 p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, 604 WID_GW(addr.u_sa.sa_family)); 605 p_flags(rt->rt_flags, "%-6.6s "); 606 if (addr.u_sa.sa_family == AF_INET || lflag) 607 printf("%6ld %8ld ", rt->rt_refcnt, rt->rt_use); 608 if (rt->rt_ifp) { 609 if (rt->rt_ifp != lastif) { 610 kget(rt->rt_ifp, ifnet); 611 kread((u_long)ifnet.if_name, name, 16); 612 lastif = rt->rt_ifp; 613 snprintf(prettyname, sizeof prettyname, 614 "%s%d", name, ifnet.if_unit); 615 } 616 printf("%8.8s", prettyname); 617 if (rt->rt_rmx.rmx_expire) { 618 time_t expire_time; 619 620 if ((expire_time = 621 rt->rt_rmx.rmx_expire - time((time_t *)0)) > 0) 622 printf(" %6d%s", (int)expire_time, 623 rt->rt_nodes[0].rn_dupedkey ? " =>" : ""); 624 else 625 goto ifandkey; 626 } else if (rt->rt_nodes[0].rn_dupedkey) { 627 ifandkey:; 628 printf(" =>"); 629 } 630 631 } 632 putchar('\n'); 633 } 634 635 char * 636 routename(in) 637 u_long in; 638 { 639 register char *cp; 640 static char line[MAXHOSTNAMELEN + 1]; 641 struct hostent *hp; 642 643 cp = 0; 644 if (!nflag) { 645 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 646 AF_INET); 647 if (hp) { 648 cp = hp->h_name; 649 trimdomain(cp); 650 } 651 } 652 if (cp) { 653 strncpy(line, cp, sizeof(line) - 1); 654 line[sizeof(line) - 1] = '\0'; 655 } else { 656 #define C(x) ((x) & 0xff) 657 in = ntohl(in); 658 sprintf(line, "%lu.%lu.%lu.%lu", 659 C(in >> 24), C(in >> 16), C(in >> 8), C(in)); 660 } 661 return (line); 662 } 663 664 static u_long 665 forgemask(a) 666 u_long a; 667 { 668 u_long m; 669 670 if (IN_CLASSA(a)) 671 m = IN_CLASSA_NET; 672 else if (IN_CLASSB(a)) 673 m = IN_CLASSB_NET; 674 else 675 m = IN_CLASSC_NET; 676 return (m); 677 } 678 679 static void 680 domask(dst, addr, mask) 681 char *dst; 682 u_long addr, mask; 683 { 684 register int b, i; 685 686 if (!mask || (forgemask(addr) == mask)) { 687 *dst = '\0'; 688 return; 689 } 690 i = 0; 691 for (b = 0; b < 32; b++) 692 if (mask & (1 << b)) { 693 register int bb; 694 695 i = b; 696 for (bb = b+1; bb < 32; bb++) 697 if (!(mask & (1 << bb))) { 698 i = -1; /* noncontig */ 699 break; 700 } 701 break; 702 } 703 if (i == -1) 704 sprintf(dst, "&0x%lx", mask); 705 else 706 sprintf(dst, "/%d", 32-i); 707 } 708 709 /* 710 * Return the name of the network whose address is given. 711 * The address is assumed to be that of a net or subnet, not a host. 712 */ 713 char * 714 netname(in, mask) 715 u_long in, mask; 716 { 717 char *cp = 0; 718 static char line[MAXHOSTNAMELEN + 1]; 719 struct netent *np = 0; 720 u_long net, omask, dmask; 721 register u_long i; 722 723 i = ntohl(in); 724 omask = mask; 725 if (!nflag && i) { 726 dmask = forgemask(i); 727 net = i & dmask; 728 if (!(np = getnetbyaddr(i, AF_INET)) && net != i) 729 np = getnetbyaddr(net, AF_INET); 730 if (np) { 731 cp = np->n_name; 732 trimdomain(cp); 733 } 734 } 735 if (cp) 736 strncpy(line, cp, sizeof(line) - 1); 737 else if ((i & 0xffffff) == 0) 738 sprintf(line, "%lu", C(i >> 24)); 739 else if ((i & 0xffff) == 0) 740 sprintf(line, "%lu.%lu", C(i >> 24) , C(i >> 16)); 741 else if ((i & 0xff) == 0) 742 sprintf(line, "%lu.%lu.%lu", C(i >> 24), C(i >> 16), C(i >> 8)); 743 else 744 sprintf(line, "%lu.%lu.%lu.%lu", C(i >> 24), 745 C(i >> 16), C(i >> 8), C(i)); 746 domask(line+strlen(line), i, omask); 747 return (line); 748 } 749 750 #ifdef INET6 751 char * 752 netname6(sa6, mask) 753 struct sockaddr_in6 *sa6; 754 struct in6_addr *mask; 755 { 756 static char line[MAXHOSTNAMELEN + 1]; 757 u_char *p = (u_char *)mask; 758 u_char *lim; 759 int masklen, illegal = 0, flag = NI_WITHSCOPEID; 760 761 if (mask) { 762 for (masklen = 0, lim = p + 16; p < lim; p++) { 763 switch (*p) { 764 case 0xff: 765 masklen += 8; 766 break; 767 case 0xfe: 768 masklen += 7; 769 break; 770 case 0xfc: 771 masklen += 6; 772 break; 773 case 0xf8: 774 masklen += 5; 775 break; 776 case 0xf0: 777 masklen += 4; 778 break; 779 case 0xe0: 780 masklen += 3; 781 break; 782 case 0xc0: 783 masklen += 2; 784 break; 785 case 0x80: 786 masklen += 1; 787 break; 788 case 0x00: 789 break; 790 default: 791 illegal ++; 792 break; 793 } 794 } 795 if (illegal) 796 fprintf(stderr, "illegal prefixlen\n"); 797 } 798 else 799 masklen = 128; 800 801 if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr)) 802 return("default"); 803 804 if (nflag) 805 flag |= NI_NUMERICHOST; 806 getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line), 807 NULL, 0, flag); 808 809 if (nflag) 810 sprintf(&line[strlen(line)], "/%d", masklen); 811 812 return line; 813 } 814 815 char * 816 routename6(sa6) 817 struct sockaddr_in6 *sa6; 818 { 819 static char line[MAXHOSTNAMELEN + 1]; 820 int flag = NI_WITHSCOPEID; 821 /* use local variable for safety */ 822 struct sockaddr_in6 sa6_local = {AF_INET6, sizeof(sa6_local),}; 823 824 sa6_local.sin6_addr = sa6->sin6_addr; 825 sa6_local.sin6_scope_id = sa6->sin6_scope_id; 826 827 if (nflag) 828 flag |= NI_NUMERICHOST; 829 830 getnameinfo((struct sockaddr *)&sa6_local, sa6_local.sin6_len, 831 line, sizeof(line), NULL, 0, flag); 832 833 return line; 834 } 835 #endif /*INET6*/ 836 837 /* 838 * Print routing statistics 839 */ 840 void 841 rt_stats(off) 842 u_long off; 843 { 844 struct rtstat rtstat; 845 846 if (off == 0) { 847 printf("rtstat: symbol not in namelist\n"); 848 return; 849 } 850 kread(off, (char *)&rtstat, sizeof (rtstat)); 851 printf("routing:\n"); 852 printf("\t%u bad routing redirect%s\n", 853 rtstat.rts_badredirect, plural(rtstat.rts_badredirect)); 854 printf("\t%u dynamically created route%s\n", 855 rtstat.rts_dynamic, plural(rtstat.rts_dynamic)); 856 printf("\t%u new gateway%s due to redirects\n", 857 rtstat.rts_newgateway, plural(rtstat.rts_newgateway)); 858 printf("\t%u destination%s found unreachable\n", 859 rtstat.rts_unreach, plural(rtstat.rts_unreach)); 860 printf("\t%u use%s of a wildcard route\n", 861 rtstat.rts_wildcard, plural(rtstat.rts_wildcard)); 862 } 863 864 char * 865 ipx_print(sa) 866 register struct sockaddr *sa; 867 { 868 u_short port; 869 struct servent *sp = 0; 870 char *net = "", *host = ""; 871 register char *p; 872 register u_char *q; 873 struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr; 874 static char mybuf[50]; 875 char cport[10], chost[15], cnet[15]; 876 877 port = ntohs(work.x_port); 878 879 if (ipx_nullnet(work) && ipx_nullhost(work)) { 880 881 if (port) { 882 if (sp) 883 sprintf(mybuf, "*.%s", sp->s_name); 884 else 885 sprintf(mybuf, "*.%x", port); 886 } else 887 sprintf(mybuf, "*.*"); 888 889 return (mybuf); 890 } 891 892 if (ipx_wildnet(work)) 893 net = "any"; 894 else if (ipx_nullnet(work)) 895 net = "*"; 896 else { 897 q = work.x_net.c_net; 898 sprintf(cnet, "%02x%02x%02x%02x", 899 q[0], q[1], q[2], q[3]); 900 for (p = cnet; *p == '0' && p < cnet + 8; p++) 901 continue; 902 net = p; 903 } 904 905 if (ipx_wildhost(work)) 906 host = "any"; 907 else if (ipx_nullhost(work)) 908 host = "*"; 909 else { 910 q = work.x_host.c_host; 911 sprintf(chost, "%02x%02x%02x%02x%02x%02x", 912 q[0], q[1], q[2], q[3], q[4], q[5]); 913 for (p = chost; *p == '0' && p < chost + 12; p++) 914 continue; 915 host = p; 916 } 917 918 if (port) { 919 if (strcmp(host, "*") == 0) 920 host = ""; 921 if (sp) 922 snprintf(cport, sizeof(cport), 923 "%s%s", *host ? "." : "", sp->s_name); 924 else 925 snprintf(cport, sizeof(cport), 926 "%s%x", *host ? "." : "", port); 927 } else 928 *cport = 0; 929 930 snprintf(mybuf, sizeof(mybuf), "%s.%s%s", net, host, cport); 931 return(mybuf); 932 } 933 934 char * 935 ipx_phost(sa) 936 struct sockaddr *sa; 937 { 938 register struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)sa; 939 struct sockaddr_ipx work; 940 static union ipx_net ipx_zeronet; 941 char *p; 942 struct ipx_addr in; 943 944 work = *sipx; 945 in = work.sipx_addr; 946 947 work.sipx_addr.x_port = 0; 948 work.sipx_addr.x_net = ipx_zeronet; 949 p = ipx_print((struct sockaddr *)&work); 950 if (strncmp("*.", p, 2) == 0) p += 2; 951 952 return(p); 953 } 954 955 #ifdef NS 956 short ns_nullh[] = {0,0,0}; 957 short ns_bh[] = {-1,-1,-1}; 958 959 char * 960 ns_print(sa) 961 register struct sockaddr *sa; 962 { 963 register struct sockaddr_ns *sns = (struct sockaddr_ns*)sa; 964 struct ns_addr work; 965 union { union ns_net net_e; u_long long_e; } net; 966 u_short port; 967 static char mybuf[50], cport[10], chost[25]; 968 char *host = ""; 969 register char *p; register u_char *q; 970 971 work = sns->sns_addr; 972 port = ntohs(work.x_port); 973 work.x_port = 0; 974 net.net_e = work.x_net; 975 if (ns_nullhost(work) && net.long_e == 0) { 976 if (port ) { 977 sprintf(mybuf, "*.%xH", port); 978 upHex(mybuf); 979 } else 980 sprintf(mybuf, "*.*"); 981 return (mybuf); 982 } 983 984 if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) { 985 host = "any"; 986 } else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) { 987 host = "*"; 988 } else { 989 q = work.x_host.c_host; 990 sprintf(chost, "%02x%02x%02x%02x%02x%02xH", 991 q[0], q[1], q[2], q[3], q[4], q[5]); 992 for (p = chost; *p == '0' && p < chost + 12; p++) 993 continue; 994 host = p; 995 } 996 if (port) 997 sprintf(cport, ".%xH", htons(port)); 998 else 999 *cport = 0; 1000 1001 sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport); 1002 upHex(mybuf); 1003 return(mybuf); 1004 } 1005 1006 char * 1007 ns_phost(sa) 1008 struct sockaddr *sa; 1009 { 1010 register struct sockaddr_ns *sns = (struct sockaddr_ns *)sa; 1011 struct sockaddr_ns work; 1012 static union ns_net ns_zeronet; 1013 char *p; 1014 1015 work = *sns; 1016 work.sns_addr.x_port = 0; 1017 work.sns_addr.x_net = ns_zeronet; 1018 1019 p = ns_print((struct sockaddr *)&work); 1020 if (strncmp("0H.", p, 3) == 0) 1021 p += 3; 1022 return(p); 1023 } 1024 #endif 1025 1026 void 1027 upHex(p0) 1028 char *p0; 1029 { 1030 register char *p = p0; 1031 1032 for (; *p; p++) 1033 switch (*p) { 1034 1035 case 'a': 1036 case 'b': 1037 case 'c': 1038 case 'd': 1039 case 'e': 1040 case 'f': 1041 *p += ('A' - 'a'); 1042 break; 1043 } 1044 } 1045