rtquery.c revision 32502
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
3432502Scharnier#ifndef lint
3532502Scharnierstatic const char copyright[] =
3618316Swollman"@(#) Copyright (c) 1982, 1986, 1993\n\
3718316Swollman	The Regents of the University of California.  All rights reserved.\n";
3832502Scharnier#endif /* not lint */
3918316Swollman
4032502Scharnier#ifndef lint
4132502Scharnier#if 0
4218316Swollmanstatic char sccsid[] = "@(#)query.c	8.1 (Berkeley) 6/5/93";
4318316Swollman#endif
4432502Scharnierstatic const char rcsid[] =
4532502Scharnier	"$Id$";
4632502Scharnier#endif /* not lint */
4718316Swollman
4818316Swollman#include <sys/param.h>
4918316Swollman#include <sys/socket.h>
5018316Swollman#include <sys/time.h>
5118316Swollman#include <netinet/in.h>
5218316Swollman#define RIPVERSION RIPv2
5318316Swollman#include <protocols/routed.h>
5418316Swollman#include <arpa/inet.h>
5532502Scharnier#include <err.h>
5632502Scharnier#include <errno.h>
5718316Swollman#include <netdb.h>
5818316Swollman#include <stdio.h>
5918316Swollman#include <stdlib.h>
6018316Swollman#include <string.h>
6132502Scharnier#include <unistd.h>
6218316Swollman#ifdef sgi
6318316Swollman#include <strings.h>
6418316Swollman#include <bstring.h>
6518316Swollman#endif
6618316Swollman
6718316Swollman#ifndef sgi
6818316Swollman#define _HAVE_SIN_LEN
6918316Swollman#endif
7018316Swollman
7119885Swollman#include <md5.h>
7218316Swollman#define	WTIME	15		/* Time to wait for all responses */
7318316Swollman#define	STIME	(250*1000)	/* usec to wait for another response */
7418316Swollman
7518316Swollmanint	s;
7618316Swollman
7718316Swollmanunion {
7818316Swollman	struct rip rip;
7918316Swollman	char	packet[MAXPACKETSIZE+MAXPATHLEN];
8018316Swollman} omsg_buf;
8118316Swollman#define OMSG omsg_buf.rip
8218316Swollmanint omsg_len = sizeof(struct rip);
8318316Swollman
8418316Swollmanunion {
8518316Swollman	struct	rip rip;
8618316Swollman	char	packet[MAXPACKETSIZE+1024];
8718316Swollman	} imsg_buf;
8818316Swollman#define IMSG imsg_buf.rip
8918316Swollman
9018316Swollmanint	nflag;				/* numbers, no names */
9118316Swollmanint	pflag;				/* play the `gated` game */
9218316Swollmanint	ripv2 = 1;			/* use RIP version 2 */
9318316Swollmanint	wtime = WTIME;
9418316Swollmanint	rflag;				/* 1=ask about a particular route */
9519880Swollmanint	trace, not_trace;		/* send trace command or not */
9619880Swollmanint	auth_type = RIP_AUTH_NONE;
9719880Swollmanchar	passwd[RIP_AUTH_PW_LEN];
9819880Swollmanu_long	keyid;
9918316Swollman
10018316Swollmanstruct timeval sent;			/* when query sent */
10118316Swollman
10218316Swollmanstatic void rip_input(struct sockaddr_in*, int);
10318316Swollmanstatic int out(char *);
10418316Swollmanstatic void trace_loop(char *argv[]);
10518316Swollmanstatic void query_loop(char *argv[], int);
10618316Swollmanstatic int getnet(char *, struct netinfo *);
10718316Swollmanstatic u_int std_mask(u_int);
10819880Swollmanstatic int parse_quote(char **, char *, char *, char *, int);
10918316Swollman
11018316Swollman
11120609Swollmanvoid
11218316Swollmanmain(int argc,
11318316Swollman     char *argv[])
11418316Swollman{
11518316Swollman	int ch, bsize;
11619880Swollman	char *p, *options, *value, delim;
11718316Swollman
11818316Swollman	OMSG.rip_nets[0].n_dst = RIP_DEFAULT;
11918316Swollman	OMSG.rip_nets[0].n_family = RIP_AF_UNSPEC;
12018316Swollman	OMSG.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY);
12118316Swollman
12224359Simp	while ((ch = getopt(argc, argv, "np1w:r:t:a:")) != -1)
12318316Swollman		switch (ch) {
12418316Swollman		case 'n':
12518316Swollman			not_trace = 1;
12618316Swollman			nflag = 1;
12718316Swollman			break;
12818316Swollman
12918316Swollman		case 'p':
13018316Swollman			not_trace = 1;
13118316Swollman			pflag = 1;
13218316Swollman			break;
13318316Swollman
13418316Swollman		case '1':
13518316Swollman			ripv2 = 0;
13618316Swollman			break;
13718316Swollman
13818316Swollman		case 'w':
13918316Swollman			not_trace = 1;
14018316Swollman			wtime = (int)strtoul(optarg, &p, 0);
14118316Swollman			if (*p != '\0'
14218316Swollman			    || wtime <= 0)
14318316Swollman				goto usage;
14418316Swollman			break;
14518316Swollman
14618316Swollman		case 'r':
14718316Swollman			not_trace = 1;
14818316Swollman			if (rflag)
14918316Swollman				goto usage;
15018316Swollman			rflag = getnet(optarg, &OMSG.rip_nets[0]);
15118316Swollman			if (!rflag) {
15218316Swollman				struct hostent *hp = gethostbyname(optarg);
15318316Swollman				if (hp == 0) {
15426724Scharnier					fprintf(stderr, "rtquery: %s:", optarg);
15518316Swollman					herror(0);
15618316Swollman					exit(1);
15718316Swollman				}
15818316Swollman				bcopy(hp->h_addr, &OMSG.rip_nets[0].n_dst,
15918316Swollman				      sizeof(OMSG.rip_nets[0].n_dst));
16018316Swollman				OMSG.rip_nets[0].n_family = RIP_AF_INET;
16118316Swollman				OMSG.rip_nets[0].n_mask = -1;
16218316Swollman				rflag = 1;
16318316Swollman			}
16418316Swollman			break;
16518316Swollman
16618316Swollman		case 't':
16718316Swollman			trace = 1;
16818316Swollman			options = optarg;
16918316Swollman			while (*options != '\0') {
17018316Swollman				char *traceopts[] = {
17118316Swollman#				    define TRACE_ON	0
17218316Swollman					"on",
17318316Swollman#				    define TRACE_MORE	1
17418316Swollman					"more",
17518316Swollman#				    define TRACE_OFF	2
17618316Swollman					"off",
17718316Swollman#				    define TRACE_DUMP	3
17818316Swollman					"dump",
17918316Swollman					0
18018316Swollman				};
18118316Swollman				switch (getsubopt(&options,traceopts,&value)) {
18218316Swollman				case TRACE_ON:
18318316Swollman					OMSG.rip_cmd = RIPCMD_TRACEON;
18418316Swollman					if (!value
18518316Swollman					    || strlen(value) > MAXPATHLEN)
18618316Swollman						goto usage;
18718316Swollman					break;
18818316Swollman				case TRACE_MORE:
18918316Swollman					if (value)
19018316Swollman						goto usage;
19118316Swollman					OMSG.rip_cmd = RIPCMD_TRACEON;
19218316Swollman					value = "";
19318316Swollman					break;
19418316Swollman				case TRACE_OFF:
19518316Swollman					if (value)
19618316Swollman						goto usage;
19718316Swollman					OMSG.rip_cmd = RIPCMD_TRACEOFF;
19818316Swollman					value = "";
19918316Swollman					break;
20018316Swollman				case TRACE_DUMP:
20118316Swollman					if (value)
20218316Swollman						goto usage;
20318316Swollman					OMSG.rip_cmd = RIPCMD_TRACEON;
20418316Swollman					value = "dump/../table";
20518316Swollman					break;
20618316Swollman				default:
20718316Swollman					goto usage;
20818316Swollman				}
20918316Swollman				strcpy((char*)OMSG.rip_tracefile, value);
21018316Swollman				omsg_len += strlen(value) - sizeof(OMSG.ripun);
21118316Swollman			}
21218316Swollman			break;
21318316Swollman
21419880Swollman		case 'a':
21519880Swollman			not_trace = 1;
21619880Swollman			p = strchr(optarg,'=');
21719880Swollman			if (!p)
21819880Swollman				goto usage;
21919880Swollman			*p++ = '\0';
22019880Swollman			if (!strcasecmp("passwd",optarg))
22119880Swollman				auth_type = RIP_AUTH_PW;
22219880Swollman			else if (!strcasecmp("md5_passwd",optarg))
22319880Swollman				auth_type = RIP_AUTH_MD5;
22419880Swollman			else
22519880Swollman				goto usage;
22619880Swollman			if (0 > parse_quote(&p,"|",&delim,
22719880Swollman					    passwd,sizeof(passwd)))
22819880Swollman				goto usage;
22919880Swollman			if (auth_type == RIP_AUTH_MD5
23019880Swollman			    && delim == '|') {
23119880Swollman				keyid = strtoul(p+1,&p,0);
23219880Swollman				if (keyid > 255 || *p != '\0')
23319880Swollman					goto usage;
23419880Swollman			} else if (delim != '\0') {
23519880Swollman				goto usage;
23619880Swollman			}
23719880Swollman			break;
23819880Swollman
23918316Swollman		default:
24018316Swollman			goto usage;
24118316Swollman	}
24218316Swollman	argv += optind;
24318316Swollman	argc -= optind;
24418316Swollman	if ((not_trace && trace) || argc == 0) {
24526724Scharnierusage:		fprintf(stderr, "%s\n%s\n",
24626724Scharnier		"usage: rtquery [-np1v] [-r addr] [-w timeout] [-a secret] host ...",
24726724Scharnier		"       rtquery [-t op] host ...");
24818316Swollman		exit(1);
24918316Swollman	}
25018316Swollman
25118316Swollman	s = socket(AF_INET, SOCK_DGRAM, 0);
25232502Scharnier	if (s < 0)
25332502Scharnier		err(2, "socket");
25418316Swollman
25518316Swollman	/* be prepared to receive a lot of routes */
25618316Swollman	for (bsize = 127*1024; ; bsize -= 1024) {
25718316Swollman		if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
25818316Swollman			       &bsize, sizeof(bsize)) == 0)
25918316Swollman			break;
26018316Swollman		if (bsize <= 4*1024) {
26132502Scharnier			warn("setsockopt SO_RCVBUF");
26218316Swollman			break;
26318316Swollman		}
26418316Swollman	}
26518316Swollman
26618316Swollman	if (trace)
26718316Swollman		trace_loop(argv);
26818316Swollman	else
26918316Swollman		query_loop(argv, argc);
27018316Swollman	/* NOTREACHED */
27118316Swollman}
27218316Swollman
27318316Swollman
27418316Swollman/* tell the target hosts about tracing
27518316Swollman */
27618316Swollmanstatic void
27718316Swollmantrace_loop(char *argv[])
27818316Swollman{
27918316Swollman	struct sockaddr_in myaddr;
28018316Swollman	int res;
28118316Swollman
28232502Scharnier	if (geteuid() != 0)
28332502Scharnier		errx(1, "-t requires UID 0");
28418316Swollman
28518316Swollman	if (ripv2) {
28618316Swollman		OMSG.rip_vers = RIPv2;
28718316Swollman	} else {
28818316Swollman		OMSG.rip_vers = RIPv1;
28918316Swollman	}
29018316Swollman
29118316Swollman	bzero(&myaddr, sizeof(myaddr));
29218316Swollman	myaddr.sin_family = AF_INET;
29318316Swollman#ifdef _HAVE_SIN_LEN
29418316Swollman	myaddr.sin_len = sizeof(myaddr);
29518316Swollman#endif
29618316Swollman	myaddr.sin_port = htons(IPPORT_RESERVED-1);
29718316Swollman	while (bind(s, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
29832502Scharnier		if (errno != EADDRINUSE || myaddr.sin_port == 0)
29932502Scharnier			err(2, "bind");
30018316Swollman		myaddr.sin_port = htons(ntohs(myaddr.sin_port)-1);
30118316Swollman	}
30218316Swollman
30318316Swollman	res = 1;
30418316Swollman	while (*argv != 0) {
30518316Swollman		if (out(*argv++) <= 0)
30618316Swollman			res = 0;
30718316Swollman	}
30818316Swollman	exit(res);
30918316Swollman}
31018316Swollman
31118316Swollman
31218316Swollman/* query all of the listed hosts
31318316Swollman */
31418316Swollmanstatic void
31518316Swollmanquery_loop(char *argv[], int argc)
31618316Swollman{
31719880Swollman#	define NA0 (OMSG.rip_auths[0])
31819880Swollman#	define NA2 (OMSG.rip_auths[2])
31918316Swollman	struct seen {
32018316Swollman		struct seen *next;
32118316Swollman		struct in_addr addr;
32218316Swollman	} *seen, *sp;
32318316Swollman	int answered = 0;
32418316Swollman	int cc;
32518316Swollman	fd_set bits;
32618316Swollman	struct timeval now, delay;
32718316Swollman	struct sockaddr_in from;
32818316Swollman	int fromlen;
32919880Swollman	MD5_CTX md5_ctx;
33018316Swollman
33118316Swollman
33218316Swollman	OMSG.rip_cmd = (pflag) ? RIPCMD_POLL : RIPCMD_REQUEST;
33318316Swollman	if (ripv2) {
33418316Swollman		OMSG.rip_vers = RIPv2;
33519880Swollman		if (auth_type == RIP_AUTH_PW) {
33619880Swollman			OMSG.rip_nets[1] = OMSG.rip_nets[0];
33719880Swollman			NA0.a_family = RIP_AF_AUTH;
33819880Swollman			NA0.a_type = RIP_AUTH_PW;
33919880Swollman			bcopy(passwd, NA0.au.au_pw,
34019880Swollman			      RIP_AUTH_PW_LEN);
34119880Swollman			omsg_len += sizeof(OMSG.rip_nets[0]);
34219880Swollman
34319880Swollman		} else if (auth_type == RIP_AUTH_MD5) {
34419880Swollman			OMSG.rip_nets[1] = OMSG.rip_nets[0];
34519880Swollman			NA0.a_family = RIP_AF_AUTH;
34619880Swollman			NA0.a_type = RIP_AUTH_MD5;
34719880Swollman			NA0.au.a_md5.md5_keyid = (int8_t)keyid;
34819880Swollman			NA0.au.a_md5.md5_auth_len = RIP_AUTH_PW_LEN;
34919880Swollman			NA0.au.a_md5.md5_seqno = 0;
35019880Swollman			NA0.au.a_md5.md5_pkt_len = sizeof(OMSG.rip_nets[1]);
35119880Swollman			NA2.a_family = RIP_AF_AUTH;
35219880Swollman			NA2.a_type = 1;
35319880Swollman			bcopy(passwd, NA2.au.au_pw, sizeof(NA2.au.au_pw));
35419880Swollman			MD5Init(&md5_ctx);
35519880Swollman			MD5Update(&md5_ctx, (u_char *)&NA0,
35619880Swollman				  (char *)(&NA2+1) - (char *)&NA0);
35719880Swollman			MD5Final(NA2.au.au_pw, &md5_ctx);
35819880Swollman			omsg_len += 2*sizeof(OMSG.rip_nets[0]);
35919880Swollman		}
36019880Swollman
36118316Swollman	} else {
36218316Swollman		OMSG.rip_vers = RIPv1;
36318316Swollman		OMSG.rip_nets[0].n_mask = 0;
36418316Swollman	}
36518316Swollman
36618316Swollman	/* ask the first (valid) host */
36718316Swollman	seen = 0;
36818316Swollman	while (0 > out(*argv++)) {
36918316Swollman		if (*argv == 0)
37032502Scharnier			exit(1);
37118316Swollman		answered++;
37218316Swollman	}
37318316Swollman
37418316Swollman	FD_ZERO(&bits);
37518316Swollman	for (;;) {
37618316Swollman		FD_SET(s, &bits);
37718316Swollman		delay.tv_sec = 0;
37818316Swollman		delay.tv_usec = STIME;
37918316Swollman		cc = select(s+1, &bits, 0,0, &delay);
38018316Swollman		if (cc > 0) {
38118316Swollman			fromlen = sizeof(from);
38218316Swollman			cc = recvfrom(s, imsg_buf.packet,
38318316Swollman				      sizeof(imsg_buf.packet), 0,
38418316Swollman				      (struct sockaddr *)&from, &fromlen);
38532502Scharnier			if (cc < 0)
38632502Scharnier				err(1, "recvfrom");
38718316Swollman			/* count the distinct responding hosts.
38818316Swollman			 * You cannot match responding hosts with
38918316Swollman			 * addresses to which queries were transmitted,
39018316Swollman			 * because a router might respond with a
39118316Swollman			 * different source address.
39218316Swollman			 */
39318316Swollman			for (sp = seen; sp != 0; sp = sp->next) {
39418316Swollman				if (sp->addr.s_addr == from.sin_addr.s_addr)
39518316Swollman					break;
39618316Swollman			}
39718316Swollman			if (sp == 0) {
39818316Swollman				sp = malloc(sizeof(*sp));
39918316Swollman				sp->addr = from.sin_addr;
40018316Swollman				sp->next = seen;
40118316Swollman				seen = sp;
40218316Swollman				answered++;
40318316Swollman			}
40418316Swollman
40518316Swollman			rip_input(&from, cc);
40618316Swollman			continue;
40718316Swollman		}
40818316Swollman
40918316Swollman		if (cc < 0) {
41032502Scharnier			if (errno == EINTR)
41118316Swollman				continue;
41232502Scharnier			err(1, "select");
41318316Swollman		}
41418316Swollman
41518316Swollman		/* After a pause in responses, probe another host.
41618316Swollman		 * This reduces the intermingling of answers.
41718316Swollman		 */
41818316Swollman		while (*argv != 0 && 0 > out(*argv++))
41918316Swollman			answered++;
42018316Swollman
42118316Swollman		/* continue until no more packets arrive
42218316Swollman		 * or we have heard from all hosts
42318316Swollman		 */
42418316Swollman		if (answered >= argc)
42518316Swollman			break;
42618316Swollman
42718316Swollman		/* or until we have waited a long time
42818316Swollman		 */
42932502Scharnier		if (gettimeofday(&now, 0) < 0)
43032502Scharnier			err(1, "gettimeofday(now)");
43118316Swollman		if (sent.tv_sec + wtime <= now.tv_sec)
43218316Swollman			break;
43318316Swollman	}
43418316Swollman
43518316Swollman	/* fail if there was no answer */
43618316Swollman	exit (answered >= argc ? 0 : 1);
43718316Swollman}
43818316Swollman
43918316Swollman
44019880Swollman/* send to one host
44118316Swollman */
44218316Swollmanstatic int
44318316Swollmanout(char *host)
44418316Swollman{
44518316Swollman	struct sockaddr_in router;
44618316Swollman	struct hostent *hp;
44718316Swollman
44818316Swollman	if (gettimeofday(&sent, 0) < 0) {
44932502Scharnier		warn("gettimeofday(sent)");
45018316Swollman		return -1;
45118316Swollman	}
45218316Swollman
45318316Swollman	bzero(&router, sizeof(router));
45418316Swollman	router.sin_family = AF_INET;
45518316Swollman#ifdef _HAVE_SIN_LEN
45618316Swollman	router.sin_len = sizeof(router);
45718316Swollman#endif
45818316Swollman	if (!inet_aton(host, &router.sin_addr)) {
45918316Swollman		hp = gethostbyname(host);
46018316Swollman		if (hp == 0) {
46118316Swollman			herror(host);
46218316Swollman			return -1;
46318316Swollman		}
46418316Swollman		bcopy(hp->h_addr, &router.sin_addr, sizeof(router.sin_addr));
46518316Swollman	}
46618316Swollman	router.sin_port = htons(RIP_PORT);
46718316Swollman
46818316Swollman	if (sendto(s, &omsg_buf, omsg_len, 0,
46918316Swollman		   (struct sockaddr *)&router, sizeof(router)) < 0) {
47032502Scharnier		warn("%s", host);
47118316Swollman		return -1;
47218316Swollman	}
47318316Swollman
47418316Swollman	return 0;
47518316Swollman}
47618316Swollman
47718316Swollman
47818316Swollman/*
47919880Swollman * Convert string to printable characters
48019880Swollman */
48119880Swollmanstatic char *
48219880Swollmanqstring(u_char *s, int len)
48319880Swollman{
48419880Swollman	static char buf[8*20+1];
48519880Swollman	char *p;
48619880Swollman	u_char *s2, c;
48719880Swollman
48819880Swollman
48919880Swollman	for (p = buf; len != 0 && p < &buf[sizeof(buf)-1]; len--) {
49019880Swollman		c = *s++;
49119880Swollman		if (c == '\0') {
49219880Swollman			for (s2 = s+1; s2 < &s[len]; s2++) {
49319880Swollman				if (*s2 != '\0')
49419880Swollman					break;
49519880Swollman			}
49619880Swollman			if (s2 >= &s[len])
49719880Swollman			    goto exit;
49819880Swollman		}
49919880Swollman
50019880Swollman		if (c >= ' ' && c < 0x7f && c != '\\') {
50119880Swollman			*p++ = c;
50219880Swollman			continue;
50319880Swollman		}
50419880Swollman		*p++ = '\\';
50519880Swollman		switch (c) {
50619880Swollman		case '\\':
50719880Swollman			*p++ = '\\';
50819880Swollman			break;
50919880Swollman		case '\n':
51019880Swollman			*p++= 'n';
51119880Swollman			break;
51219880Swollman		case '\r':
51319880Swollman			*p++= 'r';
51419880Swollman			break;
51519880Swollman		case '\t':
51619880Swollman			*p++ = 't';
51719880Swollman			break;
51819880Swollman		case '\b':
51919880Swollman			*p++ = 'b';
52019880Swollman			break;
52119880Swollman		default:
52219880Swollman			p += sprintf(p,"%o",c);
52319880Swollman			break;
52419880Swollman		}
52519880Swollman	}
52619880Swollmanexit:
52719880Swollman	*p = '\0';
52819880Swollman	return buf;
52919880Swollman}
53019880Swollman
53119880Swollman
53219880Swollman/*
53318316Swollman * Handle an incoming RIP packet.
53418316Swollman */
53518316Swollmanstatic void
53618316Swollmanrip_input(struct sockaddr_in *from,
53718316Swollman	  int size)
53818316Swollman{
53918316Swollman	struct netinfo *n, *lim;
54018316Swollman	struct in_addr in;
54118316Swollman	char *name;
54218316Swollman	char net_buf[80];
54318316Swollman	u_int mask, dmask;
54418316Swollman	char *sp;
54518316Swollman	int i;
54618316Swollman	struct hostent *hp;
54718316Swollman	struct netent *np;
54819880Swollman	struct netauth *na;
54918316Swollman
55018316Swollman
55118316Swollman	if (nflag) {
55218316Swollman		printf("%s:", inet_ntoa(from->sin_addr));
55318316Swollman	} else {
55418316Swollman		hp = gethostbyaddr((char*)&from->sin_addr,
55518316Swollman				   sizeof(struct in_addr), AF_INET);
55618316Swollman		if (hp == 0) {
55718316Swollman			printf("%s:",
55818316Swollman			       inet_ntoa(from->sin_addr));
55918316Swollman		} else {
56018316Swollman			printf("%s (%s):", hp->h_name,
56118316Swollman			       inet_ntoa(from->sin_addr));
56218316Swollman		}
56318316Swollman	}
56418316Swollman	if (IMSG.rip_cmd != RIPCMD_RESPONSE) {
56518316Swollman		printf("\n    unexpected response type %d\n", IMSG.rip_cmd);
56618316Swollman		return;
56718316Swollman	}
56818316Swollman	printf(" RIPv%d%s %d bytes\n", IMSG.rip_vers,
56918316Swollman	       (IMSG.rip_vers != RIPv1 && IMSG.rip_vers != RIPv2) ? " ?" : "",
57018316Swollman	       size);
57118316Swollman	if (size > MAXPACKETSIZE) {
57218316Swollman		if (size > sizeof(imsg_buf) - sizeof(*n)) {
57318316Swollman			printf("       at least %d bytes too long\n",
57418316Swollman			       size-MAXPACKETSIZE);
57518316Swollman			size = sizeof(imsg_buf) - sizeof(*n);
57618316Swollman		} else {
57718316Swollman			printf("       %d bytes too long\n",
57818316Swollman			       size-MAXPACKETSIZE);
57918316Swollman		}
58018316Swollman	} else if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
58118316Swollman		printf("    response of bad length=%d\n", size);
58218316Swollman	}
58318316Swollman
58418316Swollman	n = IMSG.rip_nets;
58518316Swollman	lim = (struct netinfo *)((char*)n + size) - 1;
58618316Swollman	for (; n <= lim; n++) {
58718316Swollman		name = "";
58818316Swollman		if (n->n_family == RIP_AF_INET) {
58918316Swollman			in.s_addr = n->n_dst;
59018316Swollman			(void)strcpy(net_buf, inet_ntoa(in));
59118316Swollman
59218316Swollman			mask = ntohl(n->n_mask);
59318316Swollman			dmask = mask & -mask;
59418316Swollman			if (mask != 0) {
59518316Swollman				sp = &net_buf[strlen(net_buf)];
59618316Swollman				if (IMSG.rip_vers == RIPv1) {
59718316Swollman					(void)sprintf(sp," mask=%#x ? ",mask);
59818316Swollman					mask = 0;
59918316Swollman				} else if (mask + dmask == 0) {
60018316Swollman					for (i = 0;
60118316Swollman					     (i != 32
60218316Swollman					      && ((1<<i)&mask) == 0);
60318316Swollman					     i++)
60418316Swollman						continue;
60518316Swollman					(void)sprintf(sp, "/%d",32-i);
60618316Swollman				} else {
60718316Swollman					(void)sprintf(sp," (mask %#x)", mask);
60818316Swollman				}
60918316Swollman			}
61018316Swollman
61118316Swollman			if (!nflag) {
61218316Swollman				if (mask == 0) {
61318316Swollman					mask = std_mask(in.s_addr);
61418316Swollman					if ((ntohl(in.s_addr) & ~mask) != 0)
61518316Swollman						mask = 0;
61618316Swollman				}
61718316Swollman				/* Without a netmask, do not worry about
61818316Swollman				 * whether the destination is a host or a
61918316Swollman				 * network. Try both and use the first name
62018316Swollman				 * we get.
62118316Swollman				 *
62218316Swollman				 * If we have a netmask we can make a
62318316Swollman				 * good guess.
62418316Swollman				 */
62518316Swollman				if ((in.s_addr & ~mask) == 0) {
62618316Swollman					np = getnetbyaddr((long)in.s_addr,
62718316Swollman							  AF_INET);
62818316Swollman					if (np != 0)
62918316Swollman						name = np->n_name;
63018316Swollman					else if (in.s_addr == 0)
63118316Swollman						name = "default";
63218316Swollman				}
63318316Swollman				if (name[0] == '\0'
63418316Swollman				    && ((in.s_addr & ~mask) != 0
63518316Swollman					|| mask == 0xffffffff)) {
63618316Swollman					hp = gethostbyaddr((char*)&in,
63718316Swollman							   sizeof(in),
63818316Swollman							   AF_INET);
63918316Swollman					if (hp != 0)
64018316Swollman						name = hp->h_name;
64118316Swollman				}
64218316Swollman			}
64318316Swollman
64418316Swollman		} else if (n->n_family == RIP_AF_AUTH) {
64519880Swollman			na = (struct netauth*)n;
64619880Swollman			if (na->a_type == RIP_AUTH_PW
64719880Swollman			    && n == IMSG.rip_nets) {
64819880Swollman				(void)printf("  Password Authentication:"
64919880Swollman					     " \"%s\"\n",
65019880Swollman					     qstring(na->au.au_pw,
65119880Swollman						     RIP_AUTH_PW_LEN));
65219880Swollman				continue;
65319880Swollman			}
65419880Swollman
65519880Swollman			if (na->a_type == RIP_AUTH_MD5
65619880Swollman			    && n == IMSG.rip_nets) {
65719880Swollman				(void)printf("  MD5 Authentication"
65819880Swollman					     " len=%d KeyID=%d"
65919880Swollman					     " seqno=%d"
66019880Swollman					     " rsvd=%#x,%#x\n",
66119880Swollman					     na->au.a_md5.md5_pkt_len,
66219880Swollman					     na->au.a_md5.md5_keyid,
66319880Swollman					     na->au.a_md5.md5_seqno,
66419880Swollman					     na->au.a_md5.rsvd[0],
66519880Swollman					     na->au.a_md5.rsvd[1]);
66619880Swollman				continue;
66719880Swollman			}
66819880Swollman			(void)printf("  Authentication type %d: ",
66919880Swollman				     ntohs(na->a_type));
67019880Swollman			for (i = 0; i < sizeof(na->au.au_pw); i++)
67119880Swollman				(void)printf("%02x ", na->au.au_pw[i]);
67218316Swollman			putc('\n', stdout);
67318316Swollman			continue;
67418316Swollman
67518316Swollman		} else {
67618316Swollman			(void)sprintf(net_buf, "(af %#x) %d.%d.%d.%d",
67718316Swollman				      ntohs(n->n_family),
67818316Swollman				      (char)(n->n_dst >> 24),
67918316Swollman				      (char)(n->n_dst >> 16),
68018316Swollman				      (char)(n->n_dst >> 8),
68118316Swollman				      (char)n->n_dst);
68218316Swollman		}
68318316Swollman
68418316Swollman		(void)printf("  %-18s metric %2d %-10s",
68518316Swollman			     net_buf, ntohl(n->n_metric), name);
68618316Swollman
68718316Swollman		if (n->n_nhop != 0) {
68818316Swollman			in.s_addr = n->n_nhop;
68918316Swollman			if (nflag)
69018316Swollman				hp = 0;
69118316Swollman			else
69218316Swollman				hp = gethostbyaddr((char*)&in, sizeof(in),
69318316Swollman						   AF_INET);
69418316Swollman			(void)printf(" nhop=%-15s%s",
69518316Swollman				     (hp != 0) ? hp->h_name : inet_ntoa(in),
69618316Swollman				     (IMSG.rip_vers == RIPv1) ? " ?" : "");
69718316Swollman		}
69818316Swollman		if (n->n_tag != 0)
69918316Swollman			(void)printf(" tag=%#x%s", n->n_tag,
70018316Swollman				     (IMSG.rip_vers == RIPv1) ? " ?" : "");
70118316Swollman		putc('\n', stdout);
70218316Swollman	}
70318316Swollman}
70418316Swollman
70518316Swollman
70618316Swollman/* Return the classical netmask for an IP address.
70718316Swollman */
70818316Swollmanstatic u_int
70918316Swollmanstd_mask(u_int addr)			/* in network order */
71018316Swollman{
71118316Swollman	NTOHL(addr);			/* was a host, not a network */
71218316Swollman
71318316Swollman	if (addr == 0)			/* default route has mask 0 */
71418316Swollman		return 0;
71518316Swollman	if (IN_CLASSA(addr))
71618316Swollman		return IN_CLASSA_NET;
71718316Swollman	if (IN_CLASSB(addr))
71818316Swollman		return IN_CLASSB_NET;
71918316Swollman	return IN_CLASSC_NET;
72018316Swollman}
72118316Swollman
72218316Swollman
72318316Swollman/* get a network number as a name or a number, with an optional "/xx"
72418316Swollman * netmask.
72518316Swollman */
72618316Swollmanstatic int				/* 0=bad */
72718316Swollmangetnet(char *name,
72818316Swollman       struct netinfo *rt)
72918316Swollman{
73018316Swollman	int i;
73118316Swollman	struct netent *nentp;
73218316Swollman	u_int mask;
73318316Swollman	struct in_addr in;
73418316Swollman	char hname[MAXHOSTNAMELEN+1];
73518316Swollman	char *mname, *p;
73618316Swollman
73718316Swollman
73818316Swollman	/* Detect and separate "1.2.3.4/24"
73918316Swollman	 */
74018316Swollman	if (0 != (mname = rindex(name,'/'))) {
74118316Swollman		i = (int)(mname - name);
74218316Swollman		if (i > sizeof(hname)-1)	/* name too long */
74318316Swollman			return 0;
74418316Swollman		bcopy(name, hname, i);
74518316Swollman		hname[i] = '\0';
74618316Swollman		mname++;
74718316Swollman		name = hname;
74818316Swollman	}
74918316Swollman
75018316Swollman	nentp = getnetbyname(name);
75118316Swollman	if (nentp != 0) {
75218316Swollman		in.s_addr = nentp->n_net;
75318316Swollman	} else if (inet_aton(name, &in) == 1) {
75418316Swollman		NTOHL(in.s_addr);
75518316Swollman	} else {
75618316Swollman		return 0;
75718316Swollman	}
75818316Swollman
75918316Swollman	if (mname == 0) {
76018316Swollman		mask = std_mask(in.s_addr);
76118316Swollman		if ((~mask & in.s_addr) != 0)
76218316Swollman			mask = 0xffffffff;
76318316Swollman	} else {
76418316Swollman		mask = (u_int)strtoul(mname, &p, 0);
76518316Swollman		if (*p != '\0' || mask > 32)
76618316Swollman			return 0;
76718316Swollman		mask = 0xffffffff << (32-mask);
76818316Swollman	}
76918316Swollman
77018316Swollman	rt->n_dst = htonl(in.s_addr);
77118316Swollman	rt->n_family = RIP_AF_INET;
77218316Swollman	rt->n_mask = htonl(mask);
77318316Swollman	return 1;
77418316Swollman}
77519880Swollman
77619880Swollman
77719880Swollman/* strtok(), but honoring backslash
77819880Swollman */
77919880Swollmanstatic int				/* -1=bad */
78019880Swollmanparse_quote(char **linep,
78119880Swollman	    char *delims,
78219880Swollman	    char *delimp,
78319880Swollman	    char *buf,
78419880Swollman	    int	lim)
78519880Swollman{
78619880Swollman	char c, *pc, *p;
78719880Swollman
78819880Swollman
78919880Swollman	pc = *linep;
79019880Swollman	if (*pc == '\0')
79119880Swollman		return -1;
79219880Swollman
79319880Swollman	for (;;) {
79419880Swollman		if (lim == 0)
79519880Swollman			return -1;
79619880Swollman		c = *pc++;
79719880Swollman		if (c == '\0')
79819880Swollman			break;
79919880Swollman
80019880Swollman		if (c == '\\' && pc != '\0') {
80119880Swollman			if ((c = *pc++) == 'n') {
80219880Swollman				c = '\n';
80319880Swollman			} else if (c == 'r') {
80419880Swollman				c = '\r';
80519880Swollman			} else if (c == 't') {
80619880Swollman				c = '\t';
80719880Swollman			} else if (c == 'b') {
80819880Swollman				c = '\b';
80919880Swollman			} else if (c >= '0' && c <= '7') {
81019880Swollman				c -= '0';
81119880Swollman				if (*pc >= '0' && *pc <= '7') {
81219880Swollman					c = (c<<3)+(*pc++ - '0');
81319880Swollman					if (*pc >= '0' && *pc <= '7')
81419880Swollman					    c = (c<<3)+(*pc++ - '0');
81519880Swollman				}
81619880Swollman			}
81719880Swollman
81819880Swollman		} else {
81919880Swollman			for (p = delims; *p != '\0'; ++p) {
82019880Swollman				if (*p == c)
82119880Swollman					goto exit;
82219880Swollman			}
82319880Swollman		}
82419880Swollman
82519880Swollman		*buf++ = c;
82619880Swollman		--lim;
82719880Swollman	}
82819880Swollmanexit:
82919880Swollman	if (delimp != 0)
83019880Swollman		*delimp = c;
83119880Swollman	*linep = pc-1;
83219880Swollman	if (lim != 0)
83319880Swollman		*buf = '\0';
83419880Swollman	return 0;
83519880Swollman}
836