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