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 } 415