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