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