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