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