1 /* $NetBSD: route.c,v 1.137 2012/03/17 02:13:44 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1989, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1991, 1993\ 35 The Regents of the University of California. All rights reserved."); 36 #endif /* not lint */ 37 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)route.c 8.6 (Berkeley) 4/28/95"; 41 #else 42 __RCSID("$NetBSD: route.c,v 1.137 2012/03/17 02:13:44 christos Exp $"); 43 #endif 44 #endif /* not lint */ 45 46 #include <sys/param.h> 47 #include <sys/file.h> 48 #include <sys/socket.h> 49 #include <sys/ioctl.h> 50 #include <sys/mbuf.h> 51 #include <sys/sysctl.h> 52 53 #include <net/if.h> 54 #include <net/route.h> 55 #include <net/if_dl.h> 56 #include <net80211/ieee80211_netbsd.h> 57 #include <netinet/in.h> 58 #include <netatalk/at.h> 59 #include <netiso/iso.h> 60 #include <netmpls/mpls.h> 61 #include <arpa/inet.h> 62 #include <netdb.h> 63 64 #include <errno.h> 65 #include <unistd.h> 66 #include <stdio.h> 67 #include <ctype.h> 68 #include <stdlib.h> 69 #include <string.h> 70 #include <time.h> 71 #include <paths.h> 72 #include <err.h> 73 74 #include <rump/rump.h> 75 #include <rump/rump_syscalls.h> 76 #include <rump/rumpclient.h> 77 78 #include "keywords.h" 79 #include "extern.h" 80 #include "prog_ops.h" 81 82 union sockunion { 83 struct sockaddr sa; 84 struct sockaddr_in sin; 85 #ifdef INET6 86 struct sockaddr_in6 sin6; 87 #endif 88 struct sockaddr_at sat; 89 struct sockaddr_dl sdl; 90 #ifndef SMALL 91 struct sockaddr_iso siso; 92 struct sockaddr_mpls smpls; 93 #endif /* SMALL */ 94 struct sockaddr_storage sstorage; 95 }; 96 97 typedef union sockunion *sup; 98 99 struct sou { 100 union sockunion *so_dst, *so_gate, *so_mask, *so_genmask, *so_ifa, 101 *so_ifp, *so_mpls; 102 }; 103 104 static char *any_ntoa(const struct sockaddr *); 105 static const char *route_strerror(int); 106 static void set_metric(const char *, int); 107 static int newroute(int, char *const *); 108 static void inet_makenetandmask(u_int32_t, struct sockaddr_in *, struct sou *); 109 #ifdef INET6 110 static int inet6_makenetandmask(const struct sockaddr_in6 *, struct sou *); 111 #endif 112 static int getaddr(int, const char *, struct hostent **, struct sou *); 113 static int flushroutes(int, char *const [], int); 114 static int prefixlen(const char *, struct sou *); 115 #ifndef SMALL 116 static void interfaces(void); 117 __dead static void monitor(void); 118 static int print_getmsg(struct rt_msghdr *, int, struct sou *); 119 static const char *linkstate(struct if_msghdr *); 120 static sup readtag(sup, const char *); 121 static void addtag(sup, const char *, int); 122 #endif /* SMALL */ 123 static int rtmsg(int, int, struct sou *); 124 static void mask_addr(struct sou *); 125 static void print_rtmsg(struct rt_msghdr *, int); 126 static void pmsg_common(struct rt_msghdr *); 127 static void pmsg_addrs(const char *, int); 128 static void bprintf(FILE *, int, const char *); 129 static void sodump(sup, const char *); 130 static void sockaddr(const char *, struct sockaddr *); 131 132 int pid, rtm_addrs; 133 int sock; 134 int forcehost, forcenet, doflush, nflag, af, qflag, tflag, Sflag; 135 int iflag, verbose, aflen = sizeof(struct sockaddr_in), rtag; 136 int locking, lockrest, debugonly, shortoutput; 137 struct rt_metrics rt_metrics; 138 int rtm_inits; 139 short ns_nullh[] = {0,0,0}; 140 short ns_bh[] = {-1,-1,-1}; 141 142 143 void 144 usage(const char *cp) 145 { 146 147 if (cp) 148 warnx("botched keyword: %s", cp); 149 (void)fprintf(stderr, 150 "Usage: %s [ -fnqSsv ] cmd [[ -<qualifers> ] args ]\n", 151 getprogname()); 152 exit(1); 153 /* NOTREACHED */ 154 } 155 156 #define PRIETHER "02x:%02x:%02x:%02x:%02x:%02x" 157 #define PRIETHER_ARGS(__enaddr) (__enaddr)[0], (__enaddr)[1], (__enaddr)[2], \ 158 (__enaddr)[3], (__enaddr)[4], (__enaddr)[5] 159 160 int 161 main(int argc, char * const *argv) 162 { 163 int ch; 164 165 if (argc < 2) 166 usage(NULL); 167 168 while ((ch = getopt(argc, argv, "dfnqSstv")) != -1) 169 switch (ch) { 170 case 'd': 171 debugonly = 1; 172 break; 173 case 'f': 174 doflush = 1; 175 break; 176 case 'n': 177 nflag = 1; 178 break; 179 case 'q': 180 qflag = 1; 181 break; 182 case 'S': 183 Sflag = 1; 184 break; 185 case 's': 186 shortoutput = 1; 187 break; 188 case 't': 189 tflag = 1; 190 break; 191 case 'v': 192 verbose = 1; 193 break; 194 case '?': 195 default: 196 usage(NULL); 197 /*NOTREACHED*/ 198 } 199 argc -= optind; 200 argv += optind; 201 202 if (prog_init && prog_init() == -1) 203 err(1, "init failed"); 204 205 pid = prog_getpid(); 206 if (tflag) 207 sock = prog_open("/dev/null", O_WRONLY, 0); 208 else 209 sock = prog_socket(PF_ROUTE, SOCK_RAW, 0); 210 if (sock < 0) 211 err(EXIT_FAILURE, "socket"); 212 213 if (*argv == NULL) { 214 if (doflush) 215 ch = K_FLUSH; 216 else 217 goto no_cmd; 218 } else 219 ch = keyword(*argv); 220 221 switch (ch) { 222 #ifndef SMALL 223 case K_GET: 224 #endif /* SMALL */ 225 case K_CHANGE: 226 case K_ADD: 227 case K_DELETE: 228 if (doflush) 229 (void)flushroutes(1, argv, 0); 230 return newroute(argc, argv); 231 232 case K_SHOW: 233 show(argc, argv); 234 return 0; 235 236 #ifndef SMALL 237 case K_MONITOR: 238 monitor(); 239 return 0; 240 241 #endif /* SMALL */ 242 case K_FLUSH: 243 return flushroutes(argc, argv, 0); 244 245 case K_FLUSHALL: 246 return flushroutes(argc, argv, 1); 247 no_cmd: 248 default: 249 usage(*argv); 250 /*NOTREACHED*/ 251 } 252 } 253 254 /* 255 * Purge all entries in the routing tables not 256 * associated with network interfaces. 257 */ 258 static int 259 flushroutes(int argc, char * const argv[], int doall) 260 { 261 struct sockaddr *sa; 262 size_t needed; 263 int flags, mib[6], rlen, seqno; 264 char *buf, *next, *lim; 265 const char *afname; 266 struct rt_msghdr *rtm; 267 268 flags = 0; 269 af = AF_UNSPEC; 270 /* Don't want to read back our messages */ 271 prog_shutdown(sock, SHUT_RD); 272 parse_show_opts(argc, argv, &af, &flags, &afname, false); 273 mib[0] = CTL_NET; 274 mib[1] = PF_ROUTE; 275 mib[2] = 0; /* protocol */ 276 mib[3] = 0; /* wildcard address family */ 277 mib[4] = NET_RT_DUMP; 278 mib[5] = 0; /* no flags */ 279 if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 280 err(EXIT_FAILURE, "route-sysctl-estimate"); 281 buf = lim = NULL; 282 if (needed) { 283 if ((buf = malloc(needed)) == NULL) 284 err(EXIT_FAILURE, "malloc"); 285 if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 286 err(EXIT_FAILURE, "actual retrieval of routing table"); 287 lim = buf + needed; 288 } 289 if (verbose) { 290 (void)printf("Examining routing table from sysctl\n"); 291 if (af != AF_UNSPEC) 292 printf("(address family %s)\n", afname); 293 } 294 if (needed == 0) 295 return 0; 296 seqno = 0; /* ??? */ 297 for (next = buf; next < lim; next += rtm->rtm_msglen) { 298 rtm = (struct rt_msghdr *)next; 299 sa = (struct sockaddr *)(rtm + 1); 300 if (verbose) 301 print_rtmsg(rtm, rtm->rtm_msglen); 302 if ((rtm->rtm_flags & flags) != flags) 303 continue; 304 if (!(rtm->rtm_flags & (RTF_GATEWAY | RTF_STATIC | 305 RTF_LLINFO)) && !doall) 306 continue; 307 if (af != AF_UNSPEC && sa->sa_family != af) 308 continue; 309 if (debugonly) 310 continue; 311 rtm->rtm_type = RTM_DELETE; 312 rtm->rtm_seq = seqno; 313 if ((rlen = prog_write(sock, next, 314 rtm->rtm_msglen)) < 0) { 315 warnx("writing to routing socket: %s", 316 route_strerror(errno)); 317 return 1; 318 } 319 if (rlen < (int)rtm->rtm_msglen) { 320 warnx("write to routing socket, got %d for rlen", rlen); 321 return 1; 322 } 323 seqno++; 324 if (qflag) 325 continue; 326 if (verbose) 327 print_rtmsg(rtm, rlen); 328 else { 329 (void)printf("%-20.20s ", 330 routename(sa, NULL, rtm->rtm_flags)); 331 sa = (struct sockaddr *)(RT_ROUNDUP(sa->sa_len) + 332 (char *)sa); 333 (void)printf("%-20.20s ", 334 routename(sa, NULL, RTF_HOST)); 335 (void)printf("done\n"); 336 } 337 } 338 free(buf); 339 return 0; 340 } 341 342 343 static char hexlist[] = "0123456789abcdef"; 344 345 static char * 346 any_ntoa(const struct sockaddr *sa) 347 { 348 static char obuf[3 * 256]; 349 const char *in; 350 char *out; 351 int len; 352 353 #if __GNUC__ > 2 354 len = sa->sa_len - offsetof(struct sockaddr, sa_data); 355 #else 356 len = sa->sa_len - ((struct sockaddr*)&sa->sa_data - sa); 357 #endif 358 in = sa->sa_data; 359 out = obuf; 360 361 do { 362 *out++ = hexlist[(*in >> 4) & 15]; 363 *out++ = hexlist[(*in++) & 15]; 364 *out++ = '.'; 365 } while (--len > 0); 366 out[-1] = '\0'; 367 return obuf; 368 } 369 370 int 371 netmask_length(struct sockaddr *nm, int family) 372 { 373 static int 374 /* number of bits in a nibble */ 375 _t[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 }, 376 /* good nibbles are 1111, 1110, 1100, 1000, 0000 */ 377 _g[] = { 1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,1 }; 378 int mask, good, zeroes, maskbytes, bit, i; 379 unsigned char *maskdata; 380 381 if (nm == NULL) 382 return 0; 383 384 mask = 0; 385 good = 1; 386 zeroes = 0; 387 388 switch (family) { 389 case AF_INET: { 390 struct sockaddr_in *nsin = (struct sockaddr_in *)nm; 391 maskdata = (unsigned char *)&nsin->sin_addr; 392 maskbytes = nsin->sin_len - 393 ((caddr_t)&nsin->sin_addr - (caddr_t)nsin); 394 break; 395 } 396 case AF_INET6: { 397 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nm; 398 maskdata = (unsigned char *)&sin6->sin6_addr; 399 maskbytes = sin6->sin6_len - 400 ((caddr_t)&sin6->sin6_addr - (caddr_t)sin6); 401 break; 402 } 403 default: 404 return 0; 405 } 406 407 /* 408 * Count the bits in the nibbles of the mask, and marking the 409 * netmask as not good (or at best, non-standard and very 410 * discouraged, in the case of AF_INET) if we find either of 411 * a nibble with non-contiguous bits, or a non-zero nibble 412 * after we've found a zero nibble. 413 */ 414 for (i = 0; i < maskbytes; i++) { 415 /* high nibble */ 416 mask += bit = _t[maskdata[i] >> 4]; 417 good &= _g[maskdata[i] >> 4]; 418 if (zeroes && bit) 419 good = 0; 420 if (bit == 0) 421 zeroes = 1; 422 /* low nibble */ 423 mask += bit = _t[maskdata[i] & 0xf]; 424 good &= _g[maskdata[i] & 0xf]; 425 if (zeroes && bit) 426 good = 0; 427 if (bit == 0) 428 zeroes = 1; 429 } 430 431 /* 432 * Always return the number of bits found, but as a negative 433 * if the mask wasn't one we like. 434 */ 435 return good ? mask : -mask; 436 } 437 438 char * 439 netmask_string(const struct sockaddr *mask, int len, int family) 440 { 441 static char smask[INET6_ADDRSTRLEN]; 442 struct sockaddr_in nsin; 443 struct sockaddr_in6 nsin6; 444 445 if (len >= 0) 446 snprintf(smask, sizeof(smask), "%d", len); 447 else { 448 switch (family) { 449 case AF_INET: 450 memset(&nsin, 0, sizeof(nsin)); 451 memcpy(&nsin, mask, mask->sa_len); 452 snprintf(smask, sizeof(smask), "%s", 453 inet_ntoa(nsin.sin_addr)); 454 break; 455 case AF_INET6: 456 memset(&nsin6, 0, sizeof(nsin6)); 457 memcpy(&nsin6, mask, mask->sa_len); 458 inet_ntop(family, &nsin6.sin6_addr, smask, 459 sizeof(smask)); 460 break; 461 default: 462 snprintf(smask, sizeof(smask), "%s", any_ntoa(mask)); 463 } 464 } 465 466 return smask; 467 } 468 469 const char * 470 routename(const struct sockaddr *sa, struct sockaddr *nm, int flags) 471 { 472 const char *cp; 473 static char line[50]; 474 struct hostent *hp; 475 static char domain[MAXHOSTNAMELEN + 1]; 476 static int first = 1; 477 struct in_addr in; 478 int nml; 479 480 if ((flags & RTF_HOST) == 0) 481 return netname(sa, nm); 482 483 if (first) { 484 first = 0; 485 if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 486 (cp = strchr(domain, '.'))) 487 (void)strlcpy(domain, cp + 1, sizeof(domain)); 488 else 489 domain[0] = 0; 490 } 491 492 if (sa->sa_len == 0) 493 strlcpy(line, "default", sizeof(line)); 494 else switch (sa->sa_family) { 495 496 case AF_INET: 497 in = ((const struct sockaddr_in *)sa)->sin_addr; 498 nml = netmask_length(nm, AF_INET); 499 500 cp = 0; 501 if (in.s_addr == INADDR_ANY || sa->sa_len < 4) { 502 if (nml == 0) 503 cp = "default"; 504 else { 505 static char notdefault[sizeof(NOTDEFSTRING)]; 506 507 snprintf(notdefault, sizeof(notdefault), 508 "0.0.0.0/%s", 509 netmask_string(nm, nml, AF_INET)); 510 cp = notdefault; 511 } 512 } 513 if (cp == 0 && !nflag) { 514 hp = gethostbyaddr((char *)&in, sizeof(struct in_addr), 515 AF_INET); 516 if (hp) { 517 char *ccp; 518 if ((ccp = strchr(hp->h_name, '.')) && 519 !strcmp(ccp + 1, domain)) 520 *ccp = '\0'; 521 cp = hp->h_name; 522 } 523 } 524 if (cp) 525 (void)strlcpy(line, cp, sizeof(line)); 526 else 527 (void)strlcpy(line, inet_ntoa(in), sizeof(line)); 528 break; 529 530 case AF_LINK: 531 return link_ntoa((const struct sockaddr_dl *)sa); 532 533 #ifdef INET6 534 case AF_INET6: 535 { 536 struct sockaddr_in6 sin6; 537 int niflags; 538 char nihost[NI_MAXHOST]; 539 540 niflags = 0; 541 if (nflag) 542 niflags |= NI_NUMERICHOST; 543 memset(&sin6, 0, sizeof(sin6)); 544 memcpy(&sin6, sa, sa->sa_len); 545 sin6.sin6_len = sizeof(struct sockaddr_in6); 546 sin6.sin6_family = AF_INET6; 547 #ifdef __KAME__ 548 if (sa->sa_len == sizeof(struct sockaddr_in6) && 549 (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || 550 IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) && 551 sin6.sin6_scope_id == 0) { 552 sin6.sin6_scope_id = 553 ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); 554 sin6.sin6_addr.s6_addr[2] = 0; 555 sin6.sin6_addr.s6_addr[3] = 0; 556 } 557 #endif 558 nml = netmask_length(nm, AF_INET6); 559 if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) { 560 if (nml == 0) 561 strlcpy(line, "::", sizeof(line)); 562 else 563 /* noncontiguous never happens in ipv6 */ 564 snprintf(line, sizeof(line), "::/%d", nml); 565 } 566 else if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 567 nihost, sizeof(nihost), NULL, 0, niflags) != 0) 568 strlcpy(line, "invalid", sizeof(line)); 569 else { 570 char *ccp; 571 if (!nflag && (ccp = strchr(nihost, '.')) && 572 strcmp(ccp + 1, domain) == 0) 573 *ccp = '\0'; 574 strlcpy(line, nihost, sizeof(line)); 575 } 576 break; 577 } 578 #endif 579 580 #ifndef SMALL 581 case AF_ISO: 582 (void)snprintf(line, sizeof line, "iso %s", 583 iso_ntoa(&((const struct sockaddr_iso *)sa)->siso_addr)); 584 break; 585 586 case AF_APPLETALK: 587 (void)snprintf(line, sizeof(line), "atalk %d.%d", 588 ((const struct sockaddr_at *)sa)->sat_addr.s_net, 589 ((const struct sockaddr_at *)sa)->sat_addr.s_node); 590 break; 591 case AF_MPLS: 592 { 593 union mpls_shim ms; 594 const union mpls_shim *pms; 595 size_t psize = sizeof(struct sockaddr_mpls), len; 596 597 ms.s_addr =((const struct sockaddr_mpls*)sa)->smpls_addr.s_addr; 598 ms.s_addr = ntohl(ms.s_addr); 599 600 len = snprintf(line, sizeof(line), "%u", ms.shim.label); 601 if (len >= sizeof(line)) 602 errx(1, "snprintf"); 603 pms = &((const struct sockaddr_mpls*)sa)->smpls_addr; 604 while (psize < sa->sa_len) { 605 size_t alen; 606 pms++; 607 ms.s_addr = ntohl(pms->s_addr); 608 alen = snprintf(line + len, sizeof(line) - len, " %u", 609 ms.shim.label); 610 if (alen >= sizeof(line) - len) 611 errx(1, "snprintf"); 612 len += alen; 613 psize += sizeof(ms); 614 } 615 break; 616 } 617 #endif /* SMALL */ 618 619 default: 620 (void)snprintf(line, sizeof line, "(%d) %s", 621 sa->sa_family, any_ntoa(sa)); 622 break; 623 624 } 625 return line; 626 } 627 628 /* 629 * Return the name of the network whose address is given. 630 * The address is assumed to be that of a net or subnet, not a host. 631 */ 632 const char * 633 netname(const struct sockaddr *sa, struct sockaddr *nm) 634 { 635 const char *cp = 0; 636 static char line[50]; 637 struct netent *np = 0; 638 u_int32_t net, mask; 639 u_int32_t i; 640 int subnetshift, nml; 641 struct in_addr in; 642 643 switch (sa->sa_family) { 644 645 case AF_INET: 646 in = ((const struct sockaddr_in *)sa)->sin_addr; 647 i = ntohl(in.s_addr); 648 nml = netmask_length(nm, AF_INET); 649 if (i == 0) { 650 if (nml == 0) 651 cp = "default"; 652 else { 653 static char notdefault[sizeof(NOTDEFSTRING)]; 654 655 snprintf(notdefault, sizeof(notdefault), 656 "0.0.0.0/%s", 657 netmask_string(nm, nml, AF_INET)); 658 cp = notdefault; 659 } 660 } 661 else if (!nflag) { 662 if (IN_CLASSA(i)) { 663 mask = IN_CLASSA_NET; 664 subnetshift = 8; 665 } else if (IN_CLASSB(i)) { 666 mask = IN_CLASSB_NET; 667 subnetshift = 8; 668 } else { 669 mask = IN_CLASSC_NET; 670 subnetshift = 4; 671 } 672 /* 673 * If there are more bits than the standard mask 674 * would suggest, subnets must be in use. 675 * Guess at the subnet mask, assuming reasonable 676 * width subnet fields. 677 */ 678 while (i &~ mask) 679 mask = (int32_t)mask >> subnetshift; 680 net = i & mask; 681 while ((mask & 1) == 0) 682 mask >>= 1, net >>= 1; 683 np = getnetbyaddr(net, AF_INET); 684 if (np) 685 cp = np->n_name; 686 } 687 if (cp) 688 (void)strlcpy(line, cp, sizeof(line)); 689 else { 690 if (nml == 0) 691 strlcpy(line, inet_ntoa(in), sizeof(line)); 692 else if (nml < 0) { 693 snprintf(line, sizeof(line), "%s&%s", 694 inet_ntoa(in), 695 netmask_string(nm, nml, AF_INET)); 696 } else { 697 snprintf(line, sizeof(line), "%s/%d", 698 inet_ntoa(in), nml); 699 } 700 } 701 break; 702 703 case AF_LINK: 704 return link_ntoa((const struct sockaddr_dl *)sa); 705 706 #ifdef INET6 707 case AF_INET6: 708 { 709 struct sockaddr_in6 sin6; 710 int niflags; 711 712 niflags = 0; 713 if (nflag) 714 niflags |= NI_NUMERICHOST; 715 memset(&sin6, 0, sizeof(sin6)); 716 memcpy(&sin6, sa, sa->sa_len); 717 sin6.sin6_len = sizeof(struct sockaddr_in6); 718 sin6.sin6_family = AF_INET6; 719 #ifdef __KAME__ 720 if (sa->sa_len == sizeof(struct sockaddr_in6) && 721 (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || 722 IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) && 723 sin6.sin6_scope_id == 0) { 724 sin6.sin6_scope_id = 725 ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); 726 sin6.sin6_addr.s6_addr[2] = 0; 727 sin6.sin6_addr.s6_addr[3] = 0; 728 } 729 #endif 730 nml = netmask_length(nm, AF_INET6); 731 if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) { 732 if (nml == 0) 733 strlcpy(line, "::", sizeof(line)); 734 else 735 /* noncontiguous never happens in ipv6 */ 736 snprintf(line, sizeof(line), "::/%d", nml); 737 } 738 else if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 739 line, sizeof(line), NULL, 0, niflags) != 0) 740 strlcpy(line, "invalid", sizeof(line)); 741 break; 742 } 743 #endif 744 745 #ifndef SMALL 746 case AF_ISO: 747 (void)snprintf(line, sizeof line, "iso %s", 748 iso_ntoa(&((const struct sockaddr_iso *)sa)->siso_addr)); 749 break; 750 751 case AF_APPLETALK: 752 (void)snprintf(line, sizeof(line), "atalk %d.%d", 753 ((const struct sockaddr_at *)sa)->sat_addr.s_net, 754 ((const struct sockaddr_at *)sa)->sat_addr.s_node); 755 break; 756 #endif /* SMALL */ 757 758 default: 759 (void)snprintf(line, sizeof line, "af %d: %s", 760 sa->sa_family, any_ntoa(sa)); 761 break; 762 } 763 return line; 764 } 765 766 static const char * 767 route_strerror(int error) 768 { 769 770 switch (error) { 771 case ESRCH: 772 return "not in table"; 773 case EBUSY: 774 return "entry in use"; 775 case ENOBUFS: 776 return "routing table overflow"; 777 default: 778 return strerror(error); 779 } 780 } 781 782 static void 783 set_metric(const char *value, int key) 784 { 785 int flag = 0; 786 uint64_t noval, *valp = &noval; 787 788 switch (key) { 789 #define caseof(x, y, z) \ 790 case x: valp = (uint64_t *)&rt_metrics.z; flag = y; break 791 caseof(K_MTU, RTV_MTU, rmx_mtu); 792 caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); 793 caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); 794 caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); 795 caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); 796 caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); 797 caseof(K_RTT, RTV_RTT, rmx_rtt); 798 caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); 799 } 800 rtm_inits |= flag; 801 if (lockrest || locking) 802 rt_metrics.rmx_locks |= flag; 803 if (locking) 804 locking = 0; 805 *valp = strtoul(value, NULL, 0); 806 } 807 808 static int 809 newroute(int argc, char *const *argv) 810 { 811 const char *cmd, *dest = "", *gateway = ""; 812 int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC; 813 int key; 814 struct hostent *hp = 0; 815 struct sou sou, *soup = &sou; 816 817 sou.so_dst = calloc(1, sizeof(union sockunion)); 818 sou.so_gate = calloc(1, sizeof(union sockunion)); 819 sou.so_mask = calloc(1, sizeof(union sockunion)); 820 sou.so_genmask = calloc(1, sizeof(union sockunion)); 821 sou.so_ifa = calloc(1, sizeof(union sockunion)); 822 sou.so_ifp = calloc(1, sizeof(union sockunion)); 823 sou.so_mpls = calloc(1, sizeof(union sockunion)); 824 825 if (sou.so_dst == NULL || sou.so_gate == NULL || sou.so_mask == NULL || 826 sou.so_genmask == NULL || sou.so_ifa == NULL || sou.so_ifp == NULL || 827 sou.so_mpls == NULL) 828 errx(EXIT_FAILURE, "Cannot allocate memory"); 829 830 cmd = argv[0]; 831 af = AF_UNSPEC; 832 if (*cmd != 'g') { 833 /* Don't want to read back our messages */ 834 prog_shutdown(sock, SHUT_RD); 835 } 836 while (--argc > 0) { 837 if (**(++argv)== '-') { 838 switch (key = keyword(1 + *argv)) { 839 840 case K_SA: 841 af = PF_ROUTE; 842 aflen = sizeof(union sockunion); 843 break; 844 845 #ifndef SMALL 846 case K_ATALK: 847 af = AF_APPLETALK; 848 aflen = sizeof(struct sockaddr_at); 849 break; 850 #endif 851 852 case K_INET: 853 af = AF_INET; 854 aflen = sizeof(struct sockaddr_in); 855 break; 856 857 #ifdef INET6 858 case K_INET6: 859 af = AF_INET6; 860 aflen = sizeof(struct sockaddr_in6); 861 break; 862 #endif 863 864 case K_LINK: 865 af = AF_LINK; 866 aflen = sizeof(struct sockaddr_dl); 867 break; 868 869 #ifndef SMALL 870 case K_OSI: 871 case K_ISO: 872 af = AF_ISO; 873 aflen = sizeof(struct sockaddr_iso); 874 break; 875 case K_MPLS: 876 af = AF_MPLS; 877 aflen = sizeof(struct sockaddr_mpls); 878 break; 879 case K_TAG: 880 if (!--argc) 881 usage(1+*argv); 882 af = AF_MPLS; 883 aflen = sizeof(struct sockaddr_mpls); 884 (void)getaddr(RTA_TAG, *++argv, 0, soup); 885 break; 886 #endif /* SMALL */ 887 888 case K_IFACE: 889 case K_INTERFACE: 890 iflag++; 891 break; 892 case K_NOSTATIC: 893 flags &= ~RTF_STATIC; 894 break; 895 case K_LLINFO: 896 flags |= RTF_LLINFO; 897 break; 898 case K_LOCK: 899 locking = 1; 900 break; 901 case K_LOCKREST: 902 lockrest = 1; 903 break; 904 case K_HOST: 905 forcehost++; 906 break; 907 case K_REJECT: 908 flags |= RTF_REJECT; 909 break; 910 case K_NOREJECT: 911 flags &= ~RTF_REJECT; 912 break; 913 case K_BLACKHOLE: 914 flags |= RTF_BLACKHOLE; 915 break; 916 case K_NOBLACKHOLE: 917 flags &= ~RTF_BLACKHOLE; 918 break; 919 case K_CLONED: 920 flags |= RTF_CLONED; 921 break; 922 case K_NOCLONED: 923 flags &= ~RTF_CLONED; 924 break; 925 case K_PROTO1: 926 flags |= RTF_PROTO1; 927 break; 928 case K_PROTO2: 929 flags |= RTF_PROTO2; 930 break; 931 case K_PROXY: 932 flags |= RTF_ANNOUNCE; 933 break; 934 case K_CLONING: 935 flags |= RTF_CLONING; 936 break; 937 case K_NOCLONING: 938 flags &= ~RTF_CLONING; 939 break; 940 case K_XRESOLVE: 941 flags |= RTF_XRESOLVE; 942 break; 943 case K_STATIC: 944 flags |= RTF_STATIC; 945 break; 946 case K_IFA: 947 if (!--argc) 948 usage(1+*argv); 949 (void)getaddr(RTA_IFA, *++argv, 0, soup); 950 break; 951 case K_IFP: 952 if (!--argc) 953 usage(1+*argv); 954 (void)getaddr(RTA_IFP, *++argv, 0, soup); 955 break; 956 case K_GENMASK: 957 if (!--argc) 958 usage(1+*argv); 959 (void)getaddr(RTA_GENMASK, *++argv, 0, soup); 960 break; 961 case K_GATEWAY: 962 if (!--argc) 963 usage(1+*argv); 964 (void)getaddr(RTA_GATEWAY, *++argv, 0, soup); 965 break; 966 case K_DST: 967 if (!--argc) 968 usage(1+*argv); 969 ishost = getaddr(RTA_DST, *++argv, &hp, soup); 970 dest = *argv; 971 break; 972 case K_NETMASK: 973 if (!--argc) 974 usage(1+*argv); 975 (void)getaddr(RTA_NETMASK, *++argv, 0, soup); 976 /* FALLTHROUGH */ 977 case K_NET: 978 forcenet++; 979 break; 980 case K_PREFIXLEN: 981 if (!--argc) 982 usage(1+*argv); 983 ishost = prefixlen(*++argv, soup); 984 break; 985 case K_MTU: 986 case K_HOPCOUNT: 987 case K_EXPIRE: 988 case K_RECVPIPE: 989 case K_SENDPIPE: 990 case K_SSTHRESH: 991 case K_RTT: 992 case K_RTTVAR: 993 if (!--argc) 994 usage(1+*argv); 995 set_metric(*++argv, key); 996 break; 997 default: 998 usage(1+*argv); 999 } 1000 } else { 1001 if ((rtm_addrs & RTA_DST) == 0) { 1002 dest = *argv; 1003 ishost = getaddr(RTA_DST, *argv, &hp, soup); 1004 } else if ((rtm_addrs & RTA_GATEWAY) == 0) { 1005 gateway = *argv; 1006 (void)getaddr(RTA_GATEWAY, *argv, &hp, soup); 1007 } else { 1008 ret = atoi(*argv); 1009 1010 if (ret == 0) { 1011 if (strcmp(*argv, "0") == 0) { 1012 if (!qflag) { 1013 warnx("%s, %s", 1014 "old usage of trailing 0", 1015 "assuming route to if"); 1016 } 1017 } else 1018 usage(NULL); 1019 iflag = 1; 1020 continue; 1021 } else if (ret > 0 && ret < 10) { 1022 if (!qflag) { 1023 warnx("%s, %s", 1024 "old usage of trailing digit", 1025 "assuming route via gateway"); 1026 } 1027 iflag = 0; 1028 continue; 1029 } 1030 (void)getaddr(RTA_NETMASK, *argv, 0, soup); 1031 } 1032 } 1033 } 1034 if ((rtm_addrs & RTA_DST) == 0) 1035 errx(EXIT_FAILURE, "missing destination specification"); 1036 if (*cmd == 'a' && (rtm_addrs & RTA_GATEWAY) == 0) 1037 errx(EXIT_FAILURE, "missing gateway specification"); 1038 if (forcehost && forcenet) 1039 errx(EXIT_FAILURE, "-host and -net conflict"); 1040 else if (forcehost) 1041 ishost = 1; 1042 else if (forcenet) 1043 ishost = 0; 1044 flags |= RTF_UP; 1045 if (ishost) 1046 flags |= RTF_HOST; 1047 if (iflag == 0) 1048 flags |= RTF_GATEWAY; 1049 for (attempts = 1; ; attempts++) { 1050 errno = 0; 1051 if ((ret = rtmsg(*cmd, flags, soup)) == 0) 1052 break; 1053 if (errno != ENETUNREACH && errno != ESRCH) 1054 break; 1055 if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) { 1056 hp->h_addr_list++; 1057 memmove(&soup->so_gate->sin.sin_addr, hp->h_addr_list[0], 1058 hp->h_length); 1059 } else 1060 break; 1061 } 1062 if (*cmd == 'g') 1063 return ret != 0; 1064 if (!qflag) { 1065 oerrno = errno; 1066 (void)printf("%s %s %s", cmd, ishost? "host" : "net", dest); 1067 if (*gateway) { 1068 (void)printf(": gateway %s", gateway); 1069 if (attempts > 1 && ret == 0 && af == AF_INET) 1070 (void)printf(" (%s)", 1071 inet_ntoa(soup->so_gate->sin.sin_addr)); 1072 } 1073 if (ret == 0) 1074 (void)printf("\n"); 1075 else 1076 (void)printf(": %s\n", route_strerror(oerrno)); 1077 } 1078 free(sou.so_dst); 1079 free(sou.so_gate); 1080 free(sou.so_mask); 1081 free(sou.so_genmask); 1082 free(sou.so_ifa); 1083 free(sou.so_ifp); 1084 free(sou.so_mpls); 1085 1086 return ret != 0; 1087 } 1088 1089 static void 1090 inet_makenetandmask(const u_int32_t net, struct sockaddr_in * const isin, 1091 struct sou *soup) 1092 { 1093 struct sockaddr_in *sin; 1094 u_int32_t addr, mask = 0; 1095 char *cp; 1096 1097 rtm_addrs |= RTA_NETMASK; 1098 if (net == 0) 1099 mask = addr = 0; 1100 else if (net < 128) { 1101 addr = net << IN_CLASSA_NSHIFT; 1102 mask = IN_CLASSA_NET; 1103 } else if (net < 192) { 1104 addr = net << IN_CLASSA_NSHIFT; 1105 mask = IN_CLASSB_NET; 1106 } else if (net < 224) { 1107 addr = net << IN_CLASSA_NSHIFT; 1108 mask = IN_CLASSC_NET; 1109 } else if (net < 256) { 1110 addr = net << IN_CLASSA_NSHIFT; 1111 mask = IN_CLASSD_NET; 1112 } else if (net < 49152) { /* 192 * 256 */ 1113 addr = net << IN_CLASSB_NSHIFT; 1114 mask = IN_CLASSB_NET; 1115 } else if (net < 57344) { /* 224 * 256 */ 1116 addr = net << IN_CLASSB_NSHIFT; 1117 mask = IN_CLASSC_NET; 1118 } else if (net < 65536) { 1119 addr = net << IN_CLASSB_NSHIFT; 1120 mask = IN_CLASSB_NET; 1121 } else if (net < 14680064L) { /* 224 * 65536 */ 1122 addr = net << IN_CLASSC_NSHIFT; 1123 mask = IN_CLASSC_NET; 1124 } else if (net < 16777216L) { 1125 addr = net << IN_CLASSC_NSHIFT; 1126 mask = IN_CLASSD_NET; 1127 } else { 1128 addr = net; 1129 if ((addr & IN_CLASSA_HOST) == 0) 1130 mask = IN_CLASSA_NET; 1131 else if ((addr & IN_CLASSB_HOST) == 0) 1132 mask = IN_CLASSB_NET; 1133 else if ((addr & IN_CLASSC_HOST) == 0) 1134 mask = IN_CLASSC_NET; 1135 else 1136 mask = -1; 1137 } 1138 isin->sin_addr.s_addr = htonl(addr); 1139 sin = &soup->so_mask->sin; 1140 sin->sin_addr.s_addr = htonl(mask); 1141 sin->sin_len = 0; 1142 sin->sin_family = 0; 1143 cp = (char *)(&sin->sin_addr + 1); 1144 while (*--cp == 0 && cp > (char *)sin) 1145 ; 1146 sin->sin_len = 1 + cp - (char *)sin; 1147 sin->sin_family = AF_INET; 1148 } 1149 1150 #ifdef INET6 1151 /* 1152 * XXX the function may need more improvement... 1153 */ 1154 static int 1155 inet6_makenetandmask(const struct sockaddr_in6 * const sin6, struct sou *soup) 1156 { 1157 const char *plen; 1158 struct in6_addr in6; 1159 1160 plen = NULL; 1161 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && 1162 sin6->sin6_scope_id == 0) { 1163 plen = "0"; 1164 } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) { 1165 /* aggregatable global unicast - RFC2374 */ 1166 memset(&in6, 0, sizeof(in6)); 1167 if (!memcmp(&sin6->sin6_addr.s6_addr[8], &in6.s6_addr[8], 8)) 1168 plen = "64"; 1169 } 1170 1171 if (!plen || strcmp(plen, "128") == 0) 1172 return 1; 1173 else { 1174 rtm_addrs |= RTA_NETMASK; 1175 (void)prefixlen(plen, soup); 1176 return 0; 1177 } 1178 } 1179 #endif 1180 1181 /* 1182 * Interpret an argument as a network address of some kind, 1183 * returning 1 if a host address, 0 if a network address. 1184 */ 1185 static int 1186 getaddr(int which, const char *s, struct hostent **hpp, struct sou *soup) 1187 { 1188 sup su; 1189 struct hostent *hp; 1190 struct netent *np; 1191 u_int32_t val; 1192 char *t; 1193 int afamily; /* local copy of af so we can change it */ 1194 1195 if (af == AF_UNSPEC) { 1196 af = AF_INET; 1197 aflen = sizeof(struct sockaddr_in); 1198 } 1199 afamily = af; 1200 rtm_addrs |= which; 1201 switch (which) { 1202 case RTA_DST: 1203 su = soup->so_dst; 1204 break; 1205 case RTA_GATEWAY: 1206 su = soup->so_gate; 1207 break; 1208 case RTA_NETMASK: 1209 su = soup->so_mask; 1210 break; 1211 case RTA_GENMASK: 1212 su = soup->so_genmask; 1213 break; 1214 case RTA_IFP: 1215 su = soup->so_ifp; 1216 afamily = AF_LINK; 1217 break; 1218 case RTA_IFA: 1219 su = soup->so_ifa; 1220 su->sa.sa_family = af; 1221 break; 1222 #ifndef SMALL 1223 case RTA_TAG: 1224 su = soup->so_mpls; 1225 afamily = AF_MPLS; 1226 break; 1227 #endif 1228 default: 1229 su = NULL; 1230 usage("Internal Error"); 1231 /*NOTREACHED*/ 1232 } 1233 su->sa.sa_len = aflen; 1234 su->sa.sa_family = afamily; /* cases that don't want it have left already */ 1235 if (strcmp(s, "default") == 0) { 1236 switch (which) { 1237 case RTA_DST: 1238 forcenet++; 1239 (void)getaddr(RTA_NETMASK, s, 0, soup); 1240 break; 1241 case RTA_NETMASK: 1242 case RTA_GENMASK: 1243 su->sa.sa_len = 0; 1244 } 1245 return 0; 1246 } 1247 switch (afamily) { 1248 #ifdef INET6 1249 case AF_INET6: 1250 { 1251 struct addrinfo hints, *res; 1252 char *slash = 0; 1253 1254 if (which == RTA_DST && (slash = (strrchr(s, '/'))) != 0) 1255 *slash = '\0'; 1256 memset(&hints, 0, sizeof(hints)); 1257 hints.ai_family = afamily; /*AF_INET6*/ 1258 hints.ai_flags = AI_NUMERICHOST; 1259 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 1260 if (getaddrinfo(s, "0", &hints, &res) != 0) { 1261 hints.ai_flags = 0; 1262 if (slash) { 1263 *slash = '/'; 1264 slash = 0; 1265 } 1266 if (getaddrinfo(s, "0", &hints, &res) != 0) 1267 errx(EXIT_FAILURE, "%s: bad value", s); 1268 } 1269 if (slash) 1270 *slash = '/'; 1271 if (sizeof(su->sin6) != res->ai_addrlen) 1272 errx(EXIT_FAILURE, "%s: bad value", s); 1273 if (res->ai_next) { 1274 errx(EXIT_FAILURE, 1275 "%s: address resolved to multiple values", s); 1276 } 1277 memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6)); 1278 freeaddrinfo(res); 1279 #ifdef __KAME__ 1280 if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) || 1281 IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr)) && 1282 su->sin6.sin6_scope_id) { 1283 *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] = 1284 htons(su->sin6.sin6_scope_id); 1285 su->sin6.sin6_scope_id = 0; 1286 } 1287 #endif 1288 if (hints.ai_flags == AI_NUMERICHOST) { 1289 if (slash) 1290 return prefixlen(slash + 1, soup); 1291 if (which == RTA_DST) 1292 return inet6_makenetandmask(&su->sin6, soup); 1293 return 0; 1294 } else 1295 return 1; 1296 } 1297 #endif 1298 1299 #ifndef SMALL 1300 case AF_OSI: 1301 su->siso.siso_addr = *iso_addr(s); 1302 if (which == RTA_NETMASK || which == RTA_GENMASK) { 1303 const char *cp = TSEL(&su->siso); 1304 su->siso.siso_nlen = 0; 1305 do {--cp ;} while ((cp > (char *)su) && (*cp == 0)); 1306 su->siso.siso_len = 1 + cp - (char *)su; 1307 } 1308 return 1; 1309 #endif /* SMALL */ 1310 1311 case PF_ROUTE: 1312 su->sa.sa_len = sizeof(*su); 1313 sockaddr(s, &su->sa); 1314 return 1; 1315 1316 #ifndef SMALL 1317 case AF_APPLETALK: 1318 t = strchr (s, '.'); 1319 if (!t) { 1320 badataddr: 1321 errx(EXIT_FAILURE, "bad address: %s", s); 1322 } 1323 val = atoi (s); 1324 if (val > 65535) 1325 goto badataddr; 1326 su->sat.sat_addr.s_net = val; 1327 val = atoi (t); 1328 if (val > 256) 1329 goto badataddr; 1330 su->sat.sat_addr.s_node = val; 1331 rtm_addrs |= RTA_NETMASK; 1332 return(forcehost || su->sat.sat_addr.s_node != 0); 1333 case AF_MPLS: 1334 if (which == RTA_DST) 1335 soup->so_dst = readtag(su, s); 1336 else if (which == RTA_TAG) 1337 soup->so_mpls = readtag(su, s); 1338 else 1339 errx(EXIT_FAILURE, "MPLS can be used only as " 1340 "DST or TAG"); 1341 return 1; 1342 #endif 1343 1344 case AF_LINK: 1345 link_addr(s, &su->sdl); 1346 return 1; 1347 1348 case AF_INET: 1349 default: 1350 break; 1351 } 1352 1353 if (hpp == NULL) 1354 hpp = &hp; 1355 *hpp = NULL; 1356 1357 if ((t = strchr(s, '/')) != NULL && which == RTA_DST) { 1358 *t = '\0'; 1359 if (forcenet == 0) { 1360 if ((val = inet_addr(s)) != INADDR_NONE) { 1361 inet_makenetandmask(htonl(val), &su->sin, soup); 1362 return prefixlen(&t[1], soup); 1363 } 1364 } else { 1365 if ((val = inet_network(s)) != INADDR_NONE) { 1366 inet_makenetandmask(val, &su->sin, soup); 1367 return prefixlen(&t[1], soup); 1368 } 1369 } 1370 *t = '/'; 1371 } 1372 if (inet_aton(s, &su->sin.sin_addr) && 1373 (which != RTA_DST || forcenet == 0)) { 1374 val = su->sin.sin_addr.s_addr; 1375 if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY) 1376 return 1; 1377 else { 1378 val = ntohl(val); 1379 goto netdone; 1380 } 1381 } 1382 if ((val = inet_network(s)) != INADDR_NONE || 1383 ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0)) { 1384 netdone: 1385 if (which == RTA_DST) 1386 inet_makenetandmask(val, &su->sin, soup); 1387 return 0; 1388 } 1389 hp = gethostbyname(s); 1390 if (hp) { 1391 *hpp = hp; 1392 su->sin.sin_family = hp->h_addrtype; 1393 memmove(&su->sin.sin_addr, hp->h_addr, hp->h_length); 1394 return 1; 1395 } 1396 errx(EXIT_FAILURE, "%s: bad value", s); 1397 /*NOTREACHED*/ 1398 } 1399 1400 #ifndef SMALL 1401 static sup 1402 readtag(sup su, const char *s) 1403 { 1404 char *p, *n, *norig; 1405 int mplssize = 0; 1406 sup retsu = su; 1407 1408 n = strdup(s); 1409 if (n == NULL) 1410 errx(EXIT_FAILURE, "%s: Cannot allocate memory", s); 1411 norig = n; 1412 for (uint i = 0; i < strlen(n); i++) 1413 if(n[i] == ',') 1414 mplssize++; 1415 1416 #define MPLS_NEW_SIZE (sizeof(struct sockaddr_mpls) + \ 1417 mplssize * sizeof(union mpls_shim)) 1418 1419 if (mplssize != 0 && sizeof(union sockunion) < MPLS_NEW_SIZE) { 1420 free(su); 1421 retsu = malloc(MPLS_NEW_SIZE); 1422 retsu->smpls.smpls_family = AF_MPLS; 1423 } 1424 retsu->smpls.smpls_len = MPLS_NEW_SIZE; 1425 mplssize = 0; 1426 while ((p = strchr(n, ',')) != NULL) { 1427 p[0] = '\0'; 1428 addtag(retsu, n, mplssize); 1429 n = p + 1; 1430 mplssize++; 1431 } 1432 addtag(retsu, n, mplssize); 1433 1434 free(norig); 1435 return retsu; 1436 } 1437 1438 static void 1439 addtag(sup su, const char *s, int where) 1440 { 1441 union mpls_shim *ms = &su->smpls.smpls_addr; 1442 1443 if (atoi(s) < 0 || atoi(s) >= (1 << 20)) 1444 errx(EXIT_FAILURE, "%s: Bad tag", s); 1445 ms[where].s_addr = 0; 1446 ms[where].shim.label = atoi(s); 1447 ms[where].s_addr = htonl(ms[where].s_addr); 1448 } 1449 #endif /* SMALL */ 1450 1451 int 1452 prefixlen(const char *s, struct sou *soup) 1453 { 1454 int len = atoi(s), q, r; 1455 int max; 1456 1457 switch (af) { 1458 case AF_INET: 1459 max = sizeof(struct in_addr) * 8; 1460 break; 1461 #ifdef INET6 1462 case AF_INET6: 1463 max = sizeof(struct in6_addr) * 8; 1464 break; 1465 #endif 1466 default: 1467 errx(EXIT_FAILURE, "prefixlen is not supported with af %d", af); 1468 /*NOTREACHED*/ 1469 } 1470 1471 rtm_addrs |= RTA_NETMASK; 1472 if (len < -1 || len > max) 1473 errx(EXIT_FAILURE, "%s: bad value", s); 1474 1475 q = len >> 3; 1476 r = len & 7; 1477 switch (af) { 1478 case AF_INET: 1479 memset(soup->so_mask, 0, sizeof(*soup->so_mask)); 1480 soup->so_mask->sin.sin_family = AF_INET; 1481 soup->so_mask->sin.sin_len = sizeof(struct sockaddr_in); 1482 soup->so_mask->sin.sin_addr.s_addr = (len == 0 ? 0 1483 : htonl(0xffffffff << (32 - len))); 1484 break; 1485 #ifdef INET6 1486 case AF_INET6: 1487 soup->so_mask->sin6.sin6_family = AF_INET6; 1488 soup->so_mask->sin6.sin6_len = sizeof(struct sockaddr_in6); 1489 memset(&soup->so_mask->sin6.sin6_addr, 0, 1490 sizeof(soup->so_mask->sin6.sin6_addr)); 1491 if (q > 0) 1492 memset(&soup->so_mask->sin6.sin6_addr, 0xff, q); 1493 if (r > 0) 1494 *((u_char *)&soup->so_mask->sin6.sin6_addr + q) = 1495 (0xff00 >> r) & 0xff; 1496 break; 1497 #endif 1498 } 1499 return len == max; 1500 } 1501 1502 #ifndef SMALL 1503 static void 1504 interfaces(void) 1505 { 1506 size_t needed; 1507 int mib[6]; 1508 char *buf, *lim, *next; 1509 struct rt_msghdr *rtm; 1510 1511 mib[0] = CTL_NET; 1512 mib[1] = PF_ROUTE; 1513 mib[2] = 0; /* protocol */ 1514 mib[3] = 0; /* wildcard address family */ 1515 mib[4] = NET_RT_IFLIST; 1516 mib[5] = 0; /* no flags */ 1517 if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 1518 err(EXIT_FAILURE, "route-sysctl-estimate"); 1519 if (needed) { 1520 if ((buf = malloc(needed)) == NULL) 1521 err(EXIT_FAILURE, "malloc"); 1522 if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 1523 err(EXIT_FAILURE, 1524 "actual retrieval of interface table"); 1525 } 1526 lim = buf + needed; 1527 for (next = buf; next < lim; next += rtm->rtm_msglen) { 1528 rtm = (struct rt_msghdr *)next; 1529 print_rtmsg(rtm, rtm->rtm_msglen); 1530 } 1531 free(buf); 1532 } 1533 } 1534 1535 static void 1536 monitor(void) 1537 { 1538 int n; 1539 union { 1540 char msg[2048]; 1541 struct rt_msghdr hdr; 1542 } u; 1543 1544 verbose = 1; 1545 if (debugonly) { 1546 interfaces(); 1547 exit(0); 1548 } 1549 for(;;) { 1550 time_t now; 1551 n = prog_read(sock, &u, sizeof(u)); 1552 now = time(NULL); 1553 (void)printf("got message of size %d on %s", n, ctime(&now)); 1554 print_rtmsg(&u.hdr, n); 1555 } 1556 } 1557 1558 #endif /* SMALL */ 1559 1560 1561 struct { 1562 struct rt_msghdr m_rtm; 1563 char m_space[512]; 1564 } m_rtmsg; 1565 1566 static int 1567 rtmsg(int cmd, int flags, struct sou *soup) 1568 { 1569 static int seq; 1570 int rlen; 1571 char *cp = m_rtmsg.m_space; 1572 int l; 1573 1574 #define NEXTADDR(w, u) \ 1575 if (rtm_addrs & (w)) {\ 1576 l = RT_ROUNDUP(u->sa.sa_len); memmove(cp, u, l); cp += l;\ 1577 if (verbose && ! shortoutput) sodump(u,#u);\ 1578 } 1579 1580 errno = 0; 1581 memset(&m_rtmsg, 0, sizeof(m_rtmsg)); 1582 if (cmd == 'a') 1583 cmd = RTM_ADD; 1584 else if (cmd == 'c') 1585 cmd = RTM_CHANGE; 1586 else if (cmd == 'g') { 1587 #ifdef SMALL 1588 return -1; 1589 #else /* SMALL */ 1590 cmd = RTM_GET; 1591 if (soup->so_ifp->sa.sa_family == AF_UNSPEC) { 1592 soup->so_ifp->sa.sa_family = AF_LINK; 1593 soup->so_ifp->sa.sa_len = sizeof(struct sockaddr_dl); 1594 rtm_addrs |= RTA_IFP; 1595 } 1596 #endif /* SMALL */ 1597 } else 1598 cmd = RTM_DELETE; 1599 #define rtm m_rtmsg.m_rtm 1600 rtm.rtm_type = cmd; 1601 rtm.rtm_flags = flags; 1602 rtm.rtm_version = RTM_VERSION; 1603 rtm.rtm_seq = ++seq; 1604 rtm.rtm_addrs = rtm_addrs; 1605 rtm.rtm_rmx = rt_metrics; 1606 rtm.rtm_inits = rtm_inits; 1607 1608 if (rtm_addrs & RTA_NETMASK) 1609 mask_addr(soup); 1610 NEXTADDR(RTA_DST, soup->so_dst); 1611 NEXTADDR(RTA_GATEWAY, soup->so_gate); 1612 NEXTADDR(RTA_NETMASK, soup->so_mask); 1613 NEXTADDR(RTA_GENMASK, soup->so_genmask); 1614 NEXTADDR(RTA_IFP, soup->so_ifp); 1615 NEXTADDR(RTA_IFA, soup->so_ifa); 1616 #ifndef SMALL 1617 NEXTADDR(RTA_TAG, soup->so_mpls); 1618 #endif 1619 rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 1620 if (verbose && ! shortoutput) { 1621 if (rtm_addrs) 1622 putchar('\n'); 1623 print_rtmsg(&rtm, l); 1624 } 1625 if (debugonly) 1626 return 0; 1627 if ((rlen = prog_write(sock, (char *)&m_rtmsg, l)) < 0) { 1628 warnx("writing to routing socket: %s", route_strerror(errno)); 1629 return -1; 1630 } 1631 if (rlen < l) { 1632 warnx("write to routing socket, got %d for rlen", rlen); 1633 return 1; 1634 } 1635 #ifndef SMALL 1636 if (cmd == RTM_GET) { 1637 do { 1638 l = prog_read(sock, 1639 (char *)&m_rtmsg, sizeof(m_rtmsg)); 1640 } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); 1641 if (l < 0) 1642 err(EXIT_FAILURE, "read from routing socket"); 1643 else 1644 return print_getmsg(&rtm, l, soup); 1645 } 1646 #endif /* SMALL */ 1647 #undef rtm 1648 return 0; 1649 } 1650 1651 static void 1652 mask_addr(struct sou *soup) 1653 { 1654 int olen = soup->so_mask->sa.sa_len; 1655 char *cp1 = olen + (char *)&soup->so_mask, *cp2; 1656 1657 for (soup->so_mask->sa.sa_len = 0; cp1 > (char *)&soup->so_mask; ) 1658 if (*--cp1 != 0) { 1659 soup->so_mask->sa.sa_len = 1 + cp1 - (char *)&soup->so_mask; 1660 break; 1661 } 1662 if ((rtm_addrs & RTA_DST) == 0) 1663 return; 1664 switch (soup->so_dst->sa.sa_family) { 1665 case AF_INET: 1666 #ifdef INET6 1667 case AF_INET6: 1668 #endif 1669 #ifndef SMALL 1670 case AF_APPLETALK: 1671 #endif /* SMALL */ 1672 case 0: 1673 return; 1674 #ifndef SMALL 1675 case AF_ISO: 1676 olen = MIN(soup->so_dst->siso.siso_nlen, 1677 MAX(soup->so_mask->sa.sa_len - 6, 0)); 1678 break; 1679 #endif /* SMALL */ 1680 } 1681 cp1 = soup->so_mask->sa.sa_len + 1 + (char *)&soup->so_dst; 1682 cp2 = soup->so_dst->sa.sa_len + 1 + (char *)&soup->so_dst; 1683 while (cp2 > cp1) 1684 *--cp2 = 0; 1685 cp2 = soup->so_mask->sa.sa_len + 1 + (char *)&soup->so_mask; 1686 while (cp1 > soup->so_dst->sa.sa_data) 1687 *--cp1 &= *--cp2; 1688 #ifndef SMALL 1689 switch (soup->so_dst->sa.sa_family) { 1690 case AF_ISO: 1691 soup->so_dst->siso.siso_nlen = olen; 1692 break; 1693 } 1694 #endif /* SMALL */ 1695 } 1696 1697 const char * const msgtypes[] = { 1698 [RTM_ADD] = "RTM_ADD: Add Route", 1699 [RTM_DELETE] = "RTM_DELETE: Delete Route", 1700 [RTM_CHANGE] = "RTM_CHANGE: Change Metrics or flags", 1701 [RTM_GET] = "RTM_GET: Report Metrics", 1702 [RTM_LOSING] = "RTM_LOSING: Kernel Suspects Partitioning", 1703 [RTM_REDIRECT] = "RTM_REDIRECT: Told to use different route", 1704 [RTM_MISS] = "RTM_MISS: Lookup failed on this address", 1705 [RTM_LOCK] = "RTM_LOCK: fix specified metrics", 1706 [RTM_OLDADD] = "RTM_OLDADD: caused by SIOCADDRT", 1707 [RTM_OLDDEL] = "RTM_OLDDEL: caused by SIOCDELRT", 1708 [RTM_RESOLVE] = "RTM_RESOLVE: Route created by cloning", 1709 [RTM_NEWADDR] = "RTM_NEWADDR: address being added to iface", 1710 [RTM_DELADDR] = "RTM_DELADDR: address being removed from iface", 1711 [RTM_OOIFINFO] = "RTM_OOIFINFO: iface status change (pre-1.5)", 1712 [RTM_OIFINFO] = "RTM_OIFINFO: iface status change (pre-64bit time)", 1713 [RTM_IFANNOUNCE] = "RTM_IFANNOUNCE: iface arrival/departure", 1714 [RTM_IEEE80211] = "RTM_IEEE80211: IEEE80211 wireless event", 1715 [RTM_IFINFO] = "RTM_IFINFO: iface status change", 1716 [RTM_CHGADDR] = "RTM_CHGADDR: address being changed on iface", 1717 }; 1718 1719 const char metricnames[] = 1720 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu"; 1721 const char routeflags[] = 1722 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016CLONED\017PROTO2\020PROTO1"; 1723 const char ifnetflags[] = 1724 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2\020MULTICAST"; 1725 const char addrnames[] = 1726 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011TAG"; 1727 1728 1729 #ifndef SMALL 1730 static const char * 1731 linkstate(struct if_msghdr *ifm) 1732 { 1733 static char buf[64]; 1734 1735 switch (ifm->ifm_data.ifi_link_state) { 1736 case LINK_STATE_UNKNOWN: 1737 return "carrier: unknown"; 1738 case LINK_STATE_DOWN: 1739 return "carrier: no carrier"; 1740 case LINK_STATE_UP: 1741 return "carrier: active"; 1742 default: 1743 (void)snprintf(buf, sizeof(buf), "carrier: 0x%x", 1744 ifm->ifm_data.ifi_link_state); 1745 return buf; 1746 } 1747 } 1748 #endif /* SMALL */ 1749 1750 static void 1751 print_rtmsg(struct rt_msghdr *rtm, int msglen) 1752 { 1753 struct if_msghdr *ifm; 1754 struct ifa_msghdr *ifam; 1755 struct if_announcemsghdr *ifan; 1756 union { 1757 struct ieee80211_join_event join; 1758 struct ieee80211_leave_event leave; 1759 struct ieee80211_replay_event replay; 1760 struct ieee80211_michael_event michael; 1761 } ev; 1762 size_t evlen = 0; 1763 1764 if (verbose == 0) 1765 return; 1766 if (rtm->rtm_version != RTM_VERSION) { 1767 (void)printf("routing message version %d not understood\n", 1768 rtm->rtm_version); 1769 return; 1770 } 1771 if (msgtypes[rtm->rtm_type]) 1772 (void)printf("%s: ", msgtypes[rtm->rtm_type]); 1773 else 1774 (void)printf("#%d: ", rtm->rtm_type); 1775 (void)printf("len %d, ", rtm->rtm_msglen); 1776 switch (rtm->rtm_type) { 1777 case RTM_IFINFO: 1778 ifm = (struct if_msghdr *)rtm; 1779 (void)printf("if# %d, %s, flags: ", ifm->ifm_index, 1780 #ifdef SMALL 1781 "" 1782 #else 1783 linkstate(ifm) 1784 #endif /* SMALL */ 1785 ); 1786 bprintf(stdout, ifm->ifm_flags, ifnetflags); 1787 pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs); 1788 break; 1789 case RTM_NEWADDR: 1790 case RTM_DELADDR: 1791 case RTM_CHGADDR: 1792 ifam = (struct ifa_msghdr *)rtm; 1793 (void)printf("metric %d, flags: ", ifam->ifam_metric); 1794 bprintf(stdout, ifam->ifam_flags, routeflags); 1795 pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs); 1796 break; 1797 case RTM_IEEE80211: 1798 ifan = (struct if_announcemsghdr *)rtm; 1799 (void)printf("if# %d, what: ", ifan->ifan_index); 1800 switch (ifan->ifan_what) { 1801 case RTM_IEEE80211_ASSOC: 1802 printf("associate"); 1803 break; 1804 case RTM_IEEE80211_REASSOC: 1805 printf("re-associate"); 1806 break; 1807 case RTM_IEEE80211_DISASSOC: 1808 printf("disassociate"); 1809 break; 1810 case RTM_IEEE80211_SCAN: 1811 printf("scan complete"); 1812 break; 1813 case RTM_IEEE80211_JOIN: 1814 evlen = sizeof(ev.join); 1815 printf("join"); 1816 break; 1817 case RTM_IEEE80211_LEAVE: 1818 evlen = sizeof(ev.leave); 1819 printf("leave"); 1820 break; 1821 case RTM_IEEE80211_MICHAEL: 1822 evlen = sizeof(ev.michael); 1823 printf("michael"); 1824 break; 1825 case RTM_IEEE80211_REPLAY: 1826 evlen = sizeof(ev.replay); 1827 printf("replay"); 1828 break; 1829 default: 1830 evlen = 0; 1831 printf("#%d", ifan->ifan_what); 1832 break; 1833 } 1834 if (sizeof(*ifan) + evlen > ifan->ifan_msglen) { 1835 printf(" (truncated)\n"); 1836 break; 1837 } 1838 (void)memcpy(&ev, (ifan + 1), evlen); 1839 switch (ifan->ifan_what) { 1840 case RTM_IEEE80211_JOIN: 1841 case RTM_IEEE80211_LEAVE: 1842 printf(" mac %" PRIETHER, 1843 PRIETHER_ARGS(ev.join.iev_addr)); 1844 break; 1845 case RTM_IEEE80211_REPLAY: 1846 case RTM_IEEE80211_MICHAEL: 1847 printf(" src %" PRIETHER " dst %" PRIETHER 1848 " cipher %" PRIu8 " keyix %" PRIu8, 1849 PRIETHER_ARGS(ev.replay.iev_src), 1850 PRIETHER_ARGS(ev.replay.iev_dst), 1851 ev.replay.iev_cipher, 1852 ev.replay.iev_keyix); 1853 if (ifan->ifan_what == RTM_IEEE80211_REPLAY) { 1854 printf(" key rsc %#" PRIx64 1855 " frame rsc %#" PRIx64, 1856 ev.replay.iev_keyrsc, ev.replay.iev_rsc); 1857 } 1858 break; 1859 default: 1860 break; 1861 } 1862 printf("\n"); 1863 break; 1864 case RTM_IFANNOUNCE: 1865 ifan = (struct if_announcemsghdr *)rtm; 1866 (void)printf("if# %d, what: ", ifan->ifan_index); 1867 switch (ifan->ifan_what) { 1868 case IFAN_ARRIVAL: 1869 printf("arrival"); 1870 break; 1871 case IFAN_DEPARTURE: 1872 printf("departure"); 1873 break; 1874 default: 1875 printf("#%d", ifan->ifan_what); 1876 break; 1877 } 1878 printf("\n"); 1879 break; 1880 default: 1881 (void)printf("pid %d, seq %d, errno %d, flags: ", 1882 rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 1883 bprintf(stdout, rtm->rtm_flags, routeflags); 1884 pmsg_common(rtm); 1885 } 1886 } 1887 1888 #ifndef SMALL 1889 static int 1890 print_getmsg(struct rt_msghdr *rtm, int msglen, struct sou *soup) 1891 { 1892 struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *ifa = NULL, *mpls = NULL; 1893 struct sockaddr_dl *ifp = NULL; 1894 struct sockaddr *sa; 1895 char *cp; 1896 int i; 1897 1898 if (! shortoutput) { 1899 (void)printf(" route to: %s\n", 1900 routename(&soup->so_dst->sa, NULL, RTF_HOST)); 1901 } 1902 if (rtm->rtm_version != RTM_VERSION) { 1903 warnx("routing message version %d not understood", 1904 rtm->rtm_version); 1905 return 1; 1906 } 1907 if (rtm->rtm_msglen > msglen) { 1908 warnx("message length mismatch, in packet %d, returned %d", 1909 rtm->rtm_msglen, msglen); 1910 } 1911 if (rtm->rtm_errno) { 1912 warnx("RTM_GET: %s (errno %d)", 1913 strerror(rtm->rtm_errno), rtm->rtm_errno); 1914 return 1; 1915 } 1916 cp = ((char *)(rtm + 1)); 1917 if (rtm->rtm_addrs) 1918 for (i = 1; i; i <<= 1) 1919 if (i & rtm->rtm_addrs) { 1920 sa = (struct sockaddr *)cp; 1921 switch (i) { 1922 case RTA_DST: 1923 dst = sa; 1924 break; 1925 case RTA_GATEWAY: 1926 gate = sa; 1927 break; 1928 case RTA_NETMASK: 1929 mask = sa; 1930 break; 1931 case RTA_IFP: 1932 if (sa->sa_family == AF_LINK && 1933 ((struct sockaddr_dl *)sa)->sdl_nlen) 1934 ifp = (struct sockaddr_dl *)sa; 1935 break; 1936 case RTA_IFA: 1937 ifa = sa; 1938 break; 1939 case RTA_TAG: 1940 mpls = sa; 1941 break; 1942 } 1943 RT_ADVANCE(cp, sa); 1944 } 1945 if (dst && mask) 1946 mask->sa_family = dst->sa_family; /* XXX */ 1947 if (dst && ! shortoutput) 1948 (void)printf("destination: %s\n", 1949 routename(dst, mask, RTF_HOST)); 1950 if (mask && ! shortoutput) { 1951 int savenflag = nflag; 1952 1953 nflag = 1; 1954 (void)printf(" mask: %s\n", 1955 routename(mask, NULL, RTF_HOST)); 1956 nflag = savenflag; 1957 } 1958 if (gate && rtm->rtm_flags & RTF_GATEWAY) { 1959 const char *name; 1960 1961 name = routename(gate, NULL, RTF_HOST); 1962 if (shortoutput) { 1963 if (*name == '\0') 1964 return 1; 1965 (void)printf("%s\n", name); 1966 } else 1967 (void)printf(" gateway: %s\n", name); 1968 } 1969 if (mpls) { 1970 const char *name; 1971 name = routename(mpls, NULL, RTF_HOST); 1972 if(shortoutput) { 1973 if (*name == '\0') 1974 return 1; 1975 printf("%s\n", name); 1976 } else 1977 printf(" Tag: %s\n", name); 1978 } 1979 1980 if (ifa && ! shortoutput) 1981 (void)printf(" local addr: %s\n", 1982 routename(ifa, NULL, RTF_HOST)); 1983 if (ifp && ! shortoutput) 1984 (void)printf(" interface: %.*s\n", 1985 ifp->sdl_nlen, ifp->sdl_data); 1986 if (! shortoutput) { 1987 (void)printf(" flags: "); 1988 bprintf(stdout, rtm->rtm_flags, routeflags); 1989 } 1990 1991 #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') 1992 #define msec(u) (((u) + 500) / 1000) /* usec to msec */ 1993 1994 if (! shortoutput) { 1995 (void)printf("\n%s\n", "\ 1996 recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire"); 1997 printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); 1998 printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); 1999 printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); 2000 printf("%8"PRId64"%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); 2001 printf("%8"PRId64"%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR)); 2002 printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT)); 2003 printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); 2004 if (rtm->rtm_rmx.rmx_expire) 2005 rtm->rtm_rmx.rmx_expire -= time(0); 2006 printf("%8"PRId64"%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); 2007 } 2008 #undef lock 2009 #undef msec 2010 #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD) 2011 2012 if (shortoutput) 2013 return (rtm->rtm_addrs & RTF_GATEWAY) == 0; 2014 else if (verbose) 2015 pmsg_common(rtm); 2016 else if (rtm->rtm_addrs &~ RTA_IGN) { 2017 (void)printf("sockaddrs: "); 2018 bprintf(stdout, rtm->rtm_addrs, addrnames); 2019 putchar('\n'); 2020 } 2021 return 0; 2022 #undef RTA_IGN 2023 } 2024 #endif /* SMALL */ 2025 2026 void 2027 pmsg_common(struct rt_msghdr *rtm) 2028 { 2029 (void)printf("\nlocks: "); 2030 bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames); 2031 (void)printf(" inits: "); 2032 bprintf(stdout, rtm->rtm_inits, metricnames); 2033 pmsg_addrs((char *)(rtm + 1), rtm->rtm_addrs); 2034 } 2035 2036 static void 2037 extract_addrs(const char *cp, int addrs, const struct sockaddr *sa[], int *nmfp) 2038 { 2039 int i, nmf = -1; 2040 2041 for (i = 0; i < RTAX_MAX; i++) { 2042 if ((1 << i) & addrs) { 2043 sa[i] = (const struct sockaddr *)cp; 2044 if ((i == RTAX_DST || i == RTAX_IFA) && 2045 nmf == -1) 2046 nmf = sa[i]->sa_family; 2047 RT_ADVANCE(cp, sa[i]); 2048 } else 2049 sa[i] = NULL; 2050 } 2051 2052 if (nmfp != NULL) 2053 *nmfp = nmf; 2054 } 2055 2056 static void 2057 pmsg_addrs(const char *cp, int addrs) 2058 { 2059 const struct sockaddr *sa[RTAX_MAX]; 2060 int i, nmf; 2061 2062 if (addrs != 0) { 2063 (void)printf("\nsockaddrs: "); 2064 bprintf(stdout, addrs, addrnames); 2065 (void)putchar('\n'); 2066 extract_addrs(cp, addrs, sa, &nmf); 2067 for (i = 0; i < RTAX_MAX; i++) { 2068 if (sa[i] == NULL) 2069 continue; 2070 2071 if (i == RTAX_NETMASK && sa[i]->sa_len) 2072 (void)printf(" %s", 2073 netmask_string(sa[i], -1, nmf)); 2074 else 2075 (void)printf(" %s", 2076 routename(sa[i], NULL, RTF_HOST)); 2077 } 2078 } 2079 (void)putchar('\n'); 2080 (void)fflush(stdout); 2081 } 2082 2083 static void 2084 bprintf(FILE *fp, int b, const char *f) 2085 { 2086 int i; 2087 int gotsome = 0; 2088 const uint8_t *s = (const uint8_t *)f; 2089 2090 if (b == 0) { 2091 fputs("none", fp); 2092 return; 2093 } 2094 while ((i = *s++) != 0) { 2095 if (b & (1 << (i-1))) { 2096 if (gotsome == 0) 2097 i = '<'; 2098 else 2099 i = ','; 2100 (void)putc(i, fp); 2101 gotsome = 1; 2102 for (; (i = *s) > 32; s++) 2103 (void)putc(i, fp); 2104 } else 2105 while (*s > 32) 2106 s++; 2107 } 2108 if (gotsome) 2109 (void)putc('>', fp); 2110 } 2111 2112 int 2113 keyword(const char *cp) 2114 { 2115 struct keytab *kt = keywords; 2116 2117 while (kt->kt_cp && strcmp(kt->kt_cp, cp)) 2118 kt++; 2119 return kt->kt_i; 2120 } 2121 2122 static void 2123 sodump(sup su, const char *which) 2124 { 2125 #ifdef INET6 2126 char ntop_buf[NI_MAXHOST]; 2127 #endif 2128 2129 switch (su->sa.sa_family) { 2130 case AF_INET: 2131 (void)printf("%s: inet %s; ", 2132 which, inet_ntoa(su->sin.sin_addr)); 2133 break; 2134 #ifndef SMALL 2135 case AF_APPLETALK: 2136 (void)printf("%s: atalk %d.%d; ", 2137 which, su->sat.sat_addr.s_net, su->sat.sat_addr.s_node); 2138 break; 2139 #endif 2140 case AF_LINK: 2141 (void)printf("%s: link %s; ", 2142 which, link_ntoa(&su->sdl)); 2143 break; 2144 #ifdef INET6 2145 case AF_INET6: 2146 (void)printf("%s: inet6 %s; ", 2147 which, inet_ntop(AF_INET6, &su->sin6.sin6_addr, 2148 ntop_buf, sizeof(ntop_buf))); 2149 break; 2150 #endif 2151 #ifndef SMALL 2152 case AF_ISO: 2153 (void)printf("%s: iso %s; ", 2154 which, iso_ntoa(&su->siso.siso_addr)); 2155 break; 2156 case AF_MPLS: 2157 { 2158 union mpls_shim ms; 2159 const union mpls_shim *pms; 2160 int psize = sizeof(struct sockaddr_mpls); 2161 2162 ms.s_addr = ntohl(su->smpls.smpls_addr.s_addr); 2163 printf("%s: mpls %u; ", 2164 which, ms.shim.label); 2165 2166 pms = &su->smpls.smpls_addr; 2167 while(psize < su->smpls.smpls_len) { 2168 pms++; 2169 ms.s_addr = ntohl(pms->s_addr); 2170 printf("%u; ", ms.shim.label); 2171 psize += sizeof(ms); 2172 } 2173 break; 2174 } 2175 #endif /* SMALL */ 2176 default: 2177 (void)printf("%s: (%d) %s; ", 2178 which, su->sa.sa_family, any_ntoa(&su->sa)); 2179 } 2180 (void)fflush(stdout); 2181 } 2182 2183 /* States*/ 2184 #define VIRGIN 0 2185 #define GOTONE 1 2186 #define GOTTWO 2 2187 /* Inputs */ 2188 #define DIGIT (4*0) 2189 #define END (4*1) 2190 #define DELIM (4*2) 2191 2192 static void 2193 sockaddr(const char *addr, struct sockaddr *sa) 2194 { 2195 char *cp = (char *)sa; 2196 int size = sa->sa_len; 2197 char *cplim = cp + size; 2198 int byte = 0, state = VIRGIN, new = 0; 2199 2200 (void)memset(cp, 0, size); 2201 cp++; 2202 do { 2203 if ((*addr >= '0') && (*addr <= '9')) { 2204 new = *addr - '0'; 2205 } else if ((*addr >= 'a') && (*addr <= 'f')) { 2206 new = *addr - 'a' + 10; 2207 } else if ((*addr >= 'A') && (*addr <= 'F')) { 2208 new = *addr - 'A' + 10; 2209 } else if (*addr == 0) 2210 state |= END; 2211 else 2212 state |= DELIM; 2213 addr++; 2214 switch (state /* | INPUT */) { 2215 case GOTTWO | DIGIT: 2216 *cp++ = byte; /*FALLTHROUGH*/ 2217 case VIRGIN | DIGIT: 2218 state = GOTONE; byte = new; continue; 2219 case GOTONE | DIGIT: 2220 state = GOTTWO; byte = new + (byte << 4); continue; 2221 default: /* | DELIM */ 2222 state = VIRGIN; *cp++ = byte; byte = 0; continue; 2223 case GOTONE | END: 2224 case GOTTWO | END: 2225 *cp++ = byte; /* FALLTHROUGH */ 2226 case VIRGIN | END: 2227 break; 2228 } 2229 break; 2230 } while (cp < cplim); 2231 sa->sa_len = cp - (char *)sa; 2232 } 2233