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