1 /* 2 * Copyright (c) 1983, 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)route.c 8.6 (Berkeley) 04/28/95"; 10 #endif /* not lint */ 11 12 #include <sys/param.h> 13 #include <sys/protosw.h> 14 #include <sys/socket.h> 15 #include <sys/mbuf.h> 16 17 #include <net/if.h> 18 #include <net/if_dl.h> 19 #include <net/if_types.h> 20 #define KERNEL 21 #include <net/route.h> 22 #undef KERNEL 23 #include <netinet/in.h> 24 25 #include <netns/ns.h> 26 27 #include <sys/sysctl.h> 28 29 #include <netdb.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <unistd.h> 34 #include "netstat.h" 35 36 #define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d))) 37 38 /* 39 * Definitions for showing gateway flags. 40 */ 41 struct bits { 42 short b_mask; 43 char b_val; 44 } bits[] = { 45 { RTF_UP, 'U' }, 46 { RTF_GATEWAY, 'G' }, 47 { RTF_HOST, 'H' }, 48 { RTF_REJECT, 'R' }, 49 { RTF_DYNAMIC, 'D' }, 50 { RTF_MODIFIED, 'M' }, 51 { RTF_DONE, 'd' }, /* Completed -- for routing messages only */ 52 { RTF_MASK, 'm' }, /* Mask Present -- for routing messages only */ 53 { RTF_CLONING, 'C' }, 54 { RTF_XRESOLVE, 'X' }, 55 { RTF_LLINFO, 'L' }, 56 { RTF_STATIC, 'S' }, 57 { RTF_PROTO1, '1' }, 58 { RTF_PROTO2, '2' }, 59 { 0 } 60 }; 61 62 static union { 63 struct sockaddr u_sa; 64 u_short u_data[128]; 65 } pt_u; 66 67 int do_rtent = 0; 68 struct rtentry rtentry; 69 struct radix_node rnode; 70 struct radix_mask rmask; 71 72 int NewTree = 0; 73 74 static struct sockaddr *kgetsa __P((struct sockaddr *)); 75 static void p_tree __P((struct radix_node *)); 76 static void p_rtnode __P(()); 77 static void ntreestuff __P(()); 78 static void np_rtentry __P((struct rt_msghdr *)); 79 static void p_sockaddr __P((struct sockaddr *, struct sockaddr *, int, int)); 80 static void p_flags __P((int, char *)); 81 static void p_rtentry __P((struct rtentry *)); 82 83 /* 84 * Print routing tables. 85 */ 86 void 87 routepr(rtree) 88 u_long rtree; 89 { 90 struct radix_node_head *rnh, head; 91 int i; 92 93 printf("Routing tables\n"); 94 95 if (Aflag == 0 && NewTree) 96 ntreestuff(); 97 else { 98 if (rtree == 0) { 99 printf("rt_tables: symbol not in namelist\n"); 100 return; 101 } 102 103 kget(rtree, rt_tables); 104 for (i = 0; i <= AF_MAX; i++) { 105 if ((rnh = rt_tables[i]) == 0) 106 continue; 107 kget(rnh, head); 108 if (i == AF_UNSPEC) { 109 if (Aflag && af == 0) { 110 printf("Netmasks:\n"); 111 p_tree(head.rnh_treetop); 112 } 113 } else if (af == AF_UNSPEC || af == i) { 114 pr_family(i); 115 do_rtent = 1; 116 pr_rthdr(); 117 p_tree(head.rnh_treetop); 118 } 119 } 120 } 121 } 122 123 /* 124 * Print address family header before a section of the routing table. 125 */ 126 void 127 pr_family(af) 128 int af; 129 { 130 char *afname; 131 132 switch (af) { 133 case AF_INET: 134 afname = "Internet"; 135 break; 136 case AF_NS: 137 afname = "XNS"; 138 break; 139 case AF_ISO: 140 afname = "ISO"; 141 break; 142 case AF_CCITT: 143 afname = "X.25"; 144 break; 145 default: 146 afname = NULL; 147 break; 148 } 149 if (afname) 150 printf("\n%s:\n", afname); 151 else 152 printf("\nProtocol Family %d:\n", af); 153 } 154 155 /* column widths; each followed by one space */ 156 #define WID_DST 16 /* width of destination column */ 157 #define WID_GW 18 /* width of gateway column */ 158 159 /* 160 * Print header for routing table columns. 161 */ 162 void 163 pr_rthdr() 164 { 165 166 if (Aflag) 167 printf("%-8.8s ","Address"); 168 printf("%-*.*s %-*.*s %-6.6s %6.6s%8.8s %s\n", 169 WID_DST, WID_DST, "Destination", 170 WID_GW, WID_GW, "Gateway", 171 "Flags", "Refs", "Use", "Interface"); 172 } 173 174 static struct sockaddr * 175 kgetsa(dst) 176 register struct sockaddr *dst; 177 { 178 179 kget(dst, pt_u.u_sa); 180 if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa)) 181 kread((u_long)dst, (char *)pt_u.u_data, pt_u.u_sa.sa_len); 182 return (&pt_u.u_sa); 183 } 184 185 static void 186 p_tree(rn) 187 struct radix_node *rn; 188 { 189 190 again: 191 kget(rn, rnode); 192 if (rnode.rn_b < 0) { 193 if (Aflag) 194 printf("%-8.8x ", rn); 195 if (rnode.rn_flags & RNF_ROOT) { 196 if (Aflag) 197 printf("(root node)%s", 198 rnode.rn_dupedkey ? " =>\n" : "\n"); 199 } else if (do_rtent) { 200 kget(rn, rtentry); 201 p_rtentry(&rtentry); 202 if (Aflag) 203 p_rtnode(); 204 } else { 205 p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key), 206 NULL, 0, 44); 207 putchar('\n'); 208 } 209 if (rn = rnode.rn_dupedkey) 210 goto again; 211 } else { 212 if (Aflag && do_rtent) { 213 printf("%-8.8x ", rn); 214 p_rtnode(); 215 } 216 rn = rnode.rn_r; 217 p_tree(rnode.rn_l); 218 p_tree(rn); 219 } 220 } 221 222 char nbuf[20]; 223 224 static void 225 p_rtnode() 226 { 227 struct radix_mask *rm = rnode.rn_mklist; 228 229 if (rnode.rn_b < 0) { 230 if (rnode.rn_mask) { 231 printf("\t mask "); 232 p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask), 233 NULL, 0, -1); 234 } else if (rm == 0) 235 return; 236 } else { 237 sprintf(nbuf, "(%d)", rnode.rn_b); 238 printf("%6.6s %8.8x : %8.8x", nbuf, rnode.rn_l, rnode.rn_r); 239 } 240 while (rm) { 241 kget(rm, rmask); 242 sprintf(nbuf, " %d refs, ", rmask.rm_refs); 243 printf(" mk = %8.8x {(%d),%s", 244 rm, -1 - rmask.rm_b, rmask.rm_refs ? nbuf : " "); 245 if (rmask.rm_flags & RNF_NORMAL) { 246 struct radix_node rnode_aux; 247 printf(" <normal>, "); 248 kget(rmask.rm_leaf, rnode_aux); 249 p_sockaddr(kgetsa((struct sockaddr *)rnode_aux.rn_mask), 250 NULL, 0, -1); 251 } else 252 p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask), 253 NULL, 0, -1); 254 putchar('}'); 255 if (rm = rmask.rm_mklist) 256 printf(" ->"); 257 } 258 putchar('\n'); 259 } 260 261 static void 262 ntreestuff() 263 { 264 size_t needed; 265 int mib[6]; 266 char *buf, *next, *lim; 267 register struct rt_msghdr *rtm; 268 269 mib[0] = CTL_NET; 270 mib[1] = PF_ROUTE; 271 mib[2] = 0; 272 mib[3] = 0; 273 mib[4] = NET_RT_DUMP; 274 mib[5] = 0; 275 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 276 { perror("route-sysctl-estimate"); exit(1);} 277 if ((buf = malloc(needed)) == 0) 278 { printf("out of space\n"); exit(1);} 279 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 280 { perror("sysctl of routing table"); exit(1);} 281 lim = buf + needed; 282 for (next = buf; next < lim; next += rtm->rtm_msglen) { 283 rtm = (struct rt_msghdr *)next; 284 np_rtentry(rtm); 285 } 286 } 287 288 static void 289 np_rtentry(rtm) 290 register struct rt_msghdr *rtm; 291 { 292 register struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 293 #ifdef notdef 294 static int masks_done, banner_printed; 295 #endif 296 static int old_af; 297 int af = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST; 298 299 #ifdef notdef 300 /* for the moment, netmasks are skipped over */ 301 if (!banner_printed) { 302 printf("Netmasks:\n"); 303 banner_printed = 1; 304 } 305 if (masks_done == 0) { 306 if (rtm->rtm_addrs != RTA_DST ) { 307 masks_done = 1; 308 af = sa->sa_family; 309 } 310 } else 311 #endif 312 af = sa->sa_family; 313 if (af != old_af) { 314 pr_family(af); 315 old_af = af; 316 } 317 if (rtm->rtm_addrs == RTA_DST) 318 p_sockaddr(sa, NULL, 0, 36); 319 else { 320 p_sockaddr(sa, NULL, rtm->rtm_flags, 16); 321 if (sa->sa_len == 0) 322 sa->sa_len = sizeof(long); 323 sa = (struct sockaddr *)(sa->sa_len + (char *)sa); 324 p_sockaddr(sa, NULL, 0, 18); 325 } 326 p_flags(rtm->rtm_flags & interesting, "%-6.6s "); 327 putchar('\n'); 328 } 329 330 static void 331 p_sockaddr(sa, mask, flags, width) 332 struct sockaddr *sa, *mask; 333 int flags, width; 334 { 335 char workbuf[128], *cplim; 336 register char *cp = workbuf; 337 338 switch(sa->sa_family) { 339 case AF_INET: 340 { 341 register struct sockaddr_in *sin = (struct sockaddr_in *)sa; 342 343 if (sin->sin_addr.s_addr == INADDR_ANY) 344 cp = "default"; 345 else if (flags & RTF_HOST) 346 cp = routename(sin->sin_addr.s_addr); 347 else if (mask) 348 cp = netname(sin->sin_addr.s_addr, 349 ntohl(((struct sockaddr_in *)mask) 350 ->sin_addr.s_addr)); 351 else 352 cp = netname(sin->sin_addr.s_addr, 0L); 353 break; 354 } 355 356 case AF_NS: 357 cp = ns_print(sa); 358 break; 359 360 case AF_LINK: 361 { 362 register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; 363 364 if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && 365 sdl->sdl_slen == 0) 366 (void) sprintf(workbuf, "link#%d", sdl->sdl_index); 367 else switch (sdl->sdl_type) { 368 case IFT_ETHER: 369 { 370 register int i; 371 register u_char *lla = (u_char *)sdl->sdl_data + 372 sdl->sdl_nlen; 373 374 cplim = ""; 375 for (i = 0; i < sdl->sdl_alen; i++, lla++) { 376 cp += sprintf(cp, "%s%x", cplim, *lla); 377 cplim = ":"; 378 } 379 cp = workbuf; 380 break; 381 } 382 default: 383 cp = link_ntoa(sdl); 384 break; 385 } 386 break; 387 } 388 389 default: 390 { 391 register u_char *s = (u_char *)sa->sa_data, *slim; 392 393 slim = sa->sa_len + (u_char *) sa; 394 cplim = cp + sizeof(workbuf) - 6; 395 cp += sprintf(cp, "(%d)", sa->sa_family); 396 while (s < slim && cp < cplim) { 397 cp += sprintf(cp, " %02x", *s++); 398 if (s < slim) 399 cp += sprintf(cp, "%02x", *s++); 400 } 401 cp = workbuf; 402 } 403 } 404 if (width < 0 ) 405 printf("%s ", cp); 406 else { 407 if (nflag) 408 printf("%-*s ", width, cp); 409 else 410 printf("%-*.*s ", width, width, cp); 411 } 412 } 413 414 static void 415 p_flags(f, format) 416 register int f; 417 char *format; 418 { 419 char name[33], *flags; 420 register struct bits *p = bits; 421 422 for (flags = name; p->b_mask; p++) 423 if (p->b_mask & f) 424 *flags++ = p->b_val; 425 *flags = '\0'; 426 printf(format, name); 427 } 428 429 static void 430 p_rtentry(rt) 431 register struct rtentry *rt; 432 { 433 static struct ifnet ifnet, *lastif; 434 static char name[16]; 435 register struct sockaddr *sa; 436 struct sockaddr addr, mask; 437 438 if (!(sa = kgetsa(rt_key(rt)))) 439 bzero(&addr, sizeof addr); 440 else 441 addr = *sa; 442 if (!rt_mask(rt) || !(sa = kgetsa(rt_mask(rt)))) 443 bzero(&mask, sizeof mask); 444 else 445 mask = *sa; 446 p_sockaddr(&addr, &mask, rt->rt_flags, WID_DST); 447 p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, WID_GW); 448 p_flags(rt->rt_flags, "%-6.6s "); 449 printf("%6d %8d ", rt->rt_refcnt, rt->rt_use); 450 if (rt->rt_ifp) { 451 if (rt->rt_ifp != lastif) { 452 kget(rt->rt_ifp, ifnet); 453 kread((u_long)ifnet.if_name, name, 16); 454 lastif = rt->rt_ifp; 455 } 456 printf(" %.15s%d%s", name, ifnet.if_unit, 457 rt->rt_nodes[0].rn_dupedkey ? " =>" : ""); 458 } 459 putchar('\n'); 460 } 461 462 char * 463 routename(in) 464 u_long in; 465 { 466 register char *cp; 467 static char line[MAXHOSTNAMELEN + 1]; 468 struct hostent *hp; 469 static char domain[MAXHOSTNAMELEN + 1]; 470 static int first = 1; 471 472 if (first) { 473 first = 0; 474 if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 475 (cp = index(domain, '.'))) 476 (void) strcpy(domain, cp + 1); 477 else 478 domain[0] = 0; 479 } 480 cp = 0; 481 if (!nflag) { 482 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 483 AF_INET); 484 if (hp) { 485 if ((cp = index(hp->h_name, '.')) && 486 !strcmp(cp + 1, domain)) 487 *cp = 0; 488 cp = hp->h_name; 489 } 490 } 491 if (cp) 492 strncpy(line, cp, sizeof(line) - 1); 493 else { 494 #define C(x) ((x) & 0xff) 495 in = ntohl(in); 496 sprintf(line, "%u.%u.%u.%u", 497 C(in >> 24), C(in >> 16), C(in >> 8), C(in)); 498 } 499 return (line); 500 } 501 502 static u_long 503 forgemask(a) 504 u_long a; 505 { 506 u_long m; 507 508 if (IN_CLASSA(a)) 509 m = IN_CLASSA_NET; 510 else if (IN_CLASSB(a)) 511 m = IN_CLASSB_NET; 512 else 513 m = IN_CLASSC_NET; 514 return (m); 515 } 516 517 static void 518 domask(dst, addr, mask) 519 char *dst; 520 u_long addr, mask; 521 { 522 register int b, i; 523 524 if (!mask || (forgemask(addr) == mask)) { 525 *dst = '\0'; 526 return; 527 } 528 i = 0; 529 for (b = 0; b < 32; b++) 530 if (mask & (1 << b)) { 531 register int bb; 532 533 i = b; 534 for (bb = b+1; bb < 32; bb++) 535 if (!(mask & (1 << bb))) { 536 i = -1; /* noncontig */ 537 break; 538 } 539 break; 540 } 541 if (i == -1) 542 sprintf(dst, "&0x%lx", mask); 543 else 544 sprintf(dst, "/%d", 32-i); 545 } 546 547 /* 548 * Return the name of the network whose address is given. 549 * The address is assumed to be that of a net or subnet, not a host. 550 */ 551 char * 552 netname(in, mask) 553 u_long in, mask; 554 { 555 char *cp = 0; 556 static char line[MAXHOSTNAMELEN + 1]; 557 struct netent *np = 0; 558 u_long net, omask; 559 register u_long i; 560 int subnetshift; 561 562 i = ntohl(in); 563 omask = mask; 564 if (!nflag && i) { 565 if (mask == 0) { 566 switch (mask = forgemask(i)) { 567 case IN_CLASSA_NET: 568 subnetshift = 8; 569 break; 570 case IN_CLASSB_NET: 571 subnetshift = 8; 572 break; 573 case IN_CLASSC_NET: 574 subnetshift = 4; 575 break; 576 default: 577 abort(); 578 } 579 /* 580 * If there are more bits than the standard mask 581 * would suggest, subnets must be in use. 582 * Guess at the subnet mask, assuming reasonable 583 * width subnet fields. 584 */ 585 while (i &~ mask) 586 mask = (long)mask >> subnetshift; 587 } 588 net = i & mask; 589 while ((mask & 1) == 0) 590 mask >>= 1, net >>= 1; 591 np = getnetbyaddr(net, AF_INET); 592 if (np) 593 cp = np->n_name; 594 } 595 if (cp) 596 strncpy(line, cp, sizeof(line) - 1); 597 else if ((i & 0xffffff) == 0) 598 sprintf(line, "%u", C(i >> 24)); 599 else if ((i & 0xffff) == 0) 600 sprintf(line, "%u.%u", C(i >> 24) , C(i >> 16)); 601 else if ((i & 0xff) == 0) 602 sprintf(line, "%u.%u.%u", C(i >> 24), C(i >> 16), C(i >> 8)); 603 else 604 sprintf(line, "%u.%u.%u.%u", C(i >> 24), 605 C(i >> 16), C(i >> 8), C(i)); 606 domask(line+strlen(line), i, omask); 607 return (line); 608 } 609 610 /* 611 * Print routing statistics 612 */ 613 void 614 rt_stats(off) 615 u_long off; 616 { 617 struct rtstat rtstat; 618 619 if (off == 0) { 620 printf("rtstat: symbol not in namelist\n"); 621 return; 622 } 623 kread(off, (char *)&rtstat, sizeof (rtstat)); 624 printf("routing:\n"); 625 printf("\t%u bad routing redirect%s\n", 626 rtstat.rts_badredirect, plural(rtstat.rts_badredirect)); 627 printf("\t%u dynamically created route%s\n", 628 rtstat.rts_dynamic, plural(rtstat.rts_dynamic)); 629 printf("\t%u new gateway%s due to redirects\n", 630 rtstat.rts_newgateway, plural(rtstat.rts_newgateway)); 631 printf("\t%u destination%s found unreachable\n", 632 rtstat.rts_unreach, plural(rtstat.rts_unreach)); 633 printf("\t%u use%s of a wildcard route\n", 634 rtstat.rts_wildcard, plural(rtstat.rts_wildcard)); 635 } 636 short ns_nullh[] = {0,0,0}; 637 short ns_bh[] = {-1,-1,-1}; 638 639 char * 640 ns_print(sa) 641 register struct sockaddr *sa; 642 { 643 register struct sockaddr_ns *sns = (struct sockaddr_ns*)sa; 644 struct ns_addr work; 645 union { union ns_net net_e; u_long long_e; } net; 646 u_short port; 647 static char mybuf[50], cport[10], chost[25]; 648 char *host = ""; 649 register char *p; register u_char *q; 650 651 work = sns->sns_addr; 652 port = ntohs(work.x_port); 653 work.x_port = 0; 654 net.net_e = work.x_net; 655 if (ns_nullhost(work) && net.long_e == 0) { 656 if (port ) { 657 sprintf(mybuf, "*.%xH", port); 658 upHex(mybuf); 659 } else 660 sprintf(mybuf, "*.*"); 661 return (mybuf); 662 } 663 664 if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) { 665 host = "any"; 666 } else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) { 667 host = "*"; 668 } else { 669 q = work.x_host.c_host; 670 sprintf(chost, "%02x%02x%02x%02x%02x%02xH", 671 q[0], q[1], q[2], q[3], q[4], q[5]); 672 for (p = chost; *p == '0' && p < chost + 12; p++) 673 continue; 674 host = p; 675 } 676 if (port) 677 sprintf(cport, ".%xH", htons(port)); 678 else 679 *cport = 0; 680 681 sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport); 682 upHex(mybuf); 683 return(mybuf); 684 } 685 686 char * 687 ns_phost(sa) 688 struct sockaddr *sa; 689 { 690 register struct sockaddr_ns *sns = (struct sockaddr_ns *)sa; 691 struct sockaddr_ns work; 692 static union ns_net ns_zeronet; 693 char *p; 694 695 work = *sns; 696 work.sns_addr.x_port = 0; 697 work.sns_addr.x_net = ns_zeronet; 698 699 p = ns_print((struct sockaddr *)&work); 700 if (strncmp("0H.", p, 3) == 0) p += 3; 701 return(p); 702 } 703 704 void 705 upHex(p0) 706 char *p0; 707 { 708 register char *p = p0; 709 for (; *p; p++) switch (*p) { 710 711 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 712 *p += ('A' - 'a'); 713 } 714 } 715