1 /* $OpenBSD: route.c,v 1.40 2001/06/25 00:41:39 niklas 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.40 2001/06/25 00:41:39 niklas 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 register 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 register 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 register struct rt_msghdr *rtm; 391 { 392 register 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 register char *cp = workbuf; 435 size_t n; 436 437 switch (sa->sa_family) { 438 case AF_INET: 439 { 440 register struct sockaddr_in *sin = (struct sockaddr_in *)sa; 441 register struct sockaddr_in *msin = (struct sockaddr_in *)mask; 442 443 cp = (sin->sin_addr.s_addr == 0) ? "default" : 444 ((flags & RTF_HOST) ? 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 register 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 register int i; 501 register 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 if (n >= workbuf + sizeof (workbuf) - cp) 510 n = workbuf + sizeof (workbuf) - cp - 1; 511 cp += n; 512 cplim = ":"; 513 } 514 cp = workbuf; 515 break; 516 } 517 default: 518 cp = link_ntoa(sdl); 519 break; 520 } 521 break; 522 } 523 524 case AF_APPLETALK: 525 { 526 /* XXX could do better */ 527 cp = atalk_print(sa,11); 528 break; 529 } 530 default: 531 { 532 register u_char *s = (u_char *)sa->sa_data, *slim; 533 534 slim = sa->sa_len + (u_char *) sa; 535 cplim = cp + sizeof(workbuf) - 6; 536 n = snprintf(cp, cplim - cp, "(%d)", sa->sa_family); 537 if (n >= cplim - cp) 538 n = cplim - cp - 1; 539 cp += n; 540 while (s < slim && cp < cplim) { 541 n = snprintf(cp, workbuf + sizeof (workbuf) - cp, 542 " %02x", *s++); 543 if (n >= workbuf + sizeof (workbuf) - cp) 544 n = workbuf + sizeof (workbuf) - cp - 1; 545 cp += n; 546 if (s < slim) { 547 n = snprintf(cp, 548 workbuf + sizeof (workbuf) - cp, 549 "%02x", *s++); 550 if (n >= workbuf + sizeof (workbuf) - cp) 551 n = workbuf + sizeof (workbuf) - cp - 1; 552 cp += n; 553 } 554 } 555 cp = workbuf; 556 } 557 } 558 if (width < 0 ) 559 printf("%s ", cp); 560 else { 561 if (nflag) 562 printf("%-*s ", width, cp); 563 else 564 printf("%-*.*s ", width, width, cp); 565 } 566 } 567 568 static void 569 p_flags(f, format) 570 register int f; 571 char *format; 572 { 573 char name[33], *flags; 574 register struct bits *p = bits; 575 576 for (flags = name; p->b_mask; p++) 577 if (p->b_mask & f) 578 *flags++ = p->b_val; 579 *flags = '\0'; 580 printf(format, name); 581 } 582 583 static void 584 p_rtentry(rt) 585 register struct rtentry *rt; 586 { 587 static struct ifnet ifnet, *lastif; 588 struct sockaddr_storage sock1, sock2; 589 struct sockaddr *sa = (struct sockaddr *)&sock1; 590 struct sockaddr *mask = (struct sockaddr *)&sock2; 591 592 bcopy(kgetsa(rt_key(rt)), sa, sizeof(struct sockaddr)); 593 if (sa->sa_len > sizeof(struct sockaddr)) 594 bcopy(kgetsa(rt_key(rt)), sa, sa->sa_len); 595 596 if (sa->sa_family == PF_KEY) { 597 encap_print(rt); 598 return; 599 } 600 601 if (rt_mask(rt)) { 602 bcopy(kgetsa(rt_mask(rt)), mask, sizeof(struct sockaddr)); 603 if (sa->sa_len > sizeof(struct sockaddr)) 604 bcopy(kgetsa(rt_mask(rt)), mask, sa->sa_len); 605 } else 606 mask = 0; 607 608 p_sockaddr(sa, mask, rt->rt_flags, WID_DST(sa->sa_family)); 609 p_sockaddr(kgetsa(rt->rt_gateway), 0, RTF_HOST, WID_GW(sa->sa_family)); 610 p_flags(rt->rt_flags, "%-6.6s "); 611 printf("%6d %8ld ", rt->rt_refcnt, rt->rt_use); 612 if (rt->rt_rmx.rmx_mtu) 613 printf("%6ld ", rt->rt_rmx.rmx_mtu); 614 else 615 printf("%6s ", "-"); 616 putchar((rt->rt_rmx.rmx_locks & RTV_MTU) ? 'L' : ' '); 617 if (rt->rt_ifp) { 618 if (rt->rt_ifp != lastif) { 619 kget(rt->rt_ifp, ifnet); 620 lastif = rt->rt_ifp; 621 } 622 printf(" %.16s%s", ifnet.if_xname, 623 rt->rt_nodes[0].rn_dupedkey ? " =>" : ""); 624 } 625 putchar('\n'); 626 if (vflag) { 627 printf("\texpire %10lu%c recvpipe %10ld%c " 628 "sendpipe %10ld%c\n", 629 rt->rt_rmx.rmx_expire, 630 (rt->rt_rmx.rmx_locks & RTV_EXPIRE) ? 'L' : ' ', 631 rt->rt_rmx.rmx_recvpipe, 632 (rt->rt_rmx.rmx_locks & RTV_RPIPE) ? 'L' : ' ', 633 rt->rt_rmx.rmx_sendpipe, 634 (rt->rt_rmx.rmx_locks & RTV_SPIPE) ? 'L' : ' '); 635 printf("\tssthresh %10lu%c rtt %10ld%c " 636 "rttvar %10ld%c\n", 637 rt->rt_rmx.rmx_ssthresh, 638 (rt->rt_rmx.rmx_locks & RTV_SSTHRESH) ? 'L' : ' ', 639 rt->rt_rmx.rmx_rtt, 640 (rt->rt_rmx.rmx_locks & RTV_RTT) ? 'L' : ' ', 641 rt->rt_rmx.rmx_rttvar, 642 (rt->rt_rmx.rmx_locks & RTV_RTTVAR) ? 'L' : ' '); 643 } 644 } 645 646 char * 647 routename(in) 648 in_addr_t in; 649 { 650 register char *cp; 651 static char line[MAXHOSTNAMELEN]; 652 struct hostent *hp; 653 static char domain[MAXHOSTNAMELEN]; 654 static int first = 1; 655 656 if (first) { 657 first = 0; 658 if (gethostname(domain, sizeof domain) == 0 && 659 (cp = strchr(domain, '.'))) 660 (void) strcpy(domain, cp + 1); 661 else 662 domain[0] = 0; 663 } 664 cp = 0; 665 if (!nflag) { 666 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 667 AF_INET); 668 if (hp) { 669 if ((cp = strchr(hp->h_name, '.')) && 670 !strcmp(cp + 1, domain)) 671 *cp = 0; 672 cp = hp->h_name; 673 } 674 } 675 if (cp) { 676 strncpy(line, cp, sizeof(line) - 1); 677 line[sizeof(line) - 1] = '\0'; 678 } else { 679 #define C(x) ((x) & 0xff) 680 in = ntohl(in); 681 snprintf(line, sizeof line, "%u.%u.%u.%u", 682 C(in >> 24), C(in >> 16), C(in >> 8), C(in)); 683 } 684 return (line); 685 } 686 687 /* 688 * Return the name of the network whose address is given. 689 * The address is assumed to be that of a net or subnet, not a host. 690 */ 691 char * 692 netname(in, mask) 693 in_addr_t in, mask; 694 { 695 char *cp = 0; 696 static char line[MAXHOSTNAMELEN]; 697 struct netent *np = 0; 698 int mbits; 699 700 in = ntohl(in); 701 mask = ntohl(mask); 702 if (!nflag && in != INADDR_ANY) { 703 if ((np = getnetbyaddr(in, AF_INET)) != NULL) 704 cp = np->n_name; 705 } 706 mbits = mask ? 33 - ffs(mask) : 0; 707 if (cp) { 708 strncpy(line, cp, sizeof(line) - 1); 709 line[sizeof(line) - 1] = '\0'; 710 } else if (mbits < 9) 711 snprintf(line, sizeof line, "%u/%d", C(in >> 24), mbits); 712 else if (mbits < 17) 713 snprintf(line, sizeof line, "%u.%u/%d", 714 C(in >> 24) , C(in >> 16), mbits); 715 else if (mbits < 25) 716 snprintf(line, sizeof line, "%u.%u.%u/%d", 717 C(in >> 24), C(in >> 16), C(in >> 8), mbits); 718 else 719 snprintf(line, sizeof line, "%u.%u.%u.%u/%d", C(in >> 24), 720 C(in >> 16), C(in >> 8), C(in), mbits); 721 return (line); 722 } 723 724 #ifdef INET6 725 char * 726 netname6(sa6, mask) 727 struct sockaddr_in6 *sa6; 728 struct in6_addr *mask; 729 { 730 static char line[MAXHOSTNAMELEN + 1]; 731 struct sockaddr_in6 sin6; 732 u_char *p; 733 u_char *lim; 734 int masklen, final = 0, illegal = 0; 735 int i; 736 char hbuf[NI_MAXHOST]; 737 #ifdef NI_WITHSCOPEID 738 int flag = NI_WITHSCOPEID; 739 #else 740 int flag = 0; 741 #endif 742 int error; 743 744 sin6 = *sa6; 745 746 masklen = 0; 747 lim = (u_char *)(mask + 1); 748 i = 0; 749 if (mask) { 750 for (p = (u_char *)mask; p < lim; p++) { 751 if (final && *p) { 752 illegal++; 753 sin6.sin6_addr.s6_addr[i++] = 0x00; 754 continue; 755 } 756 757 switch (*p & 0xff) { 758 case 0xff: 759 masklen += 8; 760 break; 761 case 0xfe: 762 masklen += 7; 763 final++; 764 break; 765 case 0xfc: 766 masklen += 6; 767 final++; 768 break; 769 case 0xf8: 770 masklen += 5; 771 final++; 772 break; 773 case 0xf0: 774 masklen += 4; 775 final++; 776 break; 777 case 0xe0: 778 masklen += 3; 779 final++; 780 break; 781 case 0xc0: 782 masklen += 2; 783 final++; 784 break; 785 case 0x80: 786 masklen += 1; 787 final++; 788 break; 789 case 0x00: 790 final++; 791 break; 792 default: 793 final++; 794 illegal++; 795 break; 796 } 797 798 if (!illegal) 799 sin6.sin6_addr.s6_addr[i++] &= *p; 800 else 801 sin6.sin6_addr.s6_addr[i++] = 0x00; 802 } 803 } else 804 masklen = 128; 805 806 if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) 807 return("default"); 808 809 if (illegal) 810 fprintf(stderr, "illegal prefixlen\n"); 811 812 if (nflag) 813 flag |= NI_NUMERICHOST; 814 error = getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 815 hbuf, sizeof(hbuf), NULL, 0, flag); 816 if (error) 817 snprintf(hbuf, sizeof(hbuf), "invalid"); 818 819 snprintf(line, sizeof(line), "%s/%d", hbuf, masklen); 820 return line; 821 } 822 823 char * 824 routename6(sa6) 825 struct sockaddr_in6 *sa6; 826 { 827 static char line[NI_MAXHOST]; 828 #ifdef NI_WITHSCOPEID 829 const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID; 830 #else 831 const int niflag = NI_NUMERICHOST; 832 #endif 833 if (getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, 834 line, sizeof(line), NULL, 0, niflag) != 0) 835 strcpy(line, ""); 836 return line; 837 } 838 #endif /*INET6*/ 839 840 /* 841 * Print routing statistics 842 */ 843 void 844 rt_stats(off) 845 u_long off; 846 { 847 struct rtstat rtstat; 848 849 if (off == 0) { 850 printf("rtstat: symbol not in namelist\n"); 851 return; 852 } 853 kread(off, (char *)&rtstat, sizeof (rtstat)); 854 printf("routing:\n"); 855 printf("\t%u bad routing redirect%s\n", 856 rtstat.rts_badredirect, plural(rtstat.rts_badredirect)); 857 printf("\t%u dynamically created route%s\n", 858 rtstat.rts_dynamic, plural(rtstat.rts_dynamic)); 859 printf("\t%u new gateway%s due to redirects\n", 860 rtstat.rts_newgateway, plural(rtstat.rts_newgateway)); 861 printf("\t%u destination%s found unreachable\n", 862 rtstat.rts_unreach, plural(rtstat.rts_unreach)); 863 printf("\t%u use%s of a wildcard route\n", 864 rtstat.rts_wildcard, plural(rtstat.rts_wildcard)); 865 } 866 867 short ns_nullh[] = {0,0,0}; 868 short ns_bh[] = {-1,-1,-1}; 869 870 char * 871 ns_print(sa) 872 register struct sockaddr *sa; 873 { 874 register struct sockaddr_ns *sns = (struct sockaddr_ns*)sa; 875 struct ns_addr work; 876 union { union ns_net net_e; u_long long_e; } net; 877 in_port_t port; 878 static char mybuf[50], cport[10], chost[25]; 879 char *host = ""; 880 register char *p; register u_char *q; 881 882 work = sns->sns_addr; 883 port = ntohs(work.x_port); 884 work.x_port = 0; 885 net.net_e = work.x_net; 886 if (ns_nullhost(work) && net.long_e == 0) { 887 if (port ) { 888 snprintf(mybuf, sizeof mybuf, "*.%xH", port); 889 upHex(mybuf); 890 } else 891 snprintf(mybuf, sizeof mybuf, "*.*"); 892 return (mybuf); 893 } 894 895 if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) { 896 host = "any"; 897 } else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) { 898 host = "*"; 899 } else { 900 q = work.x_host.c_host; 901 snprintf(chost, sizeof chost, "%02x%02x%02x%02x%02x%02xH", 902 q[0], q[1], q[2], q[3], q[4], q[5]); 903 for (p = chost; *p == '0' && p < chost + 12; p++) 904 continue; 905 host = p; 906 } 907 if (port) 908 snprintf(cport, sizeof cport, ".%xH", htons(port)); 909 else 910 *cport = 0; 911 912 snprintf(mybuf, sizeof mybuf, "%xH.%s%s", ntohl(net.long_e), 913 host, cport); 914 upHex(mybuf); 915 return(mybuf); 916 } 917 918 char * 919 ns_phost(sa) 920 struct sockaddr *sa; 921 { 922 register struct sockaddr_ns *sns = (struct sockaddr_ns *)sa; 923 struct sockaddr_ns work; 924 static union ns_net ns_zeronet; 925 char *p; 926 927 work = *sns; 928 work.sns_addr.x_port = 0; 929 work.sns_addr.x_net = ns_zeronet; 930 931 p = ns_print((struct sockaddr *)&work); 932 if (strncmp("0H.", p, 3) == 0) p += 3; 933 return(p); 934 } 935 936 u_short ipx_nullh[] = {0,0,0}; 937 u_short ipx_bh[] = {0xffff,0xffff,0xffff}; 938 939 char * 940 ipx_print(sa) 941 register struct sockaddr *sa; 942 { 943 register struct sockaddr_ipx *sipx = (struct sockaddr_ipx*)sa; 944 struct ipx_addr work; 945 union { union ipx_net net_e; u_long long_e; } net; 946 in_port_t port; 947 static char mybuf[50], cport[10], chost[25]; 948 char *host = ""; 949 register char *q; 950 951 work = sipx->sipx_addr; 952 port = ntohs(work.ipx_port); 953 work.ipx_port = 0; 954 net.net_e = work.ipx_net; 955 if (ipx_nullhost(work) && net.long_e == 0) { 956 if (port != 0) { 957 snprintf(mybuf, sizeof mybuf, "*.%xH", port); 958 upHex(mybuf); 959 } else 960 snprintf(mybuf, sizeof mybuf, "*.*"); 961 return (mybuf); 962 } 963 964 if (bcmp(ipx_bh, work.ipx_host.c_host, 6) == 0) { 965 host = "any"; 966 } else if (bcmp(ipx_nullh, work.ipx_host.c_host, 6) == 0) { 967 host = "*"; 968 } else { 969 q = work.ipx_host.c_host; 970 snprintf(chost, sizeof chost, "%02x:%02x:%02x:%02x:%02x:%02x", 971 q[0], q[1], q[2], q[3], q[4], q[5]); 972 host = chost; 973 } 974 if (port) 975 snprintf(cport, sizeof cport, ".%xH", htons(port)); 976 else 977 *cport = 0; 978 979 snprintf(mybuf, sizeof mybuf, "%xH.%s%s", ntohl(net.long_e), 980 host, cport); 981 upHex(mybuf); 982 return(mybuf); 983 } 984 985 char * 986 ipx_phost(sa) 987 struct sockaddr *sa; 988 { 989 register struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)sa; 990 struct sockaddr_ipx work; 991 static union ipx_net ipx_zeronet; 992 char *p; 993 994 work = *sipx; 995 work.sipx_addr.ipx_port = 0; 996 work.sipx_addr.ipx_net = ipx_zeronet; 997 998 p = ipx_print((struct sockaddr *)&work); 999 if (strncmp("0H.", p, 3) == 0) p += 3; 1000 return(p); 1001 } 1002 1003 static void 1004 encap_print(rt) 1005 register struct rtentry *rt; 1006 { 1007 struct sockaddr_encap sen1, sen2, sen3; 1008 struct ipsec_policy ipo; 1009 1010 #ifdef INET6 1011 struct sockaddr_in6 s61, s62; 1012 char ip6addr[64]; 1013 #endif /* INET6 */ 1014 1015 bcopy(kgetsa(rt_key(rt)), &sen1, sizeof(sen1)); 1016 bcopy(kgetsa(rt_mask(rt)), &sen2, sizeof(sen2)); 1017 bcopy(kgetsa(rt->rt_gateway), &sen3, sizeof(sen3)); 1018 1019 if (sen1.sen_type == SENT_IP4) 1020 { 1021 printf("%-18s %-5u ", netname(sen1.sen_ip_src.s_addr, 1022 sen2.sen_ip_src.s_addr), 1023 ntohs(sen1.sen_sport)); 1024 1025 printf("%-18s %-5u %-5u ", netname(sen1.sen_ip_dst.s_addr, 1026 sen2.sen_ip_dst.s_addr), 1027 ntohs(sen1.sen_dport), sen1.sen_proto); 1028 } 1029 1030 #ifdef INET6 1031 if (sen1.sen_type == SENT_IP6) 1032 { 1033 bzero(&s61, sizeof(s61)); 1034 bzero(&s62, sizeof(s62)); 1035 s61.sin6_family = s62.sin6_family = AF_INET6; 1036 s61.sin6_len = s62.sin6_len = sizeof(s61); 1037 bcopy(&sen1.sen_ip6_src, &s61.sin6_addr, sizeof(struct in6_addr)); 1038 bcopy(&sen2.sen_ip6_src, &s62.sin6_addr, sizeof(struct in6_addr)); 1039 1040 printf("%-42s %-5u ", netname6(&s61, &s62.sin6_addr), 1041 ntohs(sen1.sen_ip6_sport)); 1042 1043 bzero(&s61, sizeof(s61)); 1044 bzero(&s62, sizeof(s62)); 1045 s61.sin6_family = s62.sin6_family = AF_INET6; 1046 s61.sin6_len = s62.sin6_len = sizeof(s61); 1047 bcopy(&sen1.sen_ip6_dst, &s61.sin6_addr, sizeof(struct in6_addr)); 1048 bcopy(&sen2.sen_ip6_dst, &s62.sin6_addr, sizeof(struct in6_addr)); 1049 1050 printf("%-42s %-5u %-5u ", netname6(&s61, &s62.sin6_addr), 1051 ntohs(sen1.sen_ip6_dport), sen1.sen_ip6_proto); 1052 } 1053 #endif /* INET6 */ 1054 1055 if (sen3.sen_type == SENT_IPSP) 1056 { 1057 char hostn[NI_MAXHOST]; 1058 1059 kget(sen3.sen_ipsp, ipo); 1060 1061 getnameinfo(&ipo.ipo_dst.sa, ipo.ipo_dst.sa.sa_len, 1062 hostn, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); 1063 printf("%s", hostn); 1064 1065 printf("/%-u", ipo.ipo_sproto); 1066 1067 switch (ipo.ipo_type) 1068 { 1069 case IPSP_IPSEC_REQUIRE: 1070 printf("/require"); 1071 break; 1072 1073 case IPSP_IPSEC_ACQUIRE: 1074 printf("/acquire"); 1075 break; 1076 1077 case IPSP_IPSEC_USE: 1078 printf("/use"); 1079 break; 1080 1081 case IPSP_IPSEC_DONTACQ: 1082 printf("/dontacq"); 1083 break; 1084 1085 case IPSP_PERMIT: 1086 printf("/permit"); 1087 break; 1088 1089 case IPSP_DENY: 1090 printf("/deny"); 1091 break; 1092 1093 default: 1094 printf("/<unknown type!>"); 1095 } 1096 1097 if ((ipo.ipo_addr.sen_type == SENT_IP4 && 1098 ipo.ipo_addr.sen_direction == IPSP_DIRECTION_IN) || 1099 (ipo.ipo_addr.sen_type == SENT_IP6 && 1100 ipo.ipo_addr.sen_ip6_direction == IPSP_DIRECTION_IN)) 1101 printf("/in\n"); 1102 else 1103 if ((ipo.ipo_addr.sen_type == SENT_IP4 && 1104 ipo.ipo_addr.sen_direction == IPSP_DIRECTION_OUT) || 1105 (ipo.ipo_addr.sen_type == SENT_IP6 && 1106 ipo.ipo_addr.sen_ip6_direction == IPSP_DIRECTION_OUT)) 1107 printf("/out\n"); 1108 else 1109 printf("/<unknown>\n"); 1110 } 1111 } 1112 1113 void 1114 upHex(p0) 1115 char *p0; 1116 { 1117 register char *p = p0; 1118 for (; *p; p++) switch (*p) { 1119 1120 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 1121 *p += ('A' - 'a'); 1122 } 1123 } 1124