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