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