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