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