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