1 /* 2 * Copyright (c) 1983, 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static char sccsid[] = "@(#)route.c 5.20 (Berkeley) 11/29/90"; 36 #endif /* not lint */ 37 38 #include <sys/param.h> 39 #include <sys/socket.h> 40 #include <sys/mbuf.h> 41 42 #include <net/if.h> 43 #define KERNEL 44 #include <net/route.h> 45 #undef KERNEL 46 #include <netinet/in.h> 47 48 #ifdef NS 49 #include <netns/ns.h> 50 #endif 51 52 #include <netdb.h> 53 #include <sys/kinfo.h> 54 55 #include <stdio.h> 56 #include <string.h> 57 58 extern int nflag, aflag, Aflag, af; 59 int do_rtent; 60 extern char *routename(), *netname(), *plural(); 61 #ifdef NS 62 extern char *ns_print(); 63 #endif 64 extern char *malloc(); 65 #define kget(p, d) \ 66 (kvm_read((off_t)(p), (char *)&(d), sizeof (d))) 67 68 /* 69 * Definitions for showing gateway flags. 70 */ 71 struct bits { 72 short b_mask; 73 char b_val; 74 } bits[] = { 75 { RTF_UP, 'U' }, 76 { RTF_GATEWAY, 'G' }, 77 { RTF_HOST, 'H' }, 78 { RTF_DYNAMIC, 'D' }, 79 { RTF_MODIFIED, 'M' }, 80 { RTF_CLONING, 'C' }, 81 { RTF_XRESOLVE, 'X' }, 82 { RTF_LLINFO, 'L' }, 83 { RTF_REJECT, 'R' }, 84 { 0 } 85 }; 86 87 /* 88 * Print address family. 89 */ 90 void 91 p_proto(proto) 92 int proto; 93 { 94 switch (proto) 95 { 96 case AF_INET: 97 printf("inet"); 98 break; 99 case AF_NS: 100 printf("ns"); 101 break; 102 case AF_ISO: 103 printf("iso"); 104 break; 105 case AF_CCITT: 106 printf("ccitt"); 107 break; 108 default: 109 printf("%d", proto); 110 break; 111 } 112 } 113 114 115 /* 116 * Print routing tables. 117 */ 118 routepr(hostaddr, netaddr, hashsizeaddr, treeaddr) 119 off_t hostaddr, netaddr, hashsizeaddr, treeaddr; 120 { 121 struct mbuf mb; 122 register struct ortentry *rt; 123 register struct mbuf *m; 124 char name[16], *flags; 125 struct mbuf **routehash; 126 int hashsize; 127 int i, doinghost = 1; 128 129 printf("Routing tables\n"); 130 if (Aflag) 131 printf("%-8.8s ","Address"); 132 printf("%-16.16s %-18.18s %-6.6s %6.6s%8.8s %s\n", 133 "Destination", "Gateway", 134 "Flags", "Refs", "Use", "Interface"); 135 if (treeaddr) 136 return treestuff(treeaddr); 137 if (hostaddr == 0) { 138 printf("rthost: symbol not in namelist\n"); 139 return; 140 } 141 if (netaddr == 0) { 142 printf("rtnet: symbol not in namelist\n"); 143 return; 144 } 145 if (hashsizeaddr == 0) { 146 printf("rthashsize: symbol not in namelist\n"); 147 return; 148 } 149 kget(hashsizeaddr, hashsize); 150 routehash = (struct mbuf **)malloc( hashsize*sizeof (struct mbuf *) ); 151 kvm_read(hostaddr, (char *)routehash, hashsize*sizeof (struct mbuf *)); 152 again: 153 for (i = 0; i < hashsize; i++) { 154 if (routehash[i] == 0) 155 continue; 156 m = routehash[i]; 157 while (m) { 158 kget(m, mb); 159 if (Aflag) 160 printf("%8.8x ", m); 161 p_ortentry((struct ortentry *)(mb.m_dat)); 162 m = mb.m_next; 163 } 164 } 165 if (doinghost) { 166 kvm_read(netaddr, (char *)routehash, 167 hashsize*sizeof (struct mbuf *)); 168 doinghost = 0; 169 goto again; 170 } 171 free((char *)routehash); 172 return; 173 } 174 175 static union { 176 struct sockaddr u_sa; 177 u_short u_data[128]; 178 } pt_u; 179 int do_rtent = 0; 180 struct rtentry rtentry; 181 struct radix_node rnode; 182 struct radix_mask rmask; 183 184 int NewTree = 0; 185 treestuff(rtree) 186 off_t rtree; 187 { 188 struct radix_node_head *rnh, head; 189 190 if (Aflag == 0 && NewTree) 191 return(ntreestuff()); 192 for (kget(rtree, rnh); rnh; rnh = head.rnh_next) { 193 kget(rnh, head); 194 if (head.rnh_af == 0) { 195 if (Aflag || af == AF_UNSPEC) { 196 printf("Netmasks:\n"); 197 p_tree(head.rnh_treetop); 198 } 199 } else if (af == AF_UNSPEC || af == head.rnh_af) { 200 printf("\nRoute Tree for Protocol Family "); 201 p_proto(head.rnh_af); 202 printf(":\n"); 203 do_rtent = 1; 204 p_tree(head.rnh_treetop); 205 } 206 } 207 } 208 209 struct sockaddr * 210 kgetsa(dst) 211 register struct sockaddr *dst; 212 { 213 kget(dst, pt_u.u_sa); 214 if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa)) { 215 kvm_read((off_t)dst, pt_u.u_data, pt_u.u_sa.sa_len); 216 } 217 return (&pt_u.u_sa); 218 } 219 220 p_tree(rn) 221 struct radix_node *rn; 222 { 223 224 again: 225 kget(rn, rnode); 226 if (rnode.rn_b < 0) { 227 if (Aflag) 228 printf("%-8.8x ", rn); 229 if (rnode.rn_flags & RNF_ROOT) 230 printf("(root node)%s", 231 rnode.rn_dupedkey ? " =>\n" : "\n"); 232 else if (do_rtent) { 233 kget(rn, rtentry); 234 p_rtentry(&rtentry); 235 if (Aflag) 236 p_rtnode(); 237 } else { 238 p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key), 239 0, 44); 240 putchar('\n'); 241 } 242 if (rn = rnode.rn_dupedkey) 243 goto again; 244 } else { 245 if (Aflag && do_rtent) { 246 printf("%-8.8x ", rn); 247 p_rtnode(); 248 } 249 rn = rnode.rn_r; 250 p_tree(rnode.rn_l); 251 p_tree(rn); 252 } 253 } 254 char nbuf[20]; 255 256 p_rtnode() 257 { 258 259 struct radix_mask *rm = rnode.rn_mklist; 260 if (rnode.rn_b < 0) { 261 if (rnode.rn_mask) { 262 printf("\t mask "); 263 p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask), 264 0, -1); 265 } else if (rm == 0) 266 return; 267 } else { 268 sprintf(nbuf, "(%d)", rnode.rn_b); 269 printf("%6.6s %8.8x : %8.8x", nbuf, rnode.rn_l, rnode.rn_r); 270 } 271 while (rm) { 272 kget(rm, rmask); 273 sprintf(nbuf, " %d refs, ", rmask.rm_refs); 274 printf(" mk = %8.8x {(%d),%s", 275 rm, -1 - rmask.rm_b, rmask.rm_refs ? nbuf : " "); 276 p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask), 0, -1); 277 putchar('}'); 278 if (rm = rmask.rm_mklist) 279 printf(" ->"); 280 } 281 putchar('\n'); 282 } 283 284 ntreestuff() 285 { 286 int needed; 287 char *buf, *next, *lim; 288 register struct rt_msghdr *rtm; 289 290 if ((needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0)) < 0) 291 { perror("route-getkerninfo-estimate"); exit(1);} 292 if ((buf = malloc(needed)) == 0) 293 { printf("out of space\n"); exit(1);} 294 if (getkerninfo(KINFO_RT_DUMP, buf, &needed, 0) < 0) 295 { perror("actual retrieval of routing table"); exit(1);} 296 lim = buf + needed; 297 for (next = buf; next < lim; next += rtm->rtm_msglen) { 298 rtm = (struct rt_msghdr *)next; 299 np_rtentry(rtm); 300 } 301 } 302 303 np_rtentry(rtm) 304 register struct rt_msghdr *rtm; 305 { 306 register struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 307 static int masks_done, old_af, banner_printed; 308 int af = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST; 309 310 #ifdef notdef 311 /* for the moment, netmasks are skipped over */ 312 if (!banner_printed) { 313 printf("Netmasks:\n"); 314 banner_printed = 1; 315 } 316 if (masks_done == 0) { 317 if (rtm->rtm_addrs != RTA_DST ) { 318 masks_done = 1; 319 af = sa->sa_family; 320 } 321 } else 322 #endif 323 af = sa->sa_family; 324 if (af != old_af) { 325 printf("\nRoute Tree for Protocol Family %d:\n", af); 326 old_af = af; 327 } 328 if (rtm->rtm_addrs == RTA_DST) 329 p_sockaddr(sa, 0, 36); 330 else { 331 p_sockaddr(sa, rtm->rtm_flags, 16); 332 if (sa->sa_len == 0) 333 sa->sa_len = sizeof(long); 334 sa = (struct sockaddr *)(sa->sa_len + (char *)sa); 335 p_sockaddr(sa, 0, 18); 336 } 337 p_flags(rtm->rtm_flags & interesting, "%-6.6s "); 338 putchar('\n'); 339 } 340 341 p_sockaddr(sa, flags, width) 342 struct sockaddr *sa; 343 int flags, width; 344 { 345 char format[20], workbuf[128], *cp, *cplim; 346 register char *cpout; 347 348 switch(sa->sa_family) { 349 case AF_INET: 350 { 351 register struct sockaddr_in *sin = (struct sockaddr_in *)sa; 352 353 cp = (sin->sin_addr.s_addr == 0) ? "default" : 354 ((flags & RTF_HOST) ? 355 routename(sin->sin_addr) : netname(sin->sin_addr, 0L)); 356 } 357 break; 358 359 #ifdef NS 360 case AF_NS: 361 cp = ns_print((struct sockaddr_ns *)sa); 362 break; 363 #endif 364 365 default: 366 { 367 register u_short *s = ((u_short *)sa->sa_data), *slim; 368 369 slim = (u_short *) sa + ((sa->sa_len + sizeof(u_short) - 1) / 370 sizeof(u_short)); 371 cp = workbuf; 372 cplim = cp + sizeof(workbuf) - 6; 373 cp += sprintf(cp, "(%d)", sa->sa_family); 374 while (s < slim && cp < cplim) 375 cp += sprintf(cp, " %x", *s++); 376 cp = workbuf; 377 } 378 } 379 if (width < 0 ) 380 printf("%s ", cp); 381 else { 382 if (nflag) 383 printf("%-*s ", width, cp); 384 else 385 printf("%-*.*s ", width, width, cp); 386 } 387 } 388 389 p_flags(f, format) 390 register int f; 391 char *format; 392 { 393 char name[33], *flags; 394 register struct bits *p = bits; 395 for (flags = name; p->b_mask; p++) 396 if (p->b_mask & f) 397 *flags++ = p->b_val; 398 *flags = '\0'; 399 printf(format, name); 400 } 401 402 p_rtentry(rt) 403 register struct rtentry *rt; 404 { 405 char name[16]; 406 register struct sockaddr *sa; 407 struct ifnet ifnet; 408 409 p_sockaddr(kgetsa(rt_key(rt)), rt->rt_flags, 16); 410 p_sockaddr(kgetsa(rt->rt_gateway), RTF_HOST, 18); 411 p_flags(rt->rt_flags, "%-6.6s "); 412 printf("%6d %8d ", rt->rt_refcnt, rt->rt_use); 413 if (rt->rt_ifp == 0) { 414 putchar('\n'); 415 return; 416 } 417 kget(rt->rt_ifp, ifnet); 418 kvm_read((off_t)ifnet.if_name, name, 16); 419 printf(" %.15s%d%s", name, ifnet.if_unit, 420 rt->rt_nodes[0].rn_dupedkey ? " =>\n" : "\n"); 421 } 422 423 p_ortentry(rt) 424 register struct ortentry *rt; 425 { 426 char name[16], *flags; 427 register struct bits *p; 428 register struct sockaddr_in *sin; 429 struct ifnet ifnet; 430 431 p_sockaddr(&rt->rt_dst, rt->rt_flags, 16); 432 p_sockaddr(&rt->rt_gateway, 0, 18); 433 p_flags(rt->rt_flags, "%-6.6s "); 434 printf("%6d %8d ", rt->rt_refcnt, rt->rt_use); 435 if (rt->rt_ifp == 0) { 436 putchar('\n'); 437 return; 438 } 439 kget(rt->rt_ifp, ifnet); 440 kvm_read((off_t)ifnet.if_name, name, 16); 441 printf(" %.15s%d\n", name, ifnet.if_unit); 442 } 443 444 char * 445 routename(in) 446 struct in_addr in; 447 { 448 register char *cp; 449 static char line[MAXHOSTNAMELEN + 1]; 450 struct hostent *hp; 451 static char domain[MAXHOSTNAMELEN + 1]; 452 static int first = 1; 453 char *index(); 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.s_addr = ntohl(in.s_addr); 479 sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 480 C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr)); 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 struct in_addr in; 492 u_long mask; 493 { 494 char *cp = 0; 495 static char line[MAXHOSTNAMELEN + 1]; 496 struct netent *np = 0; 497 u_long net; 498 register i; 499 int subnetshift; 500 501 i = ntohl(in.s_addr); 502 if (!nflag && i) { 503 if (mask == 0) { 504 if (IN_CLASSA(i)) { 505 mask = IN_CLASSA_NET; 506 subnetshift = 8; 507 } else if (IN_CLASSB(i)) { 508 mask = IN_CLASSB_NET; 509 subnetshift = 8; 510 } else { 511 mask = IN_CLASSC_NET; 512 subnetshift = 4; 513 } 514 /* 515 * If there are more bits than the standard mask 516 * would suggest, subnets must be in use. 517 * Guess at the subnet mask, assuming reasonable 518 * width subnet fields. 519 */ 520 while (i &~ mask) 521 mask = (long)mask >> subnetshift; 522 } 523 net = i & mask; 524 while ((mask & 1) == 0) 525 mask >>= 1, net >>= 1; 526 np = getnetbyaddr(net, AF_INET); 527 if (np) 528 cp = np->n_name; 529 } 530 if (cp) 531 strncpy(line, cp, sizeof(line) - 1); 532 else if ((i & 0xffffff) == 0) 533 sprintf(line, "%u", C(i >> 24)); 534 else if ((i & 0xffff) == 0) 535 sprintf(line, "%u.%u", C(i >> 24) , C(i >> 16)); 536 else if ((i & 0xff) == 0) 537 sprintf(line, "%u.%u.%u", C(i >> 24), C(i >> 16), C(i >> 8)); 538 else 539 sprintf(line, "%u.%u.%u.%u", C(i >> 24), 540 C(i >> 16), C(i >> 8), C(i)); 541 return (line); 542 } 543 544 /* 545 * Print routing statistics 546 */ 547 rt_stats(off) 548 off_t off; 549 { 550 struct rtstat rtstat; 551 552 if (off == 0) { 553 printf("rtstat: symbol not in namelist\n"); 554 return; 555 } 556 kvm_read(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 #ifdef NS 570 short ns_nullh[] = {0,0,0}; 571 short ns_bh[] = {-1,-1,-1}; 572 573 char * 574 ns_print(sns) 575 struct sockaddr_ns *sns; 576 { 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 host = p; 607 } 608 if (port) 609 sprintf(cport, ".%xH", htons(port)); 610 else 611 *cport = 0; 612 613 sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport); 614 upHex(mybuf); 615 return(mybuf); 616 } 617 618 char * 619 ns_phost(sns) 620 struct sockaddr_ns *sns; 621 { 622 struct sockaddr_ns work; 623 static union ns_net ns_zeronet; 624 char *p; 625 626 work = *sns; 627 work.sns_addr.x_port = 0; 628 work.sns_addr.x_net = ns_zeronet; 629 630 p = ns_print(&work); 631 if (strncmp("0H.", p, 3) == 0) p += 3; 632 return(p); 633 } 634 upHex(p0) 635 char *p0; 636 { 637 register char *p = p0; 638 for (; *p; p++) switch (*p) { 639 640 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 641 *p += ('A' - 'a'); 642 } 643 } 644 #endif /* NS */ 645