1 /* 2 * 3 * Copyright (c) 1983, 1989, 1991 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 char copyright[] = 11 "@(#) Copyright (c) 1983, 1989, 1991 The Regents of the University of California.\n\ 12 All rights reserved.\n"; 13 #endif /* not lint */ 14 15 #ifndef lint 16 static char sccsid[] = "@(#)route.c 5.44 (Berkeley) 02/20/92"; 17 #endif /* not lint */ 18 19 #include <sys/param.h> 20 #include <sys/file.h> 21 #include <sys/socket.h> 22 #include <sys/ioctl.h> 23 #include <sys/mbuf.h> 24 #include <sys/kinfo.h> 25 26 #include <net/if.h> 27 #include <net/route.h> 28 #include <net/if_dl.h> 29 #include <netinet/in.h> 30 #include <netns/ns.h> 31 #include <netiso/iso.h> 32 #include <netccitt/x25.h> 33 #include <arpa/inet.h> 34 #include <netdb.h> 35 36 #include <errno.h> 37 #include <unistd.h> 38 #include <stdio.h> 39 #include <ctype.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <paths.h> 43 44 struct keytab { 45 char *kt_cp; 46 int kt_i; 47 } keywords[] = { 48 #include "keywords.h" 49 {0, 0} 50 }; 51 52 struct ortentry route; 53 union sockunion { 54 struct sockaddr sa; 55 struct sockaddr_in sin; 56 struct sockaddr_ns sns; 57 struct sockaddr_iso siso; 58 struct sockaddr_dl sdl; 59 struct sockaddr_x25 sx25; 60 } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp; 61 62 typedef union sockunion *sup; 63 int pid, rtm_addrs, uid; 64 int s; 65 int forcehost, forcenet, doflush, nflag, af, qflag, tflag, keyword(); 66 int iflag, verbose, aflen = sizeof (struct sockaddr_in); 67 int locking, lockrest, debugonly; 68 struct sockaddr_in sin = { sizeof(sin), AF_INET }; 69 struct rt_metrics rt_metrics; 70 u_long rtm_inits; 71 struct in_addr inet_makeaddr(); 72 char *routename(), *netname(); 73 void flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf(); 74 void print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(); 75 int getaddr(), rtmsg(), x25_makemask(); 76 extern char *inet_ntoa(), *iso_ntoa(), *link_ntoa(); 77 78 void 79 usage(cp) 80 char *cp; 81 { 82 if (cp) 83 (void) fprintf(stderr, "route: botched keyword: %s\n", cp); 84 (void) fprintf(stderr, 85 "usage: route [ -nqv ] cmd [[ -<qualifers> ] args ]\n"); 86 exit(1); 87 /* NOTREACHED */ 88 } 89 90 void 91 quit(s) 92 char *s; 93 { 94 int sverrno = errno; 95 96 (void) fprintf(stderr, "route: "); 97 if (s) 98 (void) fprintf(stderr, "%s: ", s); 99 (void) fprintf(stderr, "%s\n", strerror(sverrno)); 100 exit(1); 101 /* NOTREACHED */ 102 } 103 104 #define ROUNDUP(a) \ 105 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 106 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 107 108 main(argc, argv) 109 int argc; 110 char **argv; 111 { 112 extern int optind; 113 int ch; 114 char *argvp; 115 116 if (argc < 2) 117 usage((char *)NULL); 118 119 while ((ch = getopt(argc, argv, "nqdtv")) != EOF) 120 switch(ch) { 121 case 'n': 122 nflag = 1; 123 break; 124 case 'q': 125 qflag = 1; 126 break; 127 case 'v': 128 verbose = 1; 129 break; 130 case 't': 131 tflag = 1; 132 break; 133 case 'd': 134 debugonly = 1; 135 break; 136 case '?': 137 default: 138 usage(); 139 } 140 argc -= optind; 141 argv += optind; 142 143 pid = getpid(); 144 uid = getuid(); 145 if (tflag) 146 s = open("/dev/null", O_WRONLY, 0); 147 else 148 s = socket(PF_ROUTE, SOCK_RAW, 0); 149 if (s < 0) 150 quit("socket"); 151 if (*argv) 152 switch (keyword(*argv)) { 153 case K_GET: 154 uid = 0; 155 /* FALLTHROUGH */ 156 157 case K_CHANGE: 158 case K_ADD: 159 case K_DELETE: 160 newroute(argc, argv); 161 exit(0); 162 /* NOTREACHED */ 163 164 case K_MONITOR: 165 monitor(); 166 /* NOTREACHED */ 167 168 case K_FLUSH: 169 flushroutes(argc, argv); 170 exit(0); 171 /* NOTREACHED */ 172 } 173 usage(*argv); 174 /* NOTREACHED */ 175 } 176 177 /* 178 * Purge all entries in the routing tables not 179 * associated with network interfaces. 180 */ 181 void 182 flushroutes(argc, argv) 183 int argc; 184 char *argv[]; 185 { 186 int needed, seqno, rlen; 187 char *buf, *next, *lim; 188 register struct rt_msghdr *rtm; 189 190 if (uid) 191 quit("must be root to alter routing table"); 192 shutdown(s, 0); /* Don't want to read back our messages */ 193 if (argc > 1) { 194 argv++; 195 if (argc == 2 && **argv == '-') 196 switch (keyword(*argv + 1)) { 197 case K_INET: 198 af = AF_INET; 199 break; 200 case K_XNS: 201 af = AF_NS; 202 break; 203 case K_LINK: 204 af = AF_LINK; 205 break; 206 case K_ISO: 207 case K_OSI: 208 af = AF_ISO; 209 break; 210 case K_X25: 211 af = AF_CCITT; 212 default: 213 goto bad; 214 } else 215 bad: usage(*argv); 216 } 217 if ((needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0)) < 0) 218 quit("route-getkerninfo-estimate"); 219 if ((buf = malloc(needed)) == NULL) 220 quit("malloc"); 221 if ((rlen = getkerninfo(KINFO_RT_DUMP, buf, &needed, 0)) < 0) 222 quit("actual retrieval of routing table"); 223 lim = buf + rlen; 224 if (verbose) 225 (void) printf("Examining routing table from getkerninfo\n"); 226 seqno = 0; /* ??? */ 227 for (next = buf; next < lim; next += rtm->rtm_msglen) { 228 rtm = (struct rt_msghdr *)next; 229 if (verbose) 230 print_rtmsg(rtm, rtm->rtm_msglen); 231 if ((rtm->rtm_flags & RTF_GATEWAY) == 0) 232 continue; 233 if (af) { 234 struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 235 236 if (sa->sa_family != af) 237 continue; 238 } 239 if (debugonly) 240 continue; 241 rtm->rtm_type = RTM_DELETE; 242 rtm->rtm_seq = seqno; 243 rlen = write(s, next, rtm->rtm_msglen); 244 if (rlen < (int)rtm->rtm_msglen) { 245 (void) fprintf(stderr, 246 "route: write to routing socket: %s\n", 247 strerror(errno)); 248 (void) printf("got only %d for rlen\n", rlen); 249 break; 250 } 251 seqno++; 252 if (qflag) 253 continue; 254 if (verbose) 255 print_rtmsg(rtm, rlen); 256 else { 257 struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 258 (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ? 259 routename(sa) : netname(sa)); 260 sa = (struct sockaddr *)(sa->sa_len + (char *)sa); 261 (void) printf("%-20.20s ", routename(sa)); 262 (void) printf("done\n"); 263 } 264 } 265 } 266 267 char * 268 routename(sa) 269 struct sockaddr *sa; 270 { 271 register char *cp; 272 static char line[50]; 273 struct hostent *hp; 274 static char domain[MAXHOSTNAMELEN + 1]; 275 static int first = 1; 276 char *ns_print(); 277 278 if (first) { 279 first = 0; 280 if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 281 (cp = index(domain, '.'))) 282 (void) strcpy(domain, cp + 1); 283 else 284 domain[0] = 0; 285 } 286 287 if (sa->sa_len == 0) 288 strcpy(line, "default"); 289 else switch (sa->sa_family) { 290 291 case AF_INET: 292 { struct in_addr in; 293 in = ((struct sockaddr_in *)sa)->sin_addr; 294 295 cp = 0; 296 if (in.s_addr == INADDR_ANY || sa->sa_len < 4) 297 cp = "default"; 298 if (cp == 0 && !nflag) { 299 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 300 AF_INET); 301 if (hp) { 302 if ((cp = index(hp->h_name, '.')) && 303 !strcmp(cp + 1, domain)) 304 *cp = 0; 305 cp = hp->h_name; 306 } 307 } 308 if (cp) 309 strcpy(line, cp); 310 else { 311 #define C(x) ((x) & 0xff) 312 in.s_addr = ntohl(in.s_addr); 313 (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 314 C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr)); 315 } 316 break; 317 } 318 319 case AF_NS: 320 return (ns_print((struct sockaddr_ns *)sa)); 321 322 case AF_LINK: 323 return (link_ntoa((struct sockaddr_dl *)sa)); 324 325 case AF_ISO: 326 (void) sprintf(line, "iso %s", 327 iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr)); 328 break; 329 330 default: 331 { u_short *s = (u_short *)sa; 332 u_short *slim = s + ((sa->sa_len + 1) >> 1); 333 char *cp = line + sprintf(line, "(%d)", sa->sa_family); 334 335 while (++s < slim) /* start with sa->sa_data */ 336 cp += sprintf(cp, " %x", *s); 337 break; 338 } 339 } 340 return (line); 341 } 342 343 /* 344 * Return the name of the network whose address is given. 345 * The address is assumed to be that of a net or subnet, not a host. 346 */ 347 char * 348 netname(sa) 349 struct sockaddr *sa; 350 { 351 char *cp = 0; 352 static char line[50]; 353 struct netent *np = 0; 354 u_long net, mask; 355 register u_long i; 356 int subnetshift; 357 char *ns_print(); 358 359 switch (sa->sa_family) { 360 361 case AF_INET: 362 { struct in_addr in; 363 in = ((struct sockaddr_in *)sa)->sin_addr; 364 365 i = in.s_addr = ntohl(in.s_addr); 366 if (in.s_addr == 0) 367 cp = "default"; 368 else if (!nflag) { 369 if (IN_CLASSA(i)) { 370 mask = IN_CLASSA_NET; 371 subnetshift = 8; 372 } else if (IN_CLASSB(i)) { 373 mask = IN_CLASSB_NET; 374 subnetshift = 8; 375 } else { 376 mask = IN_CLASSC_NET; 377 subnetshift = 4; 378 } 379 /* 380 * If there are more bits than the standard mask 381 * would suggest, subnets must be in use. 382 * Guess at the subnet mask, assuming reasonable 383 * width subnet fields. 384 */ 385 while (in.s_addr &~ mask) 386 mask = (long)mask >> subnetshift; 387 net = in.s_addr & mask; 388 while ((mask & 1) == 0) 389 mask >>= 1, net >>= 1; 390 np = getnetbyaddr(net, AF_INET); 391 if (np) 392 cp = np->n_name; 393 } 394 if (cp) 395 strcpy(line, cp); 396 else if ((in.s_addr & 0xffffff) == 0) 397 (void) sprintf(line, "%u", C(in.s_addr >> 24)); 398 else if ((in.s_addr & 0xffff) == 0) 399 (void) sprintf(line, "%u.%u", C(in.s_addr >> 24), 400 C(in.s_addr >> 16)); 401 else if ((in.s_addr & 0xff) == 0) 402 (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24), 403 C(in.s_addr >> 16), C(in.s_addr >> 8)); 404 else 405 (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 406 C(in.s_addr >> 16), C(in.s_addr >> 8), 407 C(in.s_addr)); 408 break; 409 } 410 411 case AF_NS: 412 return (ns_print((struct sockaddr_ns *)sa)); 413 break; 414 415 case AF_LINK: 416 return (link_ntoa((struct sockaddr_dl *)sa)); 417 418 case AF_ISO: 419 (void) sprintf(line, "iso %s", 420 iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr)); 421 break; 422 423 default: 424 { u_short *s = (u_short *)sa->sa_data; 425 u_short *slim = s + ((sa->sa_len + 1)>>1); 426 char *cp = line + sprintf(line, "af %d:", sa->sa_family); 427 428 while (s < slim) 429 cp += sprintf(cp, " %x", *s++); 430 break; 431 } 432 } 433 return (line); 434 } 435 436 void 437 set_metric(value, key) 438 char *value; 439 int key; 440 { 441 int flag = 0; 442 u_long noval, *valp = &noval; 443 444 switch (key) { 445 #define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break 446 caseof(K_MTU, RTV_MTU, rmx_mtu); 447 caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); 448 caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); 449 caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); 450 caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); 451 caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); 452 caseof(K_RTT, RTV_RTT, rmx_rtt); 453 caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); 454 } 455 rtm_inits |= flag; 456 if (lockrest || locking) 457 rt_metrics.rmx_locks |= flag; 458 if (locking) 459 locking = 0; 460 *valp = atoi(value); 461 } 462 463 void 464 newroute(argc, argv) 465 int argc; 466 register char **argv; 467 { 468 char *cmd, *dest = "", *gateway = "", *err; 469 int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC; 470 int key; 471 struct hostent *hp = 0; 472 473 if (uid) 474 quit("must be root to alter routing table"); 475 cmd = argv[0]; 476 if (*cmd != 'g') 477 shutdown(s, 0); /* Don't want to read back our messages */ 478 while (--argc > 0) { 479 if (**(++argv)== '-') { 480 switch (key = keyword(1 + *argv)) { 481 case K_LINK: 482 af = AF_LINK; 483 aflen = sizeof(struct sockaddr_dl); 484 break; 485 case K_OSI: 486 case K_ISO: 487 af = AF_ISO; 488 aflen = sizeof(struct sockaddr_iso); 489 break; 490 case K_INET: 491 af = AF_INET; 492 aflen = sizeof(struct sockaddr_in); 493 break; 494 case K_X25: 495 af = AF_CCITT; 496 aflen = sizeof(struct sockaddr_x25); 497 break; 498 case K_SA: 499 af = PF_ROUTE; 500 aflen = sizeof(union sockunion); 501 break; 502 case K_XNS: 503 af = AF_NS; 504 aflen = sizeof(struct sockaddr_ns); 505 break; 506 case K_IFACE: 507 case K_INTERFACE: 508 iflag++; 509 case K_NOSTATIC: 510 flags &= ~RTF_STATIC; 511 break; 512 case K_LOCK: 513 locking = 1; 514 break; 515 case K_LOCKREST: 516 lockrest = 1; 517 break; 518 case K_HOST: 519 forcehost++; 520 break; 521 case K_REJECT: 522 flags |= RTF_REJECT; 523 break; 524 case K_PROTO1: 525 flags |= RTF_PROTO1; 526 break; 527 case K_PROTO2: 528 flags |= RTF_PROTO2; 529 break; 530 case K_CLONING: 531 flags |= RTF_CLONING; 532 break; 533 case K_XRESOLVE: 534 flags |= RTF_XRESOLVE; 535 break; 536 case K_STATIC: 537 flags |= RTF_STATIC; 538 break; 539 case K_IFA: 540 argc--; 541 (void) getaddr(RTA_IFA, *++argv, 0); 542 break; 543 case K_IFP: 544 argc--; 545 (void) getaddr(RTA_IFP, *++argv, 0); 546 break; 547 case K_GENMASK: 548 argc--; 549 (void) getaddr(RTA_GENMASK, *++argv, 0); 550 break; 551 case K_GATEWAY: 552 argc--; 553 (void) getaddr(RTA_GATEWAY, *++argv, 0); 554 break; 555 case K_DST: 556 argc--; 557 ishost = getaddr(RTA_DST, *++argv, &hp); 558 dest = *argv; 559 break; 560 case K_NETMASK: 561 argc--; 562 (void) getaddr(RTA_NETMASK, *++argv, 0); 563 /* FALLTHROUGH */ 564 case K_NET: 565 forcenet++; 566 break; 567 case K_MTU: 568 case K_HOPCOUNT: 569 case K_EXPIRE: 570 case K_RECVPIPE: 571 case K_SENDPIPE: 572 case K_SSTHRESH: 573 case K_RTT: 574 case K_RTTVAR: 575 argc--; 576 set_metric(*++argv, key); 577 break; 578 default: 579 usage(1+*argv); 580 } 581 } else { 582 if ((rtm_addrs & RTA_DST) == 0) { 583 dest = *argv; 584 ishost = getaddr(RTA_DST, *argv, &hp); 585 } else if ((rtm_addrs & RTA_GATEWAY) == 0) { 586 gateway = *argv; 587 (void) getaddr(RTA_GATEWAY, *argv, &hp); 588 } else { 589 int ret = atoi(*argv); 590 591 if (ret == 0) { 592 if (strcmp(*argv, "0") == 0) 593 printf("%s,%s", 594 "old usage of trailing 0", 595 "assuming route to if\n"); 596 else 597 usage(NULL); 598 iflag = 1; 599 continue; 600 } else if (ret > 0 && ret < 10) { 601 printf("old usage of trailing digit, "); 602 printf("assuming route via gateway\n"); 603 iflag = 0; 604 continue; 605 } 606 (void) getaddr(RTA_NETMASK, *argv, 0); 607 } 608 } 609 } 610 if (forcehost) 611 ishost = 1; 612 if (forcenet) 613 ishost = 0; 614 flags |= RTF_UP; 615 if (ishost) 616 flags |= RTF_HOST; 617 if (iflag == 0) 618 flags |= RTF_GATEWAY; 619 for (attempts = 1; ; attempts++) { 620 errno = 0; 621 if ((ret = rtmsg(*cmd, flags)) == 0) 622 break; 623 if (errno != ENETUNREACH && errno != ESRCH) 624 break; 625 if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) { 626 hp->h_addr_list++; 627 bcopy(hp->h_addr_list[0], &so_gate.sin.sin_addr, 628 hp->h_length); 629 } else 630 break; 631 } 632 if (*cmd == 'g') 633 exit(0); 634 oerrno = errno; 635 (void) printf("%s %s %s", cmd, ishost? "host" : "net", dest); 636 if (*gateway) { 637 (void) printf(": gateway %s", gateway); 638 if (attempts > 1 && ret == 0 && af == AF_INET) 639 (void) printf(" (%s)", 640 inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr)); 641 } 642 if (ret == 0) 643 (void) printf("\n"); 644 else { 645 switch (oerrno) { 646 case ESRCH: 647 err = "not in table"; 648 break; 649 case EBUSY: 650 err = "entry in use"; 651 break; 652 case ENOBUFS: 653 err = "routing table overflow"; 654 break; 655 default: 656 err = strerror(oerrno); 657 break; 658 } 659 (void) printf(": %s\n", err); 660 } 661 } 662 663 void 664 inet_makenetandmask(net, sin) 665 u_long net; 666 register struct sockaddr_in *sin; 667 { 668 u_long addr, mask = 0; 669 register char *cp; 670 671 rtm_addrs |= RTA_NETMASK; 672 if (net == 0) 673 mask = addr = 0; 674 else if (net < 128) { 675 addr = net << IN_CLASSA_NSHIFT; 676 mask = IN_CLASSA_NET; 677 } else if (net < 65536) { 678 addr = net << IN_CLASSB_NSHIFT; 679 mask = IN_CLASSB_NET; 680 } else if (net < 16777216L) { 681 addr = net << IN_CLASSC_NSHIFT; 682 mask = IN_CLASSC_NET; 683 } else { 684 addr = net; 685 if ((addr & IN_CLASSA_HOST) == 0) 686 mask = IN_CLASSA_NET; 687 else if ((addr & IN_CLASSB_HOST) == 0) 688 mask = IN_CLASSB_NET; 689 else if ((addr & IN_CLASSC_HOST) == 0) 690 mask = IN_CLASSC_NET; 691 else 692 mask = -1; 693 } 694 sin->sin_addr.s_addr = htonl(addr); 695 sin = &so_mask.sin; 696 sin->sin_addr.s_addr = htonl(mask); 697 sin->sin_len = 0; 698 sin->sin_family = 0; 699 cp = (char *)(&sin->sin_addr + 1); 700 while (*--cp == 0 && cp > (char *)sin) 701 ; 702 sin->sin_len = 1 + cp - (char *)sin; 703 } 704 705 /* 706 * Interpret an argument as a network address of some kind, 707 * returning 1 if a host address, 0 if a network address. 708 */ 709 int 710 getaddr(which, s, hpp) 711 int which; 712 char *s; 713 struct hostent **hpp; 714 { 715 register sup su; 716 struct ns_addr ns_addr(); 717 struct iso_addr *iso_addr(); 718 struct hostent *hp; 719 struct netent *np; 720 u_long val; 721 722 if (af == 0) { 723 af = AF_INET; 724 aflen = sizeof(struct sockaddr_in); 725 } 726 rtm_addrs |= which; 727 switch (which) { 728 case RTA_DST: 729 su = &so_dst; 730 su->sa.sa_family = af; 731 break; 732 case RTA_GATEWAY: 733 su = &so_gate; 734 su->sa.sa_family = af; 735 break; 736 case RTA_NETMASK: 737 su = &so_mask; 738 break; 739 case RTA_GENMASK: 740 su = &so_genmask; 741 break; 742 case RTA_IFP: 743 su = &so_ifp; 744 su->sa.sa_family = af; 745 break; 746 case RTA_IFA: 747 su = &so_ifa; 748 su->sa.sa_family = af; 749 break; 750 default: 751 usage("Internal Error"); 752 /*NOTREACHED*/ 753 } 754 su->sa.sa_len = aflen; 755 if (strcmp(s, "default") == 0) { 756 switch (which) { 757 case RTA_DST: 758 forcenet++; 759 (void) getaddr(RTA_NETMASK, s, 0); 760 break; 761 case RTA_NETMASK: 762 case RTA_GENMASK: 763 su->sa.sa_len = 0; 764 } 765 return (0); 766 } 767 switch (af) { 768 case AF_NS: 769 if (which == RTA_DST) { 770 extern short ns_bh[3]; 771 struct sockaddr_ns *sms = &(so_mask.sns); 772 bzero((char *)sms, sizeof(*sms)); 773 sms->sns_family = 0; 774 sms->sns_len = 6; 775 sms->sns_addr.x_net = *(union ns_net *)ns_bh; 776 rtm_addrs |= RTA_NETMASK; 777 } 778 su->sns.sns_addr = ns_addr(s); 779 return (!ns_nullhost(su->sns.sns_addr)); 780 781 case AF_OSI: 782 su->siso.siso_addr = *iso_addr(s); 783 if (which == RTA_NETMASK || which == RTA_GENMASK) { 784 register char *cp = (char *)TSEL(&su->siso); 785 su->siso.siso_nlen = 0; 786 do {--cp ;} while ((cp > (char *)su) && (*cp == 0)); 787 su->siso.siso_len = 1 + cp - (char *)su; 788 } 789 return (1); 790 791 case AF_LINK: 792 link_addr(s, &su->sdl); 793 return (1); 794 795 case AF_CCITT: 796 ccitt_addr(s, &su->sx25); 797 return (which == RTA_DST ? x25_makemask() : 1); 798 799 case PF_ROUTE: 800 su->sa.sa_len = sizeof(*su); 801 sockaddr(s, &su->sa); 802 return (1); 803 804 case AF_INET: 805 default: 806 break; 807 } 808 809 if (hpp == NULL) 810 hpp = &hp; 811 *hpp = NULL; 812 if (((val = inet_addr(s)) != -1) && 813 (which != RTA_DST || forcenet == 0)) { 814 su->sin.sin_addr.s_addr = val; 815 if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY) 816 return (1); 817 else { 818 val = ntohl(val); 819 goto netdone; 820 } 821 } 822 if ((val = inet_network(s)) != -1 || 823 ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0)) { 824 netdone: 825 if (which == RTA_DST) 826 inet_makenetandmask(val, &su->sin); 827 return (0); 828 } 829 hp = gethostbyname(s); 830 if (hp) { 831 *hpp = hp; 832 su->sin.sin_family = hp->h_addrtype; 833 bcopy(hp->h_addr, (char *)&su->sin.sin_addr, hp->h_length); 834 return (1); 835 } 836 (void) fprintf(stderr, "%s: bad value\n", s); 837 exit(1); 838 } 839 840 x25_makemask() 841 { 842 register char *cp; 843 844 if ((rtm_addrs & RTA_NETMASK) == 0) { 845 rtm_addrs |= RTA_NETMASK; 846 for (cp = (char *)&so_mask.sx25.x25_net; 847 cp < &so_mask.sx25.x25_opts.op_flags; cp++) 848 *cp = -1; 849 so_mask.sx25.x25_len = (u_char)&(((sup)0)->sx25.x25_opts); 850 } 851 return 0; 852 } 853 854 short ns_nullh[] = {0,0,0}; 855 short ns_bh[] = {-1,-1,-1}; 856 857 char * 858 ns_print(sns) 859 struct sockaddr_ns *sns; 860 { 861 struct ns_addr work; 862 union { union ns_net net_e; u_long long_e; } net; 863 u_short port; 864 static char mybuf[50], cport[10], chost[25]; 865 char *host = ""; 866 register char *p; 867 register u_char *q; 868 869 work = sns->sns_addr; 870 port = ntohs(work.x_port); 871 work.x_port = 0; 872 net.net_e = work.x_net; 873 if (ns_nullhost(work) && net.long_e == 0) { 874 if (!port) 875 return ("*.*"); 876 (void) sprintf(mybuf, "*.%XH", port); 877 return (mybuf); 878 } 879 880 if (bcmp((char *)ns_bh, (char *)work.x_host.c_host, 6) == 0) 881 host = "any"; 882 else if (bcmp((char *)ns_nullh, (char *)work.x_host.c_host, 6) == 0) 883 host = "*"; 884 else { 885 q = work.x_host.c_host; 886 (void) sprintf(chost, "%02X%02X%02X%02X%02X%02XH", 887 q[0], q[1], q[2], q[3], q[4], q[5]); 888 for (p = chost; *p == '0' && p < chost + 12; p++) 889 /* void */; 890 host = p; 891 } 892 if (port) 893 (void) sprintf(cport, ".%XH", htons(port)); 894 else 895 *cport = 0; 896 897 (void) sprintf(mybuf,"%XH.%s%s", ntohl(net.long_e), host, cport); 898 return (mybuf); 899 } 900 901 void 902 interfaces() 903 { 904 int needed, rlen, af; 905 char *buf, *lim, *next; 906 register struct rt_msghdr *rtm; 907 908 if ((needed = getkerninfo(KINFO_RT_IFLIST, 0, 0, 0)) < 0) 909 quit("route-getkerninfo-estimate"); 910 if ((buf = malloc(needed)) == NULL) 911 quit("malloc"); 912 if ((rlen = getkerninfo(KINFO_RT_IFLIST, buf, &needed, 0)) < 0) 913 quit("actual retrieval of interface table"); 914 lim = buf + rlen; 915 for (next = buf; next < lim; next += rtm->rtm_msglen) { 916 rtm = (struct rt_msghdr *)next; 917 print_rtmsg(rtm, rtm->rtm_msglen); 918 } 919 } 920 921 void 922 monitor() 923 { 924 int n; 925 char msg[2048]; 926 927 verbose = 1; 928 if (debugonly) { 929 interfaces(); 930 exit(0); 931 } 932 for(;;) { 933 n = read(s, msg, 2048); 934 (void) printf("got message of size %d\n", n); 935 print_rtmsg((struct rt_msghdr *)msg, n); 936 } 937 } 938 939 struct { 940 struct rt_msghdr m_rtm; 941 char m_space[512]; 942 } m_rtmsg; 943 944 int 945 rtmsg(cmd, flags) 946 int cmd, flags; 947 { 948 static int seq; 949 int rlen; 950 register char *cp = m_rtmsg.m_space; 951 register int l; 952 953 #define NEXTADDR(w, u) \ 954 if (rtm_addrs & (w)) {\ 955 l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\ 956 if (verbose) sodump(&(u),"u");\ 957 } 958 959 errno = 0; 960 bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); 961 if (cmd == 'a') 962 cmd = RTM_ADD; 963 else if (cmd == 'c') 964 cmd = RTM_CHANGE; 965 else if (cmd == 'g') { 966 cmd = RTM_GET; 967 if (so_ifp.sa.sa_family == 0) { 968 so_ifp.sa.sa_family == AF_LINK; 969 so_ifp.sa.sa_len == sizeof(struct sockaddr_dl); 970 rtm_addrs |= RTA_IFP; 971 } 972 } else 973 cmd = RTM_DELETE; 974 #define rtm m_rtmsg.m_rtm 975 rtm.rtm_type = cmd; 976 rtm.rtm_flags = flags; 977 rtm.rtm_version = RTM_VERSION; 978 rtm.rtm_seq = ++seq; 979 rtm.rtm_addrs = rtm_addrs; 980 rtm.rtm_rmx = rt_metrics; 981 rtm.rtm_inits = rtm_inits; 982 983 if (rtm_addrs & RTA_NETMASK) 984 mask_addr(); 985 NEXTADDR(RTA_DST, so_dst); 986 NEXTADDR(RTA_GATEWAY, so_gate); 987 NEXTADDR(RTA_NETMASK, so_mask); 988 NEXTADDR(RTA_GENMASK, so_genmask); 989 NEXTADDR(RTA_IFP, so_ifp); 990 NEXTADDR(RTA_IFA, so_ifa); 991 rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 992 if (verbose) 993 print_rtmsg(&rtm, l); 994 if (debugonly) 995 return (0); 996 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 997 perror("writing to routing socket"); 998 return (-1); 999 } 1000 if (cmd == RTM_GET) { 1001 do { 1002 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 1003 } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); 1004 if (l < 0) 1005 (void) fprintf(stderr, 1006 "route: read from routing socket: %s\n", 1007 strerror(errno)); 1008 else 1009 print_getmsg(&rtm, l); 1010 } 1011 #undef rtm 1012 return (0); 1013 } 1014 1015 mask_addr() 1016 { 1017 int olen = so_mask.sa.sa_len; 1018 register char *cp1 = olen + (char *)&so_mask, *cp2; 1019 1020 for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; ) 1021 if (*--cp1 != 0) { 1022 so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask; 1023 break; 1024 } 1025 if ((rtm_addrs & RTA_DST) == 0) 1026 return; 1027 switch (so_dst.sa.sa_family) { 1028 case AF_NS: 1029 case AF_INET: 1030 case AF_CCITT: 1031 case 0: 1032 return; 1033 case AF_ISO: 1034 olen = MIN(so_dst.siso.siso_nlen, so_mask.sa.sa_len - 6); 1035 break; 1036 } 1037 cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst; 1038 cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst; 1039 while (cp2 > cp1) 1040 *--cp2 = 0; 1041 cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask; 1042 while (cp1 > so_dst.sa.sa_data) 1043 *--cp1 &= *--cp2; 1044 switch (so_dst.sa.sa_family) { 1045 case AF_ISO: 1046 so_dst.siso.siso_nlen = olen; 1047 break; 1048 } 1049 } 1050 1051 char *msgtypes[] = { 1052 "", 1053 "RTM_ADD: Add Route", 1054 "RTM_DELETE: Delete Route", 1055 "RTM_CHANGE: Change Metrics or flags", 1056 "RTM_GET: Report Metrics", 1057 "RTM_LOSING: Kernel Suspects Partitioning", 1058 "RTM_REDIRECT: Told to use different route", 1059 "RTM_MISS: Lookup failed on this address", 1060 "RTM_LOCK: fix specified metrics", 1061 "RTM_OLDADD: caused by SIOCADDRT", 1062 "RTM_OLDDEL: caused by SIOCDELRT", 1063 "RTM_RESOLVE: Route created by cloning", 1064 "RTM_NEWADDR: address being added to iface", 1065 "RTM_DELADDR: address being removed from iface", 1066 "RTM_IFINFO: iface status change", 1067 0, 1068 }; 1069 1070 char metricnames[] = 1071 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu"; 1072 char routeflags[] = 1073 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE\013LLINFO\014STATIC\017PROTO2\020PROTO1"; 1074 char ifnetflags[] = 1075 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2"; 1076 char addrnames[] = 1077 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD"; 1078 1079 void 1080 print_rtmsg(rtm, msglen) 1081 register struct rt_msghdr *rtm; 1082 int msglen; 1083 { 1084 struct if_msghdr *ifm; 1085 struct ifa_msghdr *ifam; 1086 1087 if (verbose == 0) 1088 return; 1089 if (rtm->rtm_version != RTM_VERSION) { 1090 (void) printf("routing message version %d not understood\n", 1091 rtm->rtm_version); 1092 return; 1093 } 1094 (void)printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen); 1095 switch (rtm->rtm_type) { 1096 case RTM_IFINFO: 1097 ifm = (struct if_msghdr *)rtm; 1098 (void) printf("if# %d, flags:", ifm->ifm_index); 1099 bprintf(stdout, ifm->ifm_flags, ifnetflags); 1100 pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs); 1101 break; 1102 case RTM_NEWADDR: 1103 case RTM_DELADDR: 1104 ifam = (struct ifa_msghdr *)rtm; 1105 (void) printf("metric %d, flags:", ifam->ifam_metric); 1106 bprintf(stdout, ifam->ifam_flags, routeflags); 1107 pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs); 1108 break; 1109 default: 1110 (void) printf("pid: %d, seq %d, errno %d, flags:", 1111 rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 1112 bprintf(stdout, rtm->rtm_flags, routeflags); 1113 pmsg_common(rtm); 1114 } 1115 } 1116 1117 void 1118 print_getmsg(rtm, msglen) 1119 register struct rt_msghdr *rtm; 1120 int msglen; 1121 { 1122 struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL; 1123 struct sockaddr_dl *ifp = NULL; 1124 register struct sockaddr *sa; 1125 register char *cp; 1126 register int i; 1127 1128 (void) printf(" route to: %s\n", routename(&so_dst)); 1129 if (rtm->rtm_version != RTM_VERSION) { 1130 (void)fprintf(stderr, 1131 "routing message version %d not understood\n", 1132 rtm->rtm_version); 1133 return; 1134 } 1135 if (rtm->rtm_msglen > msglen) { 1136 (void)fprintf(stderr, 1137 "message length mismatch, in packet %d, returned %d\n", 1138 rtm->rtm_msglen, msglen); 1139 } 1140 if (rtm->rtm_errno) { 1141 (void) fprintf(stderr, "RTM_GET: %s (errno %d)\n", 1142 strerror(rtm->rtm_errno), rtm->rtm_errno); 1143 return; 1144 } 1145 cp = ((char *)(rtm + 1)); 1146 if (rtm->rtm_addrs) 1147 for (i = 1; i; i <<= 1) 1148 if (i & rtm->rtm_addrs) { 1149 sa = (struct sockaddr *)cp; 1150 switch (i) { 1151 case RTA_DST: 1152 dst = sa; 1153 break; 1154 case RTA_GATEWAY: 1155 gate = sa; 1156 break; 1157 case RTA_NETMASK: 1158 mask = sa; 1159 break; 1160 case RTA_IFP: 1161 if (sa->sa_family == AF_LINK && 1162 ((struct sockaddr_dl *)sa)->sdl_nlen) 1163 ifp = (struct sockaddr_dl *)sa; 1164 break; 1165 } 1166 ADVANCE(cp, sa); 1167 } 1168 if (dst && mask) 1169 mask->sa_family = dst->sa_family; /* XXX */ 1170 if (dst) 1171 (void)printf("destination: %s\n", routename(dst)); 1172 if (mask) { 1173 int savenflag = nflag; 1174 1175 nflag = 1; 1176 (void)printf(" mask: %s\n", routename(mask)); 1177 nflag = savenflag; 1178 } 1179 if (gate && rtm->rtm_flags & RTF_GATEWAY) 1180 (void)printf(" gateway: %s\n", routename(gate)); 1181 if (ifp) 1182 (void)printf(" interface: %.*s\n", 1183 ifp->sdl_nlen, ifp->sdl_data); 1184 (void)printf(" flags: "); 1185 bprintf(stdout, rtm->rtm_flags, routeflags); 1186 1187 #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') 1188 #define msec(u) (((u) + 500) / 1000) /* usec to msec */ 1189 1190 (void) printf("\n%s\n", "\ 1191 recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire"); 1192 printf("%8d%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); 1193 printf("%8d%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); 1194 printf("%8d%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); 1195 printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); 1196 printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR)); 1197 printf("%8d%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT)); 1198 printf("%8d%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); 1199 if (rtm->rtm_rmx.rmx_expire) 1200 rtm->rtm_rmx.rmx_expire -= time(0); 1201 printf("%8d%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); 1202 #undef lock 1203 #undef msec 1204 #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD) 1205 if (verbose) 1206 pmsg_common(rtm); 1207 else if (rtm->rtm_addrs &~ RTA_IGN) { 1208 (void) printf("sockaddrs: "); 1209 bprintf(stdout, rtm->rtm_addrs, addrnames); 1210 putchar('\n'); 1211 } 1212 #undef RTA_IGN 1213 } 1214 1215 void 1216 pmsg_common(rtm) 1217 register struct rt_msghdr *rtm; 1218 { 1219 (void) printf("\nlocks: "); 1220 bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames); 1221 (void) printf(" inits: "); 1222 bprintf(stdout, rtm->rtm_inits, metricnames); 1223 pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs); 1224 } 1225 1226 void 1227 pmsg_addrs(cp, addrs) 1228 char *cp; 1229 int addrs; 1230 { 1231 register struct sockaddr *sa; 1232 int i; 1233 1234 if (addrs == 0) 1235 return; 1236 (void) printf("\nsockaddrs: "); 1237 bprintf(stdout, addrs, addrnames); 1238 (void) putchar('\n'); 1239 for (i = 1; i; i <<= 1) 1240 if (i & addrs) { 1241 sa = (struct sockaddr *)cp; 1242 (void) printf(" %s", routename(sa)); 1243 ADVANCE(cp, sa); 1244 } 1245 (void) putchar('\n'); 1246 (void) fflush(stdout); 1247 } 1248 1249 void 1250 bprintf(fp, b, s) 1251 register FILE *fp; 1252 register int b; 1253 register u_char *s; 1254 { 1255 register int i; 1256 int gotsome = 0; 1257 1258 if (b == 0) 1259 return; 1260 while (i = *s++) { 1261 if (b & (1 << (i-1))) { 1262 if (gotsome == 0) 1263 i = '<'; 1264 else 1265 i = ','; 1266 (void) putc(i, fp); 1267 gotsome = 1; 1268 for (; (i = *s) > 32; s++) 1269 (void) putc(i, fp); 1270 } else 1271 while (*s > 32) 1272 s++; 1273 } 1274 if (gotsome) 1275 (void) putc('>', fp); 1276 } 1277 1278 int 1279 keyword(cp) 1280 char *cp; 1281 { 1282 register struct keytab *kt = keywords; 1283 1284 while (kt->kt_cp && strcmp(kt->kt_cp, cp)) 1285 kt++; 1286 return kt->kt_i; 1287 } 1288 1289 void 1290 sodump(su, which) 1291 register sup su; 1292 char *which; 1293 { 1294 switch (su->sa.sa_family) { 1295 case AF_LINK: 1296 (void) printf("%s: link %s; ", 1297 which, link_ntoa(&su->sdl)); 1298 break; 1299 case AF_ISO: 1300 (void) printf("%s: iso %s; ", 1301 which, iso_ntoa(&su->siso.siso_addr)); 1302 break; 1303 case AF_INET: 1304 (void) printf("%s: inet %s; ", 1305 which, inet_ntoa(su->sin.sin_addr)); 1306 break; 1307 case AF_NS: 1308 (void) printf("%s: xns %s; ", 1309 which, ns_ntoa(su->sns.sns_addr)); 1310 break; 1311 } 1312 (void) fflush(stdout); 1313 } 1314 1315 /* States*/ 1316 #define VIRGIN 0 1317 #define GOTONE 1 1318 #define GOTTWO 2 1319 /* Inputs */ 1320 #define DIGIT (4*0) 1321 #define END (4*1) 1322 #define DELIM (4*2) 1323 1324 void 1325 sockaddr(addr, sa) 1326 register char *addr; 1327 register struct sockaddr *sa; 1328 { 1329 register char *cp = (char *)sa; 1330 int size = sa->sa_len; 1331 char *cplim = cp + size; 1332 register int byte = 0, state = VIRGIN, new; 1333 1334 bzero(cp, size); 1335 cp++; 1336 do { 1337 if ((*addr >= '0') && (*addr <= '9')) { 1338 new = *addr - '0'; 1339 } else if ((*addr >= 'a') && (*addr <= 'f')) { 1340 new = *addr - 'a' + 10; 1341 } else if ((*addr >= 'A') && (*addr <= 'F')) { 1342 new = *addr - 'A' + 10; 1343 } else if (*addr == 0) 1344 state |= END; 1345 else 1346 state |= DELIM; 1347 addr++; 1348 switch (state /* | INPUT */) { 1349 case GOTTWO | DIGIT: 1350 *cp++ = byte; /*FALLTHROUGH*/ 1351 case VIRGIN | DIGIT: 1352 state = GOTONE; byte = new; continue; 1353 case GOTONE | DIGIT: 1354 state = GOTTWO; byte = new + (byte << 4); continue; 1355 default: /* | DELIM */ 1356 state = VIRGIN; *cp++ = byte; byte = 0; continue; 1357 case GOTONE | END: 1358 case GOTTWO | END: 1359 *cp++ = byte; /* FALLTHROUGH */ 1360 case VIRGIN | END: 1361 break; 1362 } 1363 break; 1364 } while (cp < cplim); 1365 sa->sa_len = cp - (char *)sa; 1366 } 1367