1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1983, 1989, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #ifndef lint 33 static const char copyright[] = 34 "@(#) Copyright (c) 1983, 1989, 1991, 1993\n\ 35 The Regents of the University of California. All rights reserved.\n"; 36 #endif /* not lint */ 37 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)route.c 8.6 (Berkeley) 4/28/95"; 41 #endif 42 #endif /* not lint */ 43 44 #include <sys/cdefs.h> 45 __FBSDID("$FreeBSD$"); 46 47 #include <sys/param.h> 48 #include <sys/file.h> 49 #include <sys/socket.h> 50 #include <sys/ioctl.h> 51 #ifdef JAIL 52 #include <sys/jail.h> 53 #endif 54 #include <sys/sysctl.h> 55 #include <sys/types.h> 56 #include <sys/queue.h> 57 58 #include <net/if.h> 59 #include <net/route.h> 60 #include <net/if_dl.h> 61 #include <netinet/in.h> 62 #include <netinet/if_ether.h> 63 #include <arpa/inet.h> 64 #include <netdb.h> 65 66 #include <ctype.h> 67 #include <err.h> 68 #include <errno.h> 69 #ifdef JAIL 70 #include <jail.h> 71 #endif 72 #include <paths.h> 73 #include <signal.h> 74 #include <stdbool.h> 75 #include <stdio.h> 76 #include <stdlib.h> 77 #include <string.h> 78 #include <sysexits.h> 79 #include <time.h> 80 #include <unistd.h> 81 #include <ifaddrs.h> 82 83 struct fibl { 84 TAILQ_ENTRY(fibl) fl_next; 85 86 int fl_num; 87 int fl_error; 88 int fl_errno; 89 }; 90 91 static struct keytab { 92 const char *kt_cp; 93 int kt_i; 94 } const keywords[] = { 95 #include "keywords.h" 96 {0, 0} 97 }; 98 99 int verbose, debugonly; 100 #ifdef JAIL 101 char * jail_name; 102 #endif 103 static struct sockaddr_storage so[RTAX_MAX]; 104 static int pid, rtm_addrs; 105 static int nflag, af, aflen, qflag, tflag; 106 static int locking, lockrest; 107 static struct rt_metrics rt_metrics; 108 static u_long rtm_inits; 109 static uid_t uid; 110 static int defaultfib; 111 static int numfibs; 112 static char domain[MAXHOSTNAMELEN + 1]; 113 static bool domain_initialized; 114 static char rt_line[NI_MAXHOST]; 115 static char net_line[MAXHOSTNAMELEN + 1]; 116 117 #ifdef WITHOUT_NETLINK 118 static int s; 119 static int rtm_seq; 120 121 static struct { 122 struct rt_msghdr m_rtm; 123 char m_space[512]; 124 } m_rtmsg; 125 126 static int rtmsg_rtsock(int, int, int); 127 static int flushroutes_fib_rtsock(int); 128 static void monitor_rtsock(void); 129 #else 130 int rtmsg_nl(int, int, int, int, struct sockaddr_storage *, struct rt_metrics *); 131 int flushroutes_fib_nl(int, int); 132 void monitor_nl(int); 133 #endif 134 135 static TAILQ_HEAD(fibl_head_t, fibl) fibl_head; 136 137 void printb(int, const char *); 138 static void flushroutes(int argc, char *argv[]); 139 static int flushroutes_fib(int); 140 static int getaddr(int, char *, int); 141 static int keyword(const char *); 142 #ifdef INET 143 static void inet_makemask(struct sockaddr_in *, u_long); 144 #endif 145 #ifdef INET6 146 static int inet6_makenetandmask(struct sockaddr_in6 *, const char *); 147 #endif 148 static void interfaces(void); 149 static void monitor(int, char*[]); 150 const char *netname(struct sockaddr *); 151 static void newroute(int, char **); 152 static int newroute_fib(int, char *, int); 153 static void pmsg_addrs(char *, int, size_t); 154 static void pmsg_common(struct rt_msghdr *, size_t); 155 static int prefixlen(const char *); 156 static void print_getmsg(struct rt_msghdr *, int, int); 157 static void print_rtmsg(struct rt_msghdr *, size_t); 158 const char *routename(struct sockaddr *); 159 static int rtmsg(int, int, int); 160 static void set_metric(char *, int); 161 static int set_sofib(int); 162 static void sockaddr(char *, struct sockaddr *, size_t); 163 static void sodump(struct sockaddr *, const char *); 164 static int fiboptlist_csv(const char *, struct fibl_head_t *); 165 static int fiboptlist_range(const char *, struct fibl_head_t *); 166 167 static void usage(const char *) __dead2; 168 169 #define READ_TIMEOUT 10 170 static volatile sig_atomic_t stop_read; 171 172 static void 173 stopit(int sig __unused) 174 { 175 176 stop_read = 1; 177 } 178 179 static void 180 usage(const char *cp) 181 { 182 if (cp != NULL) 183 warnx("bad keyword: %s", cp); 184 errx(EX_USAGE, "usage: route [-j jail] [-46dnqtv] command [[modifiers] args]"); 185 /* NOTREACHED */ 186 } 187 188 int 189 main(int argc, char **argv) 190 { 191 int ch; 192 #ifdef JAIL 193 int jid; 194 #endif 195 size_t len; 196 197 if (argc < 2) 198 usage(NULL); 199 200 while ((ch = getopt(argc, argv, "46nqdtvj:")) != -1) 201 switch(ch) { 202 case '4': 203 #ifdef INET 204 af = AF_INET; 205 aflen = sizeof(struct sockaddr_in); 206 #else 207 errx(1, "IPv4 support is not compiled in"); 208 #endif 209 break; 210 case '6': 211 #ifdef INET6 212 af = AF_INET6; 213 aflen = sizeof(struct sockaddr_in6); 214 #else 215 errx(1, "IPv6 support is not compiled in"); 216 #endif 217 break; 218 case 'n': 219 nflag = 1; 220 break; 221 case 'q': 222 qflag = 1; 223 break; 224 case 'v': 225 verbose = 1; 226 break; 227 case 't': 228 tflag = 1; 229 break; 230 case 'd': 231 debugonly = 1; 232 break; 233 case 'j': 234 #ifdef JAIL 235 if (optarg == NULL) 236 usage(NULL); 237 jail_name = optarg; 238 #else 239 errx(1, "Jail support is not compiled in"); 240 #endif 241 break; 242 case '?': 243 default: 244 usage(NULL); 245 } 246 argc -= optind; 247 argv += optind; 248 249 pid = getpid(); 250 uid = geteuid(); 251 252 #ifdef JAIL 253 if (jail_name != NULL) { 254 jid = jail_getid(jail_name); 255 if (jid == -1) 256 errx(1, "Jail not found"); 257 if (jail_attach(jid) != 0) 258 errx(1, "Cannot attach to jail"); 259 } 260 #endif 261 262 #ifdef WITHOUT_NETLINK 263 if (tflag) 264 s = open(_PATH_DEVNULL, O_WRONLY, 0); 265 else 266 s = socket(PF_ROUTE, SOCK_RAW, 0); 267 if (s < 0) 268 err(EX_OSERR, "socket"); 269 #endif 270 271 len = sizeof(numfibs); 272 if (sysctlbyname("net.fibs", (void *)&numfibs, &len, NULL, 0) == -1) 273 numfibs = -1; 274 275 len = sizeof(defaultfib); 276 if (numfibs != -1 && 277 sysctlbyname("net.my_fibnum", (void *)&defaultfib, &len, NULL, 278 0) == -1) 279 defaultfib = -1; 280 281 if (*argv != NULL) 282 switch (keyword(*argv)) { 283 case K_GET: 284 case K_SHOW: 285 uid = 0; 286 /* FALLTHROUGH */ 287 288 case K_CHANGE: 289 case K_ADD: 290 case K_DEL: 291 case K_DELETE: 292 newroute(argc, argv); 293 /* NOTREACHED */ 294 295 case K_MONITOR: 296 monitor(argc, argv); 297 /* NOTREACHED */ 298 299 case K_FLUSH: 300 flushroutes(argc, argv); 301 exit(0); 302 /* NOTREACHED */ 303 } 304 usage(*argv); 305 /* NOTREACHED */ 306 } 307 308 static int 309 set_sofib(int fib) 310 { 311 312 #ifdef WITHOUT_NETLINK 313 if (fib < 0) 314 return (0); 315 return (setsockopt(s, SOL_SOCKET, SO_SETFIB, (void *)&fib, 316 sizeof(fib))); 317 #else 318 return (0); 319 #endif 320 } 321 322 static int 323 fiboptlist_range(const char *arg, struct fibl_head_t *flh) 324 { 325 struct fibl *fl; 326 char *str0, *str, *token, *endptr; 327 int fib[2], i, error; 328 329 str0 = str = strdup(arg); 330 error = 0; 331 i = 0; 332 while ((token = strsep(&str, "-")) != NULL) { 333 switch (i) { 334 case 0: 335 case 1: 336 errno = 0; 337 fib[i] = strtol(token, &endptr, 0); 338 if (errno == 0) { 339 if (*endptr != '\0' || 340 fib[i] < 0 || 341 (numfibs != -1 && fib[i] > numfibs - 1)) 342 errno = EINVAL; 343 } 344 if (errno) 345 error = 1; 346 break; 347 default: 348 error = 1; 349 } 350 if (error) 351 goto fiboptlist_range_ret; 352 i++; 353 } 354 if (fib[0] >= fib[1]) { 355 error = 1; 356 goto fiboptlist_range_ret; 357 } 358 for (i = fib[0]; i <= fib[1]; i++) { 359 fl = calloc(1, sizeof(*fl)); 360 if (fl == NULL) { 361 error = 1; 362 goto fiboptlist_range_ret; 363 } 364 fl->fl_num = i; 365 TAILQ_INSERT_TAIL(flh, fl, fl_next); 366 } 367 fiboptlist_range_ret: 368 free(str0); 369 return (error); 370 } 371 372 #define ALLSTRLEN 64 373 static int 374 fiboptlist_csv(const char *arg, struct fibl_head_t *flh) 375 { 376 struct fibl *fl; 377 char *str0, *str, *token, *endptr; 378 int fib, error; 379 380 str0 = str = NULL; 381 if (strcmp("all", arg) == 0) { 382 str = calloc(1, ALLSTRLEN); 383 if (str == NULL) { 384 error = 1; 385 goto fiboptlist_csv_ret; 386 } 387 if (numfibs > 1) 388 snprintf(str, ALLSTRLEN - 1, "%d-%d", 0, numfibs - 1); 389 else 390 snprintf(str, ALLSTRLEN - 1, "%d", 0); 391 } else if (strcmp("default", arg) == 0) { 392 str0 = str = calloc(1, ALLSTRLEN); 393 if (str == NULL) { 394 error = 1; 395 goto fiboptlist_csv_ret; 396 } 397 snprintf(str, ALLSTRLEN - 1, "%d", defaultfib); 398 } else 399 str0 = str = strdup(arg); 400 401 error = 0; 402 while ((token = strsep(&str, ",")) != NULL) { 403 if (*token != '-' && strchr(token, '-') != NULL) { 404 error = fiboptlist_range(token, flh); 405 if (error) 406 goto fiboptlist_csv_ret; 407 } else { 408 errno = 0; 409 fib = strtol(token, &endptr, 0); 410 if (errno == 0) { 411 if (*endptr != '\0' || 412 fib < 0 || 413 (numfibs != -1 && fib > numfibs - 1)) 414 errno = EINVAL; 415 } 416 if (errno) { 417 error = 1; 418 goto fiboptlist_csv_ret; 419 } 420 fl = calloc(1, sizeof(*fl)); 421 if (fl == NULL) { 422 error = 1; 423 goto fiboptlist_csv_ret; 424 } 425 fl->fl_num = fib; 426 TAILQ_INSERT_TAIL(flh, fl, fl_next); 427 } 428 } 429 fiboptlist_csv_ret: 430 if (str0 != NULL) 431 free(str0); 432 return (error); 433 } 434 435 /* 436 * Purge all entries in the routing tables not 437 * associated with network interfaces. 438 */ 439 static void 440 flushroutes(int argc, char *argv[]) 441 { 442 struct fibl *fl; 443 int error; 444 445 if (uid != 0 && !debugonly && !tflag) 446 errx(EX_NOPERM, "must be root to alter routing table"); 447 #ifdef WITHOUT_NETLINK 448 shutdown(s, SHUT_RD); /* Don't want to read back our messages */ 449 #endif 450 451 TAILQ_INIT(&fibl_head); 452 while (argc > 1) { 453 argc--; 454 argv++; 455 if (**argv != '-') 456 usage(*argv); 457 switch (keyword(*argv + 1)) { 458 #ifdef INET 459 case K_4: 460 case K_INET: 461 af = AF_INET; 462 break; 463 #endif 464 #ifdef INET6 465 case K_6: 466 case K_INET6: 467 af = AF_INET6; 468 break; 469 #endif 470 case K_LINK: 471 af = AF_LINK; 472 break; 473 case K_FIB: 474 if (!--argc) 475 usage(*argv); 476 error = fiboptlist_csv(*++argv, &fibl_head); 477 if (error) 478 errx(EX_USAGE, "invalid fib number: %s", *argv); 479 break; 480 default: 481 usage(*argv); 482 } 483 } 484 if (TAILQ_EMPTY(&fibl_head)) { 485 error = fiboptlist_csv("default", &fibl_head); 486 if (error) 487 errx(EX_OSERR, "fiboptlist_csv failed."); 488 } 489 TAILQ_FOREACH(fl, &fibl_head, fl_next) 490 flushroutes_fib(fl->fl_num); 491 } 492 493 static int 494 flushroutes_fib(int fib) 495 { 496 #ifdef WITHOUT_NETLINK 497 return (flushroutes_fib_rtsock(fib)); 498 #else 499 return (flushroutes_fib_nl(fib, af)); 500 #endif 501 } 502 503 #ifdef WITHOUT_NETLINK 504 static int 505 flushroutes_fib_rtsock(int fib) 506 { 507 struct rt_msghdr *rtm; 508 size_t needed; 509 char *buf, *next, *lim; 510 int mib[7], rlen, seqno, count = 0; 511 int error; 512 513 error = set_sofib(fib); 514 if (error) { 515 warn("fib number %d is ignored", fib); 516 return (error); 517 } 518 519 retry: 520 mib[0] = CTL_NET; 521 mib[1] = PF_ROUTE; 522 mib[2] = 0; /* protocol */ 523 mib[3] = AF_UNSPEC; 524 mib[4] = NET_RT_DUMP; 525 mib[5] = 0; /* no flags */ 526 mib[6] = fib; 527 if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0) 528 err(EX_OSERR, "route-sysctl-estimate"); 529 if ((buf = malloc(needed)) == NULL) 530 errx(EX_OSERR, "malloc failed"); 531 if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) { 532 if (errno == ENOMEM && count++ < 10) { 533 warnx("Routing table grew, retrying"); 534 sleep(1); 535 free(buf); 536 goto retry; 537 } 538 err(EX_OSERR, "route-sysctl-get"); 539 } 540 lim = buf + needed; 541 if (verbose) 542 (void)printf("Examining routing table from sysctl\n"); 543 seqno = 0; /* ??? */ 544 for (next = buf; next < lim; next += rtm->rtm_msglen) { 545 rtm = (struct rt_msghdr *)(void *)next; 546 if (verbose) 547 print_rtmsg(rtm, rtm->rtm_msglen); 548 if ((rtm->rtm_flags & RTF_GATEWAY) == 0) 549 continue; 550 if (af != 0) { 551 struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 552 553 if (sa->sa_family != af) 554 continue; 555 } 556 if (debugonly) 557 continue; 558 rtm->rtm_type = RTM_DELETE; 559 rtm->rtm_seq = seqno; 560 rlen = write(s, next, rtm->rtm_msglen); 561 if (rlen < 0 && errno == EPERM) 562 err(1, "write to routing socket"); 563 if (rlen < (int)rtm->rtm_msglen) { 564 warn("write to routing socket"); 565 (void)printf("got only %d for rlen\n", rlen); 566 free(buf); 567 goto retry; 568 break; 569 } 570 seqno++; 571 if (qflag) 572 continue; 573 if (verbose) 574 print_rtmsg(rtm, rlen); 575 else { 576 struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 577 578 printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ? 579 routename(sa) : netname(sa)); 580 sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa); 581 printf("%-20.20s ", routename(sa)); 582 if (fib >= 0) 583 printf("-fib %-3d ", fib); 584 printf("done\n"); 585 } 586 } 587 free(buf); 588 return (error); 589 } 590 #endif 591 592 const char * 593 routename(struct sockaddr *sa) 594 { 595 struct sockaddr_dl *sdl; 596 const char *cp; 597 int n; 598 599 if (!domain_initialized) { 600 domain_initialized = true; 601 if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 602 (cp = strchr(domain, '.'))) { 603 domain[MAXHOSTNAMELEN] = '\0'; 604 (void)strcpy(domain, cp + 1); 605 } else 606 domain[0] = '\0'; 607 } 608 609 /* If the address is zero-filled, use "default". */ 610 if (sa->sa_len == 0 && nflag == 0) 611 return ("default"); 612 #if defined(INET) || defined(INET6) 613 switch (sa->sa_family) { 614 #ifdef INET 615 case AF_INET: 616 /* If the address is zero-filled, use "default". */ 617 if (nflag == 0 && 618 ((struct sockaddr_in *)(void *)sa)->sin_addr.s_addr == 619 INADDR_ANY) 620 return("default"); 621 break; 622 #endif 623 #ifdef INET6 624 case AF_INET6: 625 /* If the address is zero-filled, use "default". */ 626 if (nflag == 0 && 627 IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(void *)sa)->sin6_addr)) 628 return("default"); 629 break; 630 #endif 631 } 632 #endif 633 634 switch (sa->sa_family) { 635 #if defined(INET) || defined(INET6) 636 #ifdef INET 637 case AF_INET: 638 #endif 639 #ifdef INET6 640 case AF_INET6: 641 #endif 642 { 643 struct sockaddr_storage ss; 644 int error; 645 char *p; 646 647 memset(&ss, 0, sizeof(ss)); 648 if (sa->sa_len == 0) 649 ss.ss_family = sa->sa_family; 650 else 651 memcpy(&ss, sa, sa->sa_len); 652 /* Expand sa->sa_len because it could be shortened. */ 653 if (sa->sa_family == AF_INET) 654 ss.ss_len = sizeof(struct sockaddr_in); 655 else if (sa->sa_family == AF_INET6) 656 ss.ss_len = sizeof(struct sockaddr_in6); 657 error = getnameinfo((struct sockaddr *)&ss, ss.ss_len, 658 rt_line, sizeof(rt_line), NULL, 0, 659 (nflag == 0) ? 0 : NI_NUMERICHOST); 660 if (error) { 661 warnx("getnameinfo(): %s", gai_strerror(error)); 662 strncpy(rt_line, "invalid", sizeof(rt_line)); 663 } 664 665 /* Remove the domain part if any. */ 666 p = strchr(rt_line, '.'); 667 if (p != NULL && strcmp(p + 1, domain) == 0) 668 *p = '\0'; 669 670 return (rt_line); 671 break; 672 } 673 #endif 674 case AF_LINK: 675 sdl = (struct sockaddr_dl *)(void *)sa; 676 677 if (sdl->sdl_nlen == 0 && 678 sdl->sdl_alen == 0 && 679 sdl->sdl_slen == 0) { 680 n = snprintf(rt_line, sizeof(rt_line), "link#%d", 681 sdl->sdl_index); 682 if (n > (int)sizeof(rt_line)) 683 rt_line[0] = '\0'; 684 return (rt_line); 685 } else 686 return (link_ntoa(sdl)); 687 break; 688 689 default: 690 { 691 u_short *sp = (u_short *)(void *)sa; 692 u_short *splim = sp + ((sa->sa_len + 1) >> 1); 693 char *cps = rt_line + sprintf(rt_line, "(%d)", sa->sa_family); 694 char *cpe = rt_line + sizeof(rt_line); 695 696 while (++sp < splim && cps < cpe) /* start with sa->sa_data */ 697 if ((n = snprintf(cps, cpe - cps, " %x", *sp)) > 0) 698 cps += n; 699 else 700 *cps = '\0'; 701 break; 702 } 703 } 704 return (rt_line); 705 } 706 707 /* 708 * Return the name of the network whose address is given. 709 * The address is assumed to be that of a net, not a host. 710 */ 711 const char * 712 netname(struct sockaddr *sa) 713 { 714 struct sockaddr_dl *sdl; 715 int n; 716 #ifdef INET 717 struct netent *np = NULL; 718 const char *cp = NULL; 719 u_long i; 720 #endif 721 722 switch (sa->sa_family) { 723 #ifdef INET 724 case AF_INET: 725 { 726 struct in_addr in; 727 728 in = ((struct sockaddr_in *)(void *)sa)->sin_addr; 729 i = in.s_addr = ntohl(in.s_addr); 730 if (in.s_addr == 0) 731 cp = "default"; 732 else if (!nflag) { 733 np = getnetbyaddr(i, AF_INET); 734 if (np != NULL) 735 cp = np->n_name; 736 } 737 #define C(x) (unsigned)((x) & 0xff) 738 if (cp != NULL) 739 strncpy(net_line, cp, sizeof(net_line)); 740 else if ((in.s_addr & 0xffffff) == 0) 741 (void)sprintf(net_line, "%u", C(in.s_addr >> 24)); 742 else if ((in.s_addr & 0xffff) == 0) 743 (void)sprintf(net_line, "%u.%u", C(in.s_addr >> 24), 744 C(in.s_addr >> 16)); 745 else if ((in.s_addr & 0xff) == 0) 746 (void)sprintf(net_line, "%u.%u.%u", C(in.s_addr >> 24), 747 C(in.s_addr >> 16), C(in.s_addr >> 8)); 748 else 749 (void)sprintf(net_line, "%u.%u.%u.%u", C(in.s_addr >> 24), 750 C(in.s_addr >> 16), C(in.s_addr >> 8), 751 C(in.s_addr)); 752 #undef C 753 break; 754 } 755 #endif 756 #ifdef INET6 757 case AF_INET6: 758 { 759 struct sockaddr_in6 sin6; 760 int niflags = 0; 761 762 memset(&sin6, 0, sizeof(sin6)); 763 memcpy(&sin6, sa, sa->sa_len); 764 sin6.sin6_len = sizeof(sin6); 765 sin6.sin6_family = AF_INET6; 766 if (nflag) 767 niflags |= NI_NUMERICHOST; 768 if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 769 net_line, sizeof(net_line), NULL, 0, niflags) != 0) 770 strncpy(net_line, "invalid", sizeof(net_line)); 771 772 return(net_line); 773 } 774 #endif 775 case AF_LINK: 776 sdl = (struct sockaddr_dl *)(void *)sa; 777 778 if (sdl->sdl_nlen == 0 && 779 sdl->sdl_alen == 0 && 780 sdl->sdl_slen == 0) { 781 n = snprintf(net_line, sizeof(net_line), "link#%d", 782 sdl->sdl_index); 783 if (n > (int)sizeof(net_line)) 784 net_line[0] = '\0'; 785 return (net_line); 786 } else 787 return (link_ntoa(sdl)); 788 break; 789 790 default: 791 { 792 u_short *sp = (u_short *)(void *)sa->sa_data; 793 u_short *splim = sp + ((sa->sa_len + 1)>>1); 794 char *cps = net_line + sprintf(net_line, "af %d:", sa->sa_family); 795 char *cpe = net_line + sizeof(net_line); 796 797 while (sp < splim && cps < cpe) 798 if ((n = snprintf(cps, cpe - cps, " %x", *sp++)) > 0) 799 cps += n; 800 else 801 *cps = '\0'; 802 break; 803 } 804 } 805 return (net_line); 806 } 807 808 static void 809 set_metric(char *value, int key) 810 { 811 int flag = 0; 812 char *endptr; 813 u_long noval, *valp = &noval; 814 815 switch (key) { 816 #define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break 817 caseof(K_MTU, RTV_MTU, rmx_mtu); 818 caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); 819 caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); 820 caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); 821 caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); 822 caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); 823 caseof(K_RTT, RTV_RTT, rmx_rtt); 824 caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); 825 caseof(K_WEIGHT, RTV_WEIGHT, rmx_weight); 826 } 827 rtm_inits |= flag; 828 if (lockrest || locking) 829 rt_metrics.rmx_locks |= flag; 830 if (locking) 831 locking = 0; 832 errno = 0; 833 *valp = strtol(value, &endptr, 0); 834 if (errno == 0 && *endptr != '\0') 835 errno = EINVAL; 836 if (errno) 837 err(EX_USAGE, "%s", value); 838 if (flag & RTV_EXPIRE && (value[0] == '+' || value[0] == '-')) { 839 struct timespec ts; 840 841 clock_gettime(CLOCK_REALTIME_FAST, &ts); 842 *valp += ts.tv_sec; 843 } 844 } 845 846 #define F_ISHOST 0x01 847 #define F_FORCENET 0x02 848 #define F_FORCEHOST 0x04 849 #define F_PROXY 0x08 850 #define F_INTERFACE 0x10 851 852 static void 853 newroute(int argc, char **argv) 854 { 855 struct sigaction sa; 856 struct fibl *fl; 857 char *cmd; 858 const char *dest, *gateway, *errmsg; 859 int key, error, flags, nrflags, fibnum; 860 861 if (uid != 0 && !debugonly && !tflag) 862 errx(EX_NOPERM, "must be root to alter routing table"); 863 dest = NULL; 864 gateway = NULL; 865 flags = RTF_STATIC; 866 nrflags = 0; 867 TAILQ_INIT(&fibl_head); 868 869 sigemptyset(&sa.sa_mask); 870 sa.sa_flags = 0; 871 sa.sa_handler = stopit; 872 if (sigaction(SIGALRM, &sa, 0) == -1) 873 warn("sigaction SIGALRM"); 874 875 cmd = argv[0]; 876 #ifdef WITHOUT_NETLINK 877 if (*cmd != 'g' && *cmd != 's') 878 shutdown(s, SHUT_RD); /* Don't want to read back our messages */ 879 #endif 880 while (--argc > 0) { 881 if (**(++argv)== '-') { 882 switch (key = keyword(1 + *argv)) { 883 case K_LINK: 884 af = AF_LINK; 885 aflen = sizeof(struct sockaddr_dl); 886 break; 887 #ifdef INET 888 case K_4: 889 case K_INET: 890 af = AF_INET; 891 aflen = sizeof(struct sockaddr_in); 892 break; 893 #endif 894 #ifdef INET6 895 case K_6: 896 case K_INET6: 897 af = AF_INET6; 898 aflen = sizeof(struct sockaddr_in6); 899 break; 900 #endif 901 case K_SA: 902 af = PF_ROUTE; 903 aflen = sizeof(struct sockaddr_storage); 904 break; 905 case K_IFACE: 906 case K_INTERFACE: 907 nrflags |= F_INTERFACE; 908 break; 909 case K_NOSTATIC: 910 flags &= ~RTF_STATIC; 911 break; 912 case K_LOCK: 913 locking = 1; 914 break; 915 case K_LOCKREST: 916 lockrest = 1; 917 break; 918 case K_HOST: 919 nrflags |= F_FORCEHOST; 920 break; 921 case K_REJECT: 922 flags |= RTF_REJECT; 923 break; 924 case K_BLACKHOLE: 925 flags |= RTF_BLACKHOLE; 926 break; 927 case K_PROTO1: 928 flags |= RTF_PROTO1; 929 break; 930 case K_PROTO2: 931 flags |= RTF_PROTO2; 932 break; 933 case K_PROXY: 934 nrflags |= F_PROXY; 935 break; 936 case K_XRESOLVE: 937 flags |= RTF_XRESOLVE; 938 break; 939 case K_STATIC: 940 flags |= RTF_STATIC; 941 break; 942 case K_STICKY: 943 flags |= RTF_STICKY; 944 break; 945 case K_NOSTICK: 946 flags &= ~RTF_STICKY; 947 break; 948 case K_FIB: 949 if (!--argc) 950 usage(NULL); 951 error = fiboptlist_csv(*++argv, &fibl_head); 952 if (error) 953 errx(EX_USAGE, 954 "invalid fib number: %s", *argv); 955 break; 956 case K_IFA: 957 if (!--argc) 958 usage(NULL); 959 getaddr(RTAX_IFA, *++argv, nrflags); 960 break; 961 case K_IFP: 962 if (!--argc) 963 usage(NULL); 964 getaddr(RTAX_IFP, *++argv, nrflags); 965 break; 966 case K_GENMASK: 967 if (!--argc) 968 usage(NULL); 969 getaddr(RTAX_GENMASK, *++argv, nrflags); 970 break; 971 case K_GATEWAY: 972 if (!--argc) 973 usage(NULL); 974 getaddr(RTAX_GATEWAY, *++argv, nrflags); 975 gateway = *argv; 976 break; 977 case K_DST: 978 if (!--argc) 979 usage(NULL); 980 if (getaddr(RTAX_DST, *++argv, nrflags)) 981 nrflags |= F_ISHOST; 982 dest = *argv; 983 break; 984 case K_NETMASK: 985 if (!--argc) 986 usage(NULL); 987 getaddr(RTAX_NETMASK, *++argv, nrflags); 988 /* FALLTHROUGH */ 989 case K_NET: 990 nrflags |= F_FORCENET; 991 break; 992 case K_PREFIXLEN: 993 if (!--argc) 994 usage(NULL); 995 if (prefixlen(*++argv) == -1) { 996 nrflags &= ~F_FORCENET; 997 nrflags |= F_ISHOST; 998 } else { 999 nrflags |= F_FORCENET; 1000 nrflags &= ~F_ISHOST; 1001 } 1002 break; 1003 case K_MTU: 1004 case K_HOPCOUNT: 1005 case K_EXPIRE: 1006 case K_RECVPIPE: 1007 case K_SENDPIPE: 1008 case K_SSTHRESH: 1009 case K_RTT: 1010 case K_RTTVAR: 1011 case K_WEIGHT: 1012 if (!--argc) 1013 usage(NULL); 1014 set_metric(*++argv, key); 1015 break; 1016 default: 1017 usage(1+*argv); 1018 } 1019 } else { 1020 if ((rtm_addrs & RTA_DST) == 0) { 1021 dest = *argv; 1022 if (getaddr(RTAX_DST, *argv, nrflags)) 1023 nrflags |= F_ISHOST; 1024 } else if ((rtm_addrs & RTA_GATEWAY) == 0) { 1025 gateway = *argv; 1026 getaddr(RTAX_GATEWAY, *argv, nrflags); 1027 } else { 1028 getaddr(RTAX_NETMASK, *argv, nrflags); 1029 nrflags |= F_FORCENET; 1030 } 1031 } 1032 } 1033 1034 /* Do some sanity checks on resulting request */ 1035 if (so[RTAX_DST].ss_len == 0) { 1036 warnx("destination parameter required"); 1037 usage(NULL); 1038 } 1039 1040 if (so[RTAX_NETMASK].ss_len != 0 && 1041 so[RTAX_DST].ss_family != so[RTAX_NETMASK].ss_family) { 1042 warnx("destination and netmask family need to be the same"); 1043 usage(NULL); 1044 } 1045 1046 if (nrflags & F_FORCEHOST) { 1047 nrflags |= F_ISHOST; 1048 #ifdef INET6 1049 if (af == AF_INET6) { 1050 rtm_addrs &= ~RTA_NETMASK; 1051 memset(&so[RTAX_NETMASK], 0, sizeof(so[RTAX_NETMASK])); 1052 } 1053 #endif 1054 } 1055 if (nrflags & F_FORCENET) 1056 nrflags &= ~F_ISHOST; 1057 flags |= RTF_UP; 1058 if (nrflags & F_ISHOST) 1059 flags |= RTF_HOST; 1060 if ((nrflags & F_INTERFACE) == 0) 1061 flags |= RTF_GATEWAY; 1062 if (nrflags & F_PROXY) 1063 flags |= RTF_ANNOUNCE; 1064 if (dest == NULL) 1065 dest = ""; 1066 if (gateway == NULL) 1067 gateway = ""; 1068 1069 if (TAILQ_EMPTY(&fibl_head)) { 1070 error = fiboptlist_csv("default", &fibl_head); 1071 if (error) 1072 errx(EX_OSERR, "fiboptlist_csv failed."); 1073 } 1074 error = 0; 1075 TAILQ_FOREACH(fl, &fibl_head, fl_next) { 1076 fl->fl_error = newroute_fib(fl->fl_num, cmd, flags); 1077 if (fl->fl_error) 1078 fl->fl_errno = errno; 1079 error += fl->fl_error; 1080 } 1081 if (*cmd == 'g' || *cmd == 's') 1082 exit(error); 1083 1084 error = 0; 1085 if (!qflag) { 1086 fibnum = 0; 1087 TAILQ_FOREACH(fl, &fibl_head, fl_next) { 1088 if (fl->fl_error == 0) 1089 fibnum++; 1090 } 1091 if (fibnum > 0) { 1092 int firstfib = 1; 1093 1094 printf("%s %s %s", cmd, 1095 (nrflags & F_ISHOST) ? "host" : "net", dest); 1096 if (*gateway) 1097 printf(": gateway %s", gateway); 1098 1099 if (numfibs > 1) { 1100 TAILQ_FOREACH(fl, &fibl_head, fl_next) { 1101 if (fl->fl_error == 0 1102 && fl->fl_num >= 0) { 1103 if (firstfib) { 1104 printf(" fib "); 1105 firstfib = 0; 1106 } 1107 printf("%d", fl->fl_num); 1108 if (fibnum-- > 1) 1109 printf(","); 1110 } 1111 } 1112 } 1113 printf("\n"); 1114 } 1115 } 1116 1117 fibnum = 0; 1118 TAILQ_FOREACH(fl, &fibl_head, fl_next) { 1119 if (fl->fl_error != 0) { 1120 error = 1; 1121 if (!qflag) { 1122 printf("%s %s %s", cmd, (nrflags & F_ISHOST) 1123 ? "host" : "net", dest); 1124 if (*gateway) 1125 printf(": gateway %s", gateway); 1126 1127 if (fl->fl_num >= 0) 1128 printf(" fib %d", fl->fl_num); 1129 1130 switch (fl->fl_errno) { 1131 case ESRCH: 1132 errmsg = "not in table"; 1133 break; 1134 case EBUSY: 1135 errmsg = "entry in use"; 1136 break; 1137 case ENOBUFS: 1138 errmsg = "not enough memory"; 1139 break; 1140 case EADDRINUSE: 1141 /* 1142 * handle recursion avoidance 1143 * in rt_setgate() 1144 */ 1145 errmsg = "gateway uses the same route"; 1146 break; 1147 case EEXIST: 1148 errmsg = "route already in table"; 1149 break; 1150 default: 1151 errmsg = strerror(fl->fl_errno); 1152 break; 1153 } 1154 printf(": %s\n", errmsg); 1155 } 1156 } 1157 } 1158 exit(error); 1159 } 1160 1161 static int 1162 newroute_fib(int fib, char *cmd, int flags) 1163 { 1164 int error; 1165 1166 error = set_sofib(fib); 1167 if (error) { 1168 warn("fib number %d is ignored", fib); 1169 return (error); 1170 } 1171 1172 error = rtmsg(*cmd, flags, fib); 1173 return (error); 1174 } 1175 1176 #ifdef INET 1177 static void 1178 inet_makemask(struct sockaddr_in *sin_mask, u_long bits) 1179 { 1180 u_long mask = 0; 1181 1182 rtm_addrs |= RTA_NETMASK; 1183 1184 if (bits != 0) 1185 mask = 0xffffffff << (32 - bits); 1186 1187 sin_mask->sin_addr.s_addr = htonl(mask); 1188 sin_mask->sin_len = sizeof(struct sockaddr_in); 1189 sin_mask->sin_family = AF_INET; 1190 } 1191 #endif 1192 1193 #ifdef INET6 1194 /* 1195 * XXX the function may need more improvement... 1196 */ 1197 static int 1198 inet6_makenetandmask(struct sockaddr_in6 *sin6, const char *plen) 1199 { 1200 1201 if (plen == NULL) { 1202 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && 1203 sin6->sin6_scope_id == 0) 1204 plen = "0"; 1205 } 1206 1207 if (plen == NULL || strcmp(plen, "128") == 0) 1208 return (1); 1209 rtm_addrs |= RTA_NETMASK; 1210 prefixlen(plen); 1211 return (0); 1212 } 1213 #endif 1214 1215 /* 1216 * Interpret an argument as a network address of some kind, 1217 * returning 1 if a host address, 0 if a network address. 1218 */ 1219 static int 1220 getaddr(int idx, char *str, int nrflags) 1221 { 1222 struct sockaddr *sa; 1223 #if defined(INET) 1224 struct sockaddr_in *sin; 1225 struct hostent *hp; 1226 char *q; 1227 #elif defined(INET6) 1228 char *q; 1229 #endif 1230 1231 if (idx < 0 || idx >= RTAX_MAX) 1232 usage("internal error"); 1233 if (af == 0) { 1234 #if defined(INET) 1235 af = AF_INET; 1236 aflen = sizeof(struct sockaddr_in); 1237 #elif defined(INET6) 1238 af = AF_INET6; 1239 aflen = sizeof(struct sockaddr_in6); 1240 #else 1241 af = AF_LINK; 1242 aflen = sizeof(struct sockaddr_dl); 1243 #endif 1244 } 1245 rtm_addrs |= (1 << idx); 1246 sa = (struct sockaddr *)&so[idx]; 1247 sa->sa_family = af; 1248 sa->sa_len = aflen; 1249 1250 switch (idx) { 1251 case RTAX_GATEWAY: 1252 if (nrflags & F_INTERFACE) { 1253 struct ifaddrs *ifap, *ifa; 1254 struct sockaddr_dl *sdl0 = (struct sockaddr_dl *)(void *)sa; 1255 struct sockaddr_dl *sdl = NULL; 1256 1257 if (getifaddrs(&ifap)) 1258 err(EX_OSERR, "getifaddrs"); 1259 1260 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 1261 if (ifa->ifa_addr->sa_family != AF_LINK) 1262 continue; 1263 1264 if (strcmp(str, ifa->ifa_name) != 0) 1265 continue; 1266 1267 sdl = (struct sockaddr_dl *)(void *)ifa->ifa_addr; 1268 } 1269 /* If we found it, then use it */ 1270 if (sdl != NULL) { 1271 /* 1272 * Note that we need to copy before calling 1273 * freeifaddrs(). 1274 */ 1275 memcpy(sdl0, sdl, sdl->sdl_len); 1276 } 1277 freeifaddrs(ifap); 1278 if (sdl != NULL) 1279 return(1); 1280 else 1281 errx(EX_DATAERR, 1282 "interface '%s' does not exist", str); 1283 } 1284 break; 1285 case RTAX_IFP: 1286 sa->sa_family = AF_LINK; 1287 break; 1288 } 1289 if (strcmp(str, "default") == 0) { 1290 /* 1291 * Default is net 0.0.0.0/0 1292 */ 1293 switch (idx) { 1294 case RTAX_DST: 1295 nrflags |= F_FORCENET; 1296 getaddr(RTAX_NETMASK, str, nrflags); 1297 break; 1298 } 1299 return (0); 1300 } 1301 switch (sa->sa_family) { 1302 #ifdef INET6 1303 case AF_INET6: 1304 { 1305 struct addrinfo hints, *res; 1306 int ecode; 1307 1308 q = NULL; 1309 if (idx == RTAX_DST && (q = strchr(str, '/')) != NULL) 1310 *q = '\0'; 1311 memset(&hints, 0, sizeof(hints)); 1312 hints.ai_family = sa->sa_family; 1313 hints.ai_socktype = SOCK_DGRAM; 1314 ecode = getaddrinfo(str, NULL, &hints, &res); 1315 if (ecode != 0 || res->ai_family != AF_INET6 || 1316 res->ai_addrlen != sizeof(struct sockaddr_in6)) 1317 errx(EX_OSERR, "%s: %s", str, gai_strerror(ecode)); 1318 memcpy(sa, res->ai_addr, res->ai_addrlen); 1319 freeaddrinfo(res); 1320 if (q != NULL) 1321 *q++ = '/'; 1322 if (idx == RTAX_DST) 1323 return (inet6_makenetandmask((struct sockaddr_in6 *)(void *)sa, q)); 1324 return (0); 1325 } 1326 #endif /* INET6 */ 1327 case AF_LINK: 1328 link_addr(str, (struct sockaddr_dl *)(void *)sa); 1329 return (1); 1330 1331 case PF_ROUTE: 1332 sockaddr(str, sa, sizeof(struct sockaddr_storage)); 1333 return (1); 1334 #ifdef INET 1335 case AF_INET: 1336 #endif 1337 default: 1338 break; 1339 } 1340 1341 #ifdef INET 1342 sin = (struct sockaddr_in *)(void *)sa; 1343 1344 q = strchr(str,'/'); 1345 if (q != NULL && idx == RTAX_DST) { 1346 /* A.B.C.D/NUM */ 1347 *q = '\0'; 1348 if (inet_aton(str, &sin->sin_addr) == 0) 1349 errx(EX_NOHOST, "bad address: %s", str); 1350 1351 int masklen = strtol(q + 1, NULL, 10); 1352 if (masklen < 0 || masklen > 32) 1353 errx(EX_NOHOST, "bad mask length: %s", q + 1); 1354 1355 inet_makemask((struct sockaddr_in *)&so[RTAX_NETMASK],masklen); 1356 return (0); 1357 } 1358 if (inet_aton(str, &sin->sin_addr) != 0) 1359 return (1); 1360 1361 hp = gethostbyname(str); 1362 if (hp != NULL) { 1363 sin->sin_family = hp->h_addrtype; 1364 memmove((char *)&sin->sin_addr, hp->h_addr, 1365 MIN((size_t)hp->h_length, sizeof(sin->sin_addr))); 1366 return (1); 1367 } 1368 #endif 1369 errx(EX_NOHOST, "bad address: %s", str); 1370 } 1371 1372 static int 1373 prefixlen(const char *str) 1374 { 1375 int len = atoi(str), q, r; 1376 int max; 1377 char *p; 1378 1379 rtm_addrs |= RTA_NETMASK; 1380 switch (af) { 1381 #ifdef INET6 1382 case AF_INET6: 1383 { 1384 struct sockaddr_in6 *sin6 = 1385 (struct sockaddr_in6 *)&so[RTAX_NETMASK]; 1386 1387 max = 128; 1388 p = (char *)&sin6->sin6_addr; 1389 sin6->sin6_family = AF_INET6; 1390 sin6->sin6_len = sizeof(*sin6); 1391 break; 1392 } 1393 #endif 1394 #ifdef INET 1395 case AF_INET: 1396 { 1397 struct sockaddr_in *sin = 1398 (struct sockaddr_in *)&so[RTAX_NETMASK]; 1399 1400 max = 32; 1401 p = (char *)&sin->sin_addr; 1402 sin->sin_family = AF_INET; 1403 sin->sin_len = sizeof(*sin); 1404 break; 1405 } 1406 #endif 1407 default: 1408 errx(EX_OSERR, "prefixlen not supported in this af"); 1409 } 1410 1411 if (len < 0 || max < len) 1412 errx(EX_USAGE, "%s: invalid prefixlen", str); 1413 1414 q = len >> 3; 1415 r = len & 7; 1416 memset((void *)p, 0, max / 8); 1417 if (q > 0) 1418 memset((void *)p, 0xff, q); 1419 if (r > 0) 1420 *((u_char *)p + q) = (0xff00 >> r) & 0xff; 1421 if (len == max) 1422 return (-1); 1423 else 1424 return (len); 1425 } 1426 1427 static void 1428 interfaces(void) 1429 { 1430 size_t needed; 1431 int mib[6]; 1432 char *buf, *lim, *next, count = 0; 1433 struct rt_msghdr *rtm; 1434 1435 retry2: 1436 mib[0] = CTL_NET; 1437 mib[1] = PF_ROUTE; 1438 mib[2] = 0; /* protocol */ 1439 mib[3] = AF_UNSPEC; 1440 mib[4] = NET_RT_IFLIST; 1441 mib[5] = 0; /* no flags */ 1442 if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0) 1443 err(EX_OSERR, "route-sysctl-estimate"); 1444 if ((buf = malloc(needed)) == NULL) 1445 errx(EX_OSERR, "malloc failed"); 1446 if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) { 1447 if (errno == ENOMEM && count++ < 10) { 1448 warnx("Routing table grew, retrying"); 1449 sleep(1); 1450 free(buf); 1451 goto retry2; 1452 } 1453 err(EX_OSERR, "actual retrieval of interface table"); 1454 } 1455 lim = buf + needed; 1456 for (next = buf; next < lim; next += rtm->rtm_msglen) { 1457 rtm = (struct rt_msghdr *)(void *)next; 1458 print_rtmsg(rtm, rtm->rtm_msglen); 1459 } 1460 free(buf); 1461 } 1462 1463 static void 1464 monitor(int argc, char *argv[]) 1465 { 1466 int fib, error; 1467 char *endptr; 1468 1469 fib = defaultfib; 1470 while (argc > 1) { 1471 argc--; 1472 argv++; 1473 if (**argv != '-') 1474 usage(*argv); 1475 switch (keyword(*argv + 1)) { 1476 case K_FIB: 1477 if (!--argc) 1478 usage(*argv); 1479 errno = 0; 1480 fib = strtol(*++argv, &endptr, 0); 1481 if (errno == 0) { 1482 if (*endptr != '\0' || 1483 fib < 0 || 1484 (numfibs != -1 && fib > numfibs - 1)) 1485 errno = EINVAL; 1486 } 1487 if (errno) 1488 errx(EX_USAGE, "invalid fib number: %s", *argv); 1489 break; 1490 default: 1491 usage(*argv); 1492 } 1493 } 1494 error = set_sofib(fib); 1495 if (error) 1496 errx(EX_USAGE, "invalid fib number: %d", fib); 1497 1498 verbose = 1; 1499 if (debugonly) { 1500 interfaces(); 1501 exit(0); 1502 } 1503 #ifdef WITHOUT_NETLINK 1504 monitor_rtsock(); 1505 #else 1506 monitor_nl(fib); 1507 #endif 1508 } 1509 1510 #ifdef WITHOUT_NETLINK 1511 static void 1512 monitor_rtsock(void) 1513 { 1514 char msg[2048]; 1515 int n; 1516 1517 #ifdef SO_RERROR 1518 n = 1; 1519 if (setsockopt(s, SOL_SOCKET, SO_RERROR, &n, sizeof(n)) == -1) 1520 warn("SO_RERROR"); 1521 #endif 1522 1523 for (;;) { 1524 time_t now; 1525 n = read(s, msg, sizeof(msg)); 1526 if (n == -1) { 1527 warn("read"); 1528 continue; 1529 } 1530 now = time(NULL); 1531 (void)printf("\ngot message of size %d on %s", n, ctime(&now)); 1532 print_rtmsg((struct rt_msghdr *)(void *)msg, n); 1533 } 1534 } 1535 #endif 1536 1537 static int 1538 rtmsg(int cmd, int flags, int fib) 1539 { 1540 errno = 0; 1541 if (cmd == 'a') 1542 cmd = RTM_ADD; 1543 else if (cmd == 'c') 1544 cmd = RTM_CHANGE; 1545 else if (cmd == 'g' || cmd == 's') { 1546 cmd = RTM_GET; 1547 if (so[RTAX_IFP].ss_family == 0) { 1548 so[RTAX_IFP].ss_family = AF_LINK; 1549 so[RTAX_IFP].ss_len = sizeof(struct sockaddr_dl); 1550 rtm_addrs |= RTA_IFP; 1551 } 1552 } else { 1553 cmd = RTM_DELETE; 1554 flags |= RTF_PINNED; 1555 } 1556 #ifdef WITHOUT_NETLINK 1557 return (rtmsg_rtsock(cmd, flags, fib)); 1558 #else 1559 errno = rtmsg_nl(cmd, flags, fib, rtm_addrs, so, &rt_metrics); 1560 return (errno == 0 ? 0 : -1); 1561 #endif 1562 } 1563 1564 #ifdef WITHOUT_NETLINK 1565 static int 1566 rtmsg_rtsock(int cmd, int flags, int fib) 1567 { 1568 int rlen; 1569 char *cp = m_rtmsg.m_space; 1570 int l; 1571 1572 memset(&m_rtmsg, 0, sizeof(m_rtmsg)); 1573 1574 #define NEXTADDR(w, u) \ 1575 if (rtm_addrs & (w)) { \ 1576 l = SA_SIZE(&(u)); \ 1577 memmove(cp, (char *)&(u), l); \ 1578 cp += l; \ 1579 if (verbose) \ 1580 sodump((struct sockaddr *)&(u), #w); \ 1581 } 1582 1583 #define rtm m_rtmsg.m_rtm 1584 rtm.rtm_type = cmd; 1585 rtm.rtm_flags = flags; 1586 rtm.rtm_version = RTM_VERSION; 1587 rtm.rtm_seq = ++rtm_seq; 1588 rtm.rtm_addrs = rtm_addrs; 1589 rtm.rtm_rmx = rt_metrics; 1590 rtm.rtm_inits = rtm_inits; 1591 1592 NEXTADDR(RTA_DST, so[RTAX_DST]); 1593 NEXTADDR(RTA_GATEWAY, so[RTAX_GATEWAY]); 1594 NEXTADDR(RTA_NETMASK, so[RTAX_NETMASK]); 1595 NEXTADDR(RTA_GENMASK, so[RTAX_GENMASK]); 1596 NEXTADDR(RTA_IFP, so[RTAX_IFP]); 1597 NEXTADDR(RTA_IFA, so[RTAX_IFA]); 1598 rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 1599 if (verbose) 1600 print_rtmsg(&rtm, l); 1601 if (debugonly) 1602 return (0); 1603 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 1604 switch (errno) { 1605 case EPERM: 1606 err(1, "writing to routing socket"); 1607 break; 1608 case ESRCH: 1609 warnx("route has not been found"); 1610 break; 1611 case EEXIST: 1612 /* Handled by newroute() */ 1613 break; 1614 default: 1615 warn("writing to routing socket"); 1616 } 1617 return (-1); 1618 } 1619 if (cmd == RTM_GET) { 1620 stop_read = 0; 1621 alarm(READ_TIMEOUT); 1622 do { 1623 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 1624 } while (l > 0 && stop_read == 0 && 1625 (rtm.rtm_type != RTM_GET || rtm.rtm_seq != rtm_seq || 1626 rtm.rtm_pid != pid)); 1627 if (stop_read != 0) { 1628 warnx("read from routing socket timed out"); 1629 return (-1); 1630 } else 1631 alarm(0); 1632 if (l < 0) 1633 warn("read from routing socket"); 1634 else 1635 print_getmsg(&rtm, l, fib); 1636 } 1637 #undef rtm 1638 return (0); 1639 } 1640 #endif 1641 1642 static const char *const msgtypes[] = { 1643 "", 1644 "RTM_ADD: Add Route", 1645 "RTM_DELETE: Delete Route", 1646 "RTM_CHANGE: Change Metrics or flags", 1647 "RTM_GET: Report Metrics", 1648 "RTM_LOSING: Kernel Suspects Partitioning", 1649 "RTM_REDIRECT: Told to use different route", 1650 "RTM_MISS: Lookup failed on this address", 1651 "RTM_LOCK: fix specified metrics", 1652 "RTM_OLDADD: caused by SIOCADDRT", 1653 "RTM_OLDDEL: caused by SIOCDELRT", 1654 "RTM_RESOLVE: Route created by cloning", 1655 "RTM_NEWADDR: address being added to iface", 1656 "RTM_DELADDR: address being removed from iface", 1657 "RTM_IFINFO: iface status change", 1658 "RTM_NEWMADDR: new multicast group membership on iface", 1659 "RTM_DELMADDR: multicast group membership removed from iface", 1660 "RTM_IFANNOUNCE: interface arrival/departure", 1661 "RTM_IEEE80211: IEEE 802.11 wireless event", 1662 }; 1663 1664 static const char metricnames[] = 1665 "\011weight\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire" 1666 "\1mtu"; 1667 const char routeflags[] = 1668 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE" 1669 "\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE" 1670 "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3" 1671 "\024FIXEDMTU\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY"; 1672 static const char ifnetflags[] = 1673 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP" 1674 "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1" 1675 "\017LINK2\020MULTICAST"; 1676 static const char addrnames[] = 1677 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD"; 1678 1679 static const char errfmt[] = 1680 "\n%s: truncated route message, only %zu bytes left\n"; 1681 1682 static void 1683 print_rtmsg(struct rt_msghdr *rtm, size_t msglen) 1684 { 1685 struct if_msghdr *ifm; 1686 struct ifa_msghdr *ifam; 1687 #ifdef RTM_NEWMADDR 1688 struct ifma_msghdr *ifmam; 1689 #endif 1690 struct if_announcemsghdr *ifan; 1691 const char *state; 1692 1693 if (verbose == 0) 1694 return; 1695 if (rtm->rtm_version != RTM_VERSION) { 1696 (void)printf("routing message version %d not understood\n", 1697 rtm->rtm_version); 1698 return; 1699 } 1700 if (rtm->rtm_type < nitems(msgtypes)) 1701 (void)printf("%s: ", msgtypes[rtm->rtm_type]); 1702 else 1703 (void)printf("unknown type %d: ", rtm->rtm_type); 1704 (void)printf("len %d, ", rtm->rtm_msglen); 1705 1706 #define REQUIRE(x) do { \ 1707 if (msglen < sizeof(x)) \ 1708 goto badlen; \ 1709 else \ 1710 msglen -= sizeof(x); \ 1711 } while (0) 1712 1713 switch (rtm->rtm_type) { 1714 case RTM_IFINFO: 1715 REQUIRE(struct if_msghdr); 1716 ifm = (struct if_msghdr *)rtm; 1717 (void)printf("if# %d, ", ifm->ifm_index); 1718 switch (ifm->ifm_data.ifi_link_state) { 1719 case LINK_STATE_DOWN: 1720 state = "down"; 1721 break; 1722 case LINK_STATE_UP: 1723 state = "up"; 1724 break; 1725 default: 1726 state = "unknown"; 1727 break; 1728 } 1729 (void)printf("link: %s, flags:", state); 1730 printb(ifm->ifm_flags, ifnetflags); 1731 pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs, msglen); 1732 break; 1733 case RTM_NEWADDR: 1734 case RTM_DELADDR: 1735 REQUIRE(struct ifa_msghdr); 1736 ifam = (struct ifa_msghdr *)rtm; 1737 (void)printf("metric %d, flags:", ifam->ifam_metric); 1738 printb(ifam->ifam_flags, routeflags); 1739 pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs, msglen); 1740 break; 1741 #ifdef RTM_NEWMADDR 1742 case RTM_NEWMADDR: 1743 case RTM_DELMADDR: 1744 REQUIRE(struct ifma_msghdr); 1745 ifmam = (struct ifma_msghdr *)rtm; 1746 pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs, msglen); 1747 break; 1748 #endif 1749 case RTM_IFANNOUNCE: 1750 REQUIRE(struct if_announcemsghdr); 1751 ifan = (struct if_announcemsghdr *)rtm; 1752 (void)printf("if# %d, what: ", ifan->ifan_index); 1753 switch (ifan->ifan_what) { 1754 case IFAN_ARRIVAL: 1755 (void)printf("arrival"); 1756 break; 1757 case IFAN_DEPARTURE: 1758 printf("departure"); 1759 break; 1760 default: 1761 printf("#%d", ifan->ifan_what); 1762 break; 1763 } 1764 printf("\n"); 1765 fflush(stdout); 1766 break; 1767 1768 default: 1769 if (rtm->rtm_type <= RTM_RESOLVE) { 1770 printf("pid: %ld, seq %d, errno %d, flags:", 1771 (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 1772 printb(rtm->rtm_flags, routeflags); 1773 pmsg_common(rtm, msglen); 1774 } else 1775 printf("type: %u, len: %zu\n", rtm->rtm_type, msglen); 1776 } 1777 1778 return; 1779 1780 badlen: 1781 (void)printf(errfmt, __func__, msglen); 1782 #undef REQUIRE 1783 } 1784 1785 static void 1786 print_getmsg(struct rt_msghdr *rtm, int msglen, int fib) 1787 { 1788 struct sockaddr *sp[RTAX_MAX]; 1789 struct timespec ts; 1790 char *cp; 1791 int i; 1792 1793 memset(sp, 0, sizeof(sp)); 1794 (void)printf(" route to: %s\n", 1795 routename((struct sockaddr *)&so[RTAX_DST])); 1796 if (rtm->rtm_version != RTM_VERSION) { 1797 warnx("routing message version %d not understood", 1798 rtm->rtm_version); 1799 return; 1800 } 1801 if (rtm->rtm_msglen > msglen) { 1802 warnx("message length mismatch, in packet %d, returned %d", 1803 rtm->rtm_msglen, msglen); 1804 return; 1805 } 1806 if (rtm->rtm_errno) { 1807 errno = rtm->rtm_errno; 1808 warn("message indicates error %d", errno); 1809 return; 1810 } 1811 cp = ((char *)(rtm + 1)); 1812 for (i = 0; i < RTAX_MAX; i++) 1813 if (rtm->rtm_addrs & (1 << i)) { 1814 sp[i] = (struct sockaddr *)cp; 1815 cp += SA_SIZE((struct sockaddr *)cp); 1816 } 1817 if ((rtm->rtm_addrs & RTA_IFP) && 1818 (sp[RTAX_IFP]->sa_family != AF_LINK || 1819 ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_nlen == 0)) 1820 sp[RTAX_IFP] = NULL; 1821 if (sp[RTAX_DST]) 1822 (void)printf("destination: %s\n", routename(sp[RTAX_DST])); 1823 if (sp[RTAX_NETMASK]) 1824 (void)printf(" mask: %s\n", routename(sp[RTAX_NETMASK])); 1825 if (sp[RTAX_GATEWAY] && (rtm->rtm_flags & RTF_GATEWAY)) 1826 (void)printf(" gateway: %s\n", routename(sp[RTAX_GATEWAY])); 1827 if (fib >= 0) 1828 (void)printf(" fib: %u\n", (unsigned int)fib); 1829 if (sp[RTAX_IFP]) 1830 (void)printf(" interface: %.*s\n", 1831 ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_nlen, 1832 ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_data); 1833 (void)printf(" flags: "); 1834 printb(rtm->rtm_flags, routeflags); 1835 1836 #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') 1837 #define msec(u) (((u) + 500) / 1000) /* usec to msec */ 1838 printf("\n%9s %9s %9s %9s %9s %10s %9s\n", "recvpipe", 1839 "sendpipe", "ssthresh", "rtt,msec", "mtu ", "weight", "expire"); 1840 printf("%8lu%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); 1841 printf("%8lu%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); 1842 printf("%8lu%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); 1843 printf("%8lu%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); 1844 printf("%8lu%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); 1845 printf("%8lu%c ", rtm->rtm_rmx.rmx_weight, lock(WEIGHT)); 1846 if (rtm->rtm_rmx.rmx_expire > 0) 1847 clock_gettime(CLOCK_REALTIME_FAST, &ts); 1848 else 1849 ts.tv_sec = 0; 1850 printf("%8ld%c\n", (long)(rtm->rtm_rmx.rmx_expire - ts.tv_sec), 1851 lock(EXPIRE)); 1852 #undef lock 1853 #undef msec 1854 #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD) 1855 if (verbose) 1856 pmsg_common(rtm, msglen); 1857 else if (rtm->rtm_addrs &~ RTA_IGN) { 1858 (void)printf("sockaddrs: "); 1859 printb(rtm->rtm_addrs, addrnames); 1860 putchar('\n'); 1861 } 1862 #undef RTA_IGN 1863 } 1864 1865 static void 1866 pmsg_common(struct rt_msghdr *rtm, size_t msglen) 1867 { 1868 1869 (void)printf("\nlocks: "); 1870 printb(rtm->rtm_rmx.rmx_locks, metricnames); 1871 (void)printf(" inits: "); 1872 printb(rtm->rtm_inits, metricnames); 1873 if (msglen > sizeof(struct rt_msghdr)) 1874 pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs, 1875 msglen - sizeof(struct rt_msghdr)); 1876 else 1877 (void)fflush(stdout); 1878 } 1879 1880 static void 1881 pmsg_addrs(char *cp, int addrs, size_t len) 1882 { 1883 struct sockaddr *sa; 1884 int i; 1885 1886 if (addrs == 0) { 1887 (void)putchar('\n'); 1888 return; 1889 } 1890 (void)printf("\nsockaddrs: "); 1891 printb(addrs, addrnames); 1892 putchar('\n'); 1893 for (i = 0; i < RTAX_MAX; i++) 1894 if (addrs & (1 << i)) { 1895 sa = (struct sockaddr *)cp; 1896 if (len == 0 || len < SA_SIZE(sa)) { 1897 (void)printf(errfmt, __func__, len); 1898 break; 1899 } 1900 (void)printf(" %s", routename(sa)); 1901 len -= SA_SIZE(sa); 1902 cp += SA_SIZE(sa); 1903 } 1904 (void)putchar('\n'); 1905 (void)fflush(stdout); 1906 } 1907 1908 void 1909 printb(int b, const char *str) 1910 { 1911 int i; 1912 int gotsome = 0; 1913 1914 if (b == 0) 1915 return; 1916 while ((i = *str++) != 0) { 1917 if (b & (1 << (i-1))) { 1918 if (gotsome == 0) 1919 i = '<'; 1920 else 1921 i = ','; 1922 putchar(i); 1923 gotsome = 1; 1924 for (; (i = *str) > 32; str++) 1925 putchar(i); 1926 } else 1927 while (*str > 32) 1928 str++; 1929 } 1930 if (gotsome) 1931 putchar('>'); 1932 } 1933 1934 int 1935 keyword(const char *cp) 1936 { 1937 const struct keytab *kt = keywords; 1938 1939 while (kt->kt_cp != NULL && strcmp(kt->kt_cp, cp) != 0) 1940 kt++; 1941 return (kt->kt_i); 1942 } 1943 1944 static void 1945 sodump(struct sockaddr *sa, const char *which) 1946 { 1947 #ifdef INET6 1948 char nbuf[INET6_ADDRSTRLEN]; 1949 #endif 1950 1951 switch (sa->sa_family) { 1952 case AF_LINK: 1953 (void)printf("%s: link %s; ", which, 1954 link_ntoa((struct sockaddr_dl *)(void *)sa)); 1955 break; 1956 #ifdef INET 1957 case AF_INET: 1958 (void)printf("%s: inet %s; ", which, 1959 inet_ntoa(((struct sockaddr_in *)(void *)sa)->sin_addr)); 1960 break; 1961 #endif 1962 #ifdef INET6 1963 case AF_INET6: 1964 (void)printf("%s: inet6 %s; ", which, inet_ntop(sa->sa_family, 1965 &((struct sockaddr_in6 *)(void *)sa)->sin6_addr, nbuf, 1966 sizeof(nbuf))); 1967 break; 1968 #endif 1969 } 1970 (void)fflush(stdout); 1971 } 1972 1973 /* States*/ 1974 #define VIRGIN 0 1975 #define GOTONE 1 1976 #define GOTTWO 2 1977 /* Inputs */ 1978 #define DIGIT (4*0) 1979 #define END (4*1) 1980 #define DELIM (4*2) 1981 1982 static void 1983 sockaddr(char *addr, struct sockaddr *sa, size_t size) 1984 { 1985 char *cp = (char *)sa; 1986 char *cplim = cp + size; 1987 int byte = 0, state = VIRGIN, new = 0 /* foil gcc */; 1988 1989 memset(cp, 0, size); 1990 cp++; 1991 do { 1992 if ((*addr >= '0') && (*addr <= '9')) { 1993 new = *addr - '0'; 1994 } else if ((*addr >= 'a') && (*addr <= 'f')) { 1995 new = *addr - 'a' + 10; 1996 } else if ((*addr >= 'A') && (*addr <= 'F')) { 1997 new = *addr - 'A' + 10; 1998 } else if (*addr == '\0') 1999 state |= END; 2000 else 2001 state |= DELIM; 2002 addr++; 2003 switch (state /* | INPUT */) { 2004 case GOTTWO | DIGIT: 2005 *cp++ = byte; /*FALLTHROUGH*/ 2006 case VIRGIN | DIGIT: 2007 state = GOTONE; byte = new; continue; 2008 case GOTONE | DIGIT: 2009 state = GOTTWO; byte = new + (byte << 4); continue; 2010 default: /* | DELIM */ 2011 state = VIRGIN; *cp++ = byte; byte = 0; continue; 2012 case GOTONE | END: 2013 case GOTTWO | END: 2014 *cp++ = byte; /* FALLTHROUGH */ 2015 case VIRGIN | END: 2016 break; 2017 } 2018 break; 2019 } while (cp < cplim); 2020 sa->sa_len = cp - (char *)sa; 2021 } 2022