1 /* 2 * Copyright (c) 1983, 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)route.c 8.1 (Berkeley) 06/06/93"; 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/sysctl.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 size_t needed; 257 int mib[6]; 258 char *buf, *next, *lim; 259 register struct rt_msghdr *rtm; 260 261 mib[0] = CTL_NET; 262 mib[1] = PF_ROUTE; 263 mib[2] = 0; 264 mib[3] = 0; 265 mib[4] = NET_RT_DUMP; 266 mib[5] = 0; 267 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 268 { perror("route-sysctl-estimate"); exit(1);} 269 if ((buf = malloc(needed)) == 0) 270 { printf("out of space\n"); exit(1);} 271 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 272 { perror("sysctl of routing table"); exit(1);} 273 lim = buf + needed; 274 for (next = buf; next < lim; next += rtm->rtm_msglen) { 275 rtm = (struct rt_msghdr *)next; 276 np_rtentry(rtm); 277 } 278 } 279 280 static void 281 np_rtentry(rtm) 282 register struct rt_msghdr *rtm; 283 { 284 register struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 285 #ifdef notdef 286 static int masks_done, banner_printed; 287 #endif 288 static int old_af; 289 int af = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST; 290 291 #ifdef notdef 292 /* for the moment, netmasks are skipped over */ 293 if (!banner_printed) { 294 printf("Netmasks:\n"); 295 banner_printed = 1; 296 } 297 if (masks_done == 0) { 298 if (rtm->rtm_addrs != RTA_DST ) { 299 masks_done = 1; 300 af = sa->sa_family; 301 } 302 } else 303 #endif 304 af = sa->sa_family; 305 if (af != old_af) { 306 pr_family(af); 307 old_af = af; 308 } 309 if (rtm->rtm_addrs == RTA_DST) 310 p_sockaddr(sa, 0, 36); 311 else { 312 p_sockaddr(sa, rtm->rtm_flags, 16); 313 if (sa->sa_len == 0) 314 sa->sa_len = sizeof(long); 315 sa = (struct sockaddr *)(sa->sa_len + (char *)sa); 316 p_sockaddr(sa, 0, 18); 317 } 318 p_flags(rtm->rtm_flags & interesting, "%-6.6s "); 319 putchar('\n'); 320 } 321 322 static void 323 p_sockaddr(sa, flags, width) 324 struct sockaddr *sa; 325 int flags, width; 326 { 327 char workbuf[128], *cplim; 328 register char *cp = workbuf; 329 330 switch(sa->sa_family) { 331 case AF_INET: 332 { 333 register struct sockaddr_in *sin = (struct sockaddr_in *)sa; 334 335 cp = (sin->sin_addr.s_addr == 0) ? "default" : 336 ((flags & RTF_HOST) ? 337 routename(sin->sin_addr.s_addr) : 338 netname(sin->sin_addr.s_addr, 0L)); 339 break; 340 } 341 342 case AF_NS: 343 cp = ns_print(sa); 344 break; 345 346 case AF_LINK: 347 { 348 register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; 349 350 if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && 351 sdl->sdl_slen == 0) 352 (void) sprintf(workbuf, "link#%d", sdl->sdl_index); 353 else switch (sdl->sdl_type) { 354 case IFT_ETHER: 355 { 356 register int i; 357 register u_char *lla = (u_char *)sdl->sdl_data + 358 sdl->sdl_nlen; 359 360 cplim = ""; 361 for (i = 0; i < sdl->sdl_alen; i++, lla++) { 362 cp += sprintf(cp, "%s%x", cplim, *lla); 363 cplim = ":"; 364 } 365 cp = workbuf; 366 break; 367 } 368 default: 369 cp = link_ntoa(sdl); 370 break; 371 } 372 break; 373 } 374 375 default: 376 { 377 register u_short *s = ((u_short *)sa->sa_data), *slim; 378 379 slim = (u_short *) sa + ((sa->sa_len + sizeof(u_short) - 1) / 380 sizeof(u_short)); 381 cplim = cp + sizeof(workbuf) - 6; 382 cp += sprintf(cp, "(%d)", sa->sa_family); 383 while (s < slim && cp < cplim) 384 cp += sprintf(cp, " %x", *s++); 385 cp = workbuf; 386 } 387 } 388 if (width < 0 ) 389 printf("%s ", cp); 390 else { 391 if (nflag) 392 printf("%-*s ", width, cp); 393 else 394 printf("%-*.*s ", width, width, cp); 395 } 396 } 397 398 static void 399 p_flags(f, format) 400 register int f; 401 char *format; 402 { 403 char name[33], *flags; 404 register struct bits *p = bits; 405 406 for (flags = name; p->b_mask; p++) 407 if (p->b_mask & f) 408 *flags++ = p->b_val; 409 *flags = '\0'; 410 printf(format, name); 411 } 412 413 static void 414 p_rtentry(rt) 415 register struct rtentry *rt; 416 { 417 static struct ifnet ifnet, *lastif; 418 static char name[16]; 419 420 p_sockaddr(kgetsa(rt_key(rt)), rt->rt_flags, WID_DST); 421 p_sockaddr(kgetsa(rt->rt_gateway), RTF_HOST, WID_GW); 422 p_flags(rt->rt_flags, "%-6.6s "); 423 printf("%6d %8d ", rt->rt_refcnt, rt->rt_use); 424 if (rt->rt_ifp) { 425 if (rt->rt_ifp != lastif) { 426 kget(rt->rt_ifp, ifnet); 427 kread((u_long)ifnet.if_name, name, 16); 428 lastif = rt->rt_ifp; 429 } 430 printf(" %.15s%d%s", name, ifnet.if_unit, 431 rt->rt_nodes[0].rn_dupedkey ? " =>" : ""); 432 } 433 putchar('\n'); 434 } 435 436 char * 437 routename(in) 438 u_long in; 439 { 440 register char *cp; 441 static char line[MAXHOSTNAMELEN + 1]; 442 struct hostent *hp; 443 static char domain[MAXHOSTNAMELEN + 1]; 444 static int first = 1; 445 446 if (first) { 447 first = 0; 448 if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 449 (cp = index(domain, '.'))) 450 (void) strcpy(domain, cp + 1); 451 else 452 domain[0] = 0; 453 } 454 cp = 0; 455 if (!nflag) { 456 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 457 AF_INET); 458 if (hp) { 459 if ((cp = index(hp->h_name, '.')) && 460 !strcmp(cp + 1, domain)) 461 *cp = 0; 462 cp = hp->h_name; 463 } 464 } 465 if (cp) 466 strncpy(line, cp, sizeof(line) - 1); 467 else { 468 #define C(x) ((x) & 0xff) 469 in = ntohl(in); 470 sprintf(line, "%u.%u.%u.%u", 471 C(in >> 24), C(in >> 16), C(in >> 8), C(in)); 472 } 473 return (line); 474 } 475 476 /* 477 * Return the name of the network whose address is given. 478 * The address is assumed to be that of a net or subnet, not a host. 479 */ 480 char * 481 netname(in, mask) 482 u_long in, mask; 483 { 484 char *cp = 0; 485 static char line[MAXHOSTNAMELEN + 1]; 486 struct netent *np = 0; 487 u_long net; 488 register int i; 489 int subnetshift; 490 491 i = ntohl(in); 492 if (!nflag && i) { 493 if (mask == 0) { 494 if (IN_CLASSA(i)) { 495 mask = IN_CLASSA_NET; 496 subnetshift = 8; 497 } else if (IN_CLASSB(i)) { 498 mask = IN_CLASSB_NET; 499 subnetshift = 8; 500 } else { 501 mask = IN_CLASSC_NET; 502 subnetshift = 4; 503 } 504 /* 505 * If there are more bits than the standard mask 506 * would suggest, subnets must be in use. 507 * Guess at the subnet mask, assuming reasonable 508 * width subnet fields. 509 */ 510 while (i &~ mask) 511 mask = (long)mask >> subnetshift; 512 } 513 net = i & mask; 514 while ((mask & 1) == 0) 515 mask >>= 1, net >>= 1; 516 np = getnetbyaddr(net, AF_INET); 517 if (np) 518 cp = np->n_name; 519 } 520 if (cp) 521 strncpy(line, cp, sizeof(line) - 1); 522 else if ((i & 0xffffff) == 0) 523 sprintf(line, "%u", C(i >> 24)); 524 else if ((i & 0xffff) == 0) 525 sprintf(line, "%u.%u", C(i >> 24) , C(i >> 16)); 526 else if ((i & 0xff) == 0) 527 sprintf(line, "%u.%u.%u", C(i >> 24), C(i >> 16), C(i >> 8)); 528 else 529 sprintf(line, "%u.%u.%u.%u", C(i >> 24), 530 C(i >> 16), C(i >> 8), C(i)); 531 return (line); 532 } 533 534 /* 535 * Print routing statistics 536 */ 537 void 538 rt_stats(off) 539 u_long off; 540 { 541 struct rtstat rtstat; 542 543 if (off == 0) { 544 printf("rtstat: symbol not in namelist\n"); 545 return; 546 } 547 kread(off, (char *)&rtstat, sizeof (rtstat)); 548 printf("routing:\n"); 549 printf("\t%u bad routing redirect%s\n", 550 rtstat.rts_badredirect, plural(rtstat.rts_badredirect)); 551 printf("\t%u dynamically created route%s\n", 552 rtstat.rts_dynamic, plural(rtstat.rts_dynamic)); 553 printf("\t%u new gateway%s due to redirects\n", 554 rtstat.rts_newgateway, plural(rtstat.rts_newgateway)); 555 printf("\t%u destination%s found unreachable\n", 556 rtstat.rts_unreach, plural(rtstat.rts_unreach)); 557 printf("\t%u use%s of a wildcard route\n", 558 rtstat.rts_wildcard, plural(rtstat.rts_wildcard)); 559 } 560 short ns_nullh[] = {0,0,0}; 561 short ns_bh[] = {-1,-1,-1}; 562 563 char * 564 ns_print(sa) 565 register struct sockaddr *sa; 566 { 567 register struct sockaddr_ns *sns = (struct sockaddr_ns*)sa; 568 struct ns_addr work; 569 union { union ns_net net_e; u_long long_e; } net; 570 u_short port; 571 static char mybuf[50], cport[10], chost[25]; 572 char *host = ""; 573 register char *p; register u_char *q; 574 575 work = sns->sns_addr; 576 port = ntohs(work.x_port); 577 work.x_port = 0; 578 net.net_e = work.x_net; 579 if (ns_nullhost(work) && net.long_e == 0) { 580 if (port ) { 581 sprintf(mybuf, "*.%xH", port); 582 upHex(mybuf); 583 } else 584 sprintf(mybuf, "*.*"); 585 return (mybuf); 586 } 587 588 if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) { 589 host = "any"; 590 } else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) { 591 host = "*"; 592 } else { 593 q = work.x_host.c_host; 594 sprintf(chost, "%02x%02x%02x%02x%02x%02xH", 595 q[0], q[1], q[2], q[3], q[4], q[5]); 596 for (p = chost; *p == '0' && p < chost + 12; p++) 597 continue; 598 host = p; 599 } 600 if (port) 601 sprintf(cport, ".%xH", htons(port)); 602 else 603 *cport = 0; 604 605 sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport); 606 upHex(mybuf); 607 return(mybuf); 608 } 609 610 char * 611 ns_phost(sa) 612 struct sockaddr *sa; 613 { 614 register struct sockaddr_ns *sns = (struct sockaddr_ns *)sa; 615 struct sockaddr_ns work; 616 static union ns_net ns_zeronet; 617 char *p; 618 619 work = *sns; 620 work.sns_addr.x_port = 0; 621 work.sns_addr.x_net = ns_zeronet; 622 623 p = ns_print((struct sockaddr *)&work); 624 if (strncmp("0H.", p, 3) == 0) p += 3; 625 return(p); 626 } 627 628 void 629 upHex(p0) 630 char *p0; 631 { 632 register char *p = p0; 633 for (; *p; p++) switch (*p) { 634 635 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 636 *p += ('A' - 'a'); 637 } 638 } 639