rtquery.c revision 18316
118316Swollman/*-
218316Swollman * Copyright (c) 1982, 1986, 1993
318316Swollman *	The Regents of the University of California.  All rights reserved.
418316Swollman *
518316Swollman * Redistribution and use in source and binary forms, with or without
618316Swollman * modification, are permitted provided that the following conditions
718316Swollman * are met:
818316Swollman * 1. Redistributions of source code must retain the above copyright
918316Swollman *    notice, this list of conditions and the following disclaimer.
1018316Swollman * 2. Redistributions in binary form must reproduce the above copyright
1118316Swollman *    notice, this list of conditions and the following disclaimer in the
1218316Swollman *    documentation and/or other materials provided with the distribution.
1318316Swollman * 3. All advertising materials mentioning features or use of this software
1418316Swollman *    must display the following acknowledgement:
1518316Swollman *	This product includes software developed by the University of
1618316Swollman *	California, Berkeley and its contributors.
1718316Swollman * 4. Neither the name of the University nor the names of its contributors
1818316Swollman *    may be used to endorse or promote products derived from this software
1918316Swollman *    without specific prior written permission.
2018316Swollman *
2118316Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2218316Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2318316Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2418316Swollman * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2518316Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2618316Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2718316Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2818316Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2918316Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3018316Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3118316Swollman * SUCH DAMAGE.
3218316Swollman */
3318316Swollman
3418316Swollmanchar copyright[] =
3518316Swollman"@(#) Copyright (c) 1982, 1986, 1993\n\
3618316Swollman	The Regents of the University of California.  All rights reserved.\n";
3718316Swollman
3818316Swollman#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__)
3918316Swollmanstatic char sccsid[] = "@(#)query.c	8.1 (Berkeley) 6/5/93";
4018316Swollman#elif defined(__NetBSD__)
4118316Swollmanstatic char rcsid[] = "$NetBSD$";
4218316Swollman#endif
4318316Swollman#ident "$Revision: 1.9 $"
4418316Swollman
4518316Swollman#include <sys/param.h>
4618316Swollman#include <sys/protosw.h>
4718316Swollman#include <sys/socket.h>
4818316Swollman#include <sys/time.h>
4918316Swollman#include <netinet/in.h>
5018316Swollman#define RIPVERSION RIPv2
5118316Swollman#include <protocols/routed.h>
5218316Swollman#include <arpa/inet.h>
5318316Swollman#include <netdb.h>
5418316Swollman#include <errno.h>
5518316Swollman#include <unistd.h>
5618316Swollman#include <stdio.h>
5718316Swollman#include <stdlib.h>
5818316Swollman#include <string.h>
5918316Swollman#ifdef sgi
6018316Swollman#include <strings.h>
6118316Swollman#include <bstring.h>
6218316Swollman#endif
6318316Swollman
6418316Swollman#ifndef sgi
6518316Swollman#define _HAVE_SIN_LEN
6618316Swollman#endif
6718316Swollman
6818316Swollman#define	WTIME	15		/* Time to wait for all responses */
6918316Swollman#define	STIME	(250*1000)	/* usec to wait for another response */
7018316Swollman
7118316Swollmanint	s;
7218316Swollman
7318316Swollmanchar	*pgmname;
7418316Swollman
7518316Swollmanunion {
7618316Swollman	struct rip rip;
7718316Swollman	char	packet[MAXPACKETSIZE+MAXPATHLEN];
7818316Swollman} omsg_buf;
7918316Swollman#define OMSG omsg_buf.rip
8018316Swollmanint omsg_len = sizeof(struct rip);
8118316Swollman
8218316Swollmanunion {
8318316Swollman	struct	rip rip;
8418316Swollman	char	packet[MAXPACKETSIZE+1024];
8518316Swollman	} imsg_buf;
8618316Swollman#define IMSG imsg_buf.rip
8718316Swollman
8818316Swollmanint	nflag;				/* numbers, no names */
8918316Swollmanint	pflag;				/* play the `gated` game */
9018316Swollmanint	ripv2 = 1;			/* use RIP version 2 */
9118316Swollmanint	wtime = WTIME;
9218316Swollmanint	rflag;				/* 1=ask about a particular route */
9318316Swollmanint	trace;
9418316Swollmanint	not_trace;
9518316Swollman
9618316Swollmanstruct timeval sent;			/* when query sent */
9718316Swollman
9818316Swollmanstatic void rip_input(struct sockaddr_in*, int);
9918316Swollmanstatic int out(char *);
10018316Swollmanstatic void trace_loop(char *argv[]);
10118316Swollmanstatic void query_loop(char *argv[], int);
10218316Swollmanstatic int getnet(char *, struct netinfo *);
10318316Swollmanstatic u_int std_mask(u_int);
10418316Swollman
10518316Swollman
10618316Swollmanint
10718316Swollmanmain(int argc,
10818316Swollman     char *argv[])
10918316Swollman{
11018316Swollman	int ch, bsize;
11118316Swollman	char *p, *options, *value;
11218316Swollman
11318316Swollman	OMSG.rip_nets[0].n_dst = RIP_DEFAULT;
11418316Swollman	OMSG.rip_nets[0].n_family = RIP_AF_UNSPEC;
11518316Swollman	OMSG.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY);
11618316Swollman
11718316Swollman	pgmname = argv[0];
11818316Swollman	while ((ch = getopt(argc, argv, "np1w:r:t:")) != EOF)
11918316Swollman		switch (ch) {
12018316Swollman		case 'n':
12118316Swollman			not_trace = 1;
12218316Swollman			nflag = 1;
12318316Swollman			break;
12418316Swollman
12518316Swollman		case 'p':
12618316Swollman			not_trace = 1;
12718316Swollman			pflag = 1;
12818316Swollman			break;
12918316Swollman
13018316Swollman		case '1':
13118316Swollman			ripv2 = 0;
13218316Swollman			break;
13318316Swollman
13418316Swollman		case 'w':
13518316Swollman			not_trace = 1;
13618316Swollman			wtime = (int)strtoul(optarg, &p, 0);
13718316Swollman			if (*p != '\0'
13818316Swollman			    || wtime <= 0)
13918316Swollman				goto usage;
14018316Swollman			break;
14118316Swollman
14218316Swollman		case 'r':
14318316Swollman			not_trace = 1;
14418316Swollman			if (rflag)
14518316Swollman				goto usage;
14618316Swollman			rflag = getnet(optarg, &OMSG.rip_nets[0]);
14718316Swollman			if (!rflag) {
14818316Swollman				struct hostent *hp = gethostbyname(optarg);
14918316Swollman				if (hp == 0) {
15018316Swollman					fprintf(stderr, "%s: %s:",
15118316Swollman						pgmname, optarg);
15218316Swollman					herror(0);
15318316Swollman					exit(1);
15418316Swollman				}
15518316Swollman				bcopy(hp->h_addr, &OMSG.rip_nets[0].n_dst,
15618316Swollman				      sizeof(OMSG.rip_nets[0].n_dst));
15718316Swollman				OMSG.rip_nets[0].n_family = RIP_AF_INET;
15818316Swollman				OMSG.rip_nets[0].n_mask = -1;
15918316Swollman				rflag = 1;
16018316Swollman			}
16118316Swollman			break;
16218316Swollman
16318316Swollman		case 't':
16418316Swollman			trace = 1;
16518316Swollman			options = optarg;
16618316Swollman			while (*options != '\0') {
16718316Swollman				char *traceopts[] = {
16818316Swollman#				    define TRACE_ON	0
16918316Swollman					"on",
17018316Swollman#				    define TRACE_MORE	1
17118316Swollman					"more",
17218316Swollman#				    define TRACE_OFF	2
17318316Swollman					"off",
17418316Swollman#				    define TRACE_DUMP	3
17518316Swollman					"dump",
17618316Swollman					0
17718316Swollman				};
17818316Swollman				switch (getsubopt(&options,traceopts,&value)) {
17918316Swollman				case TRACE_ON:
18018316Swollman					OMSG.rip_cmd = RIPCMD_TRACEON;
18118316Swollman					if (!value
18218316Swollman					    || strlen(value) > MAXPATHLEN)
18318316Swollman						goto usage;
18418316Swollman					break;
18518316Swollman				case TRACE_MORE:
18618316Swollman					if (value)
18718316Swollman						goto usage;
18818316Swollman					OMSG.rip_cmd = RIPCMD_TRACEON;
18918316Swollman					value = "";
19018316Swollman					break;
19118316Swollman				case TRACE_OFF:
19218316Swollman					if (value)
19318316Swollman						goto usage;
19418316Swollman					OMSG.rip_cmd = RIPCMD_TRACEOFF;
19518316Swollman					value = "";
19618316Swollman					break;
19718316Swollman				case TRACE_DUMP:
19818316Swollman					if (value)
19918316Swollman						goto usage;
20018316Swollman					OMSG.rip_cmd = RIPCMD_TRACEON;
20118316Swollman					value = "dump/../table";
20218316Swollman					break;
20318316Swollman				default:
20418316Swollman					goto usage;
20518316Swollman				}
20618316Swollman				strcpy((char*)OMSG.rip_tracefile, value);
20718316Swollman				omsg_len += strlen(value) - sizeof(OMSG.ripun);
20818316Swollman			}
20918316Swollman			break;
21018316Swollman
21118316Swollman		default:
21218316Swollman			goto usage;
21318316Swollman	}
21418316Swollman	argv += optind;
21518316Swollman	argc -= optind;
21618316Swollman	if ((not_trace && trace) || argc == 0) {
21718316Swollmanusage:		fprintf(stderr, "%s: [-np1v] [-r tgt_rt] [-w wtime]"
21818316Swollman			" host1 [host2 ...]\n"
21918316Swollman			"or\t-t {on=filename|more|off} host1 host2 ...\n",
22018316Swollman			pgmname);
22118316Swollman		exit(1);
22218316Swollman	}
22318316Swollman
22418316Swollman	s = socket(AF_INET, SOCK_DGRAM, 0);
22518316Swollman	if (s < 0) {
22618316Swollman		perror("socket");
22718316Swollman		exit(2);
22818316Swollman	}
22918316Swollman
23018316Swollman	/* be prepared to receive a lot of routes */
23118316Swollman	for (bsize = 127*1024; ; bsize -= 1024) {
23218316Swollman		if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
23318316Swollman			       &bsize, sizeof(bsize)) == 0)
23418316Swollman			break;
23518316Swollman		if (bsize <= 4*1024) {
23618316Swollman			perror("setsockopt SO_RCVBUF");
23718316Swollman			break;
23818316Swollman		}
23918316Swollman	}
24018316Swollman
24118316Swollman	if (trace)
24218316Swollman		trace_loop(argv);
24318316Swollman	else
24418316Swollman		query_loop(argv, argc);
24518316Swollman	/* NOTREACHED */
24618316Swollman}
24718316Swollman
24818316Swollman
24918316Swollman/* tell the target hosts about tracing
25018316Swollman */
25118316Swollmanstatic void
25218316Swollmantrace_loop(char *argv[])
25318316Swollman{
25418316Swollman	struct sockaddr_in myaddr;
25518316Swollman	int res;
25618316Swollman
25718316Swollman	if (geteuid() != 0) {
25818316Swollman		(void)fprintf(stderr, "-t requires UID 0\n");
25918316Swollman		exit(1);
26018316Swollman	}
26118316Swollman
26218316Swollman	if (ripv2) {
26318316Swollman		OMSG.rip_vers = RIPv2;
26418316Swollman	} else {
26518316Swollman		OMSG.rip_vers = RIPv1;
26618316Swollman	}
26718316Swollman
26818316Swollman	bzero(&myaddr, sizeof(myaddr));
26918316Swollman	myaddr.sin_family = AF_INET;
27018316Swollman#ifdef _HAVE_SIN_LEN
27118316Swollman	myaddr.sin_len = sizeof(myaddr);
27218316Swollman#endif
27318316Swollman	myaddr.sin_port = htons(IPPORT_RESERVED-1);
27418316Swollman	while (bind(s, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
27518316Swollman		if (errno != EADDRINUSE
27618316Swollman		    || myaddr.sin_port == 0) {
27718316Swollman			perror("bind");
27818316Swollman			exit(2);
27918316Swollman		}
28018316Swollman		myaddr.sin_port = htons(ntohs(myaddr.sin_port)-1);
28118316Swollman	}
28218316Swollman
28318316Swollman	res = 1;
28418316Swollman	while (*argv != 0) {
28518316Swollman		if (out(*argv++) <= 0)
28618316Swollman			res = 0;
28718316Swollman	}
28818316Swollman	exit(res);
28918316Swollman}
29018316Swollman
29118316Swollman
29218316Swollman/* query all of the listed hosts
29318316Swollman */
29418316Swollmanstatic void
29518316Swollmanquery_loop(char *argv[], int argc)
29618316Swollman{
29718316Swollman	struct seen {
29818316Swollman		struct seen *next;
29918316Swollman		struct in_addr addr;
30018316Swollman	} *seen, *sp;
30118316Swollman	int answered = 0;
30218316Swollman	int cc;
30318316Swollman	fd_set bits;
30418316Swollman	struct timeval now, delay;
30518316Swollman	struct sockaddr_in from;
30618316Swollman	int fromlen;
30718316Swollman
30818316Swollman
30918316Swollman	OMSG.rip_cmd = (pflag) ? RIPCMD_POLL : RIPCMD_REQUEST;
31018316Swollman	if (ripv2) {
31118316Swollman		OMSG.rip_vers = RIPv2;
31218316Swollman	} else {
31318316Swollman		OMSG.rip_vers = RIPv1;
31418316Swollman		OMSG.rip_nets[0].n_mask = 0;
31518316Swollman	}
31618316Swollman
31718316Swollman	/* ask the first (valid) host */
31818316Swollman	seen = 0;
31918316Swollman	while (0 > out(*argv++)) {
32018316Swollman		if (*argv == 0)
32118316Swollman			exit(-1);
32218316Swollman		answered++;
32318316Swollman	}
32418316Swollman
32518316Swollman	FD_ZERO(&bits);
32618316Swollman	for (;;) {
32718316Swollman		FD_SET(s, &bits);
32818316Swollman		delay.tv_sec = 0;
32918316Swollman		delay.tv_usec = STIME;
33018316Swollman		cc = select(s+1, &bits, 0,0, &delay);
33118316Swollman		if (cc > 0) {
33218316Swollman			fromlen = sizeof(from);
33318316Swollman			cc = recvfrom(s, imsg_buf.packet,
33418316Swollman				      sizeof(imsg_buf.packet), 0,
33518316Swollman				      (struct sockaddr *)&from, &fromlen);
33618316Swollman			if (cc < 0) {
33718316Swollman				perror("recvfrom");
33818316Swollman				exit(1);
33918316Swollman			}
34018316Swollman			/* count the distinct responding hosts.
34118316Swollman			 * You cannot match responding hosts with
34218316Swollman			 * addresses to which queries were transmitted,
34318316Swollman			 * because a router might respond with a
34418316Swollman			 * different source address.
34518316Swollman			 */
34618316Swollman			for (sp = seen; sp != 0; sp = sp->next) {
34718316Swollman				if (sp->addr.s_addr == from.sin_addr.s_addr)
34818316Swollman					break;
34918316Swollman			}
35018316Swollman			if (sp == 0) {
35118316Swollman				sp = malloc(sizeof(*sp));
35218316Swollman				sp->addr = from.sin_addr;
35318316Swollman				sp->next = seen;
35418316Swollman				seen = sp;
35518316Swollman				answered++;
35618316Swollman			}
35718316Swollman
35818316Swollman			rip_input(&from, cc);
35918316Swollman			continue;
36018316Swollman		}
36118316Swollman
36218316Swollman		if (cc < 0) {
36318316Swollman			if ( errno == EINTR)
36418316Swollman				continue;
36518316Swollman			perror("select");
36618316Swollman			exit(1);
36718316Swollman		}
36818316Swollman
36918316Swollman		/* After a pause in responses, probe another host.
37018316Swollman		 * This reduces the intermingling of answers.
37118316Swollman		 */
37218316Swollman		while (*argv != 0 && 0 > out(*argv++))
37318316Swollman			answered++;
37418316Swollman
37518316Swollman		/* continue until no more packets arrive
37618316Swollman		 * or we have heard from all hosts
37718316Swollman		 */
37818316Swollman		if (answered >= argc)
37918316Swollman			break;
38018316Swollman
38118316Swollman		/* or until we have waited a long time
38218316Swollman		 */
38318316Swollman		if (gettimeofday(&now, 0) < 0) {
38418316Swollman			perror("gettimeofday(now)");
38518316Swollman			exit(1);
38618316Swollman		}
38718316Swollman		if (sent.tv_sec + wtime <= now.tv_sec)
38818316Swollman			break;
38918316Swollman	}
39018316Swollman
39118316Swollman	/* fail if there was no answer */
39218316Swollman	exit (answered >= argc ? 0 : 1);
39318316Swollman}
39418316Swollman
39518316Swollman
39618316Swollman/* sent do one host
39718316Swollman */
39818316Swollmanstatic int
39918316Swollmanout(char *host)
40018316Swollman{
40118316Swollman	struct sockaddr_in router;
40218316Swollman	struct hostent *hp;
40318316Swollman
40418316Swollman	if (gettimeofday(&sent, 0) < 0) {
40518316Swollman		perror("gettimeofday(sent)");
40618316Swollman		return -1;
40718316Swollman	}
40818316Swollman
40918316Swollman	bzero(&router, sizeof(router));
41018316Swollman	router.sin_family = AF_INET;
41118316Swollman#ifdef _HAVE_SIN_LEN
41218316Swollman	router.sin_len = sizeof(router);
41318316Swollman#endif
41418316Swollman	if (!inet_aton(host, &router.sin_addr)) {
41518316Swollman		hp = gethostbyname(host);
41618316Swollman		if (hp == 0) {
41718316Swollman			herror(host);
41818316Swollman			return -1;
41918316Swollman		}
42018316Swollman		bcopy(hp->h_addr, &router.sin_addr, sizeof(router.sin_addr));
42118316Swollman	}
42218316Swollman	router.sin_port = htons(RIP_PORT);
42318316Swollman
42418316Swollman	if (sendto(s, &omsg_buf, omsg_len, 0,
42518316Swollman		   (struct sockaddr *)&router, sizeof(router)) < 0) {
42618316Swollman		perror(host);
42718316Swollman		return -1;
42818316Swollman	}
42918316Swollman
43018316Swollman	return 0;
43118316Swollman}
43218316Swollman
43318316Swollman
43418316Swollman/*
43518316Swollman * Handle an incoming RIP packet.
43618316Swollman */
43718316Swollmanstatic void
43818316Swollmanrip_input(struct sockaddr_in *from,
43918316Swollman	  int size)
44018316Swollman{
44118316Swollman	struct netinfo *n, *lim;
44218316Swollman	struct in_addr in;
44318316Swollman	char *name;
44418316Swollman	char net_buf[80];
44518316Swollman	u_int mask, dmask;
44618316Swollman	char *sp;
44718316Swollman	int i;
44818316Swollman	struct hostent *hp;
44918316Swollman	struct netent *np;
45018316Swollman	struct netauth *a;
45118316Swollman
45218316Swollman
45318316Swollman	if (nflag) {
45418316Swollman		printf("%s:", inet_ntoa(from->sin_addr));
45518316Swollman	} else {
45618316Swollman		hp = gethostbyaddr((char*)&from->sin_addr,
45718316Swollman				   sizeof(struct in_addr), AF_INET);
45818316Swollman		if (hp == 0) {
45918316Swollman			printf("%s:",
46018316Swollman			       inet_ntoa(from->sin_addr));
46118316Swollman		} else {
46218316Swollman			printf("%s (%s):", hp->h_name,
46318316Swollman			       inet_ntoa(from->sin_addr));
46418316Swollman		}
46518316Swollman	}
46618316Swollman	if (IMSG.rip_cmd != RIPCMD_RESPONSE) {
46718316Swollman		printf("\n    unexpected response type %d\n", IMSG.rip_cmd);
46818316Swollman		return;
46918316Swollman	}
47018316Swollman	printf(" RIPv%d%s %d bytes\n", IMSG.rip_vers,
47118316Swollman	       (IMSG.rip_vers != RIPv1 && IMSG.rip_vers != RIPv2) ? " ?" : "",
47218316Swollman	       size);
47318316Swollman	if (size > MAXPACKETSIZE) {
47418316Swollman		if (size > sizeof(imsg_buf) - sizeof(*n)) {
47518316Swollman			printf("       at least %d bytes too long\n",
47618316Swollman			       size-MAXPACKETSIZE);
47718316Swollman			size = sizeof(imsg_buf) - sizeof(*n);
47818316Swollman		} else {
47918316Swollman			printf("       %d bytes too long\n",
48018316Swollman			       size-MAXPACKETSIZE);
48118316Swollman		}
48218316Swollman	} else if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
48318316Swollman		printf("    response of bad length=%d\n", size);
48418316Swollman	}
48518316Swollman
48618316Swollman	n = IMSG.rip_nets;
48718316Swollman	lim = (struct netinfo *)((char*)n + size) - 1;
48818316Swollman	for (; n <= lim; n++) {
48918316Swollman		name = "";
49018316Swollman		if (n->n_family == RIP_AF_INET) {
49118316Swollman			in.s_addr = n->n_dst;
49218316Swollman			(void)strcpy(net_buf, inet_ntoa(in));
49318316Swollman
49418316Swollman			mask = ntohl(n->n_mask);
49518316Swollman			dmask = mask & -mask;
49618316Swollman			if (mask != 0) {
49718316Swollman				sp = &net_buf[strlen(net_buf)];
49818316Swollman				if (IMSG.rip_vers == RIPv1) {
49918316Swollman					(void)sprintf(sp," mask=%#x ? ",mask);
50018316Swollman					mask = 0;
50118316Swollman				} else if (mask + dmask == 0) {
50218316Swollman					for (i = 0;
50318316Swollman					     (i != 32
50418316Swollman					      && ((1<<i)&mask) == 0);
50518316Swollman					     i++)
50618316Swollman						continue;
50718316Swollman					(void)sprintf(sp, "/%d",32-i);
50818316Swollman				} else {
50918316Swollman					(void)sprintf(sp," (mask %#x)", mask);
51018316Swollman				}
51118316Swollman			}
51218316Swollman
51318316Swollman			if (!nflag) {
51418316Swollman				if (mask == 0) {
51518316Swollman					mask = std_mask(in.s_addr);
51618316Swollman					if ((ntohl(in.s_addr) & ~mask) != 0)
51718316Swollman						mask = 0;
51818316Swollman				}
51918316Swollman				/* Without a netmask, do not worry about
52018316Swollman				 * whether the destination is a host or a
52118316Swollman				 * network. Try both and use the first name
52218316Swollman				 * we get.
52318316Swollman				 *
52418316Swollman				 * If we have a netmask we can make a
52518316Swollman				 * good guess.
52618316Swollman				 */
52718316Swollman				if ((in.s_addr & ~mask) == 0) {
52818316Swollman					np = getnetbyaddr((long)in.s_addr,
52918316Swollman							  AF_INET);
53018316Swollman					if (np != 0)
53118316Swollman						name = np->n_name;
53218316Swollman					else if (in.s_addr == 0)
53318316Swollman						name = "default";
53418316Swollman				}
53518316Swollman				if (name[0] == '\0'
53618316Swollman				    && ((in.s_addr & ~mask) != 0
53718316Swollman					|| mask == 0xffffffff)) {
53818316Swollman					hp = gethostbyaddr((char*)&in,
53918316Swollman							   sizeof(in),
54018316Swollman							   AF_INET);
54118316Swollman					if (hp != 0)
54218316Swollman						name = hp->h_name;
54318316Swollman				}
54418316Swollman			}
54518316Swollman
54618316Swollman		} else if (n->n_family == RIP_AF_AUTH) {
54718316Swollman			a = (struct netauth*)n;
54818316Swollman			(void)printf("    authentication type %d: ",
54918316Swollman				     a->a_type);
55018316Swollman			for (i = 0; i < sizeof(a->au.au_pw); i++)
55118316Swollman				(void)printf("%02x ", a->au.au_pw[i]);
55218316Swollman			putc('\n', stdout);
55318316Swollman			continue;
55418316Swollman
55518316Swollman		} else {
55618316Swollman			(void)sprintf(net_buf, "(af %#x) %d.%d.%d.%d",
55718316Swollman				      ntohs(n->n_family),
55818316Swollman				      (char)(n->n_dst >> 24),
55918316Swollman				      (char)(n->n_dst >> 16),
56018316Swollman				      (char)(n->n_dst >> 8),
56118316Swollman				      (char)n->n_dst);
56218316Swollman		}
56318316Swollman
56418316Swollman		(void)printf("  %-18s metric %2d %-10s",
56518316Swollman			     net_buf, ntohl(n->n_metric), name);
56618316Swollman
56718316Swollman		if (n->n_nhop != 0) {
56818316Swollman			in.s_addr = n->n_nhop;
56918316Swollman			if (nflag)
57018316Swollman				hp = 0;
57118316Swollman			else
57218316Swollman				hp = gethostbyaddr((char*)&in, sizeof(in),
57318316Swollman						   AF_INET);
57418316Swollman			(void)printf(" nhop=%-15s%s",
57518316Swollman				     (hp != 0) ? hp->h_name : inet_ntoa(in),
57618316Swollman				     (IMSG.rip_vers == RIPv1) ? " ?" : "");
57718316Swollman		}
57818316Swollman		if (n->n_tag != 0)
57918316Swollman			(void)printf(" tag=%#x%s", n->n_tag,
58018316Swollman				     (IMSG.rip_vers == RIPv1) ? " ?" : "");
58118316Swollman		putc('\n', stdout);
58218316Swollman	}
58318316Swollman}
58418316Swollman
58518316Swollman
58618316Swollman/* Return the classical netmask for an IP address.
58718316Swollman */
58818316Swollmanstatic u_int
58918316Swollmanstd_mask(u_int addr)			/* in network order */
59018316Swollman{
59118316Swollman	NTOHL(addr);			/* was a host, not a network */
59218316Swollman
59318316Swollman	if (addr == 0)			/* default route has mask 0 */
59418316Swollman		return 0;
59518316Swollman	if (IN_CLASSA(addr))
59618316Swollman		return IN_CLASSA_NET;
59718316Swollman	if (IN_CLASSB(addr))
59818316Swollman		return IN_CLASSB_NET;
59918316Swollman	return IN_CLASSC_NET;
60018316Swollman}
60118316Swollman
60218316Swollman
60318316Swollman/* get a network number as a name or a number, with an optional "/xx"
60418316Swollman * netmask.
60518316Swollman */
60618316Swollmanstatic int				/* 0=bad */
60718316Swollmangetnet(char *name,
60818316Swollman       struct netinfo *rt)
60918316Swollman{
61018316Swollman	int i;
61118316Swollman	struct netent *nentp;
61218316Swollman	u_int mask;
61318316Swollman	struct in_addr in;
61418316Swollman	char hname[MAXHOSTNAMELEN+1];
61518316Swollman	char *mname, *p;
61618316Swollman
61718316Swollman
61818316Swollman	/* Detect and separate "1.2.3.4/24"
61918316Swollman	 */
62018316Swollman	if (0 != (mname = rindex(name,'/'))) {
62118316Swollman		i = (int)(mname - name);
62218316Swollman		if (i > sizeof(hname)-1)	/* name too long */
62318316Swollman			return 0;
62418316Swollman		bcopy(name, hname, i);
62518316Swollman		hname[i] = '\0';
62618316Swollman		mname++;
62718316Swollman		name = hname;
62818316Swollman	}
62918316Swollman
63018316Swollman	nentp = getnetbyname(name);
63118316Swollman	if (nentp != 0) {
63218316Swollman		in.s_addr = nentp->n_net;
63318316Swollman	} else if (inet_aton(name, &in) == 1) {
63418316Swollman		NTOHL(in.s_addr);
63518316Swollman	} else {
63618316Swollman		return 0;
63718316Swollman	}
63818316Swollman
63918316Swollman	if (mname == 0) {
64018316Swollman		mask = std_mask(in.s_addr);
64118316Swollman		if ((~mask & in.s_addr) != 0)
64218316Swollman			mask = 0xffffffff;
64318316Swollman	} else {
64418316Swollman		mask = (u_int)strtoul(mname, &p, 0);
64518316Swollman		if (*p != '\0' || mask > 32)
64618316Swollman			return 0;
64718316Swollman		mask = 0xffffffff << (32-mask);
64818316Swollman	}
64918316Swollman
65018316Swollman	rt->n_dst = htonl(in.s_addr);
65118316Swollman	rt->n_family = RIP_AF_INET;
65218316Swollman	rt->n_mask = htonl(mask);
65318316Swollman	return 1;
65418316Swollman}
655