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