rtquery.c revision 19880
118316Swollman/*-
218316Swollman * Copyright (c) 1982, 1986, 1993
318316Swollman *	The Regents of the University of California.  All rights reserved.
418316Swollman *
518316Swollman * Redistribution and use in source and binary forms, with or without
618316Swollman * modification, are permitted provided that the following conditions
718316Swollman * are met:
818316Swollman * 1. Redistributions of source code must retain the above copyright
918316Swollman *    notice, this list of conditions and the following disclaimer.
1018316Swollman * 2. Redistributions in binary form must reproduce the above copyright
1118316Swollman *    notice, this list of conditions and the following disclaimer in the
1218316Swollman *    documentation and/or other materials provided with the distribution.
1318316Swollman * 3. All advertising materials mentioning features or use of this software
1418316Swollman *    must display the following acknowledgement:
1518316Swollman *	This product includes software developed by the University of
1618316Swollman *	California, Berkeley and its contributors.
1718316Swollman * 4. Neither the name of the University nor the names of its contributors
1818316Swollman *    may be used to endorse or promote products derived from this software
1918316Swollman *    without specific prior written permission.
2018316Swollman *
2118316Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2218316Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2318316Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2418316Swollman * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2518316Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2618316Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2718316Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2818316Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2918316Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3018316Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3118316Swollman * SUCH DAMAGE.
3218316Swollman */
3318316Swollman
3418316Swollmanchar copyright[] =
3518316Swollman"@(#) Copyright (c) 1982, 1986, 1993\n\
3618316Swollman	The Regents of the University of California.  All rights reserved.\n";
3718316Swollman
3818316Swollman#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__)
3918316Swollmanstatic char sccsid[] = "@(#)query.c	8.1 (Berkeley) 6/5/93";
4018316Swollman#elif defined(__NetBSD__)
4118316Swollmanstatic char rcsid[] = "$NetBSD$";
4218316Swollman#endif
4318316Swollman#ident "$Revision: 1.9 $"
4418316Swollman
4518316Swollman#include <sys/param.h>
4618316Swollman#include <sys/protosw.h>
4718316Swollman#include <sys/socket.h>
4818316Swollman#include <sys/time.h>
4918316Swollman#include <netinet/in.h>
5018316Swollman#define RIPVERSION RIPv2
5118316Swollman#include <protocols/routed.h>
5218316Swollman#include <arpa/inet.h>
5318316Swollman#include <netdb.h>
5418316Swollman#include <errno.h>
5518316Swollman#include <unistd.h>
5618316Swollman#include <stdio.h>
5718316Swollman#include <stdlib.h>
5818316Swollman#include <string.h>
5918316Swollman#ifdef sgi
6018316Swollman#include <strings.h>
6118316Swollman#include <bstring.h>
6218316Swollman#endif
6318316Swollman
6418316Swollman#ifndef sgi
6518316Swollman#define _HAVE_SIN_LEN
6618316Swollman#endif
6718316Swollman
6819880Swollman#define MD5_DIGEST_LEN 16
6919880Swollmantypedef struct {
7019880Swollman	u_int32_t state[4];		/* state (ABCD) */
7119880Swollman	u_int32_t count[2];		/* # of bits, modulo 2^64 (LSB 1st) */
7219880Swollman	unsigned char buffer[64];	/* input buffer */
7319880Swollman} MD5_CTX;
7419880Swollmanextern void MD5Init(MD5_CTX*);
7519880Swollmanextern void MD5Update(MD5_CTX*, u_char*, u_int);
7619880Swollmanextern void MD5Final(u_char[MD5_DIGEST_LEN], MD5_CTX*);
7719880Swollman
7819880Swollman
7918316Swollman#define	WTIME	15		/* Time to wait for all responses */
8018316Swollman#define	STIME	(250*1000)	/* usec to wait for another response */
8118316Swollman
8218316Swollmanint	s;
8318316Swollman
8418316Swollmanchar	*pgmname;
8518316Swollman
8618316Swollmanunion {
8718316Swollman	struct rip rip;
8818316Swollman	char	packet[MAXPACKETSIZE+MAXPATHLEN];
8918316Swollman} omsg_buf;
9018316Swollman#define OMSG omsg_buf.rip
9118316Swollmanint omsg_len = sizeof(struct rip);
9218316Swollman
9318316Swollmanunion {
9418316Swollman	struct	rip rip;
9518316Swollman	char	packet[MAXPACKETSIZE+1024];
9618316Swollman	} imsg_buf;
9718316Swollman#define IMSG imsg_buf.rip
9818316Swollman
9918316Swollmanint	nflag;				/* numbers, no names */
10018316Swollmanint	pflag;				/* play the `gated` game */
10118316Swollmanint	ripv2 = 1;			/* use RIP version 2 */
10218316Swollmanint	wtime = WTIME;
10318316Swollmanint	rflag;				/* 1=ask about a particular route */
10419880Swollmanint	trace, not_trace;		/* send trace command or not */
10519880Swollmanint	auth_type = RIP_AUTH_NONE;
10619880Swollmanchar	passwd[RIP_AUTH_PW_LEN];
10719880Swollmanu_long	keyid;
10818316Swollman
10918316Swollmanstruct timeval sent;			/* when query sent */
11018316Swollman
11118316Swollmanstatic void rip_input(struct sockaddr_in*, int);
11218316Swollmanstatic int out(char *);
11318316Swollmanstatic void trace_loop(char *argv[]);
11418316Swollmanstatic void query_loop(char *argv[], int);
11518316Swollmanstatic int getnet(char *, struct netinfo *);
11618316Swollmanstatic u_int std_mask(u_int);
11719880Swollmanstatic int parse_quote(char **, char *, char *, char *, int);
11818316Swollman
11918316Swollman
12018316Swollmanint
12118316Swollmanmain(int argc,
12218316Swollman     char *argv[])
12318316Swollman{
12418316Swollman	int ch, bsize;
12519880Swollman	char *p, *options, *value, delim;
12618316Swollman
12718316Swollman	OMSG.rip_nets[0].n_dst = RIP_DEFAULT;
12818316Swollman	OMSG.rip_nets[0].n_family = RIP_AF_UNSPEC;
12918316Swollman	OMSG.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY);
13018316Swollman
13118316Swollman	pgmname = argv[0];
13219880Swollman	while ((ch = getopt(argc, argv, "np1w:r:t:a:")) != EOF)
13318316Swollman		switch (ch) {
13418316Swollman		case 'n':
13518316Swollman			not_trace = 1;
13618316Swollman			nflag = 1;
13718316Swollman			break;
13818316Swollman
13918316Swollman		case 'p':
14018316Swollman			not_trace = 1;
14118316Swollman			pflag = 1;
14218316Swollman			break;
14318316Swollman
14418316Swollman		case '1':
14518316Swollman			ripv2 = 0;
14618316Swollman			break;
14718316Swollman
14818316Swollman		case 'w':
14918316Swollman			not_trace = 1;
15018316Swollman			wtime = (int)strtoul(optarg, &p, 0);
15118316Swollman			if (*p != '\0'
15218316Swollman			    || wtime <= 0)
15318316Swollman				goto usage;
15418316Swollman			break;
15518316Swollman
15618316Swollman		case 'r':
15718316Swollman			not_trace = 1;
15818316Swollman			if (rflag)
15918316Swollman				goto usage;
16018316Swollman			rflag = getnet(optarg, &OMSG.rip_nets[0]);
16118316Swollman			if (!rflag) {
16218316Swollman				struct hostent *hp = gethostbyname(optarg);
16318316Swollman				if (hp == 0) {
16418316Swollman					fprintf(stderr, "%s: %s:",
16518316Swollman						pgmname, optarg);
16618316Swollman					herror(0);
16718316Swollman					exit(1);
16818316Swollman				}
16918316Swollman				bcopy(hp->h_addr, &OMSG.rip_nets[0].n_dst,
17018316Swollman				      sizeof(OMSG.rip_nets[0].n_dst));
17118316Swollman				OMSG.rip_nets[0].n_family = RIP_AF_INET;
17218316Swollman				OMSG.rip_nets[0].n_mask = -1;
17318316Swollman				rflag = 1;
17418316Swollman			}
17518316Swollman			break;
17618316Swollman
17718316Swollman		case 't':
17818316Swollman			trace = 1;
17918316Swollman			options = optarg;
18018316Swollman			while (*options != '\0') {
18118316Swollman				char *traceopts[] = {
18218316Swollman#				    define TRACE_ON	0
18318316Swollman					"on",
18418316Swollman#				    define TRACE_MORE	1
18518316Swollman					"more",
18618316Swollman#				    define TRACE_OFF	2
18718316Swollman					"off",
18818316Swollman#				    define TRACE_DUMP	3
18918316Swollman					"dump",
19018316Swollman					0
19118316Swollman				};
19218316Swollman				switch (getsubopt(&options,traceopts,&value)) {
19318316Swollman				case TRACE_ON:
19418316Swollman					OMSG.rip_cmd = RIPCMD_TRACEON;
19518316Swollman					if (!value
19618316Swollman					    || strlen(value) > MAXPATHLEN)
19718316Swollman						goto usage;
19818316Swollman					break;
19918316Swollman				case TRACE_MORE:
20018316Swollman					if (value)
20118316Swollman						goto usage;
20218316Swollman					OMSG.rip_cmd = RIPCMD_TRACEON;
20318316Swollman					value = "";
20418316Swollman					break;
20518316Swollman				case TRACE_OFF:
20618316Swollman					if (value)
20718316Swollman						goto usage;
20818316Swollman					OMSG.rip_cmd = RIPCMD_TRACEOFF;
20918316Swollman					value = "";
21018316Swollman					break;
21118316Swollman				case TRACE_DUMP:
21218316Swollman					if (value)
21318316Swollman						goto usage;
21418316Swollman					OMSG.rip_cmd = RIPCMD_TRACEON;
21518316Swollman					value = "dump/../table";
21618316Swollman					break;
21718316Swollman				default:
21818316Swollman					goto usage;
21918316Swollman				}
22018316Swollman				strcpy((char*)OMSG.rip_tracefile, value);
22118316Swollman				omsg_len += strlen(value) - sizeof(OMSG.ripun);
22218316Swollman			}
22318316Swollman			break;
22418316Swollman
22519880Swollman		case 'a':
22619880Swollman			not_trace = 1;
22719880Swollman			p = strchr(optarg,'=');
22819880Swollman			if (!p)
22919880Swollman				goto usage;
23019880Swollman			*p++ = '\0';
23119880Swollman			if (!strcasecmp("passwd",optarg))
23219880Swollman				auth_type = RIP_AUTH_PW;
23319880Swollman			else if (!strcasecmp("md5_passwd",optarg))
23419880Swollman				auth_type = RIP_AUTH_MD5;
23519880Swollman			else
23619880Swollman				goto usage;
23719880Swollman			if (0 > parse_quote(&p,"|",&delim,
23819880Swollman					    passwd,sizeof(passwd)))
23919880Swollman				goto usage;
24019880Swollman			if (auth_type == RIP_AUTH_MD5
24119880Swollman			    && delim == '|') {
24219880Swollman				keyid = strtoul(p+1,&p,0);
24319880Swollman				if (keyid > 255 || *p != '\0')
24419880Swollman					goto usage;
24519880Swollman			} else if (delim != '\0') {
24619880Swollman				goto usage;
24719880Swollman			}
24819880Swollman			break;
24919880Swollman
25018316Swollman		default:
25118316Swollman			goto usage;
25218316Swollman	}
25318316Swollman	argv += optind;
25418316Swollman	argc -= optind;
25518316Swollman	if ((not_trace && trace) || argc == 0) {
25618316Swollmanusage:		fprintf(stderr, "%s: [-np1v] [-r tgt_rt] [-w wtime]"
25719880Swollman			" [-a type=passwd] host1 [host2 ...]\n"
25819880Swollman			"or\t-t {on=filename|more|off|on=dump/../table}"
25919880Swollman			" host1 [host2 ...]\n",
26018316Swollman			pgmname);
26118316Swollman		exit(1);
26218316Swollman	}
26318316Swollman
26418316Swollman	s = socket(AF_INET, SOCK_DGRAM, 0);
26518316Swollman	if (s < 0) {
26618316Swollman		perror("socket");
26718316Swollman		exit(2);
26818316Swollman	}
26918316Swollman
27018316Swollman	/* be prepared to receive a lot of routes */
27118316Swollman	for (bsize = 127*1024; ; bsize -= 1024) {
27218316Swollman		if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
27318316Swollman			       &bsize, sizeof(bsize)) == 0)
27418316Swollman			break;
27518316Swollman		if (bsize <= 4*1024) {
27618316Swollman			perror("setsockopt SO_RCVBUF");
27718316Swollman			break;
27818316Swollman		}
27918316Swollman	}
28018316Swollman
28118316Swollman	if (trace)
28218316Swollman		trace_loop(argv);
28318316Swollman	else
28418316Swollman		query_loop(argv, argc);
28518316Swollman	/* NOTREACHED */
28618316Swollman}
28718316Swollman
28818316Swollman
28918316Swollman/* tell the target hosts about tracing
29018316Swollman */
29118316Swollmanstatic void
29218316Swollmantrace_loop(char *argv[])
29318316Swollman{
29418316Swollman	struct sockaddr_in myaddr;
29518316Swollman	int res;
29618316Swollman
29718316Swollman	if (geteuid() != 0) {
29818316Swollman		(void)fprintf(stderr, "-t requires UID 0\n");
29918316Swollman		exit(1);
30018316Swollman	}
30118316Swollman
30218316Swollman	if (ripv2) {
30318316Swollman		OMSG.rip_vers = RIPv2;
30418316Swollman	} else {
30518316Swollman		OMSG.rip_vers = RIPv1;
30618316Swollman	}
30718316Swollman
30818316Swollman	bzero(&myaddr, sizeof(myaddr));
30918316Swollman	myaddr.sin_family = AF_INET;
31018316Swollman#ifdef _HAVE_SIN_LEN
31118316Swollman	myaddr.sin_len = sizeof(myaddr);
31218316Swollman#endif
31318316Swollman	myaddr.sin_port = htons(IPPORT_RESERVED-1);
31418316Swollman	while (bind(s, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
31518316Swollman		if (errno != EADDRINUSE
31618316Swollman		    || myaddr.sin_port == 0) {
31718316Swollman			perror("bind");
31818316Swollman			exit(2);
31918316Swollman		}
32018316Swollman		myaddr.sin_port = htons(ntohs(myaddr.sin_port)-1);
32118316Swollman	}
32218316Swollman
32318316Swollman	res = 1;
32418316Swollman	while (*argv != 0) {
32518316Swollman		if (out(*argv++) <= 0)
32618316Swollman			res = 0;
32718316Swollman	}
32818316Swollman	exit(res);
32918316Swollman}
33018316Swollman
33118316Swollman
33218316Swollman/* query all of the listed hosts
33318316Swollman */
33418316Swollmanstatic void
33518316Swollmanquery_loop(char *argv[], int argc)
33618316Swollman{
33719880Swollman#	define NA0 (OMSG.rip_auths[0])
33819880Swollman#	define NA2 (OMSG.rip_auths[2])
33918316Swollman	struct seen {
34018316Swollman		struct seen *next;
34118316Swollman		struct in_addr addr;
34218316Swollman	} *seen, *sp;
34318316Swollman	int answered = 0;
34418316Swollman	int cc;
34518316Swollman	fd_set bits;
34618316Swollman	struct timeval now, delay;
34718316Swollman	struct sockaddr_in from;
34818316Swollman	int fromlen;
34919880Swollman	MD5_CTX md5_ctx;
35018316Swollman
35118316Swollman
35218316Swollman	OMSG.rip_cmd = (pflag) ? RIPCMD_POLL : RIPCMD_REQUEST;
35318316Swollman	if (ripv2) {
35418316Swollman		OMSG.rip_vers = RIPv2;
35519880Swollman		if (auth_type == RIP_AUTH_PW) {
35619880Swollman			OMSG.rip_nets[1] = OMSG.rip_nets[0];
35719880Swollman			NA0.a_family = RIP_AF_AUTH;
35819880Swollman			NA0.a_type = RIP_AUTH_PW;
35919880Swollman			bcopy(passwd, NA0.au.au_pw,
36019880Swollman			      RIP_AUTH_PW_LEN);
36119880Swollman			omsg_len += sizeof(OMSG.rip_nets[0]);
36219880Swollman
36319880Swollman		} else if (auth_type == RIP_AUTH_MD5) {
36419880Swollman			OMSG.rip_nets[1] = OMSG.rip_nets[0];
36519880Swollman			NA0.a_family = RIP_AF_AUTH;
36619880Swollman			NA0.a_type = RIP_AUTH_MD5;
36719880Swollman			NA0.au.a_md5.md5_keyid = (int8_t)keyid;
36819880Swollman			NA0.au.a_md5.md5_auth_len = RIP_AUTH_PW_LEN;
36919880Swollman			NA0.au.a_md5.md5_seqno = 0;
37019880Swollman			NA0.au.a_md5.md5_pkt_len = sizeof(OMSG.rip_nets[1]);
37119880Swollman			NA2.a_family = RIP_AF_AUTH;
37219880Swollman			NA2.a_type = 1;
37319880Swollman			bcopy(passwd, NA2.au.au_pw, sizeof(NA2.au.au_pw));
37419880Swollman			MD5Init(&md5_ctx);
37519880Swollman			MD5Update(&md5_ctx, (u_char *)&NA0,
37619880Swollman				  (char *)(&NA2+1) - (char *)&NA0);
37719880Swollman			MD5Final(NA2.au.au_pw, &md5_ctx);
37819880Swollman			omsg_len += 2*sizeof(OMSG.rip_nets[0]);
37919880Swollman		}
38019880Swollman
38118316Swollman	} else {
38218316Swollman		OMSG.rip_vers = RIPv1;
38318316Swollman		OMSG.rip_nets[0].n_mask = 0;
38418316Swollman	}
38518316Swollman
38618316Swollman	/* ask the first (valid) host */
38718316Swollman	seen = 0;
38818316Swollman	while (0 > out(*argv++)) {
38918316Swollman		if (*argv == 0)
39018316Swollman			exit(-1);
39118316Swollman		answered++;
39218316Swollman	}
39318316Swollman
39418316Swollman	FD_ZERO(&bits);
39518316Swollman	for (;;) {
39618316Swollman		FD_SET(s, &bits);
39718316Swollman		delay.tv_sec = 0;
39818316Swollman		delay.tv_usec = STIME;
39918316Swollman		cc = select(s+1, &bits, 0,0, &delay);
40018316Swollman		if (cc > 0) {
40118316Swollman			fromlen = sizeof(from);
40218316Swollman			cc = recvfrom(s, imsg_buf.packet,
40318316Swollman				      sizeof(imsg_buf.packet), 0,
40418316Swollman				      (struct sockaddr *)&from, &fromlen);
40518316Swollman			if (cc < 0) {
40618316Swollman				perror("recvfrom");
40718316Swollman				exit(1);
40818316Swollman			}
40918316Swollman			/* count the distinct responding hosts.
41018316Swollman			 * You cannot match responding hosts with
41118316Swollman			 * addresses to which queries were transmitted,
41218316Swollman			 * because a router might respond with a
41318316Swollman			 * different source address.
41418316Swollman			 */
41518316Swollman			for (sp = seen; sp != 0; sp = sp->next) {
41618316Swollman				if (sp->addr.s_addr == from.sin_addr.s_addr)
41718316Swollman					break;
41818316Swollman			}
41918316Swollman			if (sp == 0) {
42018316Swollman				sp = malloc(sizeof(*sp));
42118316Swollman				sp->addr = from.sin_addr;
42218316Swollman				sp->next = seen;
42318316Swollman				seen = sp;
42418316Swollman				answered++;
42518316Swollman			}
42618316Swollman
42718316Swollman			rip_input(&from, cc);
42818316Swollman			continue;
42918316Swollman		}
43018316Swollman
43118316Swollman		if (cc < 0) {
43218316Swollman			if ( errno == EINTR)
43318316Swollman				continue;
43418316Swollman			perror("select");
43518316Swollman			exit(1);
43618316Swollman		}
43718316Swollman
43818316Swollman		/* After a pause in responses, probe another host.
43918316Swollman		 * This reduces the intermingling of answers.
44018316Swollman		 */
44118316Swollman		while (*argv != 0 && 0 > out(*argv++))
44218316Swollman			answered++;
44318316Swollman
44418316Swollman		/* continue until no more packets arrive
44518316Swollman		 * or we have heard from all hosts
44618316Swollman		 */
44718316Swollman		if (answered >= argc)
44818316Swollman			break;
44918316Swollman
45018316Swollman		/* or until we have waited a long time
45118316Swollman		 */
45218316Swollman		if (gettimeofday(&now, 0) < 0) {
45318316Swollman			perror("gettimeofday(now)");
45418316Swollman			exit(1);
45518316Swollman		}
45618316Swollman		if (sent.tv_sec + wtime <= now.tv_sec)
45718316Swollman			break;
45818316Swollman	}
45918316Swollman
46018316Swollman	/* fail if there was no answer */
46118316Swollman	exit (answered >= argc ? 0 : 1);
46218316Swollman}
46318316Swollman
46418316Swollman
46519880Swollman/* send to one host
46618316Swollman */
46718316Swollmanstatic int
46818316Swollmanout(char *host)
46918316Swollman{
47018316Swollman	struct sockaddr_in router;
47118316Swollman	struct hostent *hp;
47218316Swollman
47318316Swollman	if (gettimeofday(&sent, 0) < 0) {
47418316Swollman		perror("gettimeofday(sent)");
47518316Swollman		return -1;
47618316Swollman	}
47718316Swollman
47818316Swollman	bzero(&router, sizeof(router));
47918316Swollman	router.sin_family = AF_INET;
48018316Swollman#ifdef _HAVE_SIN_LEN
48118316Swollman	router.sin_len = sizeof(router);
48218316Swollman#endif
48318316Swollman	if (!inet_aton(host, &router.sin_addr)) {
48418316Swollman		hp = gethostbyname(host);
48518316Swollman		if (hp == 0) {
48618316Swollman			herror(host);
48718316Swollman			return -1;
48818316Swollman		}
48918316Swollman		bcopy(hp->h_addr, &router.sin_addr, sizeof(router.sin_addr));
49018316Swollman	}
49118316Swollman	router.sin_port = htons(RIP_PORT);
49218316Swollman
49318316Swollman	if (sendto(s, &omsg_buf, omsg_len, 0,
49418316Swollman		   (struct sockaddr *)&router, sizeof(router)) < 0) {
49518316Swollman		perror(host);
49618316Swollman		return -1;
49718316Swollman	}
49818316Swollman
49918316Swollman	return 0;
50018316Swollman}
50118316Swollman
50218316Swollman
50318316Swollman/*
50419880Swollman * Convert string to printable characters
50519880Swollman */
50619880Swollmanstatic char *
50719880Swollmanqstring(u_char *s, int len)
50819880Swollman{
50919880Swollman	static char buf[8*20+1];
51019880Swollman	char *p;
51119880Swollman	u_char *s2, c;
51219880Swollman
51319880Swollman
51419880Swollman	for (p = buf; len != 0 && p < &buf[sizeof(buf)-1]; len--) {
51519880Swollman		c = *s++;
51619880Swollman		if (c == '\0') {
51719880Swollman			for (s2 = s+1; s2 < &s[len]; s2++) {
51819880Swollman				if (*s2 != '\0')
51919880Swollman					break;
52019880Swollman			}
52119880Swollman			if (s2 >= &s[len])
52219880Swollman			    goto exit;
52319880Swollman		}
52419880Swollman
52519880Swollman		if (c >= ' ' && c < 0x7f && c != '\\') {
52619880Swollman			*p++ = c;
52719880Swollman			continue;
52819880Swollman		}
52919880Swollman		*p++ = '\\';
53019880Swollman		switch (c) {
53119880Swollman		case '\\':
53219880Swollman			*p++ = '\\';
53319880Swollman			break;
53419880Swollman		case '\n':
53519880Swollman			*p++= 'n';
53619880Swollman			break;
53719880Swollman		case '\r':
53819880Swollman			*p++= 'r';
53919880Swollman			break;
54019880Swollman		case '\t':
54119880Swollman			*p++ = 't';
54219880Swollman			break;
54319880Swollman		case '\b':
54419880Swollman			*p++ = 'b';
54519880Swollman			break;
54619880Swollman		default:
54719880Swollman			p += sprintf(p,"%o",c);
54819880Swollman			break;
54919880Swollman		}
55019880Swollman	}
55119880Swollmanexit:
55219880Swollman	*p = '\0';
55319880Swollman	return buf;
55419880Swollman}
55519880Swollman
55619880Swollman
55719880Swollman/*
55818316Swollman * Handle an incoming RIP packet.
55918316Swollman */
56018316Swollmanstatic void
56118316Swollmanrip_input(struct sockaddr_in *from,
56218316Swollman	  int size)
56318316Swollman{
56418316Swollman	struct netinfo *n, *lim;
56518316Swollman	struct in_addr in;
56618316Swollman	char *name;
56718316Swollman	char net_buf[80];
56818316Swollman	u_int mask, dmask;
56918316Swollman	char *sp;
57018316Swollman	int i;
57118316Swollman	struct hostent *hp;
57218316Swollman	struct netent *np;
57319880Swollman	struct netauth *na;
57418316Swollman
57518316Swollman
57618316Swollman	if (nflag) {
57718316Swollman		printf("%s:", inet_ntoa(from->sin_addr));
57818316Swollman	} else {
57918316Swollman		hp = gethostbyaddr((char*)&from->sin_addr,
58018316Swollman				   sizeof(struct in_addr), AF_INET);
58118316Swollman		if (hp == 0) {
58218316Swollman			printf("%s:",
58318316Swollman			       inet_ntoa(from->sin_addr));
58418316Swollman		} else {
58518316Swollman			printf("%s (%s):", hp->h_name,
58618316Swollman			       inet_ntoa(from->sin_addr));
58718316Swollman		}
58818316Swollman	}
58918316Swollman	if (IMSG.rip_cmd != RIPCMD_RESPONSE) {
59018316Swollman		printf("\n    unexpected response type %d\n", IMSG.rip_cmd);
59118316Swollman		return;
59218316Swollman	}
59318316Swollman	printf(" RIPv%d%s %d bytes\n", IMSG.rip_vers,
59418316Swollman	       (IMSG.rip_vers != RIPv1 && IMSG.rip_vers != RIPv2) ? " ?" : "",
59518316Swollman	       size);
59618316Swollman	if (size > MAXPACKETSIZE) {
59718316Swollman		if (size > sizeof(imsg_buf) - sizeof(*n)) {
59818316Swollman			printf("       at least %d bytes too long\n",
59918316Swollman			       size-MAXPACKETSIZE);
60018316Swollman			size = sizeof(imsg_buf) - sizeof(*n);
60118316Swollman		} else {
60218316Swollman			printf("       %d bytes too long\n",
60318316Swollman			       size-MAXPACKETSIZE);
60418316Swollman		}
60518316Swollman	} else if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
60618316Swollman		printf("    response of bad length=%d\n", size);
60718316Swollman	}
60818316Swollman
60918316Swollman	n = IMSG.rip_nets;
61018316Swollman	lim = (struct netinfo *)((char*)n + size) - 1;
61118316Swollman	for (; n <= lim; n++) {
61218316Swollman		name = "";
61318316Swollman		if (n->n_family == RIP_AF_INET) {
61418316Swollman			in.s_addr = n->n_dst;
61518316Swollman			(void)strcpy(net_buf, inet_ntoa(in));
61618316Swollman
61718316Swollman			mask = ntohl(n->n_mask);
61818316Swollman			dmask = mask & -mask;
61918316Swollman			if (mask != 0) {
62018316Swollman				sp = &net_buf[strlen(net_buf)];
62118316Swollman				if (IMSG.rip_vers == RIPv1) {
62218316Swollman					(void)sprintf(sp," mask=%#x ? ",mask);
62318316Swollman					mask = 0;
62418316Swollman				} else if (mask + dmask == 0) {
62518316Swollman					for (i = 0;
62618316Swollman					     (i != 32
62718316Swollman					      && ((1<<i)&mask) == 0);
62818316Swollman					     i++)
62918316Swollman						continue;
63018316Swollman					(void)sprintf(sp, "/%d",32-i);
63118316Swollman				} else {
63218316Swollman					(void)sprintf(sp," (mask %#x)", mask);
63318316Swollman				}
63418316Swollman			}
63518316Swollman
63618316Swollman			if (!nflag) {
63718316Swollman				if (mask == 0) {
63818316Swollman					mask = std_mask(in.s_addr);
63918316Swollman					if ((ntohl(in.s_addr) & ~mask) != 0)
64018316Swollman						mask = 0;
64118316Swollman				}
64218316Swollman				/* Without a netmask, do not worry about
64318316Swollman				 * whether the destination is a host or a
64418316Swollman				 * network. Try both and use the first name
64518316Swollman				 * we get.
64618316Swollman				 *
64718316Swollman				 * If we have a netmask we can make a
64818316Swollman				 * good guess.
64918316Swollman				 */
65018316Swollman				if ((in.s_addr & ~mask) == 0) {
65118316Swollman					np = getnetbyaddr((long)in.s_addr,
65218316Swollman							  AF_INET);
65318316Swollman					if (np != 0)
65418316Swollman						name = np->n_name;
65518316Swollman					else if (in.s_addr == 0)
65618316Swollman						name = "default";
65718316Swollman				}
65818316Swollman				if (name[0] == '\0'
65918316Swollman				    && ((in.s_addr & ~mask) != 0
66018316Swollman					|| mask == 0xffffffff)) {
66118316Swollman					hp = gethostbyaddr((char*)&in,
66218316Swollman							   sizeof(in),
66318316Swollman							   AF_INET);
66418316Swollman					if (hp != 0)
66518316Swollman						name = hp->h_name;
66618316Swollman				}
66718316Swollman			}
66818316Swollman
66918316Swollman		} else if (n->n_family == RIP_AF_AUTH) {
67019880Swollman			na = (struct netauth*)n;
67119880Swollman			if (na->a_type == RIP_AUTH_PW
67219880Swollman			    && n == IMSG.rip_nets) {
67319880Swollman				(void)printf("  Password Authentication:"
67419880Swollman					     " \"%s\"\n",
67519880Swollman					     qstring(na->au.au_pw,
67619880Swollman						     RIP_AUTH_PW_LEN));
67719880Swollman				continue;
67819880Swollman			}
67919880Swollman
68019880Swollman			if (na->a_type == RIP_AUTH_MD5
68119880Swollman			    && n == IMSG.rip_nets) {
68219880Swollman				(void)printf("  MD5 Authentication"
68319880Swollman					     " len=%d KeyID=%d"
68419880Swollman					     " seqno=%d"
68519880Swollman					     " rsvd=%#x,%#x\n",
68619880Swollman					     na->au.a_md5.md5_pkt_len,
68719880Swollman					     na->au.a_md5.md5_keyid,
68819880Swollman					     na->au.a_md5.md5_seqno,
68919880Swollman					     na->au.a_md5.rsvd[0],
69019880Swollman					     na->au.a_md5.rsvd[1]);
69119880Swollman				continue;
69219880Swollman			}
69319880Swollman			(void)printf("  Authentication type %d: ",
69419880Swollman				     ntohs(na->a_type));
69519880Swollman			for (i = 0; i < sizeof(na->au.au_pw); i++)
69619880Swollman				(void)printf("%02x ", na->au.au_pw[i]);
69718316Swollman			putc('\n', stdout);
69818316Swollman			continue;
69918316Swollman
70018316Swollman		} else {
70118316Swollman			(void)sprintf(net_buf, "(af %#x) %d.%d.%d.%d",
70218316Swollman				      ntohs(n->n_family),
70318316Swollman				      (char)(n->n_dst >> 24),
70418316Swollman				      (char)(n->n_dst >> 16),
70518316Swollman				      (char)(n->n_dst >> 8),
70618316Swollman				      (char)n->n_dst);
70718316Swollman		}
70818316Swollman
70918316Swollman		(void)printf("  %-18s metric %2d %-10s",
71018316Swollman			     net_buf, ntohl(n->n_metric), name);
71118316Swollman
71218316Swollman		if (n->n_nhop != 0) {
71318316Swollman			in.s_addr = n->n_nhop;
71418316Swollman			if (nflag)
71518316Swollman				hp = 0;
71618316Swollman			else
71718316Swollman				hp = gethostbyaddr((char*)&in, sizeof(in),
71818316Swollman						   AF_INET);
71918316Swollman			(void)printf(" nhop=%-15s%s",
72018316Swollman				     (hp != 0) ? hp->h_name : inet_ntoa(in),
72118316Swollman				     (IMSG.rip_vers == RIPv1) ? " ?" : "");
72218316Swollman		}
72318316Swollman		if (n->n_tag != 0)
72418316Swollman			(void)printf(" tag=%#x%s", n->n_tag,
72518316Swollman				     (IMSG.rip_vers == RIPv1) ? " ?" : "");
72618316Swollman		putc('\n', stdout);
72718316Swollman	}
72818316Swollman}
72918316Swollman
73018316Swollman
73118316Swollman/* Return the classical netmask for an IP address.
73218316Swollman */
73318316Swollmanstatic u_int
73418316Swollmanstd_mask(u_int addr)			/* in network order */
73518316Swollman{
73618316Swollman	NTOHL(addr);			/* was a host, not a network */
73718316Swollman
73818316Swollman	if (addr == 0)			/* default route has mask 0 */
73918316Swollman		return 0;
74018316Swollman	if (IN_CLASSA(addr))
74118316Swollman		return IN_CLASSA_NET;
74218316Swollman	if (IN_CLASSB(addr))
74318316Swollman		return IN_CLASSB_NET;
74418316Swollman	return IN_CLASSC_NET;
74518316Swollman}
74618316Swollman
74718316Swollman
74818316Swollman/* get a network number as a name or a number, with an optional "/xx"
74918316Swollman * netmask.
75018316Swollman */
75118316Swollmanstatic int				/* 0=bad */
75218316Swollmangetnet(char *name,
75318316Swollman       struct netinfo *rt)
75418316Swollman{
75518316Swollman	int i;
75618316Swollman	struct netent *nentp;
75718316Swollman	u_int mask;
75818316Swollman	struct in_addr in;
75918316Swollman	char hname[MAXHOSTNAMELEN+1];
76018316Swollman	char *mname, *p;
76118316Swollman
76218316Swollman
76318316Swollman	/* Detect and separate "1.2.3.4/24"
76418316Swollman	 */
76518316Swollman	if (0 != (mname = rindex(name,'/'))) {
76618316Swollman		i = (int)(mname - name);
76718316Swollman		if (i > sizeof(hname)-1)	/* name too long */
76818316Swollman			return 0;
76918316Swollman		bcopy(name, hname, i);
77018316Swollman		hname[i] = '\0';
77118316Swollman		mname++;
77218316Swollman		name = hname;
77318316Swollman	}
77418316Swollman
77518316Swollman	nentp = getnetbyname(name);
77618316Swollman	if (nentp != 0) {
77718316Swollman		in.s_addr = nentp->n_net;
77818316Swollman	} else if (inet_aton(name, &in) == 1) {
77918316Swollman		NTOHL(in.s_addr);
78018316Swollman	} else {
78118316Swollman		return 0;
78218316Swollman	}
78318316Swollman
78418316Swollman	if (mname == 0) {
78518316Swollman		mask = std_mask(in.s_addr);
78618316Swollman		if ((~mask & in.s_addr) != 0)
78718316Swollman			mask = 0xffffffff;
78818316Swollman	} else {
78918316Swollman		mask = (u_int)strtoul(mname, &p, 0);
79018316Swollman		if (*p != '\0' || mask > 32)
79118316Swollman			return 0;
79218316Swollman		mask = 0xffffffff << (32-mask);
79318316Swollman	}
79418316Swollman
79518316Swollman	rt->n_dst = htonl(in.s_addr);
79618316Swollman	rt->n_family = RIP_AF_INET;
79718316Swollman	rt->n_mask = htonl(mask);
79818316Swollman	return 1;
79918316Swollman}
80019880Swollman
80119880Swollman
80219880Swollman/* strtok(), but honoring backslash
80319880Swollman */
80419880Swollmanstatic int				/* -1=bad */
80519880Swollmanparse_quote(char **linep,
80619880Swollman	    char *delims,
80719880Swollman	    char *delimp,
80819880Swollman	    char *buf,
80919880Swollman	    int	lim)
81019880Swollman{
81119880Swollman	char c, *pc, *p;
81219880Swollman
81319880Swollman
81419880Swollman	pc = *linep;
81519880Swollman	if (*pc == '\0')
81619880Swollman		return -1;
81719880Swollman
81819880Swollman	for (;;) {
81919880Swollman		if (lim == 0)
82019880Swollman			return -1;
82119880Swollman		c = *pc++;
82219880Swollman		if (c == '\0')
82319880Swollman			break;
82419880Swollman
82519880Swollman		if (c == '\\' && pc != '\0') {
82619880Swollman			if ((c = *pc++) == 'n') {
82719880Swollman				c = '\n';
82819880Swollman			} else if (c == 'r') {
82919880Swollman				c = '\r';
83019880Swollman			} else if (c == 't') {
83119880Swollman				c = '\t';
83219880Swollman			} else if (c == 'b') {
83319880Swollman				c = '\b';
83419880Swollman			} else if (c >= '0' && c <= '7') {
83519880Swollman				c -= '0';
83619880Swollman				if (*pc >= '0' && *pc <= '7') {
83719880Swollman					c = (c<<3)+(*pc++ - '0');
83819880Swollman					if (*pc >= '0' && *pc <= '7')
83919880Swollman					    c = (c<<3)+(*pc++ - '0');
84019880Swollman				}
84119880Swollman			}
84219880Swollman
84319880Swollman		} else {
84419880Swollman			for (p = delims; *p != '\0'; ++p) {
84519880Swollman				if (*p == c)
84619880Swollman					goto exit;
84719880Swollman			}
84819880Swollman		}
84919880Swollman
85019880Swollman		*buf++ = c;
85119880Swollman		--lim;
85219880Swollman	}
85319880Swollmanexit:
85419880Swollman	if (delimp != 0)
85519880Swollman		*delimp = c;
85619880Swollman	*linep = pc-1;
85719880Swollman	if (lim != 0)
85819880Swollman		*buf = '\0';
85919880Swollman	return 0;
86019880Swollman}
861