xref: /dragonfly/sbin/route/show.c (revision 5f39c7e7)
1 /*
2  * $OpenBSD: show.c,v 1.26 2003/08/26 08:33:12 itojun Exp $
3  * $NetBSD: show.c,v 1.1 1996/11/15 18:01:41 gwr Exp $
4  */
5 /*
6  * Copyright (c) 1983, 1988, 1993
7  *	The Regents of the University of California.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. 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 #include <sys/param.h>
35 #include <sys/protosw.h>
36 #include <sys/socket.h>
37 #include <sys/mbuf.h>
38 
39 #include <net/if.h>
40 #include <net/if_dl.h>
41 #include <net/if_types.h>
42 #include <net/route.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 
46 #include <sys/sysctl.h>
47 
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <unistd.h>
52 
53 #include <netdb.h>
54 
55 #include "extern.h"
56 #include "keywords.h"
57 
58 #define ROUNDUP(a) \
59 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
60 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
61 
62 /*
63  * Definitions for showing gateway flags.
64  */
65 struct bits {
66 	int	b_mask;
67 	char	b_val;
68 };
69 static const struct bits bits[] = {
70 	{ RTF_UP,	'U' },
71 	{ RTF_GATEWAY,	'G' },
72 	{ RTF_HOST,	'H' },
73 	{ RTF_REJECT,	'R' },
74 	{ RTF_BLACKHOLE, 'B' },
75 	{ RTF_DYNAMIC,	'D' },
76 	{ RTF_MODIFIED,	'M' },
77 	{ RTF_DONE,	'd' }, /* Completed -- for routing messages only */
78 	{ RTF_CLONING,	'C' },
79 	{ RTF_XRESOLVE,	'X' },
80 	{ RTF_LLINFO,	'L' },
81 	{ RTF_STATIC,	'S' },
82 	{ RTF_PROTO1,	'1' },
83 	{ RTF_PROTO2,	'2' },
84 	{ RTF_PROTO3,	'3' },
85 	{ 0, 0 }
86 };
87 
88 static void	p_rtentry(struct rt_msghdr *);
89 static int	p_sockaddr(struct sockaddr *, int, int);
90 static void	p_flags(int, const char *);
91 static void	pr_rthdr(void);
92 static void	pr_family(int);
93 
94 /*
95  * Print routing tables.
96  */
97 void
98 show(int argc, char *argv[])
99 {
100 	struct rt_msghdr *rtm;
101 	char *buf = NULL, *next, *lim = NULL;
102 	size_t needed;
103 	int mib[7], af = 0;
104 	int miblen;
105         struct sockaddr *sa;
106 
107         if (argc > 1) {
108                 argv++;
109                 if (argc == 2 && **argv == '-') {
110                     switch (keyword(*argv + 1)) {
111                         case K_INET:
112                                 af = AF_INET;
113                                 break;
114 #ifdef INET6
115                         case K_INET6:
116                                 af = AF_INET6;
117                                 break;
118 #endif
119                         case K_LINK:
120                                 af = AF_LINK;
121                                 break;
122                         case K_ISO:
123                         case K_OSI:
124                                 af = AF_ISO;
125                                 break;
126                         case K_X25:
127                                 af = AF_CCITT;
128                                 break;
129                         default:
130                                 goto bad;
131 		    }
132                 } else
133 bad:                    usage(*argv);
134         }
135 	mib[0] = CTL_NET;
136 	mib[1] = PF_ROUTE;
137 	mib[2] = 0;
138 	mib[3] = 0;
139 	mib[4] = NET_RT_DUMP;
140 	mib[5] = 0;
141 	if (cpuflag >= 0) {
142 		mib[6] = cpuflag;
143 		miblen = 7;
144 	} else {
145 		miblen = 6;
146 	}
147 	if (sysctl(mib, miblen, NULL, &needed, NULL, 0) < 0)	{
148 		perror("route-sysctl-estimate");
149 		exit(1);
150 	}
151 	if (needed > 0) {
152 		if ((buf = malloc(needed)) == NULL) {
153 			printf("out of space\n");
154 			exit(1);
155 		}
156 		if (sysctl(mib, miblen, buf, &needed, NULL, 0) < 0) {
157 			perror("sysctl of routing table");
158 			exit(1);
159 		}
160 		lim  = buf + needed;
161 	}
162 
163 	printf("Routing tables\n");
164 
165 	if (buf != NULL) {
166 		for (next = buf; next < lim; next += rtm->rtm_msglen) {
167 			rtm = (struct rt_msghdr *)next;
168 			sa = (struct sockaddr *)(rtm + 1);
169 			if (af != 0 && sa->sa_family != af)
170 				continue;
171 			p_rtentry(rtm);
172 		}
173 		free(buf);
174 	}
175 }
176 
177 /* column widths; each followed by one space */
178 #define	WID_DST		(nflag ? 20 : 32)	/* destination column width */
179 #define	WID_GW		(nflag ? 20 : 32)	/* gateway column width */
180 
181 /*
182  * Print header for routing table columns.
183  */
184 static void
185 pr_rthdr(void)
186 {
187 	printf("%-*.*s %-*.*s %-6.6s\n",
188 	    WID_DST, WID_DST, "Destination",
189 	    WID_GW, WID_GW, "Gateway",
190 	    "Flags");
191 }
192 
193 /*
194  * Print a routing table entry.
195  */
196 static void
197 p_rtentry(struct rt_msghdr *rtm)
198 {
199 	struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
200 #ifdef notdef
201 	static int masks_done, banner_printed;
202 #endif
203 	static int old_af;
204 	int af = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST;
205 	int width;
206 
207 #ifdef notdef
208 	/* for the moment, netmasks are skipped over */
209 	if (!banner_printed) {
210 		printf("Netmasks:\n");
211 		banner_printed = 1;
212 	}
213 	if (masks_done == 0) {
214 		if (rtm->rtm_addrs != RTA_DST) {
215 			masks_done = 1;
216 			af = sa->sa_family;
217 		}
218 	} else
219 #endif
220 		af = sa->sa_family;
221 	if (old_af != af) {
222 		old_af = af;
223 		pr_family(af);
224 		pr_rthdr();
225 	}
226 
227 	/*
228 	 * Print the information.  If wflag is set p_sockaddr() can return
229 	 * a wider width then specified and we try to fit the second
230 	 * address in any remaining space so the flags still lines up.
231 	 */
232 	if (rtm->rtm_addrs == RTA_DST) {
233 		p_sockaddr(sa, 0, WID_DST + WID_GW + 2);
234 	} else {
235 		width = p_sockaddr(sa, rtm->rtm_flags, WID_DST);
236 		sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
237 		p_sockaddr(sa, 0, WID_GW + WID_DST - width);
238 	}
239 	p_flags(rtm->rtm_flags & interesting, "%-6.6s ");
240 	putchar('\n');
241 }
242 
243 /*
244  * Print address family header before a section of the routing table.
245  */
246 static void
247 pr_family(int af)
248 {
249 	const char *afname;
250 
251 	switch (af) {
252 	case AF_INET:
253 		afname = "Internet";
254 		break;
255 #ifdef INET6
256 	case AF_INET6:
257 		afname = "Internet6";
258 		break;
259 #endif /* INET6 */
260 	case AF_ISO:
261 		afname = "ISO";
262 		break;
263 	case AF_CCITT:
264 		afname = "X.25";
265 		break;
266 	default:
267 		afname = NULL;
268 		break;
269 	}
270 	if (afname != NULL)
271 		printf("\n%s:\n", afname);
272 	else
273 		printf("\nProtocol Family %d:\n", af);
274 }
275 
276 static int
277 p_sockaddr(struct sockaddr *sa, int flags, int width)
278 {
279 	char workbuf[128];
280 	char *cp = workbuf;
281 	const char *cplim;
282 	int len = sizeof(workbuf);
283 	int count;
284 
285 	switch(sa->sa_family) {
286 
287 	case AF_LINK:
288 	    {
289 		struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
290 
291 		if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
292 		    sdl->sdl_slen == 0) {
293 			snprintf(workbuf, sizeof(workbuf),
294 			    "link#%d", sdl->sdl_index);
295 		} else {
296 			switch (sdl->sdl_type) {
297 			case IFT_ETHER:
298 			case IFT_L2VLAN:
299 			case IFT_CARP:
300 			    {
301 				int i;
302 				u_char *lla = (u_char *)sdl->sdl_data +
303 				    sdl->sdl_nlen;
304 
305 				cplim = "";
306 				for (i = 0; i < sdl->sdl_alen; i++, lla++) {
307 					snprintf(cp, len, "%s%02x",
308 					    cplim, *lla);
309 					len -= strlen(cp);
310 					cp += strlen(cp);
311 					if (len <= 0)
312 						break;	/* overflow */
313 					cplim = ":";
314 				}
315 				cp = workbuf;
316 				break;
317 			    }
318 			default:
319 				cp = link_ntoa(sdl);
320 				break;
321 			}
322 		}
323 		break;
324 	    }
325 
326 	case AF_INET:
327 	    {
328 		struct sockaddr_in *in = (struct sockaddr_in *)sa;
329 
330 		if (in->sin_addr.s_addr == 0) {
331 			/* cp points to workbuf */
332 			strncpy(cp, "default", len);
333 		} else
334 			cp = (flags & RTF_HOST) ? routename(sa) : netname(sa);
335 		break;
336 	    }
337 
338 #ifdef INET6
339 	case AF_INET6:
340 	    {
341 		struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
342 
343 		if (IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) {
344 			/* cp points to workbuf */
345 			strncpy(cp, "default", len);
346 		} else {
347 			cp = ((flags & RTF_HOST) ? routename(sa)
348 						 : netname(sa));
349 		}
350 		/* make sure numeric address is not truncated */
351 		if (strchr(cp, ':') != NULL &&
352 		    (width < 0 || strlen(cp) > (size_t)width))
353 			width = strlen(cp);
354 		break;
355 	    }
356 #endif /* INET6 */
357 
358 	default:
359 	    {
360 		u_char *s = (u_char *)sa->sa_data, *slim;
361 
362 		slim =  sa->sa_len + (u_char *) sa;
363 		cplim = cp + sizeof(workbuf) - 6;
364 		snprintf(cp, len, "(%d)", sa->sa_family);
365 		len -= strlen(cp);
366 		cp += strlen(cp);
367 		if (len <= 0) {
368 			cp = workbuf;
369 			break;		/* overflow */
370 		}
371 		while (s < slim && cp < cplim) {
372 			snprintf(cp, len, " %02x", *s++);
373 			len -= strlen(cp);
374 			cp += strlen(cp);
375 			if (len <= 0)
376 				break;		/* overflow */
377 			if (s < slim) {
378 				snprintf(cp, len, "%02x", *s++);
379 				len -= strlen(cp);
380 				cp += strlen(cp);
381 				if (len <= 0)
382 					break;		/* overflow */
383 			}
384 		}
385 		cp = workbuf;
386 	    }
387 	}
388 	if (width < 0) {
389 		count = printf("%s ", cp);
390 	} else {
391 		if (nflag || wflag)
392 			count = printf("%-*s ", width, cp);
393 		else
394 			count = printf("%-*.*s ", width, width, cp);
395 	}
396 	return(count);
397 }
398 
399 static void
400 p_flags(int f, const char *format)
401 {
402 	char name[33], *flags;
403 	const struct bits *p = bits;
404 
405 	for (flags = name; p->b_mask && flags < &name[sizeof(name) - 2]; p++) {
406 		if (p->b_mask & f)
407 			*flags++ = p->b_val;
408 	}
409 	*flags = '\0';
410 	printf(format, name);
411 }
412