1 /* $OpenBSD: route.c,v 1.191 2016/09/15 12:51:20 phessler 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 #include <arpa/inet.h> 45 #include <netdb.h> 46 47 #include <errno.h> 48 #include <fcntl.h> 49 #include <unistd.h> 50 #include <limits.h> 51 #include <stdio.h> 52 #include <ctype.h> 53 #include <stddef.h> 54 #include <stdlib.h> 55 #include <string.h> 56 #include <time.h> 57 #include <paths.h> 58 #include <err.h> 59 60 #include "keywords.h" 61 #include "show.h" 62 63 const struct if_status_description 64 if_status_descriptions[] = LINK_STATE_DESCRIPTIONS; 65 66 union sockunion so_dst, so_gate, so_mask, so_ifa, so_ifp, so_label, so_src; 67 68 typedef union sockunion *sup; 69 pid_t pid; 70 int rtm_addrs, s; 71 int forcehost, forcenet, Fflag, nflag, af, qflag, tflag, Tflag; 72 int iflag, verbose, aflen = sizeof(struct sockaddr_in); 73 int locking, lockrest, debugonly; 74 u_long mpls_flags = MPLS_OP_LOCAL; 75 u_long rtm_inits; 76 uid_t uid; 77 u_int tableid; 78 79 struct rt_metrics rt_metrics; 80 81 int flushroutes(int, char **); 82 int newroute(int, char **); 83 int show(int, char *[]); 84 int keycmp(const void *, const void *); 85 int keyword(char *); 86 void monitor(int, char *[]); 87 int prefixlen(char *); 88 void sockaddr(char *, struct sockaddr *); 89 void sodump(sup, char *); 90 char *priorityname(uint8_t); 91 uint8_t getpriority(char *); 92 void print_getmsg(struct rt_msghdr *, int); 93 const char *get_linkstate(int, int); 94 void print_rtmsg(struct rt_msghdr *, int); 95 void pmsg_common(struct rt_msghdr *); 96 void pmsg_addrs(char *, int); 97 void bprintf(FILE *, int, char *); 98 void mask_addr(union sockunion *, union sockunion *, int); 99 int inet6_makenetandmask(struct sockaddr_in6 *, char *); 100 int getaddr(int, char *, struct hostent **); 101 void getmplslabel(char *, int); 102 int rtmsg(int, int, int, uint8_t); 103 __dead void usage(char *); 104 void set_metric(char *, int); 105 void inet_makenetandmask(u_int32_t, struct sockaddr_in *, int); 106 void interfaces(void); 107 void getlabel(char *); 108 int gettable(const char *); 109 int rdomain(int, char **); 110 111 __dead void 112 usage(char *cp) 113 { 114 extern char *__progname; 115 116 if (cp) 117 warnx("botched keyword: %s", cp); 118 fprintf(stderr, 119 "usage: %s [-dnqtv] [-T tableid] command [[modifiers] args]\n", 120 __progname); 121 fprintf(stderr, 122 "commands: add, change, delete, exec, flush, get, monitor, show\n"); 123 exit(1); 124 } 125 126 #define ROUNDUP(a) \ 127 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 128 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 129 130 int 131 main(int argc, char **argv) 132 { 133 int ch; 134 int rval = 0; 135 int kw; 136 int Terr = 0; 137 138 if (argc < 2) 139 usage(NULL); 140 141 tableid = getrtable(); 142 while ((ch = getopt(argc, argv, "dnqtT:v")) != -1) 143 switch (ch) { 144 case 'n': 145 nflag = 1; 146 break; 147 case 'q': 148 qflag = 1; 149 break; 150 case 'v': 151 verbose = 1; 152 break; 153 case 't': 154 tflag = 1; 155 break; 156 case 'T': 157 Terr = gettable(optarg); 158 Tflag = 1; 159 break; 160 case 'd': 161 debugonly = 1; 162 break; 163 default: 164 usage(NULL); 165 /* NOTREACHED */ 166 } 167 argc -= optind; 168 argv += optind; 169 170 pid = getpid(); 171 uid = geteuid(); 172 if (*argv == NULL) 173 usage(NULL); 174 175 kw = keyword(*argv); 176 if (Tflag && Terr != 0 && kw != K_ADD) { 177 errno = Terr; 178 err(1, "routing table %d", tableid); 179 } 180 if (kw == K_EXEC) 181 exit(rdomain(argc - 1, argv + 1)); 182 183 s = socket(PF_ROUTE, SOCK_RAW, 0); 184 if (s == -1) 185 err(1, "socket"); 186 if (kw == K_MONITOR) { 187 unsigned int filter = 0; 188 int af = 0; 189 190 while (--argc > 0) { 191 if (**(++argv)== '-') 192 switch (keyword(*argv + 1)) { 193 case K_INET: 194 af = AF_INET; 195 break; 196 case K_INET6: 197 af = AF_INET6; 198 break; 199 case K_IFACE: 200 case K_INTERFACE: 201 filter = ROUTE_FILTER(RTM_IFINFO) | 202 ROUTE_FILTER(RTM_IFANNOUNCE); 203 break; 204 default: 205 usage(*argv); 206 /* NOTREACHED */ 207 } 208 else 209 usage(*argv); 210 } 211 if (setsockopt(s, AF_ROUTE, ROUTE_MSGFILTER, &filter, 212 sizeof(filter)) == -1) 213 err(1, "setsockopt(ROUTE_MSGFILTER)"); 214 } 215 /* force socket onto table user requested */ 216 if (Tflag == 1 && Terr == 0 && 217 setsockopt(s, AF_ROUTE, ROUTE_TABLEFILTER, 218 &tableid, sizeof(tableid)) == -1) 219 err(1, "setsockopt(ROUTE_TABLEFILTER)"); 220 221 switch (kw) { 222 case K_SHOW: 223 uid = 0; 224 exit(show(argc, argv)); 225 break; 226 case K_FLUSH: 227 exit(flushroutes(argc, argv)); 228 break; 229 } 230 231 if (pledge("stdio rpath dns", NULL) == -1) 232 err(1, "pledge"); 233 234 switch (kw) { 235 case K_GET: 236 uid = 0; 237 /* FALLTHROUGH */ 238 case K_CHANGE: 239 case K_ADD: 240 case K_DELETE: 241 rval = newroute(argc, argv); 242 break; 243 case K_MONITOR: 244 monitor(argc, argv); 245 break; 246 default: 247 usage(*argv); 248 /* NOTREACHED */ 249 } 250 exit(rval); 251 } 252 253 /* 254 * Purge all entries in the routing tables not 255 * associated with network interfaces. 256 */ 257 int 258 flushroutes(int argc, char **argv) 259 { 260 size_t needed; 261 int mib[7], rlen, seqno; 262 char *buf = NULL, *next, *lim = NULL; 263 struct rt_msghdr *rtm; 264 struct sockaddr *sa; 265 uint8_t prio = 0; 266 unsigned int ifindex = 0; 267 268 if (uid) 269 errx(1, "must be root to alter routing table"); 270 shutdown(s, SHUT_RD); /* Don't want to read back our messages */ 271 while (--argc > 0) { 272 if (**(++argv) == '-') 273 switch (keyword(*argv + 1)) { 274 case K_INET: 275 af = AF_INET; 276 break; 277 case K_INET6: 278 af = AF_INET6; 279 break; 280 case K_LINK: 281 af = AF_LINK; 282 break; 283 case K_MPLS: 284 af = AF_MPLS; 285 break; 286 case K_IFACE: 287 case K_INTERFACE: 288 if (!--argc) 289 usage(1+*argv); 290 ifindex = if_nametoindex(*++argv); 291 if (ifindex == 0) 292 errx(1, "no such interface %s", *argv); 293 break; 294 case K_PRIORITY: 295 if (!--argc) 296 usage(1+*argv); 297 prio = getpriority(*++argv); 298 break; 299 default: 300 usage(*argv); 301 /* NOTREACHED */ 302 } 303 else 304 usage(*argv); 305 } 306 mib[0] = CTL_NET; 307 mib[1] = PF_ROUTE; 308 mib[2] = 0; /* protocol */ 309 mib[3] = 0; /* wildcard address family */ 310 mib[4] = NET_RT_DUMP; 311 mib[5] = 0; /* no flags */ 312 mib[6] = tableid; 313 while (1) { 314 if (sysctl(mib, 7, NULL, &needed, NULL, 0) == -1) 315 err(1, "route-sysctl-estimate"); 316 if (needed == 0) 317 break; 318 if ((buf = realloc(buf, needed)) == NULL) 319 err(1, "realloc"); 320 if (sysctl(mib, 7, buf, &needed, NULL, 0) == -1) { 321 if (errno == ENOMEM) 322 continue; 323 err(1, "actual retrieval of routing table"); 324 } 325 lim = buf + needed; 326 break; 327 } 328 329 if (pledge("stdio rpath dns", NULL) == -1) 330 err(1, "pledge"); 331 332 if (verbose) { 333 printf("Examining routing table from sysctl\n"); 334 if (af) 335 printf("(address family %s)\n", (*argv + 1)); 336 } 337 if (buf == NULL) 338 return (1); 339 340 seqno = 0; 341 for (next = buf; next < lim; next += rtm->rtm_msglen) { 342 rtm = (struct rt_msghdr *)next; 343 if (rtm->rtm_version != RTM_VERSION) 344 continue; 345 if (verbose) 346 print_rtmsg(rtm, rtm->rtm_msglen); 347 if ((rtm->rtm_flags & (RTF_GATEWAY|RTF_STATIC|RTF_LLINFO)) == 0) 348 continue; 349 if ((rtm->rtm_flags & (RTF_LOCAL|RTF_BROADCAST)) != 0) 350 continue; 351 sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); 352 if (af && sa->sa_family != af) 353 continue; 354 if (ifindex && rtm->rtm_index != ifindex) 355 continue; 356 if (prio && rtm->rtm_priority != prio) 357 continue; 358 if (sa->sa_family == AF_KEY) 359 continue; /* Don't flush SPD */ 360 if (debugonly) 361 continue; 362 rtm->rtm_type = RTM_DELETE; 363 rtm->rtm_seq = seqno; 364 rtm->rtm_tableid = tableid; 365 rlen = write(s, next, rtm->rtm_msglen); 366 if (rlen < (int)rtm->rtm_msglen) { 367 warn("write to routing socket"); 368 printf("got only %d for rlen\n", rlen); 369 break; 370 } 371 seqno++; 372 if (qflag) 373 continue; 374 if (verbose) 375 print_rtmsg(rtm, rlen); 376 else { 377 sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); 378 printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ? 379 routename(sa) : netname(sa, NULL)); /* XXX extract 380 netmask */ 381 sa = (struct sockaddr *) 382 (ROUNDUP(sa->sa_len) + (char *)sa); 383 printf("%-20.20s ", routename(sa)); 384 printf("done\n"); 385 } 386 } 387 free(buf); 388 return (0); 389 } 390 391 void 392 set_metric(char *value, int key) 393 { 394 long long relative_expire; 395 const char *errstr; 396 int flag = 0; 397 398 switch (key) { 399 case K_MTU: 400 rt_metrics.rmx_mtu = strtonum(value, 0, UINT_MAX, &errstr); 401 if (errstr) 402 errx(1, "set_metric mtu: %s is %s", value, errstr); 403 flag = RTV_MTU; 404 break; 405 case K_EXPIRE: 406 relative_expire = strtonum(value, 0, INT_MAX, &errstr); 407 if (errstr) 408 errx(1, "set_metric expire: %s is %s", value, errstr); 409 rt_metrics.rmx_expire = relative_expire ? 410 relative_expire + time(NULL) : 0; 411 flag = RTV_EXPIRE; 412 break; 413 case K_HOPCOUNT: 414 case K_RECVPIPE: 415 case K_SENDPIPE: 416 case K_SSTHRESH: 417 case K_RTT: 418 case K_RTTVAR: 419 /* no longer used, only for compatibility */ 420 return; 421 default: 422 errx(1, "king bula sez: set_metric with invalid key"); 423 } 424 rtm_inits |= flag; 425 if (lockrest || locking) 426 rt_metrics.rmx_locks |= flag; 427 if (locking) 428 locking = 0; 429 } 430 431 int 432 newroute(int argc, char **argv) 433 { 434 char *cmd, *dest = "", *gateway = "", *error; 435 int ishost = 0, ret = 0, attempts, oerrno, flags = RTF_STATIC; 436 int fmask = 0; 437 int key; 438 uint8_t prio = 0; 439 struct hostent *hp = NULL; 440 441 if (uid) 442 errx(1, "must be root to alter routing table"); 443 cmd = argv[0]; 444 if (*cmd != 'g') 445 shutdown(s, SHUT_RD); /* Don't want to read back our messages */ 446 while (--argc > 0) { 447 if (**(++argv)== '-') { 448 switch (key = keyword(1 + *argv)) { 449 case K_LINK: 450 af = AF_LINK; 451 aflen = sizeof(struct sockaddr_dl); 452 break; 453 case K_INET: 454 af = AF_INET; 455 aflen = sizeof(struct sockaddr_in); 456 break; 457 case K_INET6: 458 af = AF_INET6; 459 aflen = sizeof(struct sockaddr_in6); 460 break; 461 case K_SA: 462 af = PF_ROUTE; 463 aflen = sizeof(union sockunion); 464 break; 465 case K_MPLS: 466 af = AF_MPLS; 467 aflen = sizeof(struct sockaddr_mpls); 468 fmask |= RTF_MPLS; 469 break; 470 case K_MPLSLABEL: 471 if (!--argc) 472 usage(1+*argv); 473 if (af != AF_INET && af != AF_INET6) 474 errx(1, "-mplslabel requires " 475 "-inet or -inet6"); 476 getmplslabel(*++argv, 0); 477 mpls_flags = MPLS_OP_PUSH; 478 flags |= RTF_MPLS; 479 break; 480 case K_IN: 481 if (!--argc) 482 usage(1+*argv); 483 if (af != AF_MPLS) 484 errx(1, "-in requires -mpls"); 485 getmplslabel(*++argv, 1); 486 break; 487 case K_OUT: 488 if (!--argc) 489 usage(1+*argv); 490 if (af != AF_MPLS) 491 errx(1, "-out requires -mpls"); 492 if (mpls_flags == MPLS_OP_LOCAL) 493 errx(1, "-out requires -push, -pop, " 494 "-swap"); 495 getmplslabel(*++argv, 0); 496 flags |= RTF_MPLS; 497 break; 498 case K_POP: 499 if (af != AF_MPLS) 500 errx(1, "-pop requires -mpls"); 501 mpls_flags = MPLS_OP_POP; 502 break; 503 case K_PUSH: 504 if (af != AF_MPLS) 505 errx(1, "-push requires -mpls"); 506 mpls_flags = MPLS_OP_PUSH; 507 break; 508 case K_SWAP: 509 if (af != AF_MPLS) 510 errx(1, "-swap requires -mpls"); 511 mpls_flags = MPLS_OP_SWAP; 512 break; 513 case K_IFACE: 514 case K_INTERFACE: 515 iflag++; 516 break; 517 case K_NOSTATIC: 518 flags &= ~RTF_STATIC; 519 break; 520 case K_LLINFO: 521 flags |= RTF_LLINFO; 522 break; 523 case K_LOCK: 524 locking = 1; 525 break; 526 case K_LOCKREST: 527 lockrest = 1; 528 break; 529 case K_HOST: 530 forcehost++; 531 break; 532 case K_REJECT: 533 flags |= RTF_REJECT; 534 break; 535 case K_BLACKHOLE: 536 flags |= RTF_BLACKHOLE; 537 break; 538 case K_PROTO1: 539 flags |= RTF_PROTO1; 540 break; 541 case K_PROTO2: 542 flags |= RTF_PROTO2; 543 break; 544 case K_CLONING: 545 flags |= RTF_CLONING; 546 break; 547 case K_STATIC: 548 flags |= RTF_STATIC; 549 break; 550 case K_IFA: 551 if (!--argc) 552 usage(1+*argv); 553 getaddr(RTA_IFA, *++argv, NULL); 554 break; 555 case K_IFP: 556 if (!--argc) 557 usage(1+*argv); 558 getaddr(RTA_IFP, *++argv, NULL); 559 break; 560 case K_GATEWAY: 561 if (!--argc) 562 usage(1+*argv); 563 getaddr(RTA_GATEWAY, *++argv, NULL); 564 gateway = *argv; 565 break; 566 case K_DST: 567 if (!--argc) 568 usage(1+*argv); 569 ishost = getaddr(RTA_DST, *++argv, &hp); 570 dest = *argv; 571 break; 572 case K_LABEL: 573 if (!--argc) 574 usage(1+*argv); 575 getlabel(*++argv); 576 break; 577 case K_NETMASK: 578 if (!--argc) 579 usage(1+*argv); 580 getaddr(RTA_NETMASK, *++argv, NULL); 581 /* FALLTHROUGH */ 582 case K_NET: 583 forcenet++; 584 break; 585 case K_PREFIXLEN: 586 if (!--argc) 587 usage(1+*argv); 588 ishost = prefixlen(*++argv); 589 break; 590 case K_MPATH: 591 flags |= RTF_MPATH; 592 break; 593 case K_MTU: 594 case K_HOPCOUNT: 595 case K_EXPIRE: 596 case K_RECVPIPE: 597 case K_SENDPIPE: 598 case K_SSTHRESH: 599 case K_RTT: 600 case K_RTTVAR: 601 if (!--argc) 602 usage(1+*argv); 603 set_metric(*++argv, key); 604 break; 605 case K_PRIORITY: 606 if (!--argc) 607 usage(1+*argv); 608 prio = getpriority(*++argv); 609 break; 610 case K_BFD: 611 flags |= RTF_BFD; 612 fmask |= RTF_BFD; 613 break; 614 case K_NOBFD: 615 flags &= ~RTF_BFD; 616 fmask |= RTF_BFD; 617 break; 618 default: 619 usage(1+*argv); 620 /* NOTREACHED */ 621 } 622 } else { 623 if ((rtm_addrs & RTA_DST) == 0) { 624 dest = *argv; 625 ishost = getaddr(RTA_DST, *argv, &hp); 626 } else if ((rtm_addrs & RTA_GATEWAY) == 0) { 627 gateway = *argv; 628 getaddr(RTA_GATEWAY, *argv, &hp); 629 } else 630 usage(NULL); 631 } 632 } 633 if (forcehost) 634 ishost = 1; 635 if (forcenet) 636 ishost = 0; 637 if (forcenet && !(rtm_addrs & RTA_NETMASK)) 638 errx(1, "netmask missing"); 639 flags |= RTF_UP; 640 if (ishost) 641 flags |= RTF_HOST; 642 if (iflag == 0) 643 flags |= RTF_GATEWAY; 644 for (attempts = 1; ; attempts++) { 645 errno = 0; 646 if ((ret = rtmsg(*cmd, flags, fmask, prio)) == 0) 647 break; 648 if (errno != ENETUNREACH && errno != ESRCH) 649 break; 650 if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) { 651 hp->h_addr_list++; 652 memcpy(&so_gate.sin.sin_addr, hp->h_addr_list[0], 653 hp->h_length); 654 } else 655 break; 656 } 657 if (*cmd == 'g') { 658 if (ret != 0 && qflag == 0) 659 warn("writing to routing socket"); 660 exit(0); 661 } 662 oerrno = errno; 663 if (!qflag) { 664 printf("%s %s %s", cmd, ishost ? "host" : "net", dest); 665 if (*gateway) { 666 printf(": gateway %s", gateway); 667 if (attempts > 1 && ret == 0 && af == AF_INET) 668 printf(" (%s)", inet_ntoa(so_gate.sin.sin_addr)); 669 } 670 if (ret == 0) 671 printf("\n"); 672 if (ret != 0) { 673 switch (oerrno) { 674 case ESRCH: 675 error = "not in table"; 676 break; 677 case EBUSY: 678 error = "entry in use"; 679 break; 680 case ENOBUFS: 681 error = "routing table overflow"; 682 break; 683 default: 684 error = strerror(oerrno); 685 break; 686 } 687 printf(": %s\n", error); 688 } 689 } 690 return (ret != 0); 691 } 692 693 int 694 show(int argc, char *argv[]) 695 { 696 int af = 0; 697 char prio = 0; 698 699 while (--argc > 0) { 700 if (**(++argv)== '-') 701 switch (keyword(*argv + 1)) { 702 case K_INET: 703 af = AF_INET; 704 break; 705 case K_INET6: 706 af = AF_INET6; 707 break; 708 case K_LINK: 709 af = AF_LINK; 710 break; 711 case K_MPLS: 712 af = AF_MPLS; 713 break; 714 case K_GATEWAY: 715 Fflag = 1; 716 break; 717 case K_LABEL: 718 if (!--argc) 719 usage(1+*argv); 720 getlabel(*++argv); 721 break; 722 case K_PRIORITY: 723 if (!--argc) 724 usage(1+*argv); 725 prio = getpriority(*++argv); 726 break; 727 default: 728 usage(*argv); 729 /* NOTREACHED */ 730 } 731 else 732 usage(*argv); 733 } 734 735 p_rttables(af, tableid, Tflag, prio); 736 return (0); 737 } 738 739 void 740 inet_makenetandmask(u_int32_t net, struct sockaddr_in *sin, int bits) 741 { 742 u_int32_t addr, mask = 0; 743 char *cp; 744 745 rtm_addrs |= RTA_NETMASK; 746 if (net == 0 && bits == 0) 747 mask = addr = 0; 748 else if (bits) { 749 addr = net; 750 mask = 0xffffffff << (32 - bits); 751 } else if (net < 128) { 752 addr = net << IN_CLASSA_NSHIFT; 753 mask = IN_CLASSA_NET; 754 } else if (net < 65536) { 755 addr = net << IN_CLASSB_NSHIFT; 756 mask = IN_CLASSB_NET; 757 } else if (net < 16777216L) { 758 addr = net << IN_CLASSC_NSHIFT; 759 mask = IN_CLASSC_NET; 760 } else { 761 addr = net; 762 if ((addr & IN_CLASSA_HOST) == 0) 763 mask = IN_CLASSA_NET; 764 else if ((addr & IN_CLASSB_HOST) == 0) 765 mask = IN_CLASSB_NET; 766 else if ((addr & IN_CLASSC_HOST) == 0) 767 mask = IN_CLASSC_NET; 768 else 769 mask = 0xffffffff; 770 } 771 addr &= mask; 772 sin->sin_addr.s_addr = htonl(addr); 773 sin = &so_mask.sin; 774 sin->sin_addr.s_addr = htonl(mask); 775 sin->sin_len = 0; 776 sin->sin_family = 0; 777 cp = (char *)(&sin->sin_addr + 1); 778 while (*--cp == '\0' && cp > (char *)sin) 779 continue; 780 sin->sin_len = 1 + cp - (char *)sin; 781 } 782 783 /* 784 * XXX the function may need more improvement... 785 */ 786 int 787 inet6_makenetandmask(struct sockaddr_in6 *sin6, char *plen) 788 { 789 struct in6_addr in6; 790 const char *errstr; 791 int i, len, q, r; 792 793 if (NULL==plen) { 794 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && 795 sin6->sin6_scope_id == 0) { 796 plen = "0"; 797 } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) { 798 /* aggregatable global unicast - RFC2374 */ 799 memset(&in6, 0, sizeof(in6)); 800 if (!memcmp(&sin6->sin6_addr.s6_addr[8], 801 &in6.s6_addr[8], 8)) 802 plen = "64"; 803 } 804 } 805 806 if (!plen || strcmp(plen, "128") == 0) 807 return (1); 808 else { 809 rtm_addrs |= RTA_NETMASK; 810 prefixlen(plen); 811 812 len = strtonum(plen, 0, 128, &errstr); 813 if (errstr) 814 errx(1, "prefixlen %s is %s", plen, errstr); 815 816 q = (128-len) >> 3; 817 r = (128-len) & 7; 818 i = 15; 819 820 while (q-- > 0) 821 sin6->sin6_addr.s6_addr[i--] = 0; 822 if (r > 0) 823 sin6->sin6_addr.s6_addr[i] &= 0xff << r; 824 825 return (0); 826 } 827 } 828 829 /* 830 * Interpret an argument as a network address of some kind, 831 * returning 1 if a host address, 0 if a network address. 832 */ 833 int 834 getaddr(int which, char *s, struct hostent **hpp) 835 { 836 sup su = NULL; 837 struct hostent *hp; 838 struct netent *np; 839 int afamily, bits; 840 841 if (af == 0) { 842 if (strchr(s, ':') != NULL) { 843 af = AF_INET6; 844 aflen = sizeof(struct sockaddr_in6); 845 } else { 846 af = AF_INET; 847 aflen = sizeof(struct sockaddr_in); 848 } 849 } 850 afamily = af; /* local copy of af so we can change it */ 851 852 rtm_addrs |= which; 853 switch (which) { 854 case RTA_DST: 855 su = &so_dst; 856 break; 857 case RTA_GATEWAY: 858 su = &so_gate; 859 break; 860 case RTA_NETMASK: 861 su = &so_mask; 862 break; 863 case RTA_IFP: 864 su = &so_ifp; 865 afamily = AF_LINK; 866 break; 867 case RTA_IFA: 868 su = &so_ifa; 869 break; 870 default: 871 errx(1, "internal error"); 872 /* NOTREACHED */ 873 } 874 su->sa.sa_len = aflen; 875 su->sa.sa_family = afamily; 876 877 if (strcmp(s, "default") == 0) { 878 switch (which) { 879 case RTA_DST: 880 forcenet++; 881 getaddr(RTA_NETMASK, s, NULL); 882 break; 883 case RTA_NETMASK: 884 su->sa.sa_len = 0; 885 } 886 return (0); 887 } 888 889 switch (afamily) { 890 case AF_INET6: 891 { 892 struct addrinfo hints, *res; 893 char buf[ 894 sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255:255:255:255/128") 895 ]; 896 char *sep; 897 898 if (strlcpy(buf, s, sizeof buf) >= sizeof buf) { 899 errx(1, "%s: bad value", s); 900 } 901 902 sep = strchr(buf, '/'); 903 if (sep != NULL) 904 *sep++ = '\0'; 905 memset(&hints, 0, sizeof(hints)); 906 hints.ai_family = afamily; /*AF_INET6*/ 907 hints.ai_flags = AI_NUMERICHOST; 908 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 909 if (getaddrinfo(buf, "0", &hints, &res) != 0) { 910 hints.ai_flags = 0; 911 if (getaddrinfo(buf, "0", &hints, &res) != 0) 912 errx(1, "%s: bad value", s); 913 } 914 if (sizeof(su->sin6) != res->ai_addrlen) 915 errx(1, "%s: bad value", s); 916 if (res->ai_next) 917 errx(1, "%s: resolved to multiple values", s); 918 memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6)); 919 freeaddrinfo(res); 920 if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) || 921 IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr) || 922 IN6_IS_ADDR_MC_INTFACELOCAL(&su->sin6.sin6_addr)) && 923 su->sin6.sin6_scope_id) { 924 *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] = 925 htons(su->sin6.sin6_scope_id); 926 su->sin6.sin6_scope_id = 0; 927 } 928 if (hints.ai_flags == AI_NUMERICHOST) { 929 if (which == RTA_DST) 930 return (inet6_makenetandmask(&su->sin6, sep)); 931 return (0); 932 } else 933 return (1); 934 } 935 936 case AF_LINK: 937 su->sdl.sdl_index = if_nametoindex(s); 938 memset(&su->sdl.sdl_data, 0, sizeof(su->sdl.sdl_data)); 939 return (1); 940 case AF_MPLS: 941 errx(1, "mpls labels require -in or -out switch"); 942 case PF_ROUTE: 943 su->sa.sa_len = sizeof(*su); 944 sockaddr(s, &su->sa); 945 return (1); 946 947 case AF_INET: 948 if (hpp != NULL) 949 *hpp = NULL; 950 if (which == RTA_DST && !forcehost) { 951 bits = inet_net_pton(AF_INET, s, &su->sin.sin_addr, 952 sizeof(su->sin.sin_addr)); 953 if (bits == 32) 954 return (1); 955 if (bits >= 0) { 956 inet_makenetandmask(ntohl( 957 su->sin.sin_addr.s_addr), 958 &su->sin, bits); 959 return (0); 960 } 961 np = getnetbyname(s); 962 if (np != NULL && np->n_net != 0) { 963 inet_makenetandmask(np->n_net, &su->sin, 0); 964 return (0); 965 } 966 if (forcenet) 967 errx(1, "%s: not a network", s); 968 } 969 if (inet_pton(AF_INET, s, &su->sin.sin_addr) == 1) 970 return (1); 971 hp = gethostbyname(s); 972 if (hp != NULL) { 973 if (hpp != NULL) 974 *hpp = hp; 975 su->sin.sin_addr = *(struct in_addr *)hp->h_addr; 976 return (1); 977 } 978 errx(1, "%s: bad address", s); 979 /* NOTREACHED */ 980 981 default: 982 errx(1, "%d: bad address family", afamily); 983 /* NOTREACHED */ 984 } 985 } 986 987 void 988 getmplslabel(char *s, int in) 989 { 990 sup su = NULL; 991 const char *errstr; 992 u_int32_t label; 993 994 label = strtonum(s, 0, 0x000fffff, &errstr); 995 if (errstr) 996 errx(1, "bad label: %s is %s", s, errstr); 997 if (in) { 998 rtm_addrs |= RTA_DST; 999 su = &so_dst; 1000 su->smpls.smpls_label = htonl(label << MPLS_LABEL_OFFSET); 1001 } else { 1002 rtm_addrs |= RTA_SRC; 1003 su = &so_src; 1004 su->smpls.smpls_label = htonl(label << MPLS_LABEL_OFFSET); 1005 } 1006 1007 su->sa.sa_len = sizeof(struct sockaddr_mpls); 1008 su->sa.sa_family = AF_MPLS; 1009 } 1010 1011 int 1012 prefixlen(char *s) 1013 { 1014 const char *errstr; 1015 int len, q, r; 1016 int max; 1017 1018 switch (af) { 1019 case AF_INET: 1020 max = sizeof(struct in_addr) * 8; 1021 break; 1022 case AF_INET6: 1023 max = sizeof(struct in6_addr) * 8; 1024 break; 1025 default: 1026 errx(1, "prefixlen is not supported with af %d", af); 1027 /* NOTREACHED */ 1028 } 1029 1030 rtm_addrs |= RTA_NETMASK; 1031 len = strtonum(s, 0, max, &errstr); 1032 if (errstr) 1033 errx(1, "prefixlen %s is %s", s, errstr); 1034 1035 q = len >> 3; 1036 r = len & 7; 1037 switch (af) { 1038 case AF_INET: 1039 memset(&so_mask, 0, sizeof(so_mask)); 1040 so_mask.sin.sin_family = AF_INET; 1041 so_mask.sin.sin_len = sizeof(struct sockaddr_in); 1042 so_mask.sin.sin_addr.s_addr = htonl(0xffffffff << (32 - len)); 1043 break; 1044 case AF_INET6: 1045 so_mask.sin6.sin6_family = AF_INET6; 1046 so_mask.sin6.sin6_len = sizeof(struct sockaddr_in6); 1047 memset((void *)&so_mask.sin6.sin6_addr, 0, 1048 sizeof(so_mask.sin6.sin6_addr)); 1049 if (q > 0) 1050 memset((void *)&so_mask.sin6.sin6_addr, 0xff, q); 1051 if (r > 0) 1052 *((u_char *)&so_mask.sin6.sin6_addr + q) = 1053 (0xff00 >> r) & 0xff; 1054 break; 1055 } 1056 return (len == max); 1057 } 1058 1059 void 1060 interfaces(void) 1061 { 1062 size_t needed; 1063 int mib[6]; 1064 char *buf = NULL, *lim, *next; 1065 struct rt_msghdr *rtm; 1066 1067 mib[0] = CTL_NET; 1068 mib[1] = PF_ROUTE; 1069 mib[2] = 0; /* protocol */ 1070 mib[3] = 0; /* wildcard address family */ 1071 mib[4] = NET_RT_IFLIST; 1072 mib[5] = 0; /* no flags */ 1073 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 1074 err(1, "route-sysctl-estimate"); 1075 if (needed) { 1076 if ((buf = malloc(needed)) == NULL) 1077 err(1, "malloc"); 1078 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 1079 err(1, "actual retrieval of interface table"); 1080 lim = buf + needed; 1081 for (next = buf; next < lim; next += rtm->rtm_msglen) { 1082 rtm = (struct rt_msghdr *)next; 1083 print_rtmsg(rtm, rtm->rtm_msglen); 1084 } 1085 free(buf); 1086 } 1087 } 1088 1089 void 1090 monitor(int argc, char *argv[]) 1091 { 1092 int n; 1093 char msg[2048]; 1094 time_t now; 1095 1096 if (pledge("stdio rpath dns", NULL) == -1) 1097 err(1, "pledge"); 1098 1099 verbose = 1; 1100 if (debugonly) { 1101 interfaces(); 1102 exit(0); 1103 } 1104 for (;;) { 1105 if ((n = read(s, msg, sizeof(msg))) == -1) { 1106 if (errno == EINTR) 1107 continue; 1108 err(1, "read"); 1109 } 1110 now = time(NULL); 1111 printf("got message of size %d on %s", n, ctime(&now)); 1112 print_rtmsg((struct rt_msghdr *)msg, n); 1113 } 1114 } 1115 1116 struct { 1117 struct rt_msghdr m_rtm; 1118 char m_space[512]; 1119 } m_rtmsg; 1120 1121 int 1122 rtmsg(int cmd, int flags, int fmask, uint8_t prio) 1123 { 1124 static int seq; 1125 char *cp = m_rtmsg.m_space; 1126 int l; 1127 1128 #define NEXTADDR(w, u) \ 1129 if (rtm_addrs & (w)) { \ 1130 l = ROUNDUP(u.sa.sa_len); \ 1131 memcpy(cp, &(u), l); \ 1132 cp += l; \ 1133 if (verbose) \ 1134 sodump(&(u), #u); \ 1135 } 1136 1137 errno = 0; 1138 memset(&m_rtmsg, 0, sizeof(m_rtmsg)); 1139 if (cmd == 'a') 1140 cmd = RTM_ADD; 1141 else if (cmd == 'c') 1142 cmd = RTM_CHANGE; 1143 else if (cmd == 'g') { 1144 cmd = RTM_GET; 1145 if (so_ifp.sa.sa_family == 0) { 1146 so_ifp.sa.sa_family = AF_LINK; 1147 so_ifp.sa.sa_len = sizeof(struct sockaddr_dl); 1148 rtm_addrs |= RTA_IFP; 1149 } 1150 } else 1151 cmd = RTM_DELETE; 1152 #define rtm m_rtmsg.m_rtm 1153 rtm.rtm_type = cmd; 1154 rtm.rtm_flags = flags; 1155 rtm.rtm_fmask = fmask; 1156 rtm.rtm_version = RTM_VERSION; 1157 rtm.rtm_seq = ++seq; 1158 rtm.rtm_addrs = rtm_addrs; 1159 rtm.rtm_rmx = rt_metrics; 1160 rtm.rtm_inits = rtm_inits; 1161 rtm.rtm_tableid = tableid; 1162 rtm.rtm_priority = prio; 1163 rtm.rtm_mpls = mpls_flags; 1164 rtm.rtm_hdrlen = sizeof(rtm); 1165 1166 if (rtm_addrs & RTA_NETMASK) 1167 mask_addr(&so_dst, &so_mask, RTA_DST); 1168 NEXTADDR(RTA_DST, so_dst); 1169 NEXTADDR(RTA_GATEWAY, so_gate); 1170 NEXTADDR(RTA_NETMASK, so_mask); 1171 NEXTADDR(RTA_IFP, so_ifp); 1172 NEXTADDR(RTA_IFA, so_ifa); 1173 NEXTADDR(RTA_LABEL, so_label); 1174 NEXTADDR(RTA_SRC, so_src); 1175 rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 1176 if (verbose) 1177 print_rtmsg(&rtm, l); 1178 if (debugonly) 1179 return (0); 1180 if (write(s, &m_rtmsg, l) != l) { 1181 return (-1); 1182 } 1183 if (cmd == RTM_GET) { 1184 do { 1185 l = read(s, &m_rtmsg, sizeof(m_rtmsg)); 1186 } while (l > 0 && (rtm.rtm_version != RTM_VERSION || 1187 rtm.rtm_seq != seq || rtm.rtm_pid != pid)); 1188 if (l == -1) 1189 warn("read from routing socket"); 1190 else 1191 print_getmsg(&rtm, l); 1192 } 1193 #undef rtm 1194 return (0); 1195 } 1196 1197 void 1198 mask_addr(union sockunion *addr, union sockunion *mask, int which) 1199 { 1200 int olen = mask->sa.sa_len; 1201 char *cp1 = olen + (char *)mask, *cp2; 1202 1203 for (mask->sa.sa_len = 0; cp1 > (char *)mask; ) 1204 if (*--cp1 != '\0') { 1205 mask->sa.sa_len = 1 + cp1 - (char *)mask; 1206 break; 1207 } 1208 if ((rtm_addrs & which) == 0) 1209 return; 1210 switch (addr->sa.sa_family) { 1211 case AF_INET: 1212 case AF_INET6: 1213 case 0: 1214 return; 1215 } 1216 cp1 = mask->sa.sa_len + 1 + (char *)addr; 1217 cp2 = addr->sa.sa_len + 1 + (char *)addr; 1218 while (cp2 > cp1) 1219 *--cp2 = '\0'; 1220 cp2 = mask->sa.sa_len + 1 + (char *)mask; 1221 while (cp1 > addr->sa.sa_data) 1222 *--cp1 &= *--cp2; 1223 } 1224 1225 char *msgtypes[] = { 1226 "", 1227 "RTM_ADD: Add Route", 1228 "RTM_DELETE: Delete Route", 1229 "RTM_CHANGE: Change Metrics or flags", 1230 "RTM_GET: Report Metrics", 1231 "RTM_LOSING: Kernel Suspects Partitioning", 1232 "RTM_REDIRECT: Told to use different route", 1233 "RTM_MISS: Lookup failed on this address", 1234 "RTM_LOCK: fix specified metrics", 1235 "RTM_OLDADD: caused by SIOCADDRT", 1236 "RTM_OLDDEL: caused by SIOCDELRT", 1237 "RTM_RESOLVE: Route created by cloning", 1238 "RTM_NEWADDR: address being added to iface", 1239 "RTM_DELADDR: address being removed from iface", 1240 "RTM_IFINFO: iface status change", 1241 "RTM_IFANNOUNCE: iface arrival/departure", 1242 "RTM_DESYNC: route socket overflow", 1243 "RTM_INVALIDATE: invalidate cache of L2 route", 1244 "RTM_BFD: bidirectional forwarding detection", 1245 }; 1246 1247 char metricnames[] = 1248 "\011priority\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu"; 1249 char routeflags[] = 1250 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010XMASK_PRESENT" 1251 "\011CLONING\012MULTICAST\013LLINFO\014STATIC\015BLACKHOLE\016PROTO3\017PROTO2" 1252 "\020PROTO1\021CLONED\022CACHED\023MPATH\025MPLS\026LOCAL\027BROADCAST" 1253 "\030CONNECTED\031BFD"; 1254 char ifnetflags[] = 1255 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP\011PPROMISC" 1256 "\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2\020MULTICAST"; 1257 char addrnames[] = 1258 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC\12SRCMASK\013LABEL"; 1259 1260 const char * 1261 get_linkstate(int mt, int link_state) 1262 { 1263 const struct if_status_description *p; 1264 static char buf[8]; 1265 1266 for (p = if_status_descriptions; p->ifs_string != NULL; p++) { 1267 if (LINK_STATE_DESC_MATCH(p, mt, link_state)) 1268 return (p->ifs_string); 1269 } 1270 snprintf(buf, sizeof(buf), "[#%d]", link_state); 1271 return buf; 1272 } 1273 1274 void 1275 print_rtmsg(struct rt_msghdr *rtm, int msglen) 1276 { 1277 long long relative_expire; 1278 struct if_msghdr *ifm; 1279 struct ifa_msghdr *ifam; 1280 struct if_announcemsghdr *ifan; 1281 char ifname[IF_NAMESIZE]; 1282 1283 if (verbose == 0) 1284 return; 1285 if (rtm->rtm_version != RTM_VERSION) { 1286 warnx("routing message version %d not understood", 1287 rtm->rtm_version); 1288 return; 1289 } 1290 if (rtm->rtm_type > 0 && 1291 rtm->rtm_type < sizeof(msgtypes)/sizeof(msgtypes[0])) 1292 printf("%s", msgtypes[rtm->rtm_type]); 1293 else 1294 printf("[rtm_type %d out of range]", rtm->rtm_type); 1295 1296 printf(": len %d", rtm->rtm_msglen); 1297 switch (rtm->rtm_type) { 1298 case RTM_DESYNC: 1299 printf("\n"); 1300 break; 1301 case RTM_IFINFO: 1302 ifm = (struct if_msghdr *)rtm; 1303 (void) printf(", if# %d, ", ifm->ifm_index); 1304 if (if_indextoname(ifm->ifm_index, ifname) != NULL) 1305 printf("name: %s, ", ifname); 1306 printf("link: %s, flags:", 1307 get_linkstate(ifm->ifm_data.ifi_type, 1308 ifm->ifm_data.ifi_link_state)); 1309 bprintf(stdout, ifm->ifm_flags, ifnetflags); 1310 pmsg_addrs((char *)ifm + ifm->ifm_hdrlen, ifm->ifm_addrs); 1311 break; 1312 case RTM_NEWADDR: 1313 case RTM_DELADDR: 1314 ifam = (struct ifa_msghdr *)rtm; 1315 printf(", metric %d, flags:", ifam->ifam_metric); 1316 bprintf(stdout, ifam->ifam_flags, routeflags); 1317 pmsg_addrs((char *)ifam + ifam->ifam_hdrlen, ifam->ifam_addrs); 1318 break; 1319 case RTM_IFANNOUNCE: 1320 ifan = (struct if_announcemsghdr *)rtm; 1321 printf(", if# %d, name %s, what: ", 1322 ifan->ifan_index, ifan->ifan_name); 1323 switch (ifan->ifan_what) { 1324 case IFAN_ARRIVAL: 1325 printf("arrival"); 1326 break; 1327 case IFAN_DEPARTURE: 1328 printf("departure"); 1329 break; 1330 default: 1331 printf("#%d", ifan->ifan_what); 1332 break; 1333 } 1334 printf("\n"); 1335 break; 1336 case RTM_BFD: 1337 printf("bfd\n"); /* XXX - expand*/ 1338 break; 1339 default: 1340 printf(", priority %d, table %u, ifidx %u, ", 1341 rtm->rtm_priority, rtm->rtm_tableid, rtm->rtm_index); 1342 printf("pid: %ld, seq %d, errno %d\nflags:", 1343 (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 1344 bprintf(stdout, rtm->rtm_flags, routeflags); 1345 printf("\nfmask:"); 1346 bprintf(stdout, rtm->rtm_fmask, routeflags); 1347 if (verbose) { 1348 #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') 1349 relative_expire = rtm->rtm_rmx.rmx_expire ? 1350 rtm->rtm_rmx.rmx_expire - time(NULL) : 0; 1351 printf("\nuse: %8llu mtu: %8u%c expire: %8lld%c", 1352 rtm->rtm_rmx.rmx_pksent, 1353 rtm->rtm_rmx.rmx_mtu, lock(MTU), 1354 relative_expire, lock(EXPIRE)); 1355 #undef lock 1356 } 1357 pmsg_common(rtm); 1358 } 1359 } 1360 1361 char * 1362 priorityname(uint8_t prio) 1363 { 1364 switch (prio) { 1365 case RTP_NONE: 1366 return ("none"); 1367 case RTP_LOCAL: 1368 return ("local"); 1369 case RTP_CONNECTED: 1370 return ("connected"); 1371 case RTP_STATIC: 1372 return ("static"); 1373 case RTP_OSPF: 1374 return ("ospf"); 1375 case RTP_ISIS: 1376 return ("is-is"); 1377 case RTP_RIP: 1378 return ("rip"); 1379 case RTP_BGP: 1380 return ("bgp"); 1381 case RTP_DEFAULT: 1382 return ("default"); 1383 default: 1384 return (""); 1385 } 1386 } 1387 1388 uint8_t 1389 getpriority(char *priostr) 1390 { 1391 const char *errstr; 1392 uint8_t prio; 1393 1394 switch (keyword(priostr)) { 1395 case K_LOCAL: 1396 prio = RTP_LOCAL; 1397 break; 1398 case K_CONNECTED: 1399 prio = RTP_CONNECTED; 1400 break; 1401 case K_STATIC: 1402 prio = RTP_STATIC; 1403 break; 1404 case K_OSPF: 1405 prio = RTP_OSPF; 1406 break; 1407 case K_RIP: 1408 prio = RTP_RIP; 1409 break; 1410 case K_BGP: 1411 prio = RTP_BGP; 1412 break; 1413 default: 1414 prio = strtonum(priostr, -RTP_MAX, RTP_MAX, &errstr); 1415 if (errstr) 1416 errx(1, "priority is %s: %s", errstr, priostr); 1417 } 1418 1419 return (prio); 1420 } 1421 1422 void 1423 print_getmsg(struct rt_msghdr *rtm, int msglen) 1424 { 1425 long long relative_expire; 1426 struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *ifa = NULL; 1427 struct sockaddr_dl *ifp = NULL; 1428 struct sockaddr_rtlabel *sa_rl = NULL; 1429 struct sockaddr *mpls = NULL; 1430 struct sockaddr *sa; 1431 char *cp; 1432 int i; 1433 1434 printf(" route to: %s\n", routename(&so_dst.sa)); 1435 if (rtm->rtm_version != RTM_VERSION) { 1436 warnx("routing message version %d not understood", 1437 rtm->rtm_version); 1438 return; 1439 } 1440 if (rtm->rtm_msglen > msglen) 1441 warnx("message length mismatch, in packet %d, returned %d", 1442 rtm->rtm_msglen, msglen); 1443 if (rtm->rtm_errno) { 1444 warnx("RTM_GET: %s (errno %d)", 1445 strerror(rtm->rtm_errno), rtm->rtm_errno); 1446 return; 1447 } 1448 cp = ((char *)rtm + rtm->rtm_hdrlen); 1449 if (rtm->rtm_addrs) 1450 for (i = 1; i; i <<= 1) 1451 if (i & rtm->rtm_addrs) { 1452 sa = (struct sockaddr *)cp; 1453 switch (i) { 1454 case RTA_DST: 1455 dst = sa; 1456 break; 1457 case RTA_GATEWAY: 1458 gate = sa; 1459 break; 1460 case RTA_NETMASK: 1461 mask = sa; 1462 break; 1463 case RTA_IFA: 1464 ifa = sa; 1465 break; 1466 case RTA_IFP: 1467 if (sa->sa_family == AF_LINK && 1468 ((struct sockaddr_dl *)sa)->sdl_nlen) 1469 ifp = (struct sockaddr_dl *)sa; 1470 break; 1471 case RTA_SRC: 1472 mpls = sa; 1473 break; 1474 case RTA_LABEL: 1475 sa_rl = (struct sockaddr_rtlabel *)sa; 1476 break; 1477 } 1478 ADVANCE(cp, sa); 1479 } 1480 if (dst && mask) 1481 mask->sa_family = dst->sa_family; /* XXX */ 1482 if (dst) 1483 printf("destination: %s\n", routename(dst)); 1484 if (mask) { 1485 int savenflag = nflag; 1486 1487 nflag = 1; 1488 printf(" mask: %s\n", routename(mask)); 1489 nflag = savenflag; 1490 } 1491 if (gate && rtm->rtm_flags & RTF_GATEWAY) 1492 printf(" gateway: %s\n", routename(gate)); 1493 if (ifp) 1494 printf(" interface: %.*s\n", 1495 ifp->sdl_nlen, ifp->sdl_data); 1496 if (ifa) 1497 printf(" if address: %s\n", routename(ifa)); 1498 if (mpls) { 1499 printf(" mpls label: %s %s\n", mpls_op(rtm->rtm_mpls), 1500 routename(mpls)); 1501 } 1502 printf(" priority: %u (%s)\n", rtm->rtm_priority, 1503 priorityname(rtm->rtm_priority)); 1504 printf(" flags: "); 1505 bprintf(stdout, rtm->rtm_flags, routeflags); 1506 printf("\n"); 1507 if (sa_rl != NULL) 1508 printf(" label: %s\n", sa_rl->sr_label); 1509 1510 #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') 1511 relative_expire = rtm->rtm_rmx.rmx_expire ? 1512 rtm->rtm_rmx.rmx_expire - time(NULL) : 0; 1513 printf(" use mtu expire\n"); 1514 printf("%8llu %8u%c %8lld%c\n", 1515 rtm->rtm_rmx.rmx_pksent, 1516 rtm->rtm_rmx.rmx_mtu, lock(MTU), 1517 relative_expire, lock(EXPIRE)); 1518 #undef lock 1519 #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD) 1520 if (verbose) 1521 pmsg_common(rtm); 1522 else if (rtm->rtm_addrs &~ RTA_IGN) { 1523 printf("sockaddrs: "); 1524 bprintf(stdout, rtm->rtm_addrs, addrnames); 1525 putchar('\n'); 1526 } 1527 #undef RTA_IGN 1528 } 1529 1530 void 1531 pmsg_common(struct rt_msghdr *rtm) 1532 { 1533 printf("\nlocks: "); 1534 bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames); 1535 printf(" inits: "); 1536 bprintf(stdout, rtm->rtm_inits, metricnames); 1537 pmsg_addrs(((char *)rtm + rtm->rtm_hdrlen), rtm->rtm_addrs); 1538 } 1539 1540 void 1541 pmsg_addrs(char *cp, int addrs) 1542 { 1543 struct sockaddr *sa; 1544 int family = AF_UNSPEC; 1545 int i; 1546 char *p; 1547 1548 if (addrs != 0) { 1549 printf("\nsockaddrs: "); 1550 bprintf(stdout, addrs, addrnames); 1551 putchar('\n'); 1552 /* first run, search for address family */ 1553 p = cp; 1554 for (i = 1; i; i <<= 1) 1555 if (i & addrs) { 1556 sa = (struct sockaddr *)p; 1557 if (family == AF_UNSPEC) 1558 switch (i) { 1559 case RTA_DST: 1560 case RTA_IFA: 1561 family = sa->sa_family; 1562 } 1563 ADVANCE(p, sa); 1564 } 1565 /* second run, set address family for mask and print */ 1566 p = cp; 1567 for (i = 1; i; i <<= 1) 1568 if (i & addrs) { 1569 sa = (struct sockaddr *)p; 1570 if (family != AF_UNSPEC) 1571 switch (i) { 1572 case RTA_NETMASK: 1573 sa->sa_family = family; 1574 } 1575 printf(" %s", routename(sa)); 1576 ADVANCE(p, sa); 1577 } 1578 } 1579 putchar('\n'); 1580 fflush(stdout); 1581 } 1582 1583 void 1584 bprintf(FILE *fp, int b, char *s) 1585 { 1586 int i; 1587 int gotsome = 0; 1588 1589 if (b == 0) 1590 return; 1591 while ((i = *s++)) { 1592 if ((b & (1 << (i-1)))) { 1593 if (gotsome == 0) 1594 i = '<'; 1595 else 1596 i = ','; 1597 putc(i, fp); 1598 gotsome = 1; 1599 for (; (i = *s) > 32; s++) 1600 putc(i, fp); 1601 } else 1602 while (*s > 32) 1603 s++; 1604 } 1605 if (gotsome) 1606 putc('>', fp); 1607 } 1608 1609 int 1610 keycmp(const void *key, const void *kt) 1611 { 1612 return (strcmp(key, ((struct keytab *)kt)->kt_cp)); 1613 } 1614 1615 int 1616 keyword(char *cp) 1617 { 1618 struct keytab *kt; 1619 1620 kt = bsearch(cp, keywords, sizeof(keywords)/sizeof(keywords[0]), 1621 sizeof(keywords[0]), keycmp); 1622 if (!kt) 1623 return (0); 1624 1625 return (kt->kt_i); 1626 } 1627 1628 void 1629 sodump(sup su, char *which) 1630 { 1631 switch (su->sa.sa_family) { 1632 case AF_LINK: 1633 printf("%s: link %s; ", which, link_ntoa(&su->sdl)); 1634 break; 1635 case AF_INET: 1636 printf("%s: inet %s; ", which, inet_ntoa(su->sin.sin_addr)); 1637 break; 1638 case AF_INET6: 1639 { 1640 char ntop_buf[NI_MAXHOST]; 1641 1642 printf("%s: inet6 %s; ", 1643 which, inet_ntop(AF_INET6, &su->sin6.sin6_addr, 1644 ntop_buf, sizeof(ntop_buf))); 1645 break; 1646 } 1647 } 1648 fflush(stdout); 1649 } 1650 1651 /* States*/ 1652 #define VIRGIN 0 1653 #define GOTONE 1 1654 #define GOTTWO 2 1655 /* Inputs */ 1656 #define DIGIT (4*0) 1657 #define END (4*1) 1658 #define DELIM (4*2) 1659 1660 void 1661 sockaddr(char *addr, struct sockaddr *sa) 1662 { 1663 char *cp = (char *)sa; 1664 int size = sa->sa_len; 1665 char *cplim = cp + size; 1666 int byte = 0, state = VIRGIN, new = 0; 1667 1668 memset(cp, 0, size); 1669 cp++; 1670 do { 1671 if ((*addr >= '0') && (*addr <= '9')) { 1672 new = *addr - '0'; 1673 } else if ((*addr >= 'a') && (*addr <= 'f')) { 1674 new = *addr - 'a' + 10; 1675 } else if ((*addr >= 'A') && (*addr <= 'F')) { 1676 new = *addr - 'A' + 10; 1677 } else if (*addr == '\0') 1678 state |= END; 1679 else 1680 state |= DELIM; 1681 addr++; 1682 switch (state /* | INPUT */) { 1683 case GOTTWO | DIGIT: 1684 *cp++ = byte; /*FALLTHROUGH*/ 1685 case VIRGIN | DIGIT: 1686 state = GOTONE; byte = new; continue; 1687 case GOTONE | DIGIT: 1688 state = GOTTWO; byte = new + (byte << 4); continue; 1689 default: /* | DELIM */ 1690 state = VIRGIN; *cp++ = byte; byte = 0; continue; 1691 case GOTONE | END: 1692 case GOTTWO | END: 1693 *cp++ = byte; /* FALLTHROUGH */ 1694 case VIRGIN | END: 1695 break; 1696 } 1697 break; 1698 } while (cp < cplim); 1699 sa->sa_len = cp - (char *)sa; 1700 } 1701 1702 void 1703 getlabel(char *name) 1704 { 1705 so_label.rtlabel.sr_len = sizeof(so_label.rtlabel); 1706 so_label.rtlabel.sr_family = AF_UNSPEC; 1707 if (strlcpy(so_label.rtlabel.sr_label, name, 1708 sizeof(so_label.rtlabel.sr_label)) >= 1709 sizeof(so_label.rtlabel.sr_label)) 1710 errx(1, "label too long"); 1711 rtm_addrs |= RTA_LABEL; 1712 } 1713 1714 int 1715 gettable(const char *s) 1716 { 1717 const char *errstr; 1718 struct rt_tableinfo info; 1719 int mib[6]; 1720 size_t len; 1721 1722 tableid = strtonum(s, 0, RT_TABLEID_MAX, &errstr); 1723 if (errstr) 1724 errx(1, "invalid table id: %s", errstr); 1725 1726 mib[0] = CTL_NET; 1727 mib[1] = PF_ROUTE; 1728 mib[2] = 0; 1729 mib[3] = 0; 1730 mib[4] = NET_RT_TABLE; 1731 mib[5] = tableid; 1732 1733 len = sizeof(info); 1734 if (sysctl(mib, 6, &info, &len, NULL, 0) == -1) 1735 return (errno); 1736 else 1737 return (0); 1738 } 1739 1740 int 1741 rdomain(int argc, char **argv) 1742 { 1743 if (!argc) 1744 usage(NULL); 1745 if (setrtable(tableid) == -1) 1746 err(1, "setrtable"); 1747 execvp(*argv, argv); 1748 warn("%s", argv[0]); 1749 return (errno == ENOENT ? 127 : 126); 1750 } 1751