1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1982, 1986, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #include <sys/param.h> 34 #include <sys/protosw.h> 35 #include <sys/socket.h> 36 #include <sys/time.h> 37 #include <netinet/in.h> 38 #define RIPVERSION RIPv2 39 #include <protocols/routed.h> 40 #include <arpa/inet.h> 41 #include <netdb.h> 42 #include <errno.h> 43 #include <unistd.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #ifdef sgi 48 #include <strings.h> 49 #include <bstring.h> 50 #endif 51 52 #define UNUSED __attribute__((unused)) 53 #ifndef __RCSID 54 #define __RCSID(_s) static const char rcsid[] UNUSED = _s 55 #endif 56 #ifndef __COPYRIGHT 57 #define __COPYRIGHT(_s) static const char copyright[] UNUSED = _s 58 #endif 59 __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993\n" 60 "The Regents of the University of California." 61 " All rights reserved.\n"); 62 #ifdef __NetBSD__ 63 __RCSID("$NetBSD$"); 64 #elif defined(__FreeBSD__) 65 #else 66 __RCSID("$Revision: 2.26 $"); 67 #ident "$Revision: 2.26 $" 68 #endif 69 70 #ifndef sgi 71 #define _HAVE_SIN_LEN 72 #endif 73 74 #ifdef __NetBSD__ 75 #include <md5.h> 76 #else 77 #define MD5_DIGEST_LEN 16 78 typedef struct { 79 u_int32_t state[4]; /* state (ABCD) */ 80 u_int32_t count[2]; /* # of bits, modulo 2^64 (LSB 1st) */ 81 unsigned char buffer[64]; /* input buffer */ 82 } MD5_CTX; 83 extern void MD5Init(MD5_CTX*); 84 extern void MD5Update(MD5_CTX*, u_char*, u_int); 85 extern void MD5Final(u_char[MD5_DIGEST_LEN], MD5_CTX*); 86 #endif 87 88 89 #define WTIME 15 /* Time to wait for all responses */ 90 #define STIME (250*1000) /* usec to wait for another response */ 91 92 int soc; 93 94 const char *pgmname; 95 96 union { 97 struct rip rip; 98 char packet[MAXPACKETSIZE+MAXPATHLEN]; 99 } omsg_buf; 100 #define OMSG omsg_buf.rip 101 int omsg_len = sizeof(struct rip); 102 103 union { 104 struct rip rip; 105 char packet[MAXPACKETSIZE+1024]; 106 } imsg_buf; 107 #define IMSG imsg_buf.rip 108 109 int nflag; /* numbers, no names */ 110 int pflag; /* play the `gated` game */ 111 int ripv2 = 1; /* use RIP version 2 */ 112 int wtime = WTIME; 113 int rflag; /* 1=ask about a particular route */ 114 int trace, not_trace; /* send trace command or not */ 115 int auth_type = RIP_AUTH_NONE; 116 char passwd[RIP_AUTH_PW_LEN]; 117 u_long keyid; 118 119 struct timeval sent; /* when query sent */ 120 121 static char localhost_str[] = "localhost"; 122 static char *default_argv[] = {localhost_str, 0}; 123 124 static void rip_input(struct sockaddr_in*, int); 125 static int out(const char *); 126 static void trace_loop(char *argv[]) __attribute((__noreturn__)); 127 static void query_loop(char *argv[], int) __attribute((__noreturn__)); 128 static int getnet(char *, struct netinfo *); 129 static u_int std_mask(u_int); 130 static int parse_quote(char **, const char *, char *, char *, int); 131 static void usage(void) __dead2; 132 133 134 int 135 main(int argc, 136 char *argv[]) 137 { 138 int ch, bsize; 139 char *p, *options, *value, delim; 140 const char *result; 141 142 OMSG.rip_nets[0].n_dst = RIP_DEFAULT; 143 OMSG.rip_nets[0].n_family = RIP_AF_UNSPEC; 144 OMSG.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY); 145 146 pgmname = argv[0]; 147 while ((ch = getopt(argc, argv, "np1w:r:t:a:")) != -1) 148 switch (ch) { 149 case 'n': 150 not_trace = 1; 151 nflag = 1; 152 break; 153 154 case 'p': 155 not_trace = 1; 156 pflag = 1; 157 break; 158 159 case '1': 160 ripv2 = 0; 161 break; 162 163 case 'w': 164 not_trace = 1; 165 wtime = (int)strtoul(optarg, &p, 0); 166 if (*p != '\0' 167 || wtime <= 0) 168 usage(); 169 break; 170 171 case 'r': 172 not_trace = 1; 173 if (rflag) 174 usage(); 175 rflag = getnet(optarg, &OMSG.rip_nets[0]); 176 if (!rflag) { 177 struct hostent *hp = gethostbyname(optarg); 178 if (hp == NULL) { 179 fprintf(stderr, "%s: %s:", 180 pgmname, optarg); 181 herror(0); 182 exit(1); 183 } 184 memcpy(&OMSG.rip_nets[0].n_dst, hp->h_addr, 185 sizeof(OMSG.rip_nets[0].n_dst)); 186 OMSG.rip_nets[0].n_family = RIP_AF_INET; 187 OMSG.rip_nets[0].n_mask = -1; 188 rflag = 1; 189 } 190 break; 191 192 case 't': 193 trace = 1; 194 options = optarg; 195 while (*options != '\0') { 196 /* messy complications to make -W -Wall happy */ 197 static char on_str[] = "on"; 198 static char more_str[] = "more"; 199 static char off_str[] = "off"; 200 static char dump_str[] = "dump"; 201 static char *traceopts[] = { 202 # define TRACE_ON 0 203 on_str, 204 # define TRACE_MORE 1 205 more_str, 206 # define TRACE_OFF 2 207 off_str, 208 # define TRACE_DUMP 3 209 dump_str, 210 0 211 }; 212 result = ""; 213 switch (getsubopt(&options,traceopts,&value)) { 214 case TRACE_ON: 215 OMSG.rip_cmd = RIPCMD_TRACEON; 216 if (!value 217 || strlen(value) > MAXPATHLEN) 218 usage(); 219 result = value; 220 break; 221 case TRACE_MORE: 222 if (value) 223 usage(); 224 OMSG.rip_cmd = RIPCMD_TRACEON; 225 break; 226 case TRACE_OFF: 227 if (value) 228 usage(); 229 OMSG.rip_cmd = RIPCMD_TRACEOFF; 230 break; 231 case TRACE_DUMP: 232 if (value) 233 usage(); 234 OMSG.rip_cmd = RIPCMD_TRACEON; 235 result = "dump/../table"; 236 break; 237 default: 238 usage(); 239 } 240 strcpy((char*)OMSG.rip_tracefile, result); 241 omsg_len += strlen(result) - sizeof(OMSG.ripun); 242 } 243 break; 244 245 case 'a': 246 not_trace = 1; 247 p = strchr(optarg,'='); 248 if (!p) 249 usage(); 250 *p++ = '\0'; 251 if (!strcasecmp("passwd",optarg)) 252 auth_type = RIP_AUTH_PW; 253 else if (!strcasecmp("md5_passwd",optarg)) 254 auth_type = RIP_AUTH_MD5; 255 else 256 usage(); 257 if (0 > parse_quote(&p,"|",&delim, 258 passwd, sizeof(passwd))) 259 usage(); 260 if (auth_type == RIP_AUTH_MD5 261 && delim == '|') { 262 keyid = strtoul(p+1,&p,0); 263 if (keyid > 255 || *p != '\0') 264 usage(); 265 } else if (delim != '\0') { 266 usage(); 267 } 268 break; 269 270 default: 271 usage(); 272 } 273 argv += optind; 274 argc -= optind; 275 if (not_trace && trace) 276 usage(); 277 if (argc == 0) { 278 argc = 1; 279 argv = default_argv; 280 } 281 282 soc = socket(AF_INET, SOCK_DGRAM, 0); 283 if (soc < 0) { 284 perror("socket"); 285 exit(2); 286 } 287 288 /* be prepared to receive a lot of routes */ 289 for (bsize = 127*1024; ; bsize -= 1024) { 290 if (setsockopt(soc, SOL_SOCKET, SO_RCVBUF, 291 &bsize, sizeof(bsize)) == 0) 292 break; 293 if (bsize <= 4*1024) { 294 perror("setsockopt SO_RCVBUF"); 295 break; 296 } 297 } 298 299 if (trace) 300 trace_loop(argv); 301 else 302 query_loop(argv, argc); 303 /* NOTREACHED */ 304 return 0; 305 } 306 307 308 static void 309 usage(void) 310 { 311 fprintf(stderr, 312 "usage: rtquery [-np1] [-r tgt_rt] [-w wtime]" 313 " [-a type=passwd] host1 [host2 ...]\n" 314 "\trtquery -t {on=filename|more|off|dump}" 315 " host1 [host2 ...]\n"); 316 exit(1); 317 } 318 319 320 /* tell the target hosts about tracing 321 */ 322 static void 323 trace_loop(char *argv[]) 324 { 325 struct sockaddr_in myaddr; 326 int res; 327 328 if (geteuid() != 0) { 329 (void)fprintf(stderr, "-t requires UID 0\n"); 330 exit(1); 331 } 332 333 if (ripv2) { 334 OMSG.rip_vers = RIPv2; 335 } else { 336 OMSG.rip_vers = RIPv1; 337 } 338 339 memset(&myaddr, 0, sizeof(myaddr)); 340 myaddr.sin_family = AF_INET; 341 #ifdef _HAVE_SIN_LEN 342 myaddr.sin_len = sizeof(myaddr); 343 #endif 344 myaddr.sin_port = htons(IPPORT_RESERVED-1); 345 while (bind(soc, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { 346 if (errno != EADDRINUSE 347 || myaddr.sin_port == 0) { 348 perror("bind"); 349 exit(2); 350 } 351 myaddr.sin_port = htons(ntohs(myaddr.sin_port)-1); 352 } 353 354 res = 1; 355 while (*argv != NULL) { 356 if (out(*argv++) <= 0) 357 res = 0; 358 } 359 exit(res); 360 } 361 362 363 /* query all of the listed hosts 364 */ 365 static void 366 query_loop(char *argv[], int argc) 367 { 368 # define NA0 (OMSG.rip_auths[0]) 369 # define NA2 (OMSG.rip_auths[2]) 370 struct seen { 371 struct seen *next; 372 struct in_addr addr; 373 } *seen, *sp; 374 int answered = 0; 375 int cc; 376 fd_set bits; 377 struct timeval now, delay; 378 struct sockaddr_in from; 379 int fromlen; 380 MD5_CTX md5_ctx; 381 382 383 OMSG.rip_cmd = (pflag) ? RIPCMD_POLL : RIPCMD_REQUEST; 384 if (ripv2) { 385 OMSG.rip_vers = RIPv2; 386 if (auth_type == RIP_AUTH_PW) { 387 OMSG.rip_nets[1] = OMSG.rip_nets[0]; 388 NA0.a_family = RIP_AF_AUTH; 389 NA0.a_type = RIP_AUTH_PW; 390 memcpy(NA0.au.au_pw, passwd, RIP_AUTH_PW_LEN); 391 omsg_len += sizeof(OMSG.rip_nets[0]); 392 393 } else if (auth_type == RIP_AUTH_MD5) { 394 OMSG.rip_nets[1] = OMSG.rip_nets[0]; 395 NA0.a_family = RIP_AF_AUTH; 396 NA0.a_type = RIP_AUTH_MD5; 397 NA0.au.a_md5.md5_keyid = (int8_t)keyid; 398 NA0.au.a_md5.md5_auth_len = RIP_AUTH_MD5_KEY_LEN; 399 NA0.au.a_md5.md5_seqno = 0; 400 cc = (char *)&NA2-(char *)&OMSG; 401 NA0.au.a_md5.md5_pkt_len = htons(cc); 402 NA2.a_family = RIP_AF_AUTH; 403 NA2.a_type = htons(1); 404 MD5Init(&md5_ctx); 405 MD5Update(&md5_ctx, 406 (u_char *)&OMSG, cc); 407 MD5Update(&md5_ctx, 408 (u_char *)passwd, RIP_AUTH_MD5_HASH_LEN); 409 MD5Final(NA2.au.au_pw, &md5_ctx); 410 omsg_len += 2*sizeof(OMSG.rip_nets[0]); 411 } 412 413 } else { 414 OMSG.rip_vers = RIPv1; 415 OMSG.rip_nets[0].n_mask = 0; 416 } 417 418 /* ask the first (valid) host */ 419 seen = NULL; 420 while (0 > out(*argv++)) { 421 if (*argv == NULL) 422 exit(1); 423 answered++; 424 } 425 426 FD_ZERO(&bits); 427 for (;;) { 428 FD_SET(soc, &bits); 429 delay.tv_sec = 0; 430 delay.tv_usec = STIME; 431 cc = select(soc+1, &bits, 0,0, &delay); 432 if (cc > 0) { 433 fromlen = sizeof(from); 434 cc = recvfrom(soc, imsg_buf.packet, 435 sizeof(imsg_buf.packet), 0, 436 (struct sockaddr *)&from, &fromlen); 437 if (cc < 0) { 438 perror("recvfrom"); 439 exit(1); 440 } 441 /* count the distinct responding hosts. 442 * You cannot match responding hosts with 443 * addresses to which queries were transmitted, 444 * because a router might respond with a 445 * different source address. 446 */ 447 for (sp = seen; sp != NULL; sp = sp->next) { 448 if (sp->addr.s_addr == from.sin_addr.s_addr) 449 break; 450 } 451 if (sp == NULL) { 452 sp = malloc(sizeof(*sp)); 453 if (sp == NULL) { 454 fprintf(stderr, 455 "rtquery: malloc failed\n"); 456 exit(1); 457 } 458 sp->addr = from.sin_addr; 459 sp->next = seen; 460 seen = sp; 461 answered++; 462 } 463 464 rip_input(&from, cc); 465 continue; 466 } 467 468 if (cc < 0) { 469 if (errno == EINTR) 470 continue; 471 perror("select"); 472 exit(1); 473 } 474 475 /* After a pause in responses, probe another host. 476 * This reduces the intermingling of answers. 477 */ 478 while (*argv != NULL && out(*argv++) < 0) 479 answered++; 480 481 /* continue until no more packets arrive 482 * or we have heard from all hosts 483 */ 484 if (answered >= argc) 485 break; 486 487 /* or until we have waited a long time 488 */ 489 if (gettimeofday(&now, 0) < 0) { 490 perror("gettimeofday(now)"); 491 exit(1); 492 } 493 if (sent.tv_sec + wtime <= now.tv_sec) 494 break; 495 } 496 497 /* fail if there was no answer */ 498 exit (answered >= argc ? 0 : 1); 499 } 500 501 502 /* send to one host 503 */ 504 static int 505 out(const char *host) 506 { 507 struct sockaddr_in router; 508 struct hostent *hp; 509 510 if (gettimeofday(&sent, 0) < 0) { 511 perror("gettimeofday(sent)"); 512 return -1; 513 } 514 515 memset(&router, 0, sizeof(router)); 516 router.sin_family = AF_INET; 517 #ifdef _HAVE_SIN_LEN 518 router.sin_len = sizeof(router); 519 #endif 520 if (!inet_aton(host, &router.sin_addr)) { 521 hp = gethostbyname(host); 522 if (hp == NULL) { 523 herror(host); 524 return -1; 525 } 526 memcpy(&router.sin_addr, hp->h_addr, sizeof(router.sin_addr)); 527 } 528 router.sin_port = htons(RIP_PORT); 529 530 if (sendto(soc, &omsg_buf, omsg_len, 0, 531 (struct sockaddr *)&router, sizeof(router)) < 0) { 532 perror(host); 533 return -1; 534 } 535 536 return 0; 537 } 538 539 540 /* 541 * Convert string to printable characters 542 */ 543 static char * 544 qstring(u_char *s, int len) 545 { 546 static char buf[8*20+1]; 547 char *p; 548 u_char *s2, c; 549 550 551 for (p = buf; len != 0 && p < &buf[sizeof(buf)-1]; len--) { 552 c = *s++; 553 if (c == '\0') { 554 for (s2 = s+1; s2 < &s[len]; s2++) { 555 if (*s2 != '\0') 556 break; 557 } 558 if (s2 >= &s[len]) 559 goto exit; 560 } 561 562 if (c >= ' ' && c < 0x7f && c != '\\') { 563 *p++ = c; 564 continue; 565 } 566 *p++ = '\\'; 567 switch (c) { 568 case '\\': 569 *p++ = '\\'; 570 break; 571 case '\n': 572 *p++= 'n'; 573 break; 574 case '\r': 575 *p++= 'r'; 576 break; 577 case '\t': 578 *p++ = 't'; 579 break; 580 case '\b': 581 *p++ = 'b'; 582 break; 583 default: 584 p += sprintf(p,"%o",c); 585 break; 586 } 587 } 588 exit: 589 *p = '\0'; 590 return buf; 591 } 592 593 594 /* 595 * Handle an incoming RIP packet. 596 */ 597 static void 598 rip_input(struct sockaddr_in *from, 599 int size) 600 { 601 struct netinfo *n, *lim; 602 struct in_addr in; 603 const char *name; 604 char net_buf[80]; 605 u_char hash[RIP_AUTH_MD5_KEY_LEN]; 606 MD5_CTX md5_ctx; 607 u_char md5_authed = 0; 608 u_int mask, dmask; 609 char *sp; 610 int i; 611 struct hostent *hp; 612 struct netent *np; 613 struct netauth *na; 614 615 616 if (nflag) { 617 printf("%s:", inet_ntoa(from->sin_addr)); 618 } else { 619 hp = gethostbyaddr((char*)&from->sin_addr, 620 sizeof(struct in_addr), AF_INET); 621 if (hp == NULL) { 622 printf("%s:", 623 inet_ntoa(from->sin_addr)); 624 } else { 625 printf("%s (%s):", hp->h_name, 626 inet_ntoa(from->sin_addr)); 627 } 628 } 629 if (IMSG.rip_cmd != RIPCMD_RESPONSE) { 630 printf("\n unexpected response type %d\n", IMSG.rip_cmd); 631 return; 632 } 633 printf(" RIPv%d%s %d bytes\n", IMSG.rip_vers, 634 (IMSG.rip_vers != RIPv1 && IMSG.rip_vers != RIPv2) ? " ?" : "", 635 size); 636 if (size > MAXPACKETSIZE) { 637 if (size > (int)sizeof(imsg_buf) - (int)sizeof(*n)) { 638 printf(" at least %d bytes too long\n", 639 size-MAXPACKETSIZE); 640 size = (int)sizeof(imsg_buf) - (int)sizeof(*n); 641 } else { 642 printf(" %d bytes too long\n", 643 size-MAXPACKETSIZE); 644 } 645 } else if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) { 646 printf(" response of bad length=%d\n", size); 647 } 648 649 n = IMSG.rip_nets; 650 lim = (struct netinfo *)((char*)n + size) - 1; 651 for (; n <= lim; n++) { 652 name = ""; 653 if (n->n_family == RIP_AF_INET) { 654 in.s_addr = n->n_dst; 655 (void)strcpy(net_buf, inet_ntoa(in)); 656 657 mask = ntohl(n->n_mask); 658 dmask = mask & -mask; 659 if (mask != 0) { 660 sp = &net_buf[strlen(net_buf)]; 661 if (IMSG.rip_vers == RIPv1) { 662 (void)sprintf(sp," mask=%#x ? ",mask); 663 mask = 0; 664 } else if (mask + dmask == 0) { 665 for (i = 0; 666 (i != 32 667 && ((1<<i)&mask) == 0); 668 i++) 669 continue; 670 (void)sprintf(sp, "/%d",32-i); 671 } else { 672 (void)sprintf(sp," (mask %#x)", mask); 673 } 674 } 675 676 if (!nflag) { 677 if (mask == 0) { 678 mask = std_mask(in.s_addr); 679 if ((ntohl(in.s_addr) & ~mask) != 0) 680 mask = 0; 681 } 682 /* Without a netmask, do not worry about 683 * whether the destination is a host or a 684 * network. Try both and use the first name 685 * we get. 686 * 687 * If we have a netmask we can make a 688 * good guess. 689 */ 690 if ((in.s_addr & ~mask) == 0) { 691 np = getnetbyaddr((long)in.s_addr, 692 AF_INET); 693 if (np != NULL) 694 name = np->n_name; 695 else if (in.s_addr == 0) 696 name = "default"; 697 } 698 if (name[0] == '\0' 699 && ((in.s_addr & ~mask) != 0 700 || mask == 0xffffffff)) { 701 hp = gethostbyaddr((char*)&in, 702 sizeof(in), 703 AF_INET); 704 if (hp != NULL) 705 name = hp->h_name; 706 } 707 } 708 709 } else if (n->n_family == RIP_AF_AUTH) { 710 na = (struct netauth*)n; 711 if (na->a_type == RIP_AUTH_PW 712 && n == IMSG.rip_nets) { 713 (void)printf(" Password Authentication:" 714 " \"%s\"\n", 715 qstring(na->au.au_pw, 716 RIP_AUTH_PW_LEN)); 717 continue; 718 } 719 720 if (na->a_type == RIP_AUTH_MD5 721 && n == IMSG.rip_nets) { 722 (void)printf(" MD5 Auth" 723 " len=%d KeyID=%d" 724 " auth_len=%d" 725 " seqno=%#x" 726 " rsvd=%#x,%#x\n", 727 ntohs(na->au.a_md5.md5_pkt_len), 728 na->au.a_md5.md5_keyid, 729 na->au.a_md5.md5_auth_len, 730 (int)ntohl(na->au.a_md5.md5_seqno), 731 na->au.a_md5.rsvd[0], 732 na->au.a_md5.rsvd[1]); 733 md5_authed = 1; 734 continue; 735 } 736 (void)printf(" Authentication type %d: ", 737 ntohs(na->a_type)); 738 for (i = 0; i < (int)sizeof(na->au.au_pw); i++) 739 (void)printf("%02x ", na->au.au_pw[i]); 740 putc('\n', stdout); 741 if (md5_authed && n+1 > lim 742 && na->a_type == ntohs(1)) { 743 MD5Init(&md5_ctx); 744 MD5Update(&md5_ctx, (u_char *)&IMSG, 745 (char *)na-(char *)&IMSG 746 +RIP_AUTH_MD5_HASH_XTRA); 747 MD5Update(&md5_ctx, (u_char *)passwd, 748 RIP_AUTH_MD5_KEY_LEN); 749 MD5Final(hash, &md5_ctx); 750 (void)printf(" %s hash\n", 751 memcmp(hash, na->au.au_pw, 752 sizeof(hash)) 753 ? "WRONG" : "correct"); 754 } 755 continue; 756 757 } else { 758 (void)sprintf(net_buf, "(af %#x) %d.%d.%d.%d", 759 ntohs(n->n_family), 760 (u_char)(n->n_dst >> 24), 761 (u_char)(n->n_dst >> 16), 762 (u_char)(n->n_dst >> 8), 763 (u_char)n->n_dst); 764 } 765 766 (void)printf(" %-18s metric %2d %-10s", 767 net_buf, (int)ntohl(n->n_metric), name); 768 769 if (n->n_nhop != 0) { 770 in.s_addr = n->n_nhop; 771 if (nflag) 772 hp = NULL; 773 else 774 hp = gethostbyaddr((char*)&in, sizeof(in), 775 AF_INET); 776 (void)printf(" nhop=%-15s%s", 777 (hp != NULL) ? hp->h_name : inet_ntoa(in), 778 (IMSG.rip_vers == RIPv1) ? " ?" : ""); 779 } 780 if (n->n_tag != 0) 781 (void)printf(" tag=%#x%s", n->n_tag, 782 (IMSG.rip_vers == RIPv1) ? " ?" : ""); 783 putc('\n', stdout); 784 } 785 } 786 787 788 /* Return the classical netmask for an IP address. 789 */ 790 static u_int 791 std_mask(u_int addr) /* in network order */ 792 { 793 addr = ntohl(addr); /* was a host, not a network */ 794 795 if (addr == 0) /* default route has mask 0 */ 796 return 0; 797 if (IN_CLASSA(addr)) 798 return IN_CLASSA_NET; 799 if (IN_CLASSB(addr)) 800 return IN_CLASSB_NET; 801 return IN_CLASSC_NET; 802 } 803 804 805 /* get a network number as a name or a number, with an optional "/xx" 806 * netmask. 807 */ 808 static int /* 0=bad */ 809 getnet(char *name, 810 struct netinfo *rt) 811 { 812 int i; 813 struct netent *nentp; 814 u_int mask; 815 struct in_addr in; 816 char hname[MAXHOSTNAMELEN+1]; 817 char *mname, *p; 818 819 820 /* Detect and separate "1.2.3.4/24" 821 */ 822 if (NULL != (mname = strrchr(name,'/'))) { 823 i = (int)(mname - name); 824 if (i > (int)sizeof(hname)-1) /* name too long */ 825 return 0; 826 memmove(hname, name, i); 827 hname[i] = '\0'; 828 mname++; 829 name = hname; 830 } 831 832 nentp = getnetbyname(name); 833 if (nentp != NULL) { 834 in.s_addr = nentp->n_net; 835 } else if (inet_aton(name, &in) == 1) { 836 in.s_addr = ntohl(in.s_addr); 837 } else { 838 return 0; 839 } 840 841 if (mname == NULL) { 842 mask = std_mask(in.s_addr); 843 if ((~mask & in.s_addr) != 0) 844 mask = 0xffffffff; 845 } else { 846 mask = (u_int)strtoul(mname, &p, 0); 847 if (*p != '\0' || mask > 32) 848 return 0; 849 mask = 0xffffffff << (32-mask); 850 } 851 852 rt->n_dst = htonl(in.s_addr); 853 rt->n_family = RIP_AF_INET; 854 rt->n_mask = htonl(mask); 855 return 1; 856 } 857 858 859 /* strtok(), but honoring backslash 860 */ 861 static int /* -1=bad */ 862 parse_quote(char **linep, 863 const char *delims, 864 char *delimp, 865 char *buf, 866 int lim) 867 { 868 char c, *pc; 869 const char *p; 870 871 872 pc = *linep; 873 if (*pc == '\0') 874 return -1; 875 876 for (;;) { 877 if (lim == 0) 878 return -1; 879 c = *pc++; 880 if (c == '\0') 881 break; 882 883 if (c == '\\' && *pc != '\0') { 884 if ((c = *pc++) == 'n') { 885 c = '\n'; 886 } else if (c == 'r') { 887 c = '\r'; 888 } else if (c == 't') { 889 c = '\t'; 890 } else if (c == 'b') { 891 c = '\b'; 892 } else if (c >= '0' && c <= '7') { 893 c -= '0'; 894 if (*pc >= '0' && *pc <= '7') { 895 c = (c<<3)+(*pc++ - '0'); 896 if (*pc >= '0' && *pc <= '7') 897 c = (c<<3)+(*pc++ - '0'); 898 } 899 } 900 901 } else { 902 for (p = delims; *p != '\0'; ++p) { 903 if (*p == c) 904 goto exit; 905 } 906 } 907 908 *buf++ = c; 909 --lim; 910 } 911 exit: 912 if (delimp != NULL) 913 *delimp = c; 914 *linep = pc-1; 915 if (lim != 0) 916 *buf = '\0'; 917 return 0; 918 } 919