1 /* $NetBSD: route.c,v 1.159 2018/03/23 11:57:33 roy 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.159 2018/03/23 11:57:33 roy 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/sysctl.h> 51 52 #include <net/if.h> 53 #include <net/route.h> 54 #include <net/if_dl.h> 55 #include <net80211/ieee80211_netbsd.h> 56 #include <netinet/in.h> 57 #include <netatalk/at.h> 58 #include <netmpls/mpls.h> 59 #include <arpa/inet.h> 60 #include <netdb.h> 61 62 #include <errno.h> 63 #include <unistd.h> 64 #include <stdio.h> 65 #include <ctype.h> 66 #include <stdlib.h> 67 #include <string.h> 68 #include <time.h> 69 #include <paths.h> 70 #include <err.h> 71 #include <util.h> 72 73 #include "keywords.h" 74 #include "extern.h" 75 #include "prog_ops.h" 76 #include "rtutil.h" 77 78 union sockunion { 79 struct sockaddr sa; 80 struct sockaddr_in sin; 81 #ifdef INET6 82 struct sockaddr_in6 sin6; 83 #endif 84 struct sockaddr_at sat; 85 struct sockaddr_dl sdl; 86 #ifndef SMALL 87 struct sockaddr_mpls smpls; 88 #endif /* SMALL */ 89 struct sockaddr_storage sstorage; 90 }; 91 92 typedef union sockunion *sup; 93 94 struct sou { 95 union sockunion *so_dst, *so_gate, *so_mask, *so_genmask, *so_ifa, 96 *so_ifp, *so_mpls; 97 }; 98 99 static const char *route_strerror(int); 100 static void set_metric(const char *, int); 101 static int newroute(int, char *const *); 102 static void inet_makenetandmask(u_int32_t, struct sockaddr_in *, struct sou *); 103 #ifdef INET6 104 static int inet6_makenetandmask(const struct sockaddr_in6 *, struct sou *); 105 #endif 106 static int getaddr(int, const char *, struct hostent **, struct sou *); 107 static int flushroutes(int, char *const [], int); 108 static char *netmask_string(const struct sockaddr *, int, int); 109 static int prefixlen(const char *, struct sou *); 110 #ifndef SMALL 111 static void interfaces(void); 112 static void monitor(int, char * const *); 113 static int print_getmsg(struct rt_msghdr *, int, struct sou *); 114 static const char *linkstate(struct if_msghdr *); 115 static sup readtag(sup, const char *); 116 static void addtag(sup, const char *, int); 117 #endif /* SMALL */ 118 static int rtmsg(int, int, struct sou *); 119 static void mask_addr(struct sou *); 120 static void print_rtmsg(struct rt_msghdr *, int); 121 static void pmsg_common(struct rt_msghdr *); 122 static void pmsg_addrs(const char *, int); 123 static void bprintf(FILE *, int, const char *); 124 static void sodump(sup, const char *); 125 static void sockaddr(const char *, struct sockaddr *); 126 127 int pid, rtm_addrs; 128 int sock; 129 int forcehost, forcenet, doflush, af; 130 int iflag, Lflag, nflag, qflag, tflag, Sflag, Tflag; 131 int verbose, aflen = sizeof(struct sockaddr_in), rtag; 132 int locking, lockrest, debugonly, shortoutput; 133 struct rt_metrics rt_metrics; 134 int rtm_inits; 135 short ns_nullh[] = {0,0,0}; 136 short ns_bh[] = {-1,-1,-1}; 137 138 static const char opts[] = "dfLnqSsTtv"; 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 [-%s] cmd [[-<qualifers>] args]\n", getprogname(), opts); 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 156 int 157 main(int argc, char * const *argv) 158 { 159 int ch; 160 161 if (argc < 2) 162 usage(NULL); 163 164 while ((ch = getopt(argc, argv, opts)) != -1) 165 switch (ch) { 166 case 'd': 167 debugonly = 1; 168 break; 169 case 'f': 170 doflush = 1; 171 break; 172 case 'L': 173 Lflag = RT_LFLAG; 174 break; 175 case 'n': 176 nflag = RT_NFLAG; 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 = RT_TFLAG; 189 break; 190 case 't': 191 tflag = 1; 192 break; 193 case 'v': 194 verbose = RT_VFLAG; 195 break; 196 case '?': 197 default: 198 usage(NULL); 199 /*NOTREACHED*/ 200 } 201 argc -= optind; 202 argv += optind; 203 204 if (prog_init && prog_init() == -1) 205 err(1, "init failed"); 206 207 pid = prog_getpid(); 208 if (tflag) 209 sock = prog_open("/dev/null", O_WRONLY, 0); 210 else 211 sock = prog_socket(PF_ROUTE, SOCK_RAW, 0); 212 if (sock < 0) 213 err(EXIT_FAILURE, "socket"); 214 215 if (*argv == NULL) { 216 if (doflush) 217 ch = K_FLUSH; 218 else 219 goto no_cmd; 220 } else 221 ch = keyword(*argv); 222 223 switch (ch) { 224 #ifndef SMALL 225 case K_GET: 226 #endif /* SMALL */ 227 case K_CHANGE: 228 case K_ADD: 229 case K_DELETE: 230 if (doflush) 231 (void)flushroutes(1, argv, 0); 232 return newroute(argc, argv); 233 234 case K_SHOW: 235 show(argc, argv, Lflag|nflag|Tflag|verbose); 236 return 0; 237 238 #ifndef SMALL 239 case K_MONITOR: 240 monitor(argc, argv); 241 return 0; 242 243 #endif /* SMALL */ 244 case K_FLUSH: 245 return flushroutes(argc, argv, 0); 246 247 case K_FLUSHALL: 248 return flushroutes(argc, argv, 1); 249 no_cmd: 250 default: 251 usage(*argv); 252 /*NOTREACHED*/ 253 } 254 } 255 256 static char * 257 netmask_string(const struct sockaddr *mask, int len, int family) 258 { 259 static char smask[INET6_ADDRSTRLEN]; 260 struct sockaddr_in nsin; 261 struct sockaddr_in6 nsin6; 262 263 if (len >= 0) 264 snprintf(smask, sizeof(smask), "%d", len); 265 else { 266 switch (family) { 267 case AF_INET: 268 memset(&nsin, 0, sizeof(nsin)); 269 memcpy(&nsin, mask, mask->sa_len); 270 snprintf(smask, sizeof(smask), "%s", 271 inet_ntoa(nsin.sin_addr)); 272 break; 273 case AF_INET6: 274 memset(&nsin6, 0, sizeof(nsin6)); 275 memcpy(&nsin6, mask, mask->sa_len); 276 inet_ntop(family, &nsin6.sin6_addr, smask, 277 sizeof(smask)); 278 break; 279 default: 280 snprintf(smask, sizeof(smask), "%s", any_ntoa(mask)); 281 } 282 } 283 284 return smask; 285 } 286 /* 287 * Purge all entries in the routing tables not 288 * associated with network interfaces. 289 */ 290 static int 291 flushroutes(int argc, char * const argv[], int doall) 292 { 293 struct sockaddr *sa; 294 size_t needed; 295 int flags, mib[6], rlen, seqno; 296 char *buf, *next, *lim; 297 const char *afname; 298 struct rt_msghdr *rtm; 299 300 flags = 0; 301 af = AF_UNSPEC; 302 /* Don't want to read back our messages */ 303 prog_shutdown(sock, SHUT_RD); 304 parse_show_opts(argc, argv, &af, &flags, &afname, false); 305 mib[0] = CTL_NET; 306 mib[1] = PF_ROUTE; 307 mib[2] = 0; /* protocol */ 308 mib[3] = 0; /* wildcard address family */ 309 mib[4] = NET_RT_DUMP; 310 mib[5] = 0; /* no flags */ 311 if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 312 err(EXIT_FAILURE, "route-sysctl-estimate"); 313 buf = lim = NULL; 314 if (needed) { 315 if ((buf = malloc(needed)) == NULL) 316 err(EXIT_FAILURE, "malloc"); 317 if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 318 err(EXIT_FAILURE, "actual retrieval of routing table"); 319 lim = buf + needed; 320 } 321 if (verbose) { 322 (void)printf("Examining routing table from sysctl\n"); 323 if (af != AF_UNSPEC) 324 printf("(address family %s)\n", afname); 325 } 326 if (needed == 0) 327 return 0; 328 seqno = 0; /* ??? */ 329 for (next = buf; next < lim; next += rtm->rtm_msglen) { 330 rtm = (struct rt_msghdr *)next; 331 sa = (struct sockaddr *)(rtm + 1); 332 if (verbose) 333 print_rtmsg(rtm, rtm->rtm_msglen); 334 if ((rtm->rtm_flags & flags) != flags) 335 continue; 336 if (!(rtm->rtm_flags & (RTF_GATEWAY | RTF_STATIC)) && !doall) 337 continue; 338 if (af != AF_UNSPEC && sa->sa_family != af) 339 continue; 340 if (debugonly) 341 continue; 342 rtm->rtm_type = RTM_DELETE; 343 rtm->rtm_seq = seqno; 344 do { 345 rlen = prog_write(sock, next, rtm->rtm_msglen); 346 } while (rlen == -1 && errno == ENOBUFS); 347 if (rlen == -1) { 348 warnx("writing to routing socket: %s", 349 route_strerror(errno)); 350 return 1; 351 } 352 if (rlen < (int)rtm->rtm_msglen) { 353 warnx("write to routing socket, got %d for rlen", rlen); 354 return 1; 355 } 356 seqno++; 357 if (qflag) 358 continue; 359 if (verbose) 360 print_rtmsg(rtm, rlen); 361 else { 362 (void)printf("%-20.20s ", netname(sa, NULL, nflag)); 363 sa = (struct sockaddr *)(RT_ROUNDUP(sa->sa_len) + 364 (char *)sa); 365 (void)printf("%-20.20s ", routename(sa, nflag)); 366 (void)printf("done\n"); 367 } 368 } 369 free(buf); 370 return 0; 371 } 372 373 static const char * 374 route_strerror(int error) 375 { 376 377 switch (error) { 378 case ESRCH: 379 return "not in table"; 380 case EBUSY: 381 return "entry in use"; 382 case ENOBUFS: 383 return "routing table overflow"; 384 default: 385 return strerror(error); 386 } 387 } 388 389 static void 390 set_metric(const char *value, int key) 391 { 392 int flag = 0; 393 uint64_t noval, *valp = &noval; 394 395 switch (key) { 396 #define caseof(x, y, z) \ 397 case x: valp = (uint64_t *)&rt_metrics.z; flag = y; break 398 caseof(K_MTU, RTV_MTU, rmx_mtu); 399 caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); 400 caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); 401 caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); 402 caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); 403 caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); 404 caseof(K_RTT, RTV_RTT, rmx_rtt); 405 caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); 406 } 407 rtm_inits |= flag; 408 if (lockrest || locking) 409 rt_metrics.rmx_locks |= flag; 410 if (locking) 411 locking = 0; 412 *valp = strtoul(value, NULL, 0); 413 } 414 415 static int 416 newroute(int argc, char *const *argv) 417 { 418 const char *cmd, *dest = "", *gateway = ""; 419 int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC; 420 int key; 421 struct hostent *hp = 0; 422 struct sou sou, *soup = &sou; 423 424 sou.so_dst = calloc(1, sizeof(union sockunion)); 425 sou.so_gate = calloc(1, sizeof(union sockunion)); 426 sou.so_mask = calloc(1, sizeof(union sockunion)); 427 sou.so_genmask = calloc(1, sizeof(union sockunion)); 428 sou.so_ifa = calloc(1, sizeof(union sockunion)); 429 sou.so_ifp = calloc(1, sizeof(union sockunion)); 430 sou.so_mpls = calloc(1, sizeof(union sockunion)); 431 432 if (sou.so_dst == NULL || sou.so_gate == NULL || sou.so_mask == NULL || 433 sou.so_genmask == NULL || sou.so_ifa == NULL || sou.so_ifp == NULL || 434 sou.so_mpls == NULL) 435 errx(EXIT_FAILURE, "Cannot allocate memory"); 436 437 cmd = argv[0]; 438 af = AF_UNSPEC; 439 if (*cmd != 'g') { 440 /* Don't want to read back our messages */ 441 prog_shutdown(sock, SHUT_RD); 442 } 443 while (--argc > 0) { 444 if (**(++argv)== '-') { 445 switch (key = keyword(1 + *argv)) { 446 447 case K_SA: 448 af = PF_ROUTE; 449 aflen = sizeof(union sockunion); 450 break; 451 452 #ifndef SMALL 453 case K_ATALK: 454 af = AF_APPLETALK; 455 aflen = sizeof(struct sockaddr_at); 456 break; 457 #endif 458 459 case K_INET: 460 af = AF_INET; 461 aflen = sizeof(struct sockaddr_in); 462 break; 463 464 #ifdef INET6 465 case K_INET6: 466 af = AF_INET6; 467 aflen = sizeof(struct sockaddr_in6); 468 break; 469 #endif 470 471 case K_LINK: 472 af = AF_LINK; 473 aflen = sizeof(struct sockaddr_dl); 474 break; 475 476 #ifndef SMALL 477 case K_MPLS: 478 af = AF_MPLS; 479 aflen = sizeof(struct sockaddr_mpls); 480 break; 481 case K_TAG: 482 if (!--argc) 483 usage(1+*argv); 484 af = AF_MPLS; 485 aflen = sizeof(struct sockaddr_mpls); 486 (void)getaddr(RTA_TAG, *++argv, 0, soup); 487 break; 488 #endif /* SMALL */ 489 490 case K_IFACE: 491 case K_INTERFACE: 492 iflag++; 493 break; 494 case K_NOSTATIC: 495 flags &= ~RTF_STATIC; 496 break; 497 case K_LOCK: 498 locking = 1; 499 break; 500 case K_LOCKREST: 501 lockrest = 1; 502 break; 503 case K_HOST: 504 forcehost++; 505 break; 506 case K_REJECT: 507 flags |= RTF_REJECT; 508 break; 509 case K_NOREJECT: 510 flags &= ~RTF_REJECT; 511 break; 512 case K_BLACKHOLE: 513 flags |= RTF_BLACKHOLE; 514 break; 515 case K_NOBLACKHOLE: 516 flags &= ~RTF_BLACKHOLE; 517 break; 518 case K_PROTO1: 519 flags |= RTF_PROTO1; 520 break; 521 case K_PROTO2: 522 flags |= RTF_PROTO2; 523 break; 524 case K_PROXY: 525 flags |= RTF_ANNOUNCE; 526 break; 527 case K_CONNECTED: 528 flags |= RTF_CONNECTED; 529 break; 530 case K_NOCONNECTED: 531 flags &= ~RTF_CONNECTED; 532 break; 533 case K_STATIC: 534 flags |= RTF_STATIC; 535 break; 536 case K_IFA: 537 if (!--argc) 538 usage(1+*argv); 539 (void)getaddr(RTA_IFA, *++argv, 0, soup); 540 break; 541 case K_IFP: 542 if (!--argc) 543 usage(1+*argv); 544 (void)getaddr(RTA_IFP, *++argv, 0, soup); 545 break; 546 case K_GENMASK: 547 if (!--argc) 548 usage(1+*argv); 549 (void)getaddr(RTA_GENMASK, *++argv, 0, soup); 550 break; 551 case K_GATEWAY: 552 if (!--argc) 553 usage(1+*argv); 554 (void)getaddr(RTA_GATEWAY, *++argv, 0, soup); 555 break; 556 case K_DST: 557 if (!--argc) 558 usage(1+*argv); 559 ishost = getaddr(RTA_DST, *++argv, &hp, soup); 560 dest = *argv; 561 break; 562 case K_NETMASK: 563 if (!--argc) 564 usage(1+*argv); 565 (void)getaddr(RTA_NETMASK, *++argv, 0, soup); 566 /* FALLTHROUGH */ 567 case K_NET: 568 forcenet++; 569 break; 570 case K_PREFIXLEN: 571 if (!--argc) 572 usage(1+*argv); 573 ishost = prefixlen(*++argv, soup); 574 break; 575 case K_MTU: 576 case K_HOPCOUNT: 577 case K_EXPIRE: 578 case K_RECVPIPE: 579 case K_SENDPIPE: 580 case K_SSTHRESH: 581 case K_RTT: 582 case K_RTTVAR: 583 if (!--argc) 584 usage(1+*argv); 585 set_metric(*++argv, key); 586 break; 587 default: 588 usage(1+*argv); 589 } 590 } else { 591 if ((rtm_addrs & RTA_DST) == 0) { 592 dest = *argv; 593 ishost = getaddr(RTA_DST, *argv, &hp, soup); 594 } else if ((rtm_addrs & RTA_GATEWAY) == 0) { 595 gateway = *argv; 596 (void)getaddr(RTA_GATEWAY, *argv, &hp, soup); 597 } else { 598 ret = atoi(*argv); 599 600 if (ret == 0) { 601 if (strcmp(*argv, "0") == 0) { 602 if (!qflag) { 603 warnx("%s, %s", 604 "old usage of trailing 0", 605 "assuming route to if"); 606 } 607 } else 608 usage(NULL); 609 iflag = 1; 610 continue; 611 } else if (ret > 0 && ret < 10) { 612 if (!qflag) { 613 warnx("%s, %s", 614 "old usage of trailing digit", 615 "assuming route via gateway"); 616 } 617 iflag = 0; 618 continue; 619 } 620 (void)getaddr(RTA_NETMASK, *argv, 0, soup); 621 } 622 } 623 } 624 if ((rtm_addrs & RTA_DST) == 0) 625 errx(EXIT_FAILURE, "missing destination specification"); 626 if (*cmd == 'a' && (rtm_addrs & RTA_GATEWAY) == 0) 627 errx(EXIT_FAILURE, "missing gateway specification"); 628 if (forcehost && forcenet) 629 errx(EXIT_FAILURE, "-host and -net conflict"); 630 else if (forcehost) 631 ishost = 1; 632 else if (forcenet) 633 ishost = 0; 634 flags |= RTF_UP; 635 if (ishost) 636 flags |= RTF_HOST; 637 if (iflag == 0) 638 flags |= RTF_GATEWAY; 639 for (attempts = 1; ; attempts++) { 640 errno = 0; 641 if ((ret = rtmsg(*cmd, flags, soup)) == 0) 642 break; 643 if (errno != ENETUNREACH && errno != ESRCH) 644 break; 645 if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) { 646 hp->h_addr_list++; 647 memmove(&soup->so_gate->sin.sin_addr, hp->h_addr_list[0], 648 hp->h_length); 649 } else 650 break; 651 } 652 if (*cmd == 'g' || qflag) 653 goto out; 654 655 oerrno = errno; 656 (void)printf("%s %s %s", cmd, ishost? "host" : "net", dest); 657 if (*gateway) { 658 (void)printf(": gateway %s", gateway); 659 if (attempts > 1 && ret == 0 && af == AF_INET) 660 (void)printf(" (%s)", 661 inet_ntoa(soup->so_gate->sin.sin_addr)); 662 } 663 if (ret == 0) 664 (void)printf("\n"); 665 else 666 (void)printf(": %s\n", route_strerror(oerrno)); 667 out: 668 free(sou.so_dst); 669 free(sou.so_gate); 670 free(sou.so_mask); 671 free(sou.so_genmask); 672 free(sou.so_ifa); 673 free(sou.so_ifp); 674 free(sou.so_mpls); 675 676 return ret != 0; 677 } 678 679 static void 680 inet_makenetandmask(const u_int32_t net, struct sockaddr_in * const isin, 681 struct sou *soup) 682 { 683 struct sockaddr_in *sin; 684 u_int32_t addr, mask = 0; 685 char *cp; 686 687 rtm_addrs |= RTA_NETMASK; 688 if (net == 0) 689 mask = addr = 0; 690 else if (net < 128) { 691 addr = net << IN_CLASSA_NSHIFT; 692 mask = IN_CLASSA_NET; 693 } else if (net < 192) { 694 addr = net << IN_CLASSA_NSHIFT; 695 mask = IN_CLASSB_NET; 696 } else if (net < 224) { 697 addr = net << IN_CLASSA_NSHIFT; 698 mask = IN_CLASSC_NET; 699 } else if (net < 256) { 700 addr = net << IN_CLASSA_NSHIFT; 701 mask = IN_CLASSD_NET; 702 } else if (net < 49152) { /* 192 * 256 */ 703 addr = net << IN_CLASSB_NSHIFT; 704 mask = IN_CLASSB_NET; 705 } else if (net < 57344) { /* 224 * 256 */ 706 addr = net << IN_CLASSB_NSHIFT; 707 mask = IN_CLASSC_NET; 708 } else if (net < 65536) { 709 addr = net << IN_CLASSB_NSHIFT; 710 mask = IN_CLASSB_NET; 711 } else if (net < 14680064L) { /* 224 * 65536 */ 712 addr = net << IN_CLASSC_NSHIFT; 713 mask = IN_CLASSC_NET; 714 } else if (net < 16777216L) { 715 addr = net << IN_CLASSC_NSHIFT; 716 mask = IN_CLASSD_NET; 717 } else { 718 addr = net; 719 if ((addr & IN_CLASSA_HOST) == 0) 720 mask = IN_CLASSA_NET; 721 else if ((addr & IN_CLASSB_HOST) == 0) 722 mask = IN_CLASSB_NET; 723 else if ((addr & IN_CLASSC_HOST) == 0) 724 mask = IN_CLASSC_NET; 725 else 726 mask = -1; 727 } 728 isin->sin_addr.s_addr = htonl(addr); 729 sin = &soup->so_mask->sin; 730 sin->sin_addr.s_addr = htonl(mask); 731 sin->sin_len = 0; 732 sin->sin_family = 0; 733 cp = (char *)(&sin->sin_addr + 1); 734 while (*--cp == 0 && cp > (char *)sin) 735 ; 736 sin->sin_len = 1 + cp - (char *)sin; 737 sin->sin_family = AF_INET; 738 } 739 740 #ifdef INET6 741 /* 742 * XXX the function may need more improvement... 743 */ 744 static int 745 inet6_makenetandmask(const struct sockaddr_in6 * const sin6, struct sou *soup) 746 { 747 const char *plen; 748 struct in6_addr in6; 749 750 plen = NULL; 751 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && 752 sin6->sin6_scope_id == 0) { 753 plen = "0"; 754 } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) { 755 /* aggregatable global unicast - RFC2374 */ 756 memset(&in6, 0, sizeof(in6)); 757 if (!memcmp(&sin6->sin6_addr.s6_addr[8], &in6.s6_addr[8], 8)) 758 plen = "64"; 759 } 760 761 if (!plen || strcmp(plen, "128") == 0) 762 return 1; 763 else { 764 rtm_addrs |= RTA_NETMASK; 765 (void)prefixlen(plen, soup); 766 return 0; 767 } 768 } 769 #endif 770 771 /* 772 * Interpret an argument as a network address of some kind, 773 * returning 1 if a host address, 0 if a network address. 774 */ 775 static int 776 getaddr(int which, const char *s, struct hostent **hpp, struct sou *soup) 777 { 778 sup su; 779 struct hostent *hp; 780 struct netent *np; 781 u_int32_t val; 782 char *t; 783 int afamily; /* local copy of af so we can change it */ 784 785 if (af == AF_UNSPEC) { 786 af = AF_INET; 787 aflen = sizeof(struct sockaddr_in); 788 } 789 afamily = af; 790 rtm_addrs |= which; 791 switch (which) { 792 case RTA_DST: 793 su = soup->so_dst; 794 break; 795 case RTA_GATEWAY: 796 su = soup->so_gate; 797 break; 798 case RTA_NETMASK: 799 su = soup->so_mask; 800 break; 801 case RTA_GENMASK: 802 su = soup->so_genmask; 803 break; 804 case RTA_IFP: 805 su = soup->so_ifp; 806 afamily = AF_LINK; 807 break; 808 case RTA_IFA: 809 su = soup->so_ifa; 810 su->sa.sa_family = af; 811 break; 812 #ifndef SMALL 813 case RTA_TAG: 814 su = soup->so_mpls; 815 afamily = AF_MPLS; 816 break; 817 #endif 818 default: 819 su = NULL; 820 usage("Internal Error"); 821 /*NOTREACHED*/ 822 } 823 su->sa.sa_len = aflen; 824 su->sa.sa_family = afamily; /* cases that don't want it have left already */ 825 if (strcmp(s, "default") == 0) { 826 switch (which) { 827 case RTA_DST: 828 forcenet++; 829 (void)getaddr(RTA_NETMASK, s, 0, soup); 830 break; 831 case RTA_NETMASK: 832 case RTA_GENMASK: 833 su->sa.sa_len = 0; 834 } 835 return 0; 836 } 837 switch (afamily) { 838 #ifdef INET6 839 case AF_INET6: 840 { 841 struct addrinfo hints, *res; 842 char *slash = 0; 843 844 if (which == RTA_DST && (slash = (strrchr(s, '/'))) != 0) 845 *slash = '\0'; 846 memset(&hints, 0, sizeof(hints)); 847 hints.ai_family = afamily; /*AF_INET6*/ 848 hints.ai_flags = AI_NUMERICHOST; 849 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 850 if (getaddrinfo(s, "0", &hints, &res) != 0) { 851 hints.ai_flags = 0; 852 if (slash) { 853 *slash = '/'; 854 slash = 0; 855 } 856 if (getaddrinfo(s, "0", &hints, &res) != 0) 857 errx(EXIT_FAILURE, "%s: bad value", s); 858 } 859 if (slash) 860 *slash = '/'; 861 if (sizeof(su->sin6) != res->ai_addrlen) 862 errx(EXIT_FAILURE, "%s: bad value", s); 863 if (res->ai_next) { 864 errx(EXIT_FAILURE, 865 "%s: address resolved to multiple values", s); 866 } 867 memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6)); 868 freeaddrinfo(res); 869 inet6_putscopeid(&su->sin6, INET6_IS_ADDR_LINKLOCAL| 870 INET6_IS_ADDR_MC_LINKLOCAL); 871 if (hints.ai_flags == AI_NUMERICHOST) { 872 if (slash) 873 return prefixlen(slash + 1, soup); 874 if (which == RTA_DST) 875 return inet6_makenetandmask(&su->sin6, soup); 876 return 0; 877 } else 878 return 1; 879 } 880 #endif 881 882 case PF_ROUTE: 883 su->sa.sa_len = sizeof(*su); 884 sockaddr(s, &su->sa); 885 return 1; 886 887 #ifndef SMALL 888 case AF_APPLETALK: 889 t = strchr (s, '.'); 890 if (!t) { 891 badataddr: 892 errx(EXIT_FAILURE, "bad address: %s", s); 893 } 894 val = atoi (s); 895 if (val > 65535) 896 goto badataddr; 897 su->sat.sat_addr.s_net = val; 898 val = atoi (t); 899 if (val > 256) 900 goto badataddr; 901 su->sat.sat_addr.s_node = val; 902 rtm_addrs |= RTA_NETMASK; 903 return(forcehost || su->sat.sat_addr.s_node != 0); 904 case AF_MPLS: 905 if (which == RTA_DST) 906 soup->so_dst = readtag(su, s); 907 else if (which == RTA_TAG) 908 soup->so_mpls = readtag(su, s); 909 else 910 errx(EXIT_FAILURE, "MPLS can be used only as " 911 "DST or TAG"); 912 return 1; 913 #endif 914 915 case AF_LINK: 916 link_addr(s, &su->sdl); 917 return 1; 918 919 case AF_INET: 920 default: 921 break; 922 } 923 924 if (hpp == NULL) 925 hpp = &hp; 926 *hpp = NULL; 927 928 if ((t = strchr(s, '/')) != NULL && which == RTA_DST) { 929 *t = '\0'; 930 if (forcenet == 0) { 931 if ((val = inet_addr(s)) != INADDR_NONE) { 932 inet_makenetandmask(htonl(val), &su->sin, soup); 933 return prefixlen(&t[1], soup); 934 } 935 } else { 936 if ((val = inet_network(s)) != INADDR_NONE) { 937 inet_makenetandmask(val, &su->sin, soup); 938 return prefixlen(&t[1], soup); 939 } 940 } 941 *t = '/'; 942 } 943 if (inet_aton(s, &su->sin.sin_addr) && 944 (which != RTA_DST || forcenet == 0)) { 945 val = su->sin.sin_addr.s_addr; 946 if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY) 947 return 1; 948 else { 949 val = ntohl(val); 950 goto netdone; 951 } 952 } 953 if ((val = inet_network(s)) != INADDR_NONE || 954 ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0)) { 955 netdone: 956 if (which == RTA_DST) 957 inet_makenetandmask(val, &su->sin, soup); 958 return 0; 959 } 960 hp = gethostbyname(s); 961 if (hp) { 962 *hpp = hp; 963 su->sin.sin_family = hp->h_addrtype; 964 memmove(&su->sin.sin_addr, hp->h_addr, hp->h_length); 965 return 1; 966 } 967 errx(EXIT_FAILURE, "%s: bad value", s); 968 /*NOTREACHED*/ 969 } 970 971 #ifndef SMALL 972 static sup 973 readtag(sup su, const char *s) 974 { 975 char *p, *n, *norig; 976 int mplssize = 0; 977 sup retsu = su; 978 979 n = strdup(s); 980 if (n == NULL) 981 errx(EXIT_FAILURE, "%s: Cannot allocate memory", s); 982 norig = n; 983 for (uint i = 0; i < strlen(n); i++) 984 if(n[i] == ',') 985 mplssize++; 986 987 #define MPLS_NEW_SIZE (sizeof(struct sockaddr_mpls) + \ 988 mplssize * sizeof(union mpls_shim)) 989 990 if (mplssize != 0 && sizeof(union sockunion) < MPLS_NEW_SIZE) { 991 free(su); 992 retsu = malloc(MPLS_NEW_SIZE); 993 retsu->smpls.smpls_family = AF_MPLS; 994 } 995 retsu->smpls.smpls_len = MPLS_NEW_SIZE; 996 mplssize = 0; 997 while ((p = strchr(n, ',')) != NULL) { 998 p[0] = '\0'; 999 addtag(retsu, n, mplssize); 1000 n = p + 1; 1001 mplssize++; 1002 } 1003 addtag(retsu, n, mplssize); 1004 1005 free(norig); 1006 return retsu; 1007 } 1008 1009 static void 1010 addtag(sup su, const char *s, int where) 1011 { 1012 union mpls_shim *ms = &su->smpls.smpls_addr; 1013 1014 if (atoi(s) < 0 || atoi(s) >= (1 << 20)) 1015 errx(EXIT_FAILURE, "%s: Bad tag", s); 1016 ms[where].s_addr = 0; 1017 ms[where].shim.label = atoi(s); 1018 ms[where].s_addr = htonl(ms[where].s_addr); 1019 } 1020 #endif /* SMALL */ 1021 1022 int 1023 prefixlen(const char *s, struct sou *soup) 1024 { 1025 int max, len = atoi(s); 1026 #ifdef INET6 1027 int q, r; 1028 #endif 1029 1030 switch (af) { 1031 case AF_INET: 1032 max = sizeof(struct in_addr) * 8; 1033 break; 1034 #ifdef INET6 1035 case AF_INET6: 1036 max = sizeof(struct in6_addr) * 8; 1037 break; 1038 #endif 1039 default: 1040 errx(EXIT_FAILURE, "prefixlen is not supported with af %d", af); 1041 /*NOTREACHED*/ 1042 } 1043 1044 rtm_addrs |= RTA_NETMASK; 1045 if (len < -1 || len > max) 1046 errx(EXIT_FAILURE, "%s: bad value", s); 1047 1048 #ifdef INET6 1049 q = len >> 3; 1050 r = len & 7; 1051 #endif 1052 switch (af) { 1053 case AF_INET: 1054 memset(soup->so_mask, 0, sizeof(*soup->so_mask)); 1055 soup->so_mask->sin.sin_family = AF_INET; 1056 soup->so_mask->sin.sin_len = sizeof(struct sockaddr_in); 1057 soup->so_mask->sin.sin_addr.s_addr = (len == 0 ? 0 1058 : htonl(0xffffffff << (32 - len))); 1059 break; 1060 #ifdef INET6 1061 case AF_INET6: 1062 soup->so_mask->sin6.sin6_family = AF_INET6; 1063 soup->so_mask->sin6.sin6_len = sizeof(struct sockaddr_in6); 1064 memset(&soup->so_mask->sin6.sin6_addr, 0, 1065 sizeof(soup->so_mask->sin6.sin6_addr)); 1066 if (q > 0) 1067 memset(&soup->so_mask->sin6.sin6_addr, 0xff, q); 1068 if (r > 0) 1069 *((u_char *)&soup->so_mask->sin6.sin6_addr + q) = 1070 (0xff00 >> r) & 0xff; 1071 break; 1072 #endif 1073 } 1074 return len == max; 1075 } 1076 1077 #ifndef SMALL 1078 static void 1079 interfaces(void) 1080 { 1081 size_t needed; 1082 int mib[6]; 1083 char *buf, *lim, *next; 1084 struct rt_msghdr *rtm; 1085 1086 mib[0] = CTL_NET; 1087 mib[1] = PF_ROUTE; 1088 mib[2] = 0; /* protocol */ 1089 mib[3] = 0; /* wildcard address family */ 1090 mib[4] = NET_RT_IFLIST; 1091 mib[5] = 0; /* no flags */ 1092 if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 1093 err(EXIT_FAILURE, "route-sysctl-estimate"); 1094 if (needed) { 1095 if ((buf = malloc(needed)) == NULL) 1096 err(EXIT_FAILURE, "malloc"); 1097 if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 1098 err(EXIT_FAILURE, 1099 "actual retrieval of interface table"); 1100 } 1101 lim = buf + needed; 1102 for (next = buf; next < lim; next += rtm->rtm_msglen) { 1103 rtm = (struct rt_msghdr *)next; 1104 print_rtmsg(rtm, rtm->rtm_msglen); 1105 } 1106 free(buf); 1107 } 1108 } 1109 1110 static void 1111 monitor(int argc, char * const *argv) 1112 { 1113 int i, n; 1114 union { 1115 char msg[2048]; 1116 struct rt_msghdr hdr; 1117 } u; 1118 int count = 0; 1119 1120 /* usage: route monitor [-c <count>] */ 1121 1122 /* eat "monitor" */ 1123 argc -= 1; 1124 argv += 1; 1125 1126 /* parse [-c <count>] */ 1127 if (argc > 0) { 1128 if (argc != 2) 1129 usage(argv[0]); 1130 if (strcmp(argv[0], "-c") != 0) 1131 usage(argv[0]); 1132 1133 count = atoi(argv[1]); 1134 } 1135 1136 verbose = 1; 1137 if (debugonly) { 1138 interfaces(); 1139 exit(0); 1140 } 1141 for(i = 0; count == 0 || i < count; i++) { 1142 time_t now; 1143 n = prog_read(sock, &u, sizeof(u)); 1144 if (n == -1) { 1145 warn("read"); 1146 continue; 1147 } 1148 now = time(NULL); 1149 (void)printf("got message of size %d on %s", n, ctime(&now)); 1150 print_rtmsg(&u.hdr, n); 1151 } 1152 } 1153 1154 #endif /* SMALL */ 1155 1156 1157 struct { 1158 struct rt_msghdr m_rtm; 1159 char m_space[512]; 1160 } m_rtmsg; 1161 1162 static int 1163 rtmsg(int cmd, int flags, struct sou *soup) 1164 { 1165 static int seq; 1166 int rlen; 1167 char *cp = m_rtmsg.m_space; 1168 int l; 1169 1170 #define NEXTADDR(w, u) \ 1171 if (rtm_addrs & (w)) {\ 1172 l = RT_ROUNDUP(u->sa.sa_len); memmove(cp, u, l); cp += l;\ 1173 if (verbose && ! shortoutput) sodump(u,#u);\ 1174 } 1175 1176 errno = 0; 1177 memset(&m_rtmsg, 0, sizeof(m_rtmsg)); 1178 if (cmd == 'a') 1179 cmd = RTM_ADD; 1180 else if (cmd == 'c') 1181 cmd = RTM_CHANGE; 1182 else if (cmd == 'g') { 1183 #ifdef SMALL 1184 return -1; 1185 #else /* SMALL */ 1186 cmd = RTM_GET; 1187 if (soup->so_ifp->sa.sa_family == AF_UNSPEC) { 1188 soup->so_ifp->sa.sa_family = AF_LINK; 1189 soup->so_ifp->sa.sa_len = sizeof(struct sockaddr_dl); 1190 rtm_addrs |= RTA_IFP; 1191 } 1192 #endif /* SMALL */ 1193 } else 1194 cmd = RTM_DELETE; 1195 #define rtm m_rtmsg.m_rtm 1196 rtm.rtm_type = cmd; 1197 rtm.rtm_flags = flags; 1198 rtm.rtm_version = RTM_VERSION; 1199 rtm.rtm_seq = ++seq; 1200 rtm.rtm_addrs = rtm_addrs; 1201 rtm.rtm_rmx = rt_metrics; 1202 rtm.rtm_inits = rtm_inits; 1203 1204 if (rtm_addrs & RTA_NETMASK) 1205 mask_addr(soup); 1206 NEXTADDR(RTA_DST, soup->so_dst); 1207 NEXTADDR(RTA_GATEWAY, soup->so_gate); 1208 NEXTADDR(RTA_NETMASK, soup->so_mask); 1209 NEXTADDR(RTA_GENMASK, soup->so_genmask); 1210 NEXTADDR(RTA_IFP, soup->so_ifp); 1211 NEXTADDR(RTA_IFA, soup->so_ifa); 1212 #ifndef SMALL 1213 NEXTADDR(RTA_TAG, soup->so_mpls); 1214 #endif 1215 rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 1216 if (verbose && ! shortoutput) { 1217 if (rtm_addrs) 1218 putchar('\n'); 1219 print_rtmsg(&rtm, l); 1220 } 1221 if (debugonly) 1222 return 0; 1223 do { 1224 rlen = prog_write(sock, (char *)&m_rtmsg, l); 1225 } while (rlen == -1 && errno == ENOBUFS); 1226 if (rlen == -1) { 1227 warnx("writing to routing socket: %s", route_strerror(errno)); 1228 return -1; 1229 } 1230 if (rlen < l) { 1231 warnx("write to routing socket, got %d for rlen", rlen); 1232 return 1; 1233 } 1234 #ifndef SMALL 1235 if (cmd == RTM_GET) { 1236 do { 1237 l = prog_read(sock, 1238 (char *)&m_rtmsg, sizeof(m_rtmsg)); 1239 } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); 1240 if (l < 0) 1241 err(EXIT_FAILURE, "read from routing socket"); 1242 else 1243 return print_getmsg(&rtm, l, soup); 1244 } 1245 #endif /* SMALL */ 1246 #undef rtm 1247 return 0; 1248 } 1249 1250 static void 1251 mask_addr(struct sou *soup) 1252 { 1253 int olen = soup->so_mask->sa.sa_len; 1254 char *cp1 = olen + (char *)soup->so_mask, *cp2; 1255 1256 for (soup->so_mask->sa.sa_len = 0; cp1 > (char *)soup->so_mask; ) 1257 if (*--cp1 != 0) { 1258 soup->so_mask->sa.sa_len = 1 + cp1 - (char *)soup->so_mask; 1259 break; 1260 } 1261 if ((rtm_addrs & RTA_DST) == 0) 1262 return; 1263 switch (soup->so_dst->sa.sa_family) { 1264 case AF_INET: 1265 #ifdef INET6 1266 case AF_INET6: 1267 #endif 1268 #ifndef SMALL 1269 case AF_APPLETALK: 1270 #endif /* SMALL */ 1271 case 0: 1272 return; 1273 } 1274 cp1 = soup->so_mask->sa.sa_len + 1 + (char *)soup->so_dst; 1275 cp2 = soup->so_dst->sa.sa_len + 1 + (char *)soup->so_dst; 1276 while (cp2 > cp1) 1277 *--cp2 = 0; 1278 cp2 = soup->so_mask->sa.sa_len + 1 + (char *)soup->so_mask; 1279 while (cp1 > soup->so_dst->sa.sa_data) 1280 *--cp1 &= *--cp2; 1281 } 1282 1283 const char * const msgtypes[] = { 1284 [RTM_ADD] = "RTM_ADD: Add Route", 1285 [RTM_DELETE] = "RTM_DELETE: Delete Route", 1286 [RTM_CHANGE] = "RTM_CHANGE: Change Metrics, Flags or Gateway", 1287 [RTM_GET] = "RTM_GET: Report Metrics", 1288 [RTM_LOSING] = "RTM_LOSING: Kernel Suspects Partitioning", 1289 [RTM_REDIRECT] = "RTM_REDIRECT: Told to use different route", 1290 [RTM_MISS] = "RTM_MISS: Lookup failed on this address", 1291 [RTM_LOCK] = "RTM_LOCK: fix specified metrics", 1292 [RTM_OLDADD] = "RTM_OLDADD: caused by SIOCADDRT", 1293 [RTM_OLDDEL] = "RTM_OLDDEL: caused by SIOCDELRT", 1294 [RTM_NEWADDR] = "RTM_NEWADDR: address being added to iface", 1295 [RTM_DELADDR] = "RTM_DELADDR: address being removed from iface", 1296 [RTM_OOIFINFO] = "RTM_OOIFINFO: iface status change (pre-1.5)", 1297 [RTM_OIFINFO] = "RTM_OIFINFO: iface status change (pre-64bit time)", 1298 [RTM_IFANNOUNCE] = "RTM_IFANNOUNCE: iface arrival/departure", 1299 [RTM_IEEE80211] = "RTM_IEEE80211: IEEE80211 wireless event", 1300 [RTM_IFINFO] = "RTM_IFINFO: iface status change", 1301 [RTM_CHGADDR] = "RTM_CHGADDR: address being changed on iface", 1302 }; 1303 1304 const char metricnames[] = RTVBITS; 1305 const char routeflags[] = RTFBITS; 1306 const char ifnetflags[] = IFFBITS; 1307 const char addrnames[] = RTABITS; 1308 1309 1310 #ifndef SMALL 1311 static const char * 1312 linkstate(struct if_msghdr *ifm) 1313 { 1314 static char buf[64]; 1315 1316 switch (ifm->ifm_data.ifi_link_state) { 1317 case LINK_STATE_UNKNOWN: 1318 return "carrier: unknown"; 1319 case LINK_STATE_DOWN: 1320 return "carrier: no carrier"; 1321 case LINK_STATE_UP: 1322 return "carrier: active"; 1323 default: 1324 (void)snprintf(buf, sizeof(buf), "carrier: 0x%x", 1325 ifm->ifm_data.ifi_link_state); 1326 return buf; 1327 } 1328 } 1329 #endif /* SMALL */ 1330 1331 static void 1332 print_rtmsg(struct rt_msghdr *rtm, int msglen) 1333 { 1334 struct if_msghdr *ifm; 1335 struct ifa_msghdr *ifam; 1336 struct if_announcemsghdr *ifan; 1337 union { 1338 struct ieee80211_join_event join; 1339 struct ieee80211_leave_event leave; 1340 struct ieee80211_replay_event replay; 1341 struct ieee80211_michael_event michael; 1342 } ev; 1343 size_t evlen = 0; 1344 1345 if (verbose == 0) 1346 return; 1347 if (rtm->rtm_version != RTM_VERSION) { 1348 (void)printf("routing message version %d not understood\n", 1349 rtm->rtm_version); 1350 return; 1351 } 1352 if (msgtypes[rtm->rtm_type]) 1353 (void)printf("%s: ", msgtypes[rtm->rtm_type]); 1354 else 1355 (void)printf("#%d: ", rtm->rtm_type); 1356 (void)printf("len %d, ", rtm->rtm_msglen); 1357 switch (rtm->rtm_type) { 1358 case RTM_IFINFO: 1359 ifm = (struct if_msghdr *)rtm; 1360 (void)printf("if# %d, %s, flags: ", ifm->ifm_index, 1361 #ifdef SMALL 1362 "" 1363 #else 1364 linkstate(ifm) 1365 #endif /* SMALL */ 1366 ); 1367 bprintf(stdout, ifm->ifm_flags, ifnetflags); 1368 pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs); 1369 break; 1370 case RTM_NEWADDR: 1371 case RTM_DELADDR: 1372 case RTM_CHGADDR: 1373 ifam = (struct ifa_msghdr *)rtm; 1374 (void)printf("pid %d, metric %d, flags: ", 1375 ifam->ifam_pid, ifam->ifam_metric); 1376 bprintf(stdout, ifam->ifam_flags, routeflags); 1377 pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs); 1378 break; 1379 case RTM_IEEE80211: 1380 ifan = (struct if_announcemsghdr *)rtm; 1381 (void)printf("if# %d, what: ", ifan->ifan_index); 1382 switch (ifan->ifan_what) { 1383 case RTM_IEEE80211_ASSOC: 1384 printf("associate"); 1385 break; 1386 case RTM_IEEE80211_REASSOC: 1387 printf("re-associate"); 1388 break; 1389 case RTM_IEEE80211_DISASSOC: 1390 printf("disassociate"); 1391 break; 1392 case RTM_IEEE80211_SCAN: 1393 printf("scan complete"); 1394 break; 1395 case RTM_IEEE80211_JOIN: 1396 evlen = sizeof(ev.join); 1397 printf("join"); 1398 break; 1399 case RTM_IEEE80211_LEAVE: 1400 evlen = sizeof(ev.leave); 1401 printf("leave"); 1402 break; 1403 case RTM_IEEE80211_MICHAEL: 1404 evlen = sizeof(ev.michael); 1405 printf("michael"); 1406 break; 1407 case RTM_IEEE80211_REPLAY: 1408 evlen = sizeof(ev.replay); 1409 printf("replay"); 1410 break; 1411 default: 1412 evlen = 0; 1413 printf("#%d", ifan->ifan_what); 1414 break; 1415 } 1416 if (sizeof(*ifan) + evlen > ifan->ifan_msglen) { 1417 printf(" (truncated)\n"); 1418 break; 1419 } 1420 (void)memcpy(&ev, (ifan + 1), evlen); 1421 switch (ifan->ifan_what) { 1422 case RTM_IEEE80211_JOIN: 1423 case RTM_IEEE80211_LEAVE: 1424 printf(" mac %" PRIETHER, 1425 PRIETHER_ARGS(ev.join.iev_addr)); 1426 break; 1427 case RTM_IEEE80211_REPLAY: 1428 case RTM_IEEE80211_MICHAEL: 1429 printf(" src %" PRIETHER " dst %" PRIETHER 1430 " cipher %" PRIu8 " keyix %" PRIu8, 1431 PRIETHER_ARGS(ev.replay.iev_src), 1432 PRIETHER_ARGS(ev.replay.iev_dst), 1433 ev.replay.iev_cipher, 1434 ev.replay.iev_keyix); 1435 if (ifan->ifan_what == RTM_IEEE80211_REPLAY) { 1436 printf(" key rsc %#" PRIx64 1437 " frame rsc %#" PRIx64, 1438 ev.replay.iev_keyrsc, ev.replay.iev_rsc); 1439 } 1440 break; 1441 default: 1442 break; 1443 } 1444 printf("\n"); 1445 break; 1446 case RTM_IFANNOUNCE: 1447 ifan = (struct if_announcemsghdr *)rtm; 1448 (void)printf("if# %d, what: ", ifan->ifan_index); 1449 switch (ifan->ifan_what) { 1450 case IFAN_ARRIVAL: 1451 printf("arrival"); 1452 break; 1453 case IFAN_DEPARTURE: 1454 printf("departure"); 1455 break; 1456 default: 1457 printf("#%d", ifan->ifan_what); 1458 break; 1459 } 1460 printf("\n"); 1461 break; 1462 default: 1463 (void)printf("pid %d, seq %d, errno %d, flags: ", 1464 rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 1465 bprintf(stdout, rtm->rtm_flags, routeflags); 1466 pmsg_common(rtm); 1467 } 1468 } 1469 1470 #ifndef SMALL 1471 static int 1472 print_getmsg(struct rt_msghdr *rtm, int msglen, struct sou *soup) 1473 { 1474 struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *ifa = NULL, *mpls = NULL; 1475 struct sockaddr_dl *ifp = NULL; 1476 struct sockaddr *sa; 1477 char *cp; 1478 int i; 1479 1480 if (! shortoutput) { 1481 (void)printf(" route to: %s\n", 1482 routename(&soup->so_dst->sa, nflag)); 1483 } 1484 if (rtm->rtm_version != RTM_VERSION) { 1485 warnx("routing message version %d not understood", 1486 rtm->rtm_version); 1487 return 1; 1488 } 1489 if (rtm->rtm_msglen > msglen) { 1490 warnx("message length mismatch, in packet %d, returned %d", 1491 rtm->rtm_msglen, msglen); 1492 } 1493 if (rtm->rtm_errno) { 1494 warnx("RTM_GET: %s (errno %d)", 1495 strerror(rtm->rtm_errno), rtm->rtm_errno); 1496 return 1; 1497 } 1498 cp = ((char *)(rtm + 1)); 1499 if (rtm->rtm_addrs) 1500 for (i = 1; i; i <<= 1) 1501 if (i & rtm->rtm_addrs) { 1502 sa = (struct sockaddr *)cp; 1503 switch (i) { 1504 case RTA_DST: 1505 dst = sa; 1506 break; 1507 case RTA_GATEWAY: 1508 gate = sa; 1509 break; 1510 case RTA_NETMASK: 1511 mask = sa; 1512 break; 1513 case RTA_IFP: 1514 if (sa->sa_family == AF_LINK && 1515 ((struct sockaddr_dl *)sa)->sdl_nlen) 1516 ifp = (struct sockaddr_dl *)sa; 1517 break; 1518 case RTA_IFA: 1519 ifa = sa; 1520 break; 1521 case RTA_TAG: 1522 mpls = sa; 1523 break; 1524 } 1525 RT_ADVANCE(cp, sa); 1526 } 1527 if (dst && mask) 1528 mask->sa_family = dst->sa_family; /* XXX */ 1529 if (dst && ! shortoutput) 1530 (void)printf("destination: %s\n", 1531 routename(dst, nflag)); 1532 if (mask && ! shortoutput) { 1533 int savenflag = nflag; 1534 1535 nflag = RT_NFLAG; 1536 (void)printf(" mask: %s\n", 1537 routename(mask, nflag)); 1538 nflag = savenflag; 1539 } 1540 if (gate && rtm->rtm_flags & RTF_GATEWAY) { 1541 const char *name; 1542 1543 name = routename(gate, nflag); 1544 if (shortoutput) { 1545 if (*name == '\0') 1546 return 1; 1547 (void)printf("%s\n", name); 1548 } else 1549 (void)printf(" gateway: %s\n", name); 1550 } 1551 if (mpls) { 1552 const char *name; 1553 name = routename(mpls, nflag); 1554 if(shortoutput) { 1555 if (*name == '\0') 1556 return 1; 1557 printf("%s\n", name); 1558 } else 1559 printf(" Tag: %s\n", name); 1560 } 1561 1562 if (ifa && ! shortoutput) 1563 (void)printf(" local addr: %s\n", 1564 routename(ifa, nflag)); 1565 if (ifp && ! shortoutput) 1566 (void)printf(" interface: %.*s\n", 1567 ifp->sdl_nlen, ifp->sdl_data); 1568 if (! shortoutput) { 1569 (void)printf(" flags: "); 1570 bprintf(stdout, rtm->rtm_flags, routeflags); 1571 } 1572 1573 #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') 1574 #define msec(u) (((u) + 500) / 1000) /* usec to msec */ 1575 1576 if (! shortoutput) { 1577 (void)printf("\n%s\n", "\ 1578 recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire"); 1579 printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); 1580 printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); 1581 printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); 1582 printf("%8"PRId64"%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); 1583 printf("%8"PRId64"%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR)); 1584 printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT)); 1585 printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); 1586 if (rtm->rtm_rmx.rmx_expire) 1587 rtm->rtm_rmx.rmx_expire -= time(0); 1588 printf("%8"PRId64"%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); 1589 } 1590 #undef lock 1591 #undef msec 1592 #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD) 1593 1594 if (shortoutput) 1595 return (rtm->rtm_addrs & RTF_GATEWAY) == 0; 1596 else if (verbose) 1597 pmsg_common(rtm); 1598 else if (rtm->rtm_addrs &~ RTA_IGN) { 1599 (void)printf("sockaddrs: "); 1600 bprintf(stdout, rtm->rtm_addrs, addrnames); 1601 putchar('\n'); 1602 } 1603 return 0; 1604 #undef RTA_IGN 1605 } 1606 #endif /* SMALL */ 1607 1608 void 1609 pmsg_common(struct rt_msghdr *rtm) 1610 { 1611 (void)printf("\nlocks: "); 1612 bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames); 1613 (void)printf(" inits: "); 1614 bprintf(stdout, rtm->rtm_inits, metricnames); 1615 pmsg_addrs((char *)(rtm + 1), rtm->rtm_addrs); 1616 } 1617 1618 static void 1619 extract_addrs(const char *cp, int addrs, const struct sockaddr *sa[], int *nmfp) 1620 { 1621 int i, nmf = -1; 1622 1623 for (i = 0; i < RTAX_MAX; i++) { 1624 if ((1 << i) & addrs) { 1625 sa[i] = (const struct sockaddr *)cp; 1626 if ((i == RTAX_DST || i == RTAX_IFA) && 1627 nmf == -1) 1628 nmf = sa[i]->sa_family; 1629 RT_ADVANCE(cp, sa[i]); 1630 } else 1631 sa[i] = NULL; 1632 } 1633 1634 if (nmfp != NULL) 1635 *nmfp = nmf; 1636 } 1637 1638 static void 1639 pmsg_addrs(const char *cp, int addrs) 1640 { 1641 const struct sockaddr *sa[RTAX_MAX]; 1642 int i, nmf; 1643 1644 if (addrs != 0) { 1645 (void)printf("\nsockaddrs: "); 1646 bprintf(stdout, addrs, addrnames); 1647 (void)putchar('\n'); 1648 extract_addrs(cp, addrs, sa, &nmf); 1649 for (i = 0; i < RTAX_MAX; i++) { 1650 if (sa[i] == NULL) 1651 continue; 1652 1653 if (i == RTAX_NETMASK && sa[i]->sa_len) 1654 (void)printf(" %s", 1655 netmask_string(sa[i], -1, nmf)); 1656 else 1657 (void)printf(" %s", 1658 routename(sa[i], nflag)); 1659 } 1660 } 1661 (void)putchar('\n'); 1662 (void)fflush(stdout); 1663 } 1664 1665 static void 1666 bprintf(FILE *fp, int b, const char *f) 1667 { 1668 char buf[1024]; 1669 1670 snprintb(buf, sizeof(buf), f, b); 1671 fputs(buf, fp); 1672 } 1673 1674 int 1675 keyword(const char *cp) 1676 { 1677 struct keytab *kt = keywords; 1678 1679 while (kt->kt_cp && strcmp(kt->kt_cp, cp)) 1680 kt++; 1681 return kt->kt_i; 1682 } 1683 1684 static void 1685 sodump(sup su, const char *which) 1686 { 1687 #ifdef INET6 1688 char ntop_buf[NI_MAXHOST]; 1689 #endif 1690 1691 switch (su->sa.sa_family) { 1692 case AF_INET: 1693 (void)printf("%s: inet %s; ", 1694 which, inet_ntoa(su->sin.sin_addr)); 1695 break; 1696 #ifndef SMALL 1697 case AF_APPLETALK: 1698 (void)printf("%s: atalk %d.%d; ", 1699 which, su->sat.sat_addr.s_net, su->sat.sat_addr.s_node); 1700 break; 1701 #endif 1702 case AF_LINK: 1703 (void)printf("%s: link %s; ", 1704 which, link_ntoa(&su->sdl)); 1705 break; 1706 #ifdef INET6 1707 case AF_INET6: 1708 (void)printf("%s: inet6 %s; ", 1709 which, inet_ntop(AF_INET6, &su->sin6.sin6_addr, 1710 ntop_buf, sizeof(ntop_buf))); 1711 break; 1712 #endif 1713 #ifndef SMALL 1714 case AF_MPLS: 1715 { 1716 union mpls_shim ms; 1717 const union mpls_shim *pms; 1718 int psize = sizeof(struct sockaddr_mpls); 1719 1720 ms.s_addr = ntohl(su->smpls.smpls_addr.s_addr); 1721 printf("%s: mpls %u; ", 1722 which, ms.shim.label); 1723 1724 pms = &su->smpls.smpls_addr; 1725 while(psize < su->smpls.smpls_len) { 1726 pms++; 1727 ms.s_addr = ntohl(pms->s_addr); 1728 printf("%u; ", ms.shim.label); 1729 psize += sizeof(ms); 1730 } 1731 break; 1732 } 1733 #endif /* SMALL */ 1734 default: 1735 (void)printf("%s: (%d) %s; ", 1736 which, su->sa.sa_family, any_ntoa(&su->sa)); 1737 } 1738 (void)fflush(stdout); 1739 } 1740 1741 /* States*/ 1742 #define VIRGIN 0 1743 #define GOTONE 1 1744 #define GOTTWO 2 1745 /* Inputs */ 1746 #define DIGIT (4*0) 1747 #define END (4*1) 1748 #define DELIM (4*2) 1749 1750 static void 1751 sockaddr(const char *addr, struct sockaddr *sa) 1752 { 1753 char *cp = (char *)sa; 1754 int size = sa->sa_len; 1755 char *cplim = cp + size; 1756 int byte = 0, state = VIRGIN, new = 0; 1757 1758 (void)memset(cp, 0, size); 1759 cp++; 1760 do { 1761 if ((*addr >= '0') && (*addr <= '9')) { 1762 new = *addr - '0'; 1763 } else if ((*addr >= 'a') && (*addr <= 'f')) { 1764 new = *addr - 'a' + 10; 1765 } else if ((*addr >= 'A') && (*addr <= 'F')) { 1766 new = *addr - 'A' + 10; 1767 } else if (*addr == 0) 1768 state |= END; 1769 else 1770 state |= DELIM; 1771 addr++; 1772 switch (state /* | INPUT */) { 1773 case GOTTWO | DIGIT: 1774 *cp++ = byte; /*FALLTHROUGH*/ 1775 case VIRGIN | DIGIT: 1776 state = GOTONE; byte = new; continue; 1777 case GOTONE | DIGIT: 1778 state = GOTTWO; byte = new + (byte << 4); continue; 1779 default: /* | DELIM */ 1780 state = VIRGIN; *cp++ = byte; byte = 0; continue; 1781 case GOTONE | END: 1782 case GOTTWO | END: 1783 *cp++ = byte; /* FALLTHROUGH */ 1784 case VIRGIN | END: 1785 break; 1786 } 1787 break; 1788 } while (cp < cplim); 1789 sa->sa_len = cp - (char *)sa; 1790 } 1791