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.3 (Berkeley) 03/09/94"; 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_char *s = (u_char *)sa->sa_data, *slim; 378 379 slim = sa->sa_len + (u_char *) sa; 380 cplim = cp + sizeof(workbuf) - 6; 381 cp += sprintf(cp, "(%d)", sa->sa_family); 382 while (s < slim && cp < cplim) { 383 cp += sprintf(cp, " %02x", *s++); 384 if (s < slim) 385 cp += sprintf(cp, "%02x", *s++); 386 } 387 cp = workbuf; 388 } 389 } 390 if (width < 0 ) 391 printf("%s ", cp); 392 else { 393 if (nflag) 394 printf("%-*s ", width, cp); 395 else 396 printf("%-*.*s ", width, width, cp); 397 } 398 } 399 400 static void 401 p_flags(f, format) 402 register int f; 403 char *format; 404 { 405 char name[33], *flags; 406 register struct bits *p = bits; 407 408 for (flags = name; p->b_mask; p++) 409 if (p->b_mask & f) 410 *flags++ = p->b_val; 411 *flags = '\0'; 412 printf(format, name); 413 } 414 415 static void 416 p_rtentry(rt) 417 register struct rtentry *rt; 418 { 419 static struct ifnet ifnet, *lastif; 420 static char name[16]; 421 422 p_sockaddr(kgetsa(rt_key(rt)), rt->rt_flags, WID_DST); 423 p_sockaddr(kgetsa(rt->rt_gateway), RTF_HOST, WID_GW); 424 p_flags(rt->rt_flags, "%-6.6s "); 425 printf("%6d %8d ", rt->rt_refcnt, rt->rt_use); 426 if (rt->rt_ifp) { 427 if (rt->rt_ifp != lastif) { 428 kget(rt->rt_ifp, ifnet); 429 kread((u_long)ifnet.if_name, name, 16); 430 lastif = rt->rt_ifp; 431 } 432 printf(" %.15s%d%s", name, ifnet.if_unit, 433 rt->rt_nodes[0].rn_dupedkey ? " =>" : ""); 434 } 435 putchar('\n'); 436 } 437 438 char * 439 routename(in) 440 u_long in; 441 { 442 register char *cp; 443 static char line[MAXHOSTNAMELEN + 1]; 444 struct hostent *hp; 445 static char domain[MAXHOSTNAMELEN + 1]; 446 static int first = 1; 447 448 if (first) { 449 first = 0; 450 if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 451 (cp = index(domain, '.'))) 452 (void) strcpy(domain, cp + 1); 453 else 454 domain[0] = 0; 455 } 456 cp = 0; 457 if (!nflag) { 458 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 459 AF_INET); 460 if (hp) { 461 if ((cp = index(hp->h_name, '.')) && 462 !strcmp(cp + 1, domain)) 463 *cp = 0; 464 cp = hp->h_name; 465 } 466 } 467 if (cp) 468 strncpy(line, cp, sizeof(line) - 1); 469 else { 470 #define C(x) ((x) & 0xff) 471 in = ntohl(in); 472 sprintf(line, "%u.%u.%u.%u", 473 C(in >> 24), C(in >> 16), C(in >> 8), C(in)); 474 } 475 return (line); 476 } 477 478 /* 479 * Return the name of the network whose address is given. 480 * The address is assumed to be that of a net or subnet, not a host. 481 */ 482 char * 483 netname(in, mask) 484 u_long in, mask; 485 { 486 char *cp = 0; 487 static char line[MAXHOSTNAMELEN + 1]; 488 struct netent *np = 0; 489 u_long net; 490 register int i; 491 int subnetshift; 492 493 i = ntohl(in); 494 if (!nflag && i) { 495 if (mask == 0) { 496 if (IN_CLASSA(i)) { 497 mask = IN_CLASSA_NET; 498 subnetshift = 8; 499 } else if (IN_CLASSB(i)) { 500 mask = IN_CLASSB_NET; 501 subnetshift = 8; 502 } else { 503 mask = IN_CLASSC_NET; 504 subnetshift = 4; 505 } 506 /* 507 * If there are more bits than the standard mask 508 * would suggest, subnets must be in use. 509 * Guess at the subnet mask, assuming reasonable 510 * width subnet fields. 511 */ 512 while (i &~ mask) 513 mask = (long)mask >> subnetshift; 514 } 515 net = i & mask; 516 while ((mask & 1) == 0) 517 mask >>= 1, net >>= 1; 518 np = getnetbyaddr(net, AF_INET); 519 if (np) 520 cp = np->n_name; 521 } 522 if (cp) 523 strncpy(line, cp, sizeof(line) - 1); 524 else if ((i & 0xffffff) == 0) 525 sprintf(line, "%u", C(i >> 24)); 526 else if ((i & 0xffff) == 0) 527 sprintf(line, "%u.%u", C(i >> 24) , C(i >> 16)); 528 else if ((i & 0xff) == 0) 529 sprintf(line, "%u.%u.%u", C(i >> 24), C(i >> 16), C(i >> 8)); 530 else 531 sprintf(line, "%u.%u.%u.%u", C(i >> 24), 532 C(i >> 16), C(i >> 8), C(i)); 533 return (line); 534 } 535 536 /* 537 * Print routing statistics 538 */ 539 void 540 rt_stats(off) 541 u_long off; 542 { 543 struct rtstat rtstat; 544 545 if (off == 0) { 546 printf("rtstat: symbol not in namelist\n"); 547 return; 548 } 549 kread(off, (char *)&rtstat, sizeof (rtstat)); 550 printf("routing:\n"); 551 printf("\t%u bad routing redirect%s\n", 552 rtstat.rts_badredirect, plural(rtstat.rts_badredirect)); 553 printf("\t%u dynamically created route%s\n", 554 rtstat.rts_dynamic, plural(rtstat.rts_dynamic)); 555 printf("\t%u new gateway%s due to redirects\n", 556 rtstat.rts_newgateway, plural(rtstat.rts_newgateway)); 557 printf("\t%u destination%s found unreachable\n", 558 rtstat.rts_unreach, plural(rtstat.rts_unreach)); 559 printf("\t%u use%s of a wildcard route\n", 560 rtstat.rts_wildcard, plural(rtstat.rts_wildcard)); 561 } 562 short ns_nullh[] = {0,0,0}; 563 short ns_bh[] = {-1,-1,-1}; 564 565 char * 566 ns_print(sa) 567 register struct sockaddr *sa; 568 { 569 register struct sockaddr_ns *sns = (struct sockaddr_ns*)sa; 570 struct ns_addr work; 571 union { union ns_net net_e; u_long long_e; } net; 572 u_short port; 573 static char mybuf[50], cport[10], chost[25]; 574 char *host = ""; 575 register char *p; register u_char *q; 576 577 work = sns->sns_addr; 578 port = ntohs(work.x_port); 579 work.x_port = 0; 580 net.net_e = work.x_net; 581 if (ns_nullhost(work) && net.long_e == 0) { 582 if (port ) { 583 sprintf(mybuf, "*.%xH", port); 584 upHex(mybuf); 585 } else 586 sprintf(mybuf, "*.*"); 587 return (mybuf); 588 } 589 590 if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) { 591 host = "any"; 592 } else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) { 593 host = "*"; 594 } else { 595 q = work.x_host.c_host; 596 sprintf(chost, "%02x%02x%02x%02x%02x%02xH", 597 q[0], q[1], q[2], q[3], q[4], q[5]); 598 for (p = chost; *p == '0' && p < chost + 12; p++) 599 continue; 600 host = p; 601 } 602 if (port) 603 sprintf(cport, ".%xH", htons(port)); 604 else 605 *cport = 0; 606 607 sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport); 608 upHex(mybuf); 609 return(mybuf); 610 } 611 612 char * 613 ns_phost(sa) 614 struct sockaddr *sa; 615 { 616 register struct sockaddr_ns *sns = (struct sockaddr_ns *)sa; 617 struct sockaddr_ns work; 618 static union ns_net ns_zeronet; 619 char *p; 620 621 work = *sns; 622 work.sns_addr.x_port = 0; 623 work.sns_addr.x_net = ns_zeronet; 624 625 p = ns_print((struct sockaddr *)&work); 626 if (strncmp("0H.", p, 3) == 0) p += 3; 627 return(p); 628 } 629 630 void 631 upHex(p0) 632 char *p0; 633 { 634 register char *p = p0; 635 for (; *p; p++) switch (*p) { 636 637 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 638 *p += ('A' - 'a'); 639 } 640 } 641