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