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.3 2004/03/23 18:25:51 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 int 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: int width;
207:
208: #ifdef notdef
209: /* for the moment, netmasks are skipped over */
210: if (!banner_printed) {
211: printf("Netmasks:\n");
212: banner_printed = 1;
213: }
214: if (masks_done == 0) {
215: if (rtm->rtm_addrs != RTA_DST ) {
216: masks_done = 1;
217: af = sa->sa_family;
218: }
219: } else
220: #endif
221: af = sa->sa_family;
222: if (old_af != af) {
223: old_af = af;
224: pr_family(af);
225: pr_rthdr();
226: }
227:
228: /*
229: * Print the information. If wflag is set p_sockaddr() can return
230: * a wider width then specified and we try to fit the second
231: * address in any remaining space so the flags still lines up.
232: */
233: if (rtm->rtm_addrs == RTA_DST) {
234: p_sockaddr(sa, 0, WID_DST + WID_GW + 2);
235: } else {
236: width = p_sockaddr(sa, rtm->rtm_flags, WID_DST);
237: sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
238: p_sockaddr(sa, 0, WID_GW + WID_DST - width);
239: }
240: p_flags(rtm->rtm_flags & interesting, "%-6.6s ");
241: putchar('\n');
242: }
243:
244: /*
245: * Print address family header before a section of the routing table.
246: */
247: static void
248: pr_family(int af)
249: {
250: char *afname;
251:
252: switch (af) {
253: case AF_INET:
254: afname = "Internet";
255: break;
256: #ifdef INET6
257: case AF_INET6:
258: afname = "Internet6";
259: break;
260: #endif /* INET6 */
261: case AF_NS:
262: afname = "XNS";
263: break;
264: case AF_IPX:
265: afname = "IPX";
266: break;
267: case AF_ISO:
268: afname = "ISO";
269: break;
270: case AF_CCITT:
271: afname = "X.25";
272: break;
273: case AF_APPLETALK:
274: afname = "AppleTalk";
275: break;
276: default:
277: afname = NULL;
278: break;
279: }
280: if (afname)
281: printf("\n%s:\n", afname);
282: else
283: printf("\nProtocol Family %d:\n", af);
284: }
285:
286: static int
287: p_sockaddr(struct sockaddr *sa, int flags, int width)
288: {
289: char workbuf[128], *cplim;
290: char *cp = workbuf;
291: int len = sizeof(workbuf);
292: int count;
293:
294: switch(sa->sa_family) {
295:
296: case AF_LINK:
297: {
298: struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
299:
300: if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
301: sdl->sdl_slen == 0)
302: snprintf(workbuf, sizeof(workbuf),
303: "link#%d", sdl->sdl_index);
304: else {
305: switch (sdl->sdl_type) {
306: case IFT_ETHER:
307: {
308: int i;
309: u_char *lla = (u_char *)sdl->sdl_data +
310: sdl->sdl_nlen;
311:
312: cplim = "";
313: for (i = 0; i < sdl->sdl_alen; i++, lla++) {
314: snprintf(cp, len, "%s%x", cplim, *lla);
315: len -= strlen(cp);
316: cp += strlen(cp);
317: if (len <= 0)
318: break; /* overflow */
319: cplim = ":";
320: }
321: cp = workbuf;
322: break;
323: }
324: default:
325: cp = link_ntoa(sdl);
326: break;
327: }
328: }
329: break;
330: }
331:
332: case AF_INET:
333: {
334: struct sockaddr_in *sin = (struct sockaddr_in *)sa;
335:
336: if (sin->sin_addr.s_addr == 0)
337: cp = "default";
338: else
339: cp = (flags & RTF_HOST) ? routename(sa) : netname(sa);
340: break;
341: }
342:
343: #ifdef INET6
344: case AF_INET6:
345: {
346: struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa;
347:
348: cp = IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) ? "default" :
349: ((flags & RTF_HOST) ? routename(sa) : netname(sa));
350: /* make sure numeric address is not truncated */
351: if (strchr(cp, ':') != NULL && strlen(cp) > width)
352: width = strlen(cp);
353: break;
354: }
355: #endif /* INET6 */
356:
357: case AF_NS:
358: cp = ns_print((struct sockaddr_ns *)sa);
359: break;
360:
361: default:
362: {
363: u_char *s = (u_char *)sa->sa_data, *slim;
364:
365: slim = sa->sa_len + (u_char *) sa;
366: cplim = cp + sizeof(workbuf) - 6;
367: snprintf(cp, len, "(%d)", sa->sa_family);
368: len -= strlen(cp);
369: cp += strlen(cp);
370: if (len <= 0) {
371: cp = workbuf;
372: break; /* overflow */
373: }
374: while (s < slim && cp < cplim) {
375: snprintf(cp, len, " %02x", *s++);
376: len -= strlen(cp);
377: cp += strlen(cp);
378: if (len <= 0)
379: break; /* overflow */
380: if (s < slim) {
381: snprintf(cp, len, "%02x", *s++);
382: len -= strlen(cp);
383: cp += strlen(cp);
384: if (len <= 0)
385: break; /* overflow */
386: }
387: }
388: cp = workbuf;
389: }
390: }
391: if (width < 0 ) {
392: count = printf("%s ", cp);
393: } else {
394: if (nflag || wflag)
395: count = printf("%-*s ", width, cp);
396: else
397: count = printf("%-*.*s ", width, width, cp);
398: }
399: return(count);
400: }
401:
402: static void
403: p_flags(int f, char *format)
404: {
405: char name[33], *flags;
406: const struct bits *p = bits;
407:
408: for (flags = name; p->b_mask && flags < &name[sizeof(name-2)]; p++) {
409: if (p->b_mask & f)
410: *flags++ = p->b_val;
411: }
412: *flags = '\0';
413: printf(format, name);
414: }