1 /* 2 * Copyright 2007 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 #include <sys/ccompile.h> 60 61 #include <net/if.h> 62 #include <net/route.h> 63 #include <net/if_dl.h> 64 #include <netinet/in.h> 65 #include <arpa/inet.h> 66 #include <netdb.h> 67 #include <inet/mib2.h> 68 #include <inet/ip.h> 69 70 #include <limits.h> 71 #include <locale.h> 72 73 #include <errno.h> 74 #include <unistd.h> 75 #include <stdio.h> 76 #include <stdlib.h> 77 #include <stddef.h> 78 #include <string.h> 79 #include <stropts.h> 80 #include <fcntl.h> 81 #include <stdarg.h> 82 #include <assert.h> 83 #include <strings.h> 84 85 #include <libtsnet.h> 86 #include <tsol/label.h> 87 88 static struct keytab { 89 char *kt_cp; 90 int kt_i; 91 } keywords[] = { 92 #define K_ADD 1 93 {"add", K_ADD}, 94 #define K_BLACKHOLE 2 95 {"blackhole", K_BLACKHOLE}, 96 #define K_CHANGE 3 97 {"change", K_CHANGE}, 98 #define K_CLONING 4 99 {"cloning", K_CLONING}, 100 #define K_DELETE 5 101 {"delete", K_DELETE}, 102 #define K_DST 6 103 {"dst", K_DST}, 104 #define K_EXPIRE 7 105 {"expire", K_EXPIRE}, 106 #define K_FLUSH 8 107 {"flush", K_FLUSH}, 108 #define K_GATEWAY 9 109 {"gateway", K_GATEWAY}, 110 #define K_GET 11 111 {"get", K_GET}, 112 #define K_HOPCOUNT 12 113 {"hopcount", K_HOPCOUNT}, 114 #define K_HOST 13 115 {"host", K_HOST}, 116 #define K_IFA 14 117 {"ifa", K_IFA}, 118 #define K_IFACE 15 119 {"iface", K_IFACE}, 120 #define K_IFP 16 121 {"ifp", K_IFP}, 122 #define K_INET 17 123 {"inet", K_INET}, 124 #define K_INET6 18 125 {"inet6", K_INET6}, 126 #define K_INTERFACE 19 127 {"interface", K_INTERFACE}, 128 #define K_LINK 20 129 {"link", K_LINK}, 130 #define K_LOCK 21 131 {"lock", K_LOCK}, 132 #define K_LOCKREST 22 133 {"lockrest", K_LOCKREST}, 134 #define K_MASK 23 135 {"mask", K_MASK}, 136 #define K_MONITOR 24 137 {"monitor", K_MONITOR}, 138 #define K_MTU 25 139 {"mtu", K_MTU}, 140 #define K_NET 26 141 {"net", K_NET}, 142 #define K_NETMASK 27 143 {"netmask", K_NETMASK}, 144 #define K_NOSTATIC 28 145 {"nostatic", K_NOSTATIC}, 146 #define K_PRIVATE 29 147 {"private", K_PRIVATE}, 148 #define K_PROTO1 30 149 {"proto1", K_PROTO1}, 150 #define K_PROTO2 31 151 {"proto2", K_PROTO2}, 152 #define K_RECVPIPE 32 153 {"recvpipe", K_RECVPIPE}, 154 #define K_REJECT 33 155 {"reject", K_REJECT}, 156 #define K_RTT 34 157 {"rtt", K_RTT}, 158 #define K_RTTVAR 35 159 {"rttvar", K_RTTVAR}, 160 #define K_SA 36 161 {"sa", K_SA}, 162 #define K_SENDPIPE 37 163 {"sendpipe", K_SENDPIPE}, 164 #define K_SSTHRESH 38 165 {"ssthresh", K_SSTHRESH}, 166 #define K_STATIC 39 167 {"static", K_STATIC}, 168 #define K_XRESOLVE 40 169 {"xresolve", K_XRESOLVE}, 170 #define K_MULTIRT 41 171 {"multirt", K_MULTIRT}, 172 #define K_SETSRC 42 173 {"setsrc", K_SETSRC}, 174 #define K_SHOW 43 175 {"show", K_SHOW}, 176 #define K_SECATTR 43 177 {"secattr", K_SECATTR}, 178 {0, 0} 179 }; 180 181 /* 182 * Size of buffers used to hold command lines from the saved route file as 183 * well as error strings. 184 */ 185 #define BUF_SIZE 2048 186 187 typedef union sockunion { 188 struct sockaddr sa; 189 struct sockaddr_in sin; 190 struct sockaddr_dl sdl; 191 struct sockaddr_in6 sin6; 192 } su_t; 193 194 /* 195 * This structure represents the digested information from parsing arguments 196 * to route add, change, delete, and get. 197 * 198 */ 199 typedef struct rtcmd_irep { 200 int ri_cmd; 201 int ri_flags; 202 int ri_af; 203 ulong_t ri_inits; 204 struct rt_metrics ri_metrics; 205 int ri_addrs; 206 su_t ri_dst; 207 char *ri_dest_str; 208 su_t ri_src; 209 su_t ri_gate; 210 struct hostent *ri_gate_hp; 211 char *ri_gate_str; 212 su_t ri_mask; 213 su_t ri_ifa; 214 su_t ri_ifp; 215 char *ri_ifp_str; 216 int ri_rtsa_cnt; /* number of gateway security attributes */ 217 struct rtsa_s ri_rtsa; /* enough space for one attribute */ 218 } rtcmd_irep_t; 219 220 typedef struct mib_item_s { 221 struct mib_item_s *next_item; 222 long group; 223 long mib_id; 224 long length; 225 intmax_t *valp; 226 } mib_item_t; 227 228 typedef enum { 229 ADDR_TYPE_ANY, 230 ADDR_TYPE_HOST, 231 ADDR_TYPE_NET 232 } addr_type_t; 233 234 typedef enum { 235 SEARCH_MODE_NULL, 236 SEARCH_MODE_PRINT, 237 SEARCH_MODE_DEL 238 } search_mode_t; 239 240 static boolean_t args_to_rtcmd(rtcmd_irep_t *rcip, char **argv, 241 char *cmd_string); 242 static void bprintf(FILE *fp, int b, char *s); 243 static boolean_t compare_rtcmd(rtcmd_irep_t *srch_rt, 244 rtcmd_irep_t *file_rt); 245 static void delRouteEntry(mib2_ipRouteEntry_t *rp, 246 mib2_ipv6RouteEntry_t *rp6, int seqno); 247 static void del_rtcmd_irep(rtcmd_irep_t *rcip); 248 static void flushroutes(int argc, char *argv[]); 249 static boolean_t getaddr(rtcmd_irep_t *rcip, int which, char *s, 250 addr_type_t atype); 251 static boolean_t in6_getaddr(char *s, struct sockaddr_in6 *sin6, 252 int *plenp, struct hostent **hpp); 253 static boolean_t in_getaddr(char *s, struct sockaddr_in *sin, 254 int *plenp, int which, struct hostent **hpp, addr_type_t atype, 255 rtcmd_irep_t *rcip); 256 static int in_getprefixlen(char *addr, int max_plen); 257 static boolean_t in_prefixlentomask(int prefixlen, int maxlen, 258 uchar_t *mask); 259 static void inet_makenetandmask(rtcmd_irep_t *rcip, in_addr_t net, 260 struct sockaddr_in *sin); 261 static in_addr_t inet_makesubnetmask(in_addr_t addr, in_addr_t mask); 262 static int keyword(const char *cp); 263 static void link_addr(const char *addr, struct sockaddr_dl *sdl); 264 static char *link_ntoa(const struct sockaddr_dl *sdl); 265 static mib_item_t *mibget(int sd); 266 static char *netname(struct sockaddr *sa); 267 static int newroute(char **argv); 268 static rtcmd_irep_t *new_rtcmd_irep(void); 269 static void pmsg_addrs(const char *cp, size_t len, uint_t addrs); 270 static void pmsg_common(const struct rt_msghdr *rtm, size_t len); 271 static void print_getmsg(rtcmd_irep_t *req_rt, 272 struct rt_msghdr *rtm, int msglen); 273 static void print_rtcmd_short(FILE *to, rtcmd_irep_t *rcip, 274 boolean_t gw_good, boolean_t to_saved); 275 static void print_rtmsg(struct rt_msghdr *rtm, int msglen); 276 static void quit(char *s, int err) __NORETURN; 277 static char *routename(const struct sockaddr *sa); 278 static void rtmonitor(int argc, char *argv[]); 279 static int rtmsg(rtcmd_irep_t *rcip); 280 static int salen(const struct sockaddr *sa); 281 static void save_route(int argc, char **argv, int do_flush); 282 static void save_string(char **dst, char *src); 283 static int search_rtfile(FILE *fp, FILE *temp_fp, rtcmd_irep_t *rt, 284 search_mode_t mode); 285 static void set_metric(rtcmd_irep_t *rcip, char *value, int key, 286 boolean_t lock); 287 static int show_saved_routes(int argc); 288 static void sockaddr(char *addr, struct sockaddr *sa); 289 static void sodump(su_t *su, char *which); 290 static void syntax_arg_missing(char *keyword); 291 static void syntax_bad_keyword(char *keyword); 292 static void syntax_error(char *err, ...); 293 static void usage(char *cp); 294 static void write_to_rtfile(FILE *fp, int argc, char **argv); 295 static void pmsg_secattr(const char *, size_t, const char *); 296 297 static pid_t pid; 298 static int s; 299 static boolean_t nflag; 300 static int af = AF_INET; 301 static boolean_t qflag, tflag; 302 static boolean_t verbose; 303 static boolean_t debugonly; 304 static boolean_t fflag; 305 static boolean_t update_table; 306 static boolean_t perm_flag; 307 static boolean_t early_v6_keyword; 308 static char perm_file_sfx[] = "/etc/inet/static_routes"; 309 static char *perm_file; 310 static char temp_file_sfx[] = "/etc/inet/static_routes.tmp"; 311 static char *temp_file; 312 static struct in6_addr in6_host_mask = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 313 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 314 /* 315 * WARNING: 316 * This next variable indicates whether certain functions exit when an error 317 * is detected in the user input. Currently, exit_on_error is only set false 318 * in search_rtfile(), when argument are being parsed. Only those functions 319 * used by search_rtfile() to parse its arguments are designed to work in 320 * both modes. Take particular care in setting this false to ensure that any 321 * functions you call that might act on this flag properly return errors when 322 * exit_on_error is false. 323 */ 324 static int exit_on_error = B_TRUE; 325 326 static struct { 327 struct rt_msghdr m_rtm; 328 char m_space[BUF_SIZE]; 329 } m_rtmsg; 330 331 /* 332 * Sizes of data structures extracted from the base mib. 333 * This allows the size of the tables entries to grow while preserving 334 * binary compatibility. 335 */ 336 static int ipRouteEntrySize; 337 static int ipv6RouteEntrySize; 338 339 #define ROUNDUP_LONG(a) \ 340 ((a) > 0 ? (1 + (((a) - 1) | (sizeof (long) - 1))) : sizeof (long)) 341 #define ADVANCE(x, n) ((x) += ROUNDUP_LONG(salen(n))) 342 #define C(x) ((x) & 0xff) 343 344 /* 345 * return values from in_getprefixlen() 346 */ 347 #define BAD_ADDR -1 /* prefix is invalid */ 348 #define NO_PREFIX -2 /* no prefix was found */ 349 350 void 351 usage(char *cp) 352 { 353 if (cp != NULL) { 354 (void) fprintf(stderr, gettext("route: botched keyword: %s\n"), 355 cp); 356 } 357 (void) fprintf(stderr, gettext("usage: route [ -fnpqv ] " 358 "[ -R <root-dir> ] cmd [[ -<qualifers> ] args ]\n")); 359 exit(1); 360 /* NOTREACHED */ 361 } 362 363 /*PRINTFLIKE1*/ 364 void 365 syntax_error(char *err, ...) 366 { 367 va_list args; 368 369 if (exit_on_error) { 370 va_start(args, err); 371 (void) vfprintf(stderr, err, args); 372 va_end(args); 373 exit(1); 374 } 375 /* NOTREACHED */ 376 } 377 378 void 379 syntax_bad_keyword(char *keyword) 380 { 381 syntax_error(gettext("route: botched keyword: %s\n"), keyword); 382 } 383 384 void 385 syntax_arg_missing(char *keyword) 386 { 387 syntax_error(gettext("route: argument required following keyword %s\n"), 388 keyword); 389 } 390 391 void 392 quit(char *s, int sverrno) 393 { 394 (void) fprintf(stderr, "route: "); 395 if (s != NULL) 396 (void) fprintf(stderr, "%s: ", s); 397 (void) fprintf(stderr, "%s\n", strerror(sverrno)); 398 exit(sverrno); 399 /* NOTREACHED */ 400 } 401 402 int 403 main(int argc, char **argv) 404 { 405 extern int optind; 406 extern char *optarg; 407 int ch; 408 int rval; 409 size_t size; 410 const char *root_dir = NULL; 411 412 (void) setlocale(LC_ALL, ""); 413 414 #if !defined(TEXT_DOMAIN) 415 #define TEXT_DOMAIN "SYS_TEST" 416 #endif 417 (void) textdomain(TEXT_DOMAIN); 418 419 if (argc < 2) 420 usage(NULL); 421 422 while ((ch = getopt(argc, argv, "R:nqdtvfp")) != EOF) { 423 switch (ch) { 424 case 'n': 425 nflag = B_TRUE; 426 break; 427 case 'q': 428 qflag = B_TRUE; 429 break; 430 case 'v': 431 verbose = B_TRUE; 432 break; 433 case 't': 434 tflag = B_TRUE; 435 break; 436 case 'd': 437 debugonly = B_TRUE; 438 break; 439 case 'f': 440 fflag = B_TRUE; 441 break; 442 case 'p': 443 perm_flag = B_TRUE; 444 break; 445 case 'R': 446 root_dir = optarg; 447 break; 448 case '?': 449 default: 450 usage(NULL); 451 /* NOTREACHED */ 452 } 453 } 454 argc -= optind; 455 argv += optind; 456 457 pid = getpid(); 458 if (tflag) 459 s = open("/dev/null", O_WRONLY); 460 else 461 s = socket(PF_ROUTE, SOCK_RAW, 0); 462 if (s < 0) 463 quit("socket", errno); 464 465 /* 466 * Handle the -p and -R flags. The -R flag only applies 467 * when the -p flag is set. 468 */ 469 if (root_dir == NULL) { 470 perm_file = perm_file_sfx; 471 temp_file = temp_file_sfx; 472 } else { 473 size = strlen(root_dir) + sizeof (perm_file_sfx); 474 perm_file = malloc(size); 475 if (perm_file == NULL) 476 quit("malloc", errno); 477 (void) snprintf(perm_file, size, "%s%s", root_dir, 478 perm_file_sfx); 479 size = strlen(root_dir) + sizeof (temp_file_sfx); 480 temp_file = malloc(size); 481 if (temp_file == NULL) 482 quit("malloc", errno); 483 (void) snprintf(temp_file, size, "%s%s", root_dir, 484 temp_file_sfx); 485 } 486 /* 487 * Whether or not to act on the routing table. The only time the 488 * routing table is not modified is when both -p and -R are present. 489 */ 490 update_table = (!perm_flag || root_dir == NULL); 491 if (tflag) 492 perm_flag = 0; 493 494 if (fflag) { 495 /* 496 * Accept an address family keyword after the -f. Since the 497 * default address family is AF_INET, reassign af only for the 498 * other valid address families. 499 */ 500 if (*argv != NULL) { 501 switch (keyword(*argv)) { 502 case K_INET6: 503 af = AF_INET6; 504 early_v6_keyword = B_TRUE; 505 /* fallthrough */ 506 case K_INET: 507 /* Skip over the address family parameter. */ 508 argc--; 509 argv++; 510 break; 511 } 512 } 513 flushroutes(0, NULL); 514 } 515 516 if (*argv != NULL) { 517 switch (keyword(*argv)) { 518 case K_GET: 519 case K_CHANGE: 520 case K_ADD: 521 case K_DELETE: 522 rval = 0; 523 if (update_table) { 524 rval = newroute(argv); 525 } 526 if (perm_flag && (rval == 0 || rval == EEXIST || 527 rval == ESRCH)) { 528 save_route(argc, argv, B_FALSE); 529 return (0); 530 } 531 return (rval); 532 case K_SHOW: 533 if (perm_flag) { 534 return (show_saved_routes(argc)); 535 } else { 536 syntax_error(gettext( 537 "route: show command requires -p\n")); 538 } 539 /* NOTREACHED */ 540 case K_MONITOR: 541 rtmonitor(argc, argv); 542 /* NOTREACHED */ 543 544 case K_FLUSH: 545 flushroutes(argc, argv); 546 return (0); 547 } 548 } 549 if (!fflag) 550 usage(*argv); 551 return (0); 552 } 553 554 /* 555 * Purge all entries in the routing tables not 556 * associated with network interfaces. 557 */ 558 void 559 flushroutes(int argc, char *argv[]) 560 { 561 int seqno; 562 int sd; /* mib stream */ 563 mib_item_t *item; 564 mib2_ipRouteEntry_t *rp; 565 mib2_ipv6RouteEntry_t *rp6; 566 int oerrno; 567 int off = 0; 568 int on = 1; 569 570 if (argc > 1) { 571 argv++; 572 if (argc == 2 && **argv == '-') { 573 /* 574 * The address family (preceded by a dash) may be used 575 * to flush the routes of that particular family. 576 */ 577 switch (keyword(*argv + 1)) { 578 case K_INET: 579 af = AF_INET; 580 break; 581 case K_LINK: 582 af = AF_LINK; 583 break; 584 case K_INET6: 585 af = AF_INET6; 586 break; 587 default: 588 usage(*argv); 589 /* NOTREACHED */ 590 } 591 } else { 592 usage(*argv); 593 } 594 } 595 if (perm_flag) { 596 /* This flushes the persistent route file */ 597 save_route(0, NULL, B_TRUE); 598 } 599 if (!update_table) { 600 return; 601 } 602 603 if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&off, 604 sizeof (off)) < 0) 605 quit("setsockopt", errno); 606 607 sd = open("/dev/ip", O_RDWR); 608 oerrno = errno; 609 if (sd < 0) { 610 switch (errno) { 611 case EACCES: 612 (void) fprintf(stderr, 613 gettext("route: flush: insufficient privileges\n")); 614 exit(oerrno); 615 /* NOTREACHED */ 616 default: 617 quit(gettext("can't open mib stream"), oerrno); 618 /* NOTREACHED */ 619 } 620 } 621 if ((item = mibget(sd)) == NULL) 622 quit("mibget", errno); 623 if (verbose) { 624 (void) printf("Examining routing table from " 625 "T_SVR4_OPTMGMT_REQ\n"); 626 } 627 seqno = 0; /* ??? */ 628 switch (af) { 629 case AF_INET: 630 /* Extract ipRouteEntrySize */ 631 for (; item != NULL; item = item->next_item) { 632 if (item->mib_id != 0) 633 continue; 634 if (item->group == MIB2_IP) { 635 ipRouteEntrySize = 636 ((mib2_ip_t *)item->valp)->ipRouteEntrySize; 637 assert(IS_P2ALIGNED(ipRouteEntrySize, 638 sizeof (mib2_ipRouteEntry_t *))); 639 break; 640 } 641 } 642 if (ipRouteEntrySize == 0) { 643 (void) fprintf(stderr, 644 gettext("ipRouteEntrySize can't be determined.\n")); 645 exit(1); 646 } 647 for (; item != NULL; item = item->next_item) { 648 /* 649 * skip all the other trash that comes up the mib stream 650 */ 651 if (item->group != MIB2_IP || 652 item->mib_id != MIB2_IP_ROUTE) 653 continue; 654 for (rp = (mib2_ipRouteEntry_t *)item->valp; 655 (char *)rp < (char *)item->valp + item->length; 656 /* LINTED */ 657 rp = (mib2_ipRouteEntry_t *) 658 ((char *)rp + ipRouteEntrySize)) { 659 delRouteEntry(rp, NULL, seqno); 660 seqno++; 661 } 662 break; 663 } 664 break; 665 case AF_INET6: 666 /* Extract ipv6RouteEntrySize */ 667 for (; item != NULL; item = item->next_item) { 668 if (item->mib_id != 0) 669 continue; 670 if (item->group == MIB2_IP6) { 671 ipv6RouteEntrySize = 672 ((mib2_ipv6IfStatsEntry_t *)item->valp)-> 673 ipv6RouteEntrySize; 674 assert(IS_P2ALIGNED(ipv6RouteEntrySize, 675 sizeof (mib2_ipv6RouteEntry_t *))); 676 break; 677 } 678 } 679 if (ipv6RouteEntrySize == 0) { 680 (void) fprintf(stderr, gettext( 681 "ipv6RouteEntrySize cannot be determined.\n")); 682 exit(1); 683 } 684 for (; item != NULL; item = item->next_item) { 685 /* 686 * skip all the other trash that comes up the mib stream 687 */ 688 if (item->group != MIB2_IP6 || 689 item->mib_id != MIB2_IP6_ROUTE) 690 continue; 691 for (rp6 = (mib2_ipv6RouteEntry_t *)item->valp; 692 (char *)rp6 < (char *)item->valp + item->length; 693 /* LINTED */ 694 rp6 = (mib2_ipv6RouteEntry_t *) 695 ((char *)rp6 + ipv6RouteEntrySize)) { 696 delRouteEntry(NULL, rp6, seqno); 697 seqno++; 698 } 699 break; 700 } 701 break; 702 } 703 704 if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&on, 705 sizeof (on)) < 0) 706 quit("setsockopt", errno); 707 } 708 709 /* 710 * Given the contents of a mib_item_t of id type MIB2_IP_ROUTE or 711 * MIB2_IP6_ROUTE, construct and send an RTM_DELETE routing socket message in 712 * order to facilitate the flushing of RTF_GATEWAY routes. 713 */ 714 static void 715 delRouteEntry(mib2_ipRouteEntry_t *rp, mib2_ipv6RouteEntry_t *rp6, int seqno) 716 { 717 char *cp; 718 int ire_type; 719 int rlen; 720 struct rt_msghdr *rtm; 721 struct sockaddr_in sin; 722 struct sockaddr_in6 sin6; 723 int slen; 724 725 if (rp != NULL) 726 ire_type = rp->ipRouteInfo.re_ire_type; 727 else 728 ire_type = rp6->ipv6RouteInfo.re_ire_type; 729 if (ire_type != IRE_DEFAULT && 730 ire_type != IRE_PREFIX && 731 ire_type != IRE_HOST && 732 ire_type != IRE_HOST_REDIRECT) 733 return; 734 735 rtm = &m_rtmsg.m_rtm; 736 (void) memset(rtm, 0, sizeof (m_rtmsg)); 737 rtm->rtm_type = RTM_DELETE; 738 rtm->rtm_seq = seqno; 739 rtm->rtm_flags |= RTF_GATEWAY; 740 rtm->rtm_version = RTM_VERSION; 741 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 742 cp = m_rtmsg.m_space; 743 if (rp != NULL) { 744 slen = sizeof (struct sockaddr_in); 745 if (rp->ipRouteMask == IP_HOST_MASK) 746 rtm->rtm_flags |= RTF_HOST; 747 (void) memset(&sin, 0, slen); 748 sin.sin_family = AF_INET; 749 sin.sin_addr.s_addr = rp->ipRouteDest; 750 (void) memmove(cp, &sin, slen); 751 cp += slen; 752 sin.sin_addr.s_addr = rp->ipRouteNextHop; 753 (void) memmove(cp, &sin, slen); 754 cp += slen; 755 sin.sin_addr.s_addr = rp->ipRouteMask; 756 (void) memmove(cp, &sin, slen); 757 cp += slen; 758 } else { 759 slen = sizeof (struct sockaddr_in6); 760 if (rp6->ipv6RoutePfxLength == IPV6_ABITS) 761 rtm->rtm_flags |= RTF_HOST; 762 (void) memset(&sin6, 0, slen); 763 sin6.sin6_family = AF_INET6; 764 sin6.sin6_addr = rp6->ipv6RouteDest; 765 (void) memmove(cp, &sin6, slen); 766 cp += slen; 767 sin6.sin6_addr = rp6->ipv6RouteNextHop; 768 (void) memmove(cp, &sin6, slen); 769 cp += slen; 770 (void) memset(&sin6.sin6_addr, 0, sizeof (sin6.sin6_addr)); 771 (void) in_prefixlentomask(rp6->ipv6RoutePfxLength, IPV6_ABITS, 772 (uchar_t *)&sin6.sin6_addr.s6_addr); 773 (void) memmove(cp, &sin6, slen); 774 cp += slen; 775 } 776 rtm->rtm_msglen = cp - (char *)&m_rtmsg; 777 if (debugonly) { 778 /* 779 * In debugonly mode, the routing socket message to delete the 780 * current entry is not actually sent. However if verbose is 781 * also set, the routing socket message that would have been 782 * is printed. 783 */ 784 if (verbose) 785 print_rtmsg(rtm, rtm->rtm_msglen); 786 return; 787 } 788 789 rlen = write(s, (char *)&m_rtmsg, rtm->rtm_msglen); 790 if (rlen < (int)rtm->rtm_msglen) { 791 if (rlen < 0) { 792 (void) fprintf(stderr, 793 gettext("route: write to routing socket: %s\n"), 794 strerror(errno)); 795 } else { 796 (void) fprintf(stderr, gettext("route: write to " 797 "routing socket got only %d for rlen\n"), rlen); 798 } 799 return; 800 } 801 if (qflag) { 802 /* 803 * In quiet mode, nothing is printed at all (unless the write() 804 * itself failed. 805 */ 806 return; 807 } 808 if (verbose) { 809 print_rtmsg(rtm, rlen); 810 } else { 811 struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 812 813 (void) printf("%-20.20s ", 814 rtm->rtm_flags & RTF_HOST ? routename(sa) : 815 netname(sa)); 816 /* LINTED */ 817 sa = (struct sockaddr *)(salen(sa) + (char *)sa); 818 (void) printf("%-20.20s ", routename(sa)); 819 (void) printf("done\n"); 820 } 821 } 822 823 /* 824 * Return the name of the host whose address is given. 825 */ 826 char * 827 routename(const struct sockaddr *sa) 828 { 829 char *cp; 830 static char line[MAXHOSTNAMELEN + 1]; 831 struct hostent *hp = NULL; 832 static char domain[MAXHOSTNAMELEN + 1]; 833 static boolean_t first = B_TRUE; 834 struct in_addr in; 835 struct in6_addr in6; 836 int error_num; 837 ushort_t *s; 838 ushort_t *slim; 839 840 if (first) { 841 first = B_FALSE; 842 if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 843 (cp = strchr(domain, '.'))) 844 (void) strcpy(domain, cp + 1); 845 else 846 domain[0] = 0; 847 } 848 849 if (salen(sa) == 0) { 850 (void) strcpy(line, "default"); 851 return (line); 852 } 853 switch (sa->sa_family) { 854 855 case AF_INET: 856 /* LINTED */ 857 in = ((struct sockaddr_in *)sa)->sin_addr; 858 859 cp = NULL; 860 if (in.s_addr == INADDR_ANY) 861 cp = "default"; 862 if (cp == NULL && !nflag) { 863 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 864 AF_INET); 865 if (hp != NULL) { 866 if (((cp = strchr(hp->h_name, '.')) != NULL) && 867 (strcmp(cp + 1, domain) == 0)) 868 *cp = 0; 869 cp = hp->h_name; 870 } 871 } 872 if (cp != NULL) { 873 (void) strncpy(line, cp, MAXHOSTNAMELEN); 874 line[MAXHOSTNAMELEN] = '\0'; 875 } else { 876 in.s_addr = ntohl(in.s_addr); 877 (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 878 C(in.s_addr >> 16), C(in.s_addr >> 8), 879 C(in.s_addr)); 880 } 881 break; 882 883 case AF_LINK: 884 return (link_ntoa((struct sockaddr_dl *)sa)); 885 886 case AF_INET6: 887 /* LINTED */ 888 in6 = ((struct sockaddr_in6 *)sa)->sin6_addr; 889 890 cp = NULL; 891 if (IN6_IS_ADDR_UNSPECIFIED(&in6)) 892 cp = "default"; 893 if (cp == NULL && !nflag) { 894 hp = getipnodebyaddr((char *)&in6, 895 sizeof (struct in6_addr), AF_INET6, &error_num); 896 if (hp != NULL) { 897 if (((cp = strchr(hp->h_name, '.')) != NULL) && 898 (strcmp(cp + 1, domain) == 0)) 899 *cp = 0; 900 cp = hp->h_name; 901 } 902 } 903 if (cp != NULL) { 904 (void) strncpy(line, cp, MAXHOSTNAMELEN); 905 line[MAXHOSTNAMELEN] = '\0'; 906 } else { 907 (void) inet_ntop(AF_INET6, (void *)&in6, line, 908 INET6_ADDRSTRLEN); 909 } 910 if (hp != NULL) 911 freehostent(hp); 912 913 break; 914 915 default: 916 s = (ushort_t *)sa; 917 918 slim = s + ((salen(sa) + 1) >> 1); 919 cp = line + sprintf(line, "(%d)", sa->sa_family); 920 921 while (++s < slim) /* start with sa->sa_data */ 922 cp += sprintf(cp, " %x", *s); 923 break; 924 } 925 return (line); 926 } 927 928 /* 929 * Return the name of the network whose address is given. 930 * The address is assumed to be that of a net or subnet, not a host. 931 */ 932 static char * 933 netname(struct sockaddr *sa) 934 { 935 char *cp = NULL; 936 static char line[MAXHOSTNAMELEN + 1]; 937 struct netent *np; 938 in_addr_t net, mask; 939 int subnetshift; 940 struct in_addr in; 941 ushort_t *s; 942 ushort_t *slim; 943 944 switch (sa->sa_family) { 945 946 case AF_INET: 947 /* LINTED */ 948 in = ((struct sockaddr_in *)sa)->sin_addr; 949 950 in.s_addr = ntohl(in.s_addr); 951 if (in.s_addr == INADDR_ANY) { 952 cp = "default"; 953 } else if (!nflag) { 954 if (IN_CLASSA(in.s_addr)) { 955 mask = IN_CLASSA_NET; 956 subnetshift = 8; 957 } else if (IN_CLASSB(in.s_addr)) { 958 mask = IN_CLASSB_NET; 959 subnetshift = 8; 960 } else { 961 mask = IN_CLASSC_NET; 962 subnetshift = 4; 963 } 964 /* 965 * If there are more bits than the standard mask 966 * would suggest, subnets must be in use. 967 * Guess at the subnet mask, assuming reasonable 968 * width subnet fields. 969 */ 970 while (in.s_addr &~ mask) 971 mask = (long)mask >> subnetshift; 972 net = in.s_addr & mask; 973 while ((mask & 1) == 0) 974 mask >>= 1, net >>= 1; 975 np = getnetbyaddr(net, AF_INET); 976 if (np != NULL) 977 cp = np->n_name; 978 } 979 if (cp != NULL) { 980 (void) strncpy(line, cp, MAXHOSTNAMELEN); 981 line[MAXHOSTNAMELEN] = '\0'; 982 } else if ((in.s_addr & 0xffffff) == 0) { 983 (void) sprintf(line, "%u", C(in.s_addr >> 24)); 984 } else if ((in.s_addr & 0xffff) == 0) { 985 (void) sprintf(line, "%u.%u", C(in.s_addr >> 24), 986 C(in.s_addr >> 16)); 987 } else if ((in.s_addr & 0xff) == 0) { 988 (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24), 989 C(in.s_addr >> 16), C(in.s_addr >> 8)); 990 } else { 991 (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 992 C(in.s_addr >> 16), C(in.s_addr >> 8), 993 C(in.s_addr)); 994 } 995 break; 996 997 case AF_LINK: 998 return (link_ntoa((struct sockaddr_dl *)sa)); 999 1000 case AF_INET6: 1001 return (routename(sa)); 1002 1003 default: 1004 /* LINTED */ 1005 s = (ushort_t *)sa->sa_data; 1006 1007 slim = s + ((salen(sa) + 1) >> 1); 1008 cp = line + sprintf(line, "af %d:", sa->sa_family); 1009 1010 while (s < slim) 1011 cp += sprintf(cp, " %x", *s++); 1012 break; 1013 } 1014 return (line); 1015 } 1016 1017 /* 1018 * Initialize a new structure. Keep in mind that ri_dst_str, ri_gate_str and 1019 * ri_ifp_str will be freed by det_rtcmd_irep, so they should either be NULL 1020 * or point to dynamically allocated memory. 1021 */ 1022 rtcmd_irep_t * 1023 new_rtcmd_irep(void) 1024 { 1025 rtcmd_irep_t *rcip; 1026 1027 rcip = calloc(1, sizeof (rtcmd_irep_t)); 1028 <