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