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