route.c revision 1590
1/*
2 * Copyright (c) 1983, 1988, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char sccsid[] = "@(#)route.c	8.3 (Berkeley) 3/9/94";
36#endif /* not lint */
37
38#include <sys/param.h>
39#include <sys/protosw.h>
40#include <sys/socket.h>
41#include <sys/mbuf.h>
42
43#include <net/if.h>
44#include <net/if_dl.h>
45#include <net/if_types.h>
46#define  KERNEL
47#include <net/route.h>
48#undef KERNEL
49#include <netinet/in.h>
50
51#include <netns/ns.h>
52
53#include <sys/sysctl.h>
54
55#include <netdb.h>
56#include <stdio.h>
57#include <stdlib.h>
58#include <string.h>
59#include <unistd.h>
60#include "netstat.h"
61
62#define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d)))
63
64/*
65 * Definitions for showing gateway flags.
66 */
67struct bits {
68	short	b_mask;
69	char	b_val;
70} bits[] = {
71	{ RTF_UP,	'U' },
72	{ RTF_GATEWAY,	'G' },
73	{ RTF_HOST,	'H' },
74	{ RTF_REJECT,	'R' },
75	{ RTF_DYNAMIC,	'D' },
76	{ RTF_MODIFIED,	'M' },
77	{ RTF_DONE,	'd' }, /* Completed -- for routing messages only */
78	{ RTF_MASK,	'm' }, /* Mask Present -- for routing messages only */
79	{ RTF_CLONING,	'C' },
80	{ RTF_XRESOLVE,	'X' },
81	{ RTF_LLINFO,	'L' },
82	{ RTF_STATIC,	'S' },
83	{ RTF_PROTO1,	'1' },
84	{ RTF_PROTO2,	'2' },
85	{ 0 }
86};
87
88static union {
89	struct	sockaddr u_sa;
90	u_short	u_data[128];
91} pt_u;
92
93int	do_rtent = 0;
94struct	rtentry rtentry;
95struct	radix_node rnode;
96struct	radix_mask rmask;
97
98int	NewTree = 0;
99
100static struct sockaddr *kgetsa __P((struct sockaddr *));
101static void p_tree __P((struct radix_node *));
102static void p_rtnode __P(());
103static void ntreestuff __P(());
104static void np_rtentry __P((struct rt_msghdr *));
105static void p_sockaddr __P((struct sockaddr *, int, int));
106static void p_flags __P((int, char *));
107static void p_rtentry __P((struct rtentry *));
108
109/*
110 * Print routing tables.
111 */
112void
113routepr(rtree)
114	u_long rtree;
115{
116	struct radix_node_head *rnh, head;
117	int i;
118
119	printf("Routing tables\n");
120
121	if (Aflag == 0 && NewTree)
122		ntreestuff();
123	else {
124		if (rtree == 0) {
125			printf("rt_tables: symbol not in namelist\n");
126			return;
127		}
128
129		kget(rtree, rt_tables);
130		for (i = 0; i <= AF_MAX; i++) {
131			if ((rnh = rt_tables[i]) == 0)
132				continue;
133			kget(rnh, head);
134			if (i == AF_UNSPEC) {
135				if (Aflag && af == 0) {
136					printf("Netmasks:\n");
137					p_tree(head.rnh_treetop);
138				}
139			} else if (af == AF_UNSPEC || af == i) {
140				pr_family(i);
141				do_rtent = 1;
142				pr_rthdr();
143				p_tree(head.rnh_treetop);
144			}
145		}
146	}
147}
148
149/*
150 * Print address family header before a section of the routing table.
151 */
152void
153pr_family(af)
154	int af;
155{
156	char *afname;
157
158	switch (af) {
159	case AF_INET:
160		afname = "Internet";
161		break;
162	case AF_NS:
163		afname = "XNS";
164		break;
165	case AF_ISO:
166		afname = "ISO";
167		break;
168	case AF_CCITT:
169		afname = "X.25";
170		break;
171	default:
172		afname = NULL;
173		break;
174	}
175	if (afname)
176		printf("\n%s:\n", afname);
177	else
178		printf("\nProtocol Family %d:\n", af);
179}
180
181/* column widths; each followed by one space */
182#define	WID_DST		16	/* width of destination column */
183#define	WID_GW		18	/* width of gateway column */
184
185/*
186 * Print header for routing table columns.
187 */
188void
189pr_rthdr()
190{
191
192	if (Aflag)
193		printf("%-8.8s ","Address");
194	printf("%-*.*s %-*.*s %-6.6s  %6.6s%8.8s  %s\n",
195		WID_DST, WID_DST, "Destination",
196		WID_GW, WID_GW, "Gateway",
197		"Flags", "Refs", "Use", "Interface");
198}
199
200static struct sockaddr *
201kgetsa(dst)
202	register struct sockaddr *dst;
203{
204
205	kget(dst, pt_u.u_sa);
206	if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa))
207		kread((u_long)dst, (char *)pt_u.u_data, pt_u.u_sa.sa_len);
208	return (&pt_u.u_sa);
209}
210
211static void
212p_tree(rn)
213	struct radix_node *rn;
214{
215
216again:
217	kget(rn, rnode);
218	if (rnode.rn_b < 0) {
219		if (Aflag)
220			printf("%-8.8x ", rn);
221		if (rnode.rn_flags & RNF_ROOT) {
222			if (Aflag)
223				printf("(root node)%s",
224				    rnode.rn_dupedkey ? " =>\n" : "\n");
225		} else if (do_rtent) {
226			kget(rn, rtentry);
227			p_rtentry(&rtentry);
228			if (Aflag)
229				p_rtnode();
230		} else {
231			p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key),
232			    0, 44);
233			putchar('\n');
234		}
235		if (rn = rnode.rn_dupedkey)
236			goto again;
237	} else {
238		if (Aflag && do_rtent) {
239			printf("%-8.8x ", rn);
240			p_rtnode();
241		}
242		rn = rnode.rn_r;
243		p_tree(rnode.rn_l);
244		p_tree(rn);
245	}
246}
247
248char	nbuf[20];
249
250static void
251p_rtnode()
252{
253	struct radix_mask *rm = rnode.rn_mklist;
254
255	if (rnode.rn_b < 0) {
256		if (rnode.rn_mask) {
257			printf("\t  mask ");
258			p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask),
259				    0, -1);
260		} else if (rm == 0)
261			return;
262	} else {
263		sprintf(nbuf, "(%d)", rnode.rn_b);
264		printf("%6.6s %8.8x : %8.8x", nbuf, rnode.rn_l, rnode.rn_r);
265	}
266	while (rm) {
267		kget(rm, rmask);
268		sprintf(nbuf, " %d refs, ", rmask.rm_refs);
269		printf(" mk = %8.8x {(%d),%s",
270			rm, -1 - rmask.rm_b, rmask.rm_refs ? nbuf : " ");
271		p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask), 0, -1);
272		putchar('}');
273		if (rm = rmask.rm_mklist)
274			printf(" ->");
275	}
276	putchar('\n');
277}
278
279static void
280ntreestuff()
281{
282	size_t needed;
283	int mib[6];
284	char *buf, *next, *lim;
285	register struct rt_msghdr *rtm;
286
287        mib[0] = CTL_NET;
288        mib[1] = PF_ROUTE;
289        mib[2] = 0;
290        mib[3] = 0;
291        mib[4] = NET_RT_DUMP;
292        mib[5] = 0;
293        if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
294		{ perror("route-sysctl-estimate"); exit(1);}
295	if ((buf = malloc(needed)) == 0)
296		{ printf("out of space\n"); exit(1);}
297        if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
298		{ perror("sysctl of routing table"); exit(1);}
299	lim  = buf + needed;
300	for (next = buf; next < lim; next += rtm->rtm_msglen) {
301		rtm = (struct rt_msghdr *)next;
302		np_rtentry(rtm);
303	}
304}
305
306static void
307np_rtentry(rtm)
308	register struct rt_msghdr *rtm;
309{
310	register struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
311#ifdef notdef
312	static int masks_done, banner_printed;
313#endif
314	static int old_af;
315	int af = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST;
316
317#ifdef notdef
318	/* for the moment, netmasks are skipped over */
319	if (!banner_printed) {
320		printf("Netmasks:\n");
321		banner_printed = 1;
322	}
323	if (masks_done == 0) {
324		if (rtm->rtm_addrs != RTA_DST ) {
325			masks_done = 1;
326			af = sa->sa_family;
327		}
328	} else
329#endif
330		af = sa->sa_family;
331	if (af != old_af) {
332		pr_family(af);
333		old_af = af;
334	}
335	if (rtm->rtm_addrs == RTA_DST)
336		p_sockaddr(sa, 0, 36);
337	else {
338		p_sockaddr(sa, rtm->rtm_flags, 16);
339		if (sa->sa_len == 0)
340			sa->sa_len = sizeof(long);
341		sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
342		p_sockaddr(sa, 0, 18);
343	}
344	p_flags(rtm->rtm_flags & interesting, "%-6.6s ");
345	putchar('\n');
346}
347
348static void
349p_sockaddr(sa, flags, width)
350	struct sockaddr *sa;
351	int flags, width;
352{
353	char workbuf[128], *cplim;
354	register char *cp = workbuf;
355
356	switch(sa->sa_family) {
357	case AF_INET:
358	    {
359		register struct sockaddr_in *sin = (struct sockaddr_in *)sa;
360
361		cp = (sin->sin_addr.s_addr == 0) ? "default" :
362		      ((flags & RTF_HOST) ?
363			routename(sin->sin_addr.s_addr) :
364			netname(sin->sin_addr.s_addr, 0L));
365		break;
366	    }
367
368	case AF_NS:
369		cp = ns_print(sa);
370		break;
371
372	case AF_LINK:
373	    {
374		register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
375
376		if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
377		    sdl->sdl_slen == 0)
378			(void) sprintf(workbuf, "link#%d", sdl->sdl_index);
379		else switch (sdl->sdl_type) {
380		case IFT_ETHER:
381		    {
382			register int i;
383			register u_char *lla = (u_char *)sdl->sdl_data +
384			    sdl->sdl_nlen;
385
386			cplim = "";
387			for (i = 0; i < sdl->sdl_alen; i++, lla++) {
388				cp += sprintf(cp, "%s%x", cplim, *lla);
389				cplim = ":";
390			}
391			cp = workbuf;
392			break;
393		    }
394		default:
395			cp = link_ntoa(sdl);
396			break;
397		}
398		break;
399	    }
400
401	default:
402	    {
403		register u_char *s = (u_char *)sa->sa_data, *slim;
404
405		slim =  sa->sa_len + (u_char *) sa;
406		cplim = cp + sizeof(workbuf) - 6;
407		cp += sprintf(cp, "(%d)", sa->sa_family);
408		while (s < slim && cp < cplim) {
409			cp += sprintf(cp, " %02x", *s++);
410			if (s < slim)
411			    cp += sprintf(cp, "%02x", *s++);
412		}
413		cp = workbuf;
414	    }
415	}
416	if (width < 0 )
417		printf("%s ", cp);
418	else {
419		if (nflag)
420			printf("%-*s ", width, cp);
421		else
422			printf("%-*.*s ", width, width, cp);
423	}
424}
425
426static void
427p_flags(f, format)
428	register int f;
429	char *format;
430{
431	char name[33], *flags;
432	register struct bits *p = bits;
433
434	for (flags = name; p->b_mask; p++)
435		if (p->b_mask & f)
436			*flags++ = p->b_val;
437	*flags = '\0';
438	printf(format, name);
439}
440
441static void
442p_rtentry(rt)
443	register struct rtentry *rt;
444{
445	static struct ifnet ifnet, *lastif;
446	static char name[16];
447
448	p_sockaddr(kgetsa(rt_key(rt)), rt->rt_flags, WID_DST);
449	p_sockaddr(kgetsa(rt->rt_gateway), RTF_HOST, WID_GW);
450	p_flags(rt->rt_flags, "%-6.6s ");
451	printf("%6d %8d ", rt->rt_refcnt, rt->rt_use);
452	if (rt->rt_ifp) {
453		if (rt->rt_ifp != lastif) {
454			kget(rt->rt_ifp, ifnet);
455			kread((u_long)ifnet.if_name, name, 16);
456			lastif = rt->rt_ifp;
457		}
458		printf(" %.15s%d%s", name, ifnet.if_unit,
459			rt->rt_nodes[0].rn_dupedkey ? " =>" : "");
460	}
461	putchar('\n');
462}
463
464char *
465routename(in)
466	u_long in;
467{
468	register char *cp;
469	static char line[MAXHOSTNAMELEN + 1];
470	struct hostent *hp;
471	static char domain[MAXHOSTNAMELEN + 1];
472	static int first = 1;
473
474	if (first) {
475		first = 0;
476		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
477		    (cp = index(domain, '.')))
478			(void) strcpy(domain, cp + 1);
479		else
480			domain[0] = 0;
481	}
482	cp = 0;
483	if (!nflag) {
484		hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
485			AF_INET);
486		if (hp) {
487			if ((cp = index(hp->h_name, '.')) &&
488			    !strcmp(cp + 1, domain))
489				*cp = 0;
490			cp = hp->h_name;
491		}
492	}
493	if (cp)
494		strncpy(line, cp, sizeof(line) - 1);
495	else {
496#define C(x)	((x) & 0xff)
497		in = ntohl(in);
498		sprintf(line, "%u.%u.%u.%u",
499		    C(in >> 24), C(in >> 16), C(in >> 8), C(in));
500	}
501	return (line);
502}
503
504/*
505 * Return the name of the network whose address is given.
506 * The address is assumed to be that of a net or subnet, not a host.
507 */
508char *
509netname(in, mask)
510	u_long in, mask;
511{
512	char *cp = 0;
513	static char line[MAXHOSTNAMELEN + 1];
514	struct netent *np = 0;
515	u_long net;
516	register int i;
517	int subnetshift;
518
519	i = ntohl(in);
520	if (!nflag && i) {
521		if (mask == 0) {
522			if (IN_CLASSA(i)) {
523				mask = IN_CLASSA_NET;
524				subnetshift = 8;
525			} else if (IN_CLASSB(i)) {
526				mask = IN_CLASSB_NET;
527				subnetshift = 8;
528			} else {
529				mask = IN_CLASSC_NET;
530				subnetshift = 4;
531			}
532			/*
533			 * If there are more bits than the standard mask
534			 * would suggest, subnets must be in use.
535			 * Guess at the subnet mask, assuming reasonable
536			 * width subnet fields.
537			 */
538			while (i &~ mask)
539				mask = (long)mask >> subnetshift;
540		}
541		net = i & mask;
542		while ((mask & 1) == 0)
543			mask >>= 1, net >>= 1;
544		np = getnetbyaddr(net, AF_INET);
545		if (np)
546			cp = np->n_name;
547	}
548	if (cp)
549		strncpy(line, cp, sizeof(line) - 1);
550	else if ((i & 0xffffff) == 0)
551		sprintf(line, "%u", C(i >> 24));
552	else if ((i & 0xffff) == 0)
553		sprintf(line, "%u.%u", C(i >> 24) , C(i >> 16));
554	else if ((i & 0xff) == 0)
555		sprintf(line, "%u.%u.%u", C(i >> 24), C(i >> 16), C(i >> 8));
556	else
557		sprintf(line, "%u.%u.%u.%u", C(i >> 24),
558			C(i >> 16), C(i >> 8), C(i));
559	return (line);
560}
561
562/*
563 * Print routing statistics
564 */
565void
566rt_stats(off)
567	u_long off;
568{
569	struct rtstat rtstat;
570
571	if (off == 0) {
572		printf("rtstat: symbol not in namelist\n");
573		return;
574	}
575	kread(off, (char *)&rtstat, sizeof (rtstat));
576	printf("routing:\n");
577	printf("\t%u bad routing redirect%s\n",
578		rtstat.rts_badredirect, plural(rtstat.rts_badredirect));
579	printf("\t%u dynamically created route%s\n",
580		rtstat.rts_dynamic, plural(rtstat.rts_dynamic));
581	printf("\t%u new gateway%s due to redirects\n",
582		rtstat.rts_newgateway, plural(rtstat.rts_newgateway));
583	printf("\t%u destination%s found unreachable\n",
584		rtstat.rts_unreach, plural(rtstat.rts_unreach));
585	printf("\t%u use%s of a wildcard route\n",
586		rtstat.rts_wildcard, plural(rtstat.rts_wildcard));
587}
588short ns_nullh[] = {0,0,0};
589short ns_bh[] = {-1,-1,-1};
590
591char *
592ns_print(sa)
593	register struct sockaddr *sa;
594{
595	register struct sockaddr_ns *sns = (struct sockaddr_ns*)sa;
596	struct ns_addr work;
597	union { union ns_net net_e; u_long long_e; } net;
598	u_short port;
599	static char mybuf[50], cport[10], chost[25];
600	char *host = "";
601	register char *p; register u_char *q;
602
603	work = sns->sns_addr;
604	port = ntohs(work.x_port);
605	work.x_port = 0;
606	net.net_e  = work.x_net;
607	if (ns_nullhost(work) && net.long_e == 0) {
608		if (port ) {
609			sprintf(mybuf, "*.%xH", port);
610			upHex(mybuf);
611		} else
612			sprintf(mybuf, "*.*");
613		return (mybuf);
614	}
615
616	if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) {
617		host = "any";
618	} else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) {
619		host = "*";
620	} else {
621		q = work.x_host.c_host;
622		sprintf(chost, "%02x%02x%02x%02x%02x%02xH",
623			q[0], q[1], q[2], q[3], q[4], q[5]);
624		for (p = chost; *p == '0' && p < chost + 12; p++)
625			continue;
626		host = p;
627	}
628	if (port)
629		sprintf(cport, ".%xH", htons(port));
630	else
631		*cport = 0;
632
633	sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport);
634	upHex(mybuf);
635	return(mybuf);
636}
637
638char *
639ns_phost(sa)
640	struct sockaddr *sa;
641{
642	register struct sockaddr_ns *sns = (struct sockaddr_ns *)sa;
643	struct sockaddr_ns work;
644	static union ns_net ns_zeronet;
645	char *p;
646
647	work = *sns;
648	work.sns_addr.x_port = 0;
649	work.sns_addr.x_net = ns_zeronet;
650
651	p = ns_print((struct sockaddr *)&work);
652	if (strncmp("0H.", p, 3) == 0) p += 3;
653	return(p);
654}
655
656void
657upHex(p0)
658	char *p0;
659{
660	register char *p = p0;
661	for (; *p; p++) switch (*p) {
662
663	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
664		*p += ('A' - 'a');
665	}
666}
667