1 /* $OpenBSD: route.c,v 1.59 2003/07/02 21:44:58 deraadt Exp $ */ 2 /* $NetBSD: route.c,v 1.16 1996/04/15 18:27:05 cgd Exp $ */ 3 4 /* 5 * Copyright (c) 1983, 1989, 1991, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #ifndef lint 34 static const char copyright[] = 35 "@(#) Copyright (c) 1983, 1989, 1991, 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37 #endif /* not lint */ 38 39 #ifndef lint 40 #if 0 41 static const char sccsid[] = "@(#)route.c 8.3 (Berkeley) 3/19/94"; 42 #else 43 static const char rcsid[] = "$OpenBSD: route.c,v 1.59 2003/07/02 21:44:58 deraadt Exp $"; 44 #endif 45 #endif /* not lint */ 46 47 #include <sys/param.h> 48 #include <sys/socket.h> 49 #include <sys/ioctl.h> 50 #include <sys/mbuf.h> 51 #include <sys/sysctl.h> 52 53 #include <net/if.h> 54 #include <net/route.h> 55 #include <net/if_dl.h> 56 #include <netinet/in.h> 57 #include <netns/ns.h> 58 #include <netipx/ipx.h> 59 #include <netiso/iso.h> 60 #include <netccitt/x25.h> 61 #include <arpa/inet.h> 62 #include <netdb.h> 63 64 #include <errno.h> 65 #include <fcntl.h> 66 #include <unistd.h> 67 #include <stdio.h> 68 #include <ctype.h> 69 #include <stdlib.h> 70 #include <string.h> 71 #include <paths.h> 72 73 #include "keywords.h" 74 75 union sockunion { 76 struct sockaddr sa; 77 struct sockaddr_in sin; 78 #ifdef INET6 79 struct sockaddr_in6 sin6; 80 #endif 81 struct sockaddr_ns sns; 82 struct sockaddr_ipx sipx; 83 struct sockaddr_iso siso; 84 struct sockaddr_dl sdl; 85 struct sockaddr_x25 sx25; 86 } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp; 87 88 typedef union sockunion *sup; 89 pid_t pid; 90 int rtm_addrs, s; 91 int forcehost, forcenet, doflush, nflag, af, qflag, tflag, keyword(char *); 92 int iflag, verbose, aflen = sizeof (struct sockaddr_in); 93 int locking, lockrest, debugonly; 94 struct rt_metrics rt_metrics; 95 u_long rtm_inits; 96 uid_t uid; 97 98 char *routename(struct sockaddr *); 99 char *netname(struct sockaddr *); 100 void flushroutes(int, char **); 101 int newroute(int, char **); 102 void monitor(void); 103 int prefixlen(char *); 104 void sockaddr(char *, struct sockaddr *); 105 void sodump(sup, char *); 106 void print_getmsg(struct rt_msghdr *, int); 107 void print_rtmsg(struct rt_msghdr *, int); 108 void pmsg_common(struct rt_msghdr *); 109 void pmsg_addrs(char *, int); 110 void bprintf(FILE *, int, u_char *); 111 void mask_addr(void); 112 #ifdef INET6 113 static int inet6_makenetandmask(struct sockaddr_in6 *); 114 #endif 115 int getaddr(int, char *, struct hostent **); 116 int rtmsg(int, int); 117 int x25_makemask(void); 118 __dead void usage(char *cp); 119 void quit(char *s); 120 char *any_ntoa(const struct sockaddr *sa); 121 void set_metric(char *value, int key); 122 void inet_makenetandmask(u_int32_t net, struct sockaddr_in *sin, int bits); 123 char *ns_print(struct sockaddr_ns *sns); 124 char *ipx_print(struct sockaddr_ipx *sipx); 125 void interfaces(void); 126 127 extern void show(int, char **); /* XXX - from show.c */ 128 129 __dead void 130 usage(char *cp) 131 { 132 if (cp) 133 (void) fprintf(stderr, "route: botched keyword: %s\n", cp); 134 (void) fprintf(stderr, 135 "usage: route [ -nqv ] cmd [[ -<modifiers> ] args ]\n"); 136 (void) fprintf(stderr, 137 "keywords: get, add, change, delete, show, flush, monitor.\n"); 138 exit(1); 139 /* NOTREACHED */ 140 } 141 142 void 143 quit(char *s) 144 { 145 int sverrno = errno; 146 147 (void) fprintf(stderr, "route: "); 148 if (s) 149 (void) fprintf(stderr, "%s: ", s); 150 (void) fprintf(stderr, "%s\n", strerror(sverrno)); 151 exit(1); 152 /* NOTREACHED */ 153 } 154 155 #define ROUNDUP(a) \ 156 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 157 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 158 159 int 160 main(int argc, char **argv) 161 { 162 int ch; 163 int rval = 0; 164 165 if (argc < 2) 166 usage(NULL); 167 168 while ((ch = getopt(argc, argv, "nqdtv")) != -1) 169 switch(ch) { 170 case 'n': 171 nflag = 1; 172 break; 173 case 'q': 174 qflag = 1; 175 break; 176 case 'v': 177 verbose = 1; 178 break; 179 case 't': 180 tflag = 1; 181 break; 182 case 'd': 183 debugonly = 1; 184 break; 185 default: 186 usage(NULL); 187 } 188 argc -= optind; 189 argv += optind; 190 191 pid = getpid(); 192 uid = geteuid(); 193 if (tflag) 194 s = open(_PATH_DEVNULL, O_WRONLY); 195 else 196 s = socket(PF_ROUTE, SOCK_RAW, 0); 197 if (s < 0) 198 quit("socket"); 199 if (*argv == NULL) 200 goto no_cmd; 201 switch (keyword(*argv)) { 202 case K_GET: 203 uid = 0; 204 /* FALLTHROUGH */ 205 case K_CHANGE: 206 case K_ADD: 207 case K_DELETE: 208 rval = newroute(argc, argv); 209 break; 210 case K_SHOW: 211 uid = 0; 212 show(argc, argv); 213 break; 214 case K_MONITOR: 215 monitor(); 216 break; 217 case K_FLUSH: 218 flushroutes(argc, argv); 219 break; 220 no_cmd: 221 default: 222 usage(*argv); 223 } 224 exit(rval); 225 } 226 227 /* 228 * Purge all entries in the routing tables not 229 * associated with network interfaces. 230 */ 231 void 232 flushroutes(int argc, char **argv) 233 { 234 size_t needed; 235 int mib[6], rlen, seqno; 236 char *buf = NULL, *next, *lim = NULL; 237 struct rt_msghdr *rtm; 238 struct sockaddr *sa; 239 240 if (uid) { 241 errno = EACCES; 242 quit("must be root to alter routing table"); 243 } 244 shutdown(s, 0); /* Don't want to read back our messages */ 245 if (argc > 1) { 246 argv++; 247 if (argc == 2 && **argv == '-') 248 switch (keyword(*argv + 1)) { 249 case K_INET: 250 af = AF_INET; 251 break; 252 #ifdef INET6 253 case K_INET6: 254 af = AF_INET6; 255 break; 256 #endif 257 case K_XNS: 258 af = AF_NS; 259 break; 260 case K_IPX: 261 af = AF_IPX; 262 break; 263 case K_LINK: 264 af = AF_LINK; 265 break; 266 case K_ISO: 267 case K_OSI: 268 af = AF_ISO; 269 break; 270 case K_X25: 271 af = AF_CCITT; 272 break; 273 default: 274 goto bad; 275 } else 276 bad: usage(*argv); 277 } 278 mib[0] = CTL_NET; 279 mib[1] = PF_ROUTE; 280 mib[2] = 0; /* protocol */ 281 mib[3] = 0; /* wildcard address family */ 282 mib[4] = NET_RT_DUMP; 283 mib[5] = 0; /* no flags */ 284 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 285 quit("route-sysctl-estimate"); 286 if (needed) { 287 if ((buf = malloc(needed)) == NULL) 288 quit("malloc"); 289 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 290 quit("actual retrieval of routing table"); 291 lim = buf + needed; 292 } 293 if (verbose) { 294 (void) printf("Examining routing table from sysctl\n"); 295 if (af) 296 printf("(address family %s)\n", (*argv + 1)); 297 } 298 if (buf == NULL) 299 return; 300 301 seqno = 0; /* ??? */ 302 for (next = buf; next < lim; next += rtm->rtm_msglen) { 303 rtm = (struct rt_msghdr *)next; 304 if (verbose) 305 print_rtmsg(rtm, rtm->rtm_msglen); 306 if ((rtm->rtm_flags & (RTF_GATEWAY|RTF_STATIC|RTF_LLINFO)) == 0) 307 continue; 308 sa = (struct sockaddr *)(rtm + 1); 309 if (af) { 310 if (sa->sa_family != af) 311 continue; 312 } 313 if (sa->sa_family == AF_KEY) 314 continue; /* Don't flush SPD */ 315 if (debugonly) 316 continue; 317 rtm->rtm_type = RTM_DELETE; 318 rtm->rtm_seq = seqno; 319 rlen = write(s, next, rtm->rtm_msglen); 320 if (rlen < (int)rtm->rtm_msglen) { 321 (void) fprintf(stderr, 322 "route: write to routing socket: %s\n", 323 strerror(errno)); 324 (void) printf("got only %d for rlen\n", rlen); 325 break; 326 } 327 seqno++; 328 if (qflag) 329 continue; 330 if (verbose) 331 print_rtmsg(rtm, rlen); 332 else { 333 struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 334 (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ? 335 routename(sa) : netname(sa)); 336 sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa); 337 (void) printf("%-20.20s ", routename(sa)); 338 (void) printf("done\n"); 339 } 340 } 341 free(buf); 342 } 343 344 static char hexlist[] = "0123456789abcdef"; 345 346 char * 347 any_ntoa(const struct sockaddr *sa) 348 { 349 static char obuf[240]; 350 const char *in = sa->sa_data; 351 char *out = obuf; 352 int len = sa->sa_len; 353 354 *out++ = 'Q'; 355 do { 356 *out++ = hexlist[(*in >> 4) & 15]; 357 *out++ = hexlist[(*in++) & 15]; 358 *out++ = '.'; 359 } while (--len > 0 && (out + 3) < &obuf[sizeof obuf-1]); 360 out[-1] = '\0'; 361 return (obuf); 362 } 363 364 char * 365 routename(struct sockaddr *sa) 366 { 367 char *cp = NULL; 368 static char line[MAXHOSTNAMELEN]; 369 struct hostent *hp; 370 static char domain[MAXHOSTNAMELEN]; 371 static int first = 1; 372 char *ns_print(struct sockaddr_ns *); 373 char *ipx_print(struct sockaddr_ipx *); 374 375 if (first) { 376 first = 0; 377 if (gethostname(domain, sizeof domain) == 0 && 378 (cp = strchr(domain, '.'))) 379 (void) strlcpy(domain, cp + 1, sizeof domain); 380 else 381 domain[0] = 0; 382 cp = NULL; 383 } 384 385 if (sa->sa_len == 0) 386 (void) strlcpy(line, "default", sizeof line); 387 else switch (sa->sa_family) { 388 389 case AF_INET: 390 { struct in_addr in; 391 in = ((struct sockaddr_in *)sa)->sin_addr; 392 393 if (in.s_addr == INADDR_ANY || sa->sa_len < 4) 394 cp = "default"; 395 if (!cp && !nflag) { 396 if ((hp = gethostbyaddr((char *)&in.s_addr, 397 sizeof (in.s_addr), AF_INET)) != NULL) { 398 if ((cp = strchr(hp->h_name, '.')) && 399 !strcmp(cp + 1, domain)) 400 *cp = 0; 401 cp = hp->h_name; 402 } 403 } 404 strlcpy(line, cp ? cp : inet_ntoa(in), sizeof line); 405 break; 406 } 407 408 #ifdef INET6 409 case AF_INET6: 410 { 411 struct sockaddr_in6 sin6; 412 int niflags; 413 414 #ifdef NI_WITHSCOPEID 415 niflags = NI_WITHSCOPEID; 416 #else 417 niflags = 0; 418 #endif 419 if (nflag) 420 niflags |= NI_NUMERICHOST; 421 memset(&sin6, 0, sizeof(sin6)); 422 memcpy(&sin6, sa, sa->sa_len); 423 sin6.sin6_len = sizeof(struct sockaddr_in6); 424 sin6.sin6_family = AF_INET6; 425 #ifdef __KAME__ 426 if (sa->sa_len == sizeof(struct sockaddr_in6) && 427 (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || 428 IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) && 429 sin6.sin6_scope_id == 0) { 430 sin6.sin6_scope_id = 431 ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); 432 sin6.sin6_addr.s6_addr[2] = 0; 433 sin6.sin6_addr.s6_addr[3] = 0; 434 } 435 #endif 436 if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 437 line, sizeof(line), NULL, 0, niflags) != 0) 438 strncpy(line, "invalid", sizeof(line)); 439 break; 440 } 441 #endif 442 443 case AF_NS: 444 return (ns_print((struct sockaddr_ns *)sa)); 445 446 case AF_IPX: 447 return (ipx_print((struct sockaddr_ipx *)sa)); 448 449 case AF_LINK: 450 return (link_ntoa((struct sockaddr_dl *)sa)); 451 452 case AF_ISO: 453 (void) snprintf(line, sizeof line, "iso %s", 454 iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr)); 455 break; 456 457 default: 458 (void) snprintf(line, sizeof line, "(%d) %s", 459 sa->sa_family, any_ntoa(sa)); 460 break; 461 } 462 return (line); 463 } 464 465 /* 466 * Return the name of the network whose address is given. 467 * The address is assumed to be that of a net or subnet, not a host. 468 */ 469 char * 470 netname(struct sockaddr *sa) 471 { 472 char *cp = NULL; 473 static char line[MAXHOSTNAMELEN]; 474 struct netent *np = 0; 475 in_addr_t net, mask, subnetshift; 476 char *ns_print(struct sockaddr_ns *); 477 char *ipx_print(struct sockaddr_ipx *); 478 479 switch (sa->sa_family) { 480 481 case AF_INET: 482 { 483 struct in_addr in = ((struct sockaddr_in *)sa)->sin_addr; 484 485 in.s_addr = ntohl(in.s_addr); 486 if (in.s_addr == 0) 487 cp = "default"; 488 else if (!nflag) { 489 if (IN_CLASSA(in.s_addr)) { 490 mask = IN_CLASSA_NET; 491 subnetshift = 8; 492 } else if (IN_CLASSB(in.s_addr)) { 493 mask = IN_CLASSB_NET; 494 subnetshift = 8; 495 } else { 496 mask = IN_CLASSC_NET; 497 subnetshift = 4; 498 } 499 /* 500 * If there are more bits than the standard mask 501 * would suggest, subnets must be in use. 502 * Guess at the subnet mask, assuming reasonable 503 * width subnet fields. 504 */ 505 while (in.s_addr &~ mask) 506 mask = (int)mask >> subnetshift; 507 net = in.s_addr & mask; 508 while ((mask & 1) == 0) 509 mask >>= 1, net >>= 1; 510 np = getnetbyaddr(net, AF_INET); 511 if (np) 512 cp = np->n_name; 513 } 514 in = ((struct sockaddr_in *)sa)->sin_addr; 515 strlcpy(line, cp ? cp : inet_ntoa(in), sizeof line); 516 break; 517 } 518 519 #ifdef INET6 520 case AF_INET6: 521 { 522 struct sockaddr_in6 sin6; 523 int niflags; 524 525 #ifdef NI_WITHSCOPEID 526 niflags = NI_WITHSCOPEID; 527 #else 528 niflags = 0; 529 #endif 530 if (nflag) 531 niflags |= NI_NUMERICHOST; 532 memset(&sin6, 0, sizeof(sin6)); 533 memcpy(&sin6, sa, sa->sa_len); 534 sin6.sin6_len = sizeof(struct sockaddr_in6); 535 sin6.sin6_family = AF_INET6; 536 #ifdef __KAME__ 537 if (sa->sa_len == sizeof(struct sockaddr_in6) && 538 (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || 539 IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) && 540 sin6.sin6_scope_id == 0) { 541 sin6.sin6_scope_id = 542 ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); 543 sin6.sin6_addr.s6_addr[2] = 0; 544 sin6.sin6_addr.s6_addr[3] = 0; 545 } 546 #endif 547 if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 548 line, sizeof(line), NULL, 0, niflags) != 0) 549 strncpy(line, "invalid", sizeof(line)); 550 break; 551 } 552 #endif 553 554 case AF_NS: 555 return (ns_print((struct sockaddr_ns *)sa)); 556 557 case AF_IPX: 558 return (ipx_print((struct sockaddr_ipx *)sa)); 559 560 case AF_LINK: 561 return (link_ntoa((struct sockaddr_dl *)sa)); 562 563 case AF_ISO: 564 (void) snprintf(line, sizeof line, "iso %s", 565 iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr)); 566 break; 567 568 default: 569 snprintf(line, sizeof line, "af %d: %s", 570 sa->sa_family, any_ntoa(sa)); 571 break; 572 } 573 return (line); 574 } 575 576 void 577 set_metric(char *value, int key) 578 { 579 int flag = 0; 580 u_long noval, *valp = &noval; 581 582 switch (key) { 583 #define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break 584 caseof(K_MTU, RTV_MTU, rmx_mtu); 585 caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); 586 caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); 587 caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); 588 caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); 589 caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); 590 caseof(K_RTT, RTV_RTT, rmx_rtt); 591 caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); 592 } 593 rtm_inits |= flag; 594 if (lockrest || locking) 595 rt_metrics.rmx_locks |= flag; 596 if (locking) 597 locking = 0; 598 *valp = atoi(value); 599 } 600 601 int 602 newroute(int argc, char **argv) 603 { 604 char *cmd, *dest = "", *gateway = "", *err; 605 int ishost = 0, ret = 0, attempts, oerrno, flags = RTF_STATIC; 606 int key; 607 struct hostent *hp = 0; 608 609 if (uid) { 610 errno = EACCES; 611 quit("must be root to alter routing table"); 612 } 613 cmd = argv[0]; 614 if (*cmd != 'g') 615 shutdown(s, 0); /* Don't want to read back our messages */ 616 while (--argc > 0) { 617 if (**(++argv)== '-') { 618 switch (key = keyword(1 + *argv)) { 619 case K_LINK: 620 af = AF_LINK; 621 aflen = sizeof(struct sockaddr_dl); 622 break; 623 case K_OSI: 624 case K_ISO: 625 af = AF_ISO; 626 aflen = sizeof(struct sockaddr_iso); 627 break; 628 case K_INET: 629 af = AF_INET; 630 aflen = sizeof(struct sockaddr_in); 631 break; 632 #ifdef INET6 633 case K_INET6: 634 af = AF_INET6; 635 aflen = sizeof(struct sockaddr_in6); 636 break; 637 #endif 638 case K_X25: 639 af = AF_CCITT; 640 aflen = sizeof(struct sockaddr_x25); 641 break; 642 case K_SA: 643 af = PF_ROUTE; 644 aflen = sizeof(union sockunion); 645 break; 646 case K_XNS: 647 af = AF_NS; 648 aflen = sizeof(struct sockaddr_ns); 649 break; 650 case K_IPX: 651 af = AF_IPX; 652 aflen = sizeof(struct sockaddr_ipx); 653 break; 654 case K_IFACE: 655 case K_INTERFACE: 656 iflag++; 657 break; 658 case K_NOSTATIC: 659 flags &= ~RTF_STATIC; 660 break; 661 case K_LLINFO: 662 flags |= RTF_LLINFO; 663 break; 664 case K_LOCK: 665 locking = 1; 666 break; 667 case K_LOCKREST: 668 lockrest = 1; 669 break; 670 case K_HOST: 671 forcehost++; 672 break; 673 case K_REJECT: 674 flags |= RTF_REJECT; 675 break; 676 case K_BLACKHOLE: 677 flags |= RTF_BLACKHOLE; 678 break; 679 case K_PROTO1: 680 flags |= RTF_PROTO1; 681 break; 682 case K_PROTO2: 683 flags |= RTF_PROTO2; 684 break; 685 case K_CLONING: 686 flags |= RTF_CLONING; 687 break; 688 case K_XRESOLVE: 689 flags |= RTF_XRESOLVE; 690 break; 691 case K_STATIC: 692 flags |= RTF_STATIC; 693 break; 694 case K_IFA: 695 if (!--argc) 696 usage(1+*argv); 697 (void) getaddr(RTA_IFA, *++argv, 0); 698 break; 699 case K_IFP: 700 if (!--argc) 701 usage(1+*argv); 702 (void) getaddr(RTA_IFP, *++argv, 0); 703 break; 704 case K_GENMASK: 705 if (!--argc) 706 usage(1+*argv); 707 (void) getaddr(RTA_GENMASK, *++argv, 0); 708 break; 709 case K_GATEWAY: 710 if (!--argc) 711 usage(1+*argv); 712 (void) getaddr(RTA_GATEWAY, *++argv, 0); 713 break; 714 case K_DST: 715 if (!--argc) 716 usage(1+*argv); 717 ishost = getaddr(RTA_DST, *++argv, &hp); 718 dest = *argv; 719 break; 720 case K_NETMASK: 721 if (!--argc) 722 usage(1+*argv); 723 (void) getaddr(RTA_NETMASK, *++argv, 0); 724 /* FALLTHROUGH */ 725 case K_NET: 726 forcenet++; 727 break; 728 case K_PREFIXLEN: 729 if (!--argc) 730 usage(1+*argv); 731 ishost = prefixlen(*++argv); 732 break; 733 case K_MTU: 734 case K_HOPCOUNT: 735 case K_EXPIRE: 736 case K_RECVPIPE: 737 case K_SENDPIPE: 738 case K_SSTHRESH: 739 case K_RTT: 740 case K_RTTVAR: 741 if (!--argc) 742 usage(1+*argv); 743 set_metric(*++argv, key); 744 break; 745 default: 746 usage(1+*argv); 747 } 748 } else { 749 if ((rtm_addrs & RTA_DST) == 0) { 750 dest = *argv; 751 ishost = getaddr(RTA_DST, *argv, &hp); 752 } else if ((rtm_addrs & RTA_GATEWAY) == 0) { 753 gateway = *argv; 754 (void) getaddr(RTA_GATEWAY, *argv, &hp); 755 } else { 756 int hops = atoi(*argv); 757 758 if (hops == 0) { 759 if (!qflag && strcmp(*argv, "0") == 0) 760 printf("%s,%s", 761 "old usage of trailing 0", 762 "assuming route to if\n"); 763 else 764 usage(NULL); 765 iflag = 1; 766 continue; 767 } else if (hops > 0 && hops < 10) { 768 if (!qflag) { 769 printf("old usage of trailing digit, "); 770 printf("assuming route via gateway\n"); 771 } 772 iflag = 0; 773 continue; 774 } 775 (void) getaddr(RTA_NETMASK, *argv, 0); 776 } 777 } 778 } 779 if (forcehost) 780 ishost = 1; 781 if (forcenet) 782 ishost = 0; 783 flags |= RTF_UP; 784 if (ishost) 785 flags |= RTF_HOST; 786 if (iflag == 0) 787 flags |= RTF_GATEWAY; 788 for (attempts = 1; ; attempts++) { 789 errno = 0; 790 if ((ret = rtmsg(*cmd, flags)) == 0) 791 break; 792 if (errno != ENETUNREACH && errno != ESRCH) 793 break; 794 if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) { 795 hp->h_addr_list++; 796 memcpy(&so_gate.sin.sin_addr, hp->h_addr_list[0], 797 hp->h_length); 798 } else 799 break; 800 } 801 if (*cmd == 'g') 802 exit(0); 803 oerrno = errno; 804 if (!qflag) { 805 (void) printf("%s %s %s", cmd, ishost? "host" : "net", dest); 806 if (*gateway) { 807 (void) printf(": gateway %s", gateway); 808 if (attempts > 1 && ret == 0 && af == AF_INET) 809 (void) printf(" (%s)", 810 inet_ntoa(so_gate.sin.sin_addr)); 811 } 812 if (ret == 0) 813 (void) printf("\n"); 814 } 815 if (ret != 0) { 816 switch (oerrno) { 817 case ESRCH: 818 err = "not in table"; 819 break; 820 case EBUSY: 821 err = "entry in use"; 822 break; 823 case ENOBUFS: 824 err = "routing table overflow"; 825 break; 826 default: 827 err = strerror(oerrno); 828 break; 829 } 830 (void) printf(": %s\n", err); 831 } 832 return (ret != 0); 833 } 834 835 void 836 inet_makenetandmask(u_int32_t net, struct sockaddr_in *sin, int bits) 837 { 838 u_int32_t addr, mask = 0; 839 char *cp; 840 841 rtm_addrs |= RTA_NETMASK; 842 if (net == 0) 843 mask = addr = 0; 844 else if (bits) { 845 addr = net; 846 mask = 0xffffffff << (32 - bits); 847 } else if (net < 128) { 848 addr = net << IN_CLASSA_NSHIFT; 849 mask = IN_CLASSA_NET; 850 } else if (net < 65536) { 851 addr = net << IN_CLASSB_NSHIFT; 852 mask = IN_CLASSB_NET; 853 } else if (net < 16777216L) { 854 addr = net << IN_CLASSC_NSHIFT; 855 mask = IN_CLASSC_NET; 856 } else { 857 addr = net; 858 if ((addr & IN_CLASSA_HOST) == 0) 859 mask = IN_CLASSA_NET; 860 else if ((addr & IN_CLASSB_HOST) == 0) 861 mask = IN_CLASSB_NET; 862 else if ((addr & IN_CLASSC_HOST) == 0) 863 mask = IN_CLASSC_NET; 864 else 865 mask = -1; 866 } 867 sin->sin_addr.s_addr = htonl(addr); 868 sin = &so_mask.sin; 869 sin->sin_addr.s_addr = htonl(mask); 870 sin->sin_len = 0; 871 sin->sin_family = 0; 872 cp = (char *)(&sin->sin_addr + 1); 873 while (*--cp == 0 && cp > (char *)sin) 874 ; 875 sin->sin_len = 1 + cp - (char *)sin; 876 } 877 878 #ifdef INET6 879 /* 880 * XXX the function may need more improvement... 881 */ 882 static int 883 inet6_makenetandmask(struct sockaddr_in6 *sin6) 884 { 885 char *plen = NULL; 886 struct in6_addr in6; 887 888 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && 889 sin6->sin6_scope_id == 0) { 890 plen = "0"; 891 } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) { 892 /* aggregatable global unicast - RFC2374 */ 893 memset(&in6, 0, sizeof(in6)); 894 if (!memcmp(&sin6->sin6_addr.s6_addr[8], &in6.s6_addr[8], 8)) 895 plen = "64"; 896 } 897 898 if (!plen || strcmp(plen, "128") == 0) 899 return 1; 900 else { 901 rtm_addrs |= RTA_NETMASK; 902 (void)prefixlen(plen); 903 return 0; 904 } 905 } 906 #endif 907 908 /* 909 * Interpret an argument as a network address of some kind, 910 * returning 1 if a host address, 0 if a network address. 911 */ 912 int 913 getaddr(int which, char *s, struct hostent **hpp) 914 { 915 sup su = NULL; 916 struct ccitt_addr *ccitt_addr(char *, struct sockaddr_x25 *); 917 struct hostent *hp; 918 struct netent *np; 919 u_long val; 920 char *q, qs; 921 int afamily; 922 923 if (af == 0) { 924 af = AF_INET; 925 aflen = sizeof(struct sockaddr_in); 926 } 927 afamily = af; /* local copy of af so we can change it */ 928 rtm_addrs |= which; 929 switch (which) { 930 case RTA_DST: 931 su = &so_dst; 932 break; 933 case RTA_GATEWAY: 934 su = &so_gate; 935 break; 936 case RTA_NETMASK: 937 su = &so_mask; 938 break; 939 case RTA_GENMASK: 940 su = &so_genmask; 941 break; 942 case RTA_IFP: 943 su = &so_ifp; 944 afamily = AF_LINK; 945 break; 946 case RTA_IFA: 947 su = &so_ifa; 948 su->sa.sa_family = af; 949 break; 950 default: 951 usage("Internal Error"); 952 /*NOTREACHED*/ 953 } 954 su->sa.sa_len = aflen; 955 su->sa.sa_family = afamily; /* cases that don't want it have left already */ 956 if (strcmp(s, "default") == 0) { 957 switch (which) { 958 case RTA_DST: 959 forcenet++; 960 (void) getaddr(RTA_NETMASK, s, 0); 961 break; 962 case RTA_NETMASK: 963 case RTA_GENMASK: 964 su->sa.sa_len = 0; 965 } 966 return (0); 967 } 968 switch (afamily) { 969 #ifdef INET6 970 case AF_INET6: 971 { 972 struct addrinfo hints, *res; 973 974 memset(&hints, 0, sizeof(hints)); 975 hints.ai_family = afamily; /*AF_INET6*/ 976 hints.ai_flags = AI_NUMERICHOST; 977 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 978 if (getaddrinfo(s, "0", &hints, &res) != 0) { 979 hints.ai_flags = 0; 980 if (getaddrinfo(s, "0", &hints, &res) != 0) { 981 (void) fprintf(stderr, "%s: bad value\n", s); 982 exit(1); 983 } 984 } 985 if (sizeof(su->sin6) != res->ai_addrlen) { 986 (void) fprintf(stderr, "%s: bad value\n", s); 987 exit(1); 988 } 989 if (res->ai_next) { 990 (void) fprintf(stderr, 991 "%s: resolved to multiple values\n", s); 992 exit(1); 993 } 994 memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6)); 995 freeaddrinfo(res); 996 #ifdef __KAME__ 997 if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) || 998 IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr)) && 999 su->sin6.sin6_scope_id) { 1000 *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] = 1001 htons(su->sin6.sin6_scope_id); 1002 su->sin6.sin6_scope_id = 0; 1003 } 1004 #endif 1005 if (hints.ai_flags == AI_NUMERICHOST) { 1006 if (which == RTA_DST) 1007 return (inet6_makenetandmask(&su->sin6)); 1008 return (0); 1009 } else 1010 return (1); 1011 } 1012 #endif 1013 1014 case AF_NS: 1015 if (which == RTA_DST) { 1016 extern short ns_bh[3]; 1017 struct sockaddr_ns *sms = &(so_mask.sns); 1018 memset(sms, 0, sizeof(*sms)); 1019 sms->sns_family = 0; 1020 sms->sns_len = 6; 1021 sms->sns_addr.x_net = *(union ns_net *)ns_bh; 1022 rtm_addrs |= RTA_NETMASK; 1023 } 1024 su->sns.sns_addr = ns_addr(s); 1025 return (!ns_nullhost(su->sns.sns_addr)); 1026 1027 case AF_IPX: 1028 if (which == RTA_DST) { 1029 extern short ipx_bh[3]; 1030 struct sockaddr_ipx *sms = &(so_mask.sipx); 1031 memset(sms, 0, sizeof(*sms)); 1032 sms->sipx_family = 0; 1033 sms->sipx_len = 6; 1034 sms->sipx_addr.ipx_net = *(union ipx_net *)ipx_bh; 1035 rtm_addrs |= RTA_NETMASK; 1036 } 1037 su->sipx.sipx_addr = ipx_addr(s); 1038 return (!ipx_nullhost(su->sipx.sipx_addr)); 1039 1040 case AF_OSI: 1041 su->siso.siso_addr = *iso_addr(s); 1042 if (which == RTA_NETMASK || which == RTA_GENMASK) { 1043 char *cp = (char *)TSEL(&su->siso); 1044 su->siso.siso_nlen = 0; 1045 do { 1046 --cp; 1047 } while ((cp > (char *)su) && (*cp == 0)); 1048 su->siso.siso_len = 1 + cp - (char *)su; 1049 } 1050 return (1); 1051 1052 case AF_LINK: 1053 link_addr(s, &su->sdl); 1054 return (1); 1055 1056 case AF_CCITT: 1057 ccitt_addr(s, &su->sx25); 1058 return (which == RTA_DST ? x25_makemask() : 1); 1059 1060 case PF_ROUTE: 1061 su->sa.sa_len = sizeof(*su); 1062 sockaddr(s, &su->sa); 1063 return (1); 1064 1065 case AF_INET: 1066 default: 1067 break; 1068 } 1069 1070 if (hpp == NULL) 1071 hpp = &hp; 1072 *hpp = NULL; 1073 1074 q = strchr(s,'/'); 1075 if (q && which == RTA_DST) { 1076 qs = *q; 1077 *q = '\0'; 1078 val = inet_addr(s); 1079 if (val != INADDR_NONE) { 1080 inet_makenetandmask(htonl(val), &su->sin, 1081 strtoul(q+1, 0, 0)); 1082 return (0); 1083 } 1084 *q =qs; 1085 } 1086 if (((val = inet_addr(s)) != INADDR_NONE) && 1087 (which != RTA_DST || forcenet == 0)) { 1088 su->sin.sin_addr.s_addr = val; 1089 if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY) 1090 return (1); 1091 else { 1092 val = ntohl(val); 1093 goto netdone; 1094 } 1095 } 1096 if ((val = inet_network(s)) != INADDR_NONE || 1097 (forcehost == 0 && (np = getnetbyname(s)) != NULL && 1098 (val = np->n_net) != 0)) { 1099 netdone: 1100 if (which == RTA_DST) 1101 inet_makenetandmask(val, &su->sin, 0); 1102 return (0); 1103 } 1104 hp = gethostbyname(s); 1105 if (hp) { 1106 *hpp = hp; 1107 su->sin.sin_family = hp->h_addrtype; 1108 memcpy(&su->sin.sin_addr, hp->h_addr, hp->h_length); 1109 return (1); 1110 } 1111 (void) fprintf(stderr, "route: %s: bad value\n", s); 1112 exit(1); 1113 } 1114 1115 int 1116 prefixlen(char *s) 1117 { 1118 int len = atoi(s), q, r; 1119 int max; 1120 1121 switch (af) { 1122 case AF_INET: 1123 max = sizeof(struct in_addr) * 8; 1124 break; 1125 #ifdef INET6 1126 case AF_INET6: 1127 max = sizeof(struct in6_addr) * 8; 1128 break; 1129 #endif 1130 default: 1131 (void) fprintf(stderr, 1132 "prefixlen is not supported with af %d\n", af); 1133 exit(1); 1134 } 1135 1136 rtm_addrs |= RTA_NETMASK; 1137 if (len < -1 || len > max) { 1138 (void) fprintf(stderr, "%s: bad value\n", s); 1139 exit(1); 1140 } 1141 1142 q = len >> 3; 1143 r = len & 7; 1144 switch (af) { 1145 case AF_INET: 1146 memset(&so_mask, 0, sizeof(so_mask)); 1147 so_mask.sin.sin_family = AF_INET; 1148 so_mask.sin.sin_len = sizeof(struct sockaddr_in); 1149 so_mask.sin.sin_addr.s_addr = htonl(0xffffffff << (32 - len)); 1150 break; 1151 #ifdef INET6 1152 case AF_INET6: 1153 so_mask.sin6.sin6_family = AF_INET6; 1154 so_mask.sin6.sin6_len = sizeof(struct sockaddr_in6); 1155 memset((void *)&so_mask.sin6.sin6_addr, 0, 1156 sizeof(so_mask.sin6.sin6_addr)); 1157 if (q > 0) 1158 memset((void *)&so_mask.sin6.sin6_addr, 0xff, q); 1159 if (r > 0) 1160 *((u_char *)&so_mask.sin6.sin6_addr + q) = 1161 (0xff00 >> r) & 0xff; 1162 break; 1163 #endif 1164 } 1165 return (len == max); 1166 } 1167 1168 int 1169 x25_makemask(void) 1170 { 1171 char *cp; 1172 1173 if ((rtm_addrs & RTA_NETMASK) == 0) { 1174 rtm_addrs |= RTA_NETMASK; 1175 for (cp = (char *)&so_mask.sx25.x25_net; 1176 cp < &so_mask.sx25.x25_opts.op_flags; cp++) 1177 *cp = -1; 1178 so_mask.sx25.x25_len = (u_char)&(((sup)0)->sx25.x25_opts); 1179 } 1180 return (0); 1181 } 1182 1183 short ns_nullh[] = {0,0,0}; 1184 short ns_bh[] = {-1,-1,-1}; 1185 1186 char * 1187 ns_print(struct sockaddr_ns *sns) 1188 { 1189 struct ns_addr work; 1190 union { union ns_net net_e; u_int32_t long_e; } net; 1191 u_short port; 1192 static char mybuf[50+MAXHOSTNAMELEN]; 1193 char cport[10], chost[25]; 1194 char *host = ""; 1195 u_char *q; 1196 1197 work = sns->sns_addr; 1198 port = ntohs(work.x_port); 1199 work.x_port = 0; 1200 net.net_e = work.x_net; 1201 if (ns_nullhost(work) && net.long_e == 0) { 1202 if (!port) 1203 return ("*.*"); 1204 (void) snprintf(mybuf, sizeof mybuf, "*.0x%x", port); 1205 return (mybuf); 1206 } 1207 1208 if (memcmp(ns_bh, work.x_host.c_host, 6) == 0) 1209 host = "any"; 1210 else if (memcmp(ns_nullh, work.x_host.c_host, 6) == 0) 1211 host = "*"; 1212 else { 1213 q = work.x_host.c_host; 1214 (void) snprintf(chost, sizeof chost, "0x%02x%02x%02x%02x%02x%02x", 1215 q[0], q[1], q[2], q[3], q[4], q[5]); 1216 host = chost; 1217 } 1218 if (port) 1219 (void) snprintf(cport, sizeof cport, ".0x%x", htons(port)); 1220 else 1221 *cport = '\0'; 1222 1223 (void) snprintf(mybuf, sizeof mybuf, "0x%x.%s%s", 1224 ntohl(net.long_e), host, cport); 1225 return (mybuf); 1226 } 1227 1228 short ipx_nullh[] = {0,0,0}; 1229 short ipx_bh[] = {-1,-1,-1}; 1230 1231 char * 1232 ipx_print(struct sockaddr_ipx *sipx) 1233 { 1234 struct ipx_addr work; 1235 union { union ipx_net net_e; u_int32_t long_e; } net; 1236 u_short port; 1237 static char mybuf[50+MAXHOSTNAMELEN], cport[10], chost[25]; 1238 char *host = ""; 1239 char *p; 1240 u_char *q; 1241 1242 work = sipx->sipx_addr; 1243 port = ntohs(work.ipx_port); 1244 work.ipx_port = 0; 1245 net.net_e = work.ipx_net; 1246 if (ipx_nullhost(work) && net.long_e == 0) { 1247 if (!port) 1248 return ("*.*"); 1249 (void) snprintf(mybuf, sizeof mybuf, "*.0x%XH", port); 1250 return (mybuf); 1251 } 1252 1253 if (memcmp(ipx_bh, work.ipx_host.c_host, 6) == 0) 1254 host = "any"; 1255 else if (memcmp(ipx_nullh, work.ipx_host.c_host, 6) == 0) 1256 host = "*"; 1257 else { 1258 q = work.ipx_host.c_host; 1259 (void) snprintf(chost, sizeof chost, "%02X%02X%02X%02X%02X%02XH", 1260 q[0], q[1], q[2], q[3], q[4], q[5]); 1261 for (p = chost; *p == '0' && p < chost + 12; p++) 1262 /* void */; 1263 host = p; 1264 } 1265 if (port) 1266 (void) snprintf(cport, sizeof cport, ".%XH", htons(port)); 1267 else 1268 *cport = 0; 1269 1270 (void) snprintf(mybuf, sizeof mybuf, "%XH.%s%s", 1271 ntohl(net.long_e), host, cport); 1272 return (mybuf); 1273 } 1274 1275 void 1276 interfaces(void) 1277 { 1278 size_t needed; 1279 int mib[6]; 1280 char *buf = NULL, *lim, *next; 1281 struct rt_msghdr *rtm; 1282 1283 mib[0] = CTL_NET; 1284 mib[1] = PF_ROUTE; 1285 mib[2] = 0; /* protocol */ 1286 mib[3] = 0; /* wildcard address family */ 1287 mib[4] = NET_RT_IFLIST; 1288 mib[5] = 0; /* no flags */ 1289 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 1290 quit("route-sysctl-estimate"); 1291 if (needed) { 1292 if ((buf = malloc(needed)) == NULL) 1293 quit("malloc"); 1294 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 1295 quit("actual retrieval of interface table"); 1296 lim = buf + needed; 1297 for (next = buf; next < lim; next += rtm->rtm_msglen) { 1298 rtm = (struct rt_msghdr *)next; 1299 print_rtmsg(rtm, rtm->rtm_msglen); 1300 } 1301 free(buf); 1302 } 1303 } 1304 1305 void 1306 monitor(void) 1307 { 1308 int n; 1309 char msg[2048]; 1310 1311 verbose = 1; 1312 if (debugonly) { 1313 interfaces(); 1314 exit(0); 1315 } 1316 for(;;) { 1317 time_t now; 1318 n = read(s, msg, 2048); 1319 now = time(NULL); 1320 (void) printf("got message of size %d on %s", n, ctime(&now)); 1321 print_rtmsg((struct rt_msghdr *)msg, n); 1322 } 1323 } 1324 1325 struct { 1326 struct rt_msghdr m_rtm; 1327 char m_space[512]; 1328 } m_rtmsg; 1329 1330 int 1331 rtmsg(int cmd, int flags) 1332 { 1333 static int seq; 1334 int rlen; 1335 char *cp = m_rtmsg.m_space; 1336 int l; 1337 1338 #define NEXTADDR(w, u) \ 1339 if (rtm_addrs & (w)) {\ 1340 l = ROUNDUP(u.sa.sa_len); memcpy(cp, &(u), l); cp += l;\ 1341 if (verbose) sodump(&(u),"u");\ 1342 } 1343 1344 errno = 0; 1345 memset(&m_rtmsg, 0, sizeof(m_rtmsg)); 1346 if (cmd == 'a') 1347 cmd = RTM_ADD; 1348 else if (cmd == 'c') 1349 cmd = RTM_CHANGE; 1350 else if (cmd == 'g') { 1351 cmd = RTM_GET; 1352 if (so_ifp.sa.sa_family == 0) { 1353 so_ifp.sa.sa_family = AF_LINK; 1354 so_ifp.sa.sa_len = sizeof(struct sockaddr_dl); 1355 rtm_addrs |= RTA_IFP; 1356 } 1357 } else 1358 cmd = RTM_DELETE; 1359 #define rtm m_rtmsg.m_rtm 1360 rtm.rtm_type = cmd; 1361 rtm.rtm_flags = flags; 1362 rtm.rtm_version = RTM_VERSION; 1363 rtm.rtm_seq = ++seq; 1364 rtm.rtm_addrs = rtm_addrs; 1365 rtm.rtm_rmx = rt_metrics; 1366 rtm.rtm_inits = rtm_inits; 1367 1368 if (rtm_addrs & RTA_NETMASK) 1369 mask_addr(); 1370 NEXTADDR(RTA_DST, so_dst); 1371 NEXTADDR(RTA_GATEWAY, so_gate); 1372 NEXTADDR(RTA_NETMASK, so_mask); 1373 NEXTADDR(RTA_GENMASK, so_genmask); 1374 NEXTADDR(RTA_IFP, so_ifp); 1375 NEXTADDR(RTA_IFA, so_ifa); 1376 rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 1377 if (verbose) 1378 print_rtmsg(&rtm, l); 1379 if (debugonly) 1380 return (0); 1381 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 1382 perror("writing to routing socket"); 1383 return (-1); 1384 } 1385 if (cmd == RTM_GET) { 1386 do { 1387 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 1388 } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); 1389 if (l < 0) 1390 (void) fprintf(stderr, 1391 "route: read from routing socket: %s\n", 1392 strerror(errno)); 1393 else 1394 print_getmsg(&rtm, l); 1395 } 1396 #undef rtm 1397 return (0); 1398 } 1399 1400 void 1401 mask_addr(void) 1402 { 1403 int olen = so_mask.sa.sa_len; 1404 char *cp1 = olen + (char *)&so_mask, *cp2; 1405 1406 for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; ) 1407 if (*--cp1 != 0) { 1408 so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask; 1409 break; 1410 } 1411 if ((rtm_addrs & RTA_DST) == 0) 1412 return; 1413 switch (so_dst.sa.sa_family) { 1414 case AF_NS: 1415 case AF_IPX: 1416 case AF_INET: 1417 #ifdef INET6 1418 case AF_INET6: 1419 #endif 1420 case AF_CCITT: 1421 case 0: 1422 return; 1423 case AF_ISO: 1424 olen = MIN(so_dst.siso.siso_nlen, 1425 MAX(so_mask.sa.sa_len - 6, 0)); 1426 break; 1427 } 1428 cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst; 1429 cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst; 1430 while (cp2 > cp1) 1431 *--cp2 = 0; 1432 cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask; 1433 while (cp1 > so_dst.sa.sa_data) 1434 *--cp1 &= *--cp2; 1435 switch (so_dst.sa.sa_family) { 1436 case AF_ISO: 1437 so_dst.siso.siso_nlen = olen; 1438 break; 1439 } 1440 } 1441 1442 char *msgtypes[] = { 1443 "", 1444 "RTM_ADD: Add Route", 1445 "RTM_DELETE: Delete Route", 1446 "RTM_CHANGE: Change Metrics or flags", 1447 "RTM_GET: Report Metrics", 1448 "RTM_LOSING: Kernel Suspects Partitioning", 1449 "RTM_REDIRECT: Told to use different route", 1450 "RTM_MISS: Lookup failed on this address", 1451 "RTM_LOCK: fix specified metrics", 1452 "RTM_OLDADD: caused by SIOCADDRT", 1453 "RTM_OLDDEL: caused by SIOCDELRT", 1454 "RTM_RESOLVE: Route created by cloning", 1455 "RTM_NEWADDR: address being added to iface", 1456 "RTM_DELADDR: address being removed from iface", 1457 "RTM_IFINFO: iface status change", 1458 0, 1459 }; 1460 1461 char metricnames[] = 1462 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu"; 1463 char routeflags[] = 1464 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE\013LLINFO\014STATIC\017PROTO2\020PROTO1"; 1465 char ifnetflags[] = 1466 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2\020MULTICAST"; 1467 char addrnames[] = 1468 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD"; 1469 1470 void 1471 print_rtmsg(struct rt_msghdr *rtm, int msglen) 1472 { 1473 struct if_msghdr *ifm; 1474 struct ifa_msghdr *ifam; 1475 1476 if (verbose == 0) 1477 return; 1478 if (rtm->rtm_version != RTM_VERSION) { 1479 (void) printf("routing message version %d not understood\n", 1480 rtm->rtm_version); 1481 return; 1482 } 1483 (void)printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen); 1484 switch (rtm->rtm_type) { 1485 case RTM_IFINFO: 1486 ifm = (struct if_msghdr *)rtm; 1487 (void) printf("if# %d, flags:", ifm->ifm_index); 1488 bprintf(stdout, ifm->ifm_flags, ifnetflags); 1489 pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs); 1490 break; 1491 case RTM_NEWADDR: 1492 case RTM_DELADDR: 1493 ifam = (struct ifa_msghdr *)rtm; 1494 (void) printf("metric %d, flags:", ifam->ifam_metric); 1495 bprintf(stdout, ifam->ifam_flags, routeflags); 1496 pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs); 1497 break; 1498 default: 1499 (void) printf("pid: %ld, seq %d, errno %d, flags:", 1500 (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 1501 bprintf(stdout, rtm->rtm_flags, routeflags); 1502 pmsg_common(rtm); 1503 } 1504 } 1505 1506 void 1507 print_getmsg(struct rt_msghdr *rtm, int msglen) 1508 { 1509 struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL; 1510 struct sockaddr_dl *ifp = NULL; 1511 struct sockaddr *sa; 1512 char *cp; 1513 int i; 1514 1515 (void) printf(" route to: %s\n", routename(&so_dst.sa)); 1516 if (rtm->rtm_version != RTM_VERSION) { 1517 (void)fprintf(stderr, 1518 "routing message version %d not understood\n", 1519 rtm->rtm_version); 1520 return; 1521 } 1522 if (rtm->rtm_msglen > msglen) { 1523 (void)fprintf(stderr, 1524 "message length mismatch, in packet %d, returned %d\n", 1525 rtm->rtm_msglen, msglen); 1526 } 1527 if (rtm->rtm_errno) { 1528 (void) fprintf(stderr, "RTM_GET: %s (errno %d)\n", 1529 strerror(rtm->rtm_errno), rtm->rtm_errno); 1530 return; 1531 } 1532 cp = ((char *)(rtm + 1)); 1533 if (rtm->rtm_addrs) 1534 for (i = 1; i; i <<= 1) 1535 if (i & rtm->rtm_addrs) { 1536 sa = (struct sockaddr *)cp; 1537 switch (i) { 1538 case RTA_DST: 1539 dst = sa; 1540 break; 1541 case RTA_GATEWAY: 1542 gate = sa; 1543 break; 1544 case RTA_NETMASK: 1545 mask = sa; 1546 break; 1547 case RTA_IFP: 1548 if (sa->sa_family == AF_LINK && 1549 ((struct sockaddr_dl *)sa)->sdl_nlen) 1550 ifp = (struct sockaddr_dl *)sa; 1551 break; 1552 } 1553 ADVANCE(cp, sa); 1554 } 1555 if (dst && mask) 1556 mask->sa_family = dst->sa_family; /* XXX */ 1557 if (dst) 1558 (void)printf("destination: %s\n", routename(dst)); 1559 if (mask) { 1560 int savenflag = nflag; 1561 1562 nflag = 1; 1563 (void)printf(" mask: %s\n", routename(mask)); 1564 nflag = savenflag; 1565 } 1566 if (gate && rtm->rtm_flags & RTF_GATEWAY) 1567 (void)printf(" gateway: %s\n", routename(gate)); 1568 if (ifp) 1569 (void)printf(" interface: %.*s\n", 1570 ifp->sdl_nlen, ifp->sdl_data); 1571 (void)printf(" flags: "); 1572 bprintf(stdout, rtm->rtm_flags, routeflags); 1573 1574 #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') 1575 #define msec(u) (((u) + 500) / 1000) /* usec to msec */ 1576 1577 (void) printf("\n%s\n", "\ 1578 recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire"); 1579 printf("%8d%c ", (int)rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); 1580 printf("%8d%c ", (int)rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); 1581 printf("%8d%c ", (int)rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); 1582 printf("%8d%c ", (int)msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); 1583 printf("%8d%c ", (int)msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR)); 1584 printf("%8d%c ", (int)rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT)); 1585 printf("%8d%c ", (int)rtm->rtm_rmx.rmx_mtu, lock(MTU)); 1586 if (rtm->rtm_rmx.rmx_expire) 1587 rtm->rtm_rmx.rmx_expire -= time(0); 1588 printf("%8d%c\n", (int)rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); 1589 #undef lock 1590 #undef msec 1591 #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD) 1592 if (verbose) 1593 pmsg_common(rtm); 1594 else if (rtm->rtm_addrs &~ RTA_IGN) { 1595 (void) printf("sockaddrs: "); 1596 bprintf(stdout, rtm->rtm_addrs, addrnames); 1597 putchar('\n'); 1598 } 1599 #undef RTA_IGN 1600 } 1601 1602 void 1603 pmsg_common(struct rt_msghdr *rtm) 1604 { 1605 (void) printf("\nlocks: "); 1606 bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames); 1607 (void) printf(" inits: "); 1608 bprintf(stdout, rtm->rtm_inits, metricnames); 1609 pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs); 1610 } 1611 1612 void 1613 pmsg_addrs(char *cp, int addrs) 1614 { 1615 struct sockaddr *sa; 1616 int i; 1617 1618 if (addrs == 0) 1619 return; 1620 (void) printf("\nsockaddrs: "); 1621 bprintf(stdout, addrs, addrnames); 1622 (void) putchar('\n'); 1623 for (i = 1; i; i <<= 1) 1624 if (i & addrs) { 1625 sa = (struct sockaddr *)cp; 1626 (void) printf(" %s", routename(sa)); 1627 ADVANCE(cp, sa); 1628 } 1629 (void) putchar('\n'); 1630 (void) fflush(stdout); 1631 } 1632 1633 void 1634 bprintf(FILE *fp, int b, u_char *s) 1635 { 1636 int i; 1637 int gotsome = 0; 1638 1639 if (b == 0) 1640 return; 1641 while ((i = *s++)) { 1642 if ((b & (1 << (i-1)))) { 1643 if (gotsome == 0) 1644 i = '<'; 1645 else 1646 i = ','; 1647 (void) putc(i, fp); 1648 gotsome = 1; 1649 for (; (i = *s) > 32; s++) 1650 (void) putc(i, fp); 1651 } else 1652 while (*s > 32) 1653 s++; 1654 } 1655 if (gotsome) 1656 (void) putc('>', fp); 1657 } 1658 1659 int 1660 keyword(char *cp) 1661 { 1662 struct keytab *kt = keywords; 1663 1664 while (kt->kt_cp && strcmp(kt->kt_cp, cp)) 1665 kt++; 1666 return (kt->kt_i); 1667 } 1668 1669 void 1670 sodump(sup su, char *which) 1671 { 1672 #ifdef INET6 1673 char ntop_buf[NI_MAXHOST]; /*for inet_ntop()*/ 1674 #endif 1675 1676 switch (su->sa.sa_family) { 1677 case AF_LINK: 1678 (void) printf("%s: link %s; ", 1679 which, link_ntoa(&su->sdl)); 1680 break; 1681 case AF_ISO: 1682 (void) printf("%s: iso %s; ", 1683 which, iso_ntoa(&su->siso.siso_addr)); 1684 break; 1685 case AF_INET: 1686 (void) printf("%s: inet %s; ", 1687 which, inet_ntoa(su->sin.sin_addr)); 1688 break; 1689 #ifdef INET6 1690 case AF_INET6: 1691 (void) printf("%s: inet6 %s; ", 1692 which, inet_ntop(AF_INET6, &su->sin6.sin6_addr, 1693 ntop_buf, sizeof(ntop_buf))); 1694 break; 1695 #endif 1696 case AF_NS: 1697 (void) printf("%s: xns %s; ", 1698 which, ns_ntoa(su->sns.sns_addr)); 1699 break; 1700 case AF_IPX: 1701 (void) printf("%s: ipx %s; ", 1702 which, ipx_ntoa(su->sipx.sipx_addr)); 1703 break; 1704 } 1705 (void) fflush(stdout); 1706 } 1707 1708 /* States*/ 1709 #define VIRGIN 0 1710 #define GOTONE 1 1711 #define GOTTWO 2 1712 /* Inputs */ 1713 #define DIGIT (4*0) 1714 #define END (4*1) 1715 #define DELIM (4*2) 1716 1717 void 1718 sockaddr(char *addr, struct sockaddr *sa) 1719 { 1720 char *cp = (char *)sa; 1721 int size = sa->sa_len; 1722 char *cplim = cp + size; 1723 int byte = 0, state = VIRGIN, new = 0; 1724 1725 memset(cp, 0, size); 1726 cp++; 1727 do { 1728 if ((*addr >= '0') && (*addr <= '9')) { 1729 new = *addr - '0'; 1730 } else if ((*addr >= 'a') && (*addr <= 'f')) { 1731 new = *addr - 'a' + 10; 1732 } else if ((*addr >= 'A') && (*addr <= 'F')) { 1733 new = *addr - 'A' + 10; 1734 } else if (*addr == 0) 1735 state |= END; 1736 else 1737 state |= DELIM; 1738 addr++; 1739 switch (state /* | INPUT */) { 1740 case GOTTWO | DIGIT: 1741 *cp++ = byte; /*FALLTHROUGH*/ 1742 case VIRGIN | DIGIT: 1743 state = GOTONE; byte = new; continue; 1744 case GOTONE | DIGIT: 1745 state = GOTTWO; byte = new + (byte << 4); continue; 1746 default: /* | DELIM */ 1747 state = VIRGIN; *cp++ = byte; byte = 0; continue; 1748 case GOTONE | END: 1749 case GOTTWO | END: 1750 *cp++ = byte; /* FALLTHROUGH */ 1751 case VIRGIN | END: 1752 break; 1753 } 1754 break; 1755 } while (cp < cplim); 1756 sa->sa_len = cp - (char *)sa; 1757 } 1758