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