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.5 (Berkeley) 11/08/94"; 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 *, 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 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 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( 250 kgetsa((struct sockaddr *)rnode_aux.rn_mask), 0, -1); 251 } else 252 p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask), 0, -1); 253 putchar('}'); 254 if (rm = rmask.rm_mklist) 255 printf(" ->"); 256 } 257 putchar('\n'); 258 } 259 260 static void 261 ntreestuff() 262 { 263 size_t needed; 264 int mib[6]; 265 char *buf, *next, *lim; 266 register struct rt_msghdr *rtm; 267 268 mib[0] = CTL_NET; 269 mib[1] = PF_ROUTE; 270 mib[2] = 0; 271 mib[3] = 0; 272 mib[4] = NET_RT_DUMP; 273 mib[5] = 0; 274 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 275 { perror("route-sysctl-estimate"); exit(1);} 276 if ((buf = malloc(needed)) == 0) 277 { printf("out of space\n"); exit(1);} 278 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 279 { perror("sysctl of routing table"); exit(1);} 280 lim = buf + needed; 281 for (next = buf; next < lim; next += rtm->rtm_msglen) { 282 rtm = (struct rt_msghdr *)next; 283 np_rtentry(rtm); 284 } 285 } 286 287 static void 288 np_rtentry(rtm) 289 register struct rt_msghdr *rtm; 290 { 291 register struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 292 #ifdef notdef 293 static int masks_done, banner_printed; 294 #endif 295 static int old_af; 296 int af = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST; 297 298 #ifdef notdef 299 /* for the moment, netmasks are skipped over */ 300 if (!banner_printed) { 301 printf("Netmasks:\n"); 302 banner_printed = 1; 303 } 304 if (masks_done == 0) { 305 if (rtm->rtm_addrs != RTA_DST ) { 306 masks_done = 1; 307 af = sa->sa_family; 308 } 309 } else 310 #endif 311 af = sa->sa_family; 312 if (af != old_af) { 313 pr_family(af); 314 old_af = af; 315 } 316 if (rtm->rtm_addrs == RTA_DST) 317 p_sockaddr(sa, 0, 36); 318 else { 319 p_sockaddr(sa, rtm->rtm_flags, 16); 320 if (sa->sa_len == 0) 321 sa->sa_len = sizeof(long); 322 sa = (struct sockaddr *)(sa->sa_len + (char *)sa); 323 p_sockaddr(sa, 0, 18); 324 } 325 p_flags(rtm->rtm_flags & interesting, "%-6.6s "); 326 putchar('\n'); 327 } 328 329 static void 330 p_sockaddr(sa, flags, width) 331 struct sockaddr *sa; 332 int flags, width; 333 { 334 char workbuf[128], *cplim; 335 register char *cp = workbuf; 336 337 switch(sa->sa_family) { 338 case AF_INET: 339 { 340 register struct sockaddr_in *sin = (struct sockaddr_in *)sa; 341 342 cp = (sin->sin_addr.s_addr == 0) ? "default" : 343 ((flags & RTF_HOST) ? 344 routename(sin->sin_addr.s_addr) : 345 netname(sin->sin_addr.s_addr, 0L)); 346 break; 347 } 348 349 case AF_NS: 350 cp = ns_print(sa); 351 break; 352 353 case AF_LINK: 354 { 355 register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; 356 357 if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && 358 sdl->sdl_slen == 0) 359 (void) sprintf(workbuf, "link#%d", sdl->sdl_index); 360 else switch (sdl->sdl_type) { 361 case IFT_ETHER: 362 { 363 register int i; 364 register u_char *lla = (u_char *)sdl->sdl_data + 365 sdl->sdl_nlen; 366 367 cplim = ""; 368 for (i = 0; i < sdl->sdl_alen; i++, lla++) { 369 cp += sprintf(cp, "%s%x", cplim, *lla); 370 cplim = ":"; 371 } 372 cp = workbuf; 373 break; 374 } 375 default: 376 cp = link_ntoa(sdl); 377 break; 378 } 379 break; 380 } 381 382 default: 383 { 384 register u_char *s = (u_char *)sa->sa_data, *slim; 385 386 slim = sa->sa_len + (u_char *) sa; 387 cplim = cp + sizeof(workbuf) - 6; 388 cp += sprintf(cp, "(%d)", sa->sa_family); 389 while (s < slim && cp < cplim) { 390 cp += sprintf(cp, " %02x", *s++); 391 if (s < slim) 392 cp += sprintf(cp, "%02x", *s++); 393 } 394 cp = workbuf; 395 } 396 } 397 if (width < 0 ) 398 printf("%s ", cp); 399 else { 400 if (nflag) 401 printf("%-*s ", width, cp); 402 else 403 printf("%-*.*s ", width, width, cp); 404 } 405 } 406 407 static void 408 p_flags(f, format) 409 register int f; 410 char *format; 411 { 412 char name[33], *flags; 413 register struct bits *p = bits; 414 415 for (flags = name; p->b_mask; p++) 416 if (p->b_mask & f) 417 *flags++ = p->b_val; 418 *flags = '\0'; 419 printf(format, name); 420 } 421 422 static void 423 p_rtentry(rt) 424 register struct rtentry *rt; 425 { 426 static struct ifnet ifnet, *lastif; 427 static char name[16]; 428 429 p_sockaddr(kgetsa(rt_key(rt)), rt->rt_flags, WID_DST); 430 p_sockaddr(kgetsa(rt->rt_gateway), RTF_HOST, WID_GW); 431 p_flags(rt->rt_flags, "%-6.6s "); 432 printf("%6d %8d ", rt->rt_refcnt, rt->rt_use); 433 if (rt->rt_ifp) { 434 if (rt->rt_ifp != lastif) { 435 kget(rt->rt_ifp, ifnet); 436 kread((u_long)ifnet.if_name, name, 16); 437 lastif = rt->rt_ifp; 438 } 439 printf(" %.15s%d%s", name, ifnet.if_unit, 440 rt->rt_nodes[0].rn_dupedkey ? " =>" : ""); 441 } 442 putchar('\n'); 443 } 444 445 char * 446 routename(in) 447 u_long in; 448 { 449 register char *cp; 450 static char line[MAXHOSTNAMELEN + 1]; 451 struct hostent *hp; 452 static char domain[MAXHOSTNAMELEN + 1]; 453 static int first = 1; 454 455 if (first) { 456 first = 0; 457 if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 458 (cp = index(domain, '.'))) 459 (void) strcpy(domain, cp + 1); 460 else 461 domain[0] = 0; 462 } 463 cp = 0; 464 if (!nflag) { 465 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 466 AF_INET); 467 if (hp) { 468 if ((cp = index(hp->h_name, '.')) && 469 !strcmp(cp + 1, domain)) 470 *cp = 0; 471 cp = hp->h_name; 472 } 473 } 474 if (cp) 475 strncpy(line, cp, sizeof(line) - 1); 476 else { 477 #define C(x) ((x) & 0xff) 478 in = ntohl(in); 479 sprintf(line, "%u.%u.%u.%u", 480 C(in >> 24), C(in >> 16), C(in >> 8), C(in)); 481 } 482 return (line); 483 } 484 485 /* 486 * Return the name of the network whose address is given. 487 * The address is assumed to be that of a net or subnet, not a host. 488 */ 489 char * 490 netname(in, mask) 491 u_long in, mask; 492 { 493 char *cp = 0; 494 static char line[MAXHOSTNAMELEN + 1]; 495 struct netent *np = 0; 496 u_long net; 497 register int i; 498 int subnetshift; 499 500 i = ntohl(in); 501 if (!nflag && i) { 502 if (mask == 0) { 503 if (IN_CLASSA(i)) { 504 mask = IN_CLASSA_NET; 505 subnetshift = 8; 506 } else if (IN_CLASSB(i)) { 507 mask = IN_CLASSB_NET; 508 subnetshift = 8; 509 } else { 510 mask = IN_CLASSC_NET; 511 subnetshift = 4; 512 } 513 /* 514 * If there are more bits than the standard mask 515 * would suggest, subnets must be in use. 516 * Guess at the subnet mask, assuming reasonable 517 * width subnet fields. 518 */ 519 while (i &~ mask) 520 mask = (long)mask >> subnetshift; 521 } 522 net = i & mask; 523 while ((mask & 1) == 0) 524 mask >>= 1, net >>= 1; 525 np = getnetbyaddr(net, AF_INET); 526 if (np) 527 cp = np->n_name; 528 } 529 if (cp) 530 strncpy(line, cp, sizeof(line) - 1); 531 else if ((i & 0xffffff) == 0) 532 sprintf(line, "%u", C(i >> 24)); 533 else if ((i & 0xffff) == 0) 534 sprintf(line, "%u.%u", C(i >> 24) , C(i >> 16)); 535 else if ((i & 0xff) == 0) 536 sprintf(line, "%u.%u.%u", C(i >> 24), C(i >> 16), C(i >> 8)); 537 else 538 sprintf(line, "%u.%u.%u.%u", C(i >> 24), 539 C(i >> 16), C(i >> 8), C(i)); 540 return (line); 541 } 542 543 /* 544 * Print routing statistics 545 */ 546 void 547 rt_stats(off) 548 u_long off; 549 { 550 struct rtstat rtstat; 551 552 if (off == 0) { 553 printf("rtstat: symbol not in namelist\n"); 554 return; 555 } 556 kread(off, (char *)&rtstat, sizeof (rtstat)); 557 printf("routing:\n"); 558 printf("\t%u bad routing redirect%s\n", 559 rtstat.rts_badredirect, plural(rtstat.rts_badredirect)); 560 printf("\t%u dynamically created route%s\n", 561 rtstat.rts_dynamic, plural(rtstat.rts_dynamic)); 562 printf("\t%u new gateway%s due to redirects\n", 563 rtstat.rts_newgateway, plural(rtstat.rts_newgateway)); 564 printf("\t%u destination%s found unreachable\n", 565 rtstat.rts_unreach, plural(rtstat.rts_unreach)); 566 printf("\t%u use%s of a wildcard route\n", 567 rtstat.rts_wildcard, plural(rtstat.rts_wildcard)); 568 } 569 short ns_nullh[] = {0,0,0}; 570 short ns_bh[] = {-1,-1,-1}; 571 572 char * 573 ns_print(sa) 574 register struct sockaddr *sa; 575 { 576 register struct sockaddr_ns *sns = (struct sockaddr_ns*)sa; 577 struct ns_addr work; 578 union { union ns_net net_e; u_long long_e; } net; 579 u_short port; 580 static char mybuf[50], cport[10], chost[25]; 581 char *host = ""; 582 register char *p; register u_char *q; 583 584 work = sns->sns_addr; 585 port = ntohs(work.x_port); 586 work.x_port = 0; 587 net.net_e = work.x_net; 588 if (ns_nullhost(work) && net.long_e == 0) { 589 if (port ) { 590 sprintf(mybuf, "*.%xH", port); 591 upHex(mybuf); 592 } else 593 sprintf(mybuf, "*.*"); 594 return (mybuf); 595 } 596 597 if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) { 598 host = "any"; 599 } else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) { 600 host = "*"; 601 } else { 602 q = work.x_host.c_host; 603 sprintf(chost, "%02x%02x%02x%02x%02x%02xH", 604 q[0], q[1], q[2], q[3], q[4], q[5]); 605 for (p = chost; *p == '0' && p < chost + 12; p++) 606 continue; 607 host = p; 608 } 609 if (port) 610 sprintf(cport, ".%xH", htons(port)); 611 else 612 *cport = 0; 613 614 sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport); 615 upHex(mybuf); 616 return(mybuf); 617 } 618 619 char * 620 ns_phost(sa) 621 struct sockaddr *sa; 622 { 623 register struct sockaddr_ns *sns = (struct sockaddr_ns *)sa; 624 struct sockaddr_ns work; 625 static union ns_net ns_zeronet; 626 char *p; 627 628 work = *sns; 629 work.sns_addr.x_port = 0; 630 work.sns_addr.x_net = ns_zeronet; 631 632 p = ns_print((struct sockaddr *)&work); 633 if (strncmp("0H.", p, 3) == 0) p += 3; 634 return(p); 635 } 636 637 void 638 upHex(p0) 639 char *p0; 640 { 641 register char *p = p0; 642 for (; *p; p++) switch (*p) { 643 644 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 645 *p += ('A' - 'a'); 646 } 647 } 648