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