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