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