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