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