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