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