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