xref: /original-bsd/usr.bin/netstat/route.c (revision 262b24ac)
1 /*
2  * Copyright (c) 1983, 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
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.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)route.c	5.15 (Berkeley) 12/07/88";
20 #endif /* not lint */
21 
22 #include <stdio.h>
23 #include <strings.h>
24 
25 #include <sys/param.h>
26 #include <sys/socket.h>
27 #include <sys/mbuf.h>
28 
29 #include <net/if.h>
30 #define  KERNEL
31 #include <net/route.h>
32 #undef KERNEL
33 #include <netinet/in.h>
34 
35 #include <netns/ns.h>
36 
37 #include <netdb.h>
38 
39 extern	int kmem;
40 extern	int nflag;
41 extern	char *routename(), *netname(), *ns_print(), *plural();
42 extern	char *malloc();
43 #define kget(p, d) \
44 	(klseek(kmem, (off_t)(p), 0), read(kmem, (char *)&(d), sizeof (d)))
45 
46 /*
47  * Definitions for showing gateway flags.
48  */
49 struct bits {
50 	short	b_mask;
51 	char	b_val;
52 } bits[] = {
53 	{ RTF_UP,	'U' },
54 	{ RTF_GATEWAY,	'G' },
55 	{ RTF_HOST,	'H' },
56 	{ RTF_DYNAMIC,	'D' },
57 	{ RTF_MODIFIED,	'M' },
58 	{ 0 }
59 };
60 
61 /*
62  * Print routing tables.
63  */
64 routepr(hostaddr, netaddr, hashsizeaddr, treeaddr)
65 	off_t hostaddr, netaddr, hashsizeaddr, treeaddr;
66 {
67 	struct mbuf mb;
68 	register struct ortentry *rt;
69 	register struct mbuf *m;
70 	char name[16], *flags;
71 	struct mbuf **routehash;
72 	int hashsize;
73 	int i, doinghost = 1;
74 
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);
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 	}
89 	if (hashsizeaddr == 0) {
90 		printf("rthashsize: symbol not in namelist\n");
91 		return;
92 	}
93 	kget(hashsizeaddr, hashsize);
94 	routehash = (struct mbuf **)malloc( hashsize*sizeof (struct mbuf *) );
95 	klseek(kmem, hostaddr, 0);
96 	read(kmem, (char *)routehash, hashsize*sizeof (struct mbuf *));
97 again:
98 	for (i = 0; i < hashsize; i++) {
99 		if (routehash[i] == 0)
100 			continue;
101 		m = routehash[i];
102 		while (m) {
103 			kget(m, mb);
104 			p_rtentry((struct rtentry *)(mb.m_dat));
105 			m = mb.m_next;
106 		}
107 	}
108 	if (doinghost) {
109 		klseek(kmem, netaddr, 0);
110 		read(kmem, (char *)routehash, hashsize*sizeof (struct mbuf *));
111 		doinghost = 0;
112 		goto again;
113 	}
114 	free((char *)routehash);
115 	return;
116 }
117 
118 static union {
119 	struct	sockaddr u_sa;
120 	u_short	u_data[128];
121 } pt_u;
122 static struct rtentry rtentry;
123 
124 treestuff(rtree)
125 off_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 
142 p_tree(rn, do_rtent)
143 struct radix_node *rn;
144 {
145 	struct radix_node rnode;
146 	register u_short *s, *slim;
147 	int len;
148 
149 again:
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 
175 struct sockaddr *
176 kgetsa(dst)
177 register 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 
187 p_rtentry(rt)
188 register 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 
240 p_ortentry(rt)
241 register 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);
291 }
292 
293 char *
294 routename(in)
295 	struct in_addr in;
296 {
297 	register char *cp;
298 	static char line[MAXHOSTNAMELEN + 1];
299 	struct hostent *hp;
300 	static char domain[MAXHOSTNAMELEN + 1];
301 	static int first = 1;
302 	char *index();
303 
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 	}
312 	cp = 0;
313 	if (!nflag) {
314 		hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
315 			AF_INET);
316 		if (hp) {
317 			if ((cp = index(hp->h_name, '.')) &&
318 			    !strcmp(cp + 1, domain))
319 				*cp = 0;
320 			cp = hp->h_name;
321 		}
322 	}
323 	if (cp)
324 		strncpy(line, cp, sizeof(line) - 1);
325 	else {
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  */
338 char *
339 netname(in, mask)
340 	struct in_addr in;
341 	u_long mask;
342 {
343 	char *cp = 0;
344 	static char line[MAXHOSTNAMELEN + 1];
345 	struct netent *np = 0;
346 	u_long net;
347 	register i;
348 	int subnetshift;
349 
350 	i = ntohl(in.s_addr);
351 	if (!nflag && i) {
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 			}
363 			/*
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.
368 			 */
369 			while (i &~ mask)
370 				mask = (long)mask >> subnetshift;
371 		}
372 		net = i & mask;
373 		while ((mask & 1) == 0)
374 			mask >>= 1, net >>= 1;
375 		np = getnetbyaddr(net, AF_INET);
376 		if (np)
377 			cp = np->n_name;
378 	}
379 	if (cp)
380 		strncpy(line, cp, sizeof(line) - 1);
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));
387 	else
388 		sprintf(line, "%u.%u.%u.%u", C(i >> 24),
389 			C(i >> 16), C(i >> 8), C(i));
390 	return (line);
391 }
392 
393 /*
394  * Print routing statistics
395  */
396 rt_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");
408 	printf("\t%u bad routing redirect%s\n",
409 		rtstat.rts_badredirect, plural(rtstat.rts_badredirect));
410 	printf("\t%u dynamically created route%s\n",
411 		rtstat.rts_dynamic, plural(rtstat.rts_dynamic));
412 	printf("\t%u new gateway%s due to redirects\n",
413 		rtstat.rts_newgateway, plural(rtstat.rts_newgateway));
414 	printf("\t%u destination%s found unreachable\n",
415 		rtstat.rts_unreach, plural(rtstat.rts_unreach));
416 	printf("\t%u use%s of a wildcard route\n",
417 		rtstat.rts_wildcard, plural(rtstat.rts_wildcard));
418 }
419 short ns_nullh[] = {0,0,0};
420 short ns_bh[] = {-1,-1,-1};
421 
422 char *
423 ns_print(sns)
424 struct sockaddr_ns *sns;
425 {
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 = "";
431 	register char *p; register u_char *q;
432 
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 	}
445 
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;
456 	}
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);
464 	return(mybuf);
465 }
466 
467 char *
468 ns_phost(sns)
469 struct sockaddr_ns *sns;
470 {
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 }
483 upHex(p0)
484 char *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 	}
492 }
493