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