route.c revision 27500
1230130Smav/*
2230130Smav *
3230130Smav * Copyright (c) 1983, 1989, 1991, 1993
4230130Smav *	The Regents of the University of California.  All rights reserved.
5230130Smav *
6230130Smav * Redistribution and use in source and binary forms, with or without
7230130Smav * modification, are permitted provided that the following conditions
8230130Smav * are met:
9230130Smav * 1. Redistributions of source code must retain the above copyright
10230130Smav *    notice, this list of conditions and the following disclaimer.
11230130Smav * 2. Redistributions in binary form must reproduce the above copyright
12230130Smav *    notice, this list of conditions and the following disclaimer in the
13230130Smav *    documentation and/or other materials provided with the distribution.
14230130Smav * 3. All advertising materials mentioning features or use of this software
15230130Smav *    must display the following acknowledgement:
16230130Smav *	This product includes software developed by the University of
17230130Smav *	California, Berkeley and its contributors.
18230130Smav * 4. Neither the name of the University nor the names of its contributors
19230130Smav *    may be used to endorse or promote products derived from this software
20230130Smav *    without specific prior written permission.
21230130Smav *
22230130Smav * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23230130Smav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24230130Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25230130Smav * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26230130Smav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27230130Smav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28230130Smav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29230130Smav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30230130Smav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31230130Smav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32230130Smav * SUCH DAMAGE.
33230130Smav */
34230130Smav
35230130Smav#ifndef lint
36230130Smavstatic const char copyright[] =
37230130Smav"@(#) Copyright (c) 1983, 1989, 1991, 1993\n\
38230130Smav	The Regents of the University of California.  All rights reserved.\n";
39230130Smav#endif /* not lint */
40230130Smav
41230130Smav#ifndef lint
42230130Smav/*
43230130Smavstatic char sccsid[] = "@(#)route.c	8.3 (Berkeley) 3/19/94";
44230130Smav*/
45230130Smavstatic const char rcsid[] =
46230130Smav	"$Id: route.c,v 1.25 1997/06/18 06:30:34 charnier Exp $";
47230130Smav#endif /* not lint */
48230130Smav
49230130Smav#include <sys/param.h>
50230130Smav#include <sys/file.h>
51230130Smav#include <sys/socket.h>
52230130Smav#include <sys/ioctl.h>
53230130Smav#include <sys/sysctl.h>
54230130Smav#include <sys/time.h>
55230130Smav
56230130Smav#include <net/if.h>
57230130Smav#include <net/route.h>
58230130Smav#include <net/if_dl.h>
59230130Smav#include <netinet/in.h>
60230130Smav#include <netatalk/at.h>
61230130Smav#ifdef NS
62230130Smav#include <netns/ns.h>
63230130Smav#endif
64230130Smav#include <arpa/inet.h>
65230130Smav#include <netdb.h>
66230130Smav
67230130Smav#include <ctype.h>
68230130Smav#include <err.h>
69230130Smav#include <errno.h>
70230130Smav#include <paths.h>
71230130Smav#include <stdio.h>
72230130Smav#include <stdlib.h>
73230130Smav#include <string.h>
74230130Smav#include <sysexits.h>
75230130Smav#include <time.h>
76230130Smav#include <unistd.h>
77230130Smav
78230130Smavstruct keytab {
79230130Smav	char	*kt_cp;
80230130Smav	int	kt_i;
81230130Smav} keywords[] = {
82230130Smav#include "keywords.h"
83230130Smav	{0, 0}
84230130Smav};
85230130Smav
86230130Smavstruct	ortentry route;
87230130Smavunion	sockunion {
88230130Smav	struct	sockaddr sa;
89230130Smav	struct	sockaddr_in sin;
90230130Smav	struct	sockaddr_at sat;
91230130Smav#ifdef NS
92230130Smav	struct	sockaddr_ns sns;
93230130Smav#endif
94230130Smav	struct	sockaddr_dl sdl;
95230571Smav} so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
96230571Smav
97230130Smavtypedef union sockunion *sup;
98230130Smavint	pid, rtm_addrs, uid;
99230130Smavint	s;
100230130Smavint	forcehost, forcenet, doflush, nflag, af, qflag, tflag, keyword();
101230130Smavint	iflag, verbose, aflen = sizeof (struct sockaddr_in);
102230130Smavint	locking, lockrest, debugonly;
103230130Smavstruct	rt_metrics rt_metrics;
104230130Smavu_long  rtm_inits;
105230130Smavstruct	in_addr inet_makeaddr();
106230130Smavint	atalk_aton __P((const char *, struct at_addr *));
107230130Smavchar	*atalk_ntoa __P((struct at_addr));
108230130Smavchar	*routename(), *netname();
109230130Smavvoid	flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf();
110230130Smavvoid	print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr();
111230130Smavint	getaddr(), rtmsg(), x25_makemask();
112230130Smavextern	char *inet_ntoa(), *iso_ntoa(), *link_ntoa();
113230130Smav
114230130Smavvoid usage __P((const char *)) __dead2;
115230130Smav
116230130Smavvoid
117230130Smavusage(cp)
118230130Smav	const char *cp;
119230130Smav{
120230130Smav	if (cp)
121230130Smav		warnx("bad keyword: %s", cp);
122230130Smav	(void) fprintf(stderr,
123230130Smav	    "usage: route [ -nqv ] command [[ modifiers ] args ]\n");
124230130Smav	exit(EX_USAGE);
125230130Smav	/* NOTREACHED */
126230130Smav}
127230130Smav
128230571Smav#define ROUNDUP(a) \
129230571Smav	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
130230571Smav#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
131230571Smav
132230130Smavint
133230571Smavmain(argc, argv)
134230130Smav	int argc;
135230130Smav	char **argv;
136230130Smav{
137230130Smav	extern int optind;
138230130Smav	int ch;
139230130Smav
140230130Smav	if (argc < 2)
141230130Smav		usage((char *)NULL);
142230130Smav
143230130Smav	while ((ch = getopt(argc, argv, "nqdtv")) != EOF)
144230130Smav		switch(ch) {
145230130Smav		case 'n':
146230130Smav			nflag = 1;
147230130Smav			break;
148230130Smav		case 'q':
149230130Smav			qflag = 1;
150230130Smav			break;
151230130Smav		case 'v':
152230130Smav			verbose = 1;
153230130Smav			break;
154230130Smav		case 't':
155230130Smav			tflag = 1;
156230130Smav			break;
157230130Smav		case 'd':
158230571Smav			debugonly = 1;
159230571Smav			break;
160230571Smav		case '?':
161230571Smav		default:
162230130Smav			usage((char *)NULL);
163230130Smav		}
164230130Smav	argc -= optind;
165230130Smav	argv += optind;
166230130Smav
167230130Smav	pid = getpid();
168230130Smav	uid = getuid();
169230130Smav	if (tflag)
170230130Smav		s = open("/dev/null", O_WRONLY, 0);
171230130Smav	else
172230130Smav		s = socket(PF_ROUTE, SOCK_RAW, 0);
173230130Smav	if (s < 0)
174230130Smav		err(EX_OSERR, "socket");
175230130Smav	setuid(uid);
176230130Smav	if (*argv)
177230571Smav		switch (keyword(*argv)) {
178230571Smav		case K_GET:
179230571Smav			uid = 0;
180230571Smav			/* FALLTHROUGH */
181230571Smav
182230571Smav		case K_CHANGE:
183230571Smav		case K_ADD:
184230571Smav		case K_DELETE:
185230571Smav			newroute(argc, argv);
186230571Smav			exit(0);
187230571Smav			/* NOTREACHED */
188230571Smav
189230130Smav		case K_MONITOR:
190230130Smav			monitor();
191230130Smav			/* NOTREACHED */
192230571Smav
193230571Smav		case K_FLUSH:
194230571Smav			flushroutes(argc, argv);
195230130Smav			exit(0);
196230571Smav			/* NOTREACHED */
197230130Smav		}
198230571Smav	usage(*argv);
199230130Smav	/* NOTREACHED */
200230130Smav}
201230130Smav
202230130Smav/*
203230130Smav * Purge all entries in the routing tables not
204230130Smav * associated with network interfaces.
205230130Smav */
206230130Smavvoid
207230130Smavflushroutes(argc, argv)
208230571Smav	int argc;
209230571Smav	char *argv[];
210230571Smav{
211230571Smav	size_t needed;
212230571Smav	int mib[6], rlen, seqno;
213230571Smav	char *buf, *next, *lim;
214230571Smav	register struct rt_msghdr *rtm;
215230571Smav
216230571Smav	if (uid) {
217230571Smav		errx(EX_NOPERM, "must be root to alter routing table");
218230571Smav	}
219230571Smav	shutdown(s, 0); /* Don't want to read back our messages */
220230571Smav	if (argc > 1) {
221230571Smav		argv++;
222230571Smav		if (argc == 2 && **argv == '-')
223230571Smav		    switch (keyword(*argv + 1)) {
224230571Smav			case K_INET:
225230571Smav				af = AF_INET;
226230571Smav				break;
227230571Smav			case K_ATALK:
228230571Smav				af = AF_APPLETALK;
229230571Smav				break;
230230130Smav#ifdef NS
231230130Smav			case K_XNS:
232230130Smav				af = AF_NS;
233230130Smav				break;
234230130Smav#endif
235230130Smav			case K_LINK:
236230130Smav				af = AF_LINK;
237230130Smav				break;
238230130Smav			default:
239230130Smav				goto bad;
240230130Smav		} else
241230130Smavbad:			usage(*argv);
242230130Smav	}
243230130Smav	mib[0] = CTL_NET;
244230130Smav	mib[1] = PF_ROUTE;
245230130Smav	mib[2] = 0;		/* protocol */
246230130Smav	mib[3] = 0;		/* wildcard address family */
247230130Smav	mib[4] = NET_RT_DUMP;
248230130Smav	mib[5] = 0;		/* no flags */
249230130Smav	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
250230130Smav		err(EX_OSERR, "route-sysctl-estimate");
251230130Smav	if ((buf = malloc(needed)) == NULL)
252230130Smav		err(EX_OSERR, "malloc");
253230130Smav	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
254230130Smav		err(EX_OSERR, "route-sysctl-get");
255230130Smav	lim = buf + needed;
256230130Smav	if (verbose)
257230130Smav		(void) printf("Examining routing table from sysctl\n");
258230130Smav	seqno = 0;		/* ??? */
259230130Smav	for (next = buf; next < lim; next += rtm->rtm_msglen) {
260230130Smav		rtm = (struct rt_msghdr *)next;
261230130Smav		if (verbose)
262230130Smav			print_rtmsg(rtm, rtm->rtm_msglen);
263230130Smav		if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
264230130Smav			continue;
265230130Smav		if (af) {
266230130Smav			struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
267230130Smav
268230130Smav			if (sa->sa_family != af)
269230130Smav				continue;
270230130Smav		}
271230130Smav		if (debugonly)
272230130Smav			continue;
273230130Smav		rtm->rtm_type = RTM_DELETE;
274230130Smav		rtm->rtm_seq = seqno;
275230130Smav		rlen = write(s, next, rtm->rtm_msglen);
276230130Smav		if (rlen < (int)rtm->rtm_msglen) {
277230130Smav			warn("write to routing socket");
278230130Smav			(void) printf("got only %d for rlen\n", rlen);
279230130Smav			break;
280230130Smav		}
281230130Smav		seqno++;
282230130Smav		if (qflag)
283230130Smav			continue;
284230130Smav		if (verbose)
285230130Smav			print_rtmsg(rtm, rlen);
286230130Smav		else {
287230130Smav			struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
288230130Smav			(void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
289230130Smav			    routename(sa) : netname(sa));
290230130Smav			sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
291230130Smav			(void) printf("%-20.20s ", routename(sa));
292230130Smav			(void) printf("done\n");
293230130Smav		}
294230130Smav	}
295230130Smav}
296230130Smav
297230130Smavchar *
298230130Smavroutename(sa)
299230130Smav	struct sockaddr *sa;
300230130Smav{
301230130Smav	register char *cp;
302230130Smav	static char line[MAXHOSTNAMELEN + 1];
303230571Smav	struct hostent *hp;
304230571Smav	static char domain[MAXHOSTNAMELEN + 1];
305230130Smav	static int first = 1;
306230130Smav#ifdef NS
307230130Smav	char *ns_print();
308230130Smav#endif
309230130Smav
310230130Smav	if (first) {
311230130Smav		first = 0;
312230130Smav		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
313230130Smav		    (cp = index(domain, '.'))) {
314230130Smav			domain[MAXHOSTNAMELEN] = '\0';
315230130Smav			(void) strcpy(domain, cp + 1);
316230130Smav		} else
317230130Smav			domain[0] = 0;
318230130Smav	}
319230130Smav
320230130Smav	if (sa->sa_len == 0)
321230571Smav		strcpy(line, "default");
322230571Smav	else switch (sa->sa_family) {
323230331Smav
324230571Smav	case AF_INET:
325230571Smav	    {	struct in_addr in;
326230571Smav		in = ((struct sockaddr_in *)sa)->sin_addr;
327230571Smav
328230331Smav		cp = 0;
329230571Smav		if (in.s_addr == INADDR_ANY || sa->sa_len < 4)
330230571Smav			cp = "default";
331230571Smav		if (cp == 0 && !nflag) {
332230571Smav			hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
333230574Smav				AF_INET);
334230571Smav			if (hp) {
335230571Smav				if ((cp = index(hp->h_name, '.')) &&
336230331Smav				    !strcmp(cp + 1, domain))
337230331Smav					*cp = 0;
338230130Smav				cp = hp->h_name;
339230130Smav			}
340230130Smav		}
341230130Smav		if (cp)
342230130Smav			strncpy(line, cp, sizeof line);
343230130Smav		else {
344230130Smav			/* XXX - why not inet_ntoa()? */
345230130Smav#define C(x)	(unsigned)((x) & 0xff)
346230130Smav			in.s_addr = ntohl(in.s_addr);
347230130Smav			(void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
348230130Smav			   C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
349230130Smav		}
350230130Smav		break;
351230130Smav	    }
352230130Smav
353230130Smav	case AF_APPLETALK:
354230130Smav		(void) snprintf(line, sizeof(line), "atalk %s",
355230130Smav			atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
356230130Smav		break;
357230130Smav
358230130Smav#ifdef NS
359230130Smav	case AF_NS:
360230130Smav		return (ns_print((struct sockaddr_ns *)sa));
361230130Smav#endif
362230130Smav
363230130Smav	case AF_LINK:
364230130Smav		return (link_ntoa((struct sockaddr_dl *)sa));
365230130Smav
366230130Smav	default:
367230130Smav	    {	u_short *s = (u_short *)sa;
368230130Smav		u_short *slim = s + ((sa->sa_len + 1) >> 1);
369230130Smav		char *cp = line + sprintf(line, "(%d)", sa->sa_family);
370230130Smav		char *cpe = line + sizeof(line);
371230130Smav
372230130Smav		while (++s < slim && cp < cpe) /* start with sa->sa_data */
373230130Smav			cp += snprintf(cp, cpe - cp, " %x", *s);
374230331Smav		break;
375230130Smav	    }
376230130Smav	}
377230130Smav	return (line);
378230331Smav}
379230331Smav
380230331Smav/*
381230331Smav * Return the name of the network whose address is given.
382230331Smav * The address is assumed to be that of a net or subnet, not a host.
383230331Smav */
384230331Smavchar *
385230331Smavnetname(sa)
386230331Smav	struct sockaddr *sa;
387230331Smav{
388230331Smav	char *cp = 0;
389230331Smav	static char line[MAXHOSTNAMELEN + 1];
390230331Smav	struct netent *np = 0;
391230331Smav	u_long net, mask;
392230331Smav	register u_long i;
393230331Smav	int subnetshift;
394230331Smav#ifdef NS
395230331Smav	char *ns_print();
396230130Smav#endif
397230130Smav
398230130Smav	switch (sa->sa_family) {
399230130Smav
400230130Smav	case AF_INET:
401230130Smav	    {	struct in_addr in;
402230130Smav		in = ((struct sockaddr_in *)sa)->sin_addr;
403230130Smav
404230130Smav		i = in.s_addr = ntohl(in.s_addr);
405230130Smav		if (in.s_addr == 0)
406230130Smav			cp = "default";
407230130Smav		else if (!nflag) {
408230130Smav			if (IN_CLASSA(i)) {
409230130Smav				mask = IN_CLASSA_NET;
410230130Smav				subnetshift = 8;
411230130Smav			} else if (IN_CLASSB(i)) {
412230130Smav				mask = IN_CLASSB_NET;
413230130Smav				subnetshift = 8;
414230130Smav			} else {
415230130Smav				mask = IN_CLASSC_NET;
416230130Smav				subnetshift = 4;
417230130Smav			}
418230130Smav			/*
419230130Smav			 * If there are more bits than the standard mask
420230130Smav			 * would suggest, subnets must be in use.
421230130Smav			 * Guess at the subnet mask, assuming reasonable
422230130Smav			 * width subnet fields.
423230130Smav			 */
424230130Smav			while (in.s_addr &~ mask)
425230130Smav				mask = (long)mask >> subnetshift;
426230130Smav			net = in.s_addr & mask;
427230130Smav			while ((mask & 1) == 0)
428230130Smav				mask >>= 1, net >>= 1;
429230130Smav			np = getnetbyaddr(net, AF_INET);
430230130Smav			if (np)
431230130Smav				cp = np->n_name;
432230130Smav		}
433230130Smav		if (cp)
434230130Smav			strncpy(line, cp, sizeof(line));
435230130Smav		else if ((in.s_addr & 0xffffff) == 0)
436230130Smav			(void) sprintf(line, "%u", C(in.s_addr >> 24));
437230130Smav		else if ((in.s_addr & 0xffff) == 0)
438230130Smav			(void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
439230130Smav			    C(in.s_addr >> 16));
440230130Smav		else if ((in.s_addr & 0xff) == 0)
441230130Smav			(void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
442230130Smav			    C(in.s_addr >> 16), C(in.s_addr >> 8));
443230130Smav		else
444230130Smav			(void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
445230130Smav			    C(in.s_addr >> 16), C(in.s_addr >> 8),
446230130Smav			    C(in.s_addr));
447230130Smav		break;
448230130Smav	    }
449230130Smav
450230130Smav	case AF_APPLETALK:
451230130Smav		(void) snprintf(line, sizeof(line), "atalk %s",
452230130Smav			atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
453230130Smav		break;
454230130Smav
455230130Smav#ifdef NS
456230130Smav	case AF_NS:
457230130Smav		return (ns_print((struct sockaddr_ns *)sa));
458230130Smav		break;
459230130Smav#endif
460230130Smav
461230130Smav	case AF_LINK:
462230130Smav		return (link_ntoa((struct sockaddr_dl *)sa));
463230130Smav
464230130Smav
465230130Smav	default:
466230130Smav	    {	u_short *s = (u_short *)sa->sa_data;
467230130Smav		u_short *slim = s + ((sa->sa_len + 1)>>1);
468230130Smav		char *cp = line + sprintf(line, "af %d:", sa->sa_family);
469230130Smav		char *cpe = line + sizeof(line);
470230130Smav
471230130Smav		while (s < slim && cp < cpe)
472230130Smav			cp += snprintf(cp, cpe - cp, " %x", *s++);
473230130Smav		break;
474230130Smav	    }
475230130Smav	}
476230130Smav	return (line);
477230130Smav}
478230130Smav
479230130Smavvoid
480230130Smavset_metric(value, key)
481230130Smav	char *value;
482230130Smav	int key;
483230130Smav{
484230130Smav	int flag = 0;
485230130Smav	u_long noval, *valp = &noval;
486230130Smav
487230130Smav	switch (key) {
488230130Smav#define caseof(x, y, z)	case x: valp = &rt_metrics.z; flag = y; break
489230130Smav	caseof(K_MTU, RTV_MTU, rmx_mtu);
490230130Smav	caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
491230130Smav	caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
492230130Smav	caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
493230130Smav	caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
494230130Smav	caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
495230130Smav	caseof(K_RTT, RTV_RTT, rmx_rtt);
496230130Smav	caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
497230130Smav	}
498230130Smav	rtm_inits |= flag;
499230130Smav	if (lockrest || locking)
500230130Smav		rt_metrics.rmx_locks |= flag;
501230130Smav	if (locking)
502230130Smav		locking = 0;
503230130Smav	*valp = atoi(value);
504230130Smav}
505230130Smav
506230130Smavvoid
507230130Smavnewroute(argc, argv)
508230130Smav	int argc;
509230130Smav	register char **argv;
510230130Smav{
511230130Smav	char *cmd, *dest = "", *gateway = "", *err;
512230130Smav	int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC;
513230130Smav	int key;
514230130Smav	struct hostent *hp = 0;
515230130Smav
516230130Smav	if (uid) {
517230130Smav		errx(EX_NOPERM, "must be root to alter routing table");
518230130Smav	}
519230130Smav	cmd = argv[0];
520230130Smav	if (*cmd != 'g')
521230130Smav		shutdown(s, 0); /* Don't want to read back our messages */
522230130Smav	while (--argc > 0) {
523230130Smav		if (**(++argv)== '-') {
524230130Smav			switch (key = keyword(1 + *argv)) {
525230130Smav			case K_LINK:
526230130Smav				af = AF_LINK;
527230130Smav				aflen = sizeof(struct sockaddr_dl);
528230130Smav				break;
529230130Smav			case K_INET:
530230130Smav				af = AF_INET;
531230130Smav				aflen = sizeof(struct sockaddr_in);
532230130Smav				break;
533230130Smav			case K_ATALK:
534230130Smav				af = AF_APPLETALK;
535230130Smav				aflen = sizeof(struct sockaddr_at);
536230130Smav				break;
537230130Smav			case K_SA:
538230130Smav				af = PF_ROUTE;
539230130Smav				aflen = sizeof(union sockunion);
540230130Smav				break;
541230130Smav#ifdef NS
542230130Smav			case K_XNS:
543230130Smav				af = AF_NS;
544230130Smav				aflen = sizeof(struct sockaddr_ns);
545230130Smav				break;
546230130Smav#endif
547230130Smav			case K_IFACE:
548230130Smav			case K_INTERFACE:
549230130Smav				iflag++;
550230130Smav				break;
551230130Smav			case K_NOSTATIC:
552230130Smav				flags &= ~RTF_STATIC;
553230130Smav				break;
554230130Smav			case K_LLINFO:
555230130Smav				flags |= RTF_LLINFO;
556230130Smav				break;
557230130Smav			case K_LOCK:
558230326Smav				locking = 1;
559230130Smav				break;
560230130Smav			case K_LOCKREST:
561230130Smav				lockrest = 1;
562230130Smav				break;
563230130Smav			case K_HOST:
564230326Smav				forcehost++;
565230130Smav				break;
566230130Smav			case K_REJECT:
567230130Smav				flags |= RTF_REJECT;
568230130Smav				break;
569230130Smav			case K_BLACKHOLE:
570230130Smav				flags |= RTF_BLACKHOLE;
571230130Smav				break;
572230130Smav			case K_PROTO1:
573230130Smav				flags |= RTF_PROTO1;
574230130Smav				break;
575230130Smav			case K_PROTO2:
576230130Smav				flags |= RTF_PROTO2;
577230130Smav				break;
578230130Smav			case K_CLONING:
579230130Smav				flags |= RTF_CLONING;
580230130Smav				break;
581230130Smav			case K_XRESOLVE:
582230130Smav				flags |= RTF_XRESOLVE;
583230130Smav				break;
584230130Smav			case K_STATIC:
585230130Smav				flags |= RTF_STATIC;
586230130Smav				break;
587230130Smav			case K_IFA:
588230130Smav				argc--;
589230130Smav				(void) getaddr(RTA_IFA, *++argv, 0);
590230130Smav				break;
591230130Smav			case K_IFP:
592230130Smav				argc--;
593230130Smav				(void) getaddr(RTA_IFP, *++argv, 0);
594230130Smav				break;
595230130Smav			case K_GENMASK:
596230130Smav				argc--;
597230130Smav				(void) getaddr(RTA_GENMASK, *++argv, 0);
598230130Smav				break;
599230130Smav			case K_GATEWAY:
600230130Smav				argc--;
601230130Smav				(void) getaddr(RTA_GATEWAY, *++argv, 0);
602230130Smav				break;
603230130Smav			case K_DST:
604230130Smav				argc--;
605230130Smav				ishost = getaddr(RTA_DST, *++argv, &hp);
606230130Smav				dest = *argv;
607230130Smav				break;
608230130Smav			case K_NETMASK:
609230130Smav				argc--;
610230130Smav				(void) getaddr(RTA_NETMASK, *++argv, 0);
611230130Smav				/* FALLTHROUGH */
612230130Smav			case K_NET:
613230130Smav				forcenet++;
614230130Smav				break;
615230130Smav			case K_MTU:
616230130Smav			case K_HOPCOUNT:
617230130Smav			case K_EXPIRE:
618230130Smav			case K_RECVPIPE:
619230130Smav			case K_SENDPIPE:
620230130Smav			case K_SSTHRESH:
621230130Smav			case K_RTT:
622230130Smav			case K_RTTVAR:
623230130Smav				argc--;
624230130Smav				set_metric(*++argv, key);
625230130Smav				break;
626230130Smav			default:
627230130Smav				usage(1+*argv);
628230130Smav			}
629230130Smav		} else {
630230130Smav			if ((rtm_addrs & RTA_DST) == 0) {
631230130Smav				dest = *argv;
632230130Smav				ishost = getaddr(RTA_DST, *argv, &hp);
633230130Smav			} else if ((rtm_addrs & RTA_GATEWAY) == 0) {
634230130Smav				gateway = *argv;
635230130Smav				(void) getaddr(RTA_GATEWAY, *argv, &hp);
636230130Smav			} else {
637230130Smav				(void) getaddr(RTA_NETMASK, *argv, 0);
638230130Smav			}
639230130Smav		}
640230130Smav	}
641230130Smav	if (forcehost)
642230130Smav		ishost = 1;
643230130Smav	if (forcenet)
644230130Smav		ishost = 0;
645230130Smav	flags |= RTF_UP;
646230130Smav	if (ishost)
647230130Smav		flags |= RTF_HOST;
648230130Smav	if (iflag == 0)
649230130Smav		flags |= RTF_GATEWAY;
650230130Smav	for (attempts = 1; ; attempts++) {
651230130Smav		errno = 0;
652230130Smav		if ((ret = rtmsg(*cmd, flags)) == 0)
653230130Smav			break;
654230130Smav		if (errno != ENETUNREACH && errno != ESRCH)
655230130Smav			break;
656230130Smav		if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
657230130Smav			hp->h_addr_list++;
658230130Smav			bcopy(hp->h_addr_list[0], &so_gate.sin.sin_addr,
659230130Smav			    hp->h_length);
660230130Smav		} else
661230130Smav			break;
662230130Smav	}
663230130Smav	if (*cmd == 'g')
664230130Smav		exit(0);
665230130Smav	oerrno = errno;
666230130Smav	(void) printf("%s %s %s", cmd, ishost? "host" : "net", dest);
667230130Smav	if (*gateway) {
668230130Smav		(void) printf(": gateway %s", gateway);
669230130Smav		if (attempts > 1 && ret == 0 && af == AF_INET)
670230130Smav		    (void) printf(" (%s)",
671230130Smav			inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
672230130Smav	}
673230130Smav	if (ret == 0)
674230130Smav		(void) printf("\n");
675230130Smav	else {
676230130Smav		switch (oerrno) {
677230130Smav		case ESRCH:
678230130Smav			err = "not in table";
679230130Smav			break;
680230130Smav		case EBUSY:
681230130Smav			err = "entry in use";
682230130Smav			break;
683230130Smav		case ENOBUFS:
684230130Smav			err = "routing table overflow";
685230130Smav			break;
686230130Smav		default:
687230130Smav			err = strerror(oerrno);
688230130Smav			break;
689230130Smav		}
690230130Smav		(void) printf(": %s\n", err);
691230130Smav	}
692230130Smav}
693230130Smav
694230130Smavvoid
695230130Smavinet_makenetandmask(net, sin, bits)
696230130Smav	u_long net, bits;
697230130Smav	register struct sockaddr_in *sin;
698230130Smav{
699230130Smav	u_long addr, mask = 0;
700230130Smav	register char *cp;
701230130Smav
702230130Smav	rtm_addrs |= RTA_NETMASK;
703230130Smav	if (net == 0)
704230130Smav		mask = addr = 0;
705230130Smav	else if (bits) {
706230130Smav		addr = net;
707230130Smav		mask = 0xffffffff << (32 - bits);
708230130Smav	} else if (net < 128) {
709230130Smav		addr = net << IN_CLASSA_NSHIFT;
710230130Smav		mask = IN_CLASSA_NET;
711230130Smav	} else if (net < 65536) {
712230130Smav		addr = net << IN_CLASSB_NSHIFT;
713230130Smav		mask = IN_CLASSB_NET;
714230130Smav	} else if (net < 16777216L) {
715		addr = net << IN_CLASSC_NSHIFT;
716		mask = IN_CLASSC_NET;
717	} else {
718		addr = net;
719		if ((addr & IN_CLASSA_HOST) == 0)
720			mask =  IN_CLASSA_NET;
721		else if ((addr & IN_CLASSB_HOST) == 0)
722			mask =  IN_CLASSB_NET;
723		else if ((addr & IN_CLASSC_HOST) == 0)
724			mask =  IN_CLASSC_NET;
725		else
726			mask = -1;
727	}
728	sin->sin_addr.s_addr = htonl(addr);
729	sin = &so_mask.sin;
730	sin->sin_addr.s_addr = htonl(mask);
731	sin->sin_len = 0;
732	sin->sin_family = 0;
733	cp = (char *)(&sin->sin_addr + 1);
734	while (*--cp == 0 && cp > (char *)sin)
735		;
736	sin->sin_len = 1 + cp - (char *)sin;
737}
738
739/*
740 * Interpret an argument as a network address of some kind,
741 * returning 1 if a host address, 0 if a network address.
742 */
743int
744getaddr(which, s, hpp)
745	int which;
746	char *s;
747	struct hostent **hpp;
748{
749	register sup su;
750#ifdef NS
751	struct ns_addr ns_addr();
752#endif
753	struct hostent *hp;
754	struct netent *np;
755	u_long val;
756	char *q,qs;
757
758	if (af == 0) {
759		af = AF_INET;
760		aflen = sizeof(struct sockaddr_in);
761	}
762	rtm_addrs |= which;
763	switch (which) {
764	case RTA_DST:
765		su = &so_dst;
766		break;
767	case RTA_GATEWAY:
768		su = &so_gate;
769		if (iflag) {
770			#define MAX_IFACES	400
771			int			sock;
772			struct ifreq		iflist[MAX_IFACES];
773			struct ifconf		ifconf;
774			struct ifreq		*ifr, *ifr_end;
775			struct sockaddr_dl	*dl, *sdl = NULL;
776
777			/* Get socket */
778			if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
779				err(1, "socket");
780
781			/* Get interface list */
782			ifconf.ifc_req = iflist;
783			ifconf.ifc_len = sizeof(iflist);
784			if (ioctl(sock, SIOCGIFCONF, &ifconf) < 0)
785				err(1, "ioctl(SIOCGIFCONF)");
786			close(sock);
787
788			/* Look for this interface in the list */
789			for (ifr = ifconf.ifc_req,
790			    ifr_end = (struct ifreq *)
791				(ifconf.ifc_buf + ifconf.ifc_len);
792			    ifr < ifr_end;
793			    ifr = (struct ifreq *) ((char *) &ifr->ifr_addr
794						    + ifr->ifr_addr.sa_len)) {
795				dl = (struct sockaddr_dl *)&ifr->ifr_addr;
796				if (ifr->ifr_addr.sa_family == AF_LINK
797				    && (ifr->ifr_flags & IFF_POINTOPOINT)
798				    && !strncmp(s, dl->sdl_data, dl->sdl_nlen)
799				    && s[dl->sdl_nlen] == 0) {
800					sdl = dl;
801					break;
802				}
803			}
804
805			/* If we found it, then use it */
806			if (sdl) {
807				su->sdl = *sdl;
808				return(1);
809			}
810		}
811		break;
812	case RTA_NETMASK:
813		su = &so_mask;
814		break;
815	case RTA_GENMASK:
816		su = &so_genmask;
817		break;
818	case RTA_IFP:
819		su = &so_ifp;
820		break;
821	case RTA_IFA:
822		su = &so_ifa;
823		break;
824	default:
825		usage("Internal Error");
826		/*NOTREACHED*/
827	}
828	su->sa.sa_len = aflen;
829	su->sa.sa_family = af; /* cases that don't want it have left already */
830	if (strcmp(s, "default") == 0) {
831		/*
832		 * Default is net 0.0.0.0/0
833		 */
834		switch (which) {
835		case RTA_DST:
836			forcenet++;
837			/* bzero(su, sizeof(*su)); *//* for readability */
838			(void) getaddr(RTA_NETMASK, s, 0);
839			break;
840		case RTA_NETMASK:
841		case RTA_GENMASK:
842			/* bzero(su, sizeof(*su)); *//* for readability */
843		}
844		return (0);
845	}
846	switch (af) {
847#ifdef NS
848	case AF_NS:
849		if (which == RTA_DST) {
850			extern short ns_bh[3];
851			struct sockaddr_ns *sms = &(so_mask.sns);
852			bzero((char *)sms, sizeof(*sms));
853			sms->sns_family = 0;
854			sms->sns_len = 6;
855			sms->sns_addr.x_net = *(union ns_net *)ns_bh;
856			rtm_addrs |= RTA_NETMASK;
857		}
858		su->sns.sns_addr = ns_addr(s);
859		return (!ns_nullhost(su->sns.sns_addr));
860#endif
861
862
863	case AF_APPLETALK:
864		if (!atalk_aton(s, &su->sat.sat_addr))
865			errx(EX_NOHOST, "bad address: %s", s);
866		rtm_addrs |= RTA_NETMASK;
867		return(forcehost || su->sat.sat_addr.s_node != 0);
868
869	case AF_LINK:
870		link_addr(s, &su->sdl);
871		return (1);
872
873
874	case PF_ROUTE:
875		su->sa.sa_len = sizeof(*su);
876		sockaddr(s, &su->sa);
877		return (1);
878
879	case AF_INET:
880	default:
881		break;
882	}
883
884	if (hpp == NULL)
885		hpp = &hp;
886	*hpp = NULL;
887
888	q = strchr(s,'/');
889	if (q && which == RTA_DST) {
890		qs = *q;
891		*q = '\0';
892		if (((val = inet_addr(s)) != INADDR_NONE)) {
893			inet_makenetandmask(
894				htonl(val), &su->sin, strtoul(q+1, 0, 0));
895			return (0);
896		}
897		*q =qs;
898	}
899	if (((val = inet_addr(s)) != INADDR_NONE) &&
900	    (which != RTA_DST || forcenet == 0)) {
901		su->sin.sin_addr.s_addr = val;
902		if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
903			return (1);
904		else {
905			val = ntohl(val);
906			goto netdone;
907		}
908	}
909	if ((val = inet_network(s)) != INADDR_NONE ||
910	    (forcehost == 0 && (np = getnetbyname(s)) != NULL &&
911		    (val = np->n_net) != 0)) {
912netdone:
913		if (which == RTA_DST)
914			inet_makenetandmask(val, &su->sin, 0);
915		return (0);
916	}
917	hp = gethostbyname(s);
918	if (hp) {
919		*hpp = hp;
920		su->sin.sin_family = hp->h_addrtype;
921		bcopy(hp->h_addr, (char *)&su->sin.sin_addr, hp->h_length);
922		return (1);
923	}
924	errx(EX_NOHOST, "bad address: %s", s);
925}
926
927
928#ifdef NS
929short ns_nullh[] = {0,0,0};
930short ns_bh[] = {-1,-1,-1};
931
932char *
933ns_print(sns)
934	struct sockaddr_ns *sns;
935{
936	struct ns_addr work;
937	union { union ns_net net_e; u_long long_e; } net;
938	u_short port;
939	static char mybuf[50+MAXHOSTNAMELEN], cport[10], chost[25];
940	char *host = "";
941	register char *p;
942	register u_char *q;
943
944	work = sns->sns_addr;
945	port = ntohs(work.x_port);
946	work.x_port = 0;
947	net.net_e  = work.x_net;
948	if (ns_nullhost(work) && net.long_e == 0) {
949		if (!port)
950			return ("*.*");
951		(void) sprintf(mybuf, "*.%XH", port);
952		return (mybuf);
953	}
954
955	if (bcmp((char *)ns_bh, (char *)work.x_host.c_host, 6) == 0)
956		host = "any";
957	else if (bcmp((char *)ns_nullh, (char *)work.x_host.c_host, 6) == 0)
958		host = "*";
959	else {
960		q = work.x_host.c_host;
961		(void) sprintf(chost, "%02X%02X%02X%02X%02X%02XH",
962			q[0], q[1], q[2], q[3], q[4], q[5]);
963		for (p = chost; *p == '0' && p < chost + 12; p++)
964			/* void */;
965		host = p;
966	}
967	if (port)
968		(void) sprintf(cport, ".%XH", htons(port));
969	else
970		*cport = 0;
971
972	(void) snprintf(mybuf, sizeof(mybuf), "%lxH.%s%s",
973                    (unsigned long)ntohl(net.long_e),
974		       host, cport);
975	return (mybuf);
976}
977#endif
978
979void
980interfaces()
981{
982	size_t needed;
983	int mib[6];
984	char *buf, *lim, *next;
985	register struct rt_msghdr *rtm;
986
987	mib[0] = CTL_NET;
988	mib[1] = PF_ROUTE;
989	mib[2] = 0;		/* protocol */
990	mib[3] = 0;		/* wildcard address family */
991	mib[4] = NET_RT_IFLIST;
992	mib[5] = 0;		/* no flags */
993	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
994		err(EX_OSERR, "route-sysctl-estimate");
995	if ((buf = malloc(needed)) == NULL)
996		err(EX_OSERR, "malloc");
997	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
998		err(EX_OSERR, "actual retrieval of interface table");
999	lim = buf + needed;
1000	for (next = buf; next < lim; next += rtm->rtm_msglen) {
1001		rtm = (struct rt_msghdr *)next;
1002		print_rtmsg(rtm, rtm->rtm_msglen);
1003	}
1004}
1005
1006void
1007monitor()
1008{
1009	int n;
1010	char msg[2048];
1011
1012	verbose = 1;
1013	if (debugonly) {
1014		interfaces();
1015		exit(0);
1016	}
1017	for(;;) {
1018		n = read(s, msg, 2048);
1019		(void) printf("got message of size %d\n", n);
1020		print_rtmsg((struct rt_msghdr *)msg, n);
1021	}
1022}
1023
1024struct {
1025	struct	rt_msghdr m_rtm;
1026	char	m_space[512];
1027} m_rtmsg;
1028
1029int
1030rtmsg(cmd, flags)
1031	int cmd, flags;
1032{
1033	static int seq;
1034	int rlen;
1035	register char *cp = m_rtmsg.m_space;
1036	register int l;
1037
1038#define NEXTADDR(w, u) \
1039	if (rtm_addrs & (w)) {\
1040	    l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\
1041	    if (verbose) sodump(&(u),"u");\
1042	}
1043
1044	errno = 0;
1045	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
1046	if (cmd == 'a')
1047		cmd = RTM_ADD;
1048	else if (cmd == 'c')
1049		cmd = RTM_CHANGE;
1050	else if (cmd == 'g') {
1051		cmd = RTM_GET;
1052		if (so_ifp.sa.sa_family == 0) {
1053			so_ifp.sa.sa_family = AF_LINK;
1054			so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
1055			rtm_addrs |= RTA_IFP;
1056		}
1057	} else
1058		cmd = RTM_DELETE;
1059#define rtm m_rtmsg.m_rtm
1060	rtm.rtm_type = cmd;
1061	rtm.rtm_flags = flags;
1062	rtm.rtm_version = RTM_VERSION;
1063	rtm.rtm_seq = ++seq;
1064	rtm.rtm_addrs = rtm_addrs;
1065	rtm.rtm_rmx = rt_metrics;
1066	rtm.rtm_inits = rtm_inits;
1067
1068	if (rtm_addrs & RTA_NETMASK)
1069		mask_addr();
1070	NEXTADDR(RTA_DST, so_dst);
1071	NEXTADDR(RTA_GATEWAY, so_gate);
1072	NEXTADDR(RTA_NETMASK, so_mask);
1073	NEXTADDR(RTA_GENMASK, so_genmask);
1074	NEXTADDR(RTA_IFP, so_ifp);
1075	NEXTADDR(RTA_IFA, so_ifa);
1076	rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
1077	if (verbose)
1078		print_rtmsg(&rtm, l);
1079	if (debugonly)
1080		return (0);
1081	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
1082		perror("writing to routing socket");
1083		return (-1);
1084	}
1085	if (cmd == RTM_GET) {
1086		do {
1087			l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
1088		} while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
1089		if (l < 0)
1090			warn("read from routing socket");
1091		else
1092			print_getmsg(&rtm, l);
1093	}
1094#undef rtm
1095	return (0);
1096}
1097
1098void
1099mask_addr()
1100{
1101	int olen = so_mask.sa.sa_len;
1102	register char *cp1 = olen + (char *)&so_mask, *cp2;
1103
1104	for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; )
1105		if (*--cp1 != 0) {
1106			so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask;
1107			break;
1108		}
1109	if ((rtm_addrs & RTA_DST) == 0)
1110		return;
1111	switch (so_dst.sa.sa_family) {
1112#ifdef NS
1113	case AF_NS:
1114#endif
1115	case AF_INET:
1116	case AF_APPLETALK:
1117	case 0:
1118		return;
1119	}
1120	cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
1121	cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
1122	while (cp2 > cp1)
1123		*--cp2 = 0;
1124	cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
1125	while (cp1 > so_dst.sa.sa_data)
1126		*--cp1 &= *--cp2;
1127}
1128
1129char *msgtypes[] = {
1130	"",
1131	"RTM_ADD: Add Route",
1132	"RTM_DELETE: Delete Route",
1133	"RTM_CHANGE: Change Metrics or flags",
1134	"RTM_GET: Report Metrics",
1135	"RTM_LOSING: Kernel Suspects Partitioning",
1136	"RTM_REDIRECT: Told to use different route",
1137	"RTM_MISS: Lookup failed on this address",
1138	"RTM_LOCK: fix specified metrics",
1139	"RTM_OLDADD: caused by SIOCADDRT",
1140	"RTM_OLDDEL: caused by SIOCDELRT",
1141	"RTM_RESOLVE: Route created by cloning",
1142	"RTM_NEWADDR: address being added to iface",
1143	"RTM_DELADDR: address being removed from iface",
1144	"RTM_IFINFO: iface status change",
1145	"RTM_NEWMADDR: new multicast group membership on iface",
1146	"RTM_DELMADDR: multicast group membership removed from iface",
1147	0,
1148};
1149
1150char metricnames[] =
1151"\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
1152"\1mtu";
1153char routeflags[] =
1154"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"
1155"\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016"
1156"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024CHAINDELETE"
1157"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST";
1158char ifnetflags[] =
1159"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
1160"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
1161"\017LINK2\020MULTICAST";
1162char addrnames[] =
1163"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
1164
1165void
1166print_rtmsg(rtm, msglen)
1167	register struct rt_msghdr *rtm;
1168	int msglen;
1169{
1170	struct if_msghdr *ifm;
1171	struct ifa_msghdr *ifam;
1172#ifdef RTM_NEWMADDR
1173	struct ifma_msghdr *ifmam;
1174#endif
1175
1176	if (verbose == 0)
1177		return;
1178	if (rtm->rtm_version != RTM_VERSION) {
1179		(void) printf("routing message version %d not understood\n",
1180		    rtm->rtm_version);
1181		return;
1182	}
1183	(void)printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen);
1184	switch (rtm->rtm_type) {
1185	case RTM_IFINFO:
1186		ifm = (struct if_msghdr *)rtm;
1187		(void) printf("if# %d, flags:", ifm->ifm_index);
1188		bprintf(stdout, ifm->ifm_flags, ifnetflags);
1189		pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
1190		break;
1191	case RTM_NEWADDR:
1192	case RTM_DELADDR:
1193		ifam = (struct ifa_msghdr *)rtm;
1194		(void) printf("metric %d, flags:", ifam->ifam_metric);
1195		bprintf(stdout, ifam->ifam_flags, routeflags);
1196		pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
1197		break;
1198#ifdef RTM_NEWMADDR
1199	case RTM_NEWMADDR:
1200	case RTM_DELMADDR:
1201		ifmam = (struct ifma_msghdr *)rtm;
1202		pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs);
1203		break;
1204#endif
1205	default:
1206		(void) printf("pid: %ld, seq %d, errno %d, flags:",
1207			(long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1208		bprintf(stdout, rtm->rtm_flags, routeflags);
1209		pmsg_common(rtm);
1210	}
1211}
1212
1213void
1214print_getmsg(rtm, msglen)
1215	register struct rt_msghdr *rtm;
1216	int msglen;
1217{
1218	struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
1219	struct sockaddr_dl *ifp = NULL;
1220	register struct sockaddr *sa;
1221	register char *cp;
1222	register int i;
1223
1224	(void) printf("   route to: %s\n", routename(&so_dst));
1225	if (rtm->rtm_version != RTM_VERSION) {
1226		warnx("routing message version %d not understood",
1227		     rtm->rtm_version);
1228		return;
1229	}
1230	if (rtm->rtm_msglen > msglen) {
1231		warnx("message length mismatch, in packet %d, returned %d\n",
1232		      rtm->rtm_msglen, msglen);
1233	}
1234	if (rtm->rtm_errno)  {
1235		errno = rtm->rtm_errno;
1236		warn("message indicates error %d", errno);
1237		return;
1238	}
1239	cp = ((char *)(rtm + 1));
1240	if (rtm->rtm_addrs)
1241		for (i = 1; i; i <<= 1)
1242			if (i & rtm->rtm_addrs) {
1243				sa = (struct sockaddr *)cp;
1244				switch (i) {
1245				case RTA_DST:
1246					dst = sa;
1247					break;
1248				case RTA_GATEWAY:
1249					gate = sa;
1250					break;
1251				case RTA_NETMASK:
1252					mask = sa;
1253					break;
1254				case RTA_IFP:
1255					if (sa->sa_family == AF_LINK &&
1256					   ((struct sockaddr_dl *)sa)->sdl_nlen)
1257						ifp = (struct sockaddr_dl *)sa;
1258					break;
1259				}
1260				ADVANCE(cp, sa);
1261			}
1262	if (dst && mask)
1263		mask->sa_family = dst->sa_family;	/* XXX */
1264	if (dst)
1265		(void)printf("destination: %s\n", routename(dst));
1266	if (mask) {
1267		int savenflag = nflag;
1268
1269		nflag = 1;
1270		(void)printf("       mask: %s\n", routename(mask));
1271		nflag = savenflag;
1272	}
1273	if (gate && rtm->rtm_flags & RTF_GATEWAY)
1274		(void)printf("    gateway: %s\n", routename(gate));
1275	if (ifp)
1276		(void)printf("  interface: %.*s\n",
1277		    ifp->sdl_nlen, ifp->sdl_data);
1278	(void)printf("      flags: ");
1279	bprintf(stdout, rtm->rtm_flags, routeflags);
1280
1281#define lock(f)	((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1282#define msec(u)	(((u) + 500) / 1000)		/* usec to msec */
1283
1284	(void) printf("\n%s\n", "\
1285 recvpipe  sendpipe  ssthresh  rtt,msec    rttvar  hopcount      mtu     expire");
1286	printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
1287	printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
1288	printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
1289	printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
1290	printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
1291	printf("%8ld%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
1292	printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
1293	if (rtm->rtm_rmx.rmx_expire)
1294		rtm->rtm_rmx.rmx_expire -= time(0);
1295	printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
1296#undef lock
1297#undef msec
1298#define	RTA_IGN	(RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
1299	if (verbose)
1300		pmsg_common(rtm);
1301	else if (rtm->rtm_addrs &~ RTA_IGN) {
1302		(void) printf("sockaddrs: ");
1303		bprintf(stdout, rtm->rtm_addrs, addrnames);
1304		putchar('\n');
1305	}
1306#undef	RTA_IGN
1307}
1308
1309void
1310pmsg_common(rtm)
1311	register struct rt_msghdr *rtm;
1312{
1313	(void) printf("\nlocks: ");
1314	bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
1315	(void) printf(" inits: ");
1316	bprintf(stdout, rtm->rtm_inits, metricnames);
1317	pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
1318}
1319
1320void
1321pmsg_addrs(cp, addrs)
1322	char	*cp;
1323	int	addrs;
1324{
1325	register struct sockaddr *sa;
1326	int i;
1327
1328	if (addrs == 0)
1329		return;
1330	(void) printf("\nsockaddrs: ");
1331	bprintf(stdout, addrs, addrnames);
1332	(void) putchar('\n');
1333	for (i = 1; i; i <<= 1)
1334		if (i & addrs) {
1335			sa = (struct sockaddr *)cp;
1336			(void) printf(" %s", routename(sa));
1337			ADVANCE(cp, sa);
1338		}
1339	(void) putchar('\n');
1340	(void) fflush(stdout);
1341}
1342
1343void
1344bprintf(fp, b, s)
1345	register FILE *fp;
1346	register int b;
1347	register u_char *s;
1348{
1349	register int i;
1350	int gotsome = 0;
1351
1352	if (b == 0)
1353		return;
1354	while ((i = *s++) != 0) {
1355		if (b & (1 << (i-1))) {
1356			if (gotsome == 0)
1357				i = '<';
1358			else
1359				i = ',';
1360			(void) putc(i, fp);
1361			gotsome = 1;
1362			for (; (i = *s) > 32; s++)
1363				(void) putc(i, fp);
1364		} else
1365			while (*s > 32)
1366				s++;
1367	}
1368	if (gotsome)
1369		(void) putc('>', fp);
1370}
1371
1372int
1373keyword(cp)
1374	char *cp;
1375{
1376	register struct keytab *kt = keywords;
1377
1378	while (kt->kt_cp && strcmp(kt->kt_cp, cp))
1379		kt++;
1380	return kt->kt_i;
1381}
1382
1383void
1384sodump(su, which)
1385	register sup su;
1386	char *which;
1387{
1388	switch (su->sa.sa_family) {
1389	case AF_LINK:
1390		(void) printf("%s: link %s; ",
1391		    which, link_ntoa(&su->sdl));
1392		break;
1393	case AF_INET:
1394		(void) printf("%s: inet %s; ",
1395		    which, inet_ntoa(su->sin.sin_addr));
1396		break;
1397	case AF_APPLETALK:
1398		(void) printf("%s: atalk %s; ",
1399		    which, atalk_ntoa(su->sat.sat_addr));
1400		break;
1401#ifdef NS
1402	case AF_NS:
1403		(void) printf("%s: xns %s; ",
1404		    which, ns_ntoa(su->sns.sns_addr));
1405		break;
1406#endif
1407	}
1408	(void) fflush(stdout);
1409}
1410
1411/* States*/
1412#define VIRGIN	0
1413#define GOTONE	1
1414#define GOTTWO	2
1415/* Inputs */
1416#define	DIGIT	(4*0)
1417#define	END	(4*1)
1418#define DELIM	(4*2)
1419
1420void
1421sockaddr(addr, sa)
1422	register char *addr;
1423	register struct sockaddr *sa;
1424{
1425	register char *cp = (char *)sa;
1426	int size = sa->sa_len;
1427	char *cplim = cp + size;
1428	register int byte = 0, state = VIRGIN, new = 0 /* foil gcc */;
1429
1430	bzero(cp, size);
1431	cp++;
1432	do {
1433		if ((*addr >= '0') && (*addr <= '9')) {
1434			new = *addr - '0';
1435		} else if ((*addr >= 'a') && (*addr <= 'f')) {
1436			new = *addr - 'a' + 10;
1437		} else if ((*addr >= 'A') && (*addr <= 'F')) {
1438			new = *addr - 'A' + 10;
1439		} else if (*addr == 0)
1440			state |= END;
1441		else
1442			state |= DELIM;
1443		addr++;
1444		switch (state /* | INPUT */) {
1445		case GOTTWO | DIGIT:
1446			*cp++ = byte; /*FALLTHROUGH*/
1447		case VIRGIN | DIGIT:
1448			state = GOTONE; byte = new; continue;
1449		case GOTONE | DIGIT:
1450			state = GOTTWO; byte = new + (byte << 4); continue;
1451		default: /* | DELIM */
1452			state = VIRGIN; *cp++ = byte; byte = 0; continue;
1453		case GOTONE | END:
1454		case GOTTWO | END:
1455			*cp++ = byte; /* FALLTHROUGH */
1456		case VIRGIN | END:
1457			break;
1458		}
1459		break;
1460	} while (cp < cplim);
1461	sa->sa_len = cp - (char *)sa;
1462}
1463
1464int
1465atalk_aton(const char *text, struct at_addr *addr)
1466{
1467	u_int net, node;
1468
1469	if (sscanf(text, "%u.%u", &net, &node) != 2
1470	    || net > 0xffff || node > 0xff)
1471		return(0);
1472	addr->s_net = htons(net);
1473	addr->s_node = node;
1474	return(1);
1475}
1476
1477char *
1478atalk_ntoa(struct at_addr at)
1479{
1480	static char buf[20];
1481
1482	(void) snprintf(buf, sizeof(buf), "%u.%u", ntohs(at.s_net), at.s_node);
1483	return(buf);
1484}
1485