1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 7 /* All Rights Reserved */ 8 9 /* Copyright (c) 1990 Mentat Inc. */ 10 11 /* 12 * 13 * Copyright (c) 1983, 1989, 1991, 1993 14 * The Regents of the University of California. All rights reserved. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 3. All advertising materials mentioning features or use of this software 25 * must display the following acknowledgement: 26 * This product includes software developed by the University of 27 * California, Berkeley and its contributors. 28 * 4. Neither the name of the University nor the names of its contributors 29 * may be used to endorse or promote products derived from this software 30 * without specific prior written permission. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42 * SUCH DAMAGE. 43 * 44 * @(#)route.c 8.6 (Berkeley) 4/28/95 45 * @(#)linkaddr.c 8.1 (Berkeley) 6/4/93 46 */ 47 48 #pragma ident "%Z%%M% %I% %E% SMI" 49 50 #include <sys/param.h> 51 #include <sys/file.h> 52 #include <sys/socket.h> 53 #include <sys/ioctl.h> 54 #include <sys/stat.h> 55 #include <sys/stream.h> 56 #include <sys/sysmacros.h> 57 #include <sys/tihdr.h> 58 #include <sys/types.h> 59 60 #include <net/if.h> 61 #include <net/route.h> 62 #include <net/if_dl.h> 63 #include <netinet/in.h> 64 #include <arpa/inet.h> 65 #include <netdb.h> 66 #include <inet/mib2.h> 67 #include <inet/ip.h> 68 69 #include <limits.h> 70 #include <locale.h> 71 72 #include <errno.h> 73 #include <unistd.h> 74 #include <stdio.h> 75 #include <stdlib.h> 76 #include <string.h> 77 #include <stropts.h> 78 #include <fcntl.h> 79 #include <setjmp.h> 80 #include <stdarg.h> 81 #include <assert.h> 82 83 static struct keytab { 84 char *kt_cp; 85 int kt_i; 86 } keywords[] = { 87 #define K_ADD 1 88 {"add", K_ADD}, 89 #define K_BLACKHOLE 2 90 {"blackhole", K_BLACKHOLE}, 91 #define K_CHANGE 3 92 {"change", K_CHANGE}, 93 #define K_CLONING 4 94 {"cloning", K_CLONING}, 95 #define K_DELETE 5 96 {"delete", K_DELETE}, 97 #define K_DST 6 98 {"dst", K_DST}, 99 #define K_EXPIRE 7 100 {"expire", K_EXPIRE}, 101 #define K_FLUSH 8 102 {"flush", K_FLUSH}, 103 #define K_GATEWAY 9 104 {"gateway", K_GATEWAY}, 105 #define K_GET 11 106 {"get", K_GET}, 107 #define K_HOPCOUNT 12 108 {"hopcount", K_HOPCOUNT}, 109 #define K_HOST 13 110 {"host", K_HOST}, 111 #define K_IFA 14 112 {"ifa", K_IFA}, 113 #define K_IFACE 15 114 {"iface", K_IFACE}, 115 #define K_IFP 16 116 {"ifp", K_IFP}, 117 #define K_INET 17 118 {"inet", K_INET}, 119 #define K_INET6 18 120 {"inet6", K_INET6}, 121 #define K_INTERFACE 19 122 {"interface", K_INTERFACE}, 123 #define K_LINK 20 124 {"link", K_LINK}, 125 #define K_LOCK 21 126 {"lock", K_LOCK}, 127 #define K_LOCKREST 22 128 {"lockrest", K_LOCKREST}, 129 #define K_MASK 23 130 {"mask", K_MASK}, 131 #define K_MONITOR 24 132 {"monitor", K_MONITOR}, 133 #define K_MTU 25 134 {"mtu", K_MTU}, 135 #define K_NET 26 136 {"net", K_NET}, 137 #define K_NETMASK 27 138 {"netmask", K_NETMASK}, 139 #define K_NOSTATIC 28 140 {"nostatic", K_NOSTATIC}, 141 #define K_PRIVATE 29 142 {"private", K_PRIVATE}, 143 #define K_PROTO1 30 144 {"proto1", K_PROTO1}, 145 #define K_PROTO2 31 146 {"proto2", K_PROTO2}, 147 #define K_RECVPIPE 32 148 {"recvpipe", K_RECVPIPE}, 149 #define K_REJECT 33 150 {"reject", K_REJECT}, 151 #define K_RTT 34 152 {"rtt", K_RTT}, 153 #define K_RTTVAR 35 154 {"rttvar", K_RTTVAR}, 155 #define K_SA 36 156 {"sa", K_SA}, 157 #define K_SENDPIPE 37 158 {"sendpipe", K_SENDPIPE}, 159 #define K_SSTHRESH 38 160 {"ssthresh", K_SSTHRESH}, 161 #define K_STATIC 39 162 {"static", K_STATIC}, 163 #define K_XRESOLVE 40 164 {"xresolve", K_XRESOLVE}, 165 #define K_MULTIRT 41 166 {"multirt", K_MULTIRT}, 167 #define K_SETSRC 42 168 {"setsrc", K_SETSRC}, 169 #define K_SHOW 43 170 {"show", K_SHOW}, 171 {0, 0} 172 }; 173 174 /* 175 * Size of buffers used to hold command lines from the saved route file as 176 * well as error strings. 177 */ 178 #define BUF_SIZE 2048 179 180 typedef union sockunion { 181 struct sockaddr sa; 182 struct sockaddr_in sin; 183 struct sockaddr_dl sdl; 184 struct sockaddr_in6 sin6; 185 } su_t; 186 187 /* 188 * This structure represents the digested information from parsing arguments 189 * to route add, change, delete, and get. 190 * 191 */ 192 typedef struct rtcmd_irep { 193 int ri_cmd; 194 int ri_flags; 195 int ri_af; 196 int ri_masklen; 197 ulong_t ri_inits; 198 struct rt_metrics ri_metrics; 199 int ri_addrs; 200 su_t ri_dst; 201 char *ri_dest_str; 202 su_t ri_src; 203 su_t ri_gate; 204 struct hostent *ri_gate_hp; 205 char *ri_gate_str; 206 su_t ri_mask; 207 su_t ri_ifa; 208 su_t ri_ifp; 209 char *ri_ifp_str; 210 } rtcmd_irep_t; 211 212 typedef struct mib_item_s { 213 struct mib_item_s *next_item; 214 long group; 215 long mib_id; 216 long length; 217 intmax_t *valp; 218 } mib_item_t; 219 220 typedef enum { 221 ADDR_TYPE_ANY, 222 ADDR_TYPE_HOST, 223 ADDR_TYPE_NET 224 } addr_type_t; 225 226 typedef enum { 227 SEARCH_MODE_NULL, 228 SEARCH_MODE_PRINT, 229 SEARCH_MODE_DEL 230 } search_mode_t; 231 232 static boolean_t args_to_rtcmd(rtcmd_irep_t *rcip, char **argv, 233 char *cmd_string); 234 static void bprintf(FILE *fp, int b, char *s); 235 static boolean_t compare_rtcmd(rtcmd_irep_t *srch_rt, 236 rtcmd_irep_t *file_rt); 237 static void delRouteEntry(mib2_ipRouteEntry_t *rp, 238 mib2_ipv6RouteEntry_t *rp6, int seqno); 239 static void del_rtcmd_irep(rtcmd_irep_t *rcip); 240 static void flushroutes(int argc, char *argv[]); 241 static boolean_t getaddr(rtcmd_irep_t *rcip, int which, char *s, 242 addr_type_t atype); 243 static boolean_t in6_getaddr(char *s, struct sockaddr_in6 *sin6, 244 int *plenp, struct hostent **hpp); 245 static boolean_t in_getaddr(char *s, struct sockaddr_in *sin, 246 int *plenp, int which, struct hostent **hpp, addr_type_t atype, 247 rtcmd_irep_t *rcip); 248 static int in_getprefixlen(char *addr, int max_plen); 249 static boolean_t in_prefixlentomask(int prefixlen, int maxlen, 250 uchar_t *mask); 251 static void inet_makenetandmask(rtcmd_irep_t *rcip, in_addr_t net, 252 struct sockaddr_in *sin); 253 static in_addr_t inet_makesubnetmask(in_addr_t addr, in_addr_t mask); 254 static int keyword(char *cp); 255 static void link_addr(const char *addr, struct sockaddr_dl *sdl); 256 static char *link_ntoa(const struct sockaddr_dl *sdl); 257 static mib_item_t *mibget(int sd); 258 static char *netname(struct sockaddr *sa); 259 static int newroute(char **argv); 260 static rtcmd_irep_t *new_rtcmd_irep(void); 261 static void pmsg_addrs(char *cp, int addrs); 262 static void pmsg_common(struct rt_msghdr *rtm); 263 static void print_getmsg(rtcmd_irep_t *req_rt, 264 struct rt_msghdr *rtm, int msglen); 265 static void print_rtcmd_short(FILE *to, rtcmd_irep_t *rcip, 266 boolean_t gw_good, boolean_t to_saved); 267 static void print_rtmsg(struct rt_msghdr *rtm, int msglen); 268 static void quit(char *s, int err); 269 static char *routename(struct sockaddr *sa); 270 static void rtmonitor(int argc, char *argv[]); 271 static int rtmsg(rtcmd_irep_t *rcip); 272 static int salen(struct sockaddr *sa); 273 static void save_route(int argc, char **argv); 274 static void save_string(char **dst, char *src); 275 static int search_rtfile(FILE *fp, FILE *temp_fp, rtcmd_irep_t *rt, 276 search_mode_t mode); 277 static void set_metric(rtcmd_irep_t *rcip, char *value, int key, 278 boolean_t lock); 279 static int show_saved_routes(int argc); 280 static void sockaddr(char *addr, struct sockaddr *sa); 281 static void sodump(su_t *su, char *which); 282 static void syntax_arg_missing(char *keyword); 283 static void syntax_bad_keyword(char *keyword); 284 static void syntax_error(char *err, ...); 285 static void usage(char *cp); 286 static void write_to_rtfile(FILE *fp, int argc, char **argv); 287 288 static pid_t pid; 289 static int s; 290 static boolean_t nflag; 291 static int af = AF_INET; 292 static boolean_t qflag, tflag; 293 static boolean_t verbose; 294 static boolean_t debugonly; 295 static boolean_t fflag; 296 static boolean_t perm_flag; 297 static char perm_file_sfx[] = "/etc/inet/static_routes"; 298 static char *perm_file; 299 static char *root_dir; 300 static char temp_file_sfx[] = "/etc/inet/static_routes.tmp"; 301 static char *temp_file; 302 303 /* 304 * WARNING: 305 * This next variable indicates whether certain functions exit when an error 306 * is detected in the user input. Currently, exit_on_error is only set false 307 * in search_rtfile(), when argument are being parsed. Only those functions 308 * used by search_rtfile() to parse its arguments are designed to work in 309 * both modes. Take particular care in setting this false to ensure that any 310 * functions you call that might act on this flag properly return errors when 311 * exit_on_error is false. 312 */ 313 static int exit_on_error = B_TRUE; 314 315 static struct { 316 struct rt_msghdr m_rtm; 317 char m_space[512]; 318 } m_rtmsg; 319 320 /* 321 * Sizes of data structures extracted from the base mib. 322 * This allows the size of the tables entries to grow while preserving 323 * binary compatibility. 324 */ 325 static int ipRouteEntrySize; 326 static int ipv6RouteEntrySize; 327 328 #define ROUNDUP_LONG(a) \ 329 ((a) > 0 ? (1 + (((a) - 1) | (sizeof (long) - 1))) : sizeof (long)) 330 #define ADVANCE(x, n) ((x) += ROUNDUP_LONG(salen(n))) 331 #define C(x) ((x) & 0xff) 332 333 /* 334 * return values from in_getprefixlen() 335 */ 336 #define BAD_ADDR -1 /* prefix is invalid */ 337 #define NO_PREFIX -2 /* no prefix was found */ 338 339 340 void 341 usage(char *cp) 342 { 343 if (cp != NULL) { 344 (void) fprintf(stderr, gettext("route: botched keyword: %s\n"), 345 cp); 346 } 347 (void) fprintf(stderr, gettext("usage: route [ -fnpqv ] " 348 "[ -R <root-dir> ] cmd [[ -<qualifers> ] args ]\n")); 349 exit(1); 350 /* NOTREACHED */ 351 } 352 353 /*PRINTFLIKE1*/ 354 void 355 syntax_error(char *err, ...) 356 { 357 va_list args; 358 359 if (exit_on_error) { 360 va_start(args, err); 361 (void) vfprintf(stderr, err, args); 362 va_end(args); 363 exit(1); 364 } 365 /* NOTREACHED */ 366 } 367 368 void 369 syntax_bad_keyword(char *keyword) 370 { 371 syntax_error(gettext("route: botched keyword: %s\n"), keyword); 372 } 373 374 void 375 syntax_arg_missing(char *keyword) 376 { 377 syntax_error(gettext("route: argument required following keyword %s\n"), 378 keyword); 379 } 380 381 void 382 quit(char *s, int sverrno) 383 { 384 (void) fprintf(stderr, "route: "); 385 if (s != NULL) 386 (void) fprintf(stderr, "%s: ", s); 387 (void) fprintf(stderr, "%s\n", strerror(sverrno)); 388 exit(sverrno); 389 /* NOTREACHED */ 390 } 391 392 int 393 main(int argc, char **argv) 394 { 395 extern int optind; 396 extern char *optarg; 397 int ch; 398 int key; 399 int rval; 400 size_t size; 401 402 (void) setlocale(LC_ALL, ""); 403 404 #if !defined(TEXT_DOMAIN) 405 #define TEXT_DOMAIN "SYS_TEST" 406 #endif 407 (void) textdomain(TEXT_DOMAIN); 408 409 if (argc < 2) 410 usage((char *)NULL); 411 412 while ((ch = getopt(argc, argv, "R:nqdtvfp")) != EOF) { 413 switch (ch) { 414 case 'n': 415 nflag = B_TRUE; 416 break; 417 case 'q': 418 qflag = B_TRUE; 419 break; 420 case 'v': 421 verbose = B_TRUE; 422 break; 423 case 't': 424 tflag = B_TRUE; 425 break; 426 case 'd': 427 debugonly = B_TRUE; 428 break; 429 case 'f': 430 fflag = B_TRUE; 431 break; 432 case 'p': 433 perm_flag = B_TRUE; 434 break; 435 case 'R': 436 root_dir = optarg; 437 break; 438 case '?': 439 default: 440 usage((char *)NULL); 441 /* NOTREACHED */ 442 } 443 } 444 argc -= optind; 445 argv += optind; 446 447 pid = getpid(); 448 if (tflag) 449 s = open("/dev/null", O_WRONLY); 450 else 451 s = socket(PF_ROUTE, SOCK_RAW, 0); 452 if (s < 0) 453 quit("socket", errno); 454 455 /* 456 * Handle the -p and -R flags. The -R flag only applies 457 * when the -p flag is set. 458 */ 459 if (root_dir == NULL) { 460 perm_file = perm_file_sfx; 461 temp_file = temp_file_sfx; 462 } else { 463 size = strlen(root_dir) + sizeof (perm_file_sfx); 464 perm_file = malloc(size); 465 if (perm_file == NULL) 466 quit("malloc", errno); 467 (void) snprintf(perm_file, size, "%s%s", root_dir, 468 perm_file_sfx); 469 size = strlen(root_dir) + sizeof (temp_file_sfx); 470 temp_file = malloc(size); 471 if (temp_file == NULL) 472 quit("malloc", errno); 473 (void) snprintf(temp_file, size, "%s%s", root_dir, 474 temp_file_sfx); 475 } 476 477 if (fflag) { 478 /* 479 * Accept an address family keyword after the -f. Since the 480 * default address family is AF_INET, reassign af only for the 481 * other valid address families. 482 */ 483 if (*argv != NULL) { 484 switch (key = keyword(*argv)) { 485 case K_INET: 486 case K_INET6: 487 if (key == K_INET6) 488 af = AF_INET6; 489 /* Skip over the address family parameter. */ 490 argc--; 491 argv++; 492 break; 493 } 494 } 495 if (perm_flag && root_dir != NULL) { 496 /* 497 * Act only on the file. 498 */ 499 save_route(argc, argv); 500 } else { 501 flushroutes(0, NULL); 502 } 503 } 504 505 if (*argv != NULL) { 506 fflag = 0; 507 switch (keyword(*argv)) { 508 case K_GET: 509 case K_CHANGE: 510 case K_ADD: 511 case K_DELETE: 512 if (perm_flag && root_dir != NULL) { 513 /* 514 * Act only on the file. 515 */ 516 rval = 0; 517 } else { 518 rval = newroute(argv); 519 } 520 if (perm_flag && (rval == 0 || rval == EEXIST || 521 rval == ESRCH)) { 522 save_route(argc, argv); 523 return (0); 524 } 525 return (rval); 526 case K_SHOW: 527 if (perm_flag) { 528 return (show_saved_routes(argc)); 529 } else { 530 syntax_error(gettext( 531 "route: show command requires -p")); 532 } 533 /* NOTREACHED */ 534 case K_MONITOR: 535 rtmonitor(argc, argv); 536 /* NOTREACHED */ 537 538 case K_FLUSH: 539 flushroutes(argc, argv); 540 if (perm_flag) { 541 fflag = 1; 542 save_route(argc, argv); 543 } 544 return (0); 545 } 546 } 547 if (!fflag) 548 usage(*argv); 549 return (0); 550 } 551 552 /* 553 * Purge all entries in the routing tables not 554 * associated with network interfaces. 555 */ 556 void 557 flushroutes(int argc, char *argv[]) 558 { 559 int seqno; 560 int sd; /* mib stream */ 561 mib_item_t *item; 562 mib2_ipRouteEntry_t *rp; 563 mib2_ipv6RouteEntry_t *rp6; 564 int oerrno; 565 int off = 0; 566 int on = 1; 567 568 if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&off, 569 sizeof (off)) < 0) 570 quit("setsockopt", errno); 571 if (argc > 1) { 572 argv++; 573 if (argc == 2 && **argv == '-') { 574 /* 575 * The address family (preceded by a dash) may be used 576 * to flush the routes of that particular family. 577 */ 578 switch (keyword(*argv + 1)) { 579 case K_INET: 580 af = AF_INET; 581 break; 582 case K_LINK: 583 af = AF_LINK; 584 break; 585 case K_INET6: 586 af = AF_INET6; 587 break; 588 default: 589 usage(*argv); 590 /* NOTREACHED */ 591 } 592 } else { 593 usage(*argv); 594 } 595 } 596 sd = open("/dev/ip", O_RDWR); 597 oerrno = errno; 598 if (sd < 0) { 599 switch (errno) { 600 case EACCES: 601 (void) fprintf(stderr, 602 gettext("route: flush: insufficient privileges\n")); 603 exit(oerrno); 604 /* NOTREACHED */ 605 default: 606 quit(gettext("can't open mib stream"), oerrno); 607 /* NOTREACHED */ 608 } 609 } 610 if ((item = mibget(sd)) == NULL) 611 quit("mibget", errno); 612 if (verbose) { 613 (void) printf("Examining routing table from " 614 "T_SVR4_OPTMGMT_REQ\n"); 615 } 616 seqno = 0; /* ??? */ 617 switch (af) { 618 case AF_INET: 619 /* Extract ipRouteEntrySize */ 620 for (; item != NULL; item = item->next_item) { 621 if (item->mib_id != 0) 622 continue; 623 if (item->group == MIB2_IP) { 624 ipRouteEntrySize = 625 ((mib2_ip_t *)item->valp)->ipRouteEntrySize; 626 assert(IS_P2ALIGNED(ipRouteEntrySize, 627 sizeof (mib2_ipRouteEntry_t *))); 628 break; 629 } 630 } 631 if (ipRouteEntrySize == 0) { 632 (void) fprintf(stderr, 633 gettext("ipRouteEntrySize can't be determined.\n")); 634 exit(1); 635 } 636 for (; item != NULL; item = item->next_item) { 637 /* 638 * skip all the other trash that comes up the mib stream 639 */ 640 if (item->group != MIB2_IP || 641 item->mib_id != MIB2_IP_ROUTE) 642 continue; 643 for (rp = (mib2_ipRouteEntry_t *)item->valp; 644 (char *)rp < (char *)item->valp + item->length; 645 /* LINTED */ 646 rp = (mib2_ipRouteEntry_t *) 647 ((char *)rp + ipRouteEntrySize)) { 648 delRouteEntry(rp, NULL, seqno); 649 seqno++; 650 } 651 break; 652 } 653 break; 654 case AF_INET6: 655 /* Extract ipv6RouteEntrySize */ 656 for (; item != NULL; item = item->next_item) { 657 if (item->mib_id != 0) 658 continue; 659 if (item->group == MIB2_IP6) { 660 ipv6RouteEntrySize = 661 ((mib2_ipv6IfStatsEntry_t *)item->valp)-> 662 ipv6RouteEntrySize; 663 assert(IS_P2ALIGNED(ipv6RouteEntrySize, 664 sizeof (mib2_ipv6RouteEntry_t *))); 665 break; 666 } 667 } 668 if (ipv6RouteEntrySize == 0) { 669 (void) fprintf(stderr, gettext( 670 "ipv6RouteEntrySize cannot be determined.\n")); 671 exit(1); 672 } 673 for (; item != NULL; item = item->next_item) { 674 /* 675 * skip all the other trash that comes up the mib stream 676 */ 677 if (item->group != MIB2_IP6 || 678 item->mib_id != MIB2_IP6_ROUTE) 679 continue; 680 for (rp6 = (mib2_ipv6RouteEntry_t *)item->valp; 681 (char *)rp6 < (char *)item->valp + item->length; 682 /* LINTED */ 683 rp6 = (mib2_ipv6RouteEntry_t *) 684 ((char *)rp6 + ipv6RouteEntrySize)) { 685 delRouteEntry(NULL, rp6, seqno); 686 seqno++; 687 } 688 break; 689 } 690 break; 691 } 692 693 if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&on, 694 sizeof (on)) < 0) 695 quit("setsockopt", errno); 696 } 697 698 /* 699 * Given the contents of a mib_item_t of id type MIB2_IP_ROUTE or 700 * MIB2_IP6_ROUTE, construct and send an RTM_DELETE routing socket message in 701 * order to facilitate the flushing of RTF_GATEWAY routes. 702 */ 703 static void 704 delRouteEntry(mib2_ipRouteEntry_t *rp, mib2_ipv6RouteEntry_t *rp6, int seqno) 705 { 706 char *cp; 707 int ire_type; 708 int rlen; 709 struct rt_msghdr *rtm; 710 struct sockaddr_in sin; 711 struct sockaddr_in6 sin6; 712 int slen; 713 714 if (rp != NULL) 715 ire_type = rp->ipRouteInfo.re_ire_type; 716 else 717 ire_type = rp6->ipv6RouteInfo.re_ire_type; 718 if (ire_type != IRE_DEFAULT && 719 ire_type != IRE_PREFIX && 720 ire_type != IRE_HOST && 721 ire_type != IRE_HOST_REDIRECT) 722 return; 723 724 rtm = &m_rtmsg.m_rtm; 725 (void) memset(rtm, 0, sizeof (m_rtmsg)); 726 rtm->rtm_type = RTM_DELETE; 727 rtm->rtm_seq = seqno; 728 rtm->rtm_flags |= RTF_GATEWAY; 729 rtm->rtm_version = RTM_VERSION; 730 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 731 cp = m_rtmsg.m_space; 732 if (rp != NULL) { 733 slen = sizeof (struct sockaddr_in); 734 if (rp->ipRouteMask == IP_HOST_MASK) 735 rtm->rtm_flags |= RTF_HOST; 736 (void) memset(&sin, 0, slen); 737 sin.sin_family = AF_INET; 738 sin.sin_addr.s_addr = rp->ipRouteDest; 739 (void) memmove(cp, &sin, slen); 740 cp += slen; 741 sin.sin_addr.s_addr = rp->ipRouteNextHop; 742 (void) memmove(cp, &sin, slen); 743 cp += slen; 744 sin.sin_addr.s_addr = rp->ipRouteMask; 745 (void) memmove(cp, &sin, slen); 746 cp += slen; 747 } else { 748 slen = sizeof (struct sockaddr_in6); 749 if (rp6->ipv6RoutePfxLength == IPV6_ABITS) 750 rtm->rtm_flags |= RTF_HOST; 751 (void) memset(&sin6, 0, slen); 752 sin6.sin6_family = AF_INET6; 753 sin6.sin6_addr = rp6->ipv6RouteDest; 754 (void) memmove(cp, &sin6, slen); 755 cp += slen; 756 sin6.sin6_addr = rp6->ipv6RouteNextHop; 757 (void) memmove(cp, &sin6, slen); 758 cp += slen; 759 (void) memset(&sin6.sin6_addr, 0, sizeof (sin6.sin6_addr)); 760 (void) in_prefixlentomask(rp6->ipv6RoutePfxLength, IPV6_ABITS, 761 (uchar_t *)&sin6.sin6_addr.s6_addr); 762 (void) memmove(cp, &sin6, slen); 763 cp += slen; 764 } 765 rtm->rtm_msglen = cp - (char *)&m_rtmsg; 766 if (debugonly) { 767 /* 768 * In debugonly mode, the routing socket message to delete the 769 * current entry is not actually sent. However if verbose is 770 * also set, the routing socket message that would have been 771 * is printed. 772 */ 773 if (verbose) 774 print_rtmsg(rtm, rtm->rtm_msglen); 775 return; 776 } 777 778 rlen = write(s, (char *)&m_rtmsg, rtm->rtm_msglen); 779 if (rlen < (int)rtm->rtm_msglen) { 780 if (rlen < 0) { 781 (void) fprintf(stderr, 782 gettext("route: write to routing socket: %s\n"), 783 strerror(errno)); 784 } else { 785 (void) fprintf(stderr, gettext("route: write to " 786 "routing socket got only %d for rlen\n"), rlen); 787 } 788 return; 789 } 790 if (qflag) { 791 /* 792 * In quiet mode, nothing is printed at all (unless the write() 793 * itself failed. 794 */ 795 return; 796 } 797 if (verbose) { 798 print_rtmsg(rtm, rlen); 799 } else { 800 struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 801 802 (void) printf("%-20.20s ", 803 rtm->rtm_flags & RTF_HOST ? routename(sa) : 804 netname(sa)); 805 /* LINTED */ 806 sa = (struct sockaddr *)(salen(sa) + (char *)sa); 807 (void) printf("%-20.20s ", routename(sa)); 808 (void) printf("done\n"); 809 } 810 } 811 812 /* 813 * Return the name of the host whose address is given. 814 */ 815 char * 816 routename(struct sockaddr *sa) 817 { 818 char *cp; 819 static char line[MAXHOSTNAMELEN + 1]; 820 struct hostent *hp = NULL; 821 static char domain[MAXHOSTNAMELEN + 1]; 822 static boolean_t first = B_TRUE; 823 struct in_addr in; 824 struct in6_addr in6; 825 int error_num; 826 ushort_t *s; 827 ushort_t *slim; 828 829 if (first) { 830 first = B_FALSE; 831 if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 832 (cp = strchr(domain, '.'))) 833 (void) strcpy(domain, cp + 1); 834 else 835 domain[0] = 0; 836 } 837 838 if (salen(sa) == 0) { 839 (void) strcpy(line, "default"); 840 return (line); 841 } 842 switch (sa->sa_family) { 843 844 case AF_INET: 845 /* LINTED */ 846 in = ((struct sockaddr_in *)sa)->sin_addr; 847 848 cp = NULL; 849 if (in.s_addr == INADDR_ANY) 850 cp = "default"; 851 if (cp == NULL && !nflag) { 852 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 853 AF_INET); 854 if (hp != NULL) { 855 if (((cp = strchr(hp->h_name, '.')) != NULL) && 856 (strcmp(cp + 1, domain) == 0)) 857 *cp = 0; 858 cp = hp->h_name; 859 } 860 } 861 if (cp != NULL) { 862 (void) strncpy(line, cp, MAXHOSTNAMELEN); 863 line[MAXHOSTNAMELEN] = '\0'; 864 } else { 865 in.s_addr = ntohl(in.s_addr); 866 (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 867 C(in.s_addr >> 16), C(in.s_addr >> 8), 868 C(in.s_addr)); 869 } 870 break; 871 872 case AF_LINK: 873 return (link_ntoa((struct sockaddr_dl *)sa)); 874 875 case AF_INET6: 876 /* LINTED */ 877 in6 = ((struct sockaddr_in6 *)sa)->sin6_addr; 878 879 cp = NULL; 880 if (IN6_IS_ADDR_UNSPECIFIED(&in6)) 881 cp = "default"; 882 if (cp == NULL && !nflag) { 883 hp = getipnodebyaddr((char *)&in6, 884 sizeof (struct in6_addr), AF_INET6, &error_num); 885 if (hp != NULL) { 886 if (((cp = strchr(hp->h_name, '.')) != NULL) && 887 (strcmp(cp + 1, domain) == 0)) 888 *cp = 0; 889 cp = hp->h_name; 890 } 891 } 892 if (cp != NULL) { 893 (void) strncpy(line, cp, MAXHOSTNAMELEN); 894 line[MAXHOSTNAMELEN] = '\0'; 895 } else { 896 (void) inet_ntop(AF_INET6, (void *)&in6, line, 897 INET6_ADDRSTRLEN); 898 } 899 if (hp != NULL) 900 freehostent(hp); 901 902 break; 903 904 default: 905 s = (ushort_t *)sa; 906 907 slim = s + ((salen(sa) + 1) >> 1); 908 cp = line + sprintf(line, "(%d)", sa->sa_family); 909 910 while (++s < slim) /* start with sa->sa_data */ 911 cp += sprintf(cp, " %x", *s); 912 break; 913 } 914 return (line); 915 } 916 917 /* 918 * Return the name of the network whose address is given. 919 * The address is assumed to be that of a net or subnet, not a host. 920 */ 921 static char * 922 netname(struct sockaddr *sa) 923 { 924 char *cp = NULL; 925 static char line[MAXHOSTNAMELEN + 1]; 926 struct netent *np; 927 in_addr_t net, mask; 928 int subnetshift; 929 struct in_addr in; 930 ushort_t *s; 931 ushort_t *slim; 932 933 switch (sa->sa_family) { 934 935 case AF_INET: 936 /* LINTED */ 937 in = ((struct sockaddr_in *)sa)->sin_addr; 938 939 in.s_addr = ntohl(in.s_addr); 940 if (in.s_addr == INADDR_ANY) { 941 cp = "default"; 942 } else if (!nflag) { 943 if (IN_CLASSA(in.s_addr)) { 944 mask = IN_CLASSA_NET; 945 subnetshift = 8; 946 } else if (IN_CLASSB(in.s_addr)) { 947 mask = IN_CLASSB_NET; 948 subnetshift = 8; 949 } else { 950 mask = IN_CLASSC_NET; 951 subnetshift = 4; 952 } 953 /* 954 * If there are more bits than the standard mask 955 * would suggest, subnets must be in use. 956 * Guess at the subnet mask, assuming reasonable 957 * width subnet fields. 958 */ 959 while (in.s_addr &~ mask) 960 mask = (long)mask >> subnetshift; 961 net = in.s_addr & mask; 962 while ((mask & 1) == 0) 963 mask >>= 1, net >>= 1; 964 np = getnetbyaddr(net, AF_INET); 965 if (np != NULL) 966 cp = np->n_name; 967 } 968 if (cp != NULL) { 969 (void) strncpy(line, cp, MAXHOSTNAMELEN); 970 line[MAXHOSTNAMELEN] = '\0'; 971 } else if ((in.s_addr & 0xffffff) == 0) { 972 (void) sprintf(line, "%u", C(in.s_addr >> 24)); 973 } else if ((in.s_addr & 0xffff) == 0) { 974 (void) sprintf(line, "%u.%u", C(in.s_addr >> 24), 975 C(in.s_addr >> 16)); 976 } else if ((in.s_addr & 0xff) == 0) { 977 (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24), 978 C(in.s_addr >> 16), C(in.s_addr >> 8)); 979 } else { 980 (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 981 C(in.s_addr >> 16), C(in.s_addr >> 8), 982 C(in.s_addr)); 983 } 984 break; 985 986 case AF_LINK: 987 return (link_ntoa((struct sockaddr_dl *)sa)); 988 989 case AF_INET6: 990 return (routename(sa)); 991 992 default: 993 /* LINTED */ 994 s = (ushort_t *)sa->sa_data; 995 996 slim = s + ((salen(sa) + 1) >> 1); 997 cp = line + sprintf(line, "af %d:", sa->sa_family); 998 999 while (s < slim) 1000 cp += sprintf(cp, " %x", *s++); 1001 break; 1002 } 1003 return (line); 1004 } 1005 1006 /* 1007 * Initialize a new structure. Keep in mind that ri_dst_str, ri_gate_str and 1008 * ri_ifp_str will be freed by det_rtcmd_irep, so they should either be NULL 1009 * or point to dynamically allocated memory. 1010 */ 1011 rtcmd_irep_t * 1012 new_rtcmd_irep(void) 1013 { 1014 rtcmd_irep_t *rcip; 1015 1016 rcip = calloc(1, sizeof (rtcmd_irep_t)); 1017 if (rcip == NULL) { 1018 quit("calloc", errno); 1019 } 1020 rcip->ri_af = AF_INET; 1021 rcip->ri_flags = RTF_STATIC; 1022 return (rcip); 1023 } 1024 1025 void 1026 del_rtcmd_irep(rtcmd_irep_t *rcip) 1027 { 1028 free(rcip->ri_dest_str); 1029 free(rcip->ri_gate_str); 1030 free(rcip->ri_ifp_str); 1031 if (rcip->ri_gate_hp != NULL) { 1032 freehostent(rcip->ri_gate_hp); 1033 } 1034 free(rcip); 1035 } 1036 1037 void 1038 save_string(char **dst, char *src) 1039 { 1040 free(*dst); 1041 *dst = strdup(src); 1042 if (*dst == NULL) { 1043 quit("malloc", errno); 1044 } 1045 } 1046 1047 /* 1048 * Print the short form summary of a route command. 1049 * Eg. "add net default: gateway 10.0.0.1" 1050 * The final newline is not added, allowing the caller to append additional 1051 * information. 1052 */ 1053 void 1054 print_rtcmd_short(FILE *to, rtcmd_irep_t *rcip, boolean_t gw_good, 1055 boolean_t to_saved) 1056 { 1057 char *cmd; 1058 char obuf[INET6_ADDRSTRLEN]; 1059 1060 switch (rcip->ri_cmd) { 1061 case RTM_ADD: 1062 cmd = "add"; 1063 break; 1064 case RTM_CHANGE: 1065 cmd = "change"; 1066 break; 1067 case RTM_DELETE: 1068 cmd = "delete"; 1069 break; 1070 case RTM_GET: 1071 cmd = "get"; 1072 break; 1073 default: 1074 assert(0); 1075 } 1076 1077 (void) fprintf(to, "%s%s %s %s", cmd, 1078 (to_saved) ? " persistent" : "", 1079 (rcip->ri_flags & RTF_HOST) ? "host" : "net", 1080 (rcip->ri_dest_str == NULL) ? "NULL" : rcip->ri_dest_str); 1081 1082 if (rcip->ri_gate_str != NULL) { 1083 switch (rcip->ri_af) { 1084 case AF_INET: 1085 if (nflag) { 1086 (void) fprintf(to, ": gateway %s", 1087 inet_ntoa(rcip->ri_gate.sin.sin_addr)); 1088 } else if (gw_good && 1089 rcip->ri_gate_hp != NULL && 1090 rcip->ri_gate_hp->h_addr_list[1] != NULL) { 1091 /* 1092 * Print the actual address used in the case 1093 * where there was more than one address 1094 * available for the name, and one was used 1095 * successfully. 1096 */ 1097 (void) fprintf(to, ": gateway %s (%s)", 1098 rcip->ri_gate_str, 1099 inet_ntoa(rcip->ri_gate.sin.sin_addr)); 1100 } else { 1101 (void) fprintf(to, ": gateway %s", 1102 rcip->ri_gate_str); 1103 } 1104 break; 1105 case AF_INET6: 1106 if (inet_ntop(AF_INET6, 1107 &rcip->ri_gate.sin6.sin6_addr, obuf, 1108 INET6_ADDRSTRLEN) != NULL) { 1109 if (nflag) { 1110 (void) fprintf(to, ": gateway %s", 1111 obuf); 1112 break; 1113 } 1114 if (gw_good && 1115 rcip->ri_gate_hp->h_addr_list[1] != NULL) { 1116 (void) fprintf(to, ": gateway %s (%s)", 1117 rcip->ri_gate_str, obuf); 1118 break; 1119 } 1120 } 1121 /* FALLTHROUGH */ 1122 default: 1123 (void) fprintf(to, ": gateway %s", 1124 rcip->ri_gate_str); 1125 break; 1126 } 1127 } 1128 } 1129 1130 void 1131 set_metric(rtcmd_irep_t *rcip, char *value, int key, boolean_t lock) 1132 { 1133 int flag = 0; 1134 uint_t noval, *valp = &noval; 1135 1136 switch (key) { 1137 #define caseof(x, y, z) \ 1138 case (x): valp = &(rcip->ri_metrics.z); flag = (y); break 1139 1140 caseof(K_MTU, RTV_MTU, rmx_mtu); 1141 caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); 1142 caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); 1143 caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); 1144 caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); 1145 caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); 1146 caseof(K_RTT, RTV_RTT, rmx_rtt); 1147 caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); 1148 #undef caseof 1149 } 1150 rcip->ri_inits |= flag; 1151 if (lock) 1152 rcip->ri_metrics.rmx_locks |= flag; 1153 *valp = atoi(value); 1154 } 1155 1156 /* 1157 * Parse the options give in argv[], filling in rcip with the results. 1158 * If cmd_string is non-null, argc and argv are ignored, and cmd_string is 1159 * tokenized to produce the command line. Cmd_string is tokenized using 1160 * strtok, which will overwrite whitespace in the string with nulls. 1161 * 1162 * Returns B_TRUE on success and B_FALSE on failure. 1163 */ 1164 boolean_t 1165 args_to_rtcmd(rtcmd_irep_t *rcip, char **argv, char *cmd_string) 1166 { 1167 const char *ws = "\f\n\r\t\v "; 1168 char *tok = cmd_string; 1169 char *keyword_str; 1170 addr_type_t atype = ADDR_TYPE_ANY; 1171 boolean_t iflag = B_FALSE; 1172 boolean_t locknext = B_FALSE; 1173 boolean_t lockrest = B_FALSE; 1174 boolean_t dash_keyword; 1175 int key; 1176 char *err; 1177 1178 if (cmd_string == NULL) { 1179 tok = argv[0]; 1180 } else { 1181 tok = strtok(cmd_string, ws); 1182 } 1183 1184 /* 1185 * The command keywords are already fully checked by main() or 1186 * search_rtfile(). 1187 */ 1188 switch (*tok) { 1189 case 'a': 1190 rcip->ri_cmd = RTM_ADD; 1191 break; 1192 case 'c': 1193 rcip->ri_cmd = RTM_CHANGE; 1194 break; 1195 case 'd': 1196 rcip->ri_cmd = RTM_DELETE; 1197 break; 1198 case 'g': 1199 rcip->ri_cmd = RTM_GET; 1200 break; 1201 default: 1202 /* NOTREACHED */ 1203 quit(gettext("Internal Error"), EINVAL); 1204 /* NOTREACHED */ 1205 } 1206 1207 #define NEXTTOKEN \ 1208 ((tok = (cmd_string == NULL ? *++argv : strtok(NULL, ws))) != NULL) 1209 1210 while (NEXTTOKEN) { 1211 keyword_str = tok; 1212 if (*tok == '-') { 1213 dash_keyword = B_TRUE; 1214 key = keyword(tok + 1); 1215 } else { 1216 dash_keyword = B_FALSE; 1217 key = keyword(tok); 1218 if (key != K_HOST && key != K_NET) { 1219 /* All others must be preceded by '-' */ 1220 key = 0; 1221 } 1222 } 1223 switch (key) { 1224 case K_HOST: 1225 if (atype == ADDR_TYPE_NET) { 1226 syntax_error(gettext("route: -host and -net " 1227 "are mutually exclusive\n")); 1228 return (B_FALSE); 1229 } 1230 atype = ADDR_TYPE_HOST; 1231 break; 1232 case K_NET: 1233 if (atype == ADDR_TYPE_HOST) { 1234 syntax_error(gettext("route: -host and -net " 1235 "are mutually exclusive\n")); 1236 return (B_FALSE); 1237 } 1238 atype = ADDR_TYPE_NET; 1239 break; 1240 case K_LINK: 1241 rcip->ri_af = AF_LINK; 1242 break; 1243 case K_INET: 1244 rcip->ri_af = AF_INET; 1245 break; 1246 case K_SA: 1247 rcip->ri_af = PF_ROUTE; 1248 break; 1249 case K_INET6: 1250 rcip->ri_af = AF_INET6; 1251 break; 1252 case K_IFACE: 1253 case K_INTERFACE: 1254 iflag = B_TRUE; 1255 break; 1256 case K_NOSTATIC: 1257 rcip->ri_flags &= ~RTF_STATIC; 1258 break; 1259 case K_LOCK: 1260 locknext = B_TRUE; 1261 break; 1262 case K_LOCKREST: 1263 lockrest = B_TRUE; 1264 break; 1265 case K_REJECT: 1266 rcip->ri_flags |= RTF_REJECT; 1267 break; 1268 case K_BLACKHOLE: 1269 rcip->ri_flags |= RTF_BLACKHOLE; 1270 break; 1271 case K_PROTO1: 1272 rcip->ri_flags |= RTF_PROTO1; 1273 break; 1274 case K_PROTO2: 1275 rcip->ri_flags |= RTF_PROTO2; 1276 break; 1277 case K_CLONING: 1278 rcip->ri_flags |= RTF_CLONING; 1279 break; 1280 case K_XRESOLVE: 1281 rcip->ri_flags |= RTF_XRESOLVE; 1282 break; 1283 case K_STATIC: 1284 rcip->ri_flags |= RTF_STATIC; 1285 break; 1286 case K_IFA: 1287 if (!NEXTTOKEN) { 1288 syntax_arg_missing(keyword_str); 1289 return (B_FALSE); 1290 } 1291 if (!getaddr(rcip, RTA_IFA, tok, atype)) { 1292 return (B_FALSE); 1293 } 1294 break; 1295 case K_IFP: 1296 if (!NEXTTOKEN) { 1297 syntax_arg_missing(keyword_str); 1298 return (B_FALSE); 1299 } 1300 if (!getaddr(rcip, RTA_IFP, tok, atype)) { 1301 return (B_FALSE); 1302 } 1303 break; 1304 case K_GATEWAY: 1305 if (!NEXTTOKEN) { 1306 syntax_arg_missing(keyword_str); 1307 return (B_FALSE); 1308 } 1309 if (!getaddr(rcip, RTA_GATEWAY, tok, atype)) { 1310 return (B_FALSE); 1311 } 1312 break; 1313 case K_DST: 1314 if (!NEXTTOKEN) { 1315 syntax_arg_missing(keyword_str); 1316 return (B_FALSE); 1317 } 1318 if (!getaddr(rcip, RTA_DST, tok, atype)) { 1319 return (B_FALSE); 1320 } 1321 break; 1322 case K_NETMASK: 1323 if (!NEXTTOKEN) { 1324 syntax_arg_missing(keyword_str); 1325 return (B_FALSE); 1326 } 1327 if (!getaddr(rcip, RTA_NETMASK, tok, atype)) { 1328 return (B_FALSE); 1329 } 1330 atype = ADDR_TYPE_NET; 1331 break; 1332 case K_MTU: 1333 case K_HOPCOUNT: 1334 case K_EXPIRE: 1335 case K_RECVPIPE: 1336 case K_SENDPIPE: 1337 case K_SSTHRESH: 1338 case K_RTT: 1339 case K_RTTVAR: 1340 if (!NEXTTOKEN) { 1341 syntax_arg_missing(keyword_str); 1342 return (B_FALSE); 1343 } 1344 set_metric(rcip, tok, key, locknext || lockrest); 1345 locknext = B_FALSE; 1346 break; 1347 case K_PRIVATE: 1348 rcip->ri_flags |= RTF_PRIVATE; 1349 break; 1350 case K_MULTIRT: 1351 rcip->ri_flags |= RTF_MULTIRT; 1352 break; 1353 case K_SETSRC: 1354 if (!NEXTTOKEN) { 1355 syntax_arg_missing(keyword_str); 1356 return (B_FALSE); 1357 } 1358 if (!getaddr(rcip, RTA_SRC, tok, atype)) { 1359 return (B_FALSE); 1360 } 1361 rcip->ri_flags |= RTF_SETSRC; 1362 break; 1363 default: 1364 if (dash_keyword) { 1365 syntax_bad_keyword(tok + 1); 1366 return (B_FALSE); 1367 } 1368 if ((rcip->ri_addrs & RTA_DST) == 0) { 1369 if (!getaddr(rcip, RTA_DST, tok, atype)) { 1370 return (B_FALSE); 1371 } 1372 } else if ((rcip->ri_addrs & RTA_GATEWAY) == 0) { 1373 /* 1374 * For the gateway parameter, retrieve the 1375 * pointer to the struct hostent so that all 1376 * possible addresses can be tried until one 1377 * is successful. 1378 */ 1379 if (!getaddr(rcip, RTA_GATEWAY, tok, atype)) { 1380 return (B_FALSE); 1381 } 1382 } else { 1383 ulong_t metric; 1384 /* 1385 * Assume that a regular number is a metric. 1386 * Needed for compatibility with old route 1387 * command syntax. 1388 */ 1389 errno = 0; 1390 metric = strtoul(tok, &err, 10); 1391 if (errno == 0 && *err == '\0' && 1392 metric < 0x80000000ul) { 1393 iflag = (metric == 0); 1394 if (verbose) { 1395 (void) printf("old usage of " 1396 "trailing number, assuming " 1397 "route %s\n", iflag ? 1398 "to if" : "via gateway"); 1399 } 1400 continue; 1401 } 1402 if (!getaddr(rcip, RTA_NETMASK, tok, atype)) { 1403 return (B_FALSE); 1404 } 1405 } 1406 } 1407 } 1408 #undef NEXTTOKEN 1409 1410 if ((rcip->ri_addrs & RTA_DST) == 0) { 1411 syntax_error(gettext("route: destination required\n")); 1412 return (B_FALSE); 1413 } else if ((rcip->ri_cmd == RTM_ADD || rcip->ri_cmd == RTM_DELETE) && 1414 (rcip->ri_addrs & RTA_GATEWAY) == 0) { 1415 syntax_error(gettext( 1416 "route: gateway required for add or delete command\n")); 1417 return (B_FALSE); 1418 } 1419 1420 if (!iflag) { 1421 rcip->ri_flags |= RTF_GATEWAY; 1422 } 1423 1424 if (atype != ADDR_TYPE_NET && (rcip->ri_addrs & RTA_NETMASK)) { 1425 if ((rcip->ri_af == AF_INET && 1426 rcip->ri_mask.sin.sin_addr.s_addr == IP_HOST_MASK) || 1427 (rcip->ri_af == AF_INET6 && 1428 rcip->ri_masklen == IPV6_ABITS)) { 1429 atype = ADDR_TYPE_HOST; 1430 } else { 1431 atype = ADDR_TYPE_NET; 1432 } 1433 } 1434 if (atype == ADDR_TYPE_HOST) { 1435 rcip->ri_flags |= RTF_HOST; 1436 } 1437 return (B_TRUE); 1438 } 1439 1440 /* 1441 * This command always seeks to the end of the file prior to writing. 1442 */ 1443 void 1444 write_to_rtfile(FILE *fp, int argc, char **argv) 1445 { 1446 char file_line[BUF_SIZE]; 1447 int len; 1448 int i; 1449 1450 len = 0; 1451 for (i = 0; argc > 0 && len < BUF_SIZE; i++, argc--) { 1452 len += snprintf(&file_line[len], BUF_SIZE - len, "%s ", 1453 argv[i]); 1454 } 1455 if (len >= BUF_SIZE) 1456 quit(gettext("Internal Error"), EINVAL); 1457 file_line[len - 1] = '\n'; 1458 if (fseek(fp, 0, SEEK_END) != 0 || 1459 fputs(file_line, fp) == EOF) { 1460 quit(gettext("failed to write to route file"), 1461 errno); 1462 } 1463 } 1464 1465 boolean_t 1466 compare_rtcmd(rtcmd_irep_t *srch_rt, rtcmd_irep_t *file_rt) 1467 { 1468 if (strcmp(srch_rt->ri_dest_str, file_rt->ri_dest_str) != 0 || 1469 memcmp(&srch_rt->ri_mask, &file_rt->ri_mask, sizeof (su_t)) != 0) { 1470 return (B_FALSE); 1471 } 1472 return (srch_rt->ri_gate_str == NULL || 1473 strcmp(srch_rt->ri_gate_str, file_rt->ri_gate_str) == 0); 1474 } 1475 1476 /* 1477 * Search the route file for routes matching the supplied route. There are 3 1478 * modes of operation: 1479 * SEARCH_MODE_RET - no side effects. 1480 * SEARCH_MODE_PRINT - prints each matching line. 1481 * SEARCH_MODE_DEL - copies all valid, non-matching lines to tmp_fp. 1482 * 1483 * In all cases, the number of matches is returned. If rt is NULL, all routes 1484 * matching the global af value are considered matching. 1485 */ 1486 int 1487 search_rtfile(FILE *fp, FILE *temp_fp, rtcmd_irep_t *rt, search_mode_t mode) 1488 { 1489 char *tmp_buf; 1490 int match_cnt; 1491 boolean_t match; 1492 char file_line[BUF_SIZE + 4] = "add "; 1493 rtcmd_irep_t *thisrt; 1494 1495 match_cnt = 0; 1496 1497 /* 1498 * Leave space at the beginning of file_line for "add ". 1499 */ 1500 while (fgets(file_line + 4, BUF_SIZE, fp) != NULL) { 1501 1502 if (file_line[4] == '#' || file_line[4] == '\n') { 1503 /* Handle comments and blank lines */ 1504 if (mode == SEARCH_MODE_DEL && 1505 fputs(file_line + 4, temp_fp) == EOF) { 1506 quit(gettext( 1507 "route: failed to write to temp file"), 1508 errno); 1509 } 1510 continue; 1511 } 1512 thisrt = new_rtcmd_irep(); 1513 1514 exit_on_error = B_FALSE; 1515 tmp_buf = strdup(file_line); 1516 /* args_to_rtcmd() will mangle the string passed. */ 1517 if (!args_to_rtcmd(thisrt, NULL, tmp_buf)) { 1518 /* There was an error in args_to_rtcmd() or helpers */ 1519 del_rtcmd_irep(thisrt); 1520 free(tmp_buf); 1521 continue; 1522 } 1523 exit_on_error = B_TRUE; 1524 free(tmp_buf); 1525 1526 if (thisrt->ri_gate_str == NULL) { 1527 del_rtcmd_irep(thisrt); 1528 continue; 1529 } 1530 match = (rt == NULL) ? (thisrt->ri_af == af) : 1531 compare_rtcmd(rt, thisrt); 1532 1533 if (match) match_cnt++; 1534 if (match && mode == SEARCH_MODE_PRINT) { 1535 (void) printf("persistent: route %s", file_line); 1536 } 1537 if (match && mode == SEARCH_MODE_DEL) { 1538 thisrt->ri_cmd = RTM_DELETE; 1539 print_rtcmd_short(stdout, thisrt, B_FALSE, B_TRUE); 1540 (void) printf("\n"); 1541 } 1542 del_rtcmd_irep(thisrt); 1543 1544 if (!match && mode == SEARCH_MODE_DEL && 1545 fputs(file_line + 4, temp_fp) == EOF) { 1546 quit(gettext("failed to write to temp file"), 1547 errno); 1548 } 1549 } 1550 return (match_cnt); 1551 } 1552 1553 /* 1554 * Perform the route operation given in argv on the persistent route file. 1555 * If fflag is set, argc and argv are ignored, and the persisten route file 1556 * is flushed of all routes matching the global family. 1557 */ 1558 void 1559 save_route(int argc, char **argv) 1560 { 1561 rtcmd_irep_t *rt; 1562 int perm_fd; 1563 FILE *perm_fp; 1564 FILE *temp_fp; 1565 mode_t fmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 1566 struct flock lock; 1567 struct stat st; 1568 const char commentstr[] = 1569 "# File generated by route(1M) - do not edit.\n"; 1570 1571 perm_fd = open(perm_file, O_RDWR | O_CREAT, fmode); 1572 if (perm_fd == -1 || fstat(perm_fd, &st) == -1) 1573 quit("failed to open route file", errno); 1574 1575 lock.l_type = F_WRLCK; 1576 lock.l_whence = SEEK_SET; 1577 lock.l_start = 0; 1578 lock.l_len = 0; 1579 if (fcntl(perm_fd, F_SETLK, &lock) != 0) { 1580 quit(gettext("failed to lock route file"), errno); 1581 /* NOTREACHED */ 1582 } 1583 if (st.st_size == 0 && 1584 write(perm_fd, commentstr, sizeof (commentstr) - 1) != 1585 sizeof (commentstr) - 1) 1586 quit(gettext("failed to open route file"), errno); 1587 1588 if ((perm_fp = fdopen(perm_fd, "r+")) == NULL) { 1589 quit(gettext("failed to open route file"), errno); 1590 /* NOTREACHED */ 1591 } 1592 1593 if (!fflag) { 1594 rt = new_rtcmd_irep(); 1595 (void) args_to_rtcmd(rt, argv, NULL); 1596 } 1597 if (fflag || rt->ri_cmd == RTM_DELETE) { 1598 if ((temp_fp = fopen(temp_file, "w")) == NULL) { 1599 quit(gettext("failed to open temp file"), errno); 1600 /* NOTREACHED */ 1601 } 1602 } 1603 if (fflag) { 1604 (void) search_rtfile(perm_fp, temp_fp, NULL, SEARCH_MODE_DEL); 1605 if (fclose(temp_fp) != 0 || rename(temp_file, perm_file) != 0) { 1606 quit(gettext("failed to update route file"), errno); 1607 /* NOTREACHED */ 1608 } 1609 (void) fclose(perm_fp); 1610 return; 1611 } 1612 1613 switch (rt->ri_cmd) { 1614 case RTM_ADD: 1615 if (search_rtfile(perm_fp, NULL, rt, SEARCH_MODE_NULL) > 0) { 1616 /* Route is already in the file */ 1617 print_rtcmd_short(stderr, rt, B_FALSE, B_TRUE); 1618 (void) fprintf(stderr, ": entry exists\n"); 1619 exit(1); 1620 } 1621 write_to_rtfile(perm_fp, argc - 1, argv + 1); 1622 print_rtcmd_short(stdout, rt, B_FALSE, B_TRUE); 1623 (void) printf("\n"); 1624 break; 1625 1626 case RTM_CHANGE: 1627 syntax_error( 1628 gettext("route: change command not supported with -p\n")); 1629 /* NOTREACHED */ 1630 1631 case RTM_DELETE: 1632 if (search_rtfile(perm_fp, temp_fp, rt, SEARCH_MODE_DEL) <= 0) { 1633 /* Route not found */ 1634 print_rtcmd_short(stderr, rt, B_FALSE, B_TRUE); 1635 (void) fprintf(stderr, gettext(": not in file\n")); 1636 exit(1); 1637 } 1638 if (fclose(temp_fp) != 0 || rename(temp_file, perm_file) != 0) { 1639 quit(gettext("failed to update route file"), errno); 1640 /* NOTREACHED */ 1641 } 1642 break; 1643 1644 case RTM_GET: 1645 if (search_rtfile(perm_fp, temp_fp, rt, SEARCH_MODE_PRINT) <= 1646 0) { 1647 print_rtcmd_short(stdout, rt, B_FALSE, B_TRUE); 1648 (void) printf(gettext(": not in file\n")); 1649 } 1650 break; 1651 1652 default: 1653 quit(gettext("Internal Error"), EINVAL); 1654 /* NOTREACHED */ 1655 } 1656 1657 /* 1658 * Closing the file unlocks it. 1659 */ 1660 (void) fclose(perm_fp); 1661 } 1662 1663 int 1664 show_saved_routes(int argc) 1665 { 1666 int perm_fd; 1667 FILE *perm_fp; 1668 struct flock lock; 1669 int count = 0; 1670 1671 if (argc != 1) { 1672 syntax_error(gettext("route: invalid arguments for show\n")); 1673 } 1674 1675 perm_fd = open(perm_file, O_RDONLY, 0); 1676 1677 if (perm_fd == -1) { 1678 if (errno == ENOENT) { 1679 (void) printf("No persistent routes are defined\n"); 1680 return (0); 1681 } else { 1682 quit(gettext("failed to open route file"), errno); 1683 } 1684 } 1685 lock.l_type = F_RDLCK; 1686 lock.l_whence = SEEK_SET; 1687 lock.l_start = 0; 1688 lock.l_len = 0; 1689 if (fcntl(perm_fd, F_SETLK, &lock) != 0) { 1690 quit(gettext("failed to lock route file"), 1691 errno); 1692 /* NOTREACHED */ 1693 } 1694 if ((perm_fp = fdopen(perm_fd, "r")) == NULL) { 1695 quit(gettext("failed to open route file"), errno); 1696 /* NOTREACHED */ 1697 } 1698 count += search_rtfile(perm_fp, NULL, NULL, SEARCH_MODE_PRINT); 1699 (void) fseek(perm_fp, 0, SEEK_SET); 1700 af = AF_INET6; 1701 count += search_rtfile(perm_fp, NULL, NULL, SEARCH_MODE_PRINT); 1702 1703 if (count == 0) 1704 (void) printf("No persistent routes are defined\n"); 1705 1706 (void) fclose(perm_fp); 1707 return (0); 1708 } 1709 1710 int 1711 newroute(char **argv) 1712 { 1713 rtcmd_irep_t *newrt; 1714 int ret, attempts, oerrno; 1715 char *err; 1716 char obuf[INET6_ADDRSTRLEN]; 1717 #define hp (newrt->ri_gate_hp) 1718 1719 newrt = new_rtcmd_irep(); 1720 (void) args_to_rtcmd(newrt, argv, NULL); 1721 1722 if (newrt->ri_cmd != RTM_GET && !tflag) { 1723 /* Don't want to read back our messages */ 1724 (void) shutdown(s, 0); 1725 } 1726 if (newrt->ri_addrs & RTA_IFP) { 1727 newrt->ri_ifp.sdl.sdl_index = if_nametoindex(newrt->ri_ifp_str); 1728 if (newrt->ri_ifp.sdl.sdl_index == 0) { 1729 if (errno != ENXIO) { 1730 quit("if_nametoindex", errno); 1731 } else { 1732 (void) fprintf(stderr, 1733 gettext("route: %s: no such interface\n"), 1734 newrt->ri_ifp_str); 1735 exit(1); 1736 } 1737 } 1738 newrt->ri_ifp.sdl.sdl_family = AF_LINK; 1739 } 1740 for (attempts = 1; ; attempts++) { 1741 errno = 0; 1742 if ((ret = rtmsg(newrt)) == 0) 1743 break; 1744 if (errno != ENETUNREACH && errno != ESRCH) 1745 break; 1746 if ((newrt->ri_addrs & RTA_GATEWAY) && hp != NULL && 1747 hp->h_addr_list[attempts] != NULL) { 1748 switch (af) { 1749 case AF_INET: 1750 (void) memmove(&newrt->ri_gate.sin.sin_addr, 1751 hp->h_addr_list[attempts], hp->h_length); 1752 continue; 1753 case AF_INET6: 1754 (void) memmove(&newrt->ri_gate.sin6.sin6_addr, 1755 hp->h_addr_list[attempts], hp->h_length); 1756 continue; 1757 } 1758 } 1759 break; 1760 } 1761 oerrno = errno; 1762 1763 if (newrt->ri_cmd != RTM_GET) { 1764 print_rtcmd_short(stdout, newrt, (ret == 0), B_FALSE); 1765 if (ret == 0) 1766 (void) printf("\n"); 1767 } else if (ret != 0) { 1768 /* 1769 * Note: there is nothing additional to print for get 1770 * if ret == 0. 1771 */ 1772 if (nflag) { 1773 switch (newrt->ri_af) { 1774 case AF_INET: 1775 (void) printf(" %s", 1776 inet_ntoa(newrt->ri_dst.sin.sin_addr)); 1777 break; 1778 case AF_INET6: 1779 if (inet_ntop(AF_INET6, 1780 (void *)&newrt->ri_dst.sin6.sin6_addr, 1781 obuf, INET6_ADDRSTRLEN) != NULL) { 1782 (void) printf(" %s", obuf); 1783 break; 1784 } 1785 /* FALLTHROUGH */ 1786 default: 1787 (void) printf("%s", newrt->ri_dest_str); 1788 break; 1789 } 1790 } else { 1791 (void) printf("%s", newrt->ri_dest_str); 1792 } 1793 } 1794 1795 if (ret != 0) { 1796 switch (oerrno) { 1797 case ESRCH: 1798 err = "not in table"; 1799 break; 1800 case EBUSY: 1801 err = "entry in use"; 1802 break; 1803 case ENOBUFS: 1804 err = "routing table overflow"; 1805 break; 1806 case EEXIST: 1807 err = "entry exists"; 1808 break; 1809 case EPERM: 1810 err = "insufficient privileges"; 1811 break; 1812 default: 1813 err = strerror(oerrno); 1814 break; 1815 } 1816 (void) printf(": %s\n", err); 1817 } 1818 1819 del_rtcmd_irep(newrt); 1820 1821 return (oerrno); 1822 #undef hp 1823 } 1824 1825 1826 /* 1827 * Convert a network number to the corresponding IP address. 1828 * If the RTA_NETMASK hasn't been specified yet set it based 1829 * on the class of address. 1830 */ 1831 static void 1832 inet_makenetandmask(rtcmd_irep_t *rcip, in_addr_t net, struct sockaddr_in *sin) 1833 { 1834 in_addr_t addr, mask; 1835 1836 if (net == 0) { 1837 mask = addr = 0; 1838 } else if (net < 128) { 1839 addr = net << IN_CLASSA_NSHIFT; 1840 mask = IN_CLASSA_NET; 1841 } else if (net < 65536) { 1842 addr = net << IN_CLASSB_NSHIFT; 1843 mask = IN_CLASSB_NET; 1844 } else if (net < 16777216L) { 1845 addr = net << IN_CLASSC_NSHIFT; 1846 mask = IN_CLASSC_NET; 1847 } else { 1848 addr = net; 1849 if ((addr & IN_CLASSA_HOST) == 0) 1850 mask = IN_CLASSA_NET; 1851 else if ((addr & IN_CLASSB_HOST) == 0) 1852 mask = IN_CLASSB_NET; 1853 else if ((addr & IN_CLASSC_HOST) == 0) 1854 mask = IN_CLASSC_NET; 1855 else { 1856 if (IN_CLASSA(addr)) 1857 mask = IN_CLASSA_NET; 1858 else if (IN_CLASSB(addr)) 1859 mask = IN_CLASSB_NET; 1860 else if (IN_CLASSC(addr)) 1861 mask = IN_CLASSC_NET; 1862 else 1863 mask = IP_HOST_MASK; 1864 mask = inet_makesubnetmask(addr, mask); 1865 } 1866 } 1867 sin->sin_addr.s_addr = htonl(addr); 1868 1869 if (!(rcip->ri_addrs & RTA_NETMASK)) { 1870 rcip->ri_addrs |= RTA_NETMASK; 1871 sin = &rcip->ri_mask.sin; 1872 sin->sin_addr.s_addr = htonl(mask); 1873 sin->sin_family = AF_INET; 1874 } 1875 } 1876 1877 static in_addr_t 1878 inet_makesubnetmask(in_addr_t addr, in_addr_t mask) 1879 { 1880 int n; 1881 struct ifconf ifc; 1882 struct ifreq ifreq; 1883 struct ifreq *ifr; 1884 struct sockaddr_in *sin; 1885 char *buf; 1886 int numifs; 1887 size_t bufsize; 1888 int iosoc; 1889 in_addr_t if_addr, if_mask; 1890 in_addr_t if_subnetmask = 0; 1891 short if_flags; 1892 1893 if (mask == 0) 1894 return (0); 1895 if ((iosoc = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 1896 quit("socket", errno); 1897 if (ioctl(iosoc, SIOCGIFNUM, (char *)&numifs) < 0) 1898 quit("ioctl", errno); 1899 bufsize = numifs * sizeof (struct ifreq); 1900 buf = malloc(bufsize); 1901 if (buf == NULL) 1902 quit("malloc", errno); 1903 (void) memset(&ifc, 0, sizeof (ifc)); 1904 ifc.ifc_len = bufsize; 1905 ifc.ifc_buf = buf; 1906 if (ioctl(iosoc, SIOCGIFCONF, (char *)&ifc) < 0) 1907 quit("ioctl (get interface configuration)", errno); 1908 /* Let's check to see if this is maybe a local subnet route. */ 1909 ifr = ifc.ifc_req; 1910 for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) { 1911 ifreq = *ifr; 1912 /* LINTED */ 1913 sin = (struct sockaddr_in *)&ifr->ifr_addr; 1914 if_addr = ntohl(sin->sin_addr.s_addr); 1915 1916 if (ioctl(iosoc, SIOCGIFFLAGS, (char *)&ifreq) < 0) 1917 quit("ioctl (get interface flags)", errno); 1918 if ((ifreq.ifr_flags & IFF_UP) == 0) 1919 continue; 1920 if_flags = ifreq.ifr_flags; 1921 1922 if (ioctl(iosoc, SIOCGIFNETMASK, (char *)&ifreq) < 0) 1923 quit("ioctl (get netmask)", errno); 1924 /* LINTED */ 1925 sin = (struct sockaddr_in *)&ifreq.ifr_addr; 1926 if_mask = ntohl(sin->sin_addr.s_addr); 1927 if ((if_addr & mask) == (addr & mask)) { 1928 /* 1929 * Don't trust pt-pt interfaces if there are 1930 * other interfaces. 1931 */ 1932 if (if_flags & IFF_POINTOPOINT) { 1933 if_subnetmask = if_mask; 1934 continue; 1935 } 1936 /* 1937 * Fine. Just assume the same net mask as the 1938 * directly attached subnet interface is using. 1939 */ 1940 return (if_mask); 1941 } 1942 } 1943 if (if_subnetmask != 0) 1944 return (if_subnetmask); 1945 return (mask); 1946 } 1947 1948 /* 1949 * Interpret an argument as a network address of some kind. 1950 * 1951 * If the address family is one looked up in getaddr() using one of the 1952 * getipnodebyX() functions (currently only AF_INET6), then callers should 1953 * freehostent() the returned "struct hostent" pointer if one was passed in. 1954 * 1955 * If exit_on_error is true, this function will cause route to exit on error by 1956 * calling syntax_error(). Otherwise, it returns B_TRUE on success or B_FALSE 1957 * on failure. 1958 */ 1959 static boolean_t 1960 getaddr(rtcmd_irep_t *rcip, int which, char *s, addr_type_t atype) 1961 { 1962 su_t *su; 1963 struct hostent **hpp; 1964 struct hostent *hp; 1965 boolean_t ret; 1966 1967 if (which == RTA_GATEWAY) { 1968 hpp = &(rcip->ri_gate_hp); 1969 } else { 1970 hpp = &hp; 1971 } 1972 *hpp = NULL; 1973 1974 rcip->ri_addrs |= which; 1975 switch (which) { 1976 case RTA_DST: 1977 save_string(&rcip->ri_dest_str, s); 1978 su = &rcip->ri_dst; 1979 su->sa.sa_family = rcip->ri_af; 1980 break; 1981 case RTA_GATEWAY: 1982 save_string(&rcip->ri_gate_str, s); 1983 su = &rcip->ri_gate; 1984 su->sa.sa_family = rcip->ri_af; 1985 break; 1986 case RTA_NETMASK: 1987 su = &rcip->ri_mask; 1988 su->sa.sa_family = rcip->ri_af; 1989 break; 1990 case RTA_IFP: 1991 save_string(&rcip->ri_ifp_str, s); 1992 return (B_TRUE); 1993 /* 1994 * RTA_SRC has overloaded meaning. It can represent the 1995 * src address of incoming or outgoing packets. 1996 */ 1997 case RTA_IFA: 1998 su = &rcip->ri_ifa; 1999 su->sa.sa_family = rcip->ri_af; 2000 break; 2001 case RTA_SRC: 2002 su = &rcip->ri_src; 2003 su->sa.sa_family = rcip->ri_af; 2004 break; 2005 default: 2006 /* NOTREACHED */ 2007 quit(gettext("Internal Error"), EINVAL); 2008 /* NOTREACHED */ 2009 } 2010 if (strcmp(s, "default") == 0) { 2011 if (which == RTA_DST) { 2012 return (getaddr(rcip, RTA_NETMASK, s, ADDR_TYPE_NET)); 2013 } 2014 if (which == RTA_SRC) { 2015 return (B_TRUE); 2016 } 2017 return (B_TRUE); 2018 } 2019 switch (rcip->ri_af) { 2020 case AF_LINK: 2021 link_addr(s, &su->sdl); 2022 return (B_TRUE); 2023 case PF_ROUTE: 2024 sockaddr(s, &su->sa); 2025 return (B_TRUE); 2026 case AF_INET6: 2027 switch (which) { 2028 case RTA_DST: 2029 if (s[0] == '/') { 2030 syntax_error(gettext( 2031 "route: %s: unexpected '/'\n"), s); 2032 return (B_FALSE); 2033 } 2034 ret = in6_getaddr(s, &su->sin6, &rcip->ri_masklen, hpp); 2035 if (ret == B_FALSE) { 2036 return (B_FALSE); 2037 } 2038 switch (rcip->ri_masklen) { 2039 case NO_PREFIX: 2040 /* Nothing there - ok */ 2041 return (B_TRUE); 2042 case BAD_ADDR: 2043 syntax_error(gettext( 2044 "route: bad prefix length in %s\n"), s); 2045 return (B_FALSE); 2046 default: 2047 (void) memset(&rcip->ri_mask.sin6.sin6_addr, 0, 2048 sizeof (rcip->ri_mask.sin6.sin6_addr)); 2049 if (!in_prefixlentomask(rcip->ri_masklen, 2050 IPV6_ABITS, 2051 (uchar_t *)&rcip->ri_mask.sin6.sin6_addr)) { 2052 syntax_error(gettext( 2053 "route: bad prefix length: %d\n"), 2054 rcip->ri_masklen); 2055 return (B_FALSE); 2056 } 2057 break; 2058 } 2059 rcip->ri_mask.sin6.sin6_family = rcip->ri_af; 2060 rcip->ri_addrs |= RTA_NETMASK; 2061 return (B_TRUE); 2062 case RTA_GATEWAY: 2063 case RTA_IFA: 2064 case RTA_SRC: 2065 return (in6_getaddr(s, &su->sin6, NULL, hpp)); 2066 case RTA_NETMASK: 2067 syntax_error( 2068 gettext("route: -netmask not supported for IPv6: " 2069 "use <prefix>/<prefix-length> instead\n")); 2070 return (B_FALSE); 2071 default: 2072 quit(gettext("Internal Error"), EINVAL); 2073 /* NOTREACHED */ 2074 } 2075 case AF_INET: 2076 switch (which) { 2077 case RTA_DST: 2078 if (s[0] == '/') { 2079 syntax_error(gettext( 2080 "route: %s: unexpected '/'\n"), s); 2081 return (B_FALSE); 2082 } 2083 ret = in_getaddr(s, &su->sin, &rcip->ri_masklen, which, 2084 hpp, atype, rcip); 2085 if (ret == B_FALSE) { 2086 return (B_FALSE); 2087 } 2088 switch (rcip->ri_masklen) { 2089 case NO_PREFIX: 2090 /* Nothing there - ok */ 2091 return (B_TRUE); 2092 case BAD_ADDR: 2093 syntax_error(gettext( 2094 "route: bad prefix length in %s\n"), s); 2095 return (B_FALSE); 2096 default: 2097 (void) memset(&rcip->ri_mask.sin.sin_addr, 0, 2098 sizeof (rcip->ri_mask.sin.sin_addr)); 2099 if (!in_prefixlentomask(rcip->ri_masklen, 2100 IP_ABITS, 2101 (uchar_t *)&rcip->ri_mask.sin.sin_addr)) { 2102 syntax_error(gettext( 2103 "route: bad prefix length: %d\n"), 2104 rcip->ri_masklen); 2105 return (B_FALSE); 2106 } 2107 break; 2108 } 2109 rcip->ri_mask.sin.sin_family = rcip->ri_af; 2110 rcip->ri_addrs |= RTA_NETMASK; 2111 return (B_TRUE); 2112 case RTA_GATEWAY: 2113 case RTA_IFA: 2114 case RTA_NETMASK: 2115 case RTA_SRC: 2116 return (in_getaddr(s, &su->sin, NULL, which, hpp, atype, 2117 rcip)); 2118 default: 2119 quit(gettext("Internal Error"), EINVAL); 2120 /* NOTREACHED */ 2121 } 2122 default: 2123 quit(gettext("Internal Error"), EINVAL); 2124 /* NOTREACHED */ 2125 } 2126 return (B_TRUE); 2127 } 2128 2129 /* 2130 * Interpret an argument as an IPv4 network address of some kind, 2131 * returning B_TRUE on success or B_FALSE on failure. 2132 * This function will cause an exit() on failure if exit_on_failure is set. 2133 * 2134 * Note that this *always* tries host interpretation before network 2135 * interpretation. 2136 * 2137 * If the plenp argument is non-NULL, allow <addr>/<n> syntax and 2138 * pass out <n> in *plenp. 2139 * If <n> doesn't parse return BAD_ADDR as *plenp. 2140 * If no /<n> is present return NO_PREFIX as *plenp. 2141 */ 2142 static boolean_t 2143 in_getaddr(char *s, struct sockaddr_in *sin, int *plenp, int which, 2144 struct hostent **hpp, addr_type_t atype, rtcmd_irep_t *rcip) 2145 { 2146 struct hostent *hp; 2147 struct netent *np; 2148 in_addr_t val; 2149 char str[BUFSIZ]; 2150 2151 (void) strncpy(str, s, sizeof (str)); 2152 2153 /* 2154 * Look for '/'<n> is plenp 2155 */ 2156 if (plenp != NULL) { 2157 char *cp; 2158 2159 *plenp = in_getprefixlen(str, IP_ABITS); 2160 if (*plenp == BAD_ADDR) 2161 return (B_FALSE); 2162 cp = strchr(str, '/'); 2163 if (cp != NULL) 2164 *cp = '\0'; 2165 } else if (strchr(str, '/') != NULL) { 2166 syntax_error(gettext("route: %s: unexpected '/'\n"), str); 2167 return (B_FALSE); 2168 } 2169 2170 (void) memset(sin, 0, sizeof (*sin)); 2171 sin->sin_family = AF_INET; 2172 2173 /* 2174 * Note: only the route destination can be a network, so we treat 2175 * all other addresses as though "-net" was not specified. 2176 */ 2177 if ((((val = inet_addr(str)) != (in_addr_t)-1) || 2178 strcmp(str, "255.255.255.255") == 0) && 2179 (which != RTA_DST || atype != ADDR_TYPE_NET)) { 2180 sin->sin_addr.s_addr = val; 2181 if (inet_lnaof(sin->sin_addr) != INADDR_ANY || 2182 atype == ADDR_TYPE_HOST) { 2183 if (rcip->ri_masklen == NO_PREFIX) { 2184 rcip->ri_masklen = 32; 2185 } 2186 return (B_TRUE); 2187 } 2188 val = ntohl(val); 2189 if (which == RTA_DST) 2190 inet_makenetandmask(rcip, val, sin); 2191 return (B_TRUE); 2192 } 2193 if (atype != ADDR_TYPE_HOST && (val = inet_network(str)) != 2194 (in_addr_t)-1) { 2195 if (which == RTA_DST) 2196 inet_makenetandmask(rcip, val, sin); 2197 return (B_TRUE); 2198 } 2199 if ((which != RTA_DST || atype != ADDR_TYPE_NET) && 2200 (hp = gethostbyname(str)) != NULL) { 2201 *hpp = hp; 2202 (void) memmove(&sin->sin_addr, hp->h_addr, 2203 hp->h_length); 2204 if (rcip->ri_masklen == NO_PREFIX) { 2205 rcip->ri_masklen = 32; 2206 } 2207 return (B_TRUE); 2208 } 2209 if (atype != ADDR_TYPE_HOST && (np = getnetbyname(str)) != NULL && 2210 (val = np->n_net) != 0) { 2211 if (which == RTA_DST) 2212 inet_makenetandmask(rcip, val, sin); 2213 return (B_TRUE); 2214 } 2215 syntax_error(gettext("%s: bad value\n"), s); 2216 return (B_FALSE); 2217 } 2218 2219 /* 2220 * Interpret an argument as an IPv6 network address of some kind, 2221 * returning B_TRUE on success or B_FALSE on failure. 2222 * This function will cause an exit() on failure if exit_on_failure is set. 2223 * 2224 * If the last argument is non-NULL allow a <addr>/<n> syntax and 2225 * pass out <n> in *plenp. 2226 * If <n> doesn't parse return BAD_ADDR as *plenp. 2227 * If no /<n> is present return NO_PREFIX as *plenp. 2228 */ 2229 static boolean_t 2230 in6_getaddr(char *s, struct sockaddr_in6 *sin6, int *plenp, 2231 struct hostent **hpp) 2232 { 2233 struct hostent *hp; 2234 char str[BUFSIZ]; 2235 int error_num; 2236 2237 (void) strncpy(str, s, sizeof (str)); 2238 2239 /* 2240 * Look for '/'<n> is plenp 2241 */ 2242 if (plenp != NULL) { 2243 char *cp; 2244 2245 *plenp = in_getprefixlen(str, IPV6_ABITS); 2246 if (*plenp == BAD_ADDR) 2247 return (B_FALSE); 2248 cp = strchr(str, '/'); 2249 if (cp != NULL) 2250 *cp = '\0'; 2251 } else if (strchr(str, '/') != NULL) { 2252 syntax_error(gettext("route: %s: unexpected '/'\n"), str); 2253 return (B_FALSE); 2254 } 2255 2256 (void) memset(sin6, 0, sizeof (struct sockaddr_in6)); 2257 sin6->sin6_family = AF_INET6; 2258 2259 hp = getipnodebyname(str, AF_INET6, 0, &error_num); 2260 if (hp != NULL) { 2261 *hpp = hp; 2262 (void) memmove(&sin6->sin6_addr, hp->h_addr, hp->h_length); 2263 return (B_TRUE); 2264 } 2265 if (error_num == TRY_AGAIN) { 2266 /* 2267 * This isn't a problem if we aren't going to use the address 2268 * right away. 2269 */ 2270 if (!exit_on_error) { 2271 return (B_TRUE); 2272 } 2273 syntax_error(gettext("route: %s: bad address (try " 2274 "again later)\n"), s); 2275 return (B_FALSE); 2276 } 2277 syntax_error(gettext("route: %s: bad address\n"), s); 2278 return (B_FALSE); 2279 } 2280 2281 /* 2282 * If "slash" is zero this parses the whole string as 2283 * an integer. With "slash" non zero it parses the tail part as an integer. 2284 * 2285 * If it is not a valid integer this returns BAD_ADDR. 2286 * If there is /<n> present this returns NO_PREFIX. 2287 */ 2288 int 2289 in_getprefixlen(char *addr, int max_plen) 2290 { 2291 int prefixlen; 2292 char *str, *end; 2293 2294 str = strchr(addr, '/'); 2295 if (str == NULL) 2296 return (NO_PREFIX); 2297 str++; 2298 2299 prefixlen = strtol(str, &end, 10); 2300 if (prefixlen < 0) 2301 return (BAD_ADDR); 2302 if (str == end) 2303 return (BAD_ADDR); 2304 if (max_plen != 0 && max_plen < prefixlen) 2305 return (BAD_ADDR); 2306 else 2307 return (prefixlen); 2308 } 2309 2310 /* 2311 * Convert a prefix length to a mask. 2312 * Returns B_TRUE if ok. B_FALSE otherwise. 2313 * Assumes the mask array is zeroed by the caller. 2314 */ 2315 boolean_t 2316 in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask) 2317 { 2318 if (prefixlen < 0 || prefixlen > maxlen) 2319 return (B_FALSE); 2320 2321 while (prefixlen > 0) { 2322 if (prefixlen >= 8) { 2323 *mask++ = 0xFF; 2324 prefixlen -= 8; 2325 continue; 2326 } 2327 *mask |= 1 << (8 - prefixlen); 2328 prefixlen--; 2329 } 2330 return (B_TRUE); 2331 } 2332 2333 void 2334 rtmonitor(int argc, char *argv[]) 2335 { 2336 int n; 2337 intmax_t msg[2048 / sizeof (intmax_t)]; 2338 2339 if (tflag) 2340 exit(0); 2341 verbose = B_TRUE; 2342 if (argc > 1) { 2343 argv++; 2344 if (argc == 2 && **argv == '-') { 2345 switch (keyword(*argv + 1)) { 2346 case K_INET: 2347 af = AF_INET; 2348 break; 2349 case K_LINK: 2350 af = AF_LINK; 2351 break; 2352 case K_INET6: 2353 af = AF_INET6; 2354 break; 2355 default: 2356 usage(*argv); 2357 /* NOTREACHED */ 2358 } 2359 } else { 2360 usage(*argv); 2361 } 2362 (void) close(s); 2363 s = socket(PF_ROUTE, SOCK_RAW, af); 2364 if (s < 0) 2365 quit("socket", errno); 2366 } 2367 for (;;) { 2368 n = read(s, msg, sizeof (msg)); 2369 if (n <= 0) 2370 quit("read", errno); 2371 (void) printf("got message of size %d\n", n); 2372 print_rtmsg((struct rt_msghdr *)msg, n); 2373 } 2374 } 2375 2376 int 2377 rtmsg(rtcmd_irep_t *newrt) 2378 { 2379 static int seq; 2380 int rlen; 2381 char *cp = m_rtmsg.m_space; 2382 int l; 2383 2384 errno = 0; 2385 (void) memset(&m_rtmsg, 0, sizeof (m_rtmsg)); 2386 2387 if (newrt->ri_cmd == RTM_GET) { 2388 newrt->ri_ifp.sa.sa_family = AF_LINK; 2389 newrt->ri_addrs |= RTA_IFP; 2390 } 2391 2392 #define rtm m_rtmsg.m_rtm 2393 rtm.rtm_type = newrt->ri_cmd; 2394 rtm.rtm_flags = newrt->ri_flags; 2395 rtm.rtm_version = RTM_VERSION; 2396 rtm.rtm_seq = ++seq; 2397 rtm.rtm_addrs = newrt->ri_addrs; 2398 rtm.rtm_rmx = newrt->ri_metrics; 2399 rtm.rtm_inits = newrt->ri_inits; 2400 2401 #define NEXTADDR(w, u) \ 2402 if (newrt->ri_addrs & (w)) { \ 2403 l = ROUNDUP_LONG(salen(&u.sa)); \ 2404 (void) memmove(cp, &(u), l); \ 2405 cp += l; \ 2406 if (verbose) \ 2407 sodump(&(u), #u); \ 2408 } 2409 NEXTADDR(RTA_DST, newrt->ri_dst); 2410 NEXTADDR(RTA_GATEWAY, newrt->ri_gate); 2411 NEXTADDR(RTA_NETMASK, newrt->ri_mask); 2412 NEXTADDR(RTA_IFP, newrt->ri_ifp); 2413 NEXTADDR(RTA_IFA, newrt->ri_ifa); 2414 /* 2415 * RTA_SRC has overloaded meaning. It can represent the 2416 * src address of incoming or outgoing packets. 2417 */ 2418 NEXTADDR(RTA_SRC, newrt->ri_src); 2419 #undef NEXTADDR 2420 rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 2421 if (verbose) 2422 print_rtmsg(&rtm, l); 2423 if (debugonly) 2424 return (0); 2425 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 2426 switch (errno) { 2427 case ESRCH: 2428 case EBUSY: 2429 case ENOBUFS: 2430 case EEXIST: 2431 case ENETUNREACH: 2432 case EHOSTUNREACH: 2433 case EPERM: 2434 break; 2435 default: 2436 perror(gettext("writing to routing socket")); 2437 break; 2438 } 2439 return (-1); 2440 } else if (rlen < (int)rtm.rtm_msglen) { 2441 (void) fprintf(stderr, 2442 gettext("route: write to routing socket got only %d for " 2443 "len\n"), rlen); 2444 return (-1); 2445 } 2446 if (newrt->ri_cmd == RTM_GET) { 2447 do { 2448 l = read(s, (char *)&m_rtmsg, sizeof (m_rtmsg)); 2449 } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); 2450 if (l < 0) { 2451 (void) fprintf(stderr, 2452 gettext("route: read from routing socket: %s\n"), 2453 strerror(errno)); 2454 } else { 2455 print_getmsg(newrt, &rtm, l); 2456 } 2457 } 2458 #undef rtm 2459 return (0); 2460 } 2461 2462 static char *msgtypes[] = { 2463 "", 2464 "RTM_ADD: Add Route", 2465 "RTM_DELETE: Delete Route", 2466 "RTM_CHANGE: Change Metrics or flags", 2467 "RTM_GET: Report Metrics", 2468 "RTM_LOSING: Kernel Suspects Partitioning", 2469 "RTM_REDIRECT: Told to use different route", 2470 "RTM_MISS: Lookup failed on this address", 2471 "RTM_LOCK: fix specified metrics", 2472 "RTM_OLDADD: caused by SIOCADDRT", 2473 "RTM_OLDDEL: caused by SIOCDELRT", 2474 "RTM_RESOLVE: Route created by cloning", 2475 "RTM_NEWADDR: address being added to iface", 2476 "RTM_DELADDR: address being removed from iface", 2477 "RTM_IFINFO: iface status change", 2478 0, 2479 }; 2480 2481 #define NMSGTYPES (sizeof (msgtypes) / sizeof (msgtypes[0])) 2482 2483 static char metricnames[] = 2484 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount" 2485 "\1mtu"; 2486 static char routeflags[] = 2487 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT" 2488 "\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE" 2489 "\016PRIVATE\017PROTO2\020PROTO1\021MULTIRT\022SETSRC"; 2490 static char ifnetflags[] = 2491 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP" 2492 "\011PPROMISC\012ALLMULTI\013INTELLIGENT\014MULTICAST" 2493 "\015MULTI_BCAST\016UNNUMBERED\017DHCP\020PRIVATE" 2494 "\021NOXMIT\022NOLOCAL\023DEPRECATED\024ADDRCONF" 2495 "\025ROUTER\026NONUD\027ANYCAST\030NORTEXCH\031IPv4\032IPv6" 2496 "\033MIP\034NOFAILOVER\035FAILED\036STANDBY\037INACTIVE\040OFFLINE" 2497 "\041XRESOLV\042COS\043PREFERRED\044TEMPORARY"; 2498 static char addrnames[] = 2499 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC"; 2500 2501 void 2502 print_rtmsg(struct rt_msghdr *rtm, int msglen) 2503 { 2504 struct if_msghdr *ifm; 2505 struct ifa_msghdr *ifam; 2506 2507 if (!verbose) 2508 return; 2509 if (rtm->rtm_version != RTM_VERSION) { 2510 (void) printf("routing message version %d not understood\n", 2511 rtm->rtm_version); 2512 return; 2513 } 2514 if (rtm->rtm_msglen > (ushort_t)msglen) { 2515 (void) printf("message length mismatch, in packet %d, " 2516 "returned %d\n", 2517 rtm->rtm_msglen, msglen); 2518 } 2519 /* 2520 * Since rtm->rtm_type is unsigned, we'll just check the case of zero 2521 * and the upper-bound of (NMSGTYPES - 1). 2522 */ 2523 if (rtm->rtm_type == 0 || rtm->rtm_type >= (NMSGTYPES - 1)) { 2524 (void) printf("routing message type %d not understood\n", 2525 rtm->rtm_type); 2526 return; 2527 } 2528 (void) printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen); 2529 switch (rtm->rtm_type) { 2530 case RTM_IFINFO: 2531 ifm = (struct if_msghdr *)rtm; 2532 (void) printf("if# %d, flags:", ifm->ifm_index); 2533 bprintf(stdout, ifm->ifm_flags, ifnetflags); 2534 pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs); 2535 break; 2536 case RTM_NEWADDR: 2537 case RTM_DELADDR: 2538 ifam = (struct ifa_msghdr *)rtm; 2539 (void) printf("metric %d, flags:", ifam->ifam_metric); 2540 bprintf(stdout, ifam->ifam_flags, routeflags); 2541 pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs); 2542 break; 2543 default: 2544 (void) printf("pid: %ld, seq %d, errno %d, flags:", 2545 rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 2546 bprintf(stdout, rtm->rtm_flags, routeflags); 2547 pmsg_common(rtm); 2548 } 2549 } 2550 2551 void 2552 print_getmsg(rtcmd_irep_t *req_rt, struct rt_msghdr *rtm, int msglen) 2553 { 2554 struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *src = NULL; 2555 struct sockaddr_dl *ifp = NULL; 2556 struct sockaddr *sa; 2557 char *cp; 2558 int i; 2559 2560 (void) printf(" route to: %s\n", routename(&req_rt->ri_dst.sa)); 2561 if (rtm->rtm_version != RTM_VERSION) { 2562 (void) fprintf(stderr, 2563 gettext("routing message version %d not understood\n"), 2564 rtm->rtm_version); 2565 return; 2566 } 2567 if (rtm->rtm_msglen > (ushort_t)msglen) { 2568 (void) fprintf(stderr, 2569 gettext("message length mismatch, in packet %d, " 2570 "returned %d\n"), rtm->rtm_msglen, msglen); 2571 } 2572 if (rtm->rtm_errno) { 2573 (void) fprintf(stderr, "RTM_GET: %s (errno %d)\n", 2574 strerror(rtm->rtm_errno), rtm->rtm_errno); 2575 return; 2576 } 2577 cp = ((char *)(rtm + 1)); 2578 if (rtm->rtm_addrs != 0) { 2579 for (i = 1; i != 0; i <<= 1) { 2580 if (i & rtm->rtm_addrs) { 2581 /* LINTED */ 2582 sa = (struct sockaddr *)cp; 2583 switch (i) { 2584 case RTA_DST: 2585 dst = sa; 2586 break; 2587 case RTA_GATEWAY: 2588 gate = sa; 2589 break; 2590 case RTA_NETMASK: 2591 mask = sa; 2592 break; 2593 case RTA_IFP: 2594 if (sa->sa_family == AF_LINK && 2595 ((struct sockaddr_dl *)sa)-> 2596 sdl_nlen != 0) 2597 ifp = (struct sockaddr_dl *)sa; 2598 break; 2599 case RTA_SRC: 2600 src = sa; 2601 break; 2602 } 2603 ADVANCE(cp, sa); 2604 } 2605 } 2606 } 2607 if (dst != NULL && mask != NULL) 2608 mask->sa_family = dst->sa_family; /* XXX */ 2609 if (dst != NULL) 2610 (void) printf("destination: %s\n", routename(dst)); 2611 if (mask != NULL) { 2612 boolean_t savenflag = nflag; 2613 2614 nflag = B_TRUE; 2615 (void) printf(" mask: %s\n", routename(mask)); 2616 nflag = savenflag; 2617 } 2618 if (gate != NULL && rtm->rtm_flags & RTF_GATEWAY) 2619 (void) printf(" gateway: %s\n", routename(gate)); 2620 if (src != NULL && rtm->rtm_flags & RTF_SETSRC) 2621 (void) printf(" setsrc: %s\n", routename(src)); 2622 if (ifp != NULL) { 2623 if (verbose) { 2624 int i; 2625 2626 (void) printf(" interface: %.*s index %d address ", 2627 ifp->sdl_nlen, ifp->sdl_data, ifp->sdl_index); 2628 for (i = ifp->sdl_nlen; 2629 i < ifp->sdl_nlen + ifp->sdl_alen; 2630 i++) { 2631 (void) printf("%02x ", 2632 ifp->sdl_data[i] & 0xFF); 2633 } 2634 (void) printf("\n"); 2635 } else { 2636 (void) printf(" interface: %.*s\n", 2637 ifp->sdl_nlen, ifp->sdl_data); 2638 } 2639 } 2640 (void) printf(" flags: "); 2641 bprintf(stdout, rtm->rtm_flags, routeflags); 2642 2643 #define lock(f) ((rtm->rtm_rmx.rmx_locks & RTV_ ## f) ? 'L' : ' ') 2644 #define msec(u) (((u) + 500) / 1000) /* usec to msec */ 2645 2646 (void) printf("\n%s\n", " recvpipe sendpipe ssthresh rtt,ms " 2647 "rttvar,ms hopcount mtu expire"); 2648 (void) printf("%8d%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); 2649 (void) printf("%8d%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); 2650 (void) printf("%8d%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); 2651 (void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); 2652 (void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR)); 2653 (void) printf("%8d%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT)); 2654 (void) printf("%8d%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); 2655 if (rtm->rtm_rmx.rmx_expire) 2656 rtm->rtm_rmx.rmx_expire -= time(0); 2657 (void) printf("%8d%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); 2658 #undef lock 2659 #undef msec 2660 #define RTA_IGN \ 2661 (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD|RTA_SRC) 2662 if (verbose) { 2663 pmsg_common(rtm); 2664 } else if (rtm->rtm_addrs &~ RTA_IGN) { 2665 (void) printf("sockaddrs: "); 2666 bprintf(stdout, rtm->rtm_addrs, addrnames); 2667 (void) putchar('\n'); 2668 } 2669 #undef RTA_IGN 2670 } 2671 2672 void 2673 pmsg_common(struct rt_msghdr *rtm) 2674 { 2675 (void) printf("\nlocks: "); 2676 bprintf(stdout, (int)rtm->rtm_rmx.rmx_locks, metricnames); 2677 (void) printf(" inits: "); 2678 bprintf(stdout, (int)rtm->rtm_inits, metricnames); 2679 pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs); 2680 } 2681 2682 void 2683 pmsg_addrs(char *cp, int addrs) 2684 { 2685 struct sockaddr *sa; 2686 int i; 2687 2688 if (addrs == 0) 2689 return; 2690 (void) printf("\nsockaddrs: "); 2691 bprintf(stdout, addrs, addrnames); 2692 (void) putchar('\n'); 2693 for (i = 1; i != 0; i <<= 1) { 2694 if (i & addrs) { 2695 /* LINTED */ 2696 sa = (struct sockaddr *)cp; 2697 (void) printf(" %s", routename(sa)); 2698 ADVANCE(cp, sa); 2699 } 2700 } 2701 (void) putchar('\n'); 2702 (void) fflush(stdout); 2703 } 2704 2705 void 2706 bprintf(FILE *fp, int b, char *s) 2707 { 2708 int i; 2709 boolean_t gotsome = B_FALSE; 2710 2711 if (b == 0) 2712 return; 2713 while ((i = *s++) != 0) { 2714 if (b & (1 << (i - 1))) { 2715 if (!gotsome) 2716 i = '<'; 2717 else 2718 i = ','; 2719 (void) putc(i, fp); 2720 gotsome = B_TRUE; 2721 for (; (i = *s) > ' '; s++) 2722 (void) putc(i, fp); 2723 } else { 2724 while (*s > ' ') 2725 s++; 2726 } 2727 } 2728 if (gotsome) 2729 (void) putc('>', fp); 2730 } 2731 2732 int 2733 keyword(char *cp) 2734 { 2735 struct keytab *kt = keywords; 2736 2737 while (kt->kt_cp && strcmp(kt->kt_cp, cp)) 2738 kt++; 2739 return (kt->kt_i); 2740 } 2741 2742 void 2743 sodump(su_t *su, char *which) 2744 { 2745 static char obuf[INET6_ADDRSTRLEN]; 2746 2747 switch (su->sa.sa_family) { 2748 case AF_LINK: 2749 (void) printf("%s: link %s; ", 2750 which, link_ntoa(&su->sdl)); 2751 break; 2752 case AF_INET: 2753 (void) printf("%s: inet %s; ", 2754 which, inet_ntoa(su->sin.sin_addr)); 2755 break; 2756 case AF_INET6: 2757 if (inet_ntop(AF_INET6, (void *)&su->sin6.sin6_addr, obuf, 2758 INET6_ADDRSTRLEN) != NULL) { 2759 (void) printf("%s: inet6 %s; ", which, obuf); 2760 break; 2761 } 2762 /* FALLTHROUGH */ 2763 default: 2764 quit(gettext("Internal Error"), EINVAL); 2765 /* NOTREACHED */ 2766 } 2767 (void) fflush(stdout); 2768 } 2769 2770 /* States */ 2771 #define VIRGIN 0 2772 #define GOTONE 1 2773 #define GOTTWO 2 2774 #define RESET 3 2775 /* Inputs */ 2776 #define DIGIT (4*0) 2777 #define END (4*1) 2778 #define DELIM (4*2) 2779 #define LETTER (4*3) 2780 2781 void 2782 sockaddr(char *addr, struct sockaddr *sa) 2783 { 2784 char *cp = (char *)sa; 2785 int size = salen(sa); 2786 char *cplim = cp + size; 2787 int byte = 0, state = VIRGIN, new; 2788 2789 (void) memset(cp, 0, size); 2790 cp++; 2791 do { 2792 if ((*addr >= '0') && (*addr <= '9')) { 2793 new = *addr - '0'; 2794 } else if ((*addr >= 'a') && (*addr <= 'f')) { 2795 new = *addr - 'a' + 10; 2796 } else if ((*addr >= 'A') && (*addr <= 'F')) { 2797 new = *addr - 'A' + 10; 2798 } else if (*addr == 0) { 2799 state |= END; 2800 } else { 2801 state |= DELIM; 2802 } 2803 addr++; 2804 switch (state /* | INPUT */) { 2805 case GOTTWO | DIGIT: 2806 *cp++ = byte; 2807 /* FALLTHROUGH */ 2808 case VIRGIN | DIGIT: 2809 state = GOTONE; byte = new; continue; 2810 case GOTONE | DIGIT: 2811 state = GOTTWO; byte = new + (byte << 4); continue; 2812 default: /* | DELIM */ 2813 state = VIRGIN; *cp++ = byte; byte = 0; continue; 2814 case GOTONE | END: 2815 case GOTTWO | END: 2816 *cp++ = byte; 2817 /* FALLTHROUGH */ 2818 case VIRGIN | END: 2819 break; 2820 } 2821 break; 2822 } while (cp < cplim); 2823 } 2824 2825 int 2826 salen(struct sockaddr *sa) 2827 { 2828 switch (sa->sa_family) { 2829 case AF_INET: 2830 return (sizeof (struct sockaddr_in)); 2831 case AF_LINK: 2832 return (sizeof (struct sockaddr_dl)); 2833 case AF_INET6: 2834 return (sizeof (struct sockaddr_in6)); 2835 default: 2836 return (sizeof (struct sockaddr)); 2837 } 2838 } 2839 2840 void 2841 link_addr(const char *addr, struct sockaddr_dl *sdl) 2842 { 2843 char *cp = sdl->sdl_data; 2844 char *cplim = sizeof (struct sockaddr_dl) + (char *)sdl; 2845 int byte = 0, state = VIRGIN, new; 2846 2847 (void) memset(sdl, 0, sizeof (struct sockaddr_dl)); 2848 sdl->sdl_family = AF_LINK; 2849 do { 2850 state &= ~LETTER; 2851 if ((*addr >= '0') && (*addr <= '9')) { 2852 new = *addr - '0'; 2853 } else if ((*addr >= 'a') && (*addr <= 'f')) { 2854 new = *addr - 'a' + 10; 2855 } else if ((*addr >= 'A') && (*addr <= 'F')) { 2856 new = *addr - 'A' + 10; 2857 } else if (*addr == 0) { 2858 state |= END; 2859 } else if (state == VIRGIN && 2860 (((*addr >= 'A') && (*addr <= 'Z')) || 2861 ((*addr >= 'a') && (*addr <= 'z')))) { 2862 state |= LETTER; 2863 } else { 2864 state |= DELIM; 2865 } 2866 addr++; 2867 switch (state /* | INPUT */) { 2868 case VIRGIN | DIGIT: 2869 case VIRGIN | LETTER: 2870 *cp++ = addr[-1]; 2871 continue; 2872 case VIRGIN | DELIM: 2873 state = RESET; 2874 sdl->sdl_nlen = cp - sdl->sdl_data; 2875 continue; 2876 case GOTTWO | DIGIT: 2877 *cp++ = byte; 2878 /* FALLTHROUGH */ 2879 case RESET | DIGIT: 2880 state = GOTONE; 2881 byte = new; 2882 continue; 2883 case GOTONE | DIGIT: 2884 state = GOTTWO; 2885 byte = new + (byte << 4); 2886 continue; 2887 default: /* | DELIM */ 2888 state = RESET; 2889 *cp++ = byte; 2890 byte = 0; 2891 continue; 2892 case GOTONE | END: 2893 case GOTTWO | END: 2894 *cp++ = byte; 2895 /* FALLTHROUGH */ 2896 case RESET | END: 2897 break; 2898 } 2899 break; 2900 } while (cp < cplim); 2901 sdl->sdl_alen = cp - LLADDR(sdl); 2902 } 2903 2904 static char hexlist[] = "0123456789abcdef"; 2905 2906 char * 2907 link_ntoa(const struct sockaddr_dl *sdl) 2908 { 2909 static char obuf[64]; 2910 char *out = obuf; 2911 int i; 2912 uchar_t *in = (uchar_t *)LLADDR(sdl); 2913 uchar_t *inlim = in + sdl->sdl_alen; 2914 boolean_t firsttime = B_TRUE; 2915 2916 if (sdl->sdl_nlen) { 2917 (void) memcpy(obuf, sdl->sdl_data, sdl->sdl_nlen); 2918 out += sdl->sdl_nlen; 2919 if (sdl->sdl_alen) 2920 *out++ = ':'; 2921 } 2922 while (in < inlim) { 2923 if (firsttime) 2924 firsttime = B_FALSE; 2925 else 2926 *out++ = '.'; 2927 i = *in++; 2928 if (i > 0xf) { 2929 out[1] = hexlist[i & 0xf]; 2930 i >>= 4; 2931 out[0] = hexlist[i]; 2932 out += 2; 2933 } else { 2934 *out++ = hexlist[i]; 2935 } 2936 } 2937 *out = 0; 2938 return (obuf); 2939 } 2940 2941 static mib_item_t * 2942 mibget(int sd) 2943 { 2944 intmax_t buf[512 / sizeof (intmax_t)]; 2945 int flags; 2946 int i, j, getcode; 2947 struct strbuf ctlbuf, databuf; 2948 struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf; 2949 struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf; 2950 struct T_error_ack *tea = (struct T_error_ack *)buf; 2951 struct opthdr *req; 2952 mib_item_t *first_item = NULL; 2953 mib_item_t *last_item = NULL; 2954 mib_item_t *temp; 2955 2956 tor->PRIM_type = T_SVR4_OPTMGMT_REQ; 2957 tor->OPT_offset = sizeof (struct T_optmgmt_req); 2958 tor->OPT_length = sizeof (struct opthdr); 2959 tor->MGMT_flags = T_CURRENT; 2960 req = (struct opthdr *)&tor[1]; 2961 req->level = MIB2_IP; /* any MIB2_xxx value ok here */ 2962 req->name = 0; 2963 req->len = 0; 2964 2965 ctlbuf.buf = (char *)buf; 2966 ctlbuf.len = tor->OPT_length + tor->OPT_offset; 2967 flags = 0; 2968 if (putmsg(sd, &ctlbuf, NULL, flags) < 0) { 2969 perror("mibget: putmsg (ctl)"); 2970 return (NULL); 2971 } 2972 /* 2973 * each reply consists of a ctl part for one fixed structure 2974 * or table, as defined in mib2.h. The format is a T_OPTMGMT_ACK, 2975 * containing an opthdr structure. level/name identify the entry, 2976 * len is the size of the data part of the message. 2977 */ 2978 req = (struct opthdr *)&toa[1]; 2979 ctlbuf.maxlen = sizeof (buf); 2980 for (j = 1; ; j++) { 2981 flags = 0; 2982 getcode = getmsg(sd, &ctlbuf, NULL, &flags); 2983 if (getcode < 0) { 2984 perror("mibget: getmsg (ctl)"); 2985 if (verbose) { 2986 (void) fprintf(stderr, 2987 "# level name len\n"); 2988 i = 0; 2989 for (last_item = first_item; last_item != NULL; 2990 last_item = last_item->next_item) { 2991 (void) printf("%d %4ld %5ld %ld\n", 2992 ++i, last_item->group, 2993 last_item->mib_id, 2994 last_item->length); 2995 } 2996 } 2997 break; 2998 } 2999 if (getcode == 0 && 3000 ctlbuf.len >= sizeof (struct T_optmgmt_ack) && 3001 toa->PRIM_type == T_OPTMGMT_ACK && 3002 toa->MGMT_flags == T_SUCCESS && 3003 req->len == 0) { 3004 if (verbose) { 3005 (void) printf("mibget getmsg() %d returned EOD " 3006 "(level %lu, name %lu)\n", j, req->level, 3007 req->name); 3008 } 3009 return (first_item); /* this is EOD msg */ 3010 } 3011 3012 if (ctlbuf.len >= sizeof (struct T_error_ack) && 3013 tea->PRIM_type == T_ERROR_ACK) { 3014 (void) fprintf(stderr, gettext("mibget %d gives " 3015 "T_ERROR_ACK: TLI_error = 0x%lx, UNIX_error = " 3016 "0x%lx\n"), j, tea->TLI_error, tea->UNIX_error); 3017 errno = (tea->TLI_error == TSYSERR) 3018 ? tea->UNIX_error : EPROTO; 3019 break; 3020 } 3021 3022 if (getcode != MOREDATA || 3023 ctlbuf.len < sizeof (struct T_optmgmt_ack) || 3024 toa->PRIM_type != T_OPTMGMT_ACK || 3025 toa->MGMT_flags != T_SUCCESS) { 3026 (void) printf("mibget getmsg(ctl) %d returned %d, " 3027 "ctlbuf.len = %d, PRIM_type = %ld\n", 3028 j, getcode, ctlbuf.len, toa->PRIM_type); 3029 if (toa->PRIM_type == T_OPTMGMT_ACK) { 3030 (void) printf("T_OPTMGMT_ACK: " 3031 "MGMT_flags = 0x%lx, req->len = %ld\n", 3032 toa->MGMT_flags, req->len); 3033 } 3034 errno = ENOMSG; 3035 break; 3036 } 3037 3038 temp = malloc(sizeof (mib_item_t)); 3039 if (temp == NULL) { 3040 perror("mibget: malloc"); 3041 break; 3042 } 3043 if (last_item != NULL) 3044 last_item->next_item = temp; 3045 else 3046 first_item = temp; 3047 last_item = temp; 3048 last_item->next_item = NULL; 3049 last_item->group = req->level; 3050 last_item->mib_id = req->name; 3051 last_item->length = req->len; 3052 last_item->valp = malloc(req->len); 3053 if (verbose) { 3054 (void) printf("msg %d: group = %4ld mib_id = %5ld " 3055 "length = %ld\n", 3056 j, last_item->group, last_item->mib_id, 3057 last_item->length); 3058 } 3059 3060 databuf.maxlen = last_item->length; 3061 databuf.buf = (char *)last_item->valp; 3062 databuf.len = 0; 3063 flags = 0; 3064 getcode = getmsg(sd, NULL, &databuf, &flags); 3065 if (getcode < 0) { 3066 perror("mibget: getmsg (data)"); 3067 break; 3068 } else if (getcode != 0) { 3069 (void) printf("mibget getmsg(data) returned %d, " 3070 "databuf.maxlen = %d, databuf.len = %d\n", 3071 getcode, databuf.maxlen, databuf.len); 3072 break; 3073 } 3074 } 3075 3076 /* 3077 * On error, free all the allocated mib_item_t objects. 3078 */ 3079 while (first_item != NULL) { 3080 last_item = first_item; 3081 first_item = first_item->next_item; 3082 free(last_item); 3083 } 3084 return (NULL); 3085 } 3086