rtquery.c revision 90868
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
1446303Smarkm *    must display the following acknowledgment:
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.
3246303Smarkm *
3350476Speter * $FreeBSD: head/sbin/routed/rtquery/rtquery.c 90868 2002-02-18 20:35:27Z mike $
3418316Swollman */
3518316Swollman
3646303Smarkmchar copyright[] =
3718316Swollman"@(#) Copyright (c) 1982, 1986, 1993\n\
3818316Swollman	The Regents of the University of California.  All rights reserved.\n";
3918316Swollman
4046303Smarkm#include <sys/cdefs.h>
4118316Swollman#include <sys/param.h>
4246303Smarkm#include <sys/protosw.h>
4318316Swollman#include <sys/socket.h>
4418316Swollman#include <sys/time.h>
4518316Swollman#include <netinet/in.h>
4618316Swollman#define RIPVERSION RIPv2
4718316Swollman#include <protocols/routed.h>
4818316Swollman#include <arpa/inet.h>
4946303Smarkm#include <netdb.h>
5032502Scharnier#include <errno.h>
5146303Smarkm#include <unistd.h>
5218316Swollman#include <stdio.h>
5318316Swollman#include <stdlib.h>
5418316Swollman#include <string.h>
5518316Swollman#ifdef sgi
5618316Swollman#include <strings.h>
5718316Swollman#include <bstring.h>
5818316Swollman#endif
5918316Swollman
6046303Smarkm#if !defined(sgi) && !defined(__NetBSD__)
6146303Smarkmstatic char sccsid[] __attribute__((unused))= "@(#)query.c	8.1 (Berkeley) 6/5/93";
6246303Smarkm#elif defined(__NetBSD__)
6346303Smarkm__RCSID("$NetBSD: rtquery.c,v 1.10 1999/02/23 10:47:41 christos Exp $");
6446303Smarkm#endif
6550476Speter#ident "$Revision: 1.12 $"
6646303Smarkm
6718316Swollman#ifndef sgi
6818316Swollman#define _HAVE_SIN_LEN
6918316Swollman#endif
7018316Swollman
7146303Smarkm#define MD5_DIGEST_LEN 16
7246303Smarkmtypedef struct {
7346303Smarkm	u_int32_t state[4];		/* state (ABCD) */
7446303Smarkm	u_int32_t count[2];		/* # of bits, modulo 2^64 (LSB 1st) */
7546303Smarkm	unsigned char buffer[64];	/* input buffer */
7646303Smarkm} MD5_CTX;
7746303Smarkmextern void MD5Init(MD5_CTX*);
7846303Smarkmextern void MD5Update(MD5_CTX*, u_char*, u_int);
7946303Smarkmextern void MD5Final(u_char[MD5_DIGEST_LEN], MD5_CTX*);
8046303Smarkm
8146303Smarkm
8218316Swollman#define	WTIME	15		/* Time to wait for all responses */
8318316Swollman#define	STIME	(250*1000)	/* usec to wait for another response */
8418316Swollman
8546303Smarkmint	soc;
8618316Swollman
8746303Smarkmconst char *pgmname;
8846303Smarkm
8918316Swollmanunion {
9018316Swollman	struct rip rip;
9118316Swollman	char	packet[MAXPACKETSIZE+MAXPATHLEN];
9218316Swollman} omsg_buf;
9318316Swollman#define OMSG omsg_buf.rip
9418316Swollmanint omsg_len = sizeof(struct rip);
9518316Swollman
9618316Swollmanunion {
9718316Swollman	struct	rip rip;
9818316Swollman	char	packet[MAXPACKETSIZE+1024];
9918316Swollman	} imsg_buf;
10018316Swollman#define IMSG imsg_buf.rip
10118316Swollman
10218316Swollmanint	nflag;				/* numbers, no names */
10318316Swollmanint	pflag;				/* play the `gated` game */
10418316Swollmanint	ripv2 = 1;			/* use RIP version 2 */
10518316Swollmanint	wtime = WTIME;
10618316Swollmanint	rflag;				/* 1=ask about a particular route */
10719880Swollmanint	trace, not_trace;		/* send trace command or not */
10819880Swollmanint	auth_type = RIP_AUTH_NONE;
10919880Swollmanchar	passwd[RIP_AUTH_PW_LEN];
11019880Swollmanu_long	keyid;
11118316Swollman
11218316Swollmanstruct timeval sent;			/* when query sent */
11318316Swollman
11446303Smarkmstatic char localhost_str[] = "localhost";
11546303Smarkmstatic char *default_argv[] = {localhost_str, 0};
11646303Smarkm
11718316Swollmanstatic void rip_input(struct sockaddr_in*, int);
11846303Smarkmstatic int out(const char *);
11946303Smarkmstatic void trace_loop(char *argv[]) __attribute((__noreturn__));
12046303Smarkmstatic void query_loop(char *argv[], int) __attribute((__noreturn__));
12118316Swollmanstatic int getnet(char *, struct netinfo *);
12218316Swollmanstatic u_int std_mask(u_int);
12346303Smarkmstatic int parse_quote(char **, const char *, char *, char *, int);
12437908Scharnierstatic void usage(void);
12518316Swollman
12646303Smarkm
12737908Scharnierint
12818316Swollmanmain(int argc,
12918316Swollman     char *argv[])
13018316Swollman{
13118316Swollman	int ch, bsize;
13219880Swollman	char *p, *options, *value, delim;
13346303Smarkm	const char *result;
13418316Swollman
13518316Swollman	OMSG.rip_nets[0].n_dst = RIP_DEFAULT;
13618316Swollman	OMSG.rip_nets[0].n_family = RIP_AF_UNSPEC;
13718316Swollman	OMSG.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY);
13818316Swollman
13946303Smarkm	pgmname = argv[0];
14024359Simp	while ((ch = getopt(argc, argv, "np1w:r:t:a:")) != -1)
14118316Swollman		switch (ch) {
14218316Swollman		case 'n':
14318316Swollman			not_trace = 1;
14418316Swollman			nflag = 1;
14518316Swollman			break;
14618316Swollman
14718316Swollman		case 'p':
14818316Swollman			not_trace = 1;
14918316Swollman			pflag = 1;
15018316Swollman			break;
15118316Swollman
15218316Swollman		case '1':
15318316Swollman			ripv2 = 0;
15418316Swollman			break;
15518316Swollman
15618316Swollman		case 'w':
15718316Swollman			not_trace = 1;
15818316Swollman			wtime = (int)strtoul(optarg, &p, 0);
15918316Swollman			if (*p != '\0'
16018316Swollman			    || wtime <= 0)
16137908Scharnier				usage();
16218316Swollman			break;
16318316Swollman
16418316Swollman		case 'r':
16518316Swollman			not_trace = 1;
16618316Swollman			if (rflag)
16737908Scharnier				usage();
16818316Swollman			rflag = getnet(optarg, &OMSG.rip_nets[0]);
16918316Swollman			if (!rflag) {
17018316Swollman				struct hostent *hp = gethostbyname(optarg);
17146303Smarkm				if (hp == 0) {
17246303Smarkm					fprintf(stderr, "%s: %s:",
17346303Smarkm						pgmname, optarg);
17446303Smarkm					herror(0);
17546303Smarkm					exit(1);
17646303Smarkm				}
17746303Smarkm				memcpy(&OMSG.rip_nets[0].n_dst, hp->h_addr,
17846303Smarkm				       sizeof(OMSG.rip_nets[0].n_dst));
17918316Swollman				OMSG.rip_nets[0].n_family = RIP_AF_INET;
18018316Swollman				OMSG.rip_nets[0].n_mask = -1;
18118316Swollman				rflag = 1;
18218316Swollman			}
18318316Swollman			break;
18418316Swollman
18518316Swollman		case 't':
18618316Swollman			trace = 1;
18718316Swollman			options = optarg;
18818316Swollman			while (*options != '\0') {
18946303Smarkm				/* messy complications to make -W -Wall happy */
19046303Smarkm				static char on_str[] = "on";
19146303Smarkm				static char more_str[] = "more";
19246303Smarkm				static char off_str[] = "off";
19346303Smarkm				static char dump_str[] = "dump";
19446303Smarkm				static char *traceopts[] = {
19518316Swollman#				    define TRACE_ON	0
19646303Smarkm					on_str,
19718316Swollman#				    define TRACE_MORE	1
19846303Smarkm					more_str,
19918316Swollman#				    define TRACE_OFF	2
20046303Smarkm					off_str,
20118316Swollman#				    define TRACE_DUMP	3
20246303Smarkm					dump_str,
20318316Swollman					0
20418316Swollman				};
20546303Smarkm				result = "";
20618316Swollman				switch (getsubopt(&options,traceopts,&value)) {
20718316Swollman				case TRACE_ON:
20818316Swollman					OMSG.rip_cmd = RIPCMD_TRACEON;
20918316Swollman					if (!value
21018316Swollman					    || strlen(value) > MAXPATHLEN)
21146303Smarkm					    usage();
21246303Smarkm					result = value;
21318316Swollman					break;
21418316Swollman				case TRACE_MORE:
21518316Swollman					if (value)
21646303Smarkm					    usage();
21718316Swollman					OMSG.rip_cmd = RIPCMD_TRACEON;
21818316Swollman					break;
21918316Swollman				case TRACE_OFF:
22018316Swollman					if (value)
22146303Smarkm					    usage();
22218316Swollman					OMSG.rip_cmd = RIPCMD_TRACEOFF;
22318316Swollman					break;
22418316Swollman				case TRACE_DUMP:
22518316Swollman					if (value)
22646303Smarkm					    usage();
22718316Swollman					OMSG.rip_cmd = RIPCMD_TRACEON;
22846303Smarkm					result = "dump/../table";
22918316Swollman					break;
23018316Swollman				default:
23137908Scharnier					usage();
23218316Swollman				}
23346303Smarkm				strcpy((char*)OMSG.rip_tracefile, result);
23446303Smarkm				omsg_len += strlen(result) - sizeof(OMSG.ripun);
23518316Swollman			}
23618316Swollman			break;
23718316Swollman
23819880Swollman		case 'a':
23919880Swollman			not_trace = 1;
24019880Swollman			p = strchr(optarg,'=');
24119880Swollman			if (!p)
24237908Scharnier				usage();
24319880Swollman			*p++ = '\0';
24419880Swollman			if (!strcasecmp("passwd",optarg))
24519880Swollman				auth_type = RIP_AUTH_PW;
24619880Swollman			else if (!strcasecmp("md5_passwd",optarg))
24719880Swollman				auth_type = RIP_AUTH_MD5;
24819880Swollman			else
24937908Scharnier				usage();
25019880Swollman			if (0 > parse_quote(&p,"|",&delim,
25146303Smarkm					    passwd, sizeof(passwd)))
25237908Scharnier				usage();
25319880Swollman			if (auth_type == RIP_AUTH_MD5
25419880Swollman			    && delim == '|') {
25519880Swollman				keyid = strtoul(p+1,&p,0);
25619880Swollman				if (keyid > 255 || *p != '\0')
25737908Scharnier					usage();
25819880Swollman			} else if (delim != '\0') {
25937908Scharnier				usage();
26019880Swollman			}
26119880Swollman			break;
26219880Swollman
26318316Swollman		default:
26437908Scharnier			usage();
26518316Swollman	}
26618316Swollman	argv += optind;
26718316Swollman	argc -= optind;
26846303Smarkm	if (not_trace && trace)
26937908Scharnier		usage();
27046303Smarkm	if (argc == 0) {
27146303Smarkm		argc = 1;
27246303Smarkm		argv = default_argv;
27346303Smarkm	}
27418316Swollman
27546303Smarkm	soc = socket(AF_INET, SOCK_DGRAM, 0);
27646303Smarkm	if (soc < 0) {
27746524Smarkm		perror("socket");
27846524Smarkm		exit(2);
27946303Smarkm	}
28018316Swollman
28118316Swollman	/* be prepared to receive a lot of routes */
28218316Swollman	for (bsize = 127*1024; ; bsize -= 1024) {
28346303Smarkm		if (setsockopt(soc, SOL_SOCKET, SO_RCVBUF,
28418316Swollman			       &bsize, sizeof(bsize)) == 0)
28518316Swollman			break;
28618316Swollman		if (bsize <= 4*1024) {
28746524Smarkm			perror("setsockopt SO_RCVBUF");
28818316Swollman			break;
28918316Swollman		}
29018316Swollman	}
29118316Swollman
29218316Swollman	if (trace)
29318316Swollman		trace_loop(argv);
29418316Swollman	else
29518316Swollman		query_loop(argv, argc);
29618316Swollman	/* NOTREACHED */
29746303Smarkm	return 0;
29818316Swollman}
29918316Swollman
30046303Smarkm
30137908Scharnierstatic void
30246303Smarkmusage(void)
30337908Scharnier{
30446303Smarkm	fprintf(stderr,
30546303Smarkm		"usage:  rtquery [-np1] [-r tgt_rt] [-w wtime]"
30646303Smarkm		" [-a type=passwd] host1 [host2 ...]\n"
30746303Smarkm		"\trtquery -t {on=filename|more|off|dump}"
30846303Smarkm				" host1 [host2 ...]\n");
30937908Scharnier	exit(1);
31037908Scharnier}
31118316Swollman
31246303Smarkm
31318316Swollman/* tell the target hosts about tracing
31418316Swollman */
31518316Swollmanstatic void
31618316Swollmantrace_loop(char *argv[])
31718316Swollman{
31818316Swollman	struct sockaddr_in myaddr;
31918316Swollman	int res;
32018316Swollman
32146303Smarkm	if (geteuid() != 0) {
32246303Smarkm		(void)fprintf(stderr, "-t requires UID 0\n");
32346303Smarkm		exit(1);
32446303Smarkm	}
32518316Swollman
32618316Swollman	if (ripv2) {
32718316Swollman		OMSG.rip_vers = RIPv2;
32818316Swollman	} else {
32918316Swollman		OMSG.rip_vers = RIPv1;
33018316Swollman	}
33118316Swollman
33246303Smarkm	memset(&myaddr, 0, sizeof(myaddr));
33318316Swollman	myaddr.sin_family = AF_INET;
33418316Swollman#ifdef _HAVE_SIN_LEN
33518316Swollman	myaddr.sin_len = sizeof(myaddr);
33618316Swollman#endif
33718316Swollman	myaddr.sin_port = htons(IPPORT_RESERVED-1);
33846303Smarkm	while (bind(soc, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
33946303Smarkm		if (errno != EADDRINUSE
34046303Smarkm		    || myaddr.sin_port == 0) {
34146524Smarkm			perror("bind");
34246524Smarkm			exit(2);
34346303Smarkm		}
34418316Swollman		myaddr.sin_port = htons(ntohs(myaddr.sin_port)-1);
34518316Swollman	}
34618316Swollman
34718316Swollman	res = 1;
34818316Swollman	while (*argv != 0) {
34918316Swollman		if (out(*argv++) <= 0)
35018316Swollman			res = 0;
35118316Swollman	}
35218316Swollman	exit(res);
35318316Swollman}
35418316Swollman
35518316Swollman
35618316Swollman/* query all of the listed hosts
35718316Swollman */
35818316Swollmanstatic void
35918316Swollmanquery_loop(char *argv[], int argc)
36018316Swollman{
36119880Swollman#	define NA0 (OMSG.rip_auths[0])
36219880Swollman#	define NA2 (OMSG.rip_auths[2])
36318316Swollman	struct seen {
36418316Swollman		struct seen *next;
36518316Swollman		struct in_addr addr;
36618316Swollman	} *seen, *sp;
36718316Swollman	int answered = 0;
36818316Swollman	int cc;
36918316Swollman	fd_set bits;
37018316Swollman	struct timeval now, delay;
37118316Swollman	struct sockaddr_in from;
37218316Swollman	int fromlen;
37319880Swollman	MD5_CTX md5_ctx;
37418316Swollman
37518316Swollman
37618316Swollman	OMSG.rip_cmd = (pflag) ? RIPCMD_POLL : RIPCMD_REQUEST;
37718316Swollman	if (ripv2) {
37818316Swollman		OMSG.rip_vers = RIPv2;
37919880Swollman		if (auth_type == RIP_AUTH_PW) {
38019880Swollman			OMSG.rip_nets[1] = OMSG.rip_nets[0];
38119880Swollman			NA0.a_family = RIP_AF_AUTH;
38219880Swollman			NA0.a_type = RIP_AUTH_PW;
38346303Smarkm			memcpy(NA0.au.au_pw, passwd, RIP_AUTH_PW_LEN);
38419880Swollman			omsg_len += sizeof(OMSG.rip_nets[0]);
38519880Swollman
38619880Swollman		} else if (auth_type == RIP_AUTH_MD5) {
38719880Swollman			OMSG.rip_nets[1] = OMSG.rip_nets[0];
38819880Swollman			NA0.a_family = RIP_AF_AUTH;
38919880Swollman			NA0.a_type = RIP_AUTH_MD5;
39019880Swollman			NA0.au.a_md5.md5_keyid = (int8_t)keyid;
39146303Smarkm			NA0.au.a_md5.md5_auth_len = RIP_AUTH_MD5_LEN;
39219880Swollman			NA0.au.a_md5.md5_seqno = 0;
39346303Smarkm			cc = (char *)&NA2-(char *)&OMSG;
39446303Smarkm			NA0.au.a_md5.md5_pkt_len = htons(cc);
39519880Swollman			NA2.a_family = RIP_AF_AUTH;
39646303Smarkm			NA2.a_type = htons(1);
39719880Swollman			MD5Init(&md5_ctx);
39846303Smarkm			MD5Update(&md5_ctx,
39946303Smarkm				  (u_char *)&OMSG, cc);
40046303Smarkm			MD5Update(&md5_ctx,
40146303Smarkm				  (u_char *)passwd, RIP_AUTH_MD5_LEN);
40219880Swollman			MD5Final(NA2.au.au_pw, &md5_ctx);
40319880Swollman			omsg_len += 2*sizeof(OMSG.rip_nets[0]);
40419880Swollman		}
40519880Swollman
40618316Swollman	} else {
40718316Swollman		OMSG.rip_vers = RIPv1;
40818316Swollman		OMSG.rip_nets[0].n_mask = 0;
40918316Swollman	}
41018316Swollman
41118316Swollman	/* ask the first (valid) host */
41218316Swollman	seen = 0;
41318316Swollman	while (0 > out(*argv++)) {
41418316Swollman		if (*argv == 0)
41546303Smarkm			exit(-1);
41618316Swollman		answered++;
41718316Swollman	}
41818316Swollman
41918316Swollman	FD_ZERO(&bits);
42018316Swollman	for (;;) {
42146303Smarkm		FD_SET(soc, &bits);
42218316Swollman		delay.tv_sec = 0;
42318316Swollman		delay.tv_usec = STIME;
42446303Smarkm		cc = select(soc+1, &bits, 0,0, &delay);
42518316Swollman		if (cc > 0) {
42618316Swollman			fromlen = sizeof(from);
42746303Smarkm			cc = recvfrom(soc, imsg_buf.packet,
42818316Swollman				      sizeof(imsg_buf.packet), 0,
42918316Swollman				      (struct sockaddr *)&from, &fromlen);
43046303Smarkm			if (cc < 0) {
43146524Smarkm				perror("recvfrom");
43246524Smarkm				exit(1);
43346303Smarkm			}
43418316Swollman			/* count the distinct responding hosts.
43518316Swollman			 * You cannot match responding hosts with
43618316Swollman			 * addresses to which queries were transmitted,
43718316Swollman			 * because a router might respond with a
43818316Swollman			 * different source address.
43918316Swollman			 */
44018316Swollman			for (sp = seen; sp != 0; sp = sp->next) {
44118316Swollman				if (sp->addr.s_addr == from.sin_addr.s_addr)
44218316Swollman					break;
44318316Swollman			}
44418316Swollman			if (sp == 0) {
44518316Swollman				sp = malloc(sizeof(*sp));
44646303Smarkm				if (sp == 0) {
44746303Smarkm					fprintf(stderr,
44846303Smarkm						"rtquery: malloc failed\n");
44946303Smarkm					exit(1);
45046303Smarkm				}
45118316Swollman				sp->addr = from.sin_addr;
45218316Swollman				sp->next = seen;
45318316Swollman				seen = sp;
45418316Swollman				answered++;
45518316Swollman			}
45618316Swollman
45718316Swollman			rip_input(&from, cc);
45818316Swollman			continue;
45918316Swollman		}
46018316Swollman
46118316Swollman		if (cc < 0) {
46232502Scharnier			if (errno == EINTR)
46318316Swollman				continue;
46446524Smarkm			perror("select");
46546524Smarkm			exit(1);
46618316Swollman		}
46718316Swollman
46818316Swollman		/* After a pause in responses, probe another host.
46918316Swollman		 * This reduces the intermingling of answers.
47018316Swollman		 */
47118316Swollman		while (*argv != 0 && 0 > out(*argv++))
47218316Swollman			answered++;
47318316Swollman
47418316Swollman		/* continue until no more packets arrive
47518316Swollman		 * or we have heard from all hosts
47618316Swollman		 */
47718316Swollman		if (answered >= argc)
47818316Swollman			break;
47918316Swollman
48018316Swollman		/* or until we have waited a long time
48118316Swollman		 */
48246303Smarkm		if (gettimeofday(&now, 0) < 0) {
48346524Smarkm			perror("gettimeofday(now)");
48446524Smarkm			exit(1);
48546303Smarkm		}
48618316Swollman		if (sent.tv_sec + wtime <= now.tv_sec)
48718316Swollman			break;
48818316Swollman	}
48918316Swollman
49018316Swollman	/* fail if there was no answer */
49118316Swollman	exit (answered >= argc ? 0 : 1);
49218316Swollman}
49318316Swollman
49418316Swollman
49519880Swollman/* send to one host
49618316Swollman */
49718316Swollmanstatic int
49846303Smarkmout(const char *host)
49918316Swollman{
50018316Swollman	struct sockaddr_in router;
50118316Swollman	struct hostent *hp;
50218316Swollman
50318316Swollman	if (gettimeofday(&sent, 0) < 0) {
50446524Smarkm		perror("gettimeofday(sent)");
50546524Smarkm		return -1;
50618316Swollman	}
50718316Swollman
50846303Smarkm	memset(&router, 0, sizeof(router));
50918316Swollman	router.sin_family = AF_INET;
51018316Swollman#ifdef _HAVE_SIN_LEN
51118316Swollman	router.sin_len = sizeof(router);
51218316Swollman#endif
51318316Swollman	if (!inet_aton(host, &router.sin_addr)) {
51418316Swollman		hp = gethostbyname(host);
51518316Swollman		if (hp == 0) {
51618316Swollman			herror(host);
51718316Swollman			return -1;
51818316Swollman		}
51946303Smarkm		memcpy(&router.sin_addr, hp->h_addr, sizeof(router.sin_addr));
52018316Swollman	}
52118316Swollman	router.sin_port = htons(RIP_PORT);
52218316Swollman
52346303Smarkm	if (sendto(soc, &omsg_buf, omsg_len, 0,
52418316Swollman		   (struct sockaddr *)&router, sizeof(router)) < 0) {
52546524Smarkm		perror(host);
52646524Smarkm		return -1;
52718316Swollman	}
52818316Swollman
52918316Swollman	return 0;
53018316Swollman}
53118316Swollman
53218316Swollman
53318316Swollman/*
53419880Swollman * Convert string to printable characters
53519880Swollman */
53619880Swollmanstatic char *
53719880Swollmanqstring(u_char *s, int len)
53819880Swollman{
53919880Swollman	static char buf[8*20+1];
54019880Swollman	char *p;
54119880Swollman	u_char *s2, c;
54219880Swollman
54319880Swollman
54419880Swollman	for (p = buf; len != 0 && p < &buf[sizeof(buf)-1]; len--) {
54519880Swollman		c = *s++;
54619880Swollman		if (c == '\0') {
54719880Swollman			for (s2 = s+1; s2 < &s[len]; s2++) {
54819880Swollman				if (*s2 != '\0')
54919880Swollman					break;
55019880Swollman			}
55119880Swollman			if (s2 >= &s[len])
55219880Swollman			    goto exit;
55319880Swollman		}
55419880Swollman
55519880Swollman		if (c >= ' ' && c < 0x7f && c != '\\') {
55619880Swollman			*p++ = c;
55719880Swollman			continue;
55819880Swollman		}
55919880Swollman		*p++ = '\\';
56019880Swollman		switch (c) {
56119880Swollman		case '\\':
56219880Swollman			*p++ = '\\';
56319880Swollman			break;
56419880Swollman		case '\n':
56519880Swollman			*p++= 'n';
56619880Swollman			break;
56719880Swollman		case '\r':
56819880Swollman			*p++= 'r';
56919880Swollman			break;
57019880Swollman		case '\t':
57119880Swollman			*p++ = 't';
57219880Swollman			break;
57319880Swollman		case '\b':
57419880Swollman			*p++ = 'b';
57519880Swollman			break;
57619880Swollman		default:
57719880Swollman			p += sprintf(p,"%o",c);
57819880Swollman			break;
57919880Swollman		}
58019880Swollman	}
58119880Swollmanexit:
58219880Swollman	*p = '\0';
58319880Swollman	return buf;
58419880Swollman}
58519880Swollman
58619880Swollman
58719880Swollman/*
58818316Swollman * Handle an incoming RIP packet.
58918316Swollman */
59018316Swollmanstatic void
59118316Swollmanrip_input(struct sockaddr_in *from,
59218316Swollman	  int size)
59318316Swollman{
59418316Swollman	struct netinfo *n, *lim;
59518316Swollman	struct in_addr in;
59646303Smarkm	const char *name;
59718316Swollman	char net_buf[80];
59846303Smarkm	u_char hash[RIP_AUTH_MD5_LEN];
59946303Smarkm	MD5_CTX md5_ctx;
60046303Smarkm	u_char md5_authed = 0;
60118316Swollman	u_int mask, dmask;
60218316Swollman	char *sp;
60318316Swollman	int i;
60418316Swollman	struct hostent *hp;
60518316Swollman	struct netent *np;
60619880Swollman	struct netauth *na;
60718316Swollman
60818316Swollman
60918316Swollman	if (nflag) {
61018316Swollman		printf("%s:", inet_ntoa(from->sin_addr));
61118316Swollman	} else {
61218316Swollman		hp = gethostbyaddr((char*)&from->sin_addr,
61318316Swollman				   sizeof(struct in_addr), AF_INET);
61418316Swollman		if (hp == 0) {
61518316Swollman			printf("%s:",
61618316Swollman			       inet_ntoa(from->sin_addr));
61718316Swollman		} else {
61818316Swollman			printf("%s (%s):", hp->h_name,
61918316Swollman			       inet_ntoa(from->sin_addr));
62018316Swollman		}
62118316Swollman	}
62218316Swollman	if (IMSG.rip_cmd != RIPCMD_RESPONSE) {
62318316Swollman		printf("\n    unexpected response type %d\n", IMSG.rip_cmd);
62418316Swollman		return;
62518316Swollman	}
62618316Swollman	printf(" RIPv%d%s %d bytes\n", IMSG.rip_vers,
62718316Swollman	       (IMSG.rip_vers != RIPv1 && IMSG.rip_vers != RIPv2) ? " ?" : "",
62818316Swollman	       size);
62918316Swollman	if (size > MAXPACKETSIZE) {
63046303Smarkm		if (size > (int)sizeof(imsg_buf) - (int)sizeof(*n)) {
63118316Swollman			printf("       at least %d bytes too long\n",
63218316Swollman			       size-MAXPACKETSIZE);
63346303Smarkm			size = (int)sizeof(imsg_buf) - (int)sizeof(*n);
63418316Swollman		} else {
63518316Swollman			printf("       %d bytes too long\n",
63618316Swollman			       size-MAXPACKETSIZE);
63718316Swollman		}
63818316Swollman	} else if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
63918316Swollman		printf("    response of bad length=%d\n", size);
64018316Swollman	}
64118316Swollman
64218316Swollman	n = IMSG.rip_nets;
64318316Swollman	lim = (struct netinfo *)((char*)n + size) - 1;
64418316Swollman	for (; n <= lim; n++) {
64518316Swollman		name = "";
64618316Swollman		if (n->n_family == RIP_AF_INET) {
64718316Swollman			in.s_addr = n->n_dst;
64818316Swollman			(void)strcpy(net_buf, inet_ntoa(in));
64918316Swollman
65018316Swollman			mask = ntohl(n->n_mask);
65118316Swollman			dmask = mask & -mask;
65218316Swollman			if (mask != 0) {
65318316Swollman				sp = &net_buf[strlen(net_buf)];
65418316Swollman				if (IMSG.rip_vers == RIPv1) {
65518316Swollman					(void)sprintf(sp," mask=%#x ? ",mask);
65618316Swollman					mask = 0;
65718316Swollman				} else if (mask + dmask == 0) {
65818316Swollman					for (i = 0;
65918316Swollman					     (i != 32
66018316Swollman					      && ((1<<i)&mask) == 0);
66118316Swollman					     i++)
66218316Swollman						continue;
66318316Swollman					(void)sprintf(sp, "/%d",32-i);
66418316Swollman				} else {
66518316Swollman					(void)sprintf(sp," (mask %#x)", mask);
66618316Swollman				}
66718316Swollman			}
66818316Swollman
66918316Swollman			if (!nflag) {
67018316Swollman				if (mask == 0) {
67118316Swollman					mask = std_mask(in.s_addr);
67218316Swollman					if ((ntohl(in.s_addr) & ~mask) != 0)
67318316Swollman						mask = 0;
67418316Swollman				}
67518316Swollman				/* Without a netmask, do not worry about
67618316Swollman				 * whether the destination is a host or a
67718316Swollman				 * network. Try both and use the first name
67818316Swollman				 * we get.
67918316Swollman				 *
68018316Swollman				 * If we have a netmask we can make a
68118316Swollman				 * good guess.
68218316Swollman				 */
68318316Swollman				if ((in.s_addr & ~mask) == 0) {
68418316Swollman					np = getnetbyaddr((long)in.s_addr,
68518316Swollman							  AF_INET);
68618316Swollman					if (np != 0)
68718316Swollman						name = np->n_name;
68818316Swollman					else if (in.s_addr == 0)
68918316Swollman						name = "default";
69018316Swollman				}
69118316Swollman				if (name[0] == '\0'
69218316Swollman				    && ((in.s_addr & ~mask) != 0
69318316Swollman					|| mask == 0xffffffff)) {
69418316Swollman					hp = gethostbyaddr((char*)&in,
69518316Swollman							   sizeof(in),
69618316Swollman							   AF_INET);
69718316Swollman					if (hp != 0)
69818316Swollman						name = hp->h_name;
69918316Swollman				}
70018316Swollman			}
70118316Swollman
70218316Swollman		} else if (n->n_family == RIP_AF_AUTH) {
70319880Swollman			na = (struct netauth*)n;
70419880Swollman			if (na->a_type == RIP_AUTH_PW
70519880Swollman			    && n == IMSG.rip_nets) {
70619880Swollman				(void)printf("  Password Authentication:"
70719880Swollman					     " \"%s\"\n",
70819880Swollman					     qstring(na->au.au_pw,
70919880Swollman						     RIP_AUTH_PW_LEN));
71019880Swollman				continue;
71119880Swollman			}
71219880Swollman
71319880Swollman			if (na->a_type == RIP_AUTH_MD5
71419880Swollman			    && n == IMSG.rip_nets) {
71546303Smarkm				(void)printf("  MD5 Auth"
71619880Swollman					     " len=%d KeyID=%d"
71746303Smarkm					     " auth_len=%d"
71846303Smarkm					     " seqno=%#x"
71919880Swollman					     " rsvd=%#x,%#x\n",
72046303Smarkm					     ntohs(na->au.a_md5.md5_pkt_len),
72119880Swollman					     na->au.a_md5.md5_keyid,
72246303Smarkm					     na->au.a_md5.md5_auth_len,
72346303Smarkm					     (int)ntohl(na->au.a_md5.md5_seqno),
72419880Swollman					     na->au.a_md5.rsvd[0],
72519880Swollman					     na->au.a_md5.rsvd[1]);
72646303Smarkm				md5_authed = 1;
72719880Swollman				continue;
72819880Swollman			}
72919880Swollman			(void)printf("  Authentication type %d: ",
73019880Swollman				     ntohs(na->a_type));
73146303Smarkm			for (i = 0; i < (int)sizeof(na->au.au_pw); i++)
73219880Swollman				(void)printf("%02x ", na->au.au_pw[i]);
73318316Swollman			putc('\n', stdout);
73446303Smarkm			if (md5_authed && n+1 > lim
73546303Smarkm			    && na->a_type == ntohs(1)) {
73646303Smarkm				MD5Init(&md5_ctx);
73746303Smarkm				MD5Update(&md5_ctx, (u_char *)&IMSG,
73846303Smarkm					  (char *)na-(char *)&IMSG);
73946303Smarkm				MD5Update(&md5_ctx, (u_char *)passwd,
74046303Smarkm					  RIP_AUTH_MD5_LEN);
74146303Smarkm				MD5Final(hash, &md5_ctx);
74246303Smarkm				(void)printf("    %s hash\n",
74346303Smarkm					     memcmp(hash, na->au.au_pw,
74446303Smarkm						    sizeof(hash))
74546303Smarkm					     ? "WRONG" : "correct");
74646303Smarkm			}
74718316Swollman			continue;
74818316Swollman
74918316Swollman		} else {
75018316Swollman			(void)sprintf(net_buf, "(af %#x) %d.%d.%d.%d",
75118316Swollman				      ntohs(n->n_family),
75218316Swollman				      (char)(n->n_dst >> 24),
75318316Swollman				      (char)(n->n_dst >> 16),
75418316Swollman				      (char)(n->n_dst >> 8),
75518316Swollman				      (char)n->n_dst);
75618316Swollman		}
75718316Swollman
75818316Swollman		(void)printf("  %-18s metric %2d %-10s",
75946303Smarkm			     net_buf, (int)ntohl(n->n_metric), name);
76018316Swollman
76118316Swollman		if (n->n_nhop != 0) {
76218316Swollman			in.s_addr = n->n_nhop;
76318316Swollman			if (nflag)
76418316Swollman				hp = 0;
76518316Swollman			else
76618316Swollman				hp = gethostbyaddr((char*)&in, sizeof(in),
76718316Swollman						   AF_INET);
76818316Swollman			(void)printf(" nhop=%-15s%s",
76918316Swollman				     (hp != 0) ? hp->h_name : inet_ntoa(in),
77018316Swollman				     (IMSG.rip_vers == RIPv1) ? " ?" : "");
77118316Swollman		}
77218316Swollman		if (n->n_tag != 0)
77318316Swollman			(void)printf(" tag=%#x%s", n->n_tag,
77418316Swollman				     (IMSG.rip_vers == RIPv1) ? " ?" : "");
77518316Swollman		putc('\n', stdout);
77618316Swollman	}
77718316Swollman}
77818316Swollman
77918316Swollman
78018316Swollman/* Return the classical netmask for an IP address.
78118316Swollman */
78218316Swollmanstatic u_int
78318316Swollmanstd_mask(u_int addr)			/* in network order */
78418316Swollman{
78590868Smike	addr = ntohl(addr);		/* was a host, not a network */
78618316Swollman
78718316Swollman	if (addr == 0)			/* default route has mask 0 */
78818316Swollman		return 0;
78918316Swollman	if (IN_CLASSA(addr))
79018316Swollman		return IN_CLASSA_NET;
79118316Swollman	if (IN_CLASSB(addr))
79218316Swollman		return IN_CLASSB_NET;
79318316Swollman	return IN_CLASSC_NET;
79418316Swollman}
79518316Swollman
79618316Swollman
79718316Swollman/* get a network number as a name or a number, with an optional "/xx"
79818316Swollman * netmask.
79918316Swollman */
80018316Swollmanstatic int				/* 0=bad */
80118316Swollmangetnet(char *name,
80218316Swollman       struct netinfo *rt)
80318316Swollman{
80418316Swollman	int i;
80518316Swollman	struct netent *nentp;
80618316Swollman	u_int mask;
80718316Swollman	struct in_addr in;
80818316Swollman	char hname[MAXHOSTNAMELEN+1];
80918316Swollman	char *mname, *p;
81018316Swollman
81118316Swollman
81218316Swollman	/* Detect and separate "1.2.3.4/24"
81318316Swollman	 */
81446303Smarkm	if (0 != (mname = strrchr(name,'/'))) {
81518316Swollman		i = (int)(mname - name);
81646303Smarkm		if (i > (int)sizeof(hname)-1)	/* name too long */
81718316Swollman			return 0;
81846303Smarkm		memmove(hname, name, i);
81918316Swollman		hname[i] = '\0';
82018316Swollman		mname++;
82118316Swollman		name = hname;
82218316Swollman	}
82318316Swollman
82418316Swollman	nentp = getnetbyname(name);
82518316Swollman	if (nentp != 0) {
82618316Swollman		in.s_addr = nentp->n_net;
82718316Swollman	} else if (inet_aton(name, &in) == 1) {
82890868Smike		in.s_addr = ntohl(in.s_addr);
82918316Swollman	} else {
83018316Swollman		return 0;
83118316Swollman	}
83218316Swollman
83318316Swollman	if (mname == 0) {
83418316Swollman		mask = std_mask(in.s_addr);
83518316Swollman		if ((~mask & in.s_addr) != 0)
83618316Swollman			mask = 0xffffffff;
83718316Swollman	} else {
83818316Swollman		mask = (u_int)strtoul(mname, &p, 0);
83918316Swollman		if (*p != '\0' || mask > 32)
84018316Swollman			return 0;
84118316Swollman		mask = 0xffffffff << (32-mask);
84218316Swollman	}
84318316Swollman
84418316Swollman	rt->n_dst = htonl(in.s_addr);
84518316Swollman	rt->n_family = RIP_AF_INET;
84618316Swollman	rt->n_mask = htonl(mask);
84718316Swollman	return 1;
84818316Swollman}
84919880Swollman
85019880Swollman
85119880Swollman/* strtok(), but honoring backslash
85219880Swollman */
85319880Swollmanstatic int				/* -1=bad */
85419880Swollmanparse_quote(char **linep,
85546303Smarkm	    const char *delims,
85619880Swollman	    char *delimp,
85719880Swollman	    char *buf,
85819880Swollman	    int	lim)
85919880Swollman{
86046303Smarkm	char c, *pc;
86146303Smarkm	const char *p;
86219880Swollman
86319880Swollman
86419880Swollman	pc = *linep;
86519880Swollman	if (*pc == '\0')
86619880Swollman		return -1;
86719880Swollman
86819880Swollman	for (;;) {
86919880Swollman		if (lim == 0)
87019880Swollman			return -1;
87119880Swollman		c = *pc++;
87219880Swollman		if (c == '\0')
87319880Swollman			break;
87419880Swollman
87537815Sphk		if (c == '\\' && *pc != '\0') {
87619880Swollman			if ((c = *pc++) == 'n') {
87719880Swollman				c = '\n';
87819880Swollman			} else if (c == 'r') {
87919880Swollman				c = '\r';
88019880Swollman			} else if (c == 't') {
88119880Swollman				c = '\t';
88219880Swollman			} else if (c == 'b') {
88319880Swollman				c = '\b';
88419880Swollman			} else if (c >= '0' && c <= '7') {
88519880Swollman				c -= '0';
88619880Swollman				if (*pc >= '0' && *pc <= '7') {
88719880Swollman					c = (c<<3)+(*pc++ - '0');
88819880Swollman					if (*pc >= '0' && *pc <= '7')
88919880Swollman					    c = (c<<3)+(*pc++ - '0');
89019880Swollman				}
89119880Swollman			}
89219880Swollman
89319880Swollman		} else {
89419880Swollman			for (p = delims; *p != '\0'; ++p) {
89519880Swollman				if (*p == c)
89619880Swollman					goto exit;
89719880Swollman			}
89819880Swollman		}
89919880Swollman
90019880Swollman		*buf++ = c;
90119880Swollman		--lim;
90219880Swollman	}
90319880Swollmanexit:
90419880Swollman	if (delimp != 0)
90519880Swollman		*delimp = c;
90619880Swollman	*linep = pc-1;
90719880Swollman	if (lim != 0)
90819880Swollman		*buf = '\0';
90919880Swollman	return 0;
91019880Swollman}
911