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