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