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