route.c revision 17265
11558Srgrimes/*
21558Srgrimes *
31558Srgrimes * Copyright (c) 1983, 1989, 1991, 1993
41558Srgrimes *	The Regents of the University of California.  All rights reserved.
51558Srgrimes *
61558Srgrimes * Redistribution and use in source and binary forms, with or without
71558Srgrimes * modification, are permitted provided that the following conditions
81558Srgrimes * are met:
91558Srgrimes * 1. Redistributions of source code must retain the above copyright
101558Srgrimes *    notice, this list of conditions and the following disclaimer.
111558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
121558Srgrimes *    notice, this list of conditions and the following disclaimer in the
131558Srgrimes *    documentation and/or other materials provided with the distribution.
141558Srgrimes * 3. All advertising materials mentioning features or use of this software
151558Srgrimes *    must display the following acknowledgement:
161558Srgrimes *	This product includes software developed by the University of
171558Srgrimes *	California, Berkeley and its contributors.
181558Srgrimes * 4. Neither the name of the University nor the names of its contributors
191558Srgrimes *    may be used to endorse or promote products derived from this software
201558Srgrimes *    without specific prior written permission.
211558Srgrimes *
221558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
231558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
241558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
251558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
261558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
271558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
281558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
291558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
301558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
311558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
321558Srgrimes * SUCH DAMAGE.
331558Srgrimes */
341558Srgrimes
351558Srgrimes#ifndef lint
3613171Swollmanstatic const char copyright[] =
371558Srgrimes"@(#) Copyright (c) 1983, 1989, 1991, 1993\n\
381558Srgrimes	The Regents of the University of California.  All rights reserved.\n";
391558Srgrimes#endif /* not lint */
401558Srgrimes
411558Srgrimes#ifndef lint
4213171Swollman/*
431558Srgrimesstatic char sccsid[] = "@(#)route.c	8.3 (Berkeley) 3/19/94";
4413171Swollman*/
4513171Swollmanstatic const char rcsid[] =
4617265Sjulian	"$Id: route.c,v 1.10 1996/07/23 01:18:47 julian Exp $";
471558Srgrimes#endif /* not lint */
481558Srgrimes
491558Srgrimes#include <sys/param.h>
501558Srgrimes#include <sys/file.h>
511558Srgrimes#include <sys/socket.h>
521558Srgrimes#include <sys/ioctl.h>
531558Srgrimes#include <sys/mbuf.h>
541558Srgrimes#include <sys/sysctl.h>
551558Srgrimes
561558Srgrimes#include <net/if.h>
571558Srgrimes#include <net/route.h>
581558Srgrimes#include <net/if_dl.h>
591558Srgrimes#include <netinet/in.h>
6017046Sjulian#include <netatalk/at.h>
6114092Swollman#ifdef NS
621558Srgrimes#include <netns/ns.h>
6314092Swollman#endif
6413940Swollman#ifdef ISO
651558Srgrimes#include <netiso/iso.h>
6613940Swollman#endif
6713940Swollman#ifdef CCITT
681558Srgrimes#include <netccitt/x25.h>
6913940Swollman#endif
701558Srgrimes#include <arpa/inet.h>
711558Srgrimes#include <netdb.h>
721558Srgrimes
731558Srgrimes#include <errno.h>
741558Srgrimes#include <unistd.h>
751558Srgrimes#include <stdio.h>
761558Srgrimes#include <ctype.h>
771558Srgrimes#include <stdlib.h>
781558Srgrimes#include <string.h>
791558Srgrimes#include <paths.h>
8013171Swollman#include <err.h>
8113171Swollman#include <sysexits.h>
821558Srgrimes
831558Srgrimesstruct keytab {
841558Srgrimes	char	*kt_cp;
851558Srgrimes	int	kt_i;
861558Srgrimes} keywords[] = {
871558Srgrimes#include "keywords.h"
881558Srgrimes	{0, 0}
891558Srgrimes};
901558Srgrimes
911558Srgrimesstruct	ortentry route;
921558Srgrimesunion	sockunion {
931558Srgrimes	struct	sockaddr sa;
941558Srgrimes	struct	sockaddr_in sin;
9517046Sjulian	struct	sockaddr_at sat;
9614092Swollman#ifdef NS
971558Srgrimes	struct	sockaddr_ns sns;
9814092Swollman#endif
9913940Swollman#ifdef ISO
1001558Srgrimes	struct	sockaddr_iso siso;
10113940Swollman#endif
1021558Srgrimes	struct	sockaddr_dl sdl;
10313940Swollman#ifdef CCITT
1041558Srgrimes	struct	sockaddr_x25 sx25;
10513940Swollman#endif
1061558Srgrimes} so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
1071558Srgrimes
1081558Srgrimestypedef union sockunion *sup;
1091558Srgrimesint	pid, rtm_addrs, uid;
1101558Srgrimesint	s;
1111558Srgrimesint	forcehost, forcenet, doflush, nflag, af, qflag, tflag, keyword();
1121558Srgrimesint	iflag, verbose, aflen = sizeof (struct sockaddr_in);
1131558Srgrimesint	locking, lockrest, debugonly;
1141558Srgrimesstruct	rt_metrics rt_metrics;
1151558Srgrimesu_long  rtm_inits;
1161558Srgrimesstruct	in_addr inet_makeaddr();
11717046Sjulianint	atalk_aton __P((const char *, struct at_addr *));
11817046Sjulianchar	*atalk_ntoa __P((struct at_addr));
1191558Srgrimeschar	*routename(), *netname();
1201558Srgrimesvoid	flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf();
1211558Srgrimesvoid	print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr();
1221558Srgrimesint	getaddr(), rtmsg(), x25_makemask();
1231558Srgrimesextern	char *inet_ntoa(), *iso_ntoa(), *link_ntoa();
12413940Swollman#ifdef CCITT
12513171Swollmanextern	int ccitt_addr __P((char *, struct sockaddr_x25 *));
12613940Swollman#endif
1271558Srgrimes
12813171Swollman__dead	void usage __P((const char *)) __dead2;
12913171Swollman
1301558Srgrimes__dead void
1311558Srgrimesusage(cp)
13213171Swollman	const char *cp;
1331558Srgrimes{
1341558Srgrimes	if (cp)
13513171Swollman		warnx("bad keyword: %s", cp);
1361558Srgrimes	(void) fprintf(stderr,
1371558Srgrimes	    "usage: route [ -nqv ] cmd [[ -<qualifers> ] args ]\n");
13813171Swollman	exit(EX_USAGE);
1391558Srgrimes	/* NOTREACHED */
1401558Srgrimes}
1411558Srgrimes
1421558Srgrimes#define ROUNDUP(a) \
1431558Srgrimes	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
1441558Srgrimes#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
1451558Srgrimes
1461558Srgrimesint
1471558Srgrimesmain(argc, argv)
1481558Srgrimes	int argc;
1491558Srgrimes	char **argv;
1501558Srgrimes{
1511558Srgrimes	extern int optind;
1521558Srgrimes	int ch;
1531558Srgrimes
1541558Srgrimes	if (argc < 2)
1551558Srgrimes		usage((char *)NULL);
1561558Srgrimes
1571558Srgrimes	while ((ch = getopt(argc, argv, "nqdtv")) != EOF)
1581558Srgrimes		switch(ch) {
1591558Srgrimes		case 'n':
1601558Srgrimes			nflag = 1;
1611558Srgrimes			break;
1621558Srgrimes		case 'q':
1631558Srgrimes			qflag = 1;
1641558Srgrimes			break;
1651558Srgrimes		case 'v':
1661558Srgrimes			verbose = 1;
1671558Srgrimes			break;
1681558Srgrimes		case 't':
1691558Srgrimes			tflag = 1;
1701558Srgrimes			break;
1711558Srgrimes		case 'd':
1721558Srgrimes			debugonly = 1;
1731558Srgrimes			break;
1741558Srgrimes		case '?':
1751558Srgrimes		default:
1761558Srgrimes			usage((char *)NULL);
1771558Srgrimes		}
1781558Srgrimes	argc -= optind;
1791558Srgrimes	argv += optind;
1801558Srgrimes
1811558Srgrimes	pid = getpid();
1821558Srgrimes	uid = getuid();
1831558Srgrimes	if (tflag)
1841558Srgrimes		s = open("/dev/null", O_WRONLY, 0);
1851558Srgrimes	else
1861558Srgrimes		s = socket(PF_ROUTE, SOCK_RAW, 0);
1871558Srgrimes	if (s < 0)
18813171Swollman		err(EX_OSERR, "socket");
1891558Srgrimes	if (*argv)
1901558Srgrimes		switch (keyword(*argv)) {
1911558Srgrimes		case K_GET:
1921558Srgrimes			uid = 0;
1931558Srgrimes			/* FALLTHROUGH */
1941558Srgrimes
1951558Srgrimes		case K_CHANGE:
1961558Srgrimes		case K_ADD:
1971558Srgrimes		case K_DELETE:
1981558Srgrimes			newroute(argc, argv);
1991558Srgrimes			exit(0);
2001558Srgrimes			/* NOTREACHED */
2011558Srgrimes
2021558Srgrimes		case K_MONITOR:
2031558Srgrimes			monitor();
2041558Srgrimes			/* NOTREACHED */
2051558Srgrimes
2061558Srgrimes		case K_FLUSH:
2071558Srgrimes			flushroutes(argc, argv);
2081558Srgrimes			exit(0);
2091558Srgrimes			/* NOTREACHED */
2101558Srgrimes		}
2111558Srgrimes	usage(*argv);
2121558Srgrimes	/* NOTREACHED */
2131558Srgrimes}
2141558Srgrimes
2151558Srgrimes/*
2161558Srgrimes * Purge all entries in the routing tables not
2171558Srgrimes * associated with network interfaces.
2181558Srgrimes */
2191558Srgrimesvoid
2201558Srgrimesflushroutes(argc, argv)
2211558Srgrimes	int argc;
2221558Srgrimes	char *argv[];
2231558Srgrimes{
2241558Srgrimes	size_t needed;
2251558Srgrimes	int mib[6], rlen, seqno;
2261558Srgrimes	char *buf, *next, *lim;
2271558Srgrimes	register struct rt_msghdr *rtm;
2281558Srgrimes
2291558Srgrimes	if (uid) {
23013171Swollman		errx(EX_NOPERM, "must be root to alter routing table");
2311558Srgrimes	}
2321558Srgrimes	shutdown(s, 0); /* Don't want to read back our messages */
2331558Srgrimes	if (argc > 1) {
2341558Srgrimes		argv++;
2351558Srgrimes		if (argc == 2 && **argv == '-')
2361558Srgrimes		    switch (keyword(*argv + 1)) {
2371558Srgrimes			case K_INET:
2381558Srgrimes				af = AF_INET;
2391558Srgrimes				break;
24017046Sjulian			case K_ATALK:
24117046Sjulian				af = AF_APPLETALK;
24217046Sjulian				break;
24314092Swollman#ifdef NS
2441558Srgrimes			case K_XNS:
2451558Srgrimes				af = AF_NS;
2461558Srgrimes				break;
24714092Swollman#endif
2481558Srgrimes			case K_LINK:
2491558Srgrimes				af = AF_LINK;
2501558Srgrimes				break;
25113940Swollman#ifdef ISO
2521558Srgrimes			case K_ISO:
2531558Srgrimes			case K_OSI:
2541558Srgrimes				af = AF_ISO;
2551558Srgrimes				break;
25613940Swollman#endif
25713940Swollman#ifdef CCITT
2581558Srgrimes			case K_X25:
2591558Srgrimes				af = AF_CCITT;
26013940Swollman#endif
2611558Srgrimes			default:
2621558Srgrimes				goto bad;
2631558Srgrimes		} else
2641558Srgrimesbad:			usage(*argv);
2651558Srgrimes	}
2661558Srgrimes	mib[0] = CTL_NET;
2671558Srgrimes	mib[1] = PF_ROUTE;
2681558Srgrimes	mib[2] = 0;		/* protocol */
2691558Srgrimes	mib[3] = 0;		/* wildcard address family */
2701558Srgrimes	mib[4] = NET_RT_DUMP;
2711558Srgrimes	mib[5] = 0;		/* no flags */
2721558Srgrimes	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
27313171Swollman		err(EX_OSERR, "route-sysctl-estimate");
2741558Srgrimes	if ((buf = malloc(needed)) == NULL)
27513171Swollman		err(EX_OSERR, "malloc");
2761558Srgrimes	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
27713171Swollman		err(EX_OSERR, "route-sysctl-get");
2781558Srgrimes	lim = buf + needed;
2791558Srgrimes	if (verbose)
2801558Srgrimes		(void) printf("Examining routing table from sysctl\n");
2811558Srgrimes	seqno = 0;		/* ??? */
2821558Srgrimes	for (next = buf; next < lim; next += rtm->rtm_msglen) {
2831558Srgrimes		rtm = (struct rt_msghdr *)next;
2841558Srgrimes		if (verbose)
2851558Srgrimes			print_rtmsg(rtm, rtm->rtm_msglen);
2861558Srgrimes		if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
2871558Srgrimes			continue;
2881558Srgrimes		if (af) {
2891558Srgrimes			struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
2901558Srgrimes
2911558Srgrimes			if (sa->sa_family != af)
2921558Srgrimes				continue;
2931558Srgrimes		}
2941558Srgrimes		if (debugonly)
2951558Srgrimes			continue;
2961558Srgrimes		rtm->rtm_type = RTM_DELETE;
2971558Srgrimes		rtm->rtm_seq = seqno;
2981558Srgrimes		rlen = write(s, next, rtm->rtm_msglen);
2991558Srgrimes		if (rlen < (int)rtm->rtm_msglen) {
30013171Swollman			warn("write to routing socket");
3011558Srgrimes			(void) printf("got only %d for rlen\n", rlen);
3021558Srgrimes			break;
3031558Srgrimes		}
3041558Srgrimes		seqno++;
3051558Srgrimes		if (qflag)
3061558Srgrimes			continue;
3071558Srgrimes		if (verbose)
3081558Srgrimes			print_rtmsg(rtm, rlen);
3091558Srgrimes		else {
3101558Srgrimes			struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
3111558Srgrimes			(void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
3121558Srgrimes			    routename(sa) : netname(sa));
3131558Srgrimes			sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
3141558Srgrimes			(void) printf("%-20.20s ", routename(sa));
3151558Srgrimes			(void) printf("done\n");
3161558Srgrimes		}
3171558Srgrimes	}
3181558Srgrimes}
3191558Srgrimes
3201558Srgrimeschar *
3211558Srgrimesroutename(sa)
3221558Srgrimes	struct sockaddr *sa;
3231558Srgrimes{
3241558Srgrimes	register char *cp;
3251558Srgrimes	static char line[50];
3261558Srgrimes	struct hostent *hp;
3271558Srgrimes	static char domain[MAXHOSTNAMELEN + 1];
3281558Srgrimes	static int first = 1;
32914092Swollman#ifdef NS
3301558Srgrimes	char *ns_print();
33114092Swollman#endif
3321558Srgrimes
3331558Srgrimes	if (first) {
3341558Srgrimes		first = 0;
3351558Srgrimes		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
3361558Srgrimes		    (cp = index(domain, '.')))
3371558Srgrimes			(void) strcpy(domain, cp + 1);
3381558Srgrimes		else
3391558Srgrimes			domain[0] = 0;
3401558Srgrimes	}
3411558Srgrimes
3421558Srgrimes	if (sa->sa_len == 0)
3431558Srgrimes		strcpy(line, "default");
3441558Srgrimes	else switch (sa->sa_family) {
3451558Srgrimes
3461558Srgrimes	case AF_INET:
3471558Srgrimes	    {	struct in_addr in;
3481558Srgrimes		in = ((struct sockaddr_in *)sa)->sin_addr;
3491558Srgrimes
3501558Srgrimes		cp = 0;
3511558Srgrimes		if (in.s_addr == INADDR_ANY || sa->sa_len < 4)
3521558Srgrimes			cp = "default";
3531558Srgrimes		if (cp == 0 && !nflag) {
3541558Srgrimes			hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
3551558Srgrimes				AF_INET);
3561558Srgrimes			if (hp) {
3571558Srgrimes				if ((cp = index(hp->h_name, '.')) &&
3581558Srgrimes				    !strcmp(cp + 1, domain))
3591558Srgrimes					*cp = 0;
3601558Srgrimes				cp = hp->h_name;
3611558Srgrimes			}
3621558Srgrimes		}
3631558Srgrimes		if (cp)
3641558Srgrimes			strcpy(line, cp);
3651558Srgrimes		else {
36613171Swollman			/* XXX - why not inet_ntoa()? */
36713171Swollman#define C(x)	(unsigned)((x) & 0xff)
3681558Srgrimes			in.s_addr = ntohl(in.s_addr);
3691558Srgrimes			(void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
3701558Srgrimes			   C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
3711558Srgrimes		}
3721558Srgrimes		break;
3731558Srgrimes	    }
3741558Srgrimes
37517046Sjulian	case AF_APPLETALK:
37617046Sjulian		(void) snprintf(line, sizeof(line), "atalk %s",
37717046Sjulian			atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
37817046Sjulian		break;
37917046Sjulian
38014092Swollman#ifdef NS
3811558Srgrimes	case AF_NS:
3821558Srgrimes		return (ns_print((struct sockaddr_ns *)sa));
38314092Swollman#endif
3841558Srgrimes
3851558Srgrimes	case AF_LINK:
3861558Srgrimes		return (link_ntoa((struct sockaddr_dl *)sa));
3871558Srgrimes
38813940Swollman#ifdef ISO
3891558Srgrimes	case AF_ISO:
3901558Srgrimes		(void) sprintf(line, "iso %s",
3911558Srgrimes		    iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
3921558Srgrimes		break;
39313940Swollman#endif
3941558Srgrimes	default:
3951558Srgrimes	    {	u_short *s = (u_short *)sa;
3961558Srgrimes		u_short *slim = s + ((sa->sa_len + 1) >> 1);
3971558Srgrimes		char *cp = line + sprintf(line, "(%d)", sa->sa_family);
3981558Srgrimes
3991558Srgrimes		while (++s < slim) /* start with sa->sa_data */
4001558Srgrimes			cp += sprintf(cp, " %x", *s);
4011558Srgrimes		break;
4021558Srgrimes	    }
4031558Srgrimes	}
4041558Srgrimes	return (line);
4051558Srgrimes}
4061558Srgrimes
4071558Srgrimes/*
4081558Srgrimes * Return the name of the network whose address is given.
4091558Srgrimes * The address is assumed to be that of a net or subnet, not a host.
4101558Srgrimes */
4111558Srgrimeschar *
4121558Srgrimesnetname(sa)
4131558Srgrimes	struct sockaddr *sa;
4141558Srgrimes{
4151558Srgrimes	char *cp = 0;
4161558Srgrimes	static char line[50];
4171558Srgrimes	struct netent *np = 0;
4181558Srgrimes	u_long net, mask;
4191558Srgrimes	register u_long i;
4201558Srgrimes	int subnetshift;
42114092Swollman#ifdef NS
4221558Srgrimes	char *ns_print();
42314092Swollman#endif
4241558Srgrimes
4251558Srgrimes	switch (sa->sa_family) {
4261558Srgrimes
4271558Srgrimes	case AF_INET:
4281558Srgrimes	    {	struct in_addr in;
4291558Srgrimes		in = ((struct sockaddr_in *)sa)->sin_addr;
4301558Srgrimes
4311558Srgrimes		i = in.s_addr = ntohl(in.s_addr);
4321558Srgrimes		if (in.s_addr == 0)
4331558Srgrimes			cp = "default";
4341558Srgrimes		else if (!nflag) {
4351558Srgrimes			if (IN_CLASSA(i)) {
4361558Srgrimes				mask = IN_CLASSA_NET;
4371558Srgrimes				subnetshift = 8;
4381558Srgrimes			} else if (IN_CLASSB(i)) {
4391558Srgrimes				mask = IN_CLASSB_NET;
4401558Srgrimes				subnetshift = 8;
4411558Srgrimes			} else {
4421558Srgrimes				mask = IN_CLASSC_NET;
4431558Srgrimes				subnetshift = 4;
4441558Srgrimes			}
4451558Srgrimes			/*
4461558Srgrimes			 * If there are more bits than the standard mask
4471558Srgrimes			 * would suggest, subnets must be in use.
4481558Srgrimes			 * Guess at the subnet mask, assuming reasonable
4491558Srgrimes			 * width subnet fields.
4501558Srgrimes			 */
4511558Srgrimes			while (in.s_addr &~ mask)
4521558Srgrimes				mask = (long)mask >> subnetshift;
4531558Srgrimes			net = in.s_addr & mask;
4541558Srgrimes			while ((mask & 1) == 0)
4551558Srgrimes				mask >>= 1, net >>= 1;
4561558Srgrimes			np = getnetbyaddr(net, AF_INET);
4571558Srgrimes			if (np)
4581558Srgrimes				cp = np->n_name;
4591558Srgrimes		}
4601558Srgrimes		if (cp)
4611558Srgrimes			strcpy(line, cp);
4621558Srgrimes		else if ((in.s_addr & 0xffffff) == 0)
4631558Srgrimes			(void) sprintf(line, "%u", C(in.s_addr >> 24));
4641558Srgrimes		else if ((in.s_addr & 0xffff) == 0)
4651558Srgrimes			(void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
4661558Srgrimes			    C(in.s_addr >> 16));
4671558Srgrimes		else if ((in.s_addr & 0xff) == 0)
4681558Srgrimes			(void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
4691558Srgrimes			    C(in.s_addr >> 16), C(in.s_addr >> 8));
4701558Srgrimes		else
4711558Srgrimes			(void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
4721558Srgrimes			    C(in.s_addr >> 16), C(in.s_addr >> 8),
4731558Srgrimes			    C(in.s_addr));
4741558Srgrimes		break;
4751558Srgrimes	    }
4761558Srgrimes
47717046Sjulian	case AF_APPLETALK:
47817046Sjulian		(void) snprintf(line, sizeof(line), "atalk %s",
47917046Sjulian			atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
48017046Sjulian		break;
48117046Sjulian
48214092Swollman#ifdef NS
4831558Srgrimes	case AF_NS:
4841558Srgrimes		return (ns_print((struct sockaddr_ns *)sa));
4851558Srgrimes		break;
48614092Swollman#endif
4871558Srgrimes
4881558Srgrimes	case AF_LINK:
4891558Srgrimes		return (link_ntoa((struct sockaddr_dl *)sa));
4901558Srgrimes
49113940Swollman#ifdef ISO
4921558Srgrimes	case AF_ISO:
4931558Srgrimes		(void) sprintf(line, "iso %s",
4941558Srgrimes		    iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
4951558Srgrimes		break;
49613940Swollman#endif
4971558Srgrimes
4981558Srgrimes	default:
4991558Srgrimes	    {	u_short *s = (u_short *)sa->sa_data;
5001558Srgrimes		u_short *slim = s + ((sa->sa_len + 1)>>1);
5011558Srgrimes		char *cp = line + sprintf(line, "af %d:", sa->sa_family);
5021558Srgrimes
5031558Srgrimes		while (s < slim)
5041558Srgrimes			cp += sprintf(cp, " %x", *s++);
5051558Srgrimes		break;
5061558Srgrimes	    }
5071558Srgrimes	}
5081558Srgrimes	return (line);
5091558Srgrimes}
5101558Srgrimes
5111558Srgrimesvoid
5121558Srgrimesset_metric(value, key)
5131558Srgrimes	char *value;
5141558Srgrimes	int key;
5151558Srgrimes{
5161558Srgrimes	int flag = 0;
5171558Srgrimes	u_long noval, *valp = &noval;
5181558Srgrimes
5191558Srgrimes	switch (key) {
5201558Srgrimes#define caseof(x, y, z)	case x: valp = &rt_metrics.z; flag = y; break
5211558Srgrimes	caseof(K_MTU, RTV_MTU, rmx_mtu);
5221558Srgrimes	caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
5231558Srgrimes	caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
5241558Srgrimes	caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
5251558Srgrimes	caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
5261558Srgrimes	caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
5271558Srgrimes	caseof(K_RTT, RTV_RTT, rmx_rtt);
5281558Srgrimes	caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
5291558Srgrimes	}
5301558Srgrimes	rtm_inits |= flag;
5311558Srgrimes	if (lockrest || locking)
5321558Srgrimes		rt_metrics.rmx_locks |= flag;
5331558Srgrimes	if (locking)
5341558Srgrimes		locking = 0;
5351558Srgrimes	*valp = atoi(value);
5361558Srgrimes}
5371558Srgrimes
5381558Srgrimesvoid
5391558Srgrimesnewroute(argc, argv)
5401558Srgrimes	int argc;
5411558Srgrimes	register char **argv;
5421558Srgrimes{
5431558Srgrimes	char *cmd, *dest = "", *gateway = "", *err;
5441558Srgrimes	int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC;
5451558Srgrimes	int key;
5461558Srgrimes	struct hostent *hp = 0;
5471558Srgrimes
5481558Srgrimes	if (uid) {
54913171Swollman		errx(EX_NOPERM, "must be root to alter routing table");
5501558Srgrimes	}
5511558Srgrimes	cmd = argv[0];
5521558Srgrimes	if (*cmd != 'g')
5531558Srgrimes		shutdown(s, 0); /* Don't want to read back our messages */
5541558Srgrimes	while (--argc > 0) {
5551558Srgrimes		if (**(++argv)== '-') {
5561558Srgrimes			switch (key = keyword(1 + *argv)) {
5571558Srgrimes			case K_LINK:
5581558Srgrimes				af = AF_LINK;
5591558Srgrimes				aflen = sizeof(struct sockaddr_dl);
5601558Srgrimes				break;
56113940Swollman#ifdef ISO
5621558Srgrimes			case K_OSI:
5631558Srgrimes			case K_ISO:
5641558Srgrimes				af = AF_ISO;
5651558Srgrimes				aflen = sizeof(struct sockaddr_iso);
5661558Srgrimes				break;
56713940Swollman#endif
5681558Srgrimes			case K_INET:
5691558Srgrimes				af = AF_INET;
5701558Srgrimes				aflen = sizeof(struct sockaddr_in);
5711558Srgrimes				break;
57217046Sjulian			case K_ATALK:
57317046Sjulian				af = AF_APPLETALK;
57417046Sjulian				aflen = sizeof(struct sockaddr_at);
57517046Sjulian				break;
57613940Swollman#ifdef CCITT
5771558Srgrimes			case K_X25:
5781558Srgrimes				af = AF_CCITT;
5791558Srgrimes				aflen = sizeof(struct sockaddr_x25);
5801558Srgrimes				break;
58113940Swollman#endif
5821558Srgrimes			case K_SA:
5831558Srgrimes				af = PF_ROUTE;
5841558Srgrimes				aflen = sizeof(union sockunion);
5851558Srgrimes				break;
58614092Swollman#ifdef NS
5871558Srgrimes			case K_XNS:
5881558Srgrimes				af = AF_NS;
5891558Srgrimes				aflen = sizeof(struct sockaddr_ns);
5901558Srgrimes				break;
59114092Swollman#endif
5921558Srgrimes			case K_IFACE:
5931558Srgrimes			case K_INTERFACE:
5941558Srgrimes				iflag++;
5952787Spst				break;
5961558Srgrimes			case K_NOSTATIC:
5971558Srgrimes				flags &= ~RTF_STATIC;
5981558Srgrimes				break;
5991558Srgrimes			case K_LOCK:
6001558Srgrimes				locking = 1;
6011558Srgrimes				break;
6021558Srgrimes			case K_LOCKREST:
6031558Srgrimes				lockrest = 1;
6041558Srgrimes				break;
6051558Srgrimes			case K_HOST:
6061558Srgrimes				forcehost++;
6071558Srgrimes				break;
6081558Srgrimes			case K_REJECT:
6091558Srgrimes				flags |= RTF_REJECT;
6101558Srgrimes				break;
6111558Srgrimes			case K_BLACKHOLE:
6121558Srgrimes				flags |= RTF_BLACKHOLE;
6131558Srgrimes				break;
6141558Srgrimes			case K_PROTO1:
6151558Srgrimes				flags |= RTF_PROTO1;
6161558Srgrimes				break;
6171558Srgrimes			case K_PROTO2:
6181558Srgrimes				flags |= RTF_PROTO2;
6191558Srgrimes				break;
6201558Srgrimes			case K_CLONING:
6211558Srgrimes				flags |= RTF_CLONING;
6221558Srgrimes				break;
6231558Srgrimes			case K_XRESOLVE:
6241558Srgrimes				flags |= RTF_XRESOLVE;
6251558Srgrimes				break;
6261558Srgrimes			case K_STATIC:
6271558Srgrimes				flags |= RTF_STATIC;
6281558Srgrimes				break;
6291558Srgrimes			case K_IFA:
6301558Srgrimes				argc--;
6311558Srgrimes				(void) getaddr(RTA_IFA, *++argv, 0);
6321558Srgrimes				break;
6331558Srgrimes			case K_IFP:
6341558Srgrimes				argc--;
6351558Srgrimes				(void) getaddr(RTA_IFP, *++argv, 0);
6361558Srgrimes				break;
6371558Srgrimes			case K_GENMASK:
6381558Srgrimes				argc--;
6391558Srgrimes				(void) getaddr(RTA_GENMASK, *++argv, 0);
6401558Srgrimes				break;
6411558Srgrimes			case K_GATEWAY:
6421558Srgrimes				argc--;
6431558Srgrimes				(void) getaddr(RTA_GATEWAY, *++argv, 0);
6441558Srgrimes				break;
6451558Srgrimes			case K_DST:
6461558Srgrimes				argc--;
6471558Srgrimes				ishost = getaddr(RTA_DST, *++argv, &hp);
6481558Srgrimes				dest = *argv;
6491558Srgrimes				break;
6501558Srgrimes			case K_NETMASK:
6511558Srgrimes				argc--;
6521558Srgrimes				(void) getaddr(RTA_NETMASK, *++argv, 0);
6531558Srgrimes				/* FALLTHROUGH */
6541558Srgrimes			case K_NET:
6551558Srgrimes				forcenet++;
6561558Srgrimes				break;
6571558Srgrimes			case K_MTU:
6581558Srgrimes			case K_HOPCOUNT:
6591558Srgrimes			case K_EXPIRE:
6601558Srgrimes			case K_RECVPIPE:
6611558Srgrimes			case K_SENDPIPE:
6621558Srgrimes			case K_SSTHRESH:
6631558Srgrimes			case K_RTT:
6641558Srgrimes			case K_RTTVAR:
6651558Srgrimes				argc--;
6661558Srgrimes				set_metric(*++argv, key);
6671558Srgrimes				break;
6681558Srgrimes			default:
6691558Srgrimes				usage(1+*argv);
6701558Srgrimes			}
6711558Srgrimes		} else {
6721558Srgrimes			if ((rtm_addrs & RTA_DST) == 0) {
6731558Srgrimes				dest = *argv;
6741558Srgrimes				ishost = getaddr(RTA_DST, *argv, &hp);
6751558Srgrimes			} else if ((rtm_addrs & RTA_GATEWAY) == 0) {
6761558Srgrimes				gateway = *argv;
6771558Srgrimes				(void) getaddr(RTA_GATEWAY, *argv, &hp);
6781558Srgrimes			} else {
67913171Swollman#ifdef CRUFT
6801558Srgrimes				int ret = atoi(*argv);
6811558Srgrimes
6821558Srgrimes				if (ret == 0) {
6831558Srgrimes				    if (strcmp(*argv, "0") == 0)
6841558Srgrimes				        printf("%s,%s",
6851558Srgrimes					    "old usage of trailing 0",
6861558Srgrimes					    "assuming route to if\n");
6871558Srgrimes				    else
6881558Srgrimes					usage((char *)NULL);
6891558Srgrimes				    iflag = 1;
6901558Srgrimes				    continue;
6911558Srgrimes				} else if (ret > 0 && ret < 10) {
6921558Srgrimes				    printf("old usage of trailing digit, ");
6931558Srgrimes				    printf("assuming route via gateway\n");
6941558Srgrimes				    iflag = 0;
6951558Srgrimes				    continue;
6961558Srgrimes				}
69713171Swollman#endif
6981558Srgrimes				(void) getaddr(RTA_NETMASK, *argv, 0);
6991558Srgrimes			}
7001558Srgrimes		}
7011558Srgrimes	}
7021558Srgrimes	if (forcehost)
7031558Srgrimes		ishost = 1;
7041558Srgrimes	if (forcenet)
7051558Srgrimes		ishost = 0;
7061558Srgrimes	flags |= RTF_UP;
7071558Srgrimes	if (ishost)
7081558Srgrimes		flags |= RTF_HOST;
7091558Srgrimes	if (iflag == 0)
7101558Srgrimes		flags |= RTF_GATEWAY;
7111558Srgrimes	for (attempts = 1; ; attempts++) {
7121558Srgrimes		errno = 0;
7131558Srgrimes		if ((ret = rtmsg(*cmd, flags)) == 0)
7141558Srgrimes			break;
7151558Srgrimes		if (errno != ENETUNREACH && errno != ESRCH)
7161558Srgrimes			break;
7171558Srgrimes		if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
7181558Srgrimes			hp->h_addr_list++;
7191558Srgrimes			bcopy(hp->h_addr_list[0], &so_gate.sin.sin_addr,
7201558Srgrimes			    hp->h_length);
7211558Srgrimes		} else
7221558Srgrimes			break;
7231558Srgrimes	}
7241558Srgrimes	if (*cmd == 'g')
7251558Srgrimes		exit(0);
7261558Srgrimes	oerrno = errno;
7271558Srgrimes	(void) printf("%s %s %s", cmd, ishost? "host" : "net", dest);
7281558Srgrimes	if (*gateway) {
7291558Srgrimes		(void) printf(": gateway %s", gateway);
7301558Srgrimes		if (attempts > 1 && ret == 0 && af == AF_INET)
7311558Srgrimes		    (void) printf(" (%s)",
7321558Srgrimes			inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
7331558Srgrimes	}
7341558Srgrimes	if (ret == 0)
7351558Srgrimes		(void) printf("\n");
7361558Srgrimes	else {
7371558Srgrimes		switch (oerrno) {
7381558Srgrimes		case ESRCH:
7391558Srgrimes			err = "not in table";
7401558Srgrimes			break;
7411558Srgrimes		case EBUSY:
7421558Srgrimes			err = "entry in use";
7431558Srgrimes			break;
7441558Srgrimes		case ENOBUFS:
7451558Srgrimes			err = "routing table overflow";
7461558Srgrimes			break;
7471558Srgrimes		default:
7481558Srgrimes			err = strerror(oerrno);
7491558Srgrimes			break;
7501558Srgrimes		}
7511558Srgrimes		(void) printf(": %s\n", err);
7521558Srgrimes	}
7531558Srgrimes}
7541558Srgrimes
7551558Srgrimesvoid
7561558Srgrimesinet_makenetandmask(net, sin)
7571558Srgrimes	u_long net;
7581558Srgrimes	register struct sockaddr_in *sin;
7591558Srgrimes{
7601558Srgrimes	u_long addr, mask = 0;
7611558Srgrimes	register char *cp;
7621558Srgrimes
7631558Srgrimes	rtm_addrs |= RTA_NETMASK;
7641558Srgrimes	if (net == 0)
7651558Srgrimes		mask = addr = 0;
7661558Srgrimes	else if (net < 128) {
7671558Srgrimes		addr = net << IN_CLASSA_NSHIFT;
7681558Srgrimes		mask = IN_CLASSA_NET;
7691558Srgrimes	} else if (net < 65536) {
7701558Srgrimes		addr = net << IN_CLASSB_NSHIFT;
7711558Srgrimes		mask = IN_CLASSB_NET;
7721558Srgrimes	} else if (net < 16777216L) {
7731558Srgrimes		addr = net << IN_CLASSC_NSHIFT;
7741558Srgrimes		mask = IN_CLASSC_NET;
7751558Srgrimes	} else {
7761558Srgrimes		addr = net;
7771558Srgrimes		if ((addr & IN_CLASSA_HOST) == 0)
7781558Srgrimes			mask =  IN_CLASSA_NET;
7791558Srgrimes		else if ((addr & IN_CLASSB_HOST) == 0)
7801558Srgrimes			mask =  IN_CLASSB_NET;
7811558Srgrimes		else if ((addr & IN_CLASSC_HOST) == 0)
7821558Srgrimes			mask =  IN_CLASSC_NET;
7831558Srgrimes		else
7841558Srgrimes			mask = -1;
7851558Srgrimes	}
7861558Srgrimes	sin->sin_addr.s_addr = htonl(addr);
7871558Srgrimes	sin = &so_mask.sin;
7881558Srgrimes	sin->sin_addr.s_addr = htonl(mask);
7891558Srgrimes	sin->sin_len = 0;
7901558Srgrimes	sin->sin_family = 0;
7911558Srgrimes	cp = (char *)(&sin->sin_addr + 1);
7921558Srgrimes	while (*--cp == 0 && cp > (char *)sin)
7931558Srgrimes		;
7941558Srgrimes	sin->sin_len = 1 + cp - (char *)sin;
7951558Srgrimes}
7961558Srgrimes
7971558Srgrimes/*
7981558Srgrimes * Interpret an argument as a network address of some kind,
7991558Srgrimes * returning 1 if a host address, 0 if a network address.
8001558Srgrimes */
8011558Srgrimesint
8021558Srgrimesgetaddr(which, s, hpp)
8031558Srgrimes	int which;
8041558Srgrimes	char *s;
8051558Srgrimes	struct hostent **hpp;
8061558Srgrimes{
8071558Srgrimes	register sup su;
80814092Swollman#ifdef NS
8091558Srgrimes	struct ns_addr ns_addr();
81014092Swollman#endif
81113940Swollman#ifdef ISO
8121558Srgrimes	struct iso_addr *iso_addr();
81313940Swollman#endif
8141558Srgrimes	struct hostent *hp;
8151558Srgrimes	struct netent *np;
8161558Srgrimes	u_long val;
8171558Srgrimes
8181558Srgrimes	if (af == 0) {
8191558Srgrimes		af = AF_INET;
8201558Srgrimes		aflen = sizeof(struct sockaddr_in);
8211558Srgrimes	}
8221558Srgrimes	rtm_addrs |= which;
8231558Srgrimes	switch (which) {
8241558Srgrimes	case RTA_DST:
8251558Srgrimes		su = &so_dst;
8261558Srgrimes		su->sa.sa_family = af;
8271558Srgrimes		break;
8281558Srgrimes	case RTA_GATEWAY:
8291558Srgrimes		su = &so_gate;
8301558Srgrimes		su->sa.sa_family = af;
8311558Srgrimes		break;
8321558Srgrimes	case RTA_NETMASK:
8331558Srgrimes		su = &so_mask;
8341558Srgrimes		break;
8351558Srgrimes	case RTA_GENMASK:
8361558Srgrimes		su = &so_genmask;
8371558Srgrimes		break;
8381558Srgrimes	case RTA_IFP:
8391558Srgrimes		su = &so_ifp;
8401558Srgrimes		su->sa.sa_family = af;
8411558Srgrimes		break;
8421558Srgrimes	case RTA_IFA:
8431558Srgrimes		su = &so_ifa;
8441558Srgrimes		su->sa.sa_family = af;
8451558Srgrimes		break;
8461558Srgrimes	default:
8471558Srgrimes		usage("Internal Error");
8481558Srgrimes		/*NOTREACHED*/
8491558Srgrimes	}
8501558Srgrimes	su->sa.sa_len = aflen;
8511558Srgrimes	if (strcmp(s, "default") == 0) {
8521558Srgrimes		switch (which) {
8531558Srgrimes		case RTA_DST:
8541558Srgrimes			forcenet++;
8551558Srgrimes			(void) getaddr(RTA_NETMASK, s, 0);
8561558Srgrimes			break;
8571558Srgrimes		case RTA_NETMASK:
8581558Srgrimes		case RTA_GENMASK:
8591558Srgrimes			su->sa.sa_len = 0;
8601558Srgrimes		}
8611558Srgrimes		return (0);
8621558Srgrimes	}
8631558Srgrimes	switch (af) {
86414092Swollman#ifdef NS
8651558Srgrimes	case AF_NS:
8661558Srgrimes		if (which == RTA_DST) {
8671558Srgrimes			extern short ns_bh[3];
8681558Srgrimes			struct sockaddr_ns *sms = &(so_mask.sns);
8691558Srgrimes			bzero((char *)sms, sizeof(*sms));
8701558Srgrimes			sms->sns_family = 0;
8711558Srgrimes			sms->sns_len = 6;
8721558Srgrimes			sms->sns_addr.x_net = *(union ns_net *)ns_bh;
8731558Srgrimes			rtm_addrs |= RTA_NETMASK;
8741558Srgrimes		}
8751558Srgrimes		su->sns.sns_addr = ns_addr(s);
8761558Srgrimes		return (!ns_nullhost(su->sns.sns_addr));
87714092Swollman#endif
8781558Srgrimes
87913940Swollman#ifdef ISO
8801558Srgrimes	case AF_OSI:
8811558Srgrimes		su->siso.siso_addr = *iso_addr(s);
8821558Srgrimes		if (which == RTA_NETMASK || which == RTA_GENMASK) {
8831558Srgrimes			register char *cp = (char *)TSEL(&su->siso);
8841558Srgrimes			su->siso.siso_nlen = 0;
8851558Srgrimes			do {--cp ;} while ((cp > (char *)su) && (*cp == 0));
8861558Srgrimes			su->siso.siso_len = 1 + cp - (char *)su;
8871558Srgrimes		}
8881558Srgrimes		return (1);
88913940Swollman#endif
8901558Srgrimes
89117046Sjulian	case AF_APPLETALK:
89217046Sjulian		if (!atalk_aton(s, &su->sat.sat_addr))
89317046Sjulian			errx(EX_NOHOST, "bad address: %s", s);
89417265Sjulian		rtm_addrs |= RTA_NETMASK;
89517265Sjulian		return(forcehost || su->sat.sat_addr.s_node != 0);
89617046Sjulian
8971558Srgrimes	case AF_LINK:
8981558Srgrimes		link_addr(s, &su->sdl);
8991558Srgrimes		return (1);
9001558Srgrimes
90113940Swollman#ifdef ISO
9021558Srgrimes	case AF_CCITT:
9031558Srgrimes		ccitt_addr(s, &su->sx25);
9041558Srgrimes		return (which == RTA_DST ? x25_makemask() : 1);
90513940Swollman#endif
9061558Srgrimes
9071558Srgrimes	case PF_ROUTE:
9081558Srgrimes		su->sa.sa_len = sizeof(*su);
9091558Srgrimes		sockaddr(s, &su->sa);
9101558Srgrimes		return (1);
9111558Srgrimes
9121558Srgrimes	case AF_INET:
9131558Srgrimes	default:
9141558Srgrimes		break;
9151558Srgrimes	}
9161558Srgrimes
9171558Srgrimes	if (hpp == NULL)
9181558Srgrimes		hpp = &hp;
9191558Srgrimes	*hpp = NULL;
92014132Smpp	if (((val = inet_addr(s)) != INADDR_NONE) &&
9211558Srgrimes	    (which != RTA_DST || forcenet == 0)) {
9221558Srgrimes		su->sin.sin_addr.s_addr = val;
9231558Srgrimes		if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
9241558Srgrimes			return (1);
9251558Srgrimes		else {
9261558Srgrimes			val = ntohl(val);
9271558Srgrimes			goto netdone;
9281558Srgrimes		}
9291558Srgrimes	}
93014132Smpp	if ((val = inet_network(s)) != INADDR_NONE ||
9311558Srgrimes	    ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0)) {
9321558Srgrimesnetdone:
9331558Srgrimes		if (which == RTA_DST)
9341558Srgrimes			inet_makenetandmask(val, &su->sin);
9351558Srgrimes		return (0);
9361558Srgrimes	}
9371558Srgrimes	hp = gethostbyname(s);
9381558Srgrimes	if (hp) {
9391558Srgrimes		*hpp = hp;
9401558Srgrimes		su->sin.sin_family = hp->h_addrtype;
9411558Srgrimes		bcopy(hp->h_addr, (char *)&su->sin.sin_addr, hp->h_length);
9421558Srgrimes		return (1);
9431558Srgrimes	}
94413515Smpp	errx(EX_NOHOST, "bad address: %s", s);
9451558Srgrimes}
9461558Srgrimes
94713940Swollman#ifdef CCITT
9481558Srgrimesint
9491558Srgrimesx25_makemask()
9501558Srgrimes{
9511558Srgrimes	register char *cp;
9521558Srgrimes
9531558Srgrimes	if ((rtm_addrs & RTA_NETMASK) == 0) {
9541558Srgrimes		rtm_addrs |= RTA_NETMASK;
9551558Srgrimes		for (cp = (char *)&so_mask.sx25.x25_net;
9561558Srgrimes		     cp < &so_mask.sx25.x25_opts.op_flags; cp++)
9571558Srgrimes			*cp = -1;
9581558Srgrimes		so_mask.sx25.x25_len = (u_char)&(((sup)0)->sx25.x25_opts);
9591558Srgrimes	}
9601558Srgrimes	return 0;
9611558Srgrimes}
96213940Swollman#endif
9631558Srgrimes
96414092Swollman#ifdef NS
9651558Srgrimesshort ns_nullh[] = {0,0,0};
9661558Srgrimesshort ns_bh[] = {-1,-1,-1};
9671558Srgrimes
9681558Srgrimeschar *
9691558Srgrimesns_print(sns)
9701558Srgrimes	struct sockaddr_ns *sns;
9711558Srgrimes{
9721558Srgrimes	struct ns_addr work;
9731558Srgrimes	union { union ns_net net_e; u_long long_e; } net;
9741558Srgrimes	u_short port;
9751558Srgrimes	static char mybuf[50], cport[10], chost[25];
9761558Srgrimes	char *host = "";
9771558Srgrimes	register char *p;
9781558Srgrimes	register u_char *q;
9791558Srgrimes
9801558Srgrimes	work = sns->sns_addr;
9811558Srgrimes	port = ntohs(work.x_port);
9821558Srgrimes	work.x_port = 0;
9831558Srgrimes	net.net_e  = work.x_net;
9841558Srgrimes	if (ns_nullhost(work) && net.long_e == 0) {
9851558Srgrimes		if (!port)
9861558Srgrimes			return ("*.*");
9871558Srgrimes		(void) sprintf(mybuf, "*.%XH", port);
9881558Srgrimes		return (mybuf);
9891558Srgrimes	}
9901558Srgrimes
9911558Srgrimes	if (bcmp((char *)ns_bh, (char *)work.x_host.c_host, 6) == 0)
9921558Srgrimes		host = "any";
9931558Srgrimes	else if (bcmp((char *)ns_nullh, (char *)work.x_host.c_host, 6) == 0)
9941558Srgrimes		host = "*";
9951558Srgrimes	else {
9961558Srgrimes		q = work.x_host.c_host;
9971558Srgrimes		(void) sprintf(chost, "%02X%02X%02X%02X%02X%02XH",
9981558Srgrimes			q[0], q[1], q[2], q[3], q[4], q[5]);
9991558Srgrimes		for (p = chost; *p == '0' && p < chost + 12; p++)
10001558Srgrimes			/* void */;
10011558Srgrimes		host = p;
10021558Srgrimes	}
10031558Srgrimes	if (port)
10041558Srgrimes		(void) sprintf(cport, ".%XH", htons(port));
10051558Srgrimes	else
10061558Srgrimes		*cport = 0;
10071558Srgrimes
100813171Swollman	(void) sprintf(mybuf,"%lxH.%s%s", (unsigned long)ntohl(net.long_e),
100913171Swollman		       host, cport);
10101558Srgrimes	return (mybuf);
10111558Srgrimes}
101214092Swollman#endif
10131558Srgrimes
10141558Srgrimesvoid
10151558Srgrimesinterfaces()
10161558Srgrimes{
10171558Srgrimes	size_t needed;
10181558Srgrimes	int mib[6];
10191558Srgrimes	char *buf, *lim, *next;
10201558Srgrimes	register struct rt_msghdr *rtm;
10211558Srgrimes
10221558Srgrimes	mib[0] = CTL_NET;
10231558Srgrimes	mib[1] = PF_ROUTE;
10241558Srgrimes	mib[2] = 0;		/* protocol */
10251558Srgrimes	mib[3] = 0;		/* wildcard address family */
10261558Srgrimes	mib[4] = NET_RT_IFLIST;
10271558Srgrimes	mib[5] = 0;		/* no flags */
10281558Srgrimes	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
102913171Swollman		err(EX_OSERR, "route-sysctl-estimate");
10301558Srgrimes	if ((buf = malloc(needed)) == NULL)
103113171Swollman		err(EX_OSERR, "malloc");
10321558Srgrimes	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
103313171Swollman		err(EX_OSERR, "actual retrieval of interface table");
10341558Srgrimes	lim = buf + needed;
10351558Srgrimes	for (next = buf; next < lim; next += rtm->rtm_msglen) {
10361558Srgrimes		rtm = (struct rt_msghdr *)next;
10371558Srgrimes		print_rtmsg(rtm, rtm->rtm_msglen);
10381558Srgrimes	}
10391558Srgrimes}
10401558Srgrimes
10411558Srgrimesvoid
10421558Srgrimesmonitor()
10431558Srgrimes{
10441558Srgrimes	int n;
10451558Srgrimes	char msg[2048];
10461558Srgrimes
10471558Srgrimes	verbose = 1;
10481558Srgrimes	if (debugonly) {
10491558Srgrimes		interfaces();
10501558Srgrimes		exit(0);
10511558Srgrimes	}
10521558Srgrimes	for(;;) {
10531558Srgrimes		n = read(s, msg, 2048);
10541558Srgrimes		(void) printf("got message of size %d\n", n);
10551558Srgrimes		print_rtmsg((struct rt_msghdr *)msg, n);
10561558Srgrimes	}
10571558Srgrimes}
10581558Srgrimes
10591558Srgrimesstruct {
10601558Srgrimes	struct	rt_msghdr m_rtm;
10611558Srgrimes	char	m_space[512];
10621558Srgrimes} m_rtmsg;
10631558Srgrimes
10641558Srgrimesint
10651558Srgrimesrtmsg(cmd, flags)
10661558Srgrimes	int cmd, flags;
10671558Srgrimes{
10681558Srgrimes	static int seq;
10691558Srgrimes	int rlen;
10701558Srgrimes	register char *cp = m_rtmsg.m_space;
10711558Srgrimes	register int l;
10721558Srgrimes
10731558Srgrimes#define NEXTADDR(w, u) \
10741558Srgrimes	if (rtm_addrs & (w)) {\
10751558Srgrimes	    l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\
10761558Srgrimes	    if (verbose) sodump(&(u),"u");\
10771558Srgrimes	}
10781558Srgrimes
10791558Srgrimes	errno = 0;
10801558Srgrimes	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
10811558Srgrimes	if (cmd == 'a')
10821558Srgrimes		cmd = RTM_ADD;
10831558Srgrimes	else if (cmd == 'c')
10841558Srgrimes		cmd = RTM_CHANGE;
10851558Srgrimes	else if (cmd == 'g') {
10861558Srgrimes		cmd = RTM_GET;
10871558Srgrimes		if (so_ifp.sa.sa_family == 0) {
108813171Swollman			so_ifp.sa.sa_family = AF_LINK;
108913171Swollman			so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
10901558Srgrimes			rtm_addrs |= RTA_IFP;
10911558Srgrimes		}
10921558Srgrimes	} else
10931558Srgrimes		cmd = RTM_DELETE;
10941558Srgrimes#define rtm m_rtmsg.m_rtm
10951558Srgrimes	rtm.rtm_type = cmd;
10961558Srgrimes	rtm.rtm_flags = flags;
10971558Srgrimes	rtm.rtm_version = RTM_VERSION;
10981558Srgrimes	rtm.rtm_seq = ++seq;
10991558Srgrimes	rtm.rtm_addrs = rtm_addrs;
11001558Srgrimes	rtm.rtm_rmx = rt_metrics;
11011558Srgrimes	rtm.rtm_inits = rtm_inits;
11021558Srgrimes
11031558Srgrimes	if (rtm_addrs & RTA_NETMASK)
11041558Srgrimes		mask_addr();
11051558Srgrimes	NEXTADDR(RTA_DST, so_dst);
11061558Srgrimes	NEXTADDR(RTA_GATEWAY, so_gate);
11071558Srgrimes	NEXTADDR(RTA_NETMASK, so_mask);
11081558Srgrimes	NEXTADDR(RTA_GENMASK, so_genmask);
11091558Srgrimes	NEXTADDR(RTA_IFP, so_ifp);
11101558Srgrimes	NEXTADDR(RTA_IFA, so_ifa);
11111558Srgrimes	rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
11121558Srgrimes	if (verbose)
11131558Srgrimes		print_rtmsg(&rtm, l);
11141558Srgrimes	if (debugonly)
11151558Srgrimes		return (0);
11161558Srgrimes	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
11171558Srgrimes		perror("writing to routing socket");
11181558Srgrimes		return (-1);
11191558Srgrimes	}
11201558Srgrimes	if (cmd == RTM_GET) {
11211558Srgrimes		do {
11221558Srgrimes			l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
11231558Srgrimes		} while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
11241558Srgrimes		if (l < 0)
112513171Swollman			warn("read from routing socket");
11261558Srgrimes		else
11271558Srgrimes			print_getmsg(&rtm, l);
11281558Srgrimes	}
11291558Srgrimes#undef rtm
11301558Srgrimes	return (0);
11311558Srgrimes}
11321558Srgrimes
11331558Srgrimesvoid
11341558Srgrimesmask_addr()
11351558Srgrimes{
11361558Srgrimes	int olen = so_mask.sa.sa_len;
11371558Srgrimes	register char *cp1 = olen + (char *)&so_mask, *cp2;
11381558Srgrimes
11391558Srgrimes	for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; )
11401558Srgrimes		if (*--cp1 != 0) {
11411558Srgrimes			so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask;
11421558Srgrimes			break;
11431558Srgrimes		}
11441558Srgrimes	if ((rtm_addrs & RTA_DST) == 0)
11451558Srgrimes		return;
11461558Srgrimes	switch (so_dst.sa.sa_family) {
114714092Swollman#ifdef NS
11481558Srgrimes	case AF_NS:
114914092Swollman#endif
11501558Srgrimes	case AF_INET:
115117046Sjulian	case AF_APPLETALK:
115213940Swollman#ifdef CCITT
11531558Srgrimes	case AF_CCITT:
115413940Swollman#endif
11551558Srgrimes	case 0:
11561558Srgrimes		return;
115713940Swollman#ifdef ISO
11581558Srgrimes	case AF_ISO:
11591558Srgrimes		olen = MIN(so_dst.siso.siso_nlen,
11601558Srgrimes			   MAX(so_mask.sa.sa_len - 6, 0));
11611558Srgrimes		break;
116213940Swollman#endif
11631558Srgrimes	}
11641558Srgrimes	cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
11651558Srgrimes	cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
11661558Srgrimes	while (cp2 > cp1)
11671558Srgrimes		*--cp2 = 0;
11681558Srgrimes	cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
11691558Srgrimes	while (cp1 > so_dst.sa.sa_data)
11701558Srgrimes		*--cp1 &= *--cp2;
117113940Swollman#ifdef ISO
11721558Srgrimes	switch (so_dst.sa.sa_family) {
11731558Srgrimes	case AF_ISO:
11741558Srgrimes		so_dst.siso.siso_nlen = olen;
11751558Srgrimes		break;
11761558Srgrimes	}
117713940Swollman#endif
11781558Srgrimes}
11791558Srgrimes
11801558Srgrimeschar *msgtypes[] = {
11811558Srgrimes	"",
11821558Srgrimes	"RTM_ADD: Add Route",
11831558Srgrimes	"RTM_DELETE: Delete Route",
11841558Srgrimes	"RTM_CHANGE: Change Metrics or flags",
11851558Srgrimes	"RTM_GET: Report Metrics",
11861558Srgrimes	"RTM_LOSING: Kernel Suspects Partitioning",
11871558Srgrimes	"RTM_REDIRECT: Told to use different route",
11881558Srgrimes	"RTM_MISS: Lookup failed on this address",
11891558Srgrimes	"RTM_LOCK: fix specified metrics",
11901558Srgrimes	"RTM_OLDADD: caused by SIOCADDRT",
11911558Srgrimes	"RTM_OLDDEL: caused by SIOCDELRT",
11921558Srgrimes	"RTM_RESOLVE: Route created by cloning",
11931558Srgrimes	"RTM_NEWADDR: address being added to iface",
11941558Srgrimes	"RTM_DELADDR: address being removed from iface",
11951558Srgrimes	"RTM_IFINFO: iface status change",
11961558Srgrimes	0,
11971558Srgrimes};
11981558Srgrimes
11991558Srgrimeschar metricnames[] =
120015690Swollman"\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
120115690Swollman"\1mtu";
12021558Srgrimeschar routeflags[] =
120315690Swollman"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"
120415690Swollman"\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016"
120515690Swollman"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024CHAINDELETE"
120615690Swollman"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST";
12071558Srgrimeschar ifnetflags[] =
120815690Swollman"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
120915690Swollman"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
121015690Swollman"\017LINK2\020MULTICAST";
12111558Srgrimeschar addrnames[] =
12121558Srgrimes"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
12131558Srgrimes
12141558Srgrimesvoid
12151558Srgrimesprint_rtmsg(rtm, msglen)
12161558Srgrimes	register struct rt_msghdr *rtm;
12171558Srgrimes	int msglen;
12181558Srgrimes{
12191558Srgrimes	struct if_msghdr *ifm;
12201558Srgrimes	struct ifa_msghdr *ifam;
12211558Srgrimes
12221558Srgrimes	if (verbose == 0)
12231558Srgrimes		return;
12241558Srgrimes	if (rtm->rtm_version != RTM_VERSION) {
12251558Srgrimes		(void) printf("routing message version %d not understood\n",
12261558Srgrimes		    rtm->rtm_version);
12271558Srgrimes		return;
12281558Srgrimes	}
12291558Srgrimes	(void)printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen);
12301558Srgrimes	switch (rtm->rtm_type) {
12311558Srgrimes	case RTM_IFINFO:
12321558Srgrimes		ifm = (struct if_msghdr *)rtm;
12331558Srgrimes		(void) printf("if# %d, flags:", ifm->ifm_index);
12341558Srgrimes		bprintf(stdout, ifm->ifm_flags, ifnetflags);
12351558Srgrimes		pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
12361558Srgrimes		break;
12371558Srgrimes	case RTM_NEWADDR:
12381558Srgrimes	case RTM_DELADDR:
12391558Srgrimes		ifam = (struct ifa_msghdr *)rtm;
12401558Srgrimes		(void) printf("metric %d, flags:", ifam->ifam_metric);
12411558Srgrimes		bprintf(stdout, ifam->ifam_flags, routeflags);
12421558Srgrimes		pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
12431558Srgrimes		break;
12441558Srgrimes	default:
124513171Swollman		(void) printf("pid: %ld, seq %d, errno %d, flags:",
124613171Swollman			(long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
12471558Srgrimes		bprintf(stdout, rtm->rtm_flags, routeflags);
12481558Srgrimes		pmsg_common(rtm);
12491558Srgrimes	}
12501558Srgrimes}
12511558Srgrimes
12521558Srgrimesvoid
12531558Srgrimesprint_getmsg(rtm, msglen)
12541558Srgrimes	register struct rt_msghdr *rtm;
12551558Srgrimes	int msglen;
12561558Srgrimes{
12571558Srgrimes	struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
12581558Srgrimes	struct sockaddr_dl *ifp = NULL;
12591558Srgrimes	register struct sockaddr *sa;
12601558Srgrimes	register char *cp;
12611558Srgrimes	register int i;
12621558Srgrimes
12631558Srgrimes	(void) printf("   route to: %s\n", routename(&so_dst));
12641558Srgrimes	if (rtm->rtm_version != RTM_VERSION) {
126513171Swollman		warnx("routing message version %d not understood",
126613171Swollman		     rtm->rtm_version);
12671558Srgrimes		return;
12681558Srgrimes	}
12691558Srgrimes	if (rtm->rtm_msglen > msglen) {
127013171Swollman		warnx("message length mismatch, in packet %d, returned %d\n",
127113171Swollman		      rtm->rtm_msglen, msglen);
12721558Srgrimes	}
12731558Srgrimes	if (rtm->rtm_errno)  {
127413171Swollman		errno = rtm->rtm_errno;
127513171Swollman		warn("message indicates error %d", errno);
12761558Srgrimes		return;
12771558Srgrimes	}
12781558Srgrimes	cp = ((char *)(rtm + 1));
12791558Srgrimes	if (rtm->rtm_addrs)
12801558Srgrimes		for (i = 1; i; i <<= 1)
12811558Srgrimes			if (i & rtm->rtm_addrs) {
12821558Srgrimes				sa = (struct sockaddr *)cp;
12831558Srgrimes				switch (i) {
12841558Srgrimes				case RTA_DST:
12851558Srgrimes					dst = sa;
12861558Srgrimes					break;
12871558Srgrimes				case RTA_GATEWAY:
12881558Srgrimes					gate = sa;
12891558Srgrimes					break;
12901558Srgrimes				case RTA_NETMASK:
12911558Srgrimes					mask = sa;
12921558Srgrimes					break;
12931558Srgrimes				case RTA_IFP:
12941558Srgrimes					if (sa->sa_family == AF_LINK &&
12951558Srgrimes					   ((struct sockaddr_dl *)sa)->sdl_nlen)
12961558Srgrimes						ifp = (struct sockaddr_dl *)sa;
12971558Srgrimes					break;
12981558Srgrimes				}
12991558Srgrimes				ADVANCE(cp, sa);
13001558Srgrimes			}
13011558Srgrimes	if (dst && mask)
13021558Srgrimes		mask->sa_family = dst->sa_family;	/* XXX */
13031558Srgrimes	if (dst)
13041558Srgrimes		(void)printf("destination: %s\n", routename(dst));
13051558Srgrimes	if (mask) {
13061558Srgrimes		int savenflag = nflag;
13071558Srgrimes
13081558Srgrimes		nflag = 1;
13091558Srgrimes		(void)printf("       mask: %s\n", routename(mask));
13101558Srgrimes		nflag = savenflag;
13111558Srgrimes	}
13121558Srgrimes	if (gate && rtm->rtm_flags & RTF_GATEWAY)
13131558Srgrimes		(void)printf("    gateway: %s\n", routename(gate));
13141558Srgrimes	if (ifp)
13151558Srgrimes		(void)printf("  interface: %.*s\n",
13161558Srgrimes		    ifp->sdl_nlen, ifp->sdl_data);
13171558Srgrimes	(void)printf("      flags: ");
13181558Srgrimes	bprintf(stdout, rtm->rtm_flags, routeflags);
13191558Srgrimes
13201558Srgrimes#define lock(f)	((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
13211558Srgrimes#define msec(u)	(((u) + 500) / 1000)		/* usec to msec */
13221558Srgrimes
13231558Srgrimes	(void) printf("\n%s\n", "\
13241558Srgrimes recvpipe  sendpipe  ssthresh  rtt,msec    rttvar  hopcount      mtu     expire");
132513171Swollman	printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
132613171Swollman	printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
132713171Swollman	printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
132813171Swollman	printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
132913171Swollman	printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
133013171Swollman	printf("%8ld%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
133113171Swollman	printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
13321558Srgrimes	if (rtm->rtm_rmx.rmx_expire)
13331558Srgrimes		rtm->rtm_rmx.rmx_expire -= time(0);
133413171Swollman	printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
13351558Srgrimes#undef lock
13361558Srgrimes#undef msec
13371558Srgrimes#define	RTA_IGN	(RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
13381558Srgrimes	if (verbose)
13391558Srgrimes		pmsg_common(rtm);
13401558Srgrimes	else if (rtm->rtm_addrs &~ RTA_IGN) {
13411558Srgrimes		(void) printf("sockaddrs: ");
13421558Srgrimes		bprintf(stdout, rtm->rtm_addrs, addrnames);
13431558Srgrimes		putchar('\n');
13441558Srgrimes	}
13451558Srgrimes#undef	RTA_IGN
13461558Srgrimes}
13471558Srgrimes
13481558Srgrimesvoid
13491558Srgrimespmsg_common(rtm)
13501558Srgrimes	register struct rt_msghdr *rtm;
13511558Srgrimes{
13521558Srgrimes	(void) printf("\nlocks: ");
13531558Srgrimes	bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
13541558Srgrimes	(void) printf(" inits: ");
13551558Srgrimes	bprintf(stdout, rtm->rtm_inits, metricnames);
13561558Srgrimes	pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
13571558Srgrimes}
13581558Srgrimes
13591558Srgrimesvoid
13601558Srgrimespmsg_addrs(cp, addrs)
13611558Srgrimes	char	*cp;
13621558Srgrimes	int	addrs;
13631558Srgrimes{
13641558Srgrimes	register struct sockaddr *sa;
13651558Srgrimes	int i;
13661558Srgrimes
13671558Srgrimes	if (addrs == 0)
13681558Srgrimes		return;
13691558Srgrimes	(void) printf("\nsockaddrs: ");
13701558Srgrimes	bprintf(stdout, addrs, addrnames);
13711558Srgrimes	(void) putchar('\n');
13721558Srgrimes	for (i = 1; i; i <<= 1)
13731558Srgrimes		if (i & addrs) {
13741558Srgrimes			sa = (struct sockaddr *)cp;
13751558Srgrimes			(void) printf(" %s", routename(sa));
13761558Srgrimes			ADVANCE(cp, sa);
13771558Srgrimes		}
13781558Srgrimes	(void) putchar('\n');
13791558Srgrimes	(void) fflush(stdout);
13801558Srgrimes}
13811558Srgrimes
13821558Srgrimesvoid
13831558Srgrimesbprintf(fp, b, s)
13841558Srgrimes	register FILE *fp;
13851558Srgrimes	register int b;
13861558Srgrimes	register u_char *s;
13871558Srgrimes{
13881558Srgrimes	register int i;
13891558Srgrimes	int gotsome = 0;
13901558Srgrimes
13911558Srgrimes	if (b == 0)
13921558Srgrimes		return;
139313171Swollman	while ((i = *s++) != 0) {
13941558Srgrimes		if (b & (1 << (i-1))) {
13951558Srgrimes			if (gotsome == 0)
13961558Srgrimes				i = '<';
13971558Srgrimes			else
13981558Srgrimes				i = ',';
13991558Srgrimes			(void) putc(i, fp);
14001558Srgrimes			gotsome = 1;
14011558Srgrimes			for (; (i = *s) > 32; s++)
14021558Srgrimes				(void) putc(i, fp);
14031558Srgrimes		} else
14041558Srgrimes			while (*s > 32)
14051558Srgrimes				s++;
14061558Srgrimes	}
14071558Srgrimes	if (gotsome)
14081558Srgrimes		(void) putc('>', fp);
14091558Srgrimes}
14101558Srgrimes
14111558Srgrimesint
14121558Srgrimeskeyword(cp)
14131558Srgrimes	char *cp;
14141558Srgrimes{
14151558Srgrimes	register struct keytab *kt = keywords;
14161558Srgrimes
14171558Srgrimes	while (kt->kt_cp && strcmp(kt->kt_cp, cp))
14181558Srgrimes		kt++;
14191558Srgrimes	return kt->kt_i;
14201558Srgrimes}
14211558Srgrimes
14221558Srgrimesvoid
14231558Srgrimessodump(su, which)
14241558Srgrimes	register sup su;
14251558Srgrimes	char *which;
14261558Srgrimes{
14271558Srgrimes	switch (su->sa.sa_family) {
14281558Srgrimes	case AF_LINK:
14291558Srgrimes		(void) printf("%s: link %s; ",
14301558Srgrimes		    which, link_ntoa(&su->sdl));
14311558Srgrimes		break;
143213940Swollman#ifdef ISO
14331558Srgrimes	case AF_ISO:
14341558Srgrimes		(void) printf("%s: iso %s; ",
14351558Srgrimes		    which, iso_ntoa(&su->siso.siso_addr));
14361558Srgrimes		break;
143713940Swollman#endif
14381558Srgrimes	case AF_INET:
14391558Srgrimes		(void) printf("%s: inet %s; ",
14401558Srgrimes		    which, inet_ntoa(su->sin.sin_addr));
14411558Srgrimes		break;
144217046Sjulian	case AF_APPLETALK:
144317046Sjulian		(void) printf("%s: atalk %s; ",
144417046Sjulian		    which, atalk_ntoa(su->sat.sat_addr));
144517046Sjulian		break;
144614092Swollman#ifdef NS
14471558Srgrimes	case AF_NS:
14481558Srgrimes		(void) printf("%s: xns %s; ",
14491558Srgrimes		    which, ns_ntoa(su->sns.sns_addr));
14501558Srgrimes		break;
145114092Swollman#endif
14521558Srgrimes	}
14531558Srgrimes	(void) fflush(stdout);
14541558Srgrimes}
14551558Srgrimes
14561558Srgrimes/* States*/
14571558Srgrimes#define VIRGIN	0
14581558Srgrimes#define GOTONE	1
14591558Srgrimes#define GOTTWO	2
14601558Srgrimes/* Inputs */
14611558Srgrimes#define	DIGIT	(4*0)
14621558Srgrimes#define	END	(4*1)
14631558Srgrimes#define DELIM	(4*2)
14641558Srgrimes
14651558Srgrimesvoid
14661558Srgrimessockaddr(addr, sa)
14671558Srgrimes	register char *addr;
14681558Srgrimes	register struct sockaddr *sa;
14691558Srgrimes{
14701558Srgrimes	register char *cp = (char *)sa;
14711558Srgrimes	int size = sa->sa_len;
14721558Srgrimes	char *cplim = cp + size;
147313171Swollman	register int byte = 0, state = VIRGIN, new = 0 /* foil gcc */;
14741558Srgrimes
14751558Srgrimes	bzero(cp, size);
14761558Srgrimes	cp++;
14771558Srgrimes	do {
14781558Srgrimes		if ((*addr >= '0') && (*addr <= '9')) {
14791558Srgrimes			new = *addr - '0';
14801558Srgrimes		} else if ((*addr >= 'a') && (*addr <= 'f')) {
14811558Srgrimes			new = *addr - 'a' + 10;
14821558Srgrimes		} else if ((*addr >= 'A') && (*addr <= 'F')) {
14831558Srgrimes			new = *addr - 'A' + 10;
14841558Srgrimes		} else if (*addr == 0)
14851558Srgrimes			state |= END;
14861558Srgrimes		else
14871558Srgrimes			state |= DELIM;
14881558Srgrimes		addr++;
14891558Srgrimes		switch (state /* | INPUT */) {
14901558Srgrimes		case GOTTWO | DIGIT:
14911558Srgrimes			*cp++ = byte; /*FALLTHROUGH*/
14921558Srgrimes		case VIRGIN | DIGIT:
14931558Srgrimes			state = GOTONE; byte = new; continue;
14941558Srgrimes		case GOTONE | DIGIT:
14951558Srgrimes			state = GOTTWO; byte = new + (byte << 4); continue;
14961558Srgrimes		default: /* | DELIM */
14971558Srgrimes			state = VIRGIN; *cp++ = byte; byte = 0; continue;
14981558Srgrimes		case GOTONE | END:
14991558Srgrimes		case GOTTWO | END:
15001558Srgrimes			*cp++ = byte; /* FALLTHROUGH */
15011558Srgrimes		case VIRGIN | END:
15021558Srgrimes			break;
15031558Srgrimes		}
15041558Srgrimes		break;
15051558Srgrimes	} while (cp < cplim);
15061558Srgrimes	sa->sa_len = cp - (char *)sa;
15071558Srgrimes}
150817046Sjulian
150917046Sjulianint
151017046Sjulianatalk_aton(const char *text, struct at_addr *addr)
151117046Sjulian{
151217046Sjulian	u_int net, node;
151317046Sjulian
151417046Sjulian	if (sscanf(text, "%u.%u", &net, &node) != 2
151517046Sjulian	    || net > 0xffff || node > 0xff)
151617046Sjulian		return(0);
151717254Sjulian	addr->s_net = htons(net);
151817046Sjulian	addr->s_node = node;
151917046Sjulian	return(1);
152017046Sjulian}
152117046Sjulian
152217046Sjulianchar *
152317046Sjulianatalk_ntoa(struct at_addr at)
152417046Sjulian{
152517046Sjulian	static char buf[20];
152617046Sjulian
152717254Sjulian	(void) snprintf(buf, sizeof(buf), "%u.%u", ntohs(at.s_net), at.s_node);
152817046Sjulian	return(buf);
152917046Sjulian}
1530