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