rtquery.c revision 126250
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 126250 2004-02-25 23:45:57Z bms $
3418316Swollman */
3518316Swollman
3646303Smarkm#include <sys/cdefs.h>
3718316Swollman#include <sys/param.h>
3846303Smarkm#include <sys/protosw.h>
3918316Swollman#include <sys/socket.h>
4018316Swollman#include <sys/time.h>
4118316Swollman#include <netinet/in.h>
4218316Swollman#define RIPVERSION RIPv2
4318316Swollman#include <protocols/routed.h>
4418316Swollman#include <arpa/inet.h>
4546303Smarkm#include <netdb.h>
4632502Scharnier#include <errno.h>
4746303Smarkm#include <unistd.h>
4818316Swollman#include <stdio.h>
4918316Swollman#include <stdlib.h>
5018316Swollman#include <string.h>
5118316Swollman#ifdef sgi
5218316Swollman#include <strings.h>
5318316Swollman#include <bstring.h>
5418316Swollman#endif
5518316Swollman
56126250Sbms#define UNUSED __attribute__((unused))
57126250Sbms#ifndef __RCSID
58126250Sbms#define __RCSID(_s) static const char rcsid[] UNUSED = _s
5946303Smarkm#endif
60126250Sbms#ifndef __COPYRIGHT
61126250Sbms#define __COPYRIGHT(_s) static const char copyright[] UNUSED = _s
62126250Sbms#endif
63126250Sbms__COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993\n"
64126250Sbms	    "The Regents of the University of California."
65126250Sbms	    "  All rights reserved.\n");
66126250Sbms#ifdef __NetBSD__
67126250Sbms__RCSID("$NetBSD$");
68126250Sbms#elif defined(__FreeBSD__)
69126250Sbms__RCSID("$FreeBSD: head/sbin/routed/rtquery/rtquery.c 126250 2004-02-25 23:45:57Z bms $");
70126250Sbms#else
71126250Sbms__RCSID("$Revision: 2.26 $");
72126250Sbms#ident "$Revision: 2.26 $"
73126250Sbms#endif
7446303Smarkm
7518316Swollman#ifndef sgi
7618316Swollman#define _HAVE_SIN_LEN
7718316Swollman#endif
7818316Swollman
79126250Sbms#ifdef __NetBSD__
80126250Sbms#include <md5.h>
81126250Sbms#else
8246303Smarkm#define MD5_DIGEST_LEN 16
8346303Smarkmtypedef struct {
8446303Smarkm	u_int32_t state[4];		/* state (ABCD) */
8546303Smarkm	u_int32_t count[2];		/* # of bits, modulo 2^64 (LSB 1st) */
8646303Smarkm	unsigned char buffer[64];	/* input buffer */
8746303Smarkm} MD5_CTX;
8846303Smarkmextern void MD5Init(MD5_CTX*);
8946303Smarkmextern void MD5Update(MD5_CTX*, u_char*, u_int);
9046303Smarkmextern void MD5Final(u_char[MD5_DIGEST_LEN], MD5_CTX*);
91126250Sbms#endif
9246303Smarkm
9346303Smarkm
9418316Swollman#define	WTIME	15		/* Time to wait for all responses */
9518316Swollman#define	STIME	(250*1000)	/* usec to wait for another response */
9618316Swollman
9746303Smarkmint	soc;
9818316Swollman
9946303Smarkmconst char *pgmname;
10046303Smarkm
10118316Swollmanunion {
10218316Swollman	struct rip rip;
10318316Swollman	char	packet[MAXPACKETSIZE+MAXPATHLEN];
10418316Swollman} omsg_buf;
10518316Swollman#define OMSG omsg_buf.rip
10618316Swollmanint omsg_len = sizeof(struct rip);
10718316Swollman
10818316Swollmanunion {
10918316Swollman	struct	rip rip;
11018316Swollman	char	packet[MAXPACKETSIZE+1024];
11118316Swollman	} imsg_buf;
11218316Swollman#define IMSG imsg_buf.rip
11318316Swollman
11418316Swollmanint	nflag;				/* numbers, no names */
11518316Swollmanint	pflag;				/* play the `gated` game */
11618316Swollmanint	ripv2 = 1;			/* use RIP version 2 */
11718316Swollmanint	wtime = WTIME;
11818316Swollmanint	rflag;				/* 1=ask about a particular route */
11919880Swollmanint	trace, not_trace;		/* send trace command or not */
12019880Swollmanint	auth_type = RIP_AUTH_NONE;
12119880Swollmanchar	passwd[RIP_AUTH_PW_LEN];
12219880Swollmanu_long	keyid;
12318316Swollman
12418316Swollmanstruct timeval sent;			/* when query sent */
12518316Swollman
12646303Smarkmstatic char localhost_str[] = "localhost";
12746303Smarkmstatic char *default_argv[] = {localhost_str, 0};
12846303Smarkm
12918316Swollmanstatic void rip_input(struct sockaddr_in*, int);
13046303Smarkmstatic int out(const char *);
13146303Smarkmstatic void trace_loop(char *argv[]) __attribute((__noreturn__));
13246303Smarkmstatic void query_loop(char *argv[], int) __attribute((__noreturn__));
13318316Swollmanstatic int getnet(char *, struct netinfo *);
13418316Swollmanstatic u_int std_mask(u_int);
13546303Smarkmstatic int parse_quote(char **, const char *, char *, char *, int);
13637908Scharnierstatic void usage(void);
13718316Swollman
13846303Smarkm
13937908Scharnierint
14018316Swollmanmain(int argc,
14118316Swollman     char *argv[])
14218316Swollman{
14318316Swollman	int ch, bsize;
14419880Swollman	char *p, *options, *value, delim;
14546303Smarkm	const char *result;
14618316Swollman
14718316Swollman	OMSG.rip_nets[0].n_dst = RIP_DEFAULT;
14818316Swollman	OMSG.rip_nets[0].n_family = RIP_AF_UNSPEC;
14918316Swollman	OMSG.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY);
15018316Swollman
15146303Smarkm	pgmname = argv[0];
15224359Simp	while ((ch = getopt(argc, argv, "np1w:r:t:a:")) != -1)
15318316Swollman		switch (ch) {
15418316Swollman		case 'n':
15518316Swollman			not_trace = 1;
15618316Swollman			nflag = 1;
15718316Swollman			break;
15818316Swollman
15918316Swollman		case 'p':
16018316Swollman			not_trace = 1;
16118316Swollman			pflag = 1;
16218316Swollman			break;
16318316Swollman
16418316Swollman		case '1':
16518316Swollman			ripv2 = 0;
16618316Swollman			break;
16718316Swollman
16818316Swollman		case 'w':
16918316Swollman			not_trace = 1;
17018316Swollman			wtime = (int)strtoul(optarg, &p, 0);
17118316Swollman			if (*p != '\0'
17218316Swollman			    || wtime <= 0)
17337908Scharnier				usage();
17418316Swollman			break;
17518316Swollman
17618316Swollman		case 'r':
17718316Swollman			not_trace = 1;
17818316Swollman			if (rflag)
17937908Scharnier				usage();
18018316Swollman			rflag = getnet(optarg, &OMSG.rip_nets[0]);
18118316Swollman			if (!rflag) {
18218316Swollman				struct hostent *hp = gethostbyname(optarg);
18346303Smarkm				if (hp == 0) {
18446303Smarkm					fprintf(stderr, "%s: %s:",
18546303Smarkm						pgmname, optarg);
18646303Smarkm					herror(0);
18746303Smarkm					exit(1);
18846303Smarkm				}
18946303Smarkm				memcpy(&OMSG.rip_nets[0].n_dst, hp->h_addr,
19046303Smarkm				       sizeof(OMSG.rip_nets[0].n_dst));
19118316Swollman				OMSG.rip_nets[0].n_family = RIP_AF_INET;
19218316Swollman				OMSG.rip_nets[0].n_mask = -1;
19318316Swollman				rflag = 1;
19418316Swollman			}
19518316Swollman			break;
19618316Swollman
19718316Swollman		case 't':
19818316Swollman			trace = 1;
19918316Swollman			options = optarg;
20018316Swollman			while (*options != '\0') {
20146303Smarkm				/* messy complications to make -W -Wall happy */
20246303Smarkm				static char on_str[] = "on";
20346303Smarkm				static char more_str[] = "more";
20446303Smarkm				static char off_str[] = "off";
20546303Smarkm				static char dump_str[] = "dump";
20646303Smarkm				static char *traceopts[] = {
20718316Swollman#				    define TRACE_ON	0
20846303Smarkm					on_str,
20918316Swollman#				    define TRACE_MORE	1
21046303Smarkm					more_str,
21118316Swollman#				    define TRACE_OFF	2
21246303Smarkm					off_str,
21318316Swollman#				    define TRACE_DUMP	3
21446303Smarkm					dump_str,
21518316Swollman					0
21618316Swollman				};
21746303Smarkm				result = "";
21818316Swollman				switch (getsubopt(&options,traceopts,&value)) {
21918316Swollman				case TRACE_ON:
22018316Swollman					OMSG.rip_cmd = RIPCMD_TRACEON;
22118316Swollman					if (!value
22218316Swollman					    || strlen(value) > MAXPATHLEN)
22346303Smarkm					    usage();
22446303Smarkm					result = value;
22518316Swollman					break;
22618316Swollman				case TRACE_MORE:
22718316Swollman					if (value)
22846303Smarkm					    usage();
22918316Swollman					OMSG.rip_cmd = RIPCMD_TRACEON;
23018316Swollman					break;
23118316Swollman				case TRACE_OFF:
23218316Swollman					if (value)
23346303Smarkm					    usage();
23418316Swollman					OMSG.rip_cmd = RIPCMD_TRACEOFF;
23518316Swollman					break;
23618316Swollman				case TRACE_DUMP:
23718316Swollman					if (value)
23846303Smarkm					    usage();
23918316Swollman					OMSG.rip_cmd = RIPCMD_TRACEON;
24046303Smarkm					result = "dump/../table";
24118316Swollman					break;
24218316Swollman				default:
24337908Scharnier					usage();
24418316Swollman				}
24546303Smarkm				strcpy((char*)OMSG.rip_tracefile, result);
24646303Smarkm				omsg_len += strlen(result) - sizeof(OMSG.ripun);
24718316Swollman			}
24818316Swollman			break;
24918316Swollman
25019880Swollman		case 'a':
25119880Swollman			not_trace = 1;
25219880Swollman			p = strchr(optarg,'=');
25319880Swollman			if (!p)
25437908Scharnier				usage();
25519880Swollman			*p++ = '\0';
25619880Swollman			if (!strcasecmp("passwd",optarg))
25719880Swollman				auth_type = RIP_AUTH_PW;
25819880Swollman			else if (!strcasecmp("md5_passwd",optarg))
25919880Swollman				auth_type = RIP_AUTH_MD5;
26019880Swollman			else
26137908Scharnier				usage();
26219880Swollman			if (0 > parse_quote(&p,"|",&delim,
26346303Smarkm					    passwd, sizeof(passwd)))
26437908Scharnier				usage();
26519880Swollman			if (auth_type == RIP_AUTH_MD5
26619880Swollman			    && delim == '|') {
26719880Swollman				keyid = strtoul(p+1,&p,0);
26819880Swollman				if (keyid > 255 || *p != '\0')
26937908Scharnier					usage();
27019880Swollman			} else if (delim != '\0') {
27137908Scharnier				usage();
27219880Swollman			}
27319880Swollman			break;
27419880Swollman
27518316Swollman		default:
27637908Scharnier			usage();
27718316Swollman	}
27818316Swollman	argv += optind;
27918316Swollman	argc -= optind;
28046303Smarkm	if (not_trace && trace)
28137908Scharnier		usage();
28246303Smarkm	if (argc == 0) {
28346303Smarkm		argc = 1;
28446303Smarkm		argv = default_argv;
28546303Smarkm	}
28618316Swollman
28746303Smarkm	soc = socket(AF_INET, SOCK_DGRAM, 0);
28846303Smarkm	if (soc < 0) {
28946524Smarkm		perror("socket");
29046524Smarkm		exit(2);
29146303Smarkm	}
29218316Swollman
29318316Swollman	/* be prepared to receive a lot of routes */
29418316Swollman	for (bsize = 127*1024; ; bsize -= 1024) {
29546303Smarkm		if (setsockopt(soc, SOL_SOCKET, SO_RCVBUF,
29618316Swollman			       &bsize, sizeof(bsize)) == 0)
29718316Swollman			break;
29818316Swollman		if (bsize <= 4*1024) {
29946524Smarkm			perror("setsockopt SO_RCVBUF");
30018316Swollman			break;
30118316Swollman		}
30218316Swollman	}
30318316Swollman
30418316Swollman	if (trace)
30518316Swollman		trace_loop(argv);
30618316Swollman	else
30718316Swollman		query_loop(argv, argc);
30818316Swollman	/* NOTREACHED */
30946303Smarkm	return 0;
31018316Swollman}
31118316Swollman
31246303Smarkm
31337908Scharnierstatic void
31446303Smarkmusage(void)
31537908Scharnier{
31646303Smarkm	fprintf(stderr,
31746303Smarkm		"usage:  rtquery [-np1] [-r tgt_rt] [-w wtime]"
31846303Smarkm		" [-a type=passwd] host1 [host2 ...]\n"
31946303Smarkm		"\trtquery -t {on=filename|more|off|dump}"
32046303Smarkm				" host1 [host2 ...]\n");
32137908Scharnier	exit(1);
32237908Scharnier}
32318316Swollman
32446303Smarkm
32518316Swollman/* tell the target hosts about tracing
32618316Swollman */
32718316Swollmanstatic void
32818316Swollmantrace_loop(char *argv[])
32918316Swollman{
33018316Swollman	struct sockaddr_in myaddr;
33118316Swollman	int res;
33218316Swollman
33346303Smarkm	if (geteuid() != 0) {
33446303Smarkm		(void)fprintf(stderr, "-t requires UID 0\n");
33546303Smarkm		exit(1);
33646303Smarkm	}
33718316Swollman
33818316Swollman	if (ripv2) {
33918316Swollman		OMSG.rip_vers = RIPv2;
34018316Swollman	} else {
34118316Swollman		OMSG.rip_vers = RIPv1;
34218316Swollman	}
34318316Swollman
34446303Smarkm	memset(&myaddr, 0, sizeof(myaddr));
34518316Swollman	myaddr.sin_family = AF_INET;
34618316Swollman#ifdef _HAVE_SIN_LEN
34718316Swollman	myaddr.sin_len = sizeof(myaddr);
34818316Swollman#endif
34918316Swollman	myaddr.sin_port = htons(IPPORT_RESERVED-1);
35046303Smarkm	while (bind(soc, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
35146303Smarkm		if (errno != EADDRINUSE
35246303Smarkm		    || myaddr.sin_port == 0) {
35346524Smarkm			perror("bind");
35446524Smarkm			exit(2);
35546303Smarkm		}
35618316Swollman		myaddr.sin_port = htons(ntohs(myaddr.sin_port)-1);
35718316Swollman	}
35818316Swollman
35918316Swollman	res = 1;
36018316Swollman	while (*argv != 0) {
36118316Swollman		if (out(*argv++) <= 0)
36218316Swollman			res = 0;
36318316Swollman	}
36418316Swollman	exit(res);
36518316Swollman}
36618316Swollman
36718316Swollman
36818316Swollman/* query all of the listed hosts
36918316Swollman */
37018316Swollmanstatic void
37118316Swollmanquery_loop(char *argv[], int argc)
37218316Swollman{
37319880Swollman#	define NA0 (OMSG.rip_auths[0])
37419880Swollman#	define NA2 (OMSG.rip_auths[2])
37518316Swollman	struct seen {
37618316Swollman		struct seen *next;
37718316Swollman		struct in_addr addr;
37818316Swollman	} *seen, *sp;
37918316Swollman	int answered = 0;
38018316Swollman	int cc;
38118316Swollman	fd_set bits;
38218316Swollman	struct timeval now, delay;
38318316Swollman	struct sockaddr_in from;
38418316Swollman	int fromlen;
38519880Swollman	MD5_CTX md5_ctx;
38618316Swollman
38718316Swollman
38818316Swollman	OMSG.rip_cmd = (pflag) ? RIPCMD_POLL : RIPCMD_REQUEST;
38918316Swollman	if (ripv2) {
39018316Swollman		OMSG.rip_vers = RIPv2;
39119880Swollman		if (auth_type == RIP_AUTH_PW) {
39219880Swollman			OMSG.rip_nets[1] = OMSG.rip_nets[0];
39319880Swollman			NA0.a_family = RIP_AF_AUTH;
39419880Swollman			NA0.a_type = RIP_AUTH_PW;
39546303Smarkm			memcpy(NA0.au.au_pw, passwd, RIP_AUTH_PW_LEN);
39619880Swollman			omsg_len += sizeof(OMSG.rip_nets[0]);
39719880Swollman
39819880Swollman		} else if (auth_type == RIP_AUTH_MD5) {
39919880Swollman			OMSG.rip_nets[1] = OMSG.rip_nets[0];
40019880Swollman			NA0.a_family = RIP_AF_AUTH;
40119880Swollman			NA0.a_type = RIP_AUTH_MD5;
40219880Swollman			NA0.au.a_md5.md5_keyid = (int8_t)keyid;
403126250Sbms			NA0.au.a_md5.md5_auth_len = RIP_AUTH_MD5_KEY_LEN;
40419880Swollman			NA0.au.a_md5.md5_seqno = 0;
40546303Smarkm			cc = (char *)&NA2-(char *)&OMSG;
40646303Smarkm			NA0.au.a_md5.md5_pkt_len = htons(cc);
40719880Swollman			NA2.a_family = RIP_AF_AUTH;
40846303Smarkm			NA2.a_type = htons(1);
40919880Swollman			MD5Init(&md5_ctx);
41046303Smarkm			MD5Update(&md5_ctx,
41146303Smarkm				  (u_char *)&OMSG, cc);
41246303Smarkm			MD5Update(&md5_ctx,
413126250Sbms				  (u_char *)passwd, RIP_AUTH_MD5_HASH_LEN);
41419880Swollman			MD5Final(NA2.au.au_pw, &md5_ctx);
41519880Swollman			omsg_len += 2*sizeof(OMSG.rip_nets[0]);
41619880Swollman		}
41719880Swollman
41818316Swollman	} else {
41918316Swollman		OMSG.rip_vers = RIPv1;
42018316Swollman		OMSG.rip_nets[0].n_mask = 0;
42118316Swollman	}
42218316Swollman
42318316Swollman	/* ask the first (valid) host */
42418316Swollman	seen = 0;
42518316Swollman	while (0 > out(*argv++)) {
42618316Swollman		if (*argv == 0)
427126250Sbms			exit(1);
42818316Swollman		answered++;
42918316Swollman	}
43018316Swollman
43118316Swollman	FD_ZERO(&bits);
43218316Swollman	for (;;) {
43346303Smarkm		FD_SET(soc, &bits);
43418316Swollman		delay.tv_sec = 0;
43518316Swollman		delay.tv_usec = STIME;
43646303Smarkm		cc = select(soc+1, &bits, 0,0, &delay);
43718316Swollman		if (cc > 0) {
43818316Swollman			fromlen = sizeof(from);
43946303Smarkm			cc = recvfrom(soc, imsg_buf.packet,
44018316Swollman				      sizeof(imsg_buf.packet), 0,
44118316Swollman				      (struct sockaddr *)&from, &fromlen);
44246303Smarkm			if (cc < 0) {
44346524Smarkm				perror("recvfrom");
44446524Smarkm				exit(1);
44546303Smarkm			}
44618316Swollman			/* count the distinct responding hosts.
44718316Swollman			 * You cannot match responding hosts with
44818316Swollman			 * addresses to which queries were transmitted,
44918316Swollman			 * because a router might respond with a
45018316Swollman			 * different source address.
45118316Swollman			 */
45218316Swollman			for (sp = seen; sp != 0; sp = sp->next) {
45318316Swollman				if (sp->addr.s_addr == from.sin_addr.s_addr)
45418316Swollman					break;
45518316Swollman			}
45618316Swollman			if (sp == 0) {
45718316Swollman				sp = malloc(sizeof(*sp));
45846303Smarkm				if (sp == 0) {
45946303Smarkm					fprintf(stderr,
46046303Smarkm						"rtquery: malloc failed\n");
46146303Smarkm					exit(1);
46246303Smarkm				}
46318316Swollman				sp->addr = from.sin_addr;
46418316Swollman				sp->next = seen;
46518316Swollman				seen = sp;
46618316Swollman				answered++;
46718316Swollman			}
46818316Swollman
46918316Swollman			rip_input(&from, cc);
47018316Swollman			continue;
47118316Swollman		}
47218316Swollman
47318316Swollman		if (cc < 0) {
47432502Scharnier			if (errno == EINTR)
47518316Swollman				continue;
47646524Smarkm			perror("select");
47746524Smarkm			exit(1);
47818316Swollman		}
47918316Swollman
48018316Swollman		/* After a pause in responses, probe another host.
48118316Swollman		 * This reduces the intermingling of answers.
48218316Swollman		 */
48318316Swollman		while (*argv != 0 && 0 > out(*argv++))
48418316Swollman			answered++;
48518316Swollman
48618316Swollman		/* continue until no more packets arrive
48718316Swollman		 * or we have heard from all hosts
48818316Swollman		 */
48918316Swollman		if (answered >= argc)
49018316Swollman			break;
49118316Swollman
49218316Swollman		/* or until we have waited a long time
49318316Swollman		 */
49446303Smarkm		if (gettimeofday(&now, 0) < 0) {
49546524Smarkm			perror("gettimeofday(now)");
49646524Smarkm			exit(1);
49746303Smarkm		}
49818316Swollman		if (sent.tv_sec + wtime <= now.tv_sec)
49918316Swollman			break;
50018316Swollman	}
50118316Swollman
50218316Swollman	/* fail if there was no answer */
50318316Swollman	exit (answered >= argc ? 0 : 1);
50418316Swollman}
50518316Swollman
50618316Swollman
50719880Swollman/* send to one host
50818316Swollman */
50918316Swollmanstatic int
51046303Smarkmout(const char *host)
51118316Swollman{
51218316Swollman	struct sockaddr_in router;
51318316Swollman	struct hostent *hp;
51418316Swollman
51518316Swollman	if (gettimeofday(&sent, 0) < 0) {
51646524Smarkm		perror("gettimeofday(sent)");
51746524Smarkm		return -1;
51818316Swollman	}
51918316Swollman
52046303Smarkm	memset(&router, 0, sizeof(router));
52118316Swollman	router.sin_family = AF_INET;
52218316Swollman#ifdef _HAVE_SIN_LEN
52318316Swollman	router.sin_len = sizeof(router);
52418316Swollman#endif
52518316Swollman	if (!inet_aton(host, &router.sin_addr)) {
52618316Swollman		hp = gethostbyname(host);
52718316Swollman		if (hp == 0) {
52818316Swollman			herror(host);
52918316Swollman			return -1;
53018316Swollman		}
53146303Smarkm		memcpy(&router.sin_addr, hp->h_addr, sizeof(router.sin_addr));
53218316Swollman	}
53318316Swollman	router.sin_port = htons(RIP_PORT);
53418316Swollman
53546303Smarkm	if (sendto(soc, &omsg_buf, omsg_len, 0,
53618316Swollman		   (struct sockaddr *)&router, sizeof(router)) < 0) {
53746524Smarkm		perror(host);
53846524Smarkm		return -1;
53918316Swollman	}
54018316Swollman
54118316Swollman	return 0;
54218316Swollman}
54318316Swollman
54418316Swollman
54518316Swollman/*
54619880Swollman * Convert string to printable characters
54719880Swollman */
54819880Swollmanstatic char *
54919880Swollmanqstring(u_char *s, int len)
55019880Swollman{
55119880Swollman	static char buf[8*20+1];
55219880Swollman	char *p;
55319880Swollman	u_char *s2, c;
55419880Swollman
55519880Swollman
55619880Swollman	for (p = buf; len != 0 && p < &buf[sizeof(buf)-1]; len--) {
55719880Swollman		c = *s++;
55819880Swollman		if (c == '\0') {
55919880Swollman			for (s2 = s+1; s2 < &s[len]; s2++) {
56019880Swollman				if (*s2 != '\0')
56119880Swollman					break;
56219880Swollman			}
56319880Swollman			if (s2 >= &s[len])
56419880Swollman			    goto exit;
56519880Swollman		}
56619880Swollman
56719880Swollman		if (c >= ' ' && c < 0x7f && c != '\\') {
56819880Swollman			*p++ = c;
56919880Swollman			continue;
57019880Swollman		}
57119880Swollman		*p++ = '\\';
57219880Swollman		switch (c) {
57319880Swollman		case '\\':
57419880Swollman			*p++ = '\\';
57519880Swollman			break;
57619880Swollman		case '\n':
57719880Swollman			*p++= 'n';
57819880Swollman			break;
57919880Swollman		case '\r':
58019880Swollman			*p++= 'r';
58119880Swollman			break;
58219880Swollman		case '\t':
58319880Swollman			*p++ = 't';
58419880Swollman			break;
58519880Swollman		case '\b':
58619880Swollman			*p++ = 'b';
58719880Swollman			break;
58819880Swollman		default:
58919880Swollman			p += sprintf(p,"%o",c);
59019880Swollman			break;
59119880Swollman		}
59219880Swollman	}
59319880Swollmanexit:
59419880Swollman	*p = '\0';
59519880Swollman	return buf;
59619880Swollman}
59719880Swollman
59819880Swollman
59919880Swollman/*
60018316Swollman * Handle an incoming RIP packet.
60118316Swollman */
60218316Swollmanstatic void
60318316Swollmanrip_input(struct sockaddr_in *from,
60418316Swollman	  int size)
60518316Swollman{
60618316Swollman	struct netinfo *n, *lim;
60718316Swollman	struct in_addr in;
60846303Smarkm	const char *name;
60918316Swollman	char net_buf[80];
610126250Sbms	u_char hash[RIP_AUTH_MD5_KEY_LEN];
61146303Smarkm	MD5_CTX md5_ctx;
61246303Smarkm	u_char md5_authed = 0;
61318316Swollman	u_int mask, dmask;
61418316Swollman	char *sp;
61518316Swollman	int i;
61618316Swollman	struct hostent *hp;
61718316Swollman	struct netent *np;
61819880Swollman	struct netauth *na;
61918316Swollman
62018316Swollman
62118316Swollman	if (nflag) {
62218316Swollman		printf("%s:", inet_ntoa(from->sin_addr));
62318316Swollman	} else {
62418316Swollman		hp = gethostbyaddr((char*)&from->sin_addr,
62518316Swollman				   sizeof(struct in_addr), AF_INET);
62618316Swollman		if (hp == 0) {
62718316Swollman			printf("%s:",
62818316Swollman			       inet_ntoa(from->sin_addr));
62918316Swollman		} else {
63018316Swollman			printf("%s (%s):", hp->h_name,
63118316Swollman			       inet_ntoa(from->sin_addr));
63218316Swollman		}
63318316Swollman	}
63418316Swollman	if (IMSG.rip_cmd != RIPCMD_RESPONSE) {
63518316Swollman		printf("\n    unexpected response type %d\n", IMSG.rip_cmd);
63618316Swollman		return;
63718316Swollman	}
63818316Swollman	printf(" RIPv%d%s %d bytes\n", IMSG.rip_vers,
63918316Swollman	       (IMSG.rip_vers != RIPv1 && IMSG.rip_vers != RIPv2) ? " ?" : "",
64018316Swollman	       size);
64118316Swollman	if (size > MAXPACKETSIZE) {
64246303Smarkm		if (size > (int)sizeof(imsg_buf) - (int)sizeof(*n)) {
64318316Swollman			printf("       at least %d bytes too long\n",
64418316Swollman			       size-MAXPACKETSIZE);
64546303Smarkm			size = (int)sizeof(imsg_buf) - (int)sizeof(*n);
64618316Swollman		} else {
64718316Swollman			printf("       %d bytes too long\n",
64818316Swollman			       size-MAXPACKETSIZE);
64918316Swollman		}
65018316Swollman	} else if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
65118316Swollman		printf("    response of bad length=%d\n", size);
65218316Swollman	}
65318316Swollman
65418316Swollman	n = IMSG.rip_nets;
65518316Swollman	lim = (struct netinfo *)((char*)n + size) - 1;
65618316Swollman	for (; n <= lim; n++) {
65718316Swollman		name = "";
65818316Swollman		if (n->n_family == RIP_AF_INET) {
65918316Swollman			in.s_addr = n->n_dst;
66018316Swollman			(void)strcpy(net_buf, inet_ntoa(in));
66118316Swollman
66218316Swollman			mask = ntohl(n->n_mask);
66318316Swollman			dmask = mask & -mask;
66418316Swollman			if (mask != 0) {
66518316Swollman				sp = &net_buf[strlen(net_buf)];
66618316Swollman				if (IMSG.rip_vers == RIPv1) {
66718316Swollman					(void)sprintf(sp," mask=%#x ? ",mask);
66818316Swollman					mask = 0;
66918316Swollman				} else if (mask + dmask == 0) {
67018316Swollman					for (i = 0;
67118316Swollman					     (i != 32
67218316Swollman					      && ((1<<i)&mask) == 0);
67318316Swollman					     i++)
67418316Swollman						continue;
67518316Swollman					(void)sprintf(sp, "/%d",32-i);
67618316Swollman				} else {
67718316Swollman					(void)sprintf(sp," (mask %#x)", mask);
67818316Swollman				}
67918316Swollman			}
68018316Swollman
68118316Swollman			if (!nflag) {
68218316Swollman				if (mask == 0) {
68318316Swollman					mask = std_mask(in.s_addr);
68418316Swollman					if ((ntohl(in.s_addr) & ~mask) != 0)
68518316Swollman						mask = 0;
68618316Swollman				}
68718316Swollman				/* Without a netmask, do not worry about
68818316Swollman				 * whether the destination is a host or a
68918316Swollman				 * network. Try both and use the first name
69018316Swollman				 * we get.
69118316Swollman				 *
69218316Swollman				 * If we have a netmask we can make a
69318316Swollman				 * good guess.
69418316Swollman				 */
69518316Swollman				if ((in.s_addr & ~mask) == 0) {
69618316Swollman					np = getnetbyaddr((long)in.s_addr,
69718316Swollman							  AF_INET);
69818316Swollman					if (np != 0)
69918316Swollman						name = np->n_name;
70018316Swollman					else if (in.s_addr == 0)
70118316Swollman						name = "default";
70218316Swollman				}
70318316Swollman				if (name[0] == '\0'
70418316Swollman				    && ((in.s_addr & ~mask) != 0
70518316Swollman					|| mask == 0xffffffff)) {
70618316Swollman					hp = gethostbyaddr((char*)&in,
70718316Swollman							   sizeof(in),
70818316Swollman							   AF_INET);
70918316Swollman					if (hp != 0)
71018316Swollman						name = hp->h_name;
71118316Swollman				}
71218316Swollman			}
71318316Swollman
71418316Swollman		} else if (n->n_family == RIP_AF_AUTH) {
71519880Swollman			na = (struct netauth*)n;
71619880Swollman			if (na->a_type == RIP_AUTH_PW
71719880Swollman			    && n == IMSG.rip_nets) {
71819880Swollman				(void)printf("  Password Authentication:"
71919880Swollman					     " \"%s\"\n",
72019880Swollman					     qstring(na->au.au_pw,
72119880Swollman						     RIP_AUTH_PW_LEN));
72219880Swollman				continue;
72319880Swollman			}
72419880Swollman
72519880Swollman			if (na->a_type == RIP_AUTH_MD5
72619880Swollman			    && n == IMSG.rip_nets) {
72746303Smarkm				(void)printf("  MD5 Auth"
72819880Swollman					     " len=%d KeyID=%d"
72946303Smarkm					     " auth_len=%d"
73046303Smarkm					     " seqno=%#x"
73119880Swollman					     " rsvd=%#x,%#x\n",
73246303Smarkm					     ntohs(na->au.a_md5.md5_pkt_len),
73319880Swollman					     na->au.a_md5.md5_keyid,
73446303Smarkm					     na->au.a_md5.md5_auth_len,
73546303Smarkm					     (int)ntohl(na->au.a_md5.md5_seqno),
73619880Swollman					     na->au.a_md5.rsvd[0],
73719880Swollman					     na->au.a_md5.rsvd[1]);
73846303Smarkm				md5_authed = 1;
73919880Swollman				continue;
74019880Swollman			}
74119880Swollman			(void)printf("  Authentication type %d: ",
74219880Swollman				     ntohs(na->a_type));
74346303Smarkm			for (i = 0; i < (int)sizeof(na->au.au_pw); i++)
74419880Swollman				(void)printf("%02x ", na->au.au_pw[i]);
74518316Swollman			putc('\n', stdout);
74646303Smarkm			if (md5_authed && n+1 > lim
74746303Smarkm			    && na->a_type == ntohs(1)) {
74846303Smarkm				MD5Init(&md5_ctx);
74946303Smarkm				MD5Update(&md5_ctx, (u_char *)&IMSG,
750126250Sbms					  (char *)na-(char *)&IMSG
751126250Sbms					  +RIP_AUTH_MD5_HASH_XTRA);
75246303Smarkm				MD5Update(&md5_ctx, (u_char *)passwd,
753126250Sbms					  RIP_AUTH_MD5_KEY_LEN);
75446303Smarkm				MD5Final(hash, &md5_ctx);
75546303Smarkm				(void)printf("    %s hash\n",
75646303Smarkm					     memcmp(hash, na->au.au_pw,
75746303Smarkm						    sizeof(hash))
75846303Smarkm					     ? "WRONG" : "correct");
75946303Smarkm			}
76018316Swollman			continue;
76118316Swollman
76218316Swollman		} else {
76318316Swollman			(void)sprintf(net_buf, "(af %#x) %d.%d.%d.%d",
76418316Swollman				      ntohs(n->n_family),
765126250Sbms				      (u_char)(n->n_dst >> 24),
766126250Sbms				      (u_char)(n->n_dst >> 16),
767126250Sbms				      (u_char)(n->n_dst >> 8),
768126250Sbms				      (u_char)n->n_dst);
76918316Swollman		}
77018316Swollman
77118316Swollman		(void)printf("  %-18s metric %2d %-10s",
77246303Smarkm			     net_buf, (int)ntohl(n->n_metric), name);
77318316Swollman
77418316Swollman		if (n->n_nhop != 0) {
77518316Swollman			in.s_addr = n->n_nhop;
77618316Swollman			if (nflag)
77718316Swollman				hp = 0;
77818316Swollman			else
77918316Swollman				hp = gethostbyaddr((char*)&in, sizeof(in),
78018316Swollman						   AF_INET);
78118316Swollman			(void)printf(" nhop=%-15s%s",
78218316Swollman				     (hp != 0) ? hp->h_name : inet_ntoa(in),
78318316Swollman				     (IMSG.rip_vers == RIPv1) ? " ?" : "");
78418316Swollman		}
78518316Swollman		if (n->n_tag != 0)
78618316Swollman			(void)printf(" tag=%#x%s", n->n_tag,
78718316Swollman				     (IMSG.rip_vers == RIPv1) ? " ?" : "");
78818316Swollman		putc('\n', stdout);
78918316Swollman	}
79018316Swollman}
79118316Swollman
79218316Swollman
79318316Swollman/* Return the classical netmask for an IP address.
79418316Swollman */
79518316Swollmanstatic u_int
79618316Swollmanstd_mask(u_int addr)			/* in network order */
79718316Swollman{
79890868Smike	addr = ntohl(addr);		/* was a host, not a network */
79918316Swollman
80018316Swollman	if (addr == 0)			/* default route has mask 0 */
80118316Swollman		return 0;
80218316Swollman	if (IN_CLASSA(addr))
80318316Swollman		return IN_CLASSA_NET;
80418316Swollman	if (IN_CLASSB(addr))
80518316Swollman		return IN_CLASSB_NET;
80618316Swollman	return IN_CLASSC_NET;
80718316Swollman}
80818316Swollman
80918316Swollman
81018316Swollman/* get a network number as a name or a number, with an optional "/xx"
81118316Swollman * netmask.
81218316Swollman */
81318316Swollmanstatic int				/* 0=bad */
81418316Swollmangetnet(char *name,
81518316Swollman       struct netinfo *rt)
81618316Swollman{
81718316Swollman	int i;
81818316Swollman	struct netent *nentp;
81918316Swollman	u_int mask;
82018316Swollman	struct in_addr in;
82118316Swollman	char hname[MAXHOSTNAMELEN+1];
82218316Swollman	char *mname, *p;
82318316Swollman
82418316Swollman
82518316Swollman	/* Detect and separate "1.2.3.4/24"
82618316Swollman	 */
82746303Smarkm	if (0 != (mname = strrchr(name,'/'))) {
82818316Swollman		i = (int)(mname - name);
82946303Smarkm		if (i > (int)sizeof(hname)-1)	/* name too long */
83018316Swollman			return 0;
83146303Smarkm		memmove(hname, name, i);
83218316Swollman		hname[i] = '\0';
83318316Swollman		mname++;
83418316Swollman		name = hname;
83518316Swollman	}
83618316Swollman
83718316Swollman	nentp = getnetbyname(name);
83818316Swollman	if (nentp != 0) {
83918316Swollman		in.s_addr = nentp->n_net;
84018316Swollman	} else if (inet_aton(name, &in) == 1) {
84190868Smike		in.s_addr = ntohl(in.s_addr);
84218316Swollman	} else {
84318316Swollman		return 0;
84418316Swollman	}
84518316Swollman
84618316Swollman	if (mname == 0) {
84718316Swollman		mask = std_mask(in.s_addr);
84818316Swollman		if ((~mask & in.s_addr) != 0)
84918316Swollman			mask = 0xffffffff;
85018316Swollman	} else {
85118316Swollman		mask = (u_int)strtoul(mname, &p, 0);
85218316Swollman		if (*p != '\0' || mask > 32)
85318316Swollman			return 0;
85418316Swollman		mask = 0xffffffff << (32-mask);
85518316Swollman	}
85618316Swollman
85718316Swollman	rt->n_dst = htonl(in.s_addr);
85818316Swollman	rt->n_family = RIP_AF_INET;
85918316Swollman	rt->n_mask = htonl(mask);
86018316Swollman	return 1;
86118316Swollman}
86219880Swollman
86319880Swollman
86419880Swollman/* strtok(), but honoring backslash
86519880Swollman */
86619880Swollmanstatic int				/* -1=bad */
86719880Swollmanparse_quote(char **linep,
86846303Smarkm	    const char *delims,
86919880Swollman	    char *delimp,
87019880Swollman	    char *buf,
87119880Swollman	    int	lim)
87219880Swollman{
87346303Smarkm	char c, *pc;
87446303Smarkm	const char *p;
87519880Swollman
87619880Swollman
87719880Swollman	pc = *linep;
87819880Swollman	if (*pc == '\0')
87919880Swollman		return -1;
88019880Swollman
88119880Swollman	for (;;) {
88219880Swollman		if (lim == 0)
88319880Swollman			return -1;
88419880Swollman		c = *pc++;
88519880Swollman		if (c == '\0')
88619880Swollman			break;
88719880Swollman
88837815Sphk		if (c == '\\' && *pc != '\0') {
88919880Swollman			if ((c = *pc++) == 'n') {
89019880Swollman				c = '\n';
89119880Swollman			} else if (c == 'r') {
89219880Swollman				c = '\r';
89319880Swollman			} else if (c == 't') {
89419880Swollman				c = '\t';
89519880Swollman			} else if (c == 'b') {
89619880Swollman				c = '\b';
89719880Swollman			} else if (c >= '0' && c <= '7') {
89819880Swollman				c -= '0';
89919880Swollman				if (*pc >= '0' && *pc <= '7') {
90019880Swollman					c = (c<<3)+(*pc++ - '0');
90119880Swollman					if (*pc >= '0' && *pc <= '7')
90219880Swollman					    c = (c<<3)+(*pc++ - '0');
90319880Swollman				}
90419880Swollman			}
90519880Swollman
90619880Swollman		} else {
90719880Swollman			for (p = delims; *p != '\0'; ++p) {
90819880Swollman				if (*p == c)
90919880Swollman					goto exit;
91019880Swollman			}
91119880Swollman		}
91219880Swollman
91319880Swollman		*buf++ = c;
91419880Swollman		--lim;
91519880Swollman	}
91619880Swollmanexit:
91719880Swollman	if (delimp != 0)
91819880Swollman		*delimp = c;
91919880Swollman	*linep = pc-1;
92019880Swollman	if (lim != 0)
92119880Swollman		*buf = '\0';
92219880Swollman	return 0;
92319880Swollman}
924