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