1 /* $OpenBSD: route.c,v 1.248 2020/07/07 14:53:36 yasuoka Exp $ */ 2 /* $NetBSD: route.c,v 1.16 1996/04/15 18:27:05 cgd Exp $ */ 3 4 /* 5 * Copyright (c) 1983, 1989, 1991, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/socket.h> 34 #include <sys/sysctl.h> 35 36 #include <net/if.h> 37 #include <net/if_dl.h> 38 #include <net/if_media.h> 39 #include <net/if_types.h> 40 #include <net/route.h> 41 #include <netinet/in.h> 42 #include <netmpls/mpls.h> 43 44 #ifdef BFD 45 #include <sys/time.h> 46 #include <net/bfd.h> 47 #endif 48 49 #include <arpa/inet.h> 50 #include <netdb.h> 51 52 #include <errno.h> 53 #include <fcntl.h> 54 #include <unistd.h> 55 #include <limits.h> 56 #include <stdio.h> 57 #include <ctype.h> 58 #include <stddef.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include <time.h> 62 #include <paths.h> 63 #include <err.h> 64 65 #include "keywords.h" 66 #include "show.h" 67 68 const struct if_status_description 69 if_status_descriptions[] = LINK_STATE_DESCRIPTIONS; 70 71 union sockunion so_dst, so_gate, so_mask, so_ifa, so_ifp, so_src, so_label; 72 73 typedef union sockunion *sup; 74 pid_t pid; 75 int rtm_addrs, s; 76 int forcehost, forcenet, Fflag, nflag, qflag, tflag, Tflag; 77 int iflag, verbose, aflen = sizeof(struct sockaddr_in); 78 int locking, lockrest, debugonly; 79 u_long mpls_flags = MPLS_OP_LOCAL; 80 u_long rtm_inits; 81 uid_t uid; 82 u_int tableid; 83 84 struct rt_metrics rt_metrics; 85 86 int flushroutes(int, char **); 87 int newroute(int, char **); 88 int show(int, char *[]); 89 int keycmp(const void *, const void *); 90 int keyword(char *); 91 void monitor(int, char *[]); 92 int prefixlen(int, char *); 93 void sockaddr(char *, struct sockaddr *); 94 void sodump(sup, char *); 95 char *priorityname(uint8_t); 96 uint8_t getpriority(char *); 97 void print_getmsg(struct rt_msghdr *, int); 98 #ifdef BFD 99 const char *bfd_state(unsigned int); 100 const char *bfd_diag(unsigned int); 101 const char *bfd_calc_uptime(time_t); 102 void print_bfdmsg(struct rt_msghdr *); 103 void print_sabfd(struct sockaddr_bfd *, int); 104 #endif 105 const char *get_linkstate(int, int); 106 void print_rtmsg(struct rt_msghdr *, int); 107 void pmsg_common(struct rt_msghdr *); 108 void pmsg_addrs(char *, int); 109 void bprintf(FILE *, int, char *); 110 int getaddr(int, int, char *, struct hostent **); 111 void getmplslabel(char *, int); 112 int rtmsg(int, int, int, uint8_t); 113 __dead void usage(char *); 114 void set_metric(char *, int); 115 void inet_makenetandmask(u_int32_t, struct sockaddr_in *, int); 116 void getlabel(char *); 117 int gettable(const char *); 118 int rdomain(int, char **); 119 void print_rtdns(struct sockaddr_rtdns *); 120 void print_rtstatic(struct sockaddr_rtstatic *); 121 void print_rtsearch(struct sockaddr_rtsearch *); 122 void print_80211info(struct if_ieee80211_msghdr *); 123 124 __dead void 125 usage(char *cp) 126 { 127 extern char *__progname; 128 129 if (cp) 130 warnx("botched keyword: %s", cp); 131 fprintf(stderr, 132 "usage: %s [-dnqtv] [-T rtable] command [[modifiers] args]\n", 133 __progname); 134 fprintf(stderr, 135 "commands: add, change, delete, exec, flush, get, monitor, show\n"); 136 exit(1); 137 } 138 139 #define ROUNDUP(a) \ 140 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 141 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 142 143 int 144 main(int argc, char **argv) 145 { 146 unsigned int filter = 0; 147 int ch; 148 int rval = 0; 149 int kw; 150 int Terr = 0; 151 int af = AF_UNSPEC; 152 u_int rtable_any = RTABLE_ANY; 153 154 if (argc < 2) 155 usage(NULL); 156 157 tableid = getrtable(); 158 while ((ch = getopt(argc, argv, "dnqtT:v")) != -1) 159 switch (ch) { 160 case 'n': 161 nflag = 1; 162 break; 163 case 'q': 164 qflag = 1; 165 break; 166 case 'v': 167 verbose = 1; 168 break; 169 case 't': 170 tflag = 1; 171 break; 172 case 'T': 173 Terr = gettable(optarg); 174 Tflag = 1; 175 break; 176 case 'd': 177 debugonly = 1; 178 break; 179 default: 180 usage(NULL); 181 /* NOTREACHED */ 182 } 183 argc -= optind; 184 argv += optind; 185 186 pid = getpid(); 187 uid = geteuid(); 188 if (*argv == NULL) 189 usage(NULL); 190 191 kw = keyword(*argv); 192 if (Tflag && Terr != 0 && kw != K_ADD) { 193 errno = Terr; 194 err(1, "routing table %u", tableid); 195 } 196 if (kw == K_EXEC) 197 exit(rdomain(argc - 1, argv + 1)); 198 199 if (kw == K_MONITOR) { 200 while (--argc > 0) { 201 if (**(++argv)== '-') 202 switch (keyword(*argv + 1)) { 203 case K_INET: 204 af = AF_INET; 205 break; 206 case K_INET6: 207 af = AF_INET6; 208 break; 209 case K_IFACE: 210 case K_INTERFACE: 211 filter = ROUTE_FILTER(RTM_IFINFO) | 212 ROUTE_FILTER(RTM_IFANNOUNCE) | 213 ROUTE_FILTER(RTM_80211INFO); 214 break; 215 default: 216 usage(*argv); 217 /* NOTREACHED */ 218 } 219 else 220 usage(*argv); 221 } 222 } 223 224 if (tflag) 225 s = open(_PATH_DEVNULL, O_WRONLY); 226 else 227 s = socket(AF_ROUTE, SOCK_RAW, af); 228 if (s == -1) 229 err(1, "socket"); 230 231 if (filter != 0) { 232 if (setsockopt(s, AF_ROUTE, ROUTE_MSGFILTER, &filter, 233 sizeof(filter)) == -1) 234 err(1, "setsockopt(ROUTE_MSGFILTER)"); 235 } 236 237 if (!tflag) { 238 /* force socket onto table user requested */ 239 if (Tflag == 1 && Terr == 0) { 240 if (setsockopt(s, AF_ROUTE, ROUTE_TABLEFILTER, 241 &tableid, sizeof(tableid)) == -1) 242 err(1, "setsockopt(ROUTE_TABLEFILTER)"); 243 } else { 244 if (setsockopt(s, AF_ROUTE, ROUTE_TABLEFILTER, 245 &rtable_any, sizeof(tableid)) == -1) 246 err(1, "setsockopt(ROUTE_TABLEFILTER)"); 247 } 248 } 249 250 if (pledge("stdio dns route", NULL) == -1) 251 err(1, "pledge"); 252 253 switch (kw) { 254 case K_SHOW: 255 uid = 0; 256 exit(show(argc, argv)); 257 break; 258 case K_FLUSH: 259 exit(flushroutes(argc, argv)); 260 break; 261 } 262 263 if (pledge("stdio dns", NULL) == -1) 264 err(1, "pledge"); 265 266 switch (kw) { 267 case K_GET: 268 uid = 0; 269 /* FALLTHROUGH */ 270 case K_CHANGE: 271 case K_ADD: 272 case K_DEL: 273 case K_DELETE: 274 rval = newroute(argc, argv); 275 break; 276 case K_MONITOR: 277 monitor(argc, argv); 278 break; 279 default: 280 usage(*argv); 281 /* NOTREACHED */ 282 } 283 exit(rval); 284 } 285 286 /* 287 * Purge all entries in the routing tables not 288 * associated with network interfaces. 289 */ 290 int 291 flushroutes(int argc, char **argv) 292 { 293 size_t needed; 294 int mib[7], mcnt, rlen, seqno, af = AF_UNSPEC; 295 char *buf = NULL, *next, *lim = NULL; 296 struct rt_msghdr *rtm; 297 struct sockaddr *sa; 298 uint8_t prio = 0; 299 unsigned int ifindex = 0; 300 301 if (uid) 302 errx(1, "must be root to alter routing table"); 303 shutdown(s, SHUT_RD); /* Don't want to read back our messages */ 304 while (--argc > 0) { 305 if (**(++argv) == '-') 306 switch (keyword(*argv + 1)) { 307 case K_INET: 308 af = AF_INET; 309 break; 310 case K_INET6: 311 af = AF_INET6; 312 break; 313 case K_LINK: 314 af = AF_LINK; 315 break; 316 case K_MPLS: 317 af = AF_MPLS; 318 break; 319 case K_IFACE: 320 case K_INTERFACE: 321 if (!--argc) 322 usage(1+*argv); 323 ifindex = if_nametoindex(*++argv); 324 if (ifindex == 0) 325 errx(1, "no such interface %s", *argv); 326 break; 327 case K_PRIORITY: 328 if (!--argc) 329 usage(1+*argv); 330 prio = getpriority(*++argv); 331 break; 332 default: 333 usage(*argv); 334 /* NOTREACHED */ 335 } 336 else 337 usage(*argv); 338 } 339 mib[0] = CTL_NET; 340 mib[1] = PF_ROUTE; 341 mib[2] = 0; /* protocol */ 342 mib[3] = af; 343 mib[4] = NET_RT_DUMP; 344 mib[5] = prio; 345 mib[6] = tableid; 346 mcnt = 7; 347 348 needed = get_sysctl(mib, mcnt, &buf); 349 lim = buf + needed; 350 351 if (pledge("stdio dns", NULL) == -1) 352 err(1, "pledge"); 353 354 if (verbose) { 355 printf("Examining routing table from sysctl\n"); 356 if (af) 357 printf("(address family %s)\n", (*argv + 1)); 358 } 359 if (buf == NULL) 360 return (1); 361 362 seqno = 0; 363 for (next = buf; next < lim; next += rtm->rtm_msglen) { 364 rtm = (struct rt_msghdr *)next; 365 if (rtm->rtm_version != RTM_VERSION) 366 continue; 367 if (verbose) 368 print_rtmsg(rtm, rtm->rtm_msglen); 369 if ((rtm->rtm_flags & (RTF_GATEWAY|RTF_STATIC|RTF_LLINFO)) == 0) 370 continue; 371 if ((rtm->rtm_flags & (RTF_LOCAL|RTF_BROADCAST)) != 0) 372 continue; 373 sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); 374 if (ifindex && rtm->rtm_index != ifindex) 375 continue; 376 if (sa->sa_family == AF_KEY) 377 continue; /* Don't flush SPD */ 378 if (debugonly) 379 continue; 380 rtm->rtm_type = RTM_DELETE; 381 rtm->rtm_seq = seqno; 382 rtm->rtm_tableid = tableid; 383 rlen = write(s, next, rtm->rtm_msglen); 384 if (rlen < (int)rtm->rtm_msglen) { 385 warn("write to routing socket"); 386 printf("got only %d for rlen\n", rlen); 387 break; 388 } 389 seqno++; 390 if (qflag) 391 continue; 392 if (verbose) 393 print_rtmsg(rtm, rlen); 394 else { 395 struct sockaddr *mask, *rti_info[RTAX_MAX]; 396 397 sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); 398 399 get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 400 401 sa = rti_info[RTAX_DST]; 402 mask = rti_info[RTAX_NETMASK]; 403 404 p_sockaddr(sa, mask, rtm->rtm_flags, 20); 405 p_sockaddr(rti_info[RTAX_GATEWAY], NULL, RTF_HOST, 20); 406 printf("done\n"); 407 } 408 } 409 free(buf); 410 return (0); 411 } 412 413 void 414 set_metric(char *value, int key) 415 { 416 long long relative_expire; 417 const char *errstr; 418 int flag = 0; 419 420 switch (key) { 421 case K_MTU: 422 rt_metrics.rmx_mtu = strtonum(value, 0, UINT_MAX, &errstr); 423 if (errstr) 424 errx(1, "set_metric mtu: %s is %s", value, errstr); 425 flag = RTV_MTU; 426 break; 427 case K_EXPIRE: 428 relative_expire = strtonum(value, 0, INT_MAX, &errstr); 429 if (errstr) 430 errx(1, "set_metric expire: %s is %s", value, errstr); 431 rt_metrics.rmx_expire = relative_expire ? 432 relative_expire + time(NULL) : 0; 433 flag = RTV_EXPIRE; 434 break; 435 case K_HOPCOUNT: 436 case K_RECVPIPE: 437 case K_SENDPIPE: 438 case K_SSTHRESH: 439 case K_RTT: 440 case K_RTTVAR: 441 /* no longer used, only for compatibility */ 442 return; 443 default: 444 errx(1, "king bula sez: set_metric with invalid key"); 445 } 446 rtm_inits |= flag; 447 if (lockrest || locking) 448 rt_metrics.rmx_locks |= flag; 449 if (locking) 450 locking = 0; 451 } 452 453 int 454 newroute(int argc, char **argv) 455 { 456 char *cmd, *dest = "", *gateway = "", *error; 457 int ishost = 0, ret = 0, attempts, oerrno, flags = RTF_STATIC; 458 int fmask = 0, af = AF_UNSPEC; 459 int key; 460 uint8_t prio = 0; 461 struct hostent *hp = NULL; 462 int sawdest = 0; 463 464 if (uid) 465 errx(1, "must be root to alter routing table"); 466 cmd = argv[0]; 467 if (*cmd != 'g') 468 shutdown(s, SHUT_RD); /* Don't want to read back our messages */ 469 while (--argc > 0) { 470 if (**(++argv)== '-') { 471 switch (key = keyword(1 + *argv)) { 472 case K_LINK: 473 af = AF_LINK; 474 aflen = sizeof(struct sockaddr_dl); 475 break; 476 case K_INET: 477 af = AF_INET; 478 aflen = sizeof(struct sockaddr_in); 479 break; 480 case K_INET6: 481 af = AF_INET6; 482 aflen = sizeof(struct sockaddr_in6); 483 break; 484 case K_SA: 485 af = PF_ROUTE; 486 aflen = sizeof(struct sockaddr_storage) - 1; 487 break; 488 case K_MPLS: 489 af = AF_MPLS; 490 aflen = sizeof(struct sockaddr_mpls); 491 fmask |= RTF_MPLS; 492 break; 493 case K_MPLSLABEL: 494 if (!--argc) 495 usage(1+*argv); 496 if (af != AF_INET && af != AF_INET6) 497 errx(1, "-mplslabel requires " 498 "-inet or -inet6"); 499 getmplslabel(*++argv, 0); 500 mpls_flags = MPLS_OP_PUSH; 501 flags |= RTF_MPLS; 502 break; 503 case K_IN: 504 if (!--argc) 505 usage(1+*argv); 506 if (af != AF_MPLS) 507 errx(1, "-in requires -mpls"); 508 getmplslabel(*++argv, 1); 509 break; 510 case K_OUT: 511 if (!--argc) 512 usage(1+*argv); 513 if (af != AF_MPLS) 514 errx(1, "-out requires -mpls"); 515 if (mpls_flags == MPLS_OP_LOCAL) 516 errx(1, "-out requires -push, -pop, " 517 "-swap"); 518 getmplslabel(*++argv, 0); 519 flags |= RTF_MPLS; 520 break; 521 case K_POP: 522 if (af != AF_MPLS) 523 errx(1, "-pop requires -mpls"); 524 mpls_flags = MPLS_OP_POP; 525 break; 526 case K_PUSH: 527 if (af != AF_MPLS) 528 errx(1, "-push requires -mpls"); 529 mpls_flags = MPLS_OP_PUSH; 530 break; 531 case K_SWAP: 532 if (af != AF_MPLS) 533 errx(1, "-swap requires -mpls"); 534 mpls_flags = MPLS_OP_SWAP; 535 break; 536 case K_IFACE: 537 case K_INTERFACE: 538 iflag++; 539 break; 540 case K_NOSTATIC: 541 flags &= ~RTF_STATIC; 542 break; 543 case K_LLINFO: 544 flags |= RTF_LLINFO; 545 break; 546 case K_LOCK: 547 locking = 1; 548 break; 549 case K_LOCKREST: 550 lockrest = 1; 551 break; 552 case K_HOST: 553 forcehost++; 554 break; 555 case K_REJECT: 556 flags |= RTF_REJECT; 557 break; 558 case K_BLACKHOLE: 559 flags |= RTF_BLACKHOLE; 560 break; 561 case K_PROTO1: 562 flags |= RTF_PROTO1; 563 break; 564 case K_PROTO2: 565 flags |= RTF_PROTO2; 566 break; 567 case K_CLONING: 568 flags |= RTF_CLONING; 569 break; 570 case K_STATIC: 571 flags |= RTF_STATIC; 572 break; 573 case K_IFA: 574 if (!--argc) 575 usage(1+*argv); 576 getaddr(RTA_IFA, af, *++argv, NULL); 577 break; 578 case K_IFP: 579 if (!--argc) 580 usage(1+*argv); 581 getaddr(RTA_IFP, AF_LINK, *++argv, NULL); 582 break; 583 case K_GATEWAY: 584 if (!--argc) 585 usage(1+*argv); 586 getaddr(RTA_GATEWAY, af, *++argv, NULL); 587 gateway = *argv; 588 break; 589 case K_DST: 590 if (!--argc) 591 usage(1+*argv); 592 ishost = getaddr(RTA_DST, af, *++argv, &hp); 593 dest = *argv; 594 sawdest = 1; 595 break; 596 case K_LABEL: 597 if (!--argc) 598 usage(1+*argv); 599 getlabel(*++argv); 600 break; 601 case K_NETMASK: 602 if (!sawdest) 603 errx(1, "-netmask must follow " 604 "destination parameter"); 605 if (!--argc) 606 usage(1+*argv); 607 getaddr(RTA_NETMASK, af, *++argv, NULL); 608 /* FALLTHROUGH */ 609 case K_NET: 610 forcenet++; 611 break; 612 case K_PREFIXLEN: 613 if (!sawdest) 614 errx(1, "-prefixlen must follow " 615 "destination parameter"); 616 if (!--argc) 617 usage(1+*argv); 618 ishost = prefixlen(af, *++argv); 619 break; 620 case K_MPATH: 621 flags |= RTF_MPATH; 622 break; 623 case K_MTU: 624 case K_HOPCOUNT: 625 case K_EXPIRE: 626 case K_RECVPIPE: 627 case K_SENDPIPE: 628 case K_SSTHRESH: 629 case K_RTT: 630 case K_RTTVAR: 631 if (!--argc) 632 usage(1+*argv); 633 set_metric(*++argv, key); 634 break; 635 case K_PRIORITY: 636 if (!--argc) 637 usage(1+*argv); 638 prio = getpriority(*++argv); 639 break; 640 case K_BFD: 641 flags |= RTF_BFD; 642 fmask |= RTF_BFD; 643 break; 644 case K_NOBFD: 645 flags &= ~RTF_BFD; 646 fmask |= RTF_BFD; 647 break; 648 default: 649 usage(1+*argv); 650 /* NOTREACHED */ 651 } 652 } else { 653 if ((rtm_addrs & RTA_DST) == 0) { 654 dest = *argv; 655 sawdest = 1; 656 ishost = getaddr(RTA_DST, af, *argv, &hp); 657 } else if ((rtm_addrs & RTA_GATEWAY) == 0) { 658 gateway = *argv; 659 getaddr(RTA_GATEWAY, af, *argv, &hp); 660 } else 661 usage(NULL); 662 } 663 } 664 if (forcehost) 665 ishost = 1; 666 if (forcenet) 667 ishost = 0; 668 if (forcenet && !(rtm_addrs & RTA_NETMASK)) 669 errx(1, "netmask missing"); 670 flags |= RTF_UP; 671 if (ishost) 672 flags |= RTF_HOST; 673 if (iflag == 0) 674 flags |= RTF_GATEWAY; 675 for (attempts = 1; ; attempts++) { 676 errno = 0; 677 if ((ret = rtmsg(*cmd, flags, fmask, prio)) == 0) 678 break; 679 if (errno != ENETUNREACH && errno != ESRCH) 680 break; 681 if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) { 682 hp->h_addr_list++; 683 memcpy(&so_gate.sin.sin_addr, hp->h_addr_list[0], 684 hp->h_length); 685 } else 686 break; 687 } 688 oerrno = errno; 689 if (!qflag && (*cmd != 'g' || ret != 0)) { 690 printf("%s %s %s", cmd, ishost ? "host" : "net", dest); 691 if (*gateway) { 692 printf(": gateway %s", gateway); 693 if (attempts > 1 && ret == 0 && af == AF_INET) 694 printf(" (%s)", inet_ntoa(so_gate.sin.sin_addr)); 695 } 696 if (ret == 0) 697 printf("\n"); 698 if (ret != 0) { 699 switch (oerrno) { 700 case ESRCH: 701 error = "not in table"; 702 break; 703 case EBUSY: 704 error = "entry in use"; 705 break; 706 case ENOBUFS: 707 error = "routing table overflow"; 708 break; 709 default: 710 error = strerror(oerrno); 711 break; 712 } 713 printf(": %s\n", error); 714 } 715 } 716 return (ret != 0); 717 } 718 719 int 720 show(int argc, char *argv[]) 721 { 722 int af = AF_UNSPEC; 723 char prio = 0; 724 725 while (--argc > 0) { 726 if (**(++argv)== '-') 727 switch (keyword(*argv + 1)) { 728 case K_INET: 729 af = AF_INET; 730 break; 731 case K_INET6: 732 af = AF_INET6; 733 break; 734 case K_LINK: 735 af = AF_LINK; 736 break; 737 case K_MPLS: 738 af = AF_MPLS; 739 break; 740 case K_GATEWAY: 741 Fflag = 1; 742 break; 743 case K_LABEL: 744 if (!--argc) 745 usage(1+*argv); 746 getlabel(*++argv); 747 break; 748 case K_PRIORITY: 749 if (!--argc) 750 usage(1+*argv); 751 prio = getpriority(*++argv); 752 break; 753 default: 754 usage(*argv); 755 /* NOTREACHED */ 756 } 757 else 758 usage(*argv); 759 } 760 761 p_rttables(af, tableid, prio); 762 return (0); 763 } 764 765 void 766 inet_makenetandmask(u_int32_t net, struct sockaddr_in *sin, int bits) 767 { 768 u_int32_t mask; 769 770 rtm_addrs |= RTA_NETMASK; 771 if (bits == 0 && net == 0) 772 mask = 0; 773 else { 774 if (bits == 0) 775 bits = 32; 776 mask = 0xffffffff << (32 - bits); 777 net &= mask; 778 } 779 sin->sin_addr.s_addr = htonl(net); 780 sin = &so_mask.sin; 781 sin->sin_addr.s_addr = htonl(mask); 782 sin->sin_family = AF_INET; 783 sin->sin_len = sizeof(struct sockaddr_in); 784 } 785 786 /* 787 * Interpret an argument as a network address of some kind, 788 * returning 1 if a host address, 0 if a network address. 789 */ 790 int 791 getaddr(int which, int af, char *s, struct hostent **hpp) 792 { 793 sup su = NULL; 794 struct hostent *hp; 795 int aflength, afamily, bits; 796 797 if (af == AF_UNSPEC) { 798 if (strchr(s, ':') != NULL) { 799 af = AF_INET6; 800 aflen = sizeof(struct sockaddr_in6); 801 } else { 802 af = AF_INET; 803 aflen = sizeof(struct sockaddr_in); 804 } 805 } 806 /* local copy of len and af so we can change it */ 807 aflength = aflen; 808 afamily = af; 809 810 rtm_addrs |= which; 811 switch (which) { 812 case RTA_DST: 813 su = &so_dst; 814 break; 815 case RTA_GATEWAY: 816 su = &so_gate; 817 break; 818 case RTA_NETMASK: 819 su = &so_mask; 820 break; 821 case RTA_IFP: 822 su = &so_ifp; 823 aflength = sizeof(struct sockaddr_dl); 824 afamily = AF_LINK; 825 break; 826 case RTA_IFA: 827 su = &so_ifa; 828 break; 829 default: 830 errx(1, "internal error"); 831 /* NOTREACHED */ 832 } 833 su->sa.sa_len = aflength; 834 su->sa.sa_family = afamily; 835 836 if (strcmp(s, "default") == 0) { 837 switch (which) { 838 case RTA_DST: 839 forcenet++; 840 getaddr(RTA_NETMASK, af, s, NULL); 841 break; 842 case RTA_NETMASK: 843 su->sa.sa_len = 0; 844 } 845 return (0); 846 } 847 848 switch (afamily) { 849 case AF_INET6: 850 { 851 struct addrinfo hints, *res; 852 char buf[ 853 sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255:255:255:255/128") 854 ]; 855 char *sep; 856 int error; 857 858 if (strlcpy(buf, s, sizeof buf) >= sizeof buf) { 859 errx(1, "%s: bad value", s); 860 } 861 862 sep = strchr(buf, '/'); 863 if (sep != NULL) 864 *sep++ = '\0'; 865 memset(&hints, 0, sizeof(hints)); 866 hints.ai_family = afamily; /*AF_INET6*/ 867 hints.ai_flags = AI_NUMERICHOST; 868 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 869 error = getaddrinfo(buf, "0", &hints, &res); 870 if (error) { 871 hints.ai_flags = 0; 872 error = getaddrinfo(buf, "0", &hints, &res); 873 if (error) 874 errx(1, "%s: %s", s, gai_strerror(error)); 875 } 876 if (res->ai_next) 877 errx(1, "%s: resolved to multiple values", s); 878 memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6)); 879 freeaddrinfo(res); 880 if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) || 881 IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr) || 882 IN6_IS_ADDR_MC_INTFACELOCAL(&su->sin6.sin6_addr)) && 883 su->sin6.sin6_scope_id) { 884 *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] = 885 htons(su->sin6.sin6_scope_id); 886 su->sin6.sin6_scope_id = 0; 887 } 888 if (hints.ai_flags == AI_NUMERICHOST) { 889 if (which == RTA_DST) { 890 if (sep == NULL && su->sin6.sin6_scope_id == 0 && 891 IN6_IS_ADDR_UNSPECIFIED(&su->sin6.sin6_addr)) 892 sep = "0"; 893 if (sep == NULL || prefixlen(AF_INET6, sep)) 894 return (1); 895 } 896 return (0); 897 } else 898 return (1); 899 } 900 901 case AF_LINK: 902 su->sdl.sdl_index = if_nametoindex(s); 903 memset(&su->sdl.sdl_data, 0, sizeof(su->sdl.sdl_data)); 904 return (1); 905 case AF_MPLS: 906 errx(1, "mpls labels require -in or -out switch"); 907 case PF_ROUTE: 908 su->sa.sa_len = sizeof(struct sockaddr_storage) - 1; 909 sockaddr(s, &su->sa); 910 return (1); 911 912 case AF_INET: 913 if (hpp != NULL) 914 *hpp = NULL; 915 if (which == RTA_DST && !forcehost) { 916 bits = inet_net_pton(AF_INET, s, &su->sin.sin_addr, 917 sizeof(su->sin.sin_addr)); 918 if (bits == 32) 919 return (1); 920 if (bits >= 0) { 921 inet_makenetandmask(ntohl( 922 su->sin.sin_addr.s_addr), 923 &su->sin, bits); 924 return (0); 925 } 926 } else if (which != RTA_DST || !forcenet) 927 if (inet_pton(AF_INET, s, &su->sin.sin_addr) == 1) 928 return (1); 929 hp = gethostbyname(s); 930 if (hp == NULL) 931 errx(1, "%s: bad address", s); 932 if (hpp != NULL) 933 *hpp = hp; 934 su->sin.sin_addr = *(struct in_addr *)hp->h_addr; 935 return (1); 936 937 default: 938 errx(1, "%d: bad address family", afamily); 939 /* NOTREACHED */ 940 } 941 } 942 943 void 944 getmplslabel(char *s, int in) 945 { 946 sup su = NULL; 947 const char *errstr; 948 u_int32_t label; 949 950 label = strtonum(s, 0, MPLS_LABEL_MAX, &errstr); 951 if (errstr) 952 errx(1, "bad label: %s is %s", s, errstr); 953 if (in) { 954 rtm_addrs |= RTA_DST; 955 su = &so_dst; 956 su->smpls.smpls_label = htonl(label << MPLS_LABEL_OFFSET); 957 } else { 958 rtm_addrs |= RTA_SRC; 959 su = &so_src; 960 su->smpls.smpls_label = htonl(label << MPLS_LABEL_OFFSET); 961 } 962 963 su->sa.sa_len = sizeof(struct sockaddr_mpls); 964 su->sa.sa_family = AF_MPLS; 965 } 966 967 int 968 prefixlen(int af, char *s) 969 { 970 const char *errstr; 971 int len, q, r; 972 int max; 973 974 switch (af) { 975 case AF_INET: 976 max = sizeof(struct in_addr) * 8; 977 break; 978 case AF_INET6: 979 max = sizeof(struct in6_addr) * 8; 980 break; 981 default: 982 errx(1, "prefixlen is not supported with af %d", af); 983 /* NOTREACHED */ 984 } 985 986 rtm_addrs |= RTA_NETMASK; 987 len = strtonum(s, 0, max, &errstr); 988 if (errstr) 989 errx(1, "prefixlen %s is %s", s, errstr); 990 991 q = len >> 3; 992 r = len & 7; 993 switch (af) { 994 case AF_INET: 995 memset(&so_mask, 0, sizeof(so_mask)); 996 so_mask.sin.sin_family = AF_INET; 997 so_mask.sin.sin_len = sizeof(struct sockaddr_in); 998 if (len != 0) 999 so_mask.sin.sin_addr.s_addr = htonl(0xffffffff << (32 - len)); 1000 break; 1001 case AF_INET6: 1002 so_mask.sin6.sin6_family = AF_INET6; 1003 so_mask.sin6.sin6_len = sizeof(struct sockaddr_in6); 1004 memset((void *)&so_mask.sin6.sin6_addr, 0, 1005 sizeof(so_mask.sin6.sin6_addr)); 1006 if (q > 0) 1007 memset((void *)&so_mask.sin6.sin6_addr, 0xff, q); 1008 if (r > 0) 1009 *((u_char *)&so_mask.sin6.sin6_addr + q) = 1010 (0xff00 >> r) & 0xff; 1011 break; 1012 } 1013 return (len == max); 1014 } 1015 1016 void 1017 monitor(int argc, char *argv[]) 1018 { 1019 int n; 1020 char msg[2048]; 1021 time_t now; 1022 1023 verbose = 1; 1024 for (;;) { 1025 if ((n = read(s, msg, sizeof(msg))) == -1) { 1026 if (errno == EINTR) 1027 continue; 1028 err(1, "read"); 1029 } 1030 now = time(NULL); 1031 printf("got message of size %d on %s", n, ctime(&now)); 1032 print_rtmsg((struct rt_msghdr *)msg, n); 1033 } 1034 } 1035 1036 struct { 1037 struct rt_msghdr m_rtm; 1038 char m_space[512]; 1039 } m_rtmsg; 1040 1041 int 1042 rtmsg(int cmd, int flags, int fmask, uint8_t prio) 1043 { 1044 static int seq; 1045 char *cp = m_rtmsg.m_space; 1046 int l; 1047 1048 #define NEXTADDR(w, u) \ 1049 if (rtm_addrs & (w)) { \ 1050 l = ROUNDUP(u.sa.sa_len); \ 1051 memcpy(cp, &(u), l); \ 1052 cp += l; \ 1053 if (verbose) \ 1054 sodump(&(u), #u); \ 1055 } 1056 1057 errno = 0; 1058 memset(&m_rtmsg, 0, sizeof(m_rtmsg)); 1059 if (cmd == 'a') 1060 cmd = RTM_ADD; 1061 else if (cmd == 'c') 1062 cmd = RTM_CHANGE; 1063 else if (cmd == 'g') { 1064 cmd = RTM_GET; 1065 if (so_ifp.sa.sa_family == AF_UNSPEC) { 1066 so_ifp.sa.sa_family = AF_LINK; 1067 so_ifp.sa.sa_len = sizeof(struct sockaddr_dl); 1068 rtm_addrs |= RTA_IFP; 1069 } 1070 } else 1071 cmd = RTM_DELETE; 1072 #define rtm m_rtmsg.m_rtm 1073 rtm.rtm_type = cmd; 1074 rtm.rtm_flags = flags; 1075 rtm.rtm_fmask = fmask; 1076 rtm.rtm_version = RTM_VERSION; 1077 rtm.rtm_seq = ++seq; 1078 rtm.rtm_addrs = rtm_addrs; 1079 rtm.rtm_rmx = rt_metrics; 1080 rtm.rtm_inits = rtm_inits; 1081 rtm.rtm_tableid = tableid; 1082 rtm.rtm_priority = prio; 1083 rtm.rtm_mpls = mpls_flags; 1084 rtm.rtm_hdrlen = sizeof(rtm); 1085 1086 /* store addresses in ascending order of RTA values */ 1087 NEXTADDR(RTA_DST, so_dst); 1088 NEXTADDR(RTA_GATEWAY, so_gate); 1089 NEXTADDR(RTA_NETMASK, so_mask); 1090 NEXTADDR(RTA_IFP, so_ifp); 1091 NEXTADDR(RTA_IFA, so_ifa); 1092 NEXTADDR(RTA_SRC, so_src); 1093 NEXTADDR(RTA_LABEL, so_label); 1094 rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 1095 if (verbose) 1096 print_rtmsg(&rtm, l); 1097 if (debugonly) 1098 return (0); 1099 if (write(s, &m_rtmsg, l) != l) { 1100 return (-1); 1101 } 1102 if (cmd == RTM_GET) { 1103 do { 1104 l = read(s, &m_rtmsg, sizeof(m_rtmsg)); 1105 } while (l > 0 && (rtm.rtm_version != RTM_VERSION || 1106 rtm.rtm_seq != seq || rtm.rtm_pid != pid)); 1107 if (l == -1) 1108 warn("read from routing socket"); 1109 else 1110 print_getmsg(&rtm, l); 1111 } 1112 #undef rtm 1113 return (0); 1114 } 1115 1116 char *msgtypes[] = { 1117 "", 1118 "RTM_ADD: Add Route", 1119 "RTM_DELETE: Delete Route", 1120 "RTM_CHANGE: Change Metrics or flags", 1121 "RTM_GET: Report Metrics", 1122 "RTM_LOSING: Kernel Suspects Partitioning", 1123 "RTM_REDIRECT: Told to use different route", 1124 "RTM_MISS: Lookup failed on this address", 1125 "", 1126 "", 1127 "", 1128 "RTM_RESOLVE: Route created by cloning", 1129 "RTM_NEWADDR: address being added to iface", 1130 "RTM_DELADDR: address being removed from iface", 1131 "RTM_IFINFO: iface status change", 1132 "RTM_IFANNOUNCE: iface arrival/departure", 1133 "RTM_DESYNC: route socket overflow", 1134 "RTM_INVALIDATE: invalidate cache of L2 route", 1135 "RTM_BFD: bidirectional forwarding detection", 1136 "RTM_PROPOSAL: config proposal", 1137 "RTM_CHGADDRATTR: address attributes being changed", 1138 "RTM_80211INFO: 802.11 iface status change" 1139 }; 1140 1141 char metricnames[] = 1142 "\011priority\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu"; 1143 char routeflags[] = 1144 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010XMASK_PRESENT" 1145 "\011CLONING\012MULTICAST\013LLINFO\014STATIC\015BLACKHOLE\016PROTO3\017PROTO2" 1146 "\020PROTO1\021CLONED\022CACHED\023MPATH\025MPLS\026LOCAL\027BROADCAST" 1147 "\030CONNECTED\031BFD"; 1148 char ifnetflags[] = 1149 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6STATICARP\7RUNNING\010NOARP\011PPROMISC" 1150 "\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2\020MULTICAST" 1151 "\23INET6_NOPRIVACY\24MPLS\25WOL\26AUTOCONF6\27INET6_NOSOII\30AUTOCONF4"; 1152 char addrnames[] = 1153 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC\012SRCMASK\013LABEL\014BFD\015DNS\016STATIC\017SEARCH"; 1154 1155 const char * 1156 get_linkstate(int mt, int link_state) 1157 { 1158 const struct if_status_description *p; 1159 static char buf[8]; 1160 1161 for (p = if_status_descriptions; p->ifs_string != NULL; p++) { 1162 if (LINK_STATE_DESC_MATCH(p, mt, link_state)) 1163 return (p->ifs_string); 1164 } 1165 snprintf(buf, sizeof(buf), "[#%d]", link_state); 1166 return buf; 1167 } 1168 1169 void 1170 print_rtmsg(struct rt_msghdr *rtm, int msglen) 1171 { 1172 long long relative_expire; 1173 struct if_msghdr *ifm; 1174 struct ifa_msghdr *ifam; 1175 struct if_announcemsghdr *ifan; 1176 char ifname[IF_NAMESIZE]; 1177 1178 if (verbose == 0) 1179 return; 1180 if (rtm->rtm_version != RTM_VERSION) { 1181 warnx("routing message version %u not understood", 1182 rtm->rtm_version); 1183 return; 1184 } 1185 if (rtm->rtm_type > 0 && 1186 rtm->rtm_type < sizeof(msgtypes)/sizeof(msgtypes[0])) 1187 printf("%s", msgtypes[rtm->rtm_type]); 1188 else 1189 printf("[rtm_type %u out of range]", rtm->rtm_type); 1190 1191 printf(": len %u", rtm->rtm_msglen); 1192 switch (rtm->rtm_type) { 1193 case RTM_DESYNC: 1194 printf("\n"); 1195 break; 1196 case RTM_IFINFO: 1197 ifm = (struct if_msghdr *)rtm; 1198 printf(", if# %u, ", ifm->ifm_index); 1199 if (if_indextoname(ifm->ifm_index, ifname) != NULL) 1200 printf("name %s, ", ifname); 1201 printf("link: %s, mtu: %u, flags:", 1202 get_linkstate(ifm->ifm_data.ifi_type, 1203 ifm->ifm_data.ifi_link_state), 1204 ifm->ifm_data.ifi_mtu); 1205 bprintf(stdout, ifm->ifm_flags | (ifm->ifm_xflags << 16), 1206 ifnetflags); 1207 pmsg_addrs((char *)ifm + ifm->ifm_hdrlen, ifm->ifm_addrs); 1208 break; 1209 case RTM_80211INFO: 1210 printf(", if# %u, ", rtm->rtm_index); 1211 if (if_indextoname(rtm->rtm_index, ifname) != NULL) 1212 printf("name %s, ", ifname); 1213 print_80211info((struct if_ieee80211_msghdr *)rtm); 1214 break; 1215 case RTM_NEWADDR: 1216 case RTM_DELADDR: 1217 case RTM_CHGADDRATTR: 1218 ifam = (struct ifa_msghdr *)rtm; 1219 printf(", if# %u, ", ifam->ifam_index); 1220 if (if_indextoname(ifam->ifam_index, ifname) != NULL) 1221 printf("name %s, ", ifname); 1222 printf("metric %d, flags:", ifam->ifam_metric); 1223 bprintf(stdout, ifam->ifam_flags, routeflags); 1224 pmsg_addrs((char *)ifam + ifam->ifam_hdrlen, ifam->ifam_addrs); 1225 break; 1226 case RTM_IFANNOUNCE: 1227 ifan = (struct if_announcemsghdr *)rtm; 1228 printf(", if# %u, name %s, what: ", 1229 ifan->ifan_index, ifan->ifan_name); 1230 switch (ifan->ifan_what) { 1231 case IFAN_ARRIVAL: 1232 printf("arrival"); 1233 break; 1234 case IFAN_DEPARTURE: 1235 printf("departure"); 1236 break; 1237 default: 1238 printf("#%u", ifan->ifan_what); 1239 break; 1240 } 1241 printf("\n"); 1242 break; 1243 #ifdef BFD 1244 case RTM_BFD: 1245 print_bfdmsg(rtm); 1246 break; 1247 #endif 1248 case RTM_PROPOSAL: 1249 printf(", source "); 1250 switch (rtm->rtm_priority) { 1251 case RTP_PROPOSAL_STATIC: 1252 printf("static"); 1253 break; 1254 case RTP_PROPOSAL_DHCLIENT: 1255 printf("dhcp"); 1256 break; 1257 case RTP_PROPOSAL_SLAAC: 1258 printf("slaac"); 1259 break; 1260 case RTP_PROPOSAL_UMB: 1261 printf("umb"); 1262 break; 1263 case RTP_PROPOSAL_SOLICIT: 1264 printf("solicit"); 1265 break; 1266 default: 1267 printf("unknown"); 1268 break; 1269 } 1270 printf(", table %u, if# %u, ", 1271 rtm->rtm_tableid, rtm->rtm_index); 1272 if (if_indextoname(rtm->rtm_index, ifname) != NULL) 1273 printf("name %s, ", ifname); 1274 printf("pid: %ld, seq %d, errno %d\nflags:", 1275 (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 1276 bprintf(stdout, rtm->rtm_flags, routeflags); 1277 printf("\nfmask:"); 1278 bprintf(stdout, rtm->rtm_fmask, routeflags); 1279 if (verbose) { 1280 #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') 1281 relative_expire = rtm->rtm_rmx.rmx_expire ? 1282 rtm->rtm_rmx.rmx_expire - time(NULL) : 0; 1283 printf("\nuse: %8llu mtu: %8u%c expire: %8lld%c", 1284 rtm->rtm_rmx.rmx_pksent, 1285 rtm->rtm_rmx.rmx_mtu, lock(MTU), 1286 relative_expire, lock(EXPIRE)); 1287 #undef lock 1288 } 1289 printf("\nlocks: "); 1290 bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames); 1291 printf(" inits: "); 1292 bprintf(stdout, rtm->rtm_inits, metricnames); 1293 pmsg_addrs(((char *)rtm + rtm->rtm_hdrlen), 1294 rtm->rtm_addrs & ~(RTA_STATIC | RTA_SEARCH | RTA_DNS)); 1295 1296 if(!(rtm->rtm_addrs & (RTA_STATIC | RTA_SEARCH | RTA_DNS))) 1297 break; 1298 1299 printf("proposals: "); 1300 bprintf(stdout, rtm->rtm_addrs & (RTA_STATIC | RTA_SEARCH | 1301 RTA_DNS), addrnames); 1302 putchar('\n'); 1303 1304 if (rtm->rtm_addrs & RTA_STATIC) { 1305 char *next = (char *)rtm + rtm->rtm_hdrlen; 1306 struct sockaddr *sa, *rti_info[RTAX_MAX]; 1307 struct sockaddr_rtstatic *rtstatic; 1308 sa = (struct sockaddr *)next; 1309 get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 1310 rtstatic = (struct sockaddr_rtstatic *) 1311 rti_info[RTAX_STATIC]; 1312 if (rtstatic != NULL) 1313 print_rtstatic(rtstatic); 1314 } 1315 1316 if (rtm->rtm_addrs & RTA_SEARCH) { 1317 char *next = (char *)rtm + rtm->rtm_hdrlen; 1318 struct sockaddr *sa, *rti_info[RTAX_MAX]; 1319 struct sockaddr_rtsearch *rtsearch; 1320 sa = (struct sockaddr *)next; 1321 get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 1322 rtsearch = (struct sockaddr_rtsearch *) 1323 rti_info[RTAX_SEARCH]; 1324 if (rtsearch != NULL) 1325 print_rtsearch(rtsearch); 1326 } 1327 1328 if (rtm->rtm_addrs & RTA_DNS) { 1329 char *next = (char *)rtm + rtm->rtm_hdrlen; 1330 struct sockaddr *sa, *rti_info[RTAX_MAX]; 1331 struct sockaddr_rtdns *rtdns; 1332 sa = (struct sockaddr *)next; 1333 get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 1334 rtdns = (struct sockaddr_rtdns *)rti_info[RTAX_DNS]; 1335 if (rtdns != NULL) 1336 print_rtdns(rtdns); 1337 } 1338 putchar('\n'); 1339 break; 1340 default: 1341 printf(", priority %u, table %u, if# %u, ", 1342 rtm->rtm_priority, rtm->rtm_tableid, rtm->rtm_index); 1343 if (if_indextoname(rtm->rtm_index, ifname) != NULL) 1344 printf("name %s, ", ifname); 1345 printf("pid: %ld, seq %d, errno %d\nflags:", 1346 (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 1347 bprintf(stdout, rtm->rtm_flags, routeflags); 1348 printf("\nfmask:"); 1349 bprintf(stdout, rtm->rtm_fmask, routeflags); 1350 if (verbose) { 1351 #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') 1352 relative_expire = rtm->rtm_rmx.rmx_expire ? 1353 rtm->rtm_rmx.rmx_expire - time(NULL) : 0; 1354 printf("\nuse: %8llu mtu: %8u%c expire: %8lld%c", 1355 rtm->rtm_rmx.rmx_pksent, 1356 rtm->rtm_rmx.rmx_mtu, lock(MTU), 1357 relative_expire, lock(EXPIRE)); 1358 #undef lock 1359 } 1360 pmsg_common(rtm); 1361 } 1362 } 1363 1364 char * 1365 priorityname(uint8_t prio) 1366 { 1367 switch (prio) { 1368 case RTP_NONE: 1369 return ("none"); 1370 case RTP_LOCAL: 1371 return ("local"); 1372 case RTP_CONNECTED: 1373 return ("connected"); 1374 case RTP_STATIC: 1375 return ("static"); 1376 case RTP_OSPF: 1377 return ("ospf"); 1378 case RTP_ISIS: 1379 return ("is-is"); 1380 case RTP_RIP: 1381 return ("rip"); 1382 case RTP_BGP: 1383 return ("bgp"); 1384 case RTP_DEFAULT: 1385 return ("default"); 1386 default: 1387 return (""); 1388 } 1389 } 1390 1391 uint8_t 1392 getpriority(char *priostr) 1393 { 1394 const char *errstr; 1395 uint8_t prio; 1396 1397 switch (keyword(priostr)) { 1398 case K_LOCAL: 1399 prio = RTP_LOCAL; 1400 break; 1401 case K_CONNECTED: 1402 prio = RTP_CONNECTED; 1403 break; 1404 case K_STATIC: 1405 prio = RTP_STATIC; 1406 break; 1407 case K_OSPF: 1408 prio = RTP_OSPF; 1409 break; 1410 case K_RIP: 1411 prio = RTP_RIP; 1412 break; 1413 case K_BGP: 1414 prio = RTP_BGP; 1415 break; 1416 default: 1417 prio = strtonum(priostr, -RTP_MAX, RTP_MAX, &errstr); 1418 if (errstr) 1419 errx(1, "priority is %s: %s", errstr, priostr); 1420 } 1421 1422 return (prio); 1423 } 1424 1425 void 1426 print_getmsg(struct rt_msghdr *rtm, int msglen) 1427 { 1428 long long relative_expire; 1429 struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *ifa = NULL; 1430 struct sockaddr_dl *ifp = NULL; 1431 struct sockaddr_rtlabel *sa_rl = NULL; 1432 #ifdef BFD 1433 struct sockaddr_bfd *sa_bfd = NULL; 1434 #endif 1435 struct sockaddr *mpls = NULL; 1436 struct sockaddr *sa; 1437 char *cp; 1438 int i; 1439 1440 printf(" route to: %s\n", routename(&so_dst.sa)); 1441 if (rtm->rtm_version != RTM_VERSION) { 1442 warnx("routing message version %u not understood", 1443 rtm->rtm_version); 1444 return; 1445 } 1446 if (rtm->rtm_msglen > msglen) 1447 warnx("message length mismatch, in packet %u, returned %d", 1448 rtm->rtm_msglen, msglen); 1449 if (rtm->rtm_errno) { 1450 warnx("RTM_GET: %s (errno %d)", 1451 strerror(rtm->rtm_errno), rtm->rtm_errno); 1452 return; 1453 } 1454 cp = ((char *)rtm + rtm->rtm_hdrlen); 1455 if (rtm->rtm_addrs) 1456 for (i = 1; i; i <<= 1) 1457 if (i & rtm->rtm_addrs) { 1458 sa = (struct sockaddr *)cp; 1459 switch (i) { 1460 case RTA_DST: 1461 dst = sa; 1462 break; 1463 case RTA_GATEWAY: 1464 gate = sa; 1465 break; 1466 case RTA_NETMASK: 1467 mask = sa; 1468 break; 1469 case RTA_IFA: 1470 ifa = sa; 1471 break; 1472 case RTA_IFP: 1473 if (sa->sa_family == AF_LINK && 1474 ((struct sockaddr_dl *)sa)->sdl_nlen) 1475 ifp = (struct sockaddr_dl *)sa; 1476 break; 1477 case RTA_SRC: 1478 mpls = sa; 1479 break; 1480 case RTA_LABEL: 1481 sa_rl = (struct sockaddr_rtlabel *)sa; 1482 break; 1483 #ifdef BFD 1484 case RTA_BFD: 1485 sa_bfd = (struct sockaddr_bfd *)sa; 1486 break; 1487 #endif 1488 } 1489 ADVANCE(cp, sa); 1490 } 1491 if (dst && mask) 1492 mask->sa_family = dst->sa_family; /* XXX */ 1493 if (dst) 1494 printf("destination: %s\n", routename(dst)); 1495 if (mask) { 1496 int savenflag = nflag; 1497 1498 nflag = 1; 1499 printf(" mask: %s\n", routename(mask)); 1500 nflag = savenflag; 1501 } 1502 if (gate && rtm->rtm_flags & RTF_GATEWAY) 1503 printf(" gateway: %s\n", routename(gate)); 1504 if (ifp) 1505 printf(" interface: %.*s\n", 1506 ifp->sdl_nlen, ifp->sdl_data); 1507 if (ifa) 1508 printf(" if address: %s\n", routename(ifa)); 1509 if (mpls) { 1510 printf(" mpls label: %s %s\n", mpls_op(rtm->rtm_mpls), 1511 routename(mpls)); 1512 } 1513 printf(" priority: %u (%s)\n", rtm->rtm_priority, 1514 priorityname(rtm->rtm_priority)); 1515 printf(" flags: "); 1516 bprintf(stdout, rtm->rtm_flags, routeflags); 1517 printf("\n"); 1518 if (sa_rl != NULL) 1519 printf(" label: %s\n", sa_rl->sr_label); 1520 #ifdef BFD 1521 if (sa_bfd) 1522 print_sabfd(sa_bfd, rtm->rtm_fmask); 1523 #endif 1524 1525 #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') 1526 relative_expire = rtm->rtm_rmx.rmx_expire ? 1527 rtm->rtm_rmx.rmx_expire - time(NULL) : 0; 1528 printf(" use mtu expire\n"); 1529 printf("%8llu %8u%c %8lld%c\n", 1530 rtm->rtm_rmx.rmx_pksent, 1531 rtm->rtm_rmx.rmx_mtu, lock(MTU), 1532 relative_expire, lock(EXPIRE)); 1533 #undef lock 1534 #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD) 1535 if (verbose) 1536 pmsg_common(rtm); 1537 else if (rtm->rtm_addrs &~ RTA_IGN) { 1538 printf("sockaddrs: "); 1539 bprintf(stdout, rtm->rtm_addrs, addrnames); 1540 putchar('\n'); 1541 } 1542 #undef RTA_IGN 1543 } 1544 1545 #ifdef BFD 1546 const char * 1547 bfd_state(unsigned int state) 1548 { 1549 switch (state) { 1550 case BFD_STATE_ADMINDOWN: 1551 return("admindown"); 1552 break; 1553 case BFD_STATE_DOWN: 1554 return("down"); 1555 break; 1556 case BFD_STATE_INIT: 1557 return("init"); 1558 break; 1559 case BFD_STATE_UP: 1560 return("up"); 1561 break; 1562 } 1563 return "invalid"; 1564 } 1565 1566 const char * 1567 bfd_diag(unsigned int diag) 1568 { 1569 switch (diag) { 1570 case BFD_DIAG_NONE: 1571 return("none"); 1572 break; 1573 case BFD_DIAG_EXPIRED: 1574 return("expired"); 1575 break; 1576 case BFD_DIAG_ECHO_FAILED: 1577 return("echo-failed"); 1578 break; 1579 case BFD_DIAG_NEIGHBOR_SIGDOWN: 1580 return("neighbor-down"); 1581 break; 1582 case BFD_DIAG_FIB_RESET: 1583 return("fib-reset"); 1584 break; 1585 case BFD_DIAG_PATH_DOWN: 1586 return("path-down"); 1587 break; 1588 case BFD_DIAG_CONCAT_PATH_DOWN: 1589 return("concat-path-down"); 1590 break; 1591 case BFD_DIAG_ADMIN_DOWN: 1592 return("admindown"); 1593 break; 1594 case BFD_DIAG_CONCAT_REVERSE_DOWN: 1595 return("concat-reverse-down"); 1596 break; 1597 } 1598 return "invalid"; 1599 } 1600 1601 const char * 1602 bfd_calc_uptime(time_t time) 1603 { 1604 static char buf[256]; 1605 struct tm *tp; 1606 const char *fmt; 1607 1608 if (time > 2*86400) 1609 fmt = "%dd%kh%Mm%Ss"; 1610 else if (time > 2*3600) 1611 fmt = "%kh%Mm%Ss"; 1612 else if (time > 2*60) 1613 fmt = "%Mm%Ss"; 1614 else 1615 fmt = "%Ss"; 1616 1617 tp = localtime(&time); 1618 (void)strftime(buf, sizeof(buf), fmt, tp); 1619 return (buf); 1620 } 1621 1622 void 1623 print_bfdmsg(struct rt_msghdr *rtm) 1624 { 1625 struct bfd_msghdr *bfdm = (struct bfd_msghdr *)rtm; 1626 1627 printf("\n"); 1628 print_sabfd(&bfdm->bm_sa, rtm->rtm_fmask); 1629 pmsg_addrs(((char *)rtm + rtm->rtm_hdrlen), rtm->rtm_addrs); 1630 } 1631 1632 void 1633 print_sabfd(struct sockaddr_bfd *sa_bfd, int fmask) 1634 { 1635 struct timeval tv; 1636 1637 gettimeofday(&tv, NULL); 1638 1639 printf(" BFD:"); 1640 1641 /* only show the state, unless verbose or -bfd */ 1642 if (!verbose && ((fmask & RTF_BFD) != RTF_BFD)) { 1643 printf(" %s\n", bfd_state(sa_bfd->bs_state)); 1644 return; 1645 } 1646 1647 switch (sa_bfd->bs_mode) { 1648 case BFD_MODE_ASYNC: 1649 printf(" async"); 1650 break; 1651 case BFD_MODE_DEMAND: 1652 printf(" demand"); 1653 break; 1654 default: 1655 printf(" unknown %u", sa_bfd->bs_mode); 1656 break; 1657 } 1658 1659 printf(" state %s", bfd_state(sa_bfd->bs_state)); 1660 printf(" remote %s", bfd_state(sa_bfd->bs_remotestate)); 1661 printf(" laststate %s", bfd_state(sa_bfd->bs_laststate)); 1662 1663 printf(" error %u", sa_bfd->bs_error); 1664 printf("\n "); 1665 printf(" diag %s", bfd_diag(sa_bfd->bs_localdiag)); 1666 printf(" remote %s", bfd_diag(sa_bfd->bs_remotediag)); 1667 printf("\n "); 1668 printf(" discr %u", sa_bfd->bs_localdiscr); 1669 printf(" remote %u", sa_bfd->bs_remotediscr); 1670 printf("\n "); 1671 printf(" uptime %s", bfd_calc_uptime(tv.tv_sec - sa_bfd->bs_uptime)); 1672 if (sa_bfd->bs_lastuptime) 1673 printf(" last state time %s", 1674 bfd_calc_uptime(sa_bfd->bs_lastuptime)); 1675 printf("\n "); 1676 printf(" mintx %u", sa_bfd->bs_mintx); 1677 printf(" minrx %u", sa_bfd->bs_minrx); 1678 printf(" minecho %u", sa_bfd->bs_minecho); 1679 printf(" multiplier %u", sa_bfd->bs_multiplier); 1680 printf("\n"); 1681 } 1682 #endif /* BFD */ 1683 1684 void 1685 pmsg_common(struct rt_msghdr *rtm) 1686 { 1687 printf("\nlocks: "); 1688 bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames); 1689 printf(" inits: "); 1690 bprintf(stdout, rtm->rtm_inits, metricnames); 1691 pmsg_addrs(((char *)rtm + rtm->rtm_hdrlen), rtm->rtm_addrs); 1692 } 1693 1694 void 1695 pmsg_addrs(char *cp, int addrs) 1696 { 1697 struct sockaddr *sa; 1698 int family = AF_UNSPEC; 1699 int i; 1700 char *p; 1701 1702 if (addrs != 0) { 1703 printf("\nsockaddrs: "); 1704 bprintf(stdout, addrs, addrnames); 1705 putchar('\n'); 1706 /* first run, search for address family */ 1707 p = cp; 1708 for (i = 1; i; i <<= 1) 1709 if (i & addrs) { 1710 sa = (struct sockaddr *)p; 1711 if (family == AF_UNSPEC) 1712 switch (i) { 1713 case RTA_DST: 1714 case RTA_IFA: 1715 family = sa->sa_family; 1716 } 1717 ADVANCE(p, sa); 1718 } 1719 /* second run, set address family for mask and print */ 1720 p = cp; 1721 for (i = 1; i; i <<= 1) 1722 if (i & addrs) { 1723 sa = (struct sockaddr *)p; 1724 if (family != AF_UNSPEC) 1725 switch (i) { 1726 case RTA_NETMASK: 1727 sa->sa_family = family; 1728 } 1729 printf(" %s", routename(sa)); 1730 ADVANCE(p, sa); 1731 } 1732 } 1733 putchar('\n'); 1734 fflush(stdout); 1735 } 1736 1737 void 1738 bprintf(FILE *fp, int b, char *s) 1739 { 1740 int i; 1741 int gotsome = 0; 1742 1743 if (b == 0) 1744 return; 1745 while ((i = *s++)) { 1746 if ((b & (1 << (i-1)))) { 1747 if (gotsome == 0) 1748 i = '<'; 1749 else 1750 i = ','; 1751 putc(i, fp); 1752 gotsome = 1; 1753 for (; (i = *s) > 32; s++) 1754 putc(i, fp); 1755 } else 1756 while (*s > 32) 1757 s++; 1758 } 1759 if (gotsome) 1760 putc('>', fp); 1761 } 1762 1763 int 1764 keycmp(const void *key, const void *kt) 1765 { 1766 return (strcmp(key, ((struct keytab *)kt)->kt_cp)); 1767 } 1768 1769 int 1770 keyword(char *cp) 1771 { 1772 struct keytab *kt; 1773 1774 kt = bsearch(cp, keywords, sizeof(keywords)/sizeof(keywords[0]), 1775 sizeof(keywords[0]), keycmp); 1776 if (!kt) 1777 return (0); 1778 1779 return (kt->kt_i); 1780 } 1781 1782 void 1783 sodump(sup su, char *which) 1784 { 1785 switch (su->sa.sa_family) { 1786 case AF_LINK: 1787 printf("%s: link %s; ", which, link_ntoa(&su->sdl)); 1788 break; 1789 case AF_INET: 1790 printf("%s: inet %s; ", which, inet_ntoa(su->sin.sin_addr)); 1791 break; 1792 case AF_INET6: 1793 { 1794 char ntop_buf[NI_MAXHOST]; 1795 1796 printf("%s: inet6 %s; ", 1797 which, inet_ntop(AF_INET6, &su->sin6.sin6_addr, 1798 ntop_buf, sizeof(ntop_buf))); 1799 break; 1800 } 1801 } 1802 fflush(stdout); 1803 } 1804 1805 /* States*/ 1806 #define VIRGIN 0 1807 #define GOTONE 1 1808 #define GOTTWO 2 1809 /* Inputs */ 1810 #define DIGIT (4*0) 1811 #define END (4*1) 1812 #define DELIM (4*2) 1813 1814 void 1815 sockaddr(char *addr, struct sockaddr *sa) 1816 { 1817 char *cp = (char *)sa; 1818 int size = sa->sa_len; 1819 char *cplim = cp + size; 1820 int byte = 0, state = VIRGIN, new = 0; 1821 1822 memset(cp, 0, size); 1823 cp++; 1824 do { 1825 if ((*addr >= '0') && (*addr <= '9')) { 1826 new = *addr - '0'; 1827 } else if ((*addr >= 'a') && (*addr <= 'f')) { 1828 new = *addr - 'a' + 10; 1829 } else if ((*addr >= 'A') && (*addr <= 'F')) { 1830 new = *addr - 'A' + 10; 1831 } else if (*addr == '\0') 1832 state |= END; 1833 else 1834 state |= DELIM; 1835 addr++; 1836 switch (state /* | INPUT */) { 1837 case GOTTWO | DIGIT: 1838 *cp++ = byte; /*FALLTHROUGH*/ 1839 case VIRGIN | DIGIT: 1840 state = GOTONE; byte = new; continue; 1841 case GOTONE | DIGIT: 1842 state = GOTTWO; byte = new + (byte << 4); continue; 1843 default: /* | DELIM */ 1844 state = VIRGIN; *cp++ = byte; byte = 0; continue; 1845 case GOTONE | END: 1846 case GOTTWO | END: 1847 *cp++ = byte; /* FALLTHROUGH */ 1848 case VIRGIN | END: 1849 break; 1850 } 1851 break; 1852 } while (cp < cplim); 1853 sa->sa_len = cp - (char *)sa; 1854 } 1855 1856 void 1857 getlabel(char *name) 1858 { 1859 so_label.rtlabel.sr_len = sizeof(so_label.rtlabel); 1860 so_label.rtlabel.sr_family = AF_UNSPEC; 1861 if (strlcpy(so_label.rtlabel.sr_label, name, 1862 sizeof(so_label.rtlabel.sr_label)) >= 1863 sizeof(so_label.rtlabel.sr_label)) 1864 errx(1, "label too long"); 1865 rtm_addrs |= RTA_LABEL; 1866 } 1867 1868 int 1869 gettable(const char *s) 1870 { 1871 const char *errstr; 1872 struct rt_tableinfo info; 1873 int mib[6]; 1874 size_t len; 1875 1876 tableid = strtonum(s, 0, RT_TABLEID_MAX, &errstr); 1877 if (errstr) 1878 errx(1, "invalid table id: %s", errstr); 1879 1880 mib[0] = CTL_NET; 1881 mib[1] = PF_ROUTE; 1882 mib[2] = 0; 1883 mib[3] = 0; 1884 mib[4] = NET_RT_TABLE; 1885 mib[5] = tableid; 1886 1887 len = sizeof(info); 1888 if (sysctl(mib, 6, &info, &len, NULL, 0) == -1) 1889 return (errno); 1890 else 1891 return (0); 1892 } 1893 1894 int 1895 rdomain(int argc, char **argv) 1896 { 1897 if (!argc) 1898 usage(NULL); 1899 if (setrtable(tableid) == -1) 1900 err(1, "setrtable"); 1901 execvp(*argv, argv); 1902 warn("%s", argv[0]); 1903 return (errno == ENOENT ? 127 : 126); 1904 } 1905 1906 /* 1907 * Print RTM_PROPOSAL DNS server addresses. 1908 */ 1909 void 1910 print_rtdns(struct sockaddr_rtdns *rtdns) 1911 { 1912 struct in_addr server; 1913 struct in6_addr in6; 1914 size_t srclen, offset; 1915 unsigned int servercnt; 1916 int i; 1917 char *src = rtdns->sr_dns; 1918 char ntopbuf[INET6_ADDRSTRLEN]; 1919 1920 offset = offsetof(struct sockaddr_rtdns, sr_dns); 1921 if (rtdns->sr_len < offset) { 1922 printf("<invalid sr_len (%u <= %zu)>\n", rtdns->sr_len, 1923 offset); 1924 return; 1925 } 1926 srclen = rtdns->sr_len - offset; 1927 if (srclen > sizeof(rtdns->sr_dns)) { 1928 printf("<invalid sr_len (%zu > %zu)>\n", srclen, 1929 sizeof(rtdns->sr_dns)); 1930 return; 1931 } 1932 printf(" ["); 1933 switch (rtdns->sr_family) { 1934 case AF_INET: 1935 /* An array of IPv4 addresses. */ 1936 servercnt = srclen / sizeof(struct in_addr); 1937 if (servercnt * sizeof(struct in_addr) != srclen) { 1938 printf("<invalid server count>\n"); 1939 return; 1940 } 1941 for (i = 0; i < servercnt; i++) { 1942 memcpy(&server.s_addr, src, sizeof(server.s_addr)); 1943 printf("%s%s", inet_ntoa(server), i == servercnt - 1 ? 1944 "": ", "); 1945 src += sizeof(struct in_addr); 1946 } 1947 break; 1948 case AF_INET6: 1949 servercnt = srclen / sizeof(struct in6_addr); 1950 if (servercnt * sizeof(struct in6_addr) != srclen) { 1951 printf("<invalid server count>\n"); 1952 return; 1953 } 1954 for (i = 0; i < servercnt; i++) { 1955 memcpy(&in6, src, sizeof(in6)); 1956 src += sizeof(in6); 1957 printf("%s%s", inet_ntop(AF_INET6, &in6, ntopbuf, 1958 INET6_ADDRSTRLEN), i == servercnt - 1 ? "": ", "); 1959 } 1960 break; 1961 default: 1962 break; 1963 } 1964 printf("]"); 1965 } 1966 1967 /* 1968 * Print RTM_PROPOSAL static routes. 1969 */ 1970 void 1971 print_rtstatic(struct sockaddr_rtstatic *rtstatic) 1972 { 1973 struct sockaddr_in6 gateway6; 1974 struct in6_addr prefix; 1975 struct in_addr dest, gateway; 1976 size_t srclen, offset; 1977 int bits, bytes, error, first = 1; 1978 uint8_t prefixlen; 1979 unsigned char *src = rtstatic->sr_static; 1980 char ntoabuf[INET_ADDRSTRLEN]; 1981 char hbuf[NI_MAXHOST]; 1982 char ntopbuf[INET6_ADDRSTRLEN]; 1983 1984 offset = offsetof(struct sockaddr_rtstatic, sr_static); 1985 if (rtstatic->sr_len <= offset) { 1986 printf("<invalid sr_len (%u <= %zu)>\n", rtstatic->sr_len, 1987 offset); 1988 return; 1989 } 1990 srclen = rtstatic->sr_len - offset; 1991 if (srclen > sizeof(rtstatic->sr_static)) { 1992 printf("<invalid sr_len (%zu > %zu)>\n", srclen, 1993 sizeof(rtstatic->sr_static)); 1994 return; 1995 } 1996 printf(" ["); 1997 switch (rtstatic->sr_family) { 1998 case AF_INET: 1999 /* AF_INET -> RFC 3442 encoded static routes. */ 2000 while (srclen) { 2001 bits = *src; 2002 src++; 2003 srclen--; 2004 bytes = (bits + 7) / 8; 2005 if (srclen < bytes || bytes > sizeof(dest.s_addr)) 2006 break; 2007 memset(&dest, 0, sizeof(dest)); 2008 memcpy(&dest.s_addr, src, bytes); 2009 src += bytes; 2010 srclen -= bytes; 2011 strlcpy(ntoabuf, inet_ntoa(dest), sizeof(ntoabuf)); 2012 if (srclen < sizeof(gateway.s_addr)) 2013 break; 2014 memcpy(&gateway.s_addr, src, sizeof(gateway.s_addr)); 2015 src += sizeof(gateway.s_addr); 2016 srclen -= sizeof(gateway.s_addr); 2017 printf("%s%s/%u %s ", first ? "" : ", ", ntoabuf, bits, 2018 inet_ntoa(gateway)); 2019 first = 0; 2020 } 2021 break; 2022 case AF_INET6: 2023 while (srclen >= sizeof(prefixlen) + sizeof(prefix) + 2024 sizeof(gateway6)) { 2025 memcpy(&prefixlen, src, sizeof(prefixlen)); 2026 srclen -= sizeof(prefixlen); 2027 src += sizeof(prefixlen); 2028 2029 memcpy(&prefix, src, sizeof(prefix)); 2030 srclen -= sizeof(prefix); 2031 src += sizeof(prefix); 2032 2033 memcpy(&gateway6, src, sizeof(gateway6)); 2034 srclen -= sizeof(gateway6); 2035 src += sizeof(gateway6); 2036 2037 if ((error = getnameinfo((struct sockaddr *)&gateway6, 2038 gateway6.sin6_len, hbuf, sizeof(hbuf), NULL, 0, 2039 NI_NUMERICHOST | NI_NUMERICSERV))) { 2040 warnx("cannot get gateway address: %s", 2041 gai_strerror(error)); 2042 return; 2043 } 2044 printf("%s%s/%u %s ", first ? "" : ", ", 2045 inet_ntop(AF_INET6, &prefix, ntopbuf, 2046 INET6_ADDRSTRLEN), prefixlen, hbuf); 2047 first = 0; 2048 } 2049 break; 2050 default: 2051 printf("<unknown address family %u>", rtstatic->sr_family); 2052 break; 2053 } 2054 printf("]"); 2055 } 2056 2057 /* 2058 * Print RTM_PROPOSAL domain search list. 2059 */ 2060 void 2061 print_rtsearch(struct sockaddr_rtsearch *rtsearch) 2062 { 2063 char *src = rtsearch->sr_search; 2064 size_t srclen, offset; 2065 2066 offset = offsetof(struct sockaddr_rtsearch, sr_search); 2067 if (rtsearch->sr_len <= offset) { 2068 printf("<invalid sr_len (%u <= %zu)>\n", rtsearch->sr_len, 2069 offset); 2070 return; 2071 } 2072 srclen = rtsearch->sr_len - offset; 2073 if (srclen > sizeof(rtsearch->sr_search)) { 2074 printf("<invalid sr_len (%zu > %zu)>\n", srclen, 2075 sizeof(rtsearch->sr_search)); 2076 return; 2077 } 2078 2079 printf(" [%.*s]", (int)srclen, src); 2080 } 2081 2082 /* 2083 * Print RTM_80211INFO info. 2084 */ 2085 void 2086 print_80211info(struct if_ieee80211_msghdr *ifim) 2087 { 2088 unsigned int ascii, nwidlen, i; 2089 u_int8_t *nwid, *bssid; 2090 2091 ascii = 1; 2092 nwid = ifim->ifim_ifie.ifie_nwid; 2093 nwidlen = ifim->ifim_ifie.ifie_nwid_len; 2094 for (i = 0; i < nwidlen; i++) { 2095 if (i == 0) 2096 printf("nwid "); 2097 else 2098 printf(":"); 2099 printf("%02x", nwid[i]); 2100 if (!isprint((unsigned int)nwid[i])) 2101 ascii = 0; 2102 } 2103 if (i > 0) { 2104 if (ascii == 1) 2105 printf(" (%.*s)", nwidlen, nwid); 2106 printf(", "); 2107 } 2108 printf("channel %u, ", ifim->ifim_ifie.ifie_channel); 2109 bssid = ifim->ifim_ifie.ifie_addr; 2110 printf("bssid %02x:%02x:%02x:%02x:%02x:%02x, ", 2111 bssid[0], bssid[1], bssid[2], 2112 bssid[3], bssid[4], bssid[5]); 2113 printf("flags: 0x%x, xflags: 0x%x\n", ifim->ifim_ifie.ifie_flags, 2114 ifim->ifim_ifie.ifie_xflags); 2115 } 2116