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: * $DragonFly: src/sbin/route/show.c,v 1.2 2004/03/23 18:00:48 dillon Exp $
5: */
6: /*
7: * Copyright (c) 1983, 1988, 1993
8: * The Regents of the University of California. All rights reserved.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. Neither the name of the University nor the names of its contributors
19: * may be used to endorse or promote products derived from this software
20: * without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32: * SUCH DAMAGE.
33: */
34:
35: #include <sys/param.h>
36: #include <sys/protosw.h>
37: #include <sys/socket.h>
38: #include <sys/mbuf.h>
39:
40: #include <net/if.h>
41: #include <net/if_dl.h>
42: #include <net/if_types.h>
43: #include <net/route.h>
44: #include <netinet/in.h>
45: #include <netns/ns.h>
46: #include <arpa/inet.h>
47:
48: #include <sys/sysctl.h>
49:
50: #include <stdio.h>
51: #include <stdlib.h>
52: #include <string.h>
53: #include <unistd.h>
54:
55: #include <netdb.h>
56:
57: #include "extern.h"
58: #include "keywords.h"
59:
60: #define ROUNDUP(a) \
61: ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
62: #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
63:
64: /*
65: * Definitions for showing gateway flags.
66: */
67: struct bits {
68: int b_mask;
69: char b_val;
70: };
71: static const struct bits bits[] = {
72: { RTF_UP, 'U' },
73: { RTF_GATEWAY, 'G' },
74: { RTF_HOST, 'H' },
75: { RTF_REJECT, 'R' },
76: { RTF_BLACKHOLE, 'B' },
77: { RTF_DYNAMIC, 'D' },
78: { RTF_MODIFIED, 'M' },
79: { RTF_DONE, 'd' }, /* Completed -- for routing messages only */
80: { RTF_CLONING, 'C' },
81: { RTF_XRESOLVE, 'X' },
82: { RTF_LLINFO, 'L' },
83: { RTF_STATIC, 'S' },
84: { RTF_PROTO1, '1' },
85: { RTF_PROTO2, '2' },
86: { RTF_PROTO3, '3' },
87: { 0 }
88: };
89:
90: static void p_rtentry(struct rt_msghdr *);
91: static void p_sockaddr(struct sockaddr *, int, int);
92: static void p_flags(int, char *);
93: static void pr_rthdr(void);
94: static void pr_family(int);
95:
96: int keyword(char *);
97: void usage(char *);
98: void show(int argc, char *argv[]);
99:
100: /*
101: * Print routing tables.
102: */
103: void
104: show(int argc, char *argv[])
105: {
106: struct rt_msghdr *rtm;
107: char *buf = NULL, *next, *lim = NULL;
108: size_t needed;
109: int mib[6], af = 0;
110: struct sockaddr *sa;
111:
112: if (argc > 1) {
113: argv++;
114: if (argc == 2 && **argv == '-')
115: switch (keyword(*argv + 1)) {
116: case K_INET:
117: af = AF_INET;
118: break;
119: #ifdef INET6
120: case K_INET6:
121: af = AF_INET6;
122: break;
123: #endif
124: case K_XNS:
125: af = AF_NS;
126: break;
127: case K_LINK:
128: af = AF_LINK;
129: break;
130: case K_ISO:
131: case K_OSI:
132: af = AF_ISO;
133: break;
134: case K_X25:
135: af = AF_CCITT;
136: break;
137: default:
138: goto bad;
139: } else
140: bad: usage(*argv);
141: }
142: mib[0] = CTL_NET;
143: mib[1] = PF_ROUTE;
144: mib[2] = 0;
145: mib[3] = 0;
146: mib[4] = NET_RT_DUMP;
147: mib[5] = 0;
148: if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
149: perror("route-sysctl-estimate");
150: exit(1);
151: }
152: if (needed > 0) {
153: if ((buf = malloc(needed)) == 0) {
154: printf("out of space\n");
155: exit(1);
156: }
157: if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
158: perror("sysctl of routing table");
159: exit(1);
160: }
161: lim = buf + needed;
162: }
163:
164: printf("Routing tables\n");
165:
166: if (buf) {
167: for (next = buf; next < lim; next += rtm->rtm_msglen) {
168: rtm = (struct rt_msghdr *)next;
169: sa = (struct sockaddr *)(rtm + 1);
170: if (af && sa->sa_family != af)
171: continue;
172: p_rtentry(rtm);
173: }
174: free(buf);
175: }
176: }
177:
178: /* column widths; each followed by one space */
179: #define WID_DST (nflag ? 20 : 32) /* destination column width */
180: #define WID_GW (nflag ? 20 : 32) /* gateway column width */
181:
182: /*
183: * Print header for routing table columns.
184: */
185: static void
186: pr_rthdr(void)
187: {
188: printf("%-*.*s %-*.*s %-6.6s\n",
189: WID_DST, WID_DST, "Destination",
190: WID_GW, WID_GW, "Gateway",
191: "Flags");
192: }
193:
194: /*
195: * Print a routing table entry.
196: */
197: static void
198: p_rtentry(struct rt_msghdr *rtm)
199: {
200: struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
201: #ifdef notdef
202: static int masks_done, banner_printed;
203: #endif
204: static int old_af;
205: int af = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST;
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: if (rtm->rtm_addrs == RTA_DST)
227: p_sockaddr(sa, 0, WID_DST + WID_GW + 2);
228: else {
229: p_sockaddr(sa, rtm->rtm_flags, WID_DST);
230: sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
231: p_sockaddr(sa, 0, WID_GW);
232: }
233: p_flags(rtm->rtm_flags & interesting, "%-6.6s ");
234: putchar('\n');
235: }
236:
237: /*
238: * Print address family header before a section of the routing table.
239: */
240: static void
241: pr_family(int af)
242: {
243: char *afname;
244:
245: switch (af) {
246: case AF_INET:
247: afname = "Internet";
248: break;
249: #ifdef INET6
250: case AF_INET6:
251: afname = "Internet6";
252: break;
253: #endif /* INET6 */
254: case AF_NS:
255: afname = "XNS";
256: break;
257: case AF_IPX:
258: afname = "IPX";
259: break;
260: case AF_ISO:
261: afname = "ISO";
262: break;
263: case AF_CCITT:
264: afname = "X.25";
265: break;
266: case AF_APPLETALK:
267: afname = "AppleTalk";
268: break;
269: default:
270: afname = NULL;
271: break;
272: }
273: if (afname)
274: printf("\n%s:\n", afname);
275: else
276: printf("\nProtocol Family %d:\n", af);
277: }
278:
279: static void
280: p_sockaddr(struct sockaddr *sa, int flags, int width)
281: {
282: char workbuf[128], *cplim;
283: char *cp = workbuf;
284: int len = sizeof(workbuf);
285:
286: switch(sa->sa_family) {
287:
288: case AF_LINK:
289: {
290: struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
291:
292: if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
293: sdl->sdl_slen == 0)
294: snprintf(workbuf, sizeof(workbuf),
295: "link#%d", sdl->sdl_index);
296: else {
297: switch (sdl->sdl_type) {
298: case IFT_ETHER:
299: {
300: int i;
301: u_char *lla = (u_char *)sdl->sdl_data +
302: sdl->sdl_nlen;
303:
304: cplim = "";
305: for (i = 0; i < sdl->sdl_alen; i++, lla++) {
306: snprintf(cp, len, "%s%x", cplim, *lla);
307: len -= strlen(cp);
308: cp += strlen(cp);
309: if (len <= 0)
310: break; /* overflow */
311: cplim = ":";
312: }
313: cp = workbuf;
314: break;
315: }
316: default:
317: cp = link_ntoa(sdl);
318: break;
319: }
320: }
321: break;
322: }
323:
324: case AF_INET:
325: {
326: struct sockaddr_in *sin = (struct sockaddr_in *)sa;
327:
328: if (sin->sin_addr.s_addr == 0)
329: cp = "default";
330: else
331: cp = (flags & RTF_HOST) ? routename(sa) : netname(sa);
332: break;
333: }
334:
335: #ifdef INET6
336: case AF_INET6:
337: {
338: struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa;
339:
340: cp = IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) ? "default" :
341: ((flags & RTF_HOST) ? routename(sa) : netname(sa));
342: /* make sure numeric address is not truncated */
343: if (strchr(cp, ':') != NULL && strlen(cp) > width)
344: width = strlen(cp);
345: break;
346: }
347: #endif /* INET6 */
348:
349: case AF_NS:
350: cp = ns_print((struct sockaddr_ns *)sa);
351: break;
352:
353: default:
354: {
355: u_char *s = (u_char *)sa->sa_data, *slim;
356:
357: slim = sa->sa_len + (u_char *) sa;
358: cplim = cp + sizeof(workbuf) - 6;
359: snprintf(cp, len, "(%d)", sa->sa_family);
360: len -= strlen(cp);
361: cp += strlen(cp);
362: if (len <= 0) {
363: cp = workbuf;
364: break; /* overflow */
365: }
366: while (s < slim && cp < cplim) {
367: snprintf(cp, len, " %02x", *s++);
368: len -= strlen(cp);
369: cp += strlen(cp);
370: if (len <= 0)
371: break; /* overflow */
372: if (s < slim) {
373: snprintf(cp, len, "%02x", *s++);
374: len -= strlen(cp);
375: cp += strlen(cp);
376: if (len <= 0)
377: break; /* overflow */
378: }
379: }
380: cp = workbuf;
381: }
382: }
383: if (width < 0 ) {
384: printf("%s ", cp);
385: } else {
386: if (nflag)
387: printf("%-*s ", width, cp);
388: else
389: printf("%-*.*s ", width, width, cp);
390: }
391: }
392:
393: static void
394: p_flags(int f, char *format)
395: {
396: char name[33], *flags;
397: const struct bits *p = bits;
398:
399: for (flags = name; p->b_mask && flags < &name[sizeof(name-2)]; p++) {
400: if (p->b_mask & f)
401: *flags++ = p->b_val;
402: }
403: *flags = '\0';
404: printf(format, name);
405: }