incorporate changes for new kvm interfaces from lbl
[unix-history] / usr / src / usr.bin / netstat / route.c
... / ...
CommitLineData
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
9static char sccsid[] = "@(#)route.c 5.23 (Berkeley) %G%";
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/kinfo.h>
28
29#include <netdb.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include "netstat.h"
34
35#define kget(p, d) \
36 (kread((off_t)(p), (char *)&(d), sizeof (d)))
37
38/*
39 * Definitions for showing gateway flags.
40 */
41struct 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_DYNAMIC, 'D' },
49 { RTF_MODIFIED, 'M' },
50 { RTF_CLONING, 'C' },
51 { RTF_XRESOLVE, 'X' },
52 { RTF_LLINFO, 'L' },
53 { RTF_REJECT, 'R' },
54 { RTF_STATIC, 'S' },
55 { 0 }
56};
57
58static union {
59 struct sockaddr u_sa;
60 u_short u_data[128];
61} pt_u;
62
63int do_rtent = 0;
64struct rtentry rtentry;
65struct radix_node rnode;
66struct radix_mask rmask;
67
68int NewTree = 0;
69
70static struct sockaddr *kgetsa __P((struct sockaddr *));
71static void p_tree __P((struct radix_node *));
72static void p_rtnode __P(());
73static void ntreestuff __P(());
74static void np_rtentry __P((struct rt_msghdr *));
75static void p_sockaddr __P((struct sockaddr *, int, int));
76static void p_flags __P((int, char *));
77static void p_rtentry __P((struct rtentry *));
78
79/*
80 * Print routing tables.
81 */
82void
83routepr(rtree)
84 off_t rtree;
85{
86 struct radix_node_head *rnh, head;
87 int i;
88
89 printf("Routing tables\n");
90
91 if (Aflag == 0 && NewTree)
92 ntreestuff();
93 else {
94 if (rtree == 0) {
95 printf("rt_tables: symbol not in namelist\n");
96 return;
97 }
98
99 kget(rtree, rt_tables);
100 for (i = 0; i <= AF_MAX; i++) {
101 if ((rnh = rt_tables[i]) == 0)
102 continue;
103 kget(rnh, head);
104 if (i == AF_UNSPEC) {
105 if (Aflag && af == 0) {
106 printf("Netmasks:\n");
107 p_tree(head.rnh_treetop);
108 }
109 } else if (af == AF_UNSPEC || af == i) {
110 pr_family(i);
111 do_rtent = 1;
112 pr_rthdr();
113 p_tree(head.rnh_treetop);
114 }
115 }
116 }
117}
118
119/*
120 * Print address family header before a section of the routing table.
121 */
122void
123pr_family(af)
124 int af;
125{
126 char *afname;
127
128 switch (af) {
129 case AF_INET:
130 afname = "Internet";
131 break;
132 case AF_NS:
133 afname = "XNS";
134 break;
135 case AF_ISO:
136 afname = "ISO";
137 break;
138 case AF_CCITT:
139 afname = "X.25";
140 break;
141 default:
142 afname = NULL;
143 break;
144 }
145 if (afname)
146 printf("\n%s:\n", afname);
147 else
148 printf("\nProtocol Family %d:\n", af);
149}
150
151/* column widths; each followed by one space */
152#define WID_DST 16 /* width of destination column */
153#define WID_GW 18 /* width of gateway column */
154
155/*
156 * Print header for routing table columns.
157 */
158void
159pr_rthdr()
160{
161
162 if (Aflag)
163 printf("%-8.8s ","Address");
164 printf("%-*.*s %-*.*s %-6.6s %6.6s%8.8s %s\n",
165 WID_DST, WID_DST, "Destination",
166 WID_GW, WID_GW, "Gateway",
167 "Flags", "Refs", "Use", "Interface");
168}
169
170static struct sockaddr *
171kgetsa(dst)
172 register struct sockaddr *dst;
173{
174
175 kget(dst, pt_u.u_sa);
176 if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa))
177 kread((off_t)dst, (char *)pt_u.u_data, pt_u.u_sa.sa_len);
178 return (&pt_u.u_sa);
179}
180
181static void
182p_tree(rn)
183 struct radix_node *rn;
184{
185
186again:
187 kget(rn, rnode);
188 if (rnode.rn_b < 0) {
189 if (Aflag)
190 printf("%-8.8x ", rn);
191 if (rnode.rn_flags & RNF_ROOT) {
192 if (Aflag)
193 printf("(root node)%s",
194 rnode.rn_dupedkey ? " =>\n" : "\n");
195 } else if (do_rtent) {
196 kget(rn, rtentry);
197 p_rtentry(&rtentry);
198 if (Aflag)
199 p_rtnode();
200 } else {
201 p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key),
202 0, 44);
203 putchar('\n');
204 }
205 if (rn = rnode.rn_dupedkey)
206 goto again;
207 } else {
208 if (Aflag && do_rtent) {
209 printf("%-8.8x ", rn);
210 p_rtnode();
211 }
212 rn = rnode.rn_r;
213 p_tree(rnode.rn_l);
214 p_tree(rn);
215 }
216}
217
218char nbuf[20];
219
220static void
221p_rtnode()
222{
223 struct radix_mask *rm = rnode.rn_mklist;
224
225 if (rnode.rn_b < 0) {
226 if (rnode.rn_mask) {
227 printf("\t mask ");
228 p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask),
229 0, -1);
230 } else if (rm == 0)
231 return;
232 } else {
233 sprintf(nbuf, "(%d)", rnode.rn_b);
234 printf("%6.6s %8.8x : %8.8x", nbuf, rnode.rn_l, rnode.rn_r);
235 }
236 while (rm) {
237 kget(rm, rmask);
238 sprintf(nbuf, " %d refs, ", rmask.rm_refs);
239 printf(" mk = %8.8x {(%d),%s",
240 rm, -1 - rmask.rm_b, rmask.rm_refs ? nbuf : " ");
241 p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask), 0, -1);
242 putchar('}');
243 if (rm = rmask.rm_mklist)
244 printf(" ->");
245 }
246 putchar('\n');
247}
248
249static void
250ntreestuff()
251{
252 int needed;
253 char *buf, *next, *lim;
254 register struct rt_msghdr *rtm;
255
256 if ((needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0)) < 0)
257 { perror("route-getkerninfo-estimate"); exit(1);}
258 if ((buf = malloc(needed)) == 0)
259 { printf("out of space\n"); exit(1);}
260 if (getkerninfo(KINFO_RT_DUMP, buf, &needed, 0) < 0)
261 { perror("getkerninfo of routing table"); exit(1);}
262 lim = buf + needed;
263 for (next = buf; next < lim; next += rtm->rtm_msglen) {
264 rtm = (struct rt_msghdr *)next;
265 np_rtentry(rtm);
266 }
267}
268
269static void
270np_rtentry(rtm)
271 register struct rt_msghdr *rtm;
272{
273 register struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
274#ifdef notdef
275 static int masks_done, banner_printed;
276#endif
277 static int old_af;
278 int af = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST;
279
280#ifdef notdef
281 /* for the moment, netmasks are skipped over */
282 if (!banner_printed) {
283 printf("Netmasks:\n");
284 banner_printed = 1;
285 }
286 if (masks_done == 0) {
287 if (rtm->rtm_addrs != RTA_DST ) {
288 masks_done = 1;
289 af = sa->sa_family;
290 }
291 } else
292#endif
293 af = sa->sa_family;
294 if (af != old_af) {
295 pr_family(af);
296 old_af = af;
297 }
298 if (rtm->rtm_addrs == RTA_DST)
299 p_sockaddr(sa, 0, 36);
300 else {
301 p_sockaddr(sa, rtm->rtm_flags, 16);
302 if (sa->sa_len == 0)
303 sa->sa_len = sizeof(long);
304 sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
305 p_sockaddr(sa, 0, 18);
306 }
307 p_flags(rtm->rtm_flags & interesting, "%-6.6s ");
308 putchar('\n');
309}
310
311static void
312p_sockaddr(sa, flags, width)
313 struct sockaddr *sa;
314 int flags, width;
315{
316 char workbuf[128], *cplim;
317 register char *cp = workbuf;
318
319 switch(sa->sa_family) {
320 case AF_INET:
321 {
322 register struct sockaddr_in *sin = (struct sockaddr_in *)sa;
323
324 cp = (sin->sin_addr.s_addr == 0) ? "default" :
325 ((flags & RTF_HOST) ?
326 routename(sin->sin_addr.s_addr) :
327 netname(sin->sin_addr.s_addr, 0L));
328 break;
329 }
330
331 case AF_NS:
332 cp = ns_print(sa);
333 break;
334
335 case AF_LINK:
336 {
337 register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
338
339 if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
340 sdl->sdl_slen == 0)
341 (void) sprintf(workbuf, "link#%d", sdl->sdl_index);
342 else switch (sdl->sdl_type) {
343 case IFT_ETHER:
344 {
345 register int i;
346 register u_char *lla = (u_char *)sdl->sdl_data +
347 sdl->sdl_nlen;
348
349 cplim = "";
350 for (i = 0; i < sdl->sdl_alen; i++, lla++) {
351 cp += sprintf(cp, "%s%x", cplim, *lla);
352 cplim = ":";
353 }
354 cp = workbuf;
355 break;
356 }
357 default:
358 cp = link_ntoa(sdl);
359 break;
360 }
361 break;
362 }
363
364 default:
365 {
366 register u_short *s = ((u_short *)sa->sa_data), *slim;
367
368 slim = (u_short *) sa + ((sa->sa_len + sizeof(u_short) - 1) /
369 sizeof(u_short));
370 cplim = cp + sizeof(workbuf) - 6;
371 cp += sprintf(cp, "(%d)", sa->sa_family);
372 while (s < slim && cp < cplim)
373 cp += sprintf(cp, " %x", *s++);
374 cp = workbuf;
375 }
376 }
377 if (width < 0 )
378 printf("%s ", cp);
379 else {
380 if (nflag)
381 printf("%-*s ", width, cp);
382 else
383 printf("%-*.*s ", width, width, cp);
384 }
385}
386
387static void
388p_flags(f, format)
389 register int f;
390 char *format;
391{
392 char name[33], *flags;
393 register struct bits *p = bits;
394
395 for (flags = name; p->b_mask; p++)
396 if (p->b_mask & f)
397 *flags++ = p->b_val;
398 *flags = '\0';
399 printf(format, name);
400}
401
402static void
403p_rtentry(rt)
404 register struct rtentry *rt;
405{
406 static struct ifnet ifnet, *lastif;
407 static char name[16];
408
409 p_sockaddr(kgetsa(rt_key(rt)), rt->rt_flags, WID_DST);
410 p_sockaddr(kgetsa(rt->rt_gateway), 0, WID_GW);
411 p_flags(rt->rt_flags, "%-6.6s ");
412 printf("%6d %8d ", rt->rt_refcnt, rt->rt_use);
413 if (rt->rt_ifp) {
414 if (rt->rt_ifp != lastif) {
415 kget(rt->rt_ifp, ifnet);
416 kread((off_t)ifnet.if_name, name, 16);
417 lastif = rt->rt_ifp;
418 }
419 printf(" %.15s%d%s", name, ifnet.if_unit,
420 rt->rt_nodes[0].rn_dupedkey ? " =>" : "");
421 }
422 putchar('\n');
423}
424
425char *
426routename(in)
427 u_long in;
428{
429 register char *cp;
430 static char line[MAXHOSTNAMELEN + 1];
431 struct hostent *hp;
432 static char domain[MAXHOSTNAMELEN + 1];
433 static int first = 1;
434
435 if (first) {
436 first = 0;
437 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
438 (cp = index(domain, '.')))
439 (void) strcpy(domain, cp + 1);
440 else
441 domain[0] = 0;
442 }
443 cp = 0;
444 if (!nflag) {
445 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
446 AF_INET);
447 if (hp) {
448 if ((cp = index(hp->h_name, '.')) &&
449 !strcmp(cp + 1, domain))
450 *cp = 0;
451 cp = hp->h_name;
452 }
453 }
454 if (cp)
455 strncpy(line, cp, sizeof(line) - 1);
456 else {
457#define C(x) ((x) & 0xff)
458 in = ntohl(in);
459 sprintf(line, "%u.%u.%u.%u",
460 C(in >> 24), C(in >> 16), C(in >> 8), C(in));
461 }
462 return (line);
463}
464
465/*
466 * Return the name of the network whose address is given.
467 * The address is assumed to be that of a net or subnet, not a host.
468 */
469char *
470netname(in, mask)
471 u_long in, mask;
472{
473 char *cp = 0;
474 static char line[MAXHOSTNAMELEN + 1];
475 struct netent *np = 0;
476 u_long net;
477 register int i;
478 int subnetshift;
479
480 i = ntohl(in);
481 if (!nflag && i) {
482 if (mask == 0) {
483 if (IN_CLASSA(i)) {
484 mask = IN_CLASSA_NET;
485 subnetshift = 8;
486 } else if (IN_CLASSB(i)) {
487 mask = IN_CLASSB_NET;
488 subnetshift = 8;
489 } else {
490 mask = IN_CLASSC_NET;
491 subnetshift = 4;
492 }
493 /*
494 * If there are more bits than the standard mask
495 * would suggest, subnets must be in use.
496 * Guess at the subnet mask, assuming reasonable
497 * width subnet fields.
498 */
499 while (i &~ mask)
500 mask = (long)mask >> subnetshift;
501 }
502 net = i & mask;
503 while ((mask & 1) == 0)
504 mask >>= 1, net >>= 1;
505 np = getnetbyaddr(net, AF_INET);
506 if (np)
507 cp = np->n_name;
508 }
509 if (cp)
510 strncpy(line, cp, sizeof(line) - 1);
511 else if ((i & 0xffffff) == 0)
512 sprintf(line, "%u", C(i >> 24));
513 else if ((i & 0xffff) == 0)
514 sprintf(line, "%u.%u", C(i >> 24) , C(i >> 16));
515 else if ((i & 0xff) == 0)
516 sprintf(line, "%u.%u.%u", C(i >> 24), C(i >> 16), C(i >> 8));
517 else
518 sprintf(line, "%u.%u.%u.%u", C(i >> 24),
519 C(i >> 16), C(i >> 8), C(i));
520 return (line);
521}
522
523/*
524 * Print routing statistics
525 */
526void
527rt_stats(off)
528 off_t off;
529{
530 struct rtstat rtstat;
531
532 if (off == 0) {
533 printf("rtstat: symbol not in namelist\n");
534 return;
535 }
536 kread(off, (char *)&rtstat, sizeof (rtstat));
537 printf("routing:\n");
538 printf("\t%u bad routing redirect%s\n",
539 rtstat.rts_badredirect, plural(rtstat.rts_badredirect));
540 printf("\t%u dynamically created route%s\n",
541 rtstat.rts_dynamic, plural(rtstat.rts_dynamic));
542 printf("\t%u new gateway%s due to redirects\n",
543 rtstat.rts_newgateway, plural(rtstat.rts_newgateway));
544 printf("\t%u destination%s found unreachable\n",
545 rtstat.rts_unreach, plural(rtstat.rts_unreach));
546 printf("\t%u use%s of a wildcard route\n",
547 rtstat.rts_wildcard, plural(rtstat.rts_wildcard));
548}
549short ns_nullh[] = {0,0,0};
550short ns_bh[] = {-1,-1,-1};
551
552char *
553ns_print(sa)
554 register struct sockaddr *sa;
555{
556 register struct sockaddr_ns *sns = (struct sockaddr_ns*)sa;
557 struct ns_addr work;
558 union { union ns_net net_e; u_long long_e; } net;
559 u_short port;
560 static char mybuf[50], cport[10], chost[25];
561 char *host = "";
562 register char *p; register u_char *q;
563
564 work = sns->sns_addr;
565 port = ntohs(work.x_port);
566 work.x_port = 0;
567 net.net_e = work.x_net;
568 if (ns_nullhost(work) && net.long_e == 0) {
569 if (port ) {
570 sprintf(mybuf, "*.%xH", port);
571 upHex(mybuf);
572 } else
573 sprintf(mybuf, "*.*");
574 return (mybuf);
575 }
576
577 if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) {
578 host = "any";
579 } else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) {
580 host = "*";
581 } else {
582 q = work.x_host.c_host;
583 sprintf(chost, "%02x%02x%02x%02x%02x%02xH",
584 q[0], q[1], q[2], q[3], q[4], q[5]);
585 for (p = chost; *p == '0' && p < chost + 12; p++)
586 continue;
587 host = p;
588 }
589 if (port)
590 sprintf(cport, ".%xH", htons(port));
591 else
592 *cport = 0;
593
594 sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport);
595 upHex(mybuf);
596 return(mybuf);
597}
598
599char *
600ns_phost(sa)
601 struct sockaddr *sa;
602{
603 register struct sockaddr_ns *sns = (struct sockaddr_ns *)sa;
604 struct sockaddr_ns work;
605 static union ns_net ns_zeronet;
606 char *p;
607
608 work = *sns;
609 work.sns_addr.x_port = 0;
610 work.sns_addr.x_net = ns_zeronet;
611
612 p = ns_print((struct sockaddr *)&work);
613 if (strncmp("0H.", p, 3) == 0) p += 3;
614 return(p);
615}
616
617void
618upHex(p0)
619 char *p0;
620{
621 register char *p = p0;
622 for (; *p; p++) switch (*p) {
623
624 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
625 *p += ('A' - 'a');
626 }
627}