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