xref: /original-bsd/usr.bin/netstat/route.c (revision 1e395994)
1 /*
2  * Copyright (c) 1983, 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)route.c	5.20 (Berkeley) 11/29/90";
10 #endif /* not lint */
11 
12 #include <sys/param.h>
13 #include <sys/socket.h>
14 #include <sys/mbuf.h>
15 
16 #include <net/if.h>
17 #define  KERNEL
18 #include <net/route.h>
19 #undef KERNEL
20 #include <netinet/in.h>
21 
22 #include <netns/ns.h>
23 
24 #include <netdb.h>
25 #include <sys/kinfo.h>
26 
27 #include <stdio.h>
28 #include <string.h>
29 
30 extern	int nflag, aflag, Aflag, af;
31 int do_rtent;
32 extern	char *routename(), *netname(), *ns_print(), *plural();
33 extern	char *malloc();
34 #define kget(p, d) \
35 	(kvm_read((off_t)(p), (char *)&(d), sizeof (d)))
36 
37 /*
38  * Definitions for showing gateway flags.
39  */
40 struct bits {
41 	short	b_mask;
42 	char	b_val;
43 } bits[] = {
44 	{ RTF_UP,	'U' },
45 	{ RTF_GATEWAY,	'G' },
46 	{ RTF_HOST,	'H' },
47 	{ RTF_DYNAMIC,	'D' },
48 	{ RTF_MODIFIED,	'M' },
49 	{ RTF_CLONING,	'C' },
50 	{ RTF_XRESOLVE,	'X' },
51 	{ RTF_LLINFO,	'L' },
52 	{ RTF_REJECT,	'R' },
53 	{ 0 }
54 };
55 
56 /*
57  * Print routing tables.
58  */
59 routepr(hostaddr, netaddr, hashsizeaddr, treeaddr)
60 	off_t hostaddr, netaddr, hashsizeaddr, treeaddr;
61 {
62 	struct mbuf mb;
63 	register struct ortentry *rt;
64 	register struct mbuf *m;
65 	char name[16], *flags;
66 	struct mbuf **routehash;
67 	int hashsize;
68 	int i, doinghost = 1;
69 
70 	printf("Routing tables\n");
71 	if (Aflag)
72 		printf("%-8.8s ","Address");
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);
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 	}
86 	if (hashsizeaddr == 0) {
87 		printf("rthashsize: symbol not in namelist\n");
88 		return;
89 	}
90 	kget(hashsizeaddr, hashsize);
91 	routehash = (struct mbuf **)malloc( hashsize*sizeof (struct mbuf *) );
92 	kvm_read(hostaddr, (char *)routehash, hashsize*sizeof (struct mbuf *));
93 again:
94 	for (i = 0; i < hashsize; i++) {
95 		if (routehash[i] == 0)
96 			continue;
97 		m = routehash[i];
98 		while (m) {
99 			kget(m, mb);
100 			if (Aflag)
101 				printf("%8.8x ", m);
102 			p_ortentry((struct ortentry *)(mb.m_dat));
103 			m = mb.m_next;
104 		}
105 	}
106 	if (doinghost) {
107 		kvm_read(netaddr, (char *)routehash,
108 			hashsize*sizeof (struct mbuf *));
109 		doinghost = 0;
110 		goto again;
111 	}
112 	free((char *)routehash);
113 	return;
114 }
115 
116 static union {
117 	struct	sockaddr u_sa;
118 	u_short	u_data[128];
119 } pt_u;
120 int do_rtent = 0;
121 struct rtentry rtentry;
122 struct radix_node rnode;
123 struct radix_mask rmask;
124 
125 int NewTree = 0;
126 treestuff(rtree)
127 off_t rtree;
128 {
129 	struct radix_node_head *rnh, head;
130 
131 	if (Aflag == 0 && NewTree)
132 		return(ntreestuff());
133 	for (kget(rtree, rnh); rnh; rnh = head.rnh_next) {
134 		kget(rnh, head);
135 		if (head.rnh_af == 0) {
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) {
141 			printf("\nRoute Tree for Protocol Family %d:\n",
142 								head.rnh_af);
143 			do_rtent = 1;
144 			p_tree(head.rnh_treetop);
145 		}
146 	}
147 }
148 
149 struct sockaddr *
150 kgetsa(dst)
151 register struct sockaddr *dst;
152 {
153 	kget(dst, pt_u.u_sa);
154 	if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa)) {
155 		kvm_read((off_t)dst, pt_u.u_data, pt_u.u_sa.sa_len);
156 	}
157 	return (&pt_u.u_sa);
158 }
159 
160 p_tree(rn)
161 struct radix_node *rn;
162 {
163 
164 again:
165 	kget(rn, rnode);
166 	if (rnode.rn_b < 0) {
167 		if (Aflag)
168 			printf("%-8.8x ", rn);
169 		if (rnode.rn_flags & RNF_ROOT)
170 			printf("(root node)%s",
171 				    rnode.rn_dupedkey ? " =>\n" : "\n");
172 		else if (do_rtent) {
173 			kget(rn, rtentry);
174 			p_rtentry(&rtentry);
175 			if (Aflag)
176 				p_rtnode();
177 		} else {
178 			p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key),
179 				    0, 44);
180 			putchar('\n');
181 		}
182 		if (rn = rnode.rn_dupedkey)
183 			goto again;
184 	} else {
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 }
194 char nbuf[20];
195 
196 p_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);
210 	}
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');
222 }
223 
224 ntreestuff()
225 {
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)
233 		{ printf("out of space\n"); exit(1);}
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);
240 	}
241 }
242 
243 np_rtentry(rtm)
244 register struct rt_msghdr *rtm;
245 {
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;
249 
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)
269 		p_sockaddr(sa, 0, 36);
270 	else {
271 		p_sockaddr(sa, rtm->rtm_flags, 16);
272 		if (sa->sa_len == 0)
273 			sa->sa_len = sizeof(long);
274 		sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
275 		p_sockaddr(sa, 0, 18);
276 	}
277 	p_flags(rtm->rtm_flags & interesting, "%-6.6s ");
278 	putchar('\n');
279 }
280 
281 p_sockaddr(sa, flags, width)
282 struct sockaddr *sa;
283 int flags, width;
284 {
285 	char format[20], workbuf[128], *cp, *cplim;
286 	register char *cpout;
287 
288 	switch(sa->sa_family) {
289 	case AF_INET:
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 	    }
297 		break;
298 
299 	case AF_NS:
300 		cp = ns_print((struct sockaddr_ns *)sa);
301 		break;
302 
303 	default:
304 	    {
305 		register u_short *s = ((u_short *)sa->sa_data), *slim;
306 
307 		slim = (u_short *) sa + ((sa->sa_len + sizeof(u_short) - 1) /
308 		    sizeof(u_short));
309 		cp = workbuf;
310 		cplim = cp + sizeof(workbuf) - 6;
311 		cp += sprintf(cp, "(%d)", sa->sa_family);
312 		while (s < slim && cp < cplim)
313 			cp += sprintf(cp, " %x", *s++);
314 		cp = workbuf;
315 	    }
316 	}
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 	}
325 }
326 
327 p_flags(f, format)
328 register int f;
329 char *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)
335 			*flags++ = p->b_val;
336 	*flags = '\0';
337 	printf(format, name);
338 }
339 
340 p_rtentry(rt)
341 register struct rtentry *rt;
342 {
343 	char name[16];
344 	register struct sockaddr *sa;
345 	struct ifnet ifnet;
346 
347 	p_sockaddr(kgetsa(rt_key(rt)), rt->rt_flags, 16);
348 	p_sockaddr(kgetsa(rt->rt_gateway), 0, 18);
349 	p_flags(rt->rt_flags, "%-6.6s ");
350 	printf("%6d %8d ", rt->rt_refcnt, rt->rt_use);
351 	if (rt->rt_ifp == 0) {
352 		putchar('\n');
353 		return;
354 	}
355 	kget(rt->rt_ifp, ifnet);
356 	kvm_read((off_t)ifnet.if_name, name, 16);
357 	printf(" %.15s%d%s", name, ifnet.if_unit,
358 		rt->rt_nodes[0].rn_dupedkey ? " =>\n" : "\n");
359 }
360 
361 p_ortentry(rt)
362 register 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 
369 	p_sockaddr(&rt->rt_dst, rt->rt_flags, 16);
370 	p_sockaddr(&rt->rt_gateway, 0, 18);
371 	p_flags(rt->rt_flags, "%-6.6s ");
372 	printf("%6d %8d ", rt->rt_refcnt, rt->rt_use);
373 	if (rt->rt_ifp == 0) {
374 		putchar('\n');
375 		return;
376 	}
377 	kget(rt->rt_ifp, ifnet);
378 	kvm_read((off_t)ifnet.if_name, name, 16);
379 	printf(" %.15s%d\n", name, ifnet.if_unit);
380 }
381 
382 char *
383 routename(in)
384 	struct in_addr in;
385 {
386 	register char *cp;
387 	static char line[MAXHOSTNAMELEN + 1];
388 	struct hostent *hp;
389 	static char domain[MAXHOSTNAMELEN + 1];
390 	static int first = 1;
391 	char *index();
392 
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 	}
401 	cp = 0;
402 	if (!nflag) {
403 		hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
404 			AF_INET);
405 		if (hp) {
406 			if ((cp = index(hp->h_name, '.')) &&
407 			    !strcmp(cp + 1, domain))
408 				*cp = 0;
409 			cp = hp->h_name;
410 		}
411 	}
412 	if (cp)
413 		strncpy(line, cp, sizeof(line) - 1);
414 	else {
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  */
427 char *
428 netname(in, mask)
429 	struct in_addr in;
430 	u_long mask;
431 {
432 	char *cp = 0;
433 	static char line[MAXHOSTNAMELEN + 1];
434 	struct netent *np = 0;
435 	u_long net;
436 	register i;
437 	int subnetshift;
438 
439 	i = ntohl(in.s_addr);
440 	if (!nflag && i) {
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 			}
452 			/*
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.
457 			 */
458 			while (i &~ mask)
459 				mask = (long)mask >> subnetshift;
460 		}
461 		net = i & mask;
462 		while ((mask & 1) == 0)
463 			mask >>= 1, net >>= 1;
464 		np = getnetbyaddr(net, AF_INET);
465 		if (np)
466 			cp = np->n_name;
467 	}
468 	if (cp)
469 		strncpy(line, cp, sizeof(line) - 1);
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));
476 	else
477 		sprintf(line, "%u.%u.%u.%u", C(i >> 24),
478 			C(i >> 16), C(i >> 8), C(i));
479 	return (line);
480 }
481 
482 /*
483  * Print routing statistics
484  */
485 rt_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 	}
494 	kvm_read(off, (char *)&rtstat, sizeof (rtstat));
495 	printf("routing:\n");
496 	printf("\t%u bad routing redirect%s\n",
497 		rtstat.rts_badredirect, plural(rtstat.rts_badredirect));
498 	printf("\t%u dynamically created route%s\n",
499 		rtstat.rts_dynamic, plural(rtstat.rts_dynamic));
500 	printf("\t%u new gateway%s due to redirects\n",
501 		rtstat.rts_newgateway, plural(rtstat.rts_newgateway));
502 	printf("\t%u destination%s found unreachable\n",
503 		rtstat.rts_unreach, plural(rtstat.rts_unreach));
504 	printf("\t%u use%s of a wildcard route\n",
505 		rtstat.rts_wildcard, plural(rtstat.rts_wildcard));
506 }
507 short ns_nullh[] = {0,0,0};
508 short ns_bh[] = {-1,-1,-1};
509 
510 char *
511 ns_print(sns)
512 struct sockaddr_ns *sns;
513 {
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 = "";
519 	register char *p; register u_char *q;
520 
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 	}
533 
534 	if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) {
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;
544 	}
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);
552 	return(mybuf);
553 }
554 
555 char *
556 ns_phost(sns)
557 struct sockaddr_ns *sns;
558 {
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 }
571 upHex(p0)
572 char *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 	}
580 }
581