1/*	$NetBSD: show.c,v 1.43 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: show.c,v 1.43 2011/02/04 14:31:23 martin Exp $");
38#endif
39#endif /* not lint */
40
41#include <sys/param.h>
42#include <sys/protosw.h>
43#include <sys/socket.h>
44#include <sys/mbuf.h>
45
46#include <arpa/inet.h>
47#include <net/if.h>
48#include <net/if_dl.h>
49#include <net/if_types.h>
50#include <net/route.h>
51#include <netinet/in.h>
52#include <netmpls/mpls.h>
53
54#include <sys/sysctl.h>
55
56#include <netdb.h>
57#include <stdbool.h>
58#include <stdio.h>
59#include <stdlib.h>
60#include <string.h>
61#include <unistd.h>
62#include <err.h>
63
64#include "keywords.h"
65#include "extern.h"
66#include "prog_ops.h"
67
68
69/*
70 * Definitions for showing gateway flags.
71 */
72struct bits {
73	int	b_mask;
74	char	b_val;
75};
76static const struct bits bits[] = {
77	{ RTF_UP,	'U' },
78	{ RTF_GATEWAY,	'G' },
79	{ RTF_HOST,	'H' },
80	{ RTF_REJECT,	'R' },
81	{ RTF_DYNAMIC,	'D' },
82	{ RTF_MODIFIED,	'M' },
83	{ RTF_DONE,	'd' }, /* Completed -- for routing messages only */
84	{ RTF_MASK,	'm' }, /* Mask Present -- for routing messages only */
85	{ RTF_CLONING,	'C' },
86	{ RTF_XRESOLVE,	'X' },
87	{ RTF_LLINFO,	'L' },
88	{ RTF_STATIC,	'S' },
89	{ RTF_BLACKHOLE, 'B' },
90	{ RTF_CLONED,	'c' },
91	{ RTF_PROTO1,	'1' },
92	{ RTF_PROTO2,	'2' },
93	{ RTF_ANNOUNCE,	'p' },
94	{ 0, '\0' }
95};
96
97static void pr_rthdr(int);
98static void p_rtentry(struct rt_msghdr *);
99static void pr_family(int);
100static void p_sockaddr(struct sockaddr *, struct sockaddr *, int, int );
101static void p_flags(int);
102
103void
104parse_show_opts(int argc, char * const *argv, int *afp, int *flagsp,
105    const char **afnamep, bool nolink)
106{
107	const char *afname = "unspec";
108	int af, flags;
109
110	flags = 0;
111	af = AF_UNSPEC;
112	for (; argc >= 2; argc--) {
113		if (*argv[argc - 1] != '-')
114			goto bad;
115		switch (keyword(argv[argc - 1] + 1)) {
116		case K_HOST:
117			flags |= RTF_HOST;
118			break;
119		case K_LLINFO:
120			flags |= RTF_LLINFO;
121			break;
122		case K_INET:
123			af = AF_INET;
124			afname = argv[argc - 1] + 1;
125			break;
126#ifdef INET6
127		case K_INET6:
128			af = AF_INET6;
129			afname = argv[argc - 1] + 1;
130			break;
131#endif
132#ifndef SMALL
133		case K_ATALK:
134			af = AF_APPLETALK;
135			afname = argv[argc - 1] + 1;
136			break;
137		case K_ISO:
138		case K_OSI:
139			af = AF_ISO;
140			afname = argv[argc - 1] + 1;
141			break;
142		case K_MPLS:
143			af = AF_MPLS;
144			afname = argv[argc - 1] + 1;
145			break;
146#endif /* SMALL */
147		case K_LINK:
148			if (nolink)
149				goto bad;
150			af = AF_LINK;
151			afname = argv[argc - 1] + 1;
152			break;
153		default:
154			goto bad;
155		}
156	}
157	switch (argc) {
158	case 1:
159	case 0:
160		break;
161	default:
162	bad:
163		usage(argv[argc - 1]);
164	}
165	if (afnamep != NULL)
166		*afnamep = afname;
167	*afp = af;
168	*flagsp = flags;
169}
170
171/*
172 * Print routing tables.
173 */
174void
175show(int argc, char *const *argv)
176{
177	size_t needed;
178	int af, flags, mib[6];
179	char *buf, *next, *lim;
180	struct rt_msghdr *rtm;
181	struct sockaddr *sa;
182
183	parse_show_opts(argc, argv, &af, &flags, NULL, true);
184	mib[0] = CTL_NET;
185	mib[1] = PF_ROUTE;
186	mib[2] = 0;
187	mib[3] = 0;
188	mib[4] = NET_RT_DUMP;
189	mib[5] = 0;
190	if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
191		err(EXIT_FAILURE, "route-sysctl-estimate");
192	buf = lim = NULL;
193	if (needed) {
194		if ((buf = malloc(needed)) == 0)
195			err(EXIT_FAILURE, "malloc");
196		if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
197			err(EXIT_FAILURE, "sysctl of routing table");
198		lim  = buf + needed;
199	}
200
201	printf("Routing table%s\n", (af == AF_UNSPEC)? "s" : "");
202
203	if (needed) {
204		for (next = buf; next < lim; next += rtm->rtm_msglen) {
205			rtm = (struct rt_msghdr *)next;
206			sa = (struct sockaddr *)(rtm + 1);
207			if ((rtm->rtm_flags & flags) != flags)
208				continue;
209			if (af == AF_UNSPEC || af == sa->sa_family)
210				p_rtentry(rtm);
211		}
212		free(buf);
213	}
214}
215
216
217/* column widths; each followed by one space */
218#ifndef INET6
219#define	WID_DST(af)	18	/* width of destination column */
220#define	WID_GW(af)	18	/* width of gateway column */
221#else
222/* width of destination/gateway column */
223#if 1
224/* strlen("fe80::aaaa:bbbb:cccc:dddd@gif0") == 30, strlen("/128") == 4 */
225#define	WID_DST(af)	((af) == AF_INET6 ? (nflag ? 34 : 18) : 18)
226#define	WID_GW(af)	((af) == AF_INET6 ? (nflag ? 30 : 18) : 18)
227#else
228/* strlen("fe80::aaaa:bbbb:cccc:dddd") == 25, strlen("/128") == 4 */
229#define	WID_DST(af)	((af) == AF_INET6 ? (nflag ? 29 : 18) : 18)
230#define	WID_GW(af)	((af) == AF_INET6 ? (nflag ? 25 : 18) : 18)
231#endif
232#endif /* INET6 */
233
234/*
235 * Print header for routing table columns.
236 */
237static void
238pr_rthdr(int af)
239{
240
241	printf("%-*.*s %-*.*s %-6.6s\n",
242		WID_DST(af), WID_DST(af), "Destination",
243		WID_GW(af), WID_GW(af), "Gateway",
244		"Flags");
245}
246
247
248/*
249 * Print a routing table entry.
250 */
251static void
252p_rtentry(struct rt_msghdr *rtm)
253{
254	struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
255#ifdef notdef
256	static int masks_done, banner_printed;
257#endif
258	static int old_af;
259	int af = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST |
260	    RTF_REJECT | RTF_LLINFO;
261
262#ifdef notdef
263	/* for the moment, netmasks are skipped over */
264	if (!banner_printed) {
265		printf("Netmasks:\n");
266		banner_printed = 1;
267	}
268	if (masks_done == 0) {
269		if (rtm->rtm_addrs != RTA_DST ) {
270			masks_done = 1;
271			af = sa->sa_family;
272		}
273	} else
274#endif
275		af = sa->sa_family;
276	if (old_af != af) {
277		old_af = af;
278		pr_family(af);
279		pr_rthdr(af);
280	}
281	if (rtm->rtm_addrs == RTA_DST)
282		p_sockaddr(sa, NULL, 0, WID_DST(af) + 1 + WID_GW(af) + 1);
283	else {
284		struct sockaddr *nm;
285
286		if ((rtm->rtm_addrs & RTA_NETMASK) == 0)
287			nm = NULL;
288		else {
289			/* skip to gateway */
290			nm = (struct sockaddr *)
291			    (RT_ROUNDUP(sa->sa_len) + (char *)sa);
292			/* skip over gateway to netmask */
293			nm = (struct sockaddr *)
294			    (RT_ROUNDUP(nm->sa_len) + (char *)nm);
295		}
296
297		p_sockaddr(sa, nm, rtm->rtm_flags, WID_DST(af));
298		sa = (struct sockaddr *)(RT_ROUNDUP(sa->sa_len) + (char *)sa);
299		p_sockaddr(sa, NULL, 0, WID_GW(af));
300	}
301	p_flags(rtm->rtm_flags & interesting);
302	putchar('\n');
303}
304
305
306/*
307 * Print address family header before a section of the routing table.
308 */
309static void
310pr_family(int af)
311{
312	const char *afname;
313
314	switch (af) {
315	case AF_INET:
316		afname = "Internet";
317		break;
318#ifdef INET6
319	case AF_INET6:
320		afname = "Internet6";
321		break;
322#endif /* INET6 */
323#ifndef SMALL
324	case AF_ISO:
325		afname = "ISO";
326		break;
327	case AF_MPLS:
328		afname = "MPLS";
329		break;
330#endif /* SMALL */
331	case AF_APPLETALK:
332		afname = "AppleTalk";
333		break;
334	default:
335		afname = NULL;
336		break;
337	}
338	if (afname)
339		printf("\n%s:\n", afname);
340	else
341		printf("\nProtocol Family %d:\n", af);
342}
343
344
345static void
346p_sockaddr(struct sockaddr *sa, struct sockaddr *nm, int flags, int width)
347{
348	char workbuf[128];
349	const char *cp;
350
351	switch(sa->sa_family) {
352
353	case AF_LINK:
354		if (getnameinfo(sa, sa->sa_len, workbuf, sizeof(workbuf),
355		    NULL, 0, NI_NUMERICHOST) != 0)
356			strlcpy(workbuf, "invalid", sizeof(workbuf));
357		cp = workbuf;
358		break;
359
360	case AF_INET:
361		cp = routename(sa, nm, flags);
362		break;
363
364#ifdef INET6
365	case AF_INET6:
366		cp = routename(sa, nm, flags);
367		/* make sure numeric address is not truncated */
368		if (strchr(cp, ':') != NULL && (int)strlen(cp) > width)
369			width = strlen(cp);
370		break;
371#endif /* INET6 */
372
373#ifndef SMALL
374	case AF_MPLS:
375		{
376		struct sockaddr_mpls *smpls = (struct sockaddr_mpls *)sa;
377		union mpls_shim ms;
378
379		ms.s_addr = ntohl(smpls->smpls_addr.s_addr);
380
381		snprintf(workbuf, sizeof(workbuf), "%u",
382			ms.shim.label);
383		cp = workbuf;
384		}
385		break;
386	case AF_APPLETALK:
387		if (getnameinfo(sa, sa->sa_len, workbuf, sizeof(workbuf),
388		    NULL, 0, NI_NUMERICHOST) != 0)
389			strlcpy(workbuf, "invalid", sizeof(workbuf));
390		cp = workbuf;
391		break;
392
393#endif /* SMALL */
394
395	default:
396	    {
397		u_char *s = (u_char *)sa->sa_data, *slim;
398		char *wp = workbuf, *wplim;
399
400		slim = sa->sa_len + (u_char *)sa;
401		wplim = wp + sizeof(workbuf) - 6;
402		wp += snprintf(wp, wplim - wp, "(%d)", sa->sa_family);
403		while (s < slim && wp < wplim) {
404			wp += snprintf(wp, wplim - wp, " %02x", *s++);
405			if (s < slim)
406			    wp += snprintf(wp, wplim - wp, "%02x", *s++);
407		}
408		cp = workbuf;
409	    }
410	}
411	if (width < 0 )
412		printf("%s ", cp);
413	else {
414		if (nflag)
415			printf("%-*s ", width, cp);
416		else
417			printf("%-*.*s ", width, width, cp);
418	}
419}
420
421static void
422p_flags(int f)
423{
424	char name[33], *flags;
425	const struct bits *p = bits;
426
427	for (flags = name; p->b_mask; p++)
428		if (p->b_mask & f)
429			*flags++ = p->b_val;
430		else if (Sflag)
431			*flags++ = ' ';
432	*flags = '\0';
433	printf("%-6.6s ", name);
434}
435
436