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