1/*	$NetBSD: route.c,v 1.77 2011/02/04 14:31:23 martin Exp $	*/
2
3/*
4 * Copyright (c) 1983, 1988, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33#ifndef lint
34#if 0
35static char sccsid[] = "from: @(#)route.c	8.3 (Berkeley) 3/9/94";
36#else
37__RCSID("$NetBSD: route.c,v 1.77 2011/02/04 14:31:23 martin Exp $");
38#endif
39#endif /* not lint */
40
41#include <stdbool.h>
42#include <sys/param.h>
43#include <sys/protosw.h>
44#include <sys/socket.h>
45#include <sys/mbuf.h>
46#include <sys/un.h>
47
48#include <net/if.h>
49#include <net/if_dl.h>
50#include <net/if_types.h>
51#include <net/route.h>
52#include <netinet/in.h>
53#include <netatalk/at.h>
54#include <netiso/iso.h>
55#include <netmpls/mpls.h>
56
57#include <sys/sysctl.h>
58
59#include <arpa/inet.h>
60
61#include <err.h>
62#include <kvm.h>
63#include <netdb.h>
64#include <stdio.h>
65#include <stdlib.h>
66#include <string.h>
67#include <unistd.h>
68
69#include "netstat.h"
70
71#define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d)))
72
73/*
74 * XXX we put all of the sockaddr types in here to force the alignment
75 * to be correct.
76 */
77static union sockaddr_union {
78	struct	sockaddr u_sa;
79	struct	sockaddr_in u_in;
80	struct	sockaddr_un u_un;
81	struct	sockaddr_iso u_iso;
82	struct	sockaddr_at u_at;
83	struct	sockaddr_dl u_dl;
84	u_short	u_data[128];
85	int u_dummy;		/* force word-alignment */
86} pt_u;
87
88int	do_rtent = 0;
89struct	rtentry rtentry;
90struct	radix_node rnode;
91struct	radix_mask rmask;
92
93static struct sockaddr *kgetsa(const struct sockaddr *);
94static void p_tree(struct radix_node *);
95static void p_rtnode(void);
96static void p_krtentry(struct rtentry *);
97
98/*
99 * Print routing tables.
100 */
101void
102routepr(rtree)
103	u_long rtree;
104{
105	struct radix_node_head *rnh, head;
106	struct radix_node_head *rt_nodes[AF_MAX+1];
107	int i;
108
109	printf("Routing tables\n");
110
111	if (rtree == 0) {
112		printf("rt_tables: symbol not in namelist\n");
113		return;
114	}
115
116	kget(rtree, rt_nodes);
117	for (i = 0; i <= AF_MAX; i++) {
118		if ((rnh = rt_nodes[i]) == 0)
119			continue;
120		kget(rnh, head);
121		if (i == AF_UNSPEC) {
122			if (Aflag && (af == 0 || af == 0xff)) {
123				printf("Netmasks:\n");
124				p_tree(head.rnh_treetop);
125			}
126		} else if (af == AF_UNSPEC || af == i) {
127			pr_family(i);
128			do_rtent = 1;
129			pr_rthdr(i, Aflag);
130			p_tree(head.rnh_treetop);
131		}
132	}
133}
134
135static struct sockaddr *
136kgetsa(const struct sockaddr *dst)
137{
138
139	kget(dst, pt_u.u_sa);
140	if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa))
141		kread((u_long)dst, (char *)pt_u.u_data, pt_u.u_sa.sa_len);
142	return (&pt_u.u_sa);
143}
144
145static void
146p_tree(rn)
147	struct radix_node *rn;
148{
149
150again:
151	kget(rn, rnode);
152	if (rnode.rn_b < 0) {
153		if (Aflag)
154			printf("%-8.8lx ", (u_long) rn);
155		if (rnode.rn_flags & RNF_ROOT) {
156			if (Aflag)
157				printf("(root node)%s",
158				    rnode.rn_dupedkey ? " =>\n" : "\n");
159		} else if (do_rtent) {
160			kget(rn, rtentry);
161			p_krtentry(&rtentry);
162			if (Aflag)
163				p_rtnode();
164		} else {
165			p_sockaddr(kgetsa((const struct sockaddr *)rnode.rn_key),
166			    NULL, 0, 44);
167			putchar('\n');
168		}
169		if ((rn = rnode.rn_dupedkey) != NULL)
170			goto again;
171	} else {
172		if (Aflag && do_rtent) {
173			printf("%-8.8lx ", (u_long) rn);
174			p_rtnode();
175		}
176		rn = rnode.rn_r;
177		p_tree(rnode.rn_l);
178		p_tree(rn);
179	}
180}
181
182static void
183p_rtnode()
184{
185	struct radix_mask *rm = rnode.rn_mklist;
186	char	nbuf[20];
187
188	if (rnode.rn_b < 0) {
189		if (rnode.rn_mask) {
190			printf("\t  mask ");
191			p_sockaddr(kgetsa((const struct sockaddr *)rnode.rn_mask),
192				    NULL, 0, -1);
193		} else if (rm == 0)
194			return;
195	} else {
196		(void)snprintf(nbuf, sizeof nbuf, "(%d)", rnode.rn_b);
197		printf("%6.6s %8.8lx : %8.8lx", nbuf, (u_long) rnode.rn_l,
198		    (u_long) rnode.rn_r);
199	}
200	while (rm) {
201		kget(rm, rmask);
202		(void)snprintf(nbuf, sizeof nbuf, " %d refs, ", rmask.rm_refs);
203		printf(" mk = %8.8lx {(%d),%s", (u_long) rm,
204		    -1 - rmask.rm_b, rmask.rm_refs ? nbuf : " ");
205		if (rmask.rm_flags & RNF_NORMAL) {
206			struct radix_node rnode_aux;
207			printf(" <normal>, ");
208			kget(rmask.rm_leaf, rnode_aux);
209			p_sockaddr(kgetsa((const struct sockaddr *)rnode_aux.rn_mask),
210				    NULL, 0, -1);
211		} else
212			p_sockaddr(kgetsa((const struct sockaddr *)rmask.rm_mask),
213			    NULL, 0, -1);
214		putchar('}');
215		if ((rm = rmask.rm_mklist) != NULL)
216			printf(" ->");
217	}
218	putchar('\n');
219}
220
221static struct sockaddr *sockcopy __P((struct sockaddr *,
222    union sockaddr_union *));
223
224/*
225 * copy a sockaddr into an allocated region, allocate at least sockaddr
226 * bytes and zero unused
227 */
228static struct sockaddr *
229sockcopy(sp, dp)
230	struct sockaddr *sp;
231	union sockaddr_union *dp;
232{
233	int len;
234
235	if (sp == 0 || sp->sa_len == 0)
236		(void)memset(dp, 0, sizeof (*sp));
237	else {
238		len = (sp->sa_len >= sizeof (*sp)) ? sp->sa_len : sizeof (*sp);
239		(void)memcpy(dp, sp, len);
240	}
241	return ((struct sockaddr *)dp);
242}
243
244static void
245p_krtentry(rt)
246	struct rtentry *rt;
247{
248	static struct ifnet ifnet, *lastif;
249	union sockaddr_union addr_un, mask_un;
250	struct sockaddr *addr, *mask;
251
252	if (Lflag && (rt->rt_flags & RTF_LLINFO))
253		return;
254
255	memset(&addr_un, 0, sizeof(addr_un));
256	memset(&mask_un, 0, sizeof(mask_un));
257	addr = sockcopy(kgetsa(rt_getkey(rt)), &addr_un);
258	if (rt_mask(rt))
259		mask = sockcopy(kgetsa(rt_mask(rt)), &mask_un);
260	else
261		mask = sockcopy(NULL, &mask_un);
262	p_addr(addr, mask, rt->rt_flags);
263	p_gwaddr(kgetsa(rt->rt_gateway), kgetsa(rt->rt_gateway)->sa_family);
264	p_flags(rt->rt_flags, "%-6.6s ");
265	printf("%6d %8"PRIu64" ", rt->rt_refcnt, rt->rt_use);
266	if (rt->rt_rmx.rmx_mtu)
267		printf("%6"PRIu64, rt->rt_rmx.rmx_mtu);
268	else
269		printf("%6s", "-");
270	putchar((rt->rt_rmx.rmx_locks & RTV_MTU) ? 'L' : ' ');
271	if (tagflag == 1) {
272		if (rt->rt_tag != NULL) {
273			const struct sockaddr *tagsa = kgetsa(rt->rt_tag);
274			char *tagstr;
275
276			if (tagsa->sa_family == AF_MPLS) {
277				tagstr = mpls_ntoa(tagsa);
278				if (strlen(tagstr) < 7)
279					printf("%7s", tagstr);
280				else
281					printf("%s", tagstr);
282			}
283			else
284				printf("%7s", "-");
285		} else
286			printf("%7s", "-");
287	}
288	if (rt->rt_ifp) {
289		if (rt->rt_ifp != lastif) {
290			kget(rt->rt_ifp, ifnet);
291			lastif = rt->rt_ifp;
292		}
293		printf(" %.16s%s", ifnet.if_xname,
294			rt->rt_nodes[0].rn_dupedkey ? " =>" : "");
295	}
296	putchar('\n');
297 	if (vflag) {
298 		printf("\texpire   %10"PRId64"%c  recvpipe %10"PRIu64"%c  "
299		       "sendpipe %10"PRIu64"%c\n",
300 			(int64_t)rt->rt_rmx.rmx_expire,
301 			(rt->rt_rmx.rmx_locks & RTV_EXPIRE) ? 'L' : ' ',
302 			rt->rt_rmx.rmx_recvpipe,
303 			(rt->rt_rmx.rmx_locks & RTV_RPIPE) ? 'L' : ' ',
304 			rt->rt_rmx.rmx_sendpipe,
305 			(rt->rt_rmx.rmx_locks & RTV_SPIPE) ? 'L' : ' ');
306 		printf("\tssthresh %10"PRIu64"%c  rtt      %10"PRIu64"%c  "
307		       "rttvar   %10"PRIu64"%c\n",
308 			rt->rt_rmx.rmx_ssthresh,
309 			(rt->rt_rmx.rmx_locks & RTV_SSTHRESH) ? 'L' : ' ',
310 			rt->rt_rmx.rmx_rtt,
311 			(rt->rt_rmx.rmx_locks & RTV_RTT) ? 'L' : ' ',
312 			rt->rt_rmx.rmx_rttvar,
313			(rt->rt_rmx.rmx_locks & RTV_RTTVAR) ? 'L' : ' ');
314 		printf("\thopcount %10"PRIu64"%c\n",
315 			rt->rt_rmx.rmx_hopcount,
316			(rt->rt_rmx.rmx_locks & RTV_HOPCOUNT) ? 'L' : ' ');
317 	}
318}
319
320/*
321 * Print routing statistics
322 */
323void
324rt_stats(off)
325	u_long off;
326{
327	struct rtstat rtstats;
328
329	if (use_sysctl) {
330		size_t rtsize = sizeof(rtstats);
331
332		if (sysctlbyname("net.route.stats", &rtstats, &rtsize,
333		    NULL, 0) == -1)
334			err(1, "rt_stats: sysctl");
335	} else 	if (off == 0) {
336		printf("rtstat: symbol not in namelist\n");
337		return;
338	} else
339		kread(off, (char *)&rtstats, sizeof(rtstats));
340
341	printf("routing:\n");
342	printf("\t%llu bad routing redirect%s\n",
343		(unsigned long long)rtstats.rts_badredirect,
344		plural(rtstats.rts_badredirect));
345	printf("\t%llu dynamically created route%s\n",
346		(unsigned long long)rtstats.rts_dynamic,
347		plural(rtstats.rts_dynamic));
348	printf("\t%llu new gateway%s due to redirects\n",
349		(unsigned long long)rtstats.rts_newgateway,
350		plural(rtstats.rts_newgateway));
351	printf("\t%llu destination%s found unreachable\n",
352		(unsigned long long)rtstats.rts_unreach,
353		plural(rtstats.rts_unreach));
354	printf("\t%llu use%s of a wildcard route\n",
355		(unsigned long long)rtstats.rts_wildcard,
356		plural(rtstats.rts_wildcard));
357}
358
359void
360upHex(p0)
361	char *p0;
362{
363	char *p = p0;
364
365	for (; *p; p++)
366		switch (*p) {
367		case 'a':
368		case 'b':
369		case 'c':
370		case 'd':
371		case 'e':
372		case 'f':
373			*p += ('A' - 'a');
374		}
375}
376
377
378