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