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/stream.h> 55 #include <sys/tihdr.h> 56 #include <sys/sysmacros.h> 57 #include <sys/ccompile.h> 58 59 #include <net/if.h> 60 #include <net/route.h> 61 #include <net/if_dl.h> 62 #include <netinet/in.h> 63 #include <arpa/inet.h> 64 #include <netdb.h> 65 #include <inet/mib2.h> 66 #include <inet/ip.h> 67 68 #include <locale.h> 69 70 #include <errno.h> 71 #include <unistd.h> 72 #include <stdio.h> 73 #include <stdlib.h> 74 #include <string.h> 75 #include <stropts.h> 76 #include <fcntl.h> 77 #include <assert.h> 78 79 static struct keytab { 80 char *kt_cp; 81 int kt_i; 82 } keywords[] = { 83 #define K_ADD 1 84 {"add", K_ADD}, 85 #define K_BLACKHOLE 2 86 {"blackhole", K_BLACKHOLE}, 87 #define K_CHANGE 3 88 {"change", K_CHANGE}, 89 #define K_CLONING 4 90 {"cloning", K_CLONING}, 91 #define K_DELETE 5 92 {"delete", K_DELETE}, 93 #define K_DST 6 94 {"dst", K_DST}, 95 #define K_EXPIRE 7 96 {"expire", K_EXPIRE}, 97 #define K_FLUSH 8 98 {"flush", K_FLUSH}, 99 #define K_GATEWAY 9 100 {"gateway", K_GATEWAY}, 101 #define K_GET 11 102 {"get", K_GET}, 103 #define K_HOPCOUNT 12 104 {"hopcount", K_HOPCOUNT}, 105 #define K_HOST 13 106 {"host", K_HOST}, 107 #define K_IFA 14 108 {"ifa", K_IFA}, 109 #define K_IFACE 15 110 {"iface", K_IFACE}, 111 #define K_IFP 16 112 {"ifp", K_IFP}, 113 #define K_INET 17 114 {"inet", K_INET}, 115 #define K_INET6 18 116 {"inet6", K_INET6}, 117 #define K_INTERFACE 19 118 {"interface", K_INTERFACE}, 119 #define K_LINK 20 120 {"link", K_LINK}, 121 #define K_LOCK 21 122 {"lock", K_LOCK}, 123 #define K_LOCKREST 22 124 {"lockrest", K_LOCKREST}, 125 #define K_MASK 23 126 {"mask", K_MASK}, 127 #define K_MONITOR 24 128 {"monitor", K_MONITOR}, 129 #define K_MTU 25 130 {"mtu", K_MTU}, 131 #define K_NET 26 132 {"net", K_NET}, 133 #define K_NETMASK 27 134 {"netmask", K_NETMASK}, 135 #define K_NOSTATIC 28 136 {"nostatic", K_NOSTATIC}, 137 #define K_PRIVATE 29 138 {"private", K_PRIVATE}, 139 #define K_PROTO1 30 140 {"proto1", K_PROTO1}, 141 #define K_PROTO2 31 142 {"proto2", K_PROTO2}, 143 #define K_RECVPIPE 32 144 {"recvpipe", K_RECVPIPE}, 145 #define K_REJECT 33 146 {"reject", K_REJECT}, 147 #define K_RTT 34 148 {"rtt", K_RTT}, 149 #define K_RTTVAR 35 150 {"rttvar", K_RTTVAR}, 151 #define K_SA 36 152 {"sa", K_SA}, 153 #define K_SENDPIPE 37 154 {"sendpipe", K_SENDPIPE}, 155 #define K_SSTHRESH 38 156 {"ssthresh", K_SSTHRESH}, 157 #define K_STATIC 39 158 {"static", K_STATIC}, 159 #define K_XRESOLVE 40 160 {"xresolve", K_XRESOLVE}, 161 #define K_MULTIRT 41 162 {"multirt", K_MULTIRT}, 163 #define K_SETSRC 42 164 {"setsrc", K_SETSRC}, 165 {0, 0} 166 }; 167 168 static union sockunion { 169 struct sockaddr sa; 170 struct sockaddr_in sin; 171 struct sockaddr_dl sdl; 172 struct sockaddr_in6 sin6; 173 } so_dst, so_gate, so_mask, so_ifa, so_ifp, so_src; 174 175 typedef struct mib_item_s { 176 struct mib_item_s *next_item; 177 long group; 178 long mib_id; 179 long length; 180 intmax_t *valp; 181 } mib_item_t; 182 183 typedef union sockunion *sup; 184 185 static void bprintf(FILE *fp, int b, char *s); 186 static void delRouteEntry(mib2_ipRouteEntry_t *rp, 187 mib2_ipv6RouteEntry_t *rp6, int seqno); 188 static void flushroutes(int argc, char *argv[]); 189 static boolean_t getaddr(int which, char *s, struct hostent **hpp); 190 static boolean_t in6_getaddr(char *s, struct sockaddr_in6 *sin6, 191 int *plenp, struct hostent **hpp); 192 static boolean_t in_getaddr(char *s, struct sockaddr_in *sin, 193 int *plenp, int which, struct hostent **hpp); 194 static int in_getprefixlen(char *addr, int max_plen); 195 static boolean_t in_prefixlentomask(int prefixlen, int maxlen, 196 uchar_t *mask); 197 static void inet_makenetandmask(in_addr_t net, 198 struct sockaddr_in *sin); 199 static in_addr_t inet_makesubnetmask(in_addr_t addr, in_addr_t mask); 200 static int keyword(char *cp); 201 static void link_addr(const char *addr, struct sockaddr_dl *sdl); 202 static char *link_ntoa(const struct sockaddr_dl *sdl); 203 static mib_item_t *mibget(int sd); 204 static char *netname(struct sockaddr *sa); 205 static int newroute(int argc, char **argv); 206 static void pmsg_addrs(char *cp, int addrs); 207 static void pmsg_common(struct rt_msghdr *rtm); 208 static void print_getmsg(struct rt_msghdr *rtm, int msglen); 209 static void print_rtmsg(struct rt_msghdr *rtm, int msglen); 210 static void quit(char *s, int err) __NORETURN; 211 static char *routename(struct sockaddr *sa); 212 static void rtmonitor(int argc, char *argv[]); 213 static int rtmsg(int cmd, int flags); 214 static int salen(struct sockaddr *sa); 215 static void set_metric(char *value, int key); 216 static void sockaddr(char *addr, struct sockaddr *sa); 217 static void sodump(sup su, char *which); 218 static void usage(char *cp); 219 220 static int pid, rtm_addrs; 221 static int s; 222 static boolean_t forcehost, forcenet, nflag; 223 static int af = AF_INET; 224 static boolean_t qflag, tflag; 225 static boolean_t iflag, verbose; 226 static boolean_t locking, lockrest, debugonly; 227 static boolean_t fflag; 228 static struct rt_metrics rt_metrics; 229 static ulong_t rtm_inits; 230 static int masklen; 231 232 static struct { 233 struct rt_msghdr m_rtm; 234 char m_space[512]; 235 } m_rtmsg; 236 237 /* 238 * Sizes of data structures extracted from the base mib. 239 * This allows the size of the tables entries to grow while preserving 240 * binary compatibility. 241 */ 242 static int ipRouteEntrySize; 243 static int ipv6RouteEntrySize; 244 245 #define ROUNDUP_LONG(a) \ 246 ((a) > 0 ? (1 + (((a) - 1) | (sizeof (long) - 1))) : sizeof (long)) 247 #define ADVANCE(x, n) ((x) += ROUNDUP_LONG(salen(n))) 248 #define C(x) ((x) & 0xff) 249 250 /* 251 * return values from in_getprefixlen() 252 */ 253 #define BAD_ADDR -1 /* prefix is invalid */ 254 #define NO_PREFIX -2 /* no prefix was found */ 255 256 void 257 usage(char *cp) 258 { 259 if (cp != NULL) 260 (void) fprintf(stderr, gettext("route: botched keyword: %s\n"), 261 cp); 262 (void) fprintf(stderr, 263 gettext("usage: route [ -fnqv ] cmd [[ -<qualifers> ] args ]\n")); 264 exit(1); 265 /* NOTREACHED */ 266 } 267 268 void 269 quit(char *s, int sverrno) 270 { 271 (void) fprintf(stderr, "route: "); 272 if (s != NULL) 273 (void) fprintf(stderr, "%s: ", s); 274 (void) fprintf(stderr, "%s\n", strerror(sverrno)); 275 exit(sverrno); 276 /* NOTREACHED */ 277 } 278 279 int 280 main(int argc, char **argv) 281 { 282 extern int optind; 283 int ch; 284 int key; 285 286 (void) setlocale(LC_ALL, ""); 287 288 #if !defined(TEXT_DOMAIN) 289 #define TEXT_DOMAIN "SYS_TEST" 290 #endif 291 (void) textdomain(TEXT_DOMAIN); 292 293 if (argc < 2) 294 usage((char *)NULL); 295 296 while ((ch = getopt(argc, argv, "nqdtvf")) != EOF) { 297 switch (ch) { 298 case 'n': 299 nflag = B_TRUE; 300 break; 301 case 'q': 302 qflag = B_TRUE; 303 break; 304 case 'v': 305 verbose = B_TRUE; 306 break; 307 case 't': 308 tflag = B_TRUE; 309 break; 310 case 'd': 311 debugonly = B_TRUE; 312 break; 313 case 'f': 314 fflag = B_TRUE; 315 break; 316 case '?': 317 default: 318 usage((char *)NULL); 319 /* NOTREACHED */ 320 } 321 } 322 argc -= optind; 323 argv += optind; 324 325 pid = getpid(); 326 if (tflag) 327 s = open("/dev/null", O_WRONLY); 328 else 329 s = socket(PF_ROUTE, SOCK_RAW, 0); 330 if (s < 0) 331 quit("socket", errno); 332 if (fflag) { 333 /* 334 * Accept an address family keyword after the -f. Since the 335 * default address family is AF_INET, reassign af only for the 336 * other valid address families. 337 */ 338 if (*argv != NULL) { 339 switch (key = keyword(*argv)) { 340 case K_INET: 341 case K_INET6: 342 if (key == K_INET6) 343 af = AF_INET6; 344 /* Skip over the address family parameter. */ 345 argc--; 346 argv++; 347 break; 348 } 349 } 350 flushroutes(0, NULL); 351 } 352 if (*argv != NULL) { 353 switch (keyword(*argv)) { 354 case K_GET: 355 case K_CHANGE: 356 case K_ADD: 357 case K_DELETE: 358 return (newroute(argc, argv)); 359 360 case K_MONITOR: 361 rtmonitor(argc, argv); 362 /* NOTREACHED */ 363 364 case K_FLUSH: 365 flushroutes(argc, argv); 366 exit(0); 367 /* NOTREACHED */ 368 } 369 } 370 if (!fflag) 371 usage(*argv); 372 return (0); 373 } 374 375 /* 376 * Purge all entries in the routing tables not 377 * associated with network interfaces. 378 */ 379 void 380 flushroutes(int argc, char *argv[]) 381 { 382 int seqno; 383 int sd; /* mib stream */ 384 mib_item_t *item; 385 mib2_ipRouteEntry_t *rp; 386 mib2_ipv6RouteEntry_t *rp6; 387 int oerrno; 388 int off = 0; 389 int on = 1; 390 391 if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&off, 392 sizeof (off)) < 0) 393 quit("setsockopt", errno); 394 if (argc > 1) { 395 argv++; 396 if (argc == 2 && **argv == '-') { 397 /* 398 * The address family (preceded by a dash) may be used 399 * to flush the routes of that particular family. 400 */ 401 switch (keyword(*argv + 1)) { 402 case K_INET: 403 af = AF_INET; 404 break; 405 case K_LINK: 406 af = AF_LINK; 407 break; 408 case K_INET6: 409 af = AF_INET6; 410 break; 411 default: 412 usage(*argv); 413 /* NOTREACHED */ 414 } 415 } else { 416 usage(*argv); 417 } 418 } 419 sd = open("/dev/ip", O_RDWR); 420 oerrno = errno; 421 if (sd < 0) { 422 switch (errno) { 423 case EACCES: 424 (void) fprintf(stderr, 425 gettext("route: flush: insufficient privileges\n")); 426 exit(oerrno); 427 /* NOTREACHED */ 428 default: 429 quit(gettext("can't open mib stream"), oerrno); 430 /* NOTREACHED */ 431 } 432 } 433 if ((item = mibget(sd)) == NULL) 434 quit("mibget", errno); 435 if (verbose) { 436 (void) printf("Examining routing table from " 437 "T_SVR4_OPTMGMT_REQ\n"); 438 } 439 seqno = 0; /* ??? */ 440 switch (af) { 441 case AF_INET: 442 /* Extract ipRouteEntrySize */ 443 for (; item != NULL; item = item->next_item) { 444 if (item->mib_id != 0) 445 continue; 446 if (item->group == MIB2_IP) { 447 ipRouteEntrySize = 448 ((mib2_ip_t *)item->valp)->ipRouteEntrySize; 449 assert(IS_P2ALIGNED(ipRouteEntrySize, 450 sizeof (mib2_ipRouteEntry_t *))); 451 break; 452 } 453 } 454 if (ipRouteEntrySize == 0) { 455 (void) fprintf(stderr, 456 gettext("ipRouteEntrySize can't be determined.\n")); 457 exit(1); 458 } 459 for (; item != NULL; item = item->next_item) { 460 /* 461 * skip all the other trash that comes up the mib stream 462 */ 463 if (item->group != MIB2_IP || 464 item->mib_id != MIB2_IP_ROUTE) 465 continue; 466 for (rp = (mib2_ipRouteEntry_t *)item->valp; 467 (char *)rp < (char *)item->valp + item->length; 468 /* LINTED */ 469 rp = (mib2_ipRouteEntry_t *) 470 ((char *)rp + ipRouteEntrySize)) { 471 delRouteEntry(rp, NULL, seqno); 472 seqno++; 473 } 474 break; 475 } 476 break; 477 case AF_INET6: 478 /* Extract ipv6RouteEntrySize */ 479 for (; item != NULL; item = item->next_item) { 480 if (item->mib_id != 0) 481 continue; 482 if (item->group == MIB2_IP6) { 483 ipv6RouteEntrySize = 484 ((mib2_ipv6IfStatsEntry_t *)item->valp)-> 485 ipv6RouteEntrySize; 486 assert(IS_P2ALIGNED(ipv6RouteEntrySize, 487 sizeof (mib2_ipv6RouteEntry_t *))); 488 break; 489 } 490 } 491 if (ipv6RouteEntrySize == 0) { 492 (void) fprintf(stderr, gettext( 493 "ipv6RouteEntrySize cannot be determined.\n")); 494 exit(1); 495 } 496 for (; item != NULL; item = item->next_item) { 497 /* 498 * skip all the other trash that comes up the mib stream 499 */ 500 if (item->group != MIB2_IP6 || 501 item->mib_id != MIB2_IP6_ROUTE) 502 continue; 503 for (rp6 = (mib2_ipv6RouteEntry_t *)item->valp; 504 (char *)rp6 < (char *)item->valp + item->length; 505 /* LINTED */ 506 rp6 = (mib2_ipv6RouteEntry_t *) 507 ((char *)rp6 + ipv6RouteEntrySize)) { 508 delRouteEntry(NULL, rp6, seqno); 509 seqno++; 510 } 511 break; 512 } 513 break; 514 } 515 516 if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&on, 517 sizeof (on)) < 0) 518 quit("setsockopt", errno); 519 } 520 521 /* 522 * Given the contents of a mib_item_t of id type MIB2_IP_ROUTE or 523 * MIB2_IP6_ROUTE, construct and send an RTM_DELETE routing socket message in 524 * order to facilitate the flushing of RTF_GATEWAY routes. 525 */ 526 static void 527 delRouteEntry(mib2_ipRouteEntry_t *rp, mib2_ipv6RouteEntry_t *rp6, int seqno) 528 { 529 char *cp; 530 int ire_type; 531 int rlen; 532 struct rt_msghdr *rtm; 533 struct sockaddr_in sin; 534 struct sockaddr_in6 sin6; 535 int slen; 536 537 if (rp != NULL) 538 ire_type = rp->ipRouteInfo.re_ire_type; 539 else 540 ire_type = rp6->ipv6RouteInfo.re_ire_type; 541 if (ire_type != IRE_DEFAULT && 542 ire_type != IRE_PREFIX && 543 ire_type != IRE_HOST && 544 ire_type != IRE_HOST_REDIRECT) 545 return; 546 547 rtm = &m_rtmsg.m_rtm; 548 (void) memset(rtm, 0, sizeof (m_rtmsg)); 549 rtm->rtm_type = RTM_DELETE; 550 rtm->rtm_seq = seqno; 551 rtm->rtm_flags |= RTF_GATEWAY; 552 rtm->rtm_version = RTM_VERSION; 553 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 554 cp = m_rtmsg.m_space; 555 if (rp != NULL) { 556 slen = sizeof (struct sockaddr_in); 557 if (rp->ipRouteMask == IP_HOST_MASK) 558 rtm->rtm_flags |= RTF_HOST; 559 (void) memset(&sin, 0, slen); 560 sin.sin_family = AF_INET; 561 sin.sin_addr.s_addr = rp->ipRouteDest; 562 (void) memmove(cp, &sin, slen); 563 cp += slen; 564 sin.sin_addr.s_addr = rp->ipRouteNextHop; 565 (void) memmove(cp, &sin, slen); 566 cp += slen; 567 sin.sin_addr.s_addr = rp->ipRouteMask; 568 (void) memmove(cp, &sin, slen); 569 cp += slen; 570 } else { 571 slen = sizeof (struct sockaddr_in6); 572 if (rp6->ipv6RoutePfxLength == IPV6_ABITS) 573 rtm->rtm_flags |= RTF_HOST; 574 (void) memset(&sin6, 0, slen); 575 sin6.sin6_family = AF_INET6; 576 sin6.sin6_addr = rp6->ipv6RouteDest; 577 (void) memmove(cp, &sin6, slen); 578 cp += slen; 579 sin6.sin6_addr = rp6->ipv6RouteNextHop; 580 (void) memmove(cp, &sin6, slen); 581 cp += slen; 582 (void) memset(&sin6.sin6_addr, 0, sizeof (sin6.sin6_addr)); 583 (void) in_prefixlentomask(rp6->ipv6RoutePfxLength, IPV6_ABITS, 584 (uchar_t *)&sin6.sin6_addr.s6_addr); 585 (void) memmove(cp, &sin6, slen); 586 cp += slen; 587 } 588 rtm->rtm_msglen = cp - (char *)&m_rtmsg; 589 if (debugonly) { 590 /* 591 * In debugonly mode, the routing socket message to delete the 592 * current entry is not actually sent. However if verbose is 593 * also set, the routing socket message that would have been 594 * is printed. 595 */ 596 if (verbose) 597 print_rtmsg(rtm, rtm->rtm_msglen); 598 return; 599 } 600 601 rlen = write(s, (char *)&m_rtmsg, rtm->rtm_msglen); 602 if (rlen < (int)rtm->rtm_msglen) { 603 if (rlen < 0) { 604 (void) fprintf(stderr, 605 gettext("route: write to routing socket: %s\n"), 606 strerror(errno)); 607 } else { 608 (void) fprintf(stderr, gettext("route: write to " 609 "routing socket got only %d for rlen\n"), rlen); 610 } 611 return; 612 } 613 if (qflag) { 614 /* 615 * In quiet mode, nothing is printed at all (unless the write() 616 * itself failed. 617 */ 618 return; 619 } 620 if (verbose) { 621 print_rtmsg(rtm, rlen); 622 } else { 623 struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 624 625 (void) printf("%-20.20s ", 626 rtm->rtm_flags & RTF_HOST ? routename(sa) : 627 netname(sa)); 628 /* LINTED */ 629 sa = (struct sockaddr *)(salen(sa) + (char *)sa); 630 (void) printf("%-20.20s ", routename(sa)); 631 (void) printf("done\n"); 632 } 633 } 634 635 /* 636 * Return the name of the host whose address is given. 637 */ 638 char * 639 routename(struct sockaddr *sa) 640 { 641 char *cp; 642 static char line[MAXHOSTNAMELEN + 1]; 643 struct hostent *hp = NULL; 644 static char domain[MAXHOSTNAMELEN + 1]; 645 static boolean_t first = B_TRUE; 646 struct in_addr in; 647 struct in6_addr in6; 648 int error_num; 649 ushort_t *s; 650 ushort_t *slim; 651 652 if (first) { 653 first = B_FALSE; 654 if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 655 (cp = strchr(domain, '.'))) 656 (void) strcpy(domain, cp + 1); 657 else 658 domain[0] = 0; 659 } 660 661 if (salen(sa) == 0) { 662 (void) strcpy(line, "default"); 663 return (line); 664 } 665 switch (sa->sa_family) { 666 667 case AF_INET: 668 /* LINTED */ 669 in = ((struct sockaddr_in *)sa)->sin_addr; 670 671 cp = NULL; 672 if (in.s_addr == INADDR_ANY) 673 cp = "default"; 674 if (cp == NULL && !nflag) { 675 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 676 AF_INET); 677 if (hp != NULL) { 678 if (((cp = strchr(hp->h_name, '.')) != NULL) && 679 (strcmp(cp + 1, domain) == 0)) 680 *cp = 0; 681 cp = hp->h_name; 682 } 683 } 684 if (cp != NULL) { 685 (void) strncpy(line, cp, MAXHOSTNAMELEN); 686 line[MAXHOSTNAMELEN] = '\0'; 687 } else { 688 in.s_addr = ntohl(in.s_addr); 689 (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 690 C(in.s_addr >> 16), C(in.s_addr >> 8), 691 C(in.s_addr)); 692 } 693 break; 694 695 case AF_LINK: 696 return (link_ntoa((struct sockaddr_dl *)sa)); 697 698 case AF_INET6: 699 /* LINTED */ 700 in6 = ((struct sockaddr_in6 *)sa)->sin6_addr; 701 702 cp = NULL; 703 if (IN6_IS_ADDR_UNSPECIFIED(&in6)) 704 cp = "default"; 705 if (cp == NULL && !nflag) { 706 hp = getipnodebyaddr((char *)&in6, 707 sizeof (struct in6_addr), AF_INET6, &error_num); 708 if (hp != NULL) { 709 if (((cp = strchr(hp->h_name, '.')) != NULL) && 710 (strcmp(cp + 1, domain) == 0)) 711 *cp = 0; 712 cp = hp->h_name; 713 } 714 } 715 if (cp != NULL) { 716 (void) strncpy(line, cp, MAXHOSTNAMELEN); 717 line[MAXHOSTNAMELEN] = '\0'; 718 } else { 719 (void) inet_ntop(AF_INET6, (void *)&in6, line, 720 INET6_ADDRSTRLEN); 721 } 722 if (hp != NULL) 723 freehostent(hp); 724 725 break; 726 727 default: 728 s = (ushort_t *)sa; 729 730 slim = s + ((salen(sa) + 1) >> 1); 731 cp = line + sprintf(line, "(%d)", sa->sa_family); 732 733 while (++s < slim) /* start with sa->sa_data */ 734 cp += sprintf(cp, " %x", *s); 735 break; 736 } 737 return (line); 738 } 739 740 /* 741 * Return the name of the network whose address is given. 742 * The address is assumed to be that of a net or subnet, not a host. 743 */ 744 static char * 745 netname(struct sockaddr *sa) 746 { 747 char *cp = NULL; 748 static char line[MAXHOSTNAMELEN + 1]; 749 struct netent *np; 750 in_addr_t net, mask; 751 int subnetshift; 752 struct in_addr in; 753 ushort_t *s; 754 ushort_t *slim; 755 756 switch (sa->sa_family) { 757 758 case AF_INET: 759 /* LINTED */ 760 in = ((struct sockaddr_in *)sa)->sin_addr; 761 762 in.s_addr = ntohl(in.s_addr); 763 if (in.s_addr == INADDR_ANY) { 764 cp = "default"; 765 } else if (!nflag) { 766 if (IN_CLASSA(in.s_addr)) { 767 mask = IN_CLASSA_NET; 768 subnetshift = 8; 769 } else if (IN_CLASSB(in.s_addr)) { 770 mask = IN_CLASSB_NET; 771 subnetshift = 8; 772 } else { 773 mask = IN_CLASSC_NET; 774 subnetshift = 4; 775 } 776 /* 777 * If there are more bits than the standard mask 778 * would suggest, subnets must be in use. 779 * Guess at the subnet mask, assuming reasonable 780 * width subnet fields. 781 */ 782 while (in.s_addr &~ mask) 783 mask = (long)mask >> subnetshift; 784 net = in.s_addr & mask; 785 while ((mask & 1) == 0) 786 mask >>= 1, net >>= 1; 787 np = getnetbyaddr(net, AF_INET); 788 if (np != NULL) 789 cp = np->n_name; 790 } 791 if (cp != NULL) { 792 (void) strncpy(line, cp, MAXHOSTNAMELEN); 793 line[MAXHOSTNAMELEN] = '\0'; 794 } else if ((in.s_addr & 0xffffff) == 0) { 795 (void) sprintf(line, "%u", C(in.s_addr >> 24)); 796 } else if ((in.s_addr & 0xffff) == 0) { 797 (void) sprintf(line, "%u.%u", C(in.s_addr >> 24), 798 C(in.s_addr >> 16)); 799 } else if ((in.s_addr & 0xff) == 0) { 800 (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24), 801 C(in.s_addr >> 16), C(in.s_addr >> 8)); 802 } else { 803 (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 804 C(in.s_addr >> 16), C(in.s_addr >> 8), 805 C(in.s_addr)); 806 } 807 break; 808 809 case AF_LINK: 810 return (link_ntoa((struct sockaddr_dl *)sa)); 811 812 case AF_INET6: 813 return (routename(sa)); 814 815 default: 816 /* LINTED */ 817 s = (ushort_t *)sa->sa_data; 818 819 slim = s + ((salen(sa) + 1) >> 1); 820 cp = line + sprintf(line, "af %d:", sa->sa_family); 821 822 while (s < slim) 823 cp += sprintf(cp, " %x", *s++); 824 break; 825 } 826 return (line); 827 } 828 829 void 830 set_metric(char *value, int key) 831 { 832 int flag = 0; 833 uint_t noval, *valp = &noval; 834 835 switch (key) { 836 #define caseof(x, y, z) case (x): valp = &rt_metrics.z; flag = (y); break 837 caseof(K_MTU, RTV_MTU, rmx_mtu); 838 caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); 839 caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); 840 caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); 841 caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); 842 caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); 843 caseof(K_RTT, RTV_RTT, rmx_rtt); 844 caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); 845 #undef caseof 846 } 847 rtm_inits |= flag; 848 if (lockrest || locking) 849 rt_metrics.rmx_locks |= flag; 850 if (locking) 851 locking = B_FALSE; 852 *valp = atoi(value); 853 } 854 855 int 856 newroute(int argc, char **argv) 857 { 858 char *cmd, *dest = "", *gateway = "", *err; 859 boolean_t ishost = B_FALSE; 860 int ret, attempts, oerrno, flags = RTF_STATIC; 861 int key; 862 struct hostent *hp = NULL; 863 static char obuf[INET6_ADDRSTRLEN]; 864 865 cmd = argv[0]; 866 if (*cmd != 'g' && !tflag) { 867 /* Don't want to read back our messages */ 868 (void) shutdown(s, 0); 869 } 870 while (--argc > 0) { 871 key = keyword(*(++argv)); 872 if (key == K_HOST) { 873 forcehost = B_TRUE; 874 } else if (key == K_NET) { 875 forcenet = B_TRUE; 876 } else if (**(argv) == '-') { 877 switch (key = keyword(1 + *argv)) { 878 case K_LINK: 879 af = AF_LINK; 880 break; 881 case K_INET: 882 af = AF_INET; 883 break; 884 case K_SA: 885 af = PF_ROUTE; 886 break; 887 case K_INET6: 888 af = AF_INET6; 889 break; 890 case K_IFACE: 891 case K_INTERFACE: 892 iflag = B_TRUE; 893 /* FALLTHROUGH */ 894 case K_NOSTATIC: 895 flags &= ~RTF_STATIC; 896 break; 897 case K_LOCK: 898 locking = B_TRUE; 899 break; 900 case K_LOCKREST: 901 lockrest = B_TRUE; 902 break; 903 case K_HOST: 904 forcehost = B_TRUE; 905 break; 906 case K_REJECT: 907 flags |= RTF_REJECT; 908 break; 909 case K_BLACKHOLE: 910 flags |= RTF_BLACKHOLE; 911 break; 912 case K_PROTO1: 913 flags |= RTF_PROTO1; 914 break; 915 case K_PROTO2: 916 flags |= RTF_PROTO2; 917 break; 918 case K_CLONING: 919 flags |= RTF_CLONING; 920 break; 921 case K_XRESOLVE: 922 flags |= RTF_XRESOLVE; 923 break; 924 case K_STATIC: 925 flags |= RTF_STATIC; 926 break; 927 case K_IFA: 928 argc--; 929 (void) getaddr(RTA_IFA, *++argv, NULL); 930 break; 931 case K_IFP: 932 argc--; 933 (void) getaddr(RTA_IFP, *++argv, NULL); 934 break; 935 case K_GATEWAY: 936 /* 937 * For the gateway parameter, retrieve the 938 * pointer to the struct hostent so that all 939 * possible addresses can be tried until one 940 * is successful. 941 */ 942 argc--; 943 gateway = *++argv; 944 (void) getaddr(RTA_GATEWAY, *argv, &hp); 945 break; 946 case K_DST: 947 argc--; 948 ishost = getaddr(RTA_DST, *++argv, NULL); 949 dest = *argv; 950 break; 951 case K_NETMASK: 952 argc--; 953 (void) getaddr(RTA_NETMASK, *++argv, NULL); 954 /* FALLTHROUGH */ 955 case K_NET: 956 forcenet = B_TRUE; 957 break; 958 case K_MTU: 959 case K_HOPCOUNT: 960 case K_EXPIRE: 961 case K_RECVPIPE: 962 case K_SENDPIPE: 963 case K_SSTHRESH: 964 case K_RTT: 965 case K_RTTVAR: 966 argc--; 967 set_metric(*++argv, key); 968 break; 969 case K_PRIVATE: 970 flags |= RTF_PRIVATE; 971 break; 972 case K_MULTIRT: 973 flags |= RTF_MULTIRT; 974 break; 975 case K_SETSRC: 976 argc--; 977 (void) getaddr(RTA_SRC, *++argv, NULL); 978 flags |= RTF_SETSRC; 979 break; 980 default: 981 usage(*argv + 1); 982 /* NOTREACHED */ 983 } 984 } else { 985 if ((rtm_addrs & RTA_DST) == 0) { 986 dest = *argv; 987 ishost = getaddr(RTA_DST, *argv, NULL); 988 } else if ((rtm_addrs & RTA_GATEWAY) == 0) { 989 /* 990 * For the gateway parameter, retrieve the 991 * pointer to the struct hostent so that all 992 * possible addresses can be tried until one 993 * is successful. 994 */ 995 gateway = *argv; 996 (void) getaddr(RTA_GATEWAY, *argv, &hp); 997 } else { 998 ulong_t metric = strtoul(*argv, &err, 10); 999 1000 /* 1001 * Assume that a regular number is a metric. 1002 * Needed for compatibility with old route 1003 * command syntax. 1004 */ 1005 if (*argv != err && *err == '\0' && 1006 metric < 0x80000000ul) { 1007 iflag = (metric == 0); 1008 if (verbose) { 1009 (void) printf("old usage of " 1010 "trailing number, assuming " 1011 "route %s\n", iflag ? 1012 "to if" : "via gateway"); 1013 } 1014 continue; 1015 } 1016 (void) getaddr(RTA_NETMASK, *argv, NULL); 1017 } 1018 } 1019 } 1020 if ((rtm_addrs & RTA_DST) == 0) { 1021 (void) fprintf(stderr, 1022 gettext("route: destination required following command\n")); 1023 usage((char *)NULL); 1024 } else if ((*cmd == 'a' || *cmd == 'd') && 1025 (rtm_addrs & RTA_GATEWAY) == 0) { 1026 (void) fprintf(stderr, 1027 gettext("route: gateway required for add or delete " 1028 "command\n")); 1029 usage((char *)NULL); 1030 } 1031 1032 /* 1033 * If the netmask has been specified use it to determine RTF_HOST. 1034 * Otherwise rely on the "-net" and "-host" specifiers. 1035 * Final fallback is whether ot not any bits were set in the address 1036 * past the classful network component. 1037 */ 1038 if (rtm_addrs & RTA_NETMASK) { 1039 if ((af == AF_INET && 1040 so_mask.sin.sin_addr.s_addr == IP_HOST_MASK) || 1041 (af == AF_INET6 && masklen == IPV6_ABITS)) 1042 forcehost = B_TRUE; 1043 else 1044 forcenet = B_TRUE; 1045 } 1046 if (forcehost) 1047 ishost = B_TRUE; 1048 if (forcenet) 1049 ishost = B_FALSE; 1050 flags |= RTF_UP; 1051 if (ishost) 1052 flags |= RTF_HOST; 1053 if (!iflag) 1054 flags |= RTF_GATEWAY; 1055 for (attempts = 1; ; attempts++) { 1056 errno = 0; 1057 if ((ret = rtmsg(*cmd, flags)) == 0) 1058 break; 1059 if (errno != ENETUNREACH && errno != ESRCH) 1060 break; 1061 if (*gateway != '\0' && hp != NULL && 1062 hp->h_addr_list[attempts] != NULL) { 1063 switch (af) { 1064 case AF_INET: 1065 (void) memmove(&so_gate.sin.sin_addr, 1066 hp->h_addr_list[attempts], hp->h_length); 1067 continue; 1068 case AF_INET6: 1069 (void) memmove(&so_gate.sin6.sin6_addr, 1070 hp->h_addr_list[attempts], hp->h_length); 1071 continue; 1072 } 1073 } 1074 break; 1075 } 1076 oerrno = errno; 1077 if (*cmd != 'g') { 1078 (void) printf("%s %s %s", cmd, ishost ? "host" : "net", dest); 1079 if (*gateway != '\0') { 1080 switch (af) { 1081 case AF_INET: 1082 if (nflag) { 1083 (void) printf(": gateway %s", 1084 inet_ntoa(so_gate.sin.sin_addr)); 1085 } else if (attempts > 1 && ret == 0) { 1086 (void) printf(": gateway %s (%s)", 1087 gateway, 1088 inet_ntoa(so_gate.sin.sin_addr)); 1089 } else { 1090 (void) printf(": gateway %s", gateway); 1091 } 1092 break; 1093 case AF_INET6: 1094 if (inet_ntop(AF_INET6, 1095 (void *)&so_gate.sin6.sin6_addr, obuf, 1096 INET6_ADDRSTRLEN) != NULL) { 1097 if (nflag) { 1098 (void) printf(": gateway %s", 1099 obuf); 1100 } else if (attempts > 1 && ret == 0) { 1101 (void) printf(": gateway %s " 1102 "(%s)", 1103 gateway, obuf); 1104 } 1105 break; 1106 } 1107 /* FALLTHROUGH */ 1108 default: 1109 (void) printf(": gateway %s", gateway); 1110 break; 1111 } 1112 } 1113 if (ret == 0) 1114 (void) printf("\n"); 1115 } 1116 if (ret != 0) { 1117 if (*cmd == 'g') { 1118 if (nflag) { 1119 switch (af) { 1120 case AF_INET: 1121 (void) printf(" %s", 1122 inet_ntoa(so_dst.sin.sin_addr)); 1123 break; 1124 case AF_INET6: 1125 if (inet_ntop(AF_INET6, 1126 (void *)&so_dst.sin6.sin6_addr, 1127 obuf, INET6_ADDRSTRLEN) != NULL) { 1128 (void) printf(" %s", obuf); 1129 break; 1130 } 1131 /* FALLTHROUGH */ 1132 default: 1133 (void) printf("%s", dest); 1134 break; 1135 } 1136 } else { 1137 (void) printf("%s", dest); 1138 } 1139 } 1140 switch (oerrno) { 1141 case ESRCH: 1142 err = "not in table"; 1143 break; 1144 case EBUSY: 1145 err = "entry in use"; 1146 break; 1147 case ENOBUFS: 1148 err = "routing table overflow"; 1149 break; 1150 case EEXIST: 1151 err = "entry exists"; 1152 break; 1153 case EPERM: 1154 err = "insufficient privileges"; 1155 break; 1156 default: 1157 err = strerror(oerrno); 1158 break; 1159 } 1160 (void) printf(": %s\n", err); 1161 } 1162 /* 1163 * In the case of AF_INET6, one of the getipnodebyX() functions was used 1164 * so free the allocated hostent. 1165 */ 1166 if (af == AF_INET6 && hp != NULL) 1167 freehostent(hp); 1168 1169 return (oerrno); 1170 } 1171 1172 1173 /* 1174 * Convert a network number to the corresponding IP address. 1175 * If the RTA_NETMASK hasn't been specified yet set it based 1176 * on the class of address. 1177 */ 1178 static void 1179 inet_makenetandmask(in_addr_t net, struct sockaddr_in *sin) 1180 { 1181 in_addr_t addr, mask; 1182 char *cp; 1183 1184 if (net == 0) { 1185 mask = addr = 0; 1186 } else if (net < 128) { 1187 addr = net << IN_CLASSA_NSHIFT; 1188 mask = IN_CLASSA_NET; 1189 } else if (net < 65536) { 1190 addr = net << IN_CLASSB_NSHIFT; 1191 mask = IN_CLASSB_NET; 1192 } else if (net < 16777216L) { 1193 addr = net << IN_CLASSC_NSHIFT; 1194 mask = IN_CLASSC_NET; 1195 } else { 1196 addr = net; 1197 if ((addr & IN_CLASSA_HOST) == 0) 1198 mask = IN_CLASSA_NET; 1199 else if ((addr & IN_CLASSB_HOST) == 0) 1200 mask = IN_CLASSB_NET; 1201 else if ((addr & IN_CLASSC_HOST) == 0) 1202 mask = IN_CLASSC_NET; 1203 else { 1204 if (IN_CLASSA(addr)) 1205 mask = IN_CLASSA_NET; 1206 else if (IN_CLASSB(addr)) 1207 mask = IN_CLASSB_NET; 1208 else if (IN_CLASSC(addr)) 1209 mask = IN_CLASSC_NET; 1210 else 1211 mask = IP_HOST_MASK; 1212 mask = inet_makesubnetmask(addr, mask); 1213 } 1214 } 1215 sin->sin_addr.s_addr = htonl(addr); 1216 1217 if (!(rtm_addrs & RTA_NETMASK)) { 1218 rtm_addrs |= RTA_NETMASK; 1219 sin = &so_mask.sin; 1220 sin->sin_addr.s_addr = htonl(mask); 1221 sin->sin_family = AF_INET; 1222 cp = (char *)(&sin->sin_addr + 1); 1223 while (*--cp == 0 && cp > (char *)sin) 1224 ; 1225 } 1226 } 1227 1228 static in_addr_t 1229 inet_makesubnetmask(in_addr_t addr, in_addr_t mask) 1230 { 1231 int n; 1232 struct ifconf ifc; 1233 struct ifreq ifreq; 1234 struct ifreq *ifr; 1235 struct sockaddr_in *sin; 1236 char *buf; 1237 int numifs; 1238 size_t bufsize; 1239 int iosoc; 1240 in_addr_t if_addr, if_mask; 1241 in_addr_t if_subnetmask = 0; 1242 short if_flags; 1243 1244 if (mask == 0) 1245 return (0); 1246 if ((iosoc = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 1247 quit("socket", errno); 1248 if (ioctl(iosoc, SIOCGIFNUM, (char *)&numifs) < 0) 1249 quit("ioctl", errno); 1250 bufsize = numifs * sizeof (struct ifreq); 1251 buf = malloc(bufsize); 1252 if (buf == NULL) 1253 quit("malloc", errno); 1254 (void) memset(&ifc, 0, sizeof (ifc)); 1255 ifc.ifc_len = bufsize; 1256 ifc.ifc_buf = buf; 1257 if (ioctl(iosoc, SIOCGIFCONF, (char *)&ifc) < 0) 1258 quit("ioctl (get interface configuration)", errno); 1259 /* Let's check to see if this is maybe a local subnet route. */ 1260 ifr = ifc.ifc_req; 1261 for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) { 1262 ifreq = *ifr; 1263 /* LINTED */ 1264 sin = (struct sockaddr_in *)&ifr->ifr_addr; 1265 if_addr = ntohl(sin->sin_addr.s_addr); 1266 1267 if (ioctl(iosoc, SIOCGIFFLAGS, (char *)&ifreq) < 0) 1268 quit("ioctl (get interface flags)", errno); 1269 if ((ifreq.ifr_flags & IFF_UP) == 0) 1270 continue; 1271 if_flags = ifreq.ifr_flags; 1272 1273 if (ioctl(iosoc, SIOCGIFNETMASK, (char *)&ifreq) < 0) 1274 quit("ioctl (get netmask)", errno); 1275 /* LINTED */ 1276 sin = (struct sockaddr_in *)&ifreq.ifr_addr; 1277 if_mask = ntohl(sin->sin_addr.s_addr); 1278 if ((if_addr & mask) == (addr & mask)) { 1279 /* 1280 * Don't trust pt-pt interfaces if there are 1281 * other interfaces. 1282 */ 1283 if (if_flags & IFF_POINTOPOINT) { 1284 if_subnetmask = if_mask; 1285 continue; 1286 } 1287 /* 1288 * Fine. Just assume the same net mask as the 1289 * directly attached subnet interface is using. 1290 */ 1291 return (if_mask); 1292 } 1293 } 1294 if (if_subnetmask != 0) 1295 return (if_subnetmask); 1296 return (mask); 1297 } 1298 1299 /* 1300 * Interpret an argument as a network address of some kind, 1301 * returning B_TRUE if a host address, B_FALSE if a network address. 1302 * 1303 * If the address family is one looked up in getaddr() using one of the 1304 * getipnodebyX() functions (currently only AF_INET6), then callers should 1305 * freehostent() the returned "struct hostent" pointer if one was passed in. 1306 */ 1307 static boolean_t 1308 getaddr(int which, char *s, struct hostent **hpp) 1309 { 1310 sup su; 1311 struct hostent *hp; 1312 boolean_t ret; 1313 1314 if (s == NULL) { 1315 (void) fprintf(stderr, 1316 gettext("route: argument required following keyword\n")); 1317 usage((char *)NULL); 1318 } 1319 if (hpp == NULL) 1320 hpp = &hp; 1321 *hpp = NULL; 1322 rtm_addrs |= which; 1323 switch (which) { 1324 case RTA_DST: 1325 su = &so_dst; 1326 su->sa.sa_family = af; 1327 break; 1328 case RTA_GATEWAY: 1329 su = &so_gate; 1330 su->sa.sa_family = af; 1331 break; 1332 case RTA_NETMASK: 1333 su = &so_mask; 1334 su->sa.sa_family = af; 1335 break; 1336 case RTA_IFP: 1337 so_ifp.sdl.sdl_index = if_nametoindex(s); 1338 if (so_ifp.sdl.sdl_index == 0) { 1339 if (errno == ENXIO) { 1340 (void) fprintf(stderr, 1341 gettext("route: %s: no such interface\n"), 1342 s); 1343 exit(1); 1344 } else { 1345 quit("if_nametoindex", errno); 1346 } 1347 } 1348 so_ifp.sdl.sdl_family = AF_LINK; 1349 return (B_FALSE); 1350 /* 1351 * RTA_SRC has overloaded meaning. It can represent the 1352 * src address of incoming or outgoing packets. 1353 */ 1354 case RTA_IFA: 1355 su = &so_ifa; 1356 su->sa.sa_family = af; 1357 break; 1358 case RTA_SRC: 1359 su = &so_src; 1360 su->sa.sa_family = af; 1361 break; 1362 default: 1363 /* NOTREACHED */ 1364 quit(gettext("Internal Error"), EINVAL); 1365 /* NOTREACHED */ 1366 } 1367 if (strcmp(s, "default") == 0) { 1368 if (which == RTA_DST) { 1369 forcenet = B_TRUE; 1370 (void) getaddr(RTA_NETMASK, s, NULL); 1371 } 1372 if (which == RTA_SRC) { 1373 return (B_TRUE); 1374 } 1375 return (B_FALSE); 1376 } 1377 switch (af) { 1378 case AF_LINK: 1379 link_addr(s, &su->sdl); 1380 return (B_TRUE); 1381 case PF_ROUTE: 1382 sockaddr(s, &su->sa); 1383 return (B_TRUE); 1384 case AF_INET6: 1385 switch (which) { 1386 case RTA_DST: 1387 if (s[0] == '/') { 1388 (void) fprintf(stderr, 1389 gettext("route: %s: unexpected '/'\n"), s); 1390 exit(1); 1391 } 1392 ret = in6_getaddr(s, &su->sin6, &masklen, hpp); 1393 switch (masklen) { 1394 case NO_PREFIX: 1395 /* Nothing there - ok */ 1396 return (ret); 1397 case BAD_ADDR: 1398 (void) fprintf(stderr, 1399 gettext("route: bad prefix length in %s\n"), 1400 s); 1401 exit(1); 1402 /* NOTREACHED */ 1403 default: 1404 (void) memset(&so_mask.sin6.sin6_addr, 0, 1405 sizeof (so_mask.sin6.sin6_addr)); 1406 if (!in_prefixlentomask(masklen, IPV6_ABITS, 1407 (uchar_t *)&so_mask.sin6.sin6_addr)) { 1408 (void) fprintf(stderr, 1409 gettext("route: bad prefix length: " 1410 "%d\n"), masklen); 1411 exit(1); 1412 } 1413 break; 1414 } 1415 so_mask.sin6.sin6_family = af; 1416 rtm_addrs |= RTA_NETMASK; 1417 return (ret); 1418 case RTA_GATEWAY: 1419 case RTA_IFA: 1420 case RTA_SRC: 1421 ret = in6_getaddr(s, &su->sin6, NULL, hpp); 1422 return (ret); 1423 case RTA_NETMASK: 1424 (void) fprintf(stderr, 1425 gettext("route: -netmask not supported for IPv6: " 1426 "use <prefix>/<prefix-length> instead")); 1427 exit(1); 1428 /* NOTREACHED */ 1429 default: 1430 quit(gettext("Internal Error"), EINVAL); 1431 /* NOTREACHED */ 1432 } 1433 case AF_INET: 1434 switch (which) { 1435 case RTA_DST: 1436 if (s[0] == '/') { 1437 (void) fprintf(stderr, 1438 gettext("route: %s: unexpected '/'\n"), s); 1439 exit(1); 1440 } 1441 ret = in_getaddr(s, &su->sin, &masklen, which, hpp); 1442 switch (masklen) { 1443 case NO_PREFIX: 1444 /* Nothing there - ok */ 1445 return (ret); 1446 case BAD_ADDR: 1447 (void) fprintf(stderr, 1448 gettext("route: bad prefix length in %s\n"), 1449 s); 1450 exit(1); 1451 /* NOTREACHED */ 1452 default: 1453 (void) memset(&so_mask.sin.sin_addr, 0, 1454 sizeof (so_mask.sin.sin_addr)); 1455 if (!in_prefixlentomask(masklen, IP_ABITS, 1456 (uchar_t *)&so_mask.sin.sin_addr)) { 1457 (void) fprintf(stderr, 1458 gettext("route: bad prefix length: " 1459 "%d\n"), masklen); 1460 exit(1); 1461 } 1462 break; 1463 } 1464 so_mask.sin.sin_family = af; 1465 rtm_addrs |= RTA_NETMASK; 1466 return (ret); 1467 case RTA_GATEWAY: 1468 case RTA_IFA: 1469 case RTA_NETMASK: 1470 case RTA_SRC: 1471 ret = in_getaddr(s, &su->sin, NULL, which, hpp); 1472 return (ret); 1473 default: 1474 quit(gettext("Internal Error"), EINVAL); 1475 /* NOTREACHED */ 1476 } 1477 default: 1478 quit(gettext("Internal Error"), EINVAL); 1479 /* NOTREACHED */ 1480 } 1481 1482 } 1483 1484 /* 1485 * Interpret an argument as an IPv4 network address of some kind, 1486 * returning B_TRUE if a host address, B_FALSE if a network address. 1487 * Note that this *always* tries host interpretation before network 1488 * interpretation. 1489 * 1490 * If the plenp argument is non-NULL, allow <addr>/<n> syntax and 1491 * pass out <n> in *plenp. 1492 * If <n> doesn't parse return BAD_ADDR as *plenp. 1493 * If no /<n> is present return NO_PREFIX as *plenp. 1494 */ 1495 static boolean_t 1496 in_getaddr(char *s, struct sockaddr_in *sin, int *plenp, int which, 1497 struct hostent **hpp) 1498 { 1499 struct hostent *hp; 1500 struct netent *np; 1501 in_addr_t val; 1502 char str[BUFSIZ]; 1503 1504 (void) strncpy(str, s, sizeof (str)); 1505 1506 /* 1507 * Look for '/'<n> is plenp 1508 */ 1509 if (plenp != NULL) { 1510 char *cp; 1511 1512 *plenp = in_getprefixlen(str, IP_ABITS); 1513 if (*plenp == BAD_ADDR) 1514 return (B_FALSE); 1515 cp = strchr(str, '/'); 1516 if (cp != NULL) 1517 *cp = '\0'; 1518 } else if (strchr(str, '/') != NULL) { 1519 (void) fprintf(stderr, gettext("route: %s: unexpected '/'\n"), 1520 str); 1521 exit(1); 1522 } 1523 1524 (void) memset(sin, 0, sizeof (*sin)); 1525 sin->sin_family = AF_INET; 1526 1527 /* 1528 * Note: only the route destination can be a network, so we treat 1529 * all other addresses as though "-net" was not specified. 1530 */ 1531 if ((((val = inet_addr(str)) != (in_addr_t)-1) || 1532 strcmp(str, "255.255.255.255") == 0) && 1533 (which != RTA_DST || !forcenet)) { 1534 sin->sin_addr.s_addr = val; 1535 if (inet_lnaof(sin->sin_addr) != INADDR_ANY || 1536 forcehost) 1537 return (B_TRUE); 1538 val = ntohl(val); 1539 if (which == RTA_DST) 1540 inet_makenetandmask(val, sin); 1541 return (B_FALSE); 1542 } 1543 if (!forcehost && (val = inet_network(str)) != (in_addr_t)-1) { 1544 if (which == RTA_DST) 1545 inet_makenetandmask(val, sin); 1546 return (B_FALSE); 1547 } 1548 if ((which != RTA_DST || !forcenet) && 1549 (hp = gethostbyname(str)) != NULL) { 1550 *hpp = hp; 1551 (void) memmove(&sin->sin_addr, hp->h_addr, 1552 hp->h_length); 1553 return (B_TRUE); 1554 } 1555 if (!forcehost && (np = getnetbyname(str)) != NULL && 1556 (val = np->n_net) != 0) { 1557 if (which == RTA_DST) 1558 inet_makenetandmask(val, sin); 1559 return (B_FALSE); 1560 } 1561 (void) fprintf(stderr, gettext("%s: bad value\n"), s); 1562 exit(1); 1563 /* NOTREACHED */ 1564 } 1565 1566 /* 1567 * Interpret an argument as an IPv6 network address of some kind, 1568 * returning B_TRUE if a host address, B_FALSE if a network address. 1569 * 1570 * If the last argument is non-NULL allow a <addr>/<n> syntax and 1571 * pass out <n> in *plenp. 1572 * If <n> doesn't parse return BAD_ADDR as *plenp. 1573 * If no /<n> is present return NO_PREFIX as *plenp. 1574 */ 1575 static boolean_t 1576 in6_getaddr(char *s, struct sockaddr_in6 *sin6, int *plenp, 1577 struct hostent **hpp) 1578 { 1579 struct hostent *hp; 1580 char str[BUFSIZ]; 1581 int error_num; 1582 1583 (void) strncpy(str, s, sizeof (str)); 1584 1585 /* 1586 * Look for '/'<n> is plenp 1587 */ 1588 if (plenp != NULL) { 1589 char *cp; 1590 1591 *plenp = in_getprefixlen(str, IPV6_ABITS); 1592 if (*plenp == BAD_ADDR) 1593 return (B_FALSE); 1594 cp = strchr(str, '/'); 1595 if (cp != NULL) 1596 *cp = '\0'; 1597 } else if (strchr(str, '/') != NULL) { 1598 (void) fprintf(stderr, gettext("route: %s: unexpected '/'\n"), 1599 str); 1600 exit(1); 1601 } 1602 1603 (void) memset(sin6, 0, sizeof (struct sockaddr_in6)); 1604 sin6->sin6_family = AF_INET6; 1605 1606 hp = getipnodebyname(str, AF_INET6, 0, &error_num); 1607 if (hp != NULL) { 1608 *hpp = hp; 1609 (void) memmove(&sin6->sin6_addr, hp->h_addr, hp->h_length); 1610 return (B_TRUE); 1611 } 1612 if (error_num == TRY_AGAIN) { 1613 (void) fprintf(stderr, gettext("route: %s: bad address (try " 1614 "again later)\n"), s); 1615 } else { 1616 (void) fprintf(stderr, gettext("route: %s: bad address\n"), s); 1617 } 1618 exit(1); 1619 /* NOTREACHED */ 1620 } 1621 1622 /* 1623 * If "slash" is zero this parses the whole string as 1624 * an integer. With "slash" non zero it parses the tail part as an integer. 1625 * 1626 * If it is not a valid integer this returns BAD_ADDR. 1627 * If there is /<n> present this returns NO_PREFIX. 1628 */ 1629 int 1630 in_getprefixlen(char *addr, int max_plen) 1631 { 1632 int prefixlen; 1633 char *str, *end; 1634 1635 str = strchr(addr, '/'); 1636 if (str == NULL) 1637 return (NO_PREFIX); 1638 str++; 1639 1640 prefixlen = strtol(str, &end, 10); 1641 if (prefixlen < 0) 1642 return (BAD_ADDR); 1643 if (str == end) 1644 return (BAD_ADDR); 1645 if (max_plen != 0 && max_plen < prefixlen) 1646 return (BAD_ADDR); 1647 else 1648 return (prefixlen); 1649 } 1650 1651 /* 1652 * Convert a prefix length to a mask. 1653 * Returns B_TRUE if ok. B_FALSE otherwise. 1654 * Assumes the mask array is zeroed by the caller. 1655 */ 1656 boolean_t 1657 in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask) 1658 { 1659 if (prefixlen < 0 || prefixlen > maxlen) 1660 return (B_FALSE); 1661 1662 while (prefixlen > 0) { 1663 if (prefixlen >= 8) { 1664 *mask++ = 0xFF; 1665 prefixlen -= 8; 1666 continue; 1667 } 1668 *mask |= 1 << (8 - prefixlen); 1669 prefixlen--; 1670 } 1671 return (B_TRUE); 1672 } 1673 1674 void 1675 rtmonitor(int argc, char *argv[]) 1676 { 1677 int n; 1678 intmax_t msg[2048 / sizeof (intmax_t)]; 1679 1680 if (tflag) 1681 exit(0); 1682 verbose = B_TRUE; 1683 if (argc > 1) { 1684 argv++; 1685 if (argc == 2 && **argv == '-') { 1686 switch (keyword(*argv + 1)) { 1687 case K_INET: 1688 af = AF_INET; 1689 break; 1690 case K_LINK: 1691 af = AF_LINK; 1692 break; 1693 case K_INET6: 1694 af = AF_INET6; 1695 break; 1696 default: 1697 usage(*argv); 1698 /* NOTREACHED */ 1699 } 1700 } else { 1701 usage(*argv); 1702 } 1703 (void) close(s); 1704 s = socket(PF_ROUTE, SOCK_RAW, af); 1705 if (s < 0) 1706 quit("socket", errno); 1707 } 1708 for (;;) { 1709 n = read(s, msg, sizeof (msg)); 1710 if (n <= 0) 1711 quit("read", errno); 1712 (void) printf("got message of size %d\n", n); 1713 print_rtmsg((struct rt_msghdr *)msg, n); 1714 } 1715 } 1716 1717 int 1718 rtmsg(int cmd, int flags) 1719 { 1720 static int seq; 1721 int rlen; 1722 char *cp = m_rtmsg.m_space; 1723 int l; 1724 1725 errno = 0; 1726 (void) memset(&m_rtmsg, 0, sizeof (m_rtmsg)); 1727 if (cmd == 'a') { 1728 cmd = RTM_ADD; 1729 } else if (cmd == 'c') { 1730 cmd = RTM_CHANGE; 1731 } else if (cmd == 'g') { 1732 cmd = RTM_GET; 1733 if (so_ifp.sa.sa_family == 0) { 1734 so_ifp.sa.sa_family = AF_LINK; 1735 rtm_addrs |= RTA_IFP; 1736 } 1737 } else { 1738 cmd = RTM_DELETE; 1739 } 1740 #define rtm m_rtmsg.m_rtm 1741 rtm.rtm_type = cmd; 1742 rtm.rtm_flags = flags; 1743 rtm.rtm_version = RTM_VERSION; 1744 rtm.rtm_seq = ++seq; 1745 rtm.rtm_addrs = rtm_addrs; 1746 rtm.rtm_rmx = rt_metrics; 1747 rtm.rtm_inits = rtm_inits; 1748 1749 #define NEXTADDR(w, u) \ 1750 if (rtm_addrs & (w)) { \ 1751 l = ROUNDUP_LONG(salen(&u.sa)); \ 1752 (void) memmove(cp, &(u), l); \ 1753 cp += l; \ 1754 if (verbose) \ 1755 sodump(&(u), #u); \ 1756 } 1757 NEXTADDR(RTA_DST, so_dst); 1758 NEXTADDR(RTA_GATEWAY, so_gate); 1759 NEXTADDR(RTA_NETMASK, so_mask); 1760 NEXTADDR(RTA_IFP, so_ifp); 1761 NEXTADDR(RTA_IFA, so_ifa); 1762 /* 1763 * RTA_SRC has overloaded meaning. It can represent the 1764 * src address of incoming or outgoing packets. 1765 */ 1766 NEXTADDR(RTA_SRC, so_src); 1767 #undef NEXTADDR 1768 rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 1769 if (verbose) 1770 print_rtmsg(&rtm, l); 1771 if (debugonly) 1772 return (0); 1773 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 1774 switch (errno) { 1775 case ESRCH: 1776 case EBUSY: 1777 case ENOBUFS: 1778 case EEXIST: 1779 case ENETUNREACH: 1780 case EHOSTUNREACH: 1781 case EPERM: 1782 break; 1783 default: 1784 perror(gettext("writing to routing socket")); 1785 break; 1786 } 1787 return (-1); 1788 } else if (rlen < (int)rtm.rtm_msglen) { 1789 (void) fprintf(stderr, 1790 gettext("route: write to routing socket got only %d for " 1791 "len\n"), rlen); 1792 return (-1); 1793 } 1794 if (cmd == RTM_GET) { 1795 do { 1796 l = read(s, (char *)&m_rtmsg, sizeof (m_rtmsg)); 1797 } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); 1798 if (l < 0) { 1799 (void) fprintf(stderr, 1800 gettext("route: read from routing socket: %s\n"), 1801 strerror(errno)); 1802 } else { 1803 print_getmsg(&rtm, l); 1804 } 1805 } 1806 #undef rtm 1807 return (0); 1808 } 1809 1810 static char *msgtypes[] = { 1811 "", 1812 "RTM_ADD: Add Route", 1813 "RTM_DELETE: Delete Route", 1814 "RTM_CHANGE: Change Metrics or flags", 1815 "RTM_GET: Report Metrics", 1816 "RTM_LOSING: Kernel Suspects Partitioning", 1817 "RTM_REDIRECT: Told to use different route", 1818 "RTM_MISS: Lookup failed on this address", 1819 "RTM_LOCK: fix specified metrics", 1820 "RTM_OLDADD: caused by SIOCADDRT", 1821 "RTM_OLDDEL: caused by SIOCDELRT", 1822 "RTM_RESOLVE: Route created by cloning", 1823 "RTM_NEWADDR: address being added to iface", 1824 "RTM_DELADDR: address being removed from iface", 1825 "RTM_IFINFO: iface status change", 1826 0, 1827 }; 1828 1829 #define NMSGTYPES (sizeof (msgtypes) / sizeof (msgtypes[0])) 1830 1831 static char metricnames[] = 1832 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount" 1833 "\1mtu"; 1834 static char routeflags[] = 1835 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT" 1836 "\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE" 1837 "\016PRIVATE\017PROTO2\020PROTO1\021MULTIRT\022SETSRC"; 1838 static char ifnetflags[] = 1839 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP" 1840 "\011PPROMISC\012ALLMULTI\013INTELLIGENT\014MULTICAST" 1841 "\015MULTI_BCAST\016UNNUMBERED\017DHCP\020PRIVATE" 1842 "\021NOXMIT\022NOLOCAL\023DEPRECATED\024ADDRCONF" 1843 "\025ROUTER\026NONUD\027ANYCAST\030NORTEXCH\031IPv4\032IPv6" 1844 "\033MIP\034NOFAILOVER\035FAILED\036STANDBY\037INACTIVE\040OFFLINE" 1845 "\041XRESOLV\042COS\043PREFERRED\044TEMPORARY"; 1846 static char addrnames[] = 1847 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC"; 1848 1849 void 1850 print_rtmsg(struct rt_msghdr *rtm, int msglen) 1851 { 1852 struct if_msghdr *ifm; 1853 struct ifa_msghdr *ifam; 1854 1855 if (!verbose) 1856 return; 1857 if (rtm->rtm_version != RTM_VERSION) { 1858 (void) printf("routing message version %d not understood\n", 1859 rtm->rtm_version); 1860 return; 1861 } 1862 if (rtm->rtm_msglen > (ushort_t)msglen) { 1863 (void) printf("message length mismatch, in packet %d, " 1864 "returned %d\n", 1865 rtm->rtm_msglen, msglen); 1866 } 1867 /* 1868 * Since rtm->rtm_type is unsigned, we'll just check the case of zero 1869 * and the upper-bound of (NMSGTYPES - 1). 1870 */ 1871 if (rtm->rtm_type == 0 || rtm->rtm_type >= (NMSGTYPES - 1)) { 1872 (void) printf("routing message type %d not understood\n", 1873 rtm->rtm_type); 1874 return; 1875 } 1876 (void) printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen); 1877 switch (rtm->rtm_type) { 1878 case RTM_IFINFO: 1879 ifm = (struct if_msghdr *)rtm; 1880 (void) printf("if# %d, flags:", ifm->ifm_index); 1881 bprintf(stdout, ifm->ifm_flags, ifnetflags); 1882 pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs); 1883 break; 1884 case RTM_NEWADDR: 1885 case RTM_DELADDR: 1886 ifam = (struct ifa_msghdr *)rtm; 1887 (void) printf("metric %d, flags:", ifam->ifam_metric); 1888 bprintf(stdout, ifam->ifam_flags, routeflags); 1889 pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs); 1890 break; 1891 default: 1892 (void) printf("pid: %ld, seq %d, errno %d, flags:", 1893 rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 1894 bprintf(stdout, rtm->rtm_flags, routeflags); 1895 pmsg_common(rtm); 1896 } 1897 } 1898 1899 void 1900 print_getmsg(struct rt_msghdr *rtm, int msglen) 1901 { 1902 struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *src = NULL; 1903 struct sockaddr_dl *ifp = NULL; 1904 struct sockaddr *sa; 1905 char *cp; 1906 int i; 1907 1908 (void) printf(" route to: %s\n", routename(&so_dst.sa)); 1909 if (rtm->rtm_version != RTM_VERSION) { 1910 (void) fprintf(stderr, 1911 gettext("routing message version %d not understood\n"), 1912 rtm->rtm_version); 1913 return; 1914 } 1915 if (rtm->rtm_msglen > (ushort_t)msglen) { 1916 (void) fprintf(stderr, 1917 gettext("message length mismatch, in packet %d, " 1918 "returned %d\n"), rtm->rtm_msglen, msglen); 1919 } 1920 if (rtm->rtm_errno) { 1921 (void) fprintf(stderr, "RTM_GET: %s (errno %d)\n", 1922 strerror(rtm->rtm_errno), rtm->rtm_errno); 1923 return; 1924 } 1925 cp = ((char *)(rtm + 1)); 1926 if (rtm->rtm_addrs != 0) { 1927 for (i = 1; i != 0; i <<= 1) { 1928 if (i & rtm->rtm_addrs) { 1929 /* LINTED */ 1930 sa = (struct sockaddr *)cp; 1931 switch (i) { 1932 case RTA_DST: 1933 dst = sa; 1934 break; 1935 case RTA_GATEWAY: 1936 gate = sa; 1937 break; 1938 case RTA_NETMASK: 1939 mask = sa; 1940 break; 1941 case RTA_IFP: 1942 if (sa->sa_family == AF_LINK && 1943 ((struct sockaddr_dl *)sa)-> 1944 sdl_nlen != 0) 1945 ifp = (struct sockaddr_dl *)sa; 1946 break; 1947 case RTA_SRC: 1948 src = sa; 1949 break; 1950 } 1951 ADVANCE(cp, sa); 1952 } 1953 } 1954 } 1955 if (dst != NULL && mask != NULL) 1956 mask->sa_family = dst->sa_family; /* XXX */ 1957 if (dst != NULL) 1958 (void) printf("destination: %s\n", routename(dst)); 1959 if (mask != NULL) { 1960 boolean_t savenflag = nflag; 1961 1962 nflag = B_TRUE; 1963 (void) printf(" mask: %s\n", routename(mask)); 1964 nflag = savenflag; 1965 } 1966 if (gate != NULL && rtm->rtm_flags & RTF_GATEWAY) 1967 (void) printf(" gateway: %s\n", routename(gate)); 1968 if (src != NULL && rtm->rtm_flags & RTF_SETSRC) 1969 (void) printf(" setsrc: %s\n", routename(src)); 1970 if (ifp != NULL) { 1971 if (verbose) { 1972 int i; 1973 1974 (void) printf(" interface: %.*s index %d address ", 1975 ifp->sdl_nlen, ifp->sdl_data, ifp->sdl_index); 1976 for (i = ifp->sdl_nlen; 1977 i < ifp->sdl_nlen + ifp->sdl_alen; 1978 i++) { 1979 (void) printf("%02x ", 1980 ifp->sdl_data[i] & 0xFF); 1981 } 1982 (void) printf("\n"); 1983 } else { 1984 (void) printf(" interface: %.*s\n", 1985 ifp->sdl_nlen, ifp->sdl_data); 1986 } 1987 } 1988 (void) printf(" flags: "); 1989 bprintf(stdout, rtm->rtm_flags, routeflags); 1990 1991 #define lock(f) ((rtm->rtm_rmx.rmx_locks & RTV_ ## f) ? 'L' : ' ') 1992 #define msec(u) (((u) + 500) / 1000) /* usec to msec */ 1993 1994 (void) printf("\n%s\n", " recvpipe sendpipe ssthresh rtt,ms " 1995 "rttvar,ms hopcount mtu expire"); 1996 (void) printf("%8d%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); 1997 (void) printf("%8d%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); 1998 (void) printf("%8d%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); 1999 (void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); 2000 (void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR)); 2001 (void) printf("%8d%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT)); 2002 (void) printf("%8d%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); 2003 if (rtm->rtm_rmx.rmx_expire) 2004 rtm->rtm_rmx.rmx_expire -= time(0); 2005 (void) printf("%8d%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); 2006 #undef lock 2007 #undef msec 2008 #define RTA_IGN \ 2009 (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD|RTA_SRC) 2010 if (verbose) { 2011 pmsg_common(rtm); 2012 } else if (rtm->rtm_addrs &~ RTA_IGN) { 2013 (void) printf("sockaddrs: "); 2014 bprintf(stdout, rtm->rtm_addrs, addrnames); 2015 (void) putchar('\n'); 2016 } 2017 #undef RTA_IGN 2018 } 2019 2020 void 2021 pmsg_common(struct rt_msghdr *rtm) 2022 { 2023 (void) printf("\nlocks: "); 2024 bprintf(stdout, (int)rtm->rtm_rmx.rmx_locks, metricnames); 2025 (void) printf(" inits: "); 2026 bprintf(stdout, (int)rtm->rtm_inits, metricnames); 2027 pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs); 2028 } 2029 2030 void 2031 pmsg_addrs(char *cp, int addrs) 2032 { 2033 struct sockaddr *sa; 2034 int i; 2035 2036 if (addrs == 0) 2037 return; 2038 (void) printf("\nsockaddrs: "); 2039 bprintf(stdout, addrs, addrnames); 2040 (void) putchar('\n'); 2041 for (i = 1; i != 0; i <<= 1) { 2042 if (i & addrs) { 2043 /* LINTED */ 2044 sa = (struct sockaddr *)cp; 2045 (void) printf(" %s", routename(sa)); 2046 ADVANCE(cp, sa); 2047 } 2048 } 2049 (void) putchar('\n'); 2050 (void) fflush(stdout); 2051 } 2052 2053 void 2054 bprintf(FILE *fp, int b, char *s) 2055 { 2056 int i; 2057 boolean_t gotsome = B_FALSE; 2058 2059 if (b == 0) 2060 return; 2061 while ((i = *s++) != 0) { 2062 if (b & (1 << (i - 1))) { 2063 if (!gotsome) 2064 i = '<'; 2065 else 2066 i = ','; 2067 (void) putc(i, fp); 2068 gotsome = B_TRUE; 2069 for (; (i = *s) > ' '; s++) 2070 (void) putc(i, fp); 2071 } else { 2072 while (*s > ' ') 2073 s++; 2074 } 2075 } 2076 if (gotsome) 2077 (void) putc('>', fp); 2078 } 2079 2080 int 2081 keyword(char *cp) 2082 { 2083 struct keytab *kt = keywords; 2084 2085 while (kt->kt_cp && strcmp(kt->kt_cp, cp)) 2086 kt++; 2087 return (kt->kt_i); 2088 } 2089 2090 void 2091 sodump(sup su, char *which) 2092 { 2093 static char obuf[INET6_ADDRSTRLEN]; 2094 2095 switch (su->sa.sa_family) { 2096 case AF_LINK: 2097 (void) printf("%s: link %s; ", 2098 which, link_ntoa(&su->sdl)); 2099 break; 2100 case AF_INET: 2101 (void) printf("%s: inet %s; ", 2102 which, inet_ntoa(su->sin.sin_addr)); 2103 break; 2104 case AF_INET6: 2105 if (inet_ntop(AF_INET6, (void *)&su->sin6.sin6_addr, obuf, 2106 INET6_ADDRSTRLEN) != NULL) { 2107 (void) printf("%s: inet6 %s; ", which, obuf); 2108 break; 2109 } 2110 /* FALLTHROUGH */ 2111 default: 2112 quit(gettext("Internal Error"), EINVAL); 2113 /* NOTREACHED */ 2114 } 2115 (void) fflush(stdout); 2116 } 2117 2118 /* States */ 2119 #define VIRGIN 0 2120 #define GOTONE 1 2121 #define GOTTWO 2 2122 #define RESET 3 2123 /* Inputs */ 2124 #define DIGIT (4*0) 2125 #define END (4*1) 2126 #define DELIM (4*2) 2127 #define LETTER (4*3) 2128 2129 void 2130 sockaddr(char *addr, struct sockaddr *sa) 2131 { 2132 char *cp = (char *)sa; 2133 int size = salen(sa); 2134 char *cplim = cp + size; 2135 int byte = 0, state = VIRGIN, new; 2136 2137 (void) memset(cp, 0, size); 2138 cp++; 2139 do { 2140 if ((*addr >= '0') && (*addr <= '9')) { 2141 new = *addr - '0'; 2142 } else if ((*addr >= 'a') && (*addr <= 'f')) { 2143 new = *addr - 'a' + 10; 2144 } else if ((*addr >= 'A') && (*addr <= 'F')) { 2145 new = *addr - 'A' + 10; 2146 } else if (*addr == 0) { 2147 state |= END; 2148 } else { 2149 state |= DELIM; 2150 } 2151 addr++; 2152 switch (state /* | INPUT */) { 2153 case GOTTWO | DIGIT: 2154 *cp++ = byte; 2155 /* FALLTHROUGH */ 2156 case VIRGIN | DIGIT: 2157 state = GOTONE; byte = new; continue; 2158 case GOTONE | DIGIT: 2159 state = GOTTWO; byte = new + (byte << 4); continue; 2160 default: /* | DELIM */ 2161 state = VIRGIN; *cp++ = byte; byte = 0; continue; 2162 case GOTONE | END: 2163 case GOTTWO | END: 2164 *cp++ = byte; 2165 /* FALLTHROUGH */ 2166 case VIRGIN | END: 2167 break; 2168 } 2169 break; 2170 } while (cp < cplim); 2171 } 2172 2173 int 2174 salen(struct sockaddr *sa) 2175 { 2176 switch (sa->sa_family) { 2177 case AF_INET: 2178 return (sizeof (struct sockaddr_in)); 2179 case AF_LINK: 2180 return (sizeof (struct sockaddr_dl)); 2181 case AF_INET6: 2182 return (sizeof (struct sockaddr_in6)); 2183 default: 2184 return (sizeof (struct sockaddr)); 2185 } 2186 } 2187 2188 void 2189 link_addr(const char *addr, struct sockaddr_dl *sdl) 2190 { 2191 char *cp = sdl->sdl_data; 2192 char *cplim = sizeof (struct sockaddr_dl) + (char *)sdl; 2193 int byte = 0, state = VIRGIN, new; 2194 2195 (void) memset(sdl, 0, sizeof (struct sockaddr_dl)); 2196 sdl->sdl_family = AF_LINK; 2197 do { 2198 state &= ~LETTER; 2199 if ((*addr >= '0') && (*addr <= '9')) { 2200 new = *addr - '0'; 2201 } else if ((*addr >= 'a') && (*addr <= 'f')) { 2202 new = *addr - 'a' + 10; 2203 } else if ((*addr >= 'A') && (*addr <= 'F')) { 2204 new = *addr - 'A' + 10; 2205 } else if (*addr == 0) { 2206 state |= END; 2207 } else if (state == VIRGIN && 2208 (((*addr >= 'A') && (*addr <= 'Z')) || 2209 ((*addr >= 'a') && (*addr <= 'z')))) { 2210 state |= LETTER; 2211 } else { 2212 state |= DELIM; 2213 } 2214 addr++; 2215 switch (state /* | INPUT */) { 2216 case VIRGIN | DIGIT: 2217 case VIRGIN | LETTER: 2218 *cp++ = addr[-1]; 2219 continue; 2220 case VIRGIN | DELIM: 2221 state = RESET; 2222 sdl->sdl_nlen = cp - sdl->sdl_data; 2223 continue; 2224 case GOTTWO | DIGIT: 2225 *cp++ = byte; 2226 /* FALLTHROUGH */ 2227 case RESET | DIGIT: 2228 state = GOTONE; 2229 byte = new; 2230 continue; 2231 case GOTONE | DIGIT: 2232 state = GOTTWO; 2233 byte = new + (byte << 4); 2234 continue; 2235 default: /* | DELIM */ 2236 state = RESET; 2237 *cp++ = byte; 2238 byte = 0; 2239 continue; 2240 case GOTONE | END: 2241 case GOTTWO | END: 2242 *cp++ = byte; 2243 /* FALLTHROUGH */ 2244 case RESET | END: 2245 break; 2246 } 2247 break; 2248 } while (cp < cplim); 2249 sdl->sdl_alen = cp - LLADDR(sdl); 2250 } 2251 2252 static char hexlist[] = "0123456789abcdef"; 2253 2254 char * 2255 link_ntoa(const struct sockaddr_dl *sdl) 2256 { 2257 static char obuf[64]; 2258 char *out = obuf; 2259 int i; 2260 uchar_t *in = (uchar_t *)LLADDR(sdl); 2261 uchar_t *inlim = in + sdl->sdl_alen; 2262 boolean_t firsttime = B_TRUE; 2263 2264 if (sdl->sdl_nlen) { 2265 (void) memcpy(obuf, sdl->sdl_data, sdl->sdl_nlen); 2266 out += sdl->sdl_nlen; 2267 if (sdl->sdl_alen) 2268 *out++ = ':'; 2269 } 2270 while (in < inlim) { 2271 if (firsttime) 2272 firsttime = B_FALSE; 2273 else 2274 *out++ = '.'; 2275 i = *in++; 2276 if (i > 0xf) { 2277 out[1] = hexlist[i & 0xf]; 2278 i >>= 4; 2279 out[0] = hexlist[i]; 2280 out += 2; 2281 } else { 2282 *out++ = hexlist[i]; 2283 } 2284 } 2285 *out = 0; 2286 return (obuf); 2287 } 2288 2289 static mib_item_t * 2290 mibget(int sd) 2291 { 2292 intmax_t buf[512 / sizeof (intmax_t)]; 2293 int flags; 2294 int i, j, getcode; 2295 struct strbuf ctlbuf, databuf; 2296 struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf; 2297 struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf; 2298 struct T_error_ack *tea = (struct T_error_ack *)buf; 2299 struct opthdr *req; 2300 mib_item_t *first_item = NULL; 2301 mib_item_t *last_item = NULL; 2302 mib_item_t *temp; 2303 2304 tor->PRIM_type = T_SVR4_OPTMGMT_REQ; 2305 tor->OPT_offset = sizeof (struct T_optmgmt_req); 2306 tor->OPT_length = sizeof (struct opthdr); 2307 tor->MGMT_flags = T_CURRENT; 2308 req = (struct opthdr *)&tor[1]; 2309 req->level = MIB2_IP; /* any MIB2_xxx value ok here */ 2310 req->name = 0; 2311 req->len = 0; 2312 2313 ctlbuf.buf = (char *)buf; 2314 ctlbuf.len = tor->OPT_length + tor->OPT_offset; 2315 flags = 0; 2316 if (putmsg(sd, &ctlbuf, NULL, flags) < 0) { 2317 perror("mibget: putmsg (ctl)"); 2318 return (NULL); 2319 } 2320 /* 2321 * each reply consists of a ctl part for one fixed structure 2322 * or table, as defined in mib2.h. The format is a T_OPTMGMT_ACK, 2323 * containing an opthdr structure. level/name identify the entry, 2324 * len is the size of the data part of the message. 2325 */ 2326 req = (struct opthdr *)&toa[1]; 2327 ctlbuf.maxlen = sizeof (buf); 2328 for (j = 1; ; j++) { 2329 flags = 0; 2330 getcode = getmsg(sd, &ctlbuf, NULL, &flags); 2331 if (getcode < 0) { 2332 perror("mibget: getmsg (ctl)"); 2333 if (verbose) { 2334 (void) fprintf(stderr, 2335 "# level name len\n"); 2336 i = 0; 2337 for (last_item = first_item; last_item != NULL; 2338 last_item = last_item->next_item) { 2339 (void) printf("%d %4ld %5ld %ld\n", 2340 ++i, last_item->group, 2341 last_item->mib_id, 2342 last_item->length); 2343 } 2344 } 2345 break; 2346 } 2347 if (getcode == 0 && 2348 ctlbuf.len >= sizeof (struct T_optmgmt_ack) && 2349 toa->PRIM_type == T_OPTMGMT_ACK && 2350 toa->MGMT_flags == T_SUCCESS && 2351 req->len == 0) { 2352 if (verbose) { 2353 (void) printf("mibget getmsg() %d returned EOD " 2354 "(level %lu, name %lu)\n", j, req->level, 2355 req->name); 2356 } 2357 return (first_item); /* this is EOD msg */ 2358 } 2359 2360 if (ctlbuf.len >= sizeof (struct T_error_ack) && 2361 tea->PRIM_type == T_ERROR_ACK) { 2362 (void) fprintf(stderr, gettext("mibget %d gives " 2363 "T_ERROR_ACK: TLI_error = 0x%lx, UNIX_error = " 2364 "0x%lx\n"), j, tea->TLI_error, tea->UNIX_error); 2365 errno = (tea->TLI_error == TSYSERR) 2366 ? tea->UNIX_error : EPROTO; 2367 break; 2368 } 2369 2370 if (getcode != MOREDATA || 2371 ctlbuf.len < sizeof (struct T_optmgmt_ack) || 2372 toa->PRIM_type != T_OPTMGMT_ACK || 2373 toa->MGMT_flags != T_SUCCESS) { 2374 (void) printf("mibget getmsg(ctl) %d returned %d, " 2375 "ctlbuf.len = %d, PRIM_type = %ld\n", 2376 j, getcode, ctlbuf.len, toa->PRIM_type); 2377 if (toa->PRIM_type == T_OPTMGMT_ACK) { 2378 (void) printf("T_OPTMGMT_ACK: " 2379 "MGMT_flags = 0x%lx, req->len = %ld\n", 2380 toa->MGMT_flags, req->len); 2381 } 2382 errno = ENOMSG; 2383 break; 2384 } 2385 2386 temp = malloc(sizeof (mib_item_t)); 2387 if (temp == NULL) { 2388 perror("mibget: malloc"); 2389 break; 2390 } 2391 if (last_item != NULL) 2392 last_item->next_item = temp; 2393 else 2394 first_item = temp; 2395 last_item = temp; 2396 last_item->next_item = NULL; 2397 last_item->group = req->level; 2398 last_item->mib_id = req->name; 2399 last_item->length = req->len; 2400 last_item->valp = malloc(req->len); 2401 if (verbose) { 2402 (void) printf("msg %d: group = %4ld mib_id = %5ld " 2403 "length = %ld\n", 2404 j, last_item->group, last_item->mib_id, 2405 last_item->length); 2406 } 2407 2408 databuf.maxlen = last_item->length; 2409 databuf.buf = (char *)last_item->valp; 2410 databuf.len = 0; 2411 flags = 0; 2412 getcode = getmsg(sd, NULL, &databuf, &flags); 2413 if (getcode < 0) { 2414 perror("mibget: getmsg (data)"); 2415 break; 2416 } else if (getcode != 0) { 2417 (void) printf("mibget getmsg(data) returned %d, " 2418 "databuf.maxlen = %d, databuf.len = %d\n", 2419 getcode, databuf.maxlen, databuf.len); 2420 break; 2421 } 2422 } 2423 2424 /* 2425 * On error, free all the allocated mib_item_t objects. 2426 */ 2427 while (first_item != NULL) { 2428 last_item = first_item; 2429 first_item = first_item->next_item; 2430 free(last_item); 2431 } 2432 return (NULL); 2433 } 2434