1 /*- 2 * Copyright (c) 1982, 1986, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 char copyright[] = 35 "@(#) Copyright (c) 1982, 1986, 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37 38 #if !defined(lint) && !defined(sgi) && !defined(__NetBSD__) 39 static char sccsid[] = "@(#)query.c 8.1 (Berkeley) 6/5/93"; 40 #elif defined(__NetBSD__) 41 static char rcsid[] = "$NetBSD$"; 42 #endif 43 #ident "$Revision: 1.9 $" 44 45 #include <sys/param.h> 46 #include <sys/protosw.h> 47 #include <sys/socket.h> 48 #include <sys/time.h> 49 #include <netinet/in.h> 50 #define RIPVERSION RIPv2 51 #include <protocols/routed.h> 52 #include <arpa/inet.h> 53 #include <netdb.h> 54 #include <errno.h> 55 #include <unistd.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #ifdef sgi 60 #include <strings.h> 61 #include <bstring.h> 62 #endif 63 64 #ifndef sgi 65 #define _HAVE_SIN_LEN 66 #endif 67 68 #define WTIME 15 /* Time to wait for all responses */ 69 #define STIME (250*1000) /* usec to wait for another response */ 70 71 int s; 72 73 char *pgmname; 74 75 union { 76 struct rip rip; 77 char packet[MAXPACKETSIZE+MAXPATHLEN]; 78 } omsg_buf; 79 #define OMSG omsg_buf.rip 80 int omsg_len = sizeof(struct rip); 81 82 union { 83 struct rip rip; 84 char packet[MAXPACKETSIZE+1024]; 85 } imsg_buf; 86 #define IMSG imsg_buf.rip 87 88 int nflag; /* numbers, no names */ 89 int pflag; /* play the `gated` game */ 90 int ripv2 = 1; /* use RIP version 2 */ 91 int wtime = WTIME; 92 int rflag; /* 1=ask about a particular route */ 93 int trace; 94 int not_trace; 95 96 struct timeval sent; /* when query sent */ 97 98 static void rip_input(struct sockaddr_in*, int); 99 static int out(char *); 100 static void trace_loop(char *argv[]); 101 static void query_loop(char *argv[], int); 102 static int getnet(char *, struct netinfo *); 103 static u_int std_mask(u_int); 104 105 106 int 107 main(int argc, 108 char *argv[]) 109 { 110 int ch, bsize; 111 char *p, *options, *value; 112 113 OMSG.rip_nets[0].n_dst = RIP_DEFAULT; 114 OMSG.rip_nets[0].n_family = RIP_AF_UNSPEC; 115 OMSG.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY); 116 117 pgmname = argv[0]; 118 while ((ch = getopt(argc, argv, "np1w:r:t:")) != EOF) 119 switch (ch) { 120 case 'n': 121 not_trace = 1; 122 nflag = 1; 123 break; 124 125 case 'p': 126 not_trace = 1; 127 pflag = 1; 128 break; 129 130 case '1': 131 ripv2 = 0; 132 break; 133 134 case 'w': 135 not_trace = 1; 136 wtime = (int)strtoul(optarg, &p, 0); 137 if (*p != '\0' 138 || wtime <= 0) 139 goto usage; 140 break; 141 142 case 'r': 143 not_trace = 1; 144 if (rflag) 145 goto usage; 146 rflag = getnet(optarg, &OMSG.rip_nets[0]); 147 if (!rflag) { 148 struct hostent *hp = gethostbyname(optarg); 149 if (hp == 0) { 150 fprintf(stderr, "%s: %s:", 151 pgmname, optarg); 152 herror(0); 153 exit(1); 154 } 155 bcopy(hp->h_addr, &OMSG.rip_nets[0].n_dst, 156 sizeof(OMSG.rip_nets[0].n_dst)); 157 OMSG.rip_nets[0].n_family = RIP_AF_INET; 158 OMSG.rip_nets[0].n_mask = -1; 159 rflag = 1; 160 } 161 break; 162 163 case 't': 164 trace = 1; 165 options = optarg; 166 while (*options != '\0') { 167 char *traceopts[] = { 168 # define TRACE_ON 0 169 "on", 170 # define TRACE_MORE 1 171 "more", 172 # define TRACE_OFF 2 173 "off", 174 # define TRACE_DUMP 3 175 "dump", 176 0 177 }; 178 switch (getsubopt(&options,traceopts,&value)) { 179 case TRACE_ON: 180 OMSG.rip_cmd = RIPCMD_TRACEON; 181 if (!value 182 || strlen(value) > MAXPATHLEN) 183 goto usage; 184 break; 185 case TRACE_MORE: 186 if (value) 187 goto usage; 188 OMSG.rip_cmd = RIPCMD_TRACEON; 189 value = ""; 190 break; 191 case TRACE_OFF: 192 if (value) 193 goto usage; 194 OMSG.rip_cmd = RIPCMD_TRACEOFF; 195 value = ""; 196 break; 197 case TRACE_DUMP: 198 if (value) 199 goto usage; 200 OMSG.rip_cmd = RIPCMD_TRACEON; 201 value = "dump/../table"; 202 break; 203 default: 204 goto usage; 205 } 206 strcpy((char*)OMSG.rip_tracefile, value); 207 omsg_len += strlen(value) - sizeof(OMSG.ripun); 208 } 209 break; 210 211 default: 212 goto usage; 213 } 214 argv += optind; 215 argc -= optind; 216 if ((not_trace && trace) || argc == 0) { 217 usage: fprintf(stderr, "%s: [-np1v] [-r tgt_rt] [-w wtime]" 218 " host1 [host2 ...]\n" 219 "or\t-t {on=filename|more|off} host1 host2 ...\n", 220 pgmname); 221 exit(1); 222 } 223 224 s = socket(AF_INET, SOCK_DGRAM, 0); 225 if (s < 0) { 226 perror("socket"); 227 exit(2); 228 } 229 230 /* be prepared to receive a lot of routes */ 231 for (bsize = 127*1024; ; bsize -= 1024) { 232 if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 233 &bsize, sizeof(bsize)) == 0) 234 break; 235 if (bsize <= 4*1024) { 236 perror("setsockopt SO_RCVBUF"); 237 break; 238 } 239 } 240 241 if (trace) 242 trace_loop(argv); 243 else 244 query_loop(argv, argc); 245 /* NOTREACHED */ 246 } 247 248 249 /* tell the target hosts about tracing 250 */ 251 static void 252 trace_loop(char *argv[]) 253 { 254 struct sockaddr_in myaddr; 255 int res; 256 257 if (geteuid() != 0) { 258 (void)fprintf(stderr, "-t requires UID 0\n"); 259 exit(1); 260 } 261 262 if (ripv2) { 263 OMSG.rip_vers = RIPv2; 264 } else { 265 OMSG.rip_vers = RIPv1; 266 } 267 268 bzero(&myaddr, sizeof(myaddr)); 269 myaddr.sin_family = AF_INET; 270 #ifdef _HAVE_SIN_LEN 271 myaddr.sin_len = sizeof(myaddr); 272 #endif 273 myaddr.sin_port = htons(IPPORT_RESERVED-1); 274 while (bind(s, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { 275 if (errno != EADDRINUSE 276 || myaddr.sin_port == 0) { 277 perror("bind"); 278 exit(2); 279 } 280 myaddr.sin_port = htons(ntohs(myaddr.sin_port)-1); 281 } 282 283 res = 1; 284 while (*argv != 0) { 285 if (out(*argv++) <= 0) 286 res = 0; 287 } 288 exit(res); 289 } 290 291 292 /* query all of the listed hosts 293 */ 294 static void 295 query_loop(char *argv[], int argc) 296 { 297 struct seen { 298 struct seen *next; 299 struct in_addr addr; 300 } *seen, *sp; 301 int answered = 0; 302 int cc; 303 fd_set bits; 304 struct timeval now, delay; 305 struct sockaddr_in from; 306 int fromlen; 307 308 309 OMSG.rip_cmd = (pflag) ? RIPCMD_POLL : RIPCMD_REQUEST; 310 if (ripv2) { 311 OMSG.rip_vers = RIPv2; 312 } else { 313 OMSG.rip_vers = RIPv1; 314 OMSG.rip_nets[0].n_mask = 0; 315 } 316 317 /* ask the first (valid) host */ 318 seen = 0; 319 while (0 > out(*argv++)) { 320 if (*argv == 0) 321 exit(-1); 322 answered++; 323 } 324 325 FD_ZERO(&bits); 326 for (;;) { 327 FD_SET(s, &bits); 328 delay.tv_sec = 0; 329 delay.tv_usec = STIME; 330 cc = select(s+1, &bits, 0,0, &delay); 331 if (cc > 0) { 332 fromlen = sizeof(from); 333 cc = recvfrom(s, imsg_buf.packet, 334 sizeof(imsg_buf.packet), 0, 335 (struct sockaddr *)&from, &fromlen); 336 if (cc < 0) { 337 perror("recvfrom"); 338 exit(1); 339 } 340 /* count the distinct responding hosts. 341 * You cannot match responding hosts with 342 * addresses to which queries were transmitted, 343 * because a router might respond with a 344 * different source address. 345 */ 346 for (sp = seen; sp != 0; sp = sp->next) { 347 if (sp->addr.s_addr == from.sin_addr.s_addr) 348 break; 349 } 350 if (sp == 0) { 351 sp = malloc(sizeof(*sp)); 352 sp->addr = from.sin_addr; 353 sp->next = seen; 354 seen = sp; 355 answered++; 356 } 357 358 rip_input(&from, cc); 359 continue; 360 } 361 362 if (cc < 0) { 363 if ( errno == EINTR) 364 continue; 365 perror("select"); 366 exit(1); 367 } 368 369 /* After a pause in responses, probe another host. 370 * This reduces the intermingling of answers. 371 */ 372 while (*argv != 0 && 0 > out(*argv++)) 373 answered++; 374 375 /* continue until no more packets arrive 376 * or we have heard from all hosts 377 */ 378 if (answered >= argc) 379 break; 380 381 /* or until we have waited a long time 382 */ 383 if (gettimeofday(&now, 0) < 0) { 384 perror("gettimeofday(now)"); 385 exit(1); 386 } 387 if (sent.tv_sec + wtime <= now.tv_sec) 388 break; 389 } 390 391 /* fail if there was no answer */ 392 exit (answered >= argc ? 0 : 1); 393 } 394 395 396 /* sent do one host 397 */ 398 static int 399 out(char *host) 400 { 401 struct sockaddr_in router; 402 struct hostent *hp; 403 404 if (gettimeofday(&sent, 0) < 0) { 405 perror("gettimeofday(sent)"); 406 return -1; 407 } 408 409 bzero(&router, sizeof(router)); 410 router.sin_family = AF_INET; 411 #ifdef _HAVE_SIN_LEN 412 router.sin_len = sizeof(router); 413 #endif 414 if (!inet_aton(host, &router.sin_addr)) { 415 hp = gethostbyname(host); 416 if (hp == 0) { 417 herror(host); 418 return -1; 419 } 420 bcopy(hp->h_addr, &router.sin_addr, sizeof(router.sin_addr)); 421 } 422 router.sin_port = htons(RIP_PORT); 423 424 if (sendto(s, &omsg_buf, omsg_len, 0, 425 (struct sockaddr *)&router, sizeof(router)) < 0) { 426 perror(host); 427 return -1; 428 } 429 430 return 0; 431 } 432 433 434 /* 435 * Handle an incoming RIP packet. 436 */ 437 static void 438 rip_input(struct sockaddr_in *from, 439 int size) 440 { 441 struct netinfo *n, *lim; 442 struct in_addr in; 443 char *name; 444 char net_buf[80]; 445 u_int mask, dmask; 446 char *sp; 447 int i; 448 struct hostent *hp; 449 struct netent *np; 450 struct netauth *a; 451 452 453 if (nflag) { 454 printf("%s:", inet_ntoa(from->sin_addr)); 455 } else { 456 hp = gethostbyaddr((char*)&from->sin_addr, 457 sizeof(struct in_addr), AF_INET); 458 if (hp == 0) { 459 printf("%s:", 460 inet_ntoa(from->sin_addr)); 461 } else { 462 printf("%s (%s):", hp->h_name, 463 inet_ntoa(from->sin_addr)); 464 } 465 } 466 if (IMSG.rip_cmd != RIPCMD_RESPONSE) { 467 printf("\n unexpected response type %d\n", IMSG.rip_cmd); 468 return; 469 } 470 printf(" RIPv%d%s %d bytes\n", IMSG.rip_vers, 471 (IMSG.rip_vers != RIPv1 && IMSG.rip_vers != RIPv2) ? " ?" : "", 472 size); 473 if (size > MAXPACKETSIZE) { 474 if (size > sizeof(imsg_buf) - sizeof(*n)) { 475 printf(" at least %d bytes too long\n", 476 size-MAXPACKETSIZE); 477 size = sizeof(imsg_buf) - sizeof(*n); 478 } else { 479 printf(" %d bytes too long\n", 480 size-MAXPACKETSIZE); 481 } 482 } else if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) { 483 printf(" response of bad length=%d\n", size); 484 } 485 486 n = IMSG.rip_nets; 487 lim = (struct netinfo *)((char*)n + size) - 1; 488 for (; n <= lim; n++) { 489 name = ""; 490 if (n->n_family == RIP_AF_INET) { 491 in.s_addr = n->n_dst; 492 (void)strcpy(net_buf, inet_ntoa(in)); 493 494 mask = ntohl(n->n_mask); 495 dmask = mask & -mask; 496 if (mask != 0) { 497 sp = &net_buf[strlen(net_buf)]; 498 if (IMSG.rip_vers == RIPv1) { 499 (void)sprintf(sp," mask=%#x ? ",mask); 500 mask = 0; 501 } else if (mask + dmask == 0) { 502 for (i = 0; 503 (i != 32 504 && ((1<<i)&mask) == 0); 505 i++) 506 continue; 507 (void)sprintf(sp, "/%d",32-i); 508 } else { 509 (void)sprintf(sp," (mask %#x)", mask); 510 } 511 } 512 513 if (!nflag) { 514 if (mask == 0) { 515 mask = std_mask(in.s_addr); 516 if ((ntohl(in.s_addr) & ~mask) != 0) 517 mask = 0; 518 } 519 /* Without a netmask, do not worry about 520 * whether the destination is a host or a 521 * network. Try both and use the first name 522 * we get. 523 * 524 * If we have a netmask we can make a 525 * good guess. 526 */ 527 if ((in.s_addr & ~mask) == 0) { 528 np = getnetbyaddr((long)in.s_addr, 529 AF_INET); 530 if (np != 0) 531 name = np->n_name; 532 else if (in.s_addr == 0) 533 name = "default"; 534 } 535 if (name[0] == '\0' 536 && ((in.s_addr & ~mask) != 0 537 || mask == 0xffffffff)) { 538 hp = gethostbyaddr((char*)&in, 539 sizeof(in), 540 AF_INET); 541 if (hp != 0) 542 name = hp->h_name; 543 } 544 } 545 546 } else if (n->n_family == RIP_AF_AUTH) { 547 a = (struct netauth*)n; 548 (void)printf(" authentication type %d: ", 549 a->a_type); 550 for (i = 0; i < sizeof(a->au.au_pw); i++) 551 (void)printf("%02x ", a->au.au_pw[i]); 552 putc('\n', stdout); 553 continue; 554 555 } else { 556 (void)sprintf(net_buf, "(af %#x) %d.%d.%d.%d", 557 ntohs(n->n_family), 558 (char)(n->n_dst >> 24), 559 (char)(n->n_dst >> 16), 560 (char)(n->n_dst >> 8), 561 (char)n->n_dst); 562 } 563 564 (void)printf(" %-18s metric %2d %-10s", 565 net_buf, ntohl(n->n_metric), name); 566 567 if (n->n_nhop != 0) { 568 in.s_addr = n->n_nhop; 569 if (nflag) 570 hp = 0; 571 else 572 hp = gethostbyaddr((char*)&in, sizeof(in), 573 AF_INET); 574 (void)printf(" nhop=%-15s%s", 575 (hp != 0) ? hp->h_name : inet_ntoa(in), 576 (IMSG.rip_vers == RIPv1) ? " ?" : ""); 577 } 578 if (n->n_tag != 0) 579 (void)printf(" tag=%#x%s", n->n_tag, 580 (IMSG.rip_vers == RIPv1) ? " ?" : ""); 581 putc('\n', stdout); 582 } 583 } 584 585 586 /* Return the classical netmask for an IP address. 587 */ 588 static u_int 589 std_mask(u_int addr) /* in network order */ 590 { 591 NTOHL(addr); /* was a host, not a network */ 592 593 if (addr == 0) /* default route has mask 0 */ 594 return 0; 595 if (IN_CLASSA(addr)) 596 return IN_CLASSA_NET; 597 if (IN_CLASSB(addr)) 598 return IN_CLASSB_NET; 599 return IN_CLASSC_NET; 600 } 601 602 603 /* get a network number as a name or a number, with an optional "/xx" 604 * netmask. 605 */ 606 static int /* 0=bad */ 607 getnet(char *name, 608 struct netinfo *rt) 609 { 610 int i; 611 struct netent *nentp; 612 u_int mask; 613 struct in_addr in; 614 char hname[MAXHOSTNAMELEN+1]; 615 char *mname, *p; 616 617 618 /* Detect and separate "1.2.3.4/24" 619 */ 620 if (0 != (mname = rindex(name,'/'))) { 621 i = (int)(mname - name); 622 if (i > sizeof(hname)-1) /* name too long */ 623 return 0; 624 bcopy(name, hname, i); 625 hname[i] = '\0'; 626 mname++; 627 name = hname; 628 } 629 630 nentp = getnetbyname(name); 631 if (nentp != 0) { 632 in.s_addr = nentp->n_net; 633 } else if (inet_aton(name, &in) == 1) { 634 NTOHL(in.s_addr); 635 } else { 636 return 0; 637 } 638 639 if (mname == 0) { 640 mask = std_mask(in.s_addr); 641 if ((~mask & in.s_addr) != 0) 642 mask = 0xffffffff; 643 } else { 644 mask = (u_int)strtoul(mname, &p, 0); 645 if (*p != '\0' || mask > 32) 646 return 0; 647 mask = 0xffffffff << (32-mask); 648 } 649 650 rt->n_dst = htonl(in.s_addr); 651 rt->n_family = RIP_AF_INET; 652 rt->n_mask = htonl(mask); 653 return 1; 654 } 655