route.c revision 47668
11558Srgrimes/*
21558Srgrimes * Copyright (c) 1983, 1989, 1991, 1993
31558Srgrimes *	The Regents of the University of California.  All rights reserved.
41558Srgrimes *
51558Srgrimes * Redistribution and use in source and binary forms, with or without
61558Srgrimes * modification, are permitted provided that the following conditions
71558Srgrimes * are met:
81558Srgrimes * 1. Redistributions of source code must retain the above copyright
91558Srgrimes *    notice, this list of conditions and the following disclaimer.
101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111558Srgrimes *    notice, this list of conditions and the following disclaimer in the
121558Srgrimes *    documentation and/or other materials provided with the distribution.
131558Srgrimes * 3. All advertising materials mentioning features or use of this software
141558Srgrimes *    must display the following acknowledgement:
151558Srgrimes *	This product includes software developed by the University of
161558Srgrimes *	California, Berkeley and its contributors.
171558Srgrimes * 4. Neither the name of the University nor the names of its contributors
181558Srgrimes *    may be used to endorse or promote products derived from this software
191558Srgrimes *    without specific prior written permission.
201558Srgrimes *
211558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311558Srgrimes * SUCH DAMAGE.
321558Srgrimes */
331558Srgrimes
341558Srgrimes#ifndef lint
3513171Swollmanstatic const char copyright[] =
361558Srgrimes"@(#) Copyright (c) 1983, 1989, 1991, 1993\n\
371558Srgrimes	The Regents of the University of California.  All rights reserved.\n";
381558Srgrimes#endif /* not lint */
391558Srgrimes
401558Srgrimes#ifndef lint
4137907Scharnier#if 0
421558Srgrimesstatic char sccsid[] = "@(#)route.c	8.3 (Berkeley) 3/19/94";
4337907Scharnier#endif
4413171Swollmanstatic const char rcsid[] =
4547668Sru	"$Id: route.c,v 1.29 1998/07/28 06:25:35 charnier Exp $";
461558Srgrimes#endif /* not lint */
471558Srgrimes
481558Srgrimes#include <sys/param.h>
491558Srgrimes#include <sys/file.h>
501558Srgrimes#include <sys/socket.h>
511558Srgrimes#include <sys/ioctl.h>
521558Srgrimes#include <sys/sysctl.h>
531558Srgrimes
541558Srgrimes#include <net/if.h>
551558Srgrimes#include <net/route.h>
561558Srgrimes#include <net/if_dl.h>
571558Srgrimes#include <netinet/in.h>
5817046Sjulian#include <netatalk/at.h>
5914092Swollman#ifdef NS
601558Srgrimes#include <netns/ns.h>
6114092Swollman#endif
621558Srgrimes#include <arpa/inet.h>
631558Srgrimes#include <netdb.h>
641558Srgrimes
6520287Swollman#include <ctype.h>
6620287Swollman#include <err.h>
671558Srgrimes#include <errno.h>
681558Srgrimes#include <stdio.h>
691558Srgrimes#include <stdlib.h>
701558Srgrimes#include <string.h>
7113171Swollman#include <sysexits.h>
7220287Swollman#include <unistd.h>
731558Srgrimes
741558Srgrimesstruct keytab {
751558Srgrimes	char	*kt_cp;
761558Srgrimes	int	kt_i;
771558Srgrimes} keywords[] = {
781558Srgrimes#include "keywords.h"
791558Srgrimes	{0, 0}
801558Srgrimes};
811558Srgrimes
821558Srgrimesstruct	ortentry route;
831558Srgrimesunion	sockunion {
841558Srgrimes	struct	sockaddr sa;
851558Srgrimes	struct	sockaddr_in sin;
8617046Sjulian	struct	sockaddr_at sat;
8714092Swollman#ifdef NS
881558Srgrimes	struct	sockaddr_ns sns;
8914092Swollman#endif
901558Srgrimes	struct	sockaddr_dl sdl;
911558Srgrimes} so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
921558Srgrimes
931558Srgrimestypedef union sockunion *sup;
941558Srgrimesint	pid, rtm_addrs, uid;
951558Srgrimesint	s;
961558Srgrimesint	forcehost, forcenet, doflush, nflag, af, qflag, tflag, keyword();
971558Srgrimesint	iflag, verbose, aflen = sizeof (struct sockaddr_in);
981558Srgrimesint	locking, lockrest, debugonly;
991558Srgrimesstruct	rt_metrics rt_metrics;
1001558Srgrimesu_long  rtm_inits;
1011558Srgrimesstruct	in_addr inet_makeaddr();
10217046Sjulianint	atalk_aton __P((const char *, struct at_addr *));
10317046Sjulianchar	*atalk_ntoa __P((struct at_addr));
1041558Srgrimeschar	*routename(), *netname();
1051558Srgrimesvoid	flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf();
1061558Srgrimesvoid	print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr();
1071558Srgrimesint	getaddr(), rtmsg(), x25_makemask();
1081558Srgrimesextern	char *inet_ntoa(), *iso_ntoa(), *link_ntoa();
1091558Srgrimes
11018286Sbdevoid usage __P((const char *)) __dead2;
11113171Swollman
11218286Sbdevoid
1131558Srgrimesusage(cp)
11413171Swollman	const char *cp;
1151558Srgrimes{
1161558Srgrimes	if (cp)
11713171Swollman		warnx("bad keyword: %s", cp);
1181558Srgrimes	(void) fprintf(stderr,
11937907Scharnier	    "usage: route [-dnqtv] command [[modifiers] args]\n");
12013171Swollman	exit(EX_USAGE);
1211558Srgrimes	/* NOTREACHED */
1221558Srgrimes}
1231558Srgrimes
1241558Srgrimes#define ROUNDUP(a) \
1251558Srgrimes	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
1261558Srgrimes#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
1271558Srgrimes
1281558Srgrimesint
1291558Srgrimesmain(argc, argv)
1301558Srgrimes	int argc;
1311558Srgrimes	char **argv;
1321558Srgrimes{
1331558Srgrimes	int ch;
1341558Srgrimes
1351558Srgrimes	if (argc < 2)
1361558Srgrimes		usage((char *)NULL);
1371558Srgrimes
13837907Scharnier	while ((ch = getopt(argc, argv, "nqdtv")) != -1)
1391558Srgrimes		switch(ch) {
1401558Srgrimes		case 'n':
1411558Srgrimes			nflag = 1;
1421558Srgrimes			break;
1431558Srgrimes		case 'q':
1441558Srgrimes			qflag = 1;
1451558Srgrimes			break;
1461558Srgrimes		case 'v':
1471558Srgrimes			verbose = 1;
1481558Srgrimes			break;
1491558Srgrimes		case 't':
1501558Srgrimes			tflag = 1;
1511558Srgrimes			break;
1521558Srgrimes		case 'd':
1531558Srgrimes			debugonly = 1;
1541558Srgrimes			break;
1551558Srgrimes		case '?':
1561558Srgrimes		default:
1571558Srgrimes			usage((char *)NULL);
1581558Srgrimes		}
1591558Srgrimes	argc -= optind;
1601558Srgrimes	argv += optind;
1611558Srgrimes
1621558Srgrimes	pid = getpid();
1631558Srgrimes	uid = getuid();
1641558Srgrimes	if (tflag)
1651558Srgrimes		s = open("/dev/null", O_WRONLY, 0);
1661558Srgrimes	else
1671558Srgrimes		s = socket(PF_ROUTE, SOCK_RAW, 0);
1681558Srgrimes	if (s < 0)
16913171Swollman		err(EX_OSERR, "socket");
17019209Sfenner	setuid(uid);
1711558Srgrimes	if (*argv)
1721558Srgrimes		switch (keyword(*argv)) {
1731558Srgrimes		case K_GET:
1741558Srgrimes			uid = 0;
1751558Srgrimes			/* FALLTHROUGH */
1761558Srgrimes
1771558Srgrimes		case K_CHANGE:
1781558Srgrimes		case K_ADD:
1791558Srgrimes		case K_DELETE:
1801558Srgrimes			newroute(argc, argv);
1811558Srgrimes			exit(0);
1821558Srgrimes			/* NOTREACHED */
1831558Srgrimes
1841558Srgrimes		case K_MONITOR:
1851558Srgrimes			monitor();
1861558Srgrimes			/* NOTREACHED */
1871558Srgrimes
1881558Srgrimes		case K_FLUSH:
1891558Srgrimes			flushroutes(argc, argv);
1901558Srgrimes			exit(0);
1911558Srgrimes			/* NOTREACHED */
1921558Srgrimes		}
1931558Srgrimes	usage(*argv);
1941558Srgrimes	/* NOTREACHED */
1951558Srgrimes}
1961558Srgrimes
1971558Srgrimes/*
1981558Srgrimes * Purge all entries in the routing tables not
1991558Srgrimes * associated with network interfaces.
2001558Srgrimes */
2011558Srgrimesvoid
2021558Srgrimesflushroutes(argc, argv)
2031558Srgrimes	int argc;
2041558Srgrimes	char *argv[];
2051558Srgrimes{
2061558Srgrimes	size_t needed;
2071558Srgrimes	int mib[6], rlen, seqno;
2081558Srgrimes	char *buf, *next, *lim;
2091558Srgrimes	register struct rt_msghdr *rtm;
2101558Srgrimes
2111558Srgrimes	if (uid) {
21213171Swollman		errx(EX_NOPERM, "must be root to alter routing table");
2131558Srgrimes	}
2141558Srgrimes	shutdown(s, 0); /* Don't want to read back our messages */
2151558Srgrimes	if (argc > 1) {
2161558Srgrimes		argv++;
2171558Srgrimes		if (argc == 2 && **argv == '-')
2181558Srgrimes		    switch (keyword(*argv + 1)) {
2191558Srgrimes			case K_INET:
2201558Srgrimes				af = AF_INET;
2211558Srgrimes				break;
22217046Sjulian			case K_ATALK:
22317046Sjulian				af = AF_APPLETALK;
22417046Sjulian				break;
22514092Swollman#ifdef NS
2261558Srgrimes			case K_XNS:
2271558Srgrimes				af = AF_NS;
2281558Srgrimes				break;
22914092Swollman#endif
2301558Srgrimes			case K_LINK:
2311558Srgrimes				af = AF_LINK;
2321558Srgrimes				break;
2331558Srgrimes			default:
2341558Srgrimes				goto bad;
2351558Srgrimes		} else
2361558Srgrimesbad:			usage(*argv);
2371558Srgrimes	}
2381558Srgrimes	mib[0] = CTL_NET;
2391558Srgrimes	mib[1] = PF_ROUTE;
2401558Srgrimes	mib[2] = 0;		/* protocol */
2411558Srgrimes	mib[3] = 0;		/* wildcard address family */
2421558Srgrimes	mib[4] = NET_RT_DUMP;
2431558Srgrimes	mib[5] = 0;		/* no flags */
2441558Srgrimes	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
24513171Swollman		err(EX_OSERR, "route-sysctl-estimate");
2461558Srgrimes	if ((buf = malloc(needed)) == NULL)
24737907Scharnier		errx(EX_OSERR, "malloc failed");
2481558Srgrimes	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
24913171Swollman		err(EX_OSERR, "route-sysctl-get");
2501558Srgrimes	lim = buf + needed;
2511558Srgrimes	if (verbose)
2521558Srgrimes		(void) printf("Examining routing table from sysctl\n");
2531558Srgrimes	seqno = 0;		/* ??? */
2541558Srgrimes	for (next = buf; next < lim; next += rtm->rtm_msglen) {
2551558Srgrimes		rtm = (struct rt_msghdr *)next;
2561558Srgrimes		if (verbose)
2571558Srgrimes			print_rtmsg(rtm, rtm->rtm_msglen);
2581558Srgrimes		if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
2591558Srgrimes			continue;
2601558Srgrimes		if (af) {
2611558Srgrimes			struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
2621558Srgrimes
2631558Srgrimes			if (sa->sa_family != af)
2641558Srgrimes				continue;
2651558Srgrimes		}
2661558Srgrimes		if (debugonly)
2671558Srgrimes			continue;
2681558Srgrimes		rtm->rtm_type = RTM_DELETE;
2691558Srgrimes		rtm->rtm_seq = seqno;
2701558Srgrimes		rlen = write(s, next, rtm->rtm_msglen);
2711558Srgrimes		if (rlen < (int)rtm->rtm_msglen) {
27213171Swollman			warn("write to routing socket");
2731558Srgrimes			(void) printf("got only %d for rlen\n", rlen);
2741558Srgrimes			break;
2751558Srgrimes		}
2761558Srgrimes		seqno++;
2771558Srgrimes		if (qflag)
2781558Srgrimes			continue;
2791558Srgrimes		if (verbose)
2801558Srgrimes			print_rtmsg(rtm, rlen);
2811558Srgrimes		else {
2821558Srgrimes			struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
2831558Srgrimes			(void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
2841558Srgrimes			    routename(sa) : netname(sa));
2851558Srgrimes			sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
2861558Srgrimes			(void) printf("%-20.20s ", routename(sa));
2871558Srgrimes			(void) printf("done\n");
2881558Srgrimes		}
2891558Srgrimes	}
2901558Srgrimes}
2911558Srgrimes
2921558Srgrimeschar *
2931558Srgrimesroutename(sa)
2941558Srgrimes	struct sockaddr *sa;
2951558Srgrimes{
2961558Srgrimes	register char *cp;
29719209Sfenner	static char line[MAXHOSTNAMELEN + 1];
2981558Srgrimes	struct hostent *hp;
2991558Srgrimes	static char domain[MAXHOSTNAMELEN + 1];
3001558Srgrimes	static int first = 1;
30114092Swollman#ifdef NS
3021558Srgrimes	char *ns_print();
30314092Swollman#endif
3041558Srgrimes
3051558Srgrimes	if (first) {
3061558Srgrimes		first = 0;
3071558Srgrimes		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
30819209Sfenner		    (cp = index(domain, '.'))) {
30919209Sfenner			domain[MAXHOSTNAMELEN] = '\0';
3101558Srgrimes			(void) strcpy(domain, cp + 1);
31119209Sfenner		} else
3121558Srgrimes			domain[0] = 0;
3131558Srgrimes	}
3141558Srgrimes
3151558Srgrimes	if (sa->sa_len == 0)
3161558Srgrimes		strcpy(line, "default");
3171558Srgrimes	else switch (sa->sa_family) {
3181558Srgrimes
3191558Srgrimes	case AF_INET:
3201558Srgrimes	    {	struct in_addr in;
3211558Srgrimes		in = ((struct sockaddr_in *)sa)->sin_addr;
3221558Srgrimes
3231558Srgrimes		cp = 0;
3241558Srgrimes		if (in.s_addr == INADDR_ANY || sa->sa_len < 4)
3251558Srgrimes			cp = "default";
3261558Srgrimes		if (cp == 0 && !nflag) {
3271558Srgrimes			hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
3281558Srgrimes				AF_INET);
3291558Srgrimes			if (hp) {
3301558Srgrimes				if ((cp = index(hp->h_name, '.')) &&
3311558Srgrimes				    !strcmp(cp + 1, domain))
3321558Srgrimes					*cp = 0;
3331558Srgrimes				cp = hp->h_name;
3341558Srgrimes			}
3351558Srgrimes		}
33631958Simp		if (cp) {
33731958Simp			strncpy(line, cp, sizeof(line) - 1);
33831958Simp			line[sizeof(line) - 1] = '\0';
33931958Simp		} else {
34013171Swollman			/* XXX - why not inet_ntoa()? */
34113171Swollman#define C(x)	(unsigned)((x) & 0xff)
3421558Srgrimes			in.s_addr = ntohl(in.s_addr);
3431558Srgrimes			(void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
3441558Srgrimes			   C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
3451558Srgrimes		}
3461558Srgrimes		break;
3471558Srgrimes	    }
3481558Srgrimes
34917046Sjulian	case AF_APPLETALK:
35017046Sjulian		(void) snprintf(line, sizeof(line), "atalk %s",
35117046Sjulian			atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
35217046Sjulian		break;
35317046Sjulian
35414092Swollman#ifdef NS
3551558Srgrimes	case AF_NS:
3561558Srgrimes		return (ns_print((struct sockaddr_ns *)sa));
35714092Swollman#endif
3581558Srgrimes
3591558Srgrimes	case AF_LINK:
3601558Srgrimes		return (link_ntoa((struct sockaddr_dl *)sa));
3611558Srgrimes
3621558Srgrimes	default:
3631558Srgrimes	    {	u_short *s = (u_short *)sa;
3641558Srgrimes		u_short *slim = s + ((sa->sa_len + 1) >> 1);
3651558Srgrimes		char *cp = line + sprintf(line, "(%d)", sa->sa_family);
36619209Sfenner		char *cpe = line + sizeof(line);
3671558Srgrimes
36819209Sfenner		while (++s < slim && cp < cpe) /* start with sa->sa_data */
36919209Sfenner			cp += snprintf(cp, cpe - cp, " %x", *s);
3701558Srgrimes		break;
3711558Srgrimes	    }
3721558Srgrimes	}
3731558Srgrimes	return (line);
3741558Srgrimes}
3751558Srgrimes
3761558Srgrimes/*
3771558Srgrimes * Return the name of the network whose address is given.
3781558Srgrimes * The address is assumed to be that of a net or subnet, not a host.
3791558Srgrimes */
3801558Srgrimeschar *
3811558Srgrimesnetname(sa)
3821558Srgrimes	struct sockaddr *sa;
3831558Srgrimes{
3841558Srgrimes	char *cp = 0;
38519209Sfenner	static char line[MAXHOSTNAMELEN + 1];
3861558Srgrimes	struct netent *np = 0;
3871558Srgrimes	u_long net, mask;
3881558Srgrimes	register u_long i;
3891558Srgrimes	int subnetshift;
39014092Swollman#ifdef NS
3911558Srgrimes	char *ns_print();
39214092Swollman#endif
3931558Srgrimes
3941558Srgrimes	switch (sa->sa_family) {
3951558Srgrimes
3961558Srgrimes	case AF_INET:
3971558Srgrimes	    {	struct in_addr in;
3981558Srgrimes		in = ((struct sockaddr_in *)sa)->sin_addr;
3991558Srgrimes
4001558Srgrimes		i = in.s_addr = ntohl(in.s_addr);
4011558Srgrimes		if (in.s_addr == 0)
4021558Srgrimes			cp = "default";
4031558Srgrimes		else if (!nflag) {
4041558Srgrimes			if (IN_CLASSA(i)) {
4051558Srgrimes				mask = IN_CLASSA_NET;
4061558Srgrimes				subnetshift = 8;
4071558Srgrimes			} else if (IN_CLASSB(i)) {
4081558Srgrimes				mask = IN_CLASSB_NET;
4091558Srgrimes				subnetshift = 8;
4101558Srgrimes			} else {
4111558Srgrimes				mask = IN_CLASSC_NET;
4121558Srgrimes				subnetshift = 4;
4131558Srgrimes			}
4141558Srgrimes			/*
4151558Srgrimes			 * If there are more bits than the standard mask
4161558Srgrimes			 * would suggest, subnets must be in use.
4171558Srgrimes			 * Guess at the subnet mask, assuming reasonable
4181558Srgrimes			 * width subnet fields.
4191558Srgrimes			 */
4201558Srgrimes			while (in.s_addr &~ mask)
4211558Srgrimes				mask = (long)mask >> subnetshift;
4221558Srgrimes			net = in.s_addr & mask;
4231558Srgrimes			while ((mask & 1) == 0)
4241558Srgrimes				mask >>= 1, net >>= 1;
4251558Srgrimes			np = getnetbyaddr(net, AF_INET);
4261558Srgrimes			if (np)
4271558Srgrimes				cp = np->n_name;
4281558Srgrimes		}
4291558Srgrimes		if (cp)
43019209Sfenner			strncpy(line, cp, sizeof(line));
4311558Srgrimes		else if ((in.s_addr & 0xffffff) == 0)
4321558Srgrimes			(void) sprintf(line, "%u", C(in.s_addr >> 24));
4331558Srgrimes		else if ((in.s_addr & 0xffff) == 0)
4341558Srgrimes			(void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
4351558Srgrimes			    C(in.s_addr >> 16));
4361558Srgrimes		else if ((in.s_addr & 0xff) == 0)
4371558Srgrimes			(void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
4381558Srgrimes			    C(in.s_addr >> 16), C(in.s_addr >> 8));
4391558Srgrimes		else
4401558Srgrimes			(void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
4411558Srgrimes			    C(in.s_addr >> 16), C(in.s_addr >> 8),
4421558Srgrimes			    C(in.s_addr));
4431558Srgrimes		break;
4441558Srgrimes	    }
4451558Srgrimes
44617046Sjulian	case AF_APPLETALK:
44717046Sjulian		(void) snprintf(line, sizeof(line), "atalk %s",
44817046Sjulian			atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
44917046Sjulian		break;
45017046Sjulian
45114092Swollman#ifdef NS
4521558Srgrimes	case AF_NS:
4531558Srgrimes		return (ns_print((struct sockaddr_ns *)sa));
4541558Srgrimes		break;
45514092Swollman#endif
4561558Srgrimes
4571558Srgrimes	case AF_LINK:
4581558Srgrimes		return (link_ntoa((struct sockaddr_dl *)sa));
4591558Srgrimes
4601558Srgrimes
4611558Srgrimes	default:
4621558Srgrimes	    {	u_short *s = (u_short *)sa->sa_data;
4631558Srgrimes		u_short *slim = s + ((sa->sa_len + 1)>>1);
4641558Srgrimes		char *cp = line + sprintf(line, "af %d:", sa->sa_family);
46519209Sfenner		char *cpe = line + sizeof(line);
4661558Srgrimes
46719209Sfenner		while (s < slim && cp < cpe)
46819209Sfenner			cp += snprintf(cp, cpe - cp, " %x", *s++);
4691558Srgrimes		break;
4701558Srgrimes	    }
4711558Srgrimes	}
4721558Srgrimes	return (line);
4731558Srgrimes}
4741558Srgrimes
4751558Srgrimesvoid
4761558Srgrimesset_metric(value, key)
4771558Srgrimes	char *value;
4781558Srgrimes	int key;
4791558Srgrimes{
4801558Srgrimes	int flag = 0;
4811558Srgrimes	u_long noval, *valp = &noval;
4821558Srgrimes
4831558Srgrimes	switch (key) {
4841558Srgrimes#define caseof(x, y, z)	case x: valp = &rt_metrics.z; flag = y; break
4851558Srgrimes	caseof(K_MTU, RTV_MTU, rmx_mtu);
4861558Srgrimes	caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
4871558Srgrimes	caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
4881558Srgrimes	caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
4891558Srgrimes	caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
4901558Srgrimes	caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
4911558Srgrimes	caseof(K_RTT, RTV_RTT, rmx_rtt);
4921558Srgrimes	caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
4931558Srgrimes	}
4941558Srgrimes	rtm_inits |= flag;
4951558Srgrimes	if (lockrest || locking)
4961558Srgrimes		rt_metrics.rmx_locks |= flag;
4971558Srgrimes	if (locking)
4981558Srgrimes		locking = 0;
4991558Srgrimes	*valp = atoi(value);
5001558Srgrimes}
5011558Srgrimes
5021558Srgrimesvoid
5031558Srgrimesnewroute(argc, argv)
5041558Srgrimes	int argc;
5051558Srgrimes	register char **argv;
5061558Srgrimes{
5071558Srgrimes	char *cmd, *dest = "", *gateway = "", *err;
5081558Srgrimes	int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC;
5091558Srgrimes	int key;
5101558Srgrimes	struct hostent *hp = 0;
5111558Srgrimes
5121558Srgrimes	if (uid) {
51313171Swollman		errx(EX_NOPERM, "must be root to alter routing table");
5141558Srgrimes	}
5151558Srgrimes	cmd = argv[0];
5161558Srgrimes	if (*cmd != 'g')
5171558Srgrimes		shutdown(s, 0); /* Don't want to read back our messages */
5181558Srgrimes	while (--argc > 0) {
5191558Srgrimes		if (**(++argv)== '-') {
5201558Srgrimes			switch (key = keyword(1 + *argv)) {
5211558Srgrimes			case K_LINK:
5221558Srgrimes				af = AF_LINK;
5231558Srgrimes				aflen = sizeof(struct sockaddr_dl);
5241558Srgrimes				break;
5251558Srgrimes			case K_INET:
5261558Srgrimes				af = AF_INET;
5271558Srgrimes				aflen = sizeof(struct sockaddr_in);
5281558Srgrimes				break;
52917046Sjulian			case K_ATALK:
53017046Sjulian				af = AF_APPLETALK;
53117046Sjulian				aflen = sizeof(struct sockaddr_at);
53217046Sjulian				break;
5331558Srgrimes			case K_SA:
5341558Srgrimes				af = PF_ROUTE;
5351558Srgrimes				aflen = sizeof(union sockunion);
5361558Srgrimes				break;
53714092Swollman#ifdef NS
5381558Srgrimes			case K_XNS:
5391558Srgrimes				af = AF_NS;
5401558Srgrimes				aflen = sizeof(struct sockaddr_ns);
5411558Srgrimes				break;
54214092Swollman#endif
5431558Srgrimes			case K_IFACE:
5441558Srgrimes			case K_INTERFACE:
5451558Srgrimes				iflag++;
5462787Spst				break;
5471558Srgrimes			case K_NOSTATIC:
5481558Srgrimes				flags &= ~RTF_STATIC;
5491558Srgrimes				break;
55017591Sjulian			case K_LLINFO:
55117591Sjulian				flags |= RTF_LLINFO;
55217591Sjulian				break;
5531558Srgrimes			case K_LOCK:
5541558Srgrimes				locking = 1;
5551558Srgrimes				break;
5561558Srgrimes			case K_LOCKREST:
5571558Srgrimes				lockrest = 1;
5581558Srgrimes				break;
5591558Srgrimes			case K_HOST:
5601558Srgrimes				forcehost++;
5611558Srgrimes				break;
5621558Srgrimes			case K_REJECT:
5631558Srgrimes				flags |= RTF_REJECT;
5641558Srgrimes				break;
5651558Srgrimes			case K_BLACKHOLE:
5661558Srgrimes				flags |= RTF_BLACKHOLE;
5671558Srgrimes				break;
5681558Srgrimes			case K_PROTO1:
5691558Srgrimes				flags |= RTF_PROTO1;
5701558Srgrimes				break;
5711558Srgrimes			case K_PROTO2:
5721558Srgrimes				flags |= RTF_PROTO2;
5731558Srgrimes				break;
5741558Srgrimes			case K_CLONING:
5751558Srgrimes				flags |= RTF_CLONING;
5761558Srgrimes				break;
5771558Srgrimes			case K_XRESOLVE:
5781558Srgrimes				flags |= RTF_XRESOLVE;
5791558Srgrimes				break;
5801558Srgrimes			case K_STATIC:
5811558Srgrimes				flags |= RTF_STATIC;
5821558Srgrimes				break;
5831558Srgrimes			case K_IFA:
58447668Sru				if (!--argc)
58547668Sru					usage((char *)NULL);
5861558Srgrimes				(void) getaddr(RTA_IFA, *++argv, 0);
5871558Srgrimes				break;
5881558Srgrimes			case K_IFP:
58947668Sru				if (!--argc)
59047668Sru					usage((char *)NULL);
5911558Srgrimes				(void) getaddr(RTA_IFP, *++argv, 0);
5921558Srgrimes				break;
5931558Srgrimes			case K_GENMASK:
59447668Sru				if (!--argc)
59547668Sru					usage((char *)NULL);
5961558Srgrimes				(void) getaddr(RTA_GENMASK, *++argv, 0);
5971558Srgrimes				break;
5981558Srgrimes			case K_GATEWAY:
59947668Sru				if (!--argc)
60047668Sru					usage((char *)NULL);
6011558Srgrimes				(void) getaddr(RTA_GATEWAY, *++argv, 0);
6021558Srgrimes				break;
6031558Srgrimes			case K_DST:
60447668Sru				if (!--argc)
60547668Sru					usage((char *)NULL);
6061558Srgrimes				ishost = getaddr(RTA_DST, *++argv, &hp);
6071558Srgrimes				dest = *argv;
6081558Srgrimes				break;
6091558Srgrimes			case K_NETMASK:
61047668Sru				if (!--argc)
61147668Sru					usage((char *)NULL);
6121558Srgrimes				(void) getaddr(RTA_NETMASK, *++argv, 0);
6131558Srgrimes				/* FALLTHROUGH */
6141558Srgrimes			case K_NET:
6151558Srgrimes				forcenet++;
6161558Srgrimes				break;
6171558Srgrimes			case K_MTU:
6181558Srgrimes			case K_HOPCOUNT:
6191558Srgrimes			case K_EXPIRE:
6201558Srgrimes			case K_RECVPIPE:
6211558Srgrimes			case K_SENDPIPE:
6221558Srgrimes			case K_SSTHRESH:
6231558Srgrimes			case K_RTT:
6241558Srgrimes			case K_RTTVAR:
62547668Sru				if (!--argc)
62647668Sru					usage((char *)NULL);
6271558Srgrimes				set_metric(*++argv, key);
6281558Srgrimes				break;
6291558Srgrimes			default:
6301558Srgrimes				usage(1+*argv);
6311558Srgrimes			}
6321558Srgrimes		} else {
6331558Srgrimes			if ((rtm_addrs & RTA_DST) == 0) {
6341558Srgrimes				dest = *argv;
6351558Srgrimes				ishost = getaddr(RTA_DST, *argv, &hp);
6361558Srgrimes			} else if ((rtm_addrs & RTA_GATEWAY) == 0) {
6371558Srgrimes				gateway = *argv;
6381558Srgrimes				(void) getaddr(RTA_GATEWAY, *argv, &hp);
6391558Srgrimes			} else {
6401558Srgrimes				(void) getaddr(RTA_NETMASK, *argv, 0);
6411558Srgrimes			}
6421558Srgrimes		}
6431558Srgrimes	}
6441558Srgrimes	if (forcehost)
6451558Srgrimes		ishost = 1;
6461558Srgrimes	if (forcenet)
6471558Srgrimes		ishost = 0;
6481558Srgrimes	flags |= RTF_UP;
6491558Srgrimes	if (ishost)
6501558Srgrimes		flags |= RTF_HOST;
6511558Srgrimes	if (iflag == 0)
6521558Srgrimes		flags |= RTF_GATEWAY;
6531558Srgrimes	for (attempts = 1; ; attempts++) {
6541558Srgrimes		errno = 0;
6551558Srgrimes		if ((ret = rtmsg(*cmd, flags)) == 0)
6561558Srgrimes			break;
6571558Srgrimes		if (errno != ENETUNREACH && errno != ESRCH)
6581558Srgrimes			break;
6591558Srgrimes		if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
6601558Srgrimes			hp->h_addr_list++;
6611558Srgrimes			bcopy(hp->h_addr_list[0], &so_gate.sin.sin_addr,
66231958Simp			    MIN(hp->h_length, sizeof(so_gate.sin.sin_addr)));
6631558Srgrimes		} else
6641558Srgrimes			break;
6651558Srgrimes	}
6661558Srgrimes	if (*cmd == 'g')
6671558Srgrimes		exit(0);
6681558Srgrimes	oerrno = errno;
6691558Srgrimes	(void) printf("%s %s %s", cmd, ishost? "host" : "net", dest);
6701558Srgrimes	if (*gateway) {
6711558Srgrimes		(void) printf(": gateway %s", gateway);
6721558Srgrimes		if (attempts > 1 && ret == 0 && af == AF_INET)
6731558Srgrimes		    (void) printf(" (%s)",
6741558Srgrimes			inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
6751558Srgrimes	}
6761558Srgrimes	if (ret == 0)
6771558Srgrimes		(void) printf("\n");
6781558Srgrimes	else {
6791558Srgrimes		switch (oerrno) {
6801558Srgrimes		case ESRCH:
6811558Srgrimes			err = "not in table";
6821558Srgrimes			break;
6831558Srgrimes		case EBUSY:
6841558Srgrimes			err = "entry in use";
6851558Srgrimes			break;
6861558Srgrimes		case ENOBUFS:
6871558Srgrimes			err = "routing table overflow";
6881558Srgrimes			break;
6891558Srgrimes		default:
6901558Srgrimes			err = strerror(oerrno);
6911558Srgrimes			break;
6921558Srgrimes		}
6931558Srgrimes		(void) printf(": %s\n", err);
6941558Srgrimes	}
6951558Srgrimes}
6961558Srgrimes
6971558Srgrimesvoid
69824558Sphkinet_makenetandmask(net, sin, bits)
69924558Sphk	u_long net, bits;
7001558Srgrimes	register struct sockaddr_in *sin;
7011558Srgrimes{
7021558Srgrimes	u_long addr, mask = 0;
7031558Srgrimes	register char *cp;
7041558Srgrimes
7051558Srgrimes	rtm_addrs |= RTA_NETMASK;
7061558Srgrimes	if (net == 0)
7071558Srgrimes		mask = addr = 0;
70824558Sphk	else if (bits) {
70924558Sphk		addr = net;
71024558Sphk		mask = 0xffffffff << (32 - bits);
71124558Sphk	} else if (net < 128) {
7121558Srgrimes		addr = net << IN_CLASSA_NSHIFT;
7131558Srgrimes		mask = IN_CLASSA_NET;
7141558Srgrimes	} else if (net < 65536) {
7151558Srgrimes		addr = net << IN_CLASSB_NSHIFT;
7161558Srgrimes		mask = IN_CLASSB_NET;
7171558Srgrimes	} else if (net < 16777216L) {
7181558Srgrimes		addr = net << IN_CLASSC_NSHIFT;
7191558Srgrimes		mask = IN_CLASSC_NET;
7201558Srgrimes	} else {
7211558Srgrimes		addr = net;
7221558Srgrimes		if ((addr & IN_CLASSA_HOST) == 0)
7231558Srgrimes			mask =  IN_CLASSA_NET;
7241558Srgrimes		else if ((addr & IN_CLASSB_HOST) == 0)
7251558Srgrimes			mask =  IN_CLASSB_NET;
7261558Srgrimes		else if ((addr & IN_CLASSC_HOST) == 0)
7271558Srgrimes			mask =  IN_CLASSC_NET;
7281558Srgrimes		else
7291558Srgrimes			mask = -1;
7301558Srgrimes	}
7311558Srgrimes	sin->sin_addr.s_addr = htonl(addr);
7321558Srgrimes	sin = &so_mask.sin;
7331558Srgrimes	sin->sin_addr.s_addr = htonl(mask);
7341558Srgrimes	sin->sin_len = 0;
7351558Srgrimes	sin->sin_family = 0;
7361558Srgrimes	cp = (char *)(&sin->sin_addr + 1);
7371558Srgrimes	while (*--cp == 0 && cp > (char *)sin)
7381558Srgrimes		;
7391558Srgrimes	sin->sin_len = 1 + cp - (char *)sin;
7401558Srgrimes}
7411558Srgrimes
7421558Srgrimes/*
7431558Srgrimes * Interpret an argument as a network address of some kind,
7441558Srgrimes * returning 1 if a host address, 0 if a network address.
7451558Srgrimes */
7461558Srgrimesint
7471558Srgrimesgetaddr(which, s, hpp)
7481558Srgrimes	int which;
7491558Srgrimes	char *s;
7501558Srgrimes	struct hostent **hpp;
7511558Srgrimes{
7521558Srgrimes	register sup su;
75314092Swollman#ifdef NS
7541558Srgrimes	struct ns_addr ns_addr();
75514092Swollman#endif
7561558Srgrimes	struct hostent *hp;
7571558Srgrimes	struct netent *np;
7581558Srgrimes	u_long val;
75924558Sphk	char *q,qs;
7601558Srgrimes
7611558Srgrimes	if (af == 0) {
7621558Srgrimes		af = AF_INET;
7631558Srgrimes		aflen = sizeof(struct sockaddr_in);
7641558Srgrimes	}
7651558Srgrimes	rtm_addrs |= which;
7661558Srgrimes	switch (which) {
7671558Srgrimes	case RTA_DST:
7681558Srgrimes		su = &so_dst;
7691558Srgrimes		break;
7701558Srgrimes	case RTA_GATEWAY:
7711558Srgrimes		su = &so_gate;
77217486Sjulian		if (iflag) {
77317486Sjulian			#define MAX_IFACES	400
77417486Sjulian			int			sock;
77517486Sjulian			struct ifreq		iflist[MAX_IFACES];
77617486Sjulian			struct ifconf		ifconf;
77717486Sjulian			struct ifreq		*ifr, *ifr_end;
77817486Sjulian			struct sockaddr_dl	*dl, *sdl = NULL;
77917486Sjulian
78017486Sjulian			/* Get socket */
78117486Sjulian			if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
78217486Sjulian				err(1, "socket");
78317486Sjulian
78417486Sjulian			/* Get interface list */
78517486Sjulian			ifconf.ifc_req = iflist;
78617486Sjulian			ifconf.ifc_len = sizeof(iflist);
78717486Sjulian			if (ioctl(sock, SIOCGIFCONF, &ifconf) < 0)
78817486Sjulian				err(1, "ioctl(SIOCGIFCONF)");
78917486Sjulian			close(sock);
79017486Sjulian
79117486Sjulian			/* Look for this interface in the list */
79217486Sjulian			for (ifr = ifconf.ifc_req,
79317486Sjulian			    ifr_end = (struct ifreq *)
79417486Sjulian				(ifconf.ifc_buf + ifconf.ifc_len);
79517486Sjulian			    ifr < ifr_end;
79617486Sjulian			    ifr = (struct ifreq *) ((char *) &ifr->ifr_addr
79717486Sjulian						    + ifr->ifr_addr.sa_len)) {
79817486Sjulian				dl = (struct sockaddr_dl *)&ifr->ifr_addr;
79917486Sjulian				if (ifr->ifr_addr.sa_family == AF_LINK
80017486Sjulian				    && (ifr->ifr_flags & IFF_POINTOPOINT)
80117486Sjulian				    && !strncmp(s, dl->sdl_data, dl->sdl_nlen)
80217486Sjulian				    && s[dl->sdl_nlen] == 0) {
80317486Sjulian					sdl = dl;
80417486Sjulian					break;
80517486Sjulian				}
80617486Sjulian			}
80717486Sjulian
80817486Sjulian			/* If we found it, then use it */
80917486Sjulian			if (sdl) {
81017486Sjulian				su->sdl = *sdl;
81117486Sjulian				return(1);
81217486Sjulian			}
81317486Sjulian		}
8141558Srgrimes		break;
8151558Srgrimes	case RTA_NETMASK:
8161558Srgrimes		su = &so_mask;
8171558Srgrimes		break;
8181558Srgrimes	case RTA_GENMASK:
8191558Srgrimes		su = &so_genmask;
8201558Srgrimes		break;
8211558Srgrimes	case RTA_IFP:
8221558Srgrimes		su = &so_ifp;
8231558Srgrimes		break;
8241558Srgrimes	case RTA_IFA:
8251558Srgrimes		su = &so_ifa;
8261558Srgrimes		break;
8271558Srgrimes	default:
82837907Scharnier		usage("internal error");
8291558Srgrimes		/*NOTREACHED*/
8301558Srgrimes	}
8311558Srgrimes	su->sa.sa_len = aflen;
83227500Sjulian	su->sa.sa_family = af; /* cases that don't want it have left already */
8331558Srgrimes	if (strcmp(s, "default") == 0) {
83427500Sjulian		/*
83527500Sjulian		 * Default is net 0.0.0.0/0
83627500Sjulian		 */
8371558Srgrimes		switch (which) {
8381558Srgrimes		case RTA_DST:
8391558Srgrimes			forcenet++;
84027500Sjulian			/* bzero(su, sizeof(*su)); *//* for readability */
8411558Srgrimes			(void) getaddr(RTA_NETMASK, s, 0);
8421558Srgrimes			break;
8431558Srgrimes		case RTA_NETMASK:
8441558Srgrimes		case RTA_GENMASK:
84527500Sjulian			/* bzero(su, sizeof(*su)); *//* for readability */
8461558Srgrimes		}
8471558Srgrimes		return (0);
8481558Srgrimes	}
8491558Srgrimes	switch (af) {
85014092Swollman#ifdef NS
8511558Srgrimes	case AF_NS:
8521558Srgrimes		if (which == RTA_DST) {
8531558Srgrimes			extern short ns_bh[3];
8541558Srgrimes			struct sockaddr_ns *sms = &(so_mask.sns);
8551558Srgrimes			bzero((char *)sms, sizeof(*sms));
8561558Srgrimes			sms->sns_family = 0;
8571558Srgrimes			sms->sns_len = 6;
8581558Srgrimes			sms->sns_addr.x_net = *(union ns_net *)ns_bh;
8591558Srgrimes			rtm_addrs |= RTA_NETMASK;
8601558Srgrimes		}
8611558Srgrimes		su->sns.sns_addr = ns_addr(s);
8621558Srgrimes		return (!ns_nullhost(su->sns.sns_addr));
86314092Swollman#endif
8641558Srgrimes
8651558Srgrimes
86617046Sjulian	case AF_APPLETALK:
86717046Sjulian		if (!atalk_aton(s, &su->sat.sat_addr))
86817046Sjulian			errx(EX_NOHOST, "bad address: %s", s);
86917265Sjulian		rtm_addrs |= RTA_NETMASK;
87017265Sjulian		return(forcehost || su->sat.sat_addr.s_node != 0);
87117046Sjulian
8721558Srgrimes	case AF_LINK:
8731558Srgrimes		link_addr(s, &su->sdl);
8741558Srgrimes		return (1);
8751558Srgrimes
8761558Srgrimes
8771558Srgrimes	case PF_ROUTE:
8781558Srgrimes		su->sa.sa_len = sizeof(*su);
8791558Srgrimes		sockaddr(s, &su->sa);
8801558Srgrimes		return (1);
8811558Srgrimes
8821558Srgrimes	case AF_INET:
8831558Srgrimes	default:
8841558Srgrimes		break;
8851558Srgrimes	}
8861558Srgrimes
8871558Srgrimes	if (hpp == NULL)
8881558Srgrimes		hpp = &hp;
8891558Srgrimes	*hpp = NULL;
89024558Sphk
89124558Sphk	q = strchr(s,'/');
89224558Sphk	if (q && which == RTA_DST) {
89324558Sphk		qs = *q;
89424558Sphk		*q = '\0';
89524558Sphk		if (((val = inet_addr(s)) != INADDR_NONE)) {
89624558Sphk			inet_makenetandmask(
89724558Sphk				htonl(val), &su->sin, strtoul(q+1, 0, 0));
89824558Sphk			return (0);
89924558Sphk		}
90024558Sphk		*q =qs;
90124558Sphk	}
90214132Smpp	if (((val = inet_addr(s)) != INADDR_NONE) &&
9031558Srgrimes	    (which != RTA_DST || forcenet == 0)) {
9041558Srgrimes		su->sin.sin_addr.s_addr = val;
9051558Srgrimes		if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
9061558Srgrimes			return (1);
9071558Srgrimes		else {
9081558Srgrimes			val = ntohl(val);
9091558Srgrimes			goto netdone;
9101558Srgrimes		}
9111558Srgrimes	}
91214132Smpp	if ((val = inet_network(s)) != INADDR_NONE ||
91319209Sfenner	    (forcehost == 0 && (np = getnetbyname(s)) != NULL &&
91419209Sfenner		    (val = np->n_net) != 0)) {
9151558Srgrimesnetdone:
9161558Srgrimes		if (which == RTA_DST)
91724558Sphk			inet_makenetandmask(val, &su->sin, 0);
9181558Srgrimes		return (0);
9191558Srgrimes	}
9201558Srgrimes	hp = gethostbyname(s);
9211558Srgrimes	if (hp) {
9221558Srgrimes		*hpp = hp;
9231558Srgrimes		su->sin.sin_family = hp->h_addrtype;
92431958Simp		bcopy(hp->h_addr, (char *)&su->sin.sin_addr,
92532008Simp		    MIN(hp->h_length, sizeof(su->sin.sin_addr)));
9261558Srgrimes		return (1);
9271558Srgrimes	}
92813515Smpp	errx(EX_NOHOST, "bad address: %s", s);
9291558Srgrimes}
9301558Srgrimes
9311558Srgrimes
93214092Swollman#ifdef NS
9331558Srgrimesshort ns_nullh[] = {0,0,0};
9341558Srgrimesshort ns_bh[] = {-1,-1,-1};
9351558Srgrimes
9361558Srgrimeschar *
9371558Srgrimesns_print(sns)
9381558Srgrimes	struct sockaddr_ns *sns;
9391558Srgrimes{
9401558Srgrimes	struct ns_addr work;
9411558Srgrimes	union { union ns_net net_e; u_long long_e; } net;
9421558Srgrimes	u_short port;
94322953Sroberto	static char mybuf[50+MAXHOSTNAMELEN], cport[10], chost[25];
9441558Srgrimes	char *host = "";
9451558Srgrimes	register char *p;
9461558Srgrimes	register u_char *q;
9471558Srgrimes
9481558Srgrimes	work = sns->sns_addr;
9491558Srgrimes	port = ntohs(work.x_port);
9501558Srgrimes	work.x_port = 0;
9511558Srgrimes	net.net_e  = work.x_net;
9521558Srgrimes	if (ns_nullhost(work) && net.long_e == 0) {
9531558Srgrimes		if (!port)
9541558Srgrimes			return ("*.*");
9551558Srgrimes		(void) sprintf(mybuf, "*.%XH", port);
9561558Srgrimes		return (mybuf);
9571558Srgrimes	}
9581558Srgrimes
9591558Srgrimes	if (bcmp((char *)ns_bh, (char *)work.x_host.c_host, 6) == 0)
9601558Srgrimes		host = "any";
9611558Srgrimes	else if (bcmp((char *)ns_nullh, (char *)work.x_host.c_host, 6) == 0)
9621558Srgrimes		host = "*";
9631558Srgrimes	else {
9641558Srgrimes		q = work.x_host.c_host;
9651558Srgrimes		(void) sprintf(chost, "%02X%02X%02X%02X%02X%02XH",
9661558Srgrimes			q[0], q[1], q[2], q[3], q[4], q[5]);
9671558Srgrimes		for (p = chost; *p == '0' && p < chost + 12; p++)
9681558Srgrimes			/* void */;
9691558Srgrimes		host = p;
9701558Srgrimes	}
9711558Srgrimes	if (port)
9721558Srgrimes		(void) sprintf(cport, ".%XH", htons(port));
9731558Srgrimes	else
9741558Srgrimes		*cport = 0;
9751558Srgrimes
97622953Sroberto	(void) snprintf(mybuf, sizeof(mybuf), "%lxH.%s%s",
97722953Sroberto                    (unsigned long)ntohl(net.long_e),
97813171Swollman		       host, cport);
9791558Srgrimes	return (mybuf);
9801558Srgrimes}
98114092Swollman#endif
9821558Srgrimes
9831558Srgrimesvoid
9841558Srgrimesinterfaces()
9851558Srgrimes{
9861558Srgrimes	size_t needed;
9871558Srgrimes	int mib[6];
9881558Srgrimes	char *buf, *lim, *next;
9891558Srgrimes	register struct rt_msghdr *rtm;
9901558Srgrimes
9911558Srgrimes	mib[0] = CTL_NET;
9921558Srgrimes	mib[1] = PF_ROUTE;
9931558Srgrimes	mib[2] = 0;		/* protocol */
9941558Srgrimes	mib[3] = 0;		/* wildcard address family */
9951558Srgrimes	mib[4] = NET_RT_IFLIST;
9961558Srgrimes	mib[5] = 0;		/* no flags */
9971558Srgrimes	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
99813171Swollman		err(EX_OSERR, "route-sysctl-estimate");
9991558Srgrimes	if ((buf = malloc(needed)) == NULL)
100037907Scharnier		errx(EX_OSERR, "malloc failed");
10011558Srgrimes	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
100213171Swollman		err(EX_OSERR, "actual retrieval of interface table");
10031558Srgrimes	lim = buf + needed;
10041558Srgrimes	for (next = buf; next < lim; next += rtm->rtm_msglen) {
10051558Srgrimes		rtm = (struct rt_msghdr *)next;
10061558Srgrimes		print_rtmsg(rtm, rtm->rtm_msglen);
10071558Srgrimes	}
10081558Srgrimes}
10091558Srgrimes
10101558Srgrimesvoid
10111558Srgrimesmonitor()
10121558Srgrimes{
10131558Srgrimes	int n;
10141558Srgrimes	char msg[2048];
10151558Srgrimes
10161558Srgrimes	verbose = 1;
10171558Srgrimes	if (debugonly) {
10181558Srgrimes		interfaces();
10191558Srgrimes		exit(0);
10201558Srgrimes	}
10211558Srgrimes	for(;;) {
10221558Srgrimes		n = read(s, msg, 2048);
10231558Srgrimes		(void) printf("got message of size %d\n", n);
10241558Srgrimes		print_rtmsg((struct rt_msghdr *)msg, n);
10251558Srgrimes	}
10261558Srgrimes}
10271558Srgrimes
10281558Srgrimesstruct {
10291558Srgrimes	struct	rt_msghdr m_rtm;
10301558Srgrimes	char	m_space[512];
10311558Srgrimes} m_rtmsg;
10321558Srgrimes
10331558Srgrimesint
10341558Srgrimesrtmsg(cmd, flags)
10351558Srgrimes	int cmd, flags;
10361558Srgrimes{
10371558Srgrimes	static int seq;
10381558Srgrimes	int rlen;
10391558Srgrimes	register char *cp = m_rtmsg.m_space;
10401558Srgrimes	register int l;
10411558Srgrimes
10421558Srgrimes#define NEXTADDR(w, u) \
10431558Srgrimes	if (rtm_addrs & (w)) {\
10441558Srgrimes	    l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\
10451558Srgrimes	    if (verbose) sodump(&(u),"u");\
10461558Srgrimes	}
10471558Srgrimes
10481558Srgrimes	errno = 0;
10491558Srgrimes	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
10501558Srgrimes	if (cmd == 'a')
10511558Srgrimes		cmd = RTM_ADD;
10521558Srgrimes	else if (cmd == 'c')
10531558Srgrimes		cmd = RTM_CHANGE;
10541558Srgrimes	else if (cmd == 'g') {
10551558Srgrimes		cmd = RTM_GET;
10561558Srgrimes		if (so_ifp.sa.sa_family == 0) {
105713171Swollman			so_ifp.sa.sa_family = AF_LINK;
105813171Swollman			so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
10591558Srgrimes			rtm_addrs |= RTA_IFP;
10601558Srgrimes		}
10611558Srgrimes	} else
10621558Srgrimes		cmd = RTM_DELETE;
10631558Srgrimes#define rtm m_rtmsg.m_rtm
10641558Srgrimes	rtm.rtm_type = cmd;
10651558Srgrimes	rtm.rtm_flags = flags;
10661558Srgrimes	rtm.rtm_version = RTM_VERSION;
10671558Srgrimes	rtm.rtm_seq = ++seq;
10681558Srgrimes	rtm.rtm_addrs = rtm_addrs;
10691558Srgrimes	rtm.rtm_rmx = rt_metrics;
10701558Srgrimes	rtm.rtm_inits = rtm_inits;
10711558Srgrimes
10721558Srgrimes	if (rtm_addrs & RTA_NETMASK)
10731558Srgrimes		mask_addr();
10741558Srgrimes	NEXTADDR(RTA_DST, so_dst);
10751558Srgrimes	NEXTADDR(RTA_GATEWAY, so_gate);
10761558Srgrimes	NEXTADDR(RTA_NETMASK, so_mask);
10771558Srgrimes	NEXTADDR(RTA_GENMASK, so_genmask);
10781558Srgrimes	NEXTADDR(RTA_IFP, so_ifp);
10791558Srgrimes	NEXTADDR(RTA_IFA, so_ifa);
10801558Srgrimes	rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
10811558Srgrimes	if (verbose)
10821558Srgrimes		print_rtmsg(&rtm, l);
10831558Srgrimes	if (debugonly)
10841558Srgrimes		return (0);
10851558Srgrimes	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
108637907Scharnier		warn("writing to routing socket");
10871558Srgrimes		return (-1);
10881558Srgrimes	}
10891558Srgrimes	if (cmd == RTM_GET) {
10901558Srgrimes		do {
10911558Srgrimes			l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
10921558Srgrimes		} while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
10931558Srgrimes		if (l < 0)
109413171Swollman			warn("read from routing socket");
10951558Srgrimes		else
10961558Srgrimes			print_getmsg(&rtm, l);
10971558Srgrimes	}
10981558Srgrimes#undef rtm
10991558Srgrimes	return (0);
11001558Srgrimes}
11011558Srgrimes
11021558Srgrimesvoid
11031558Srgrimesmask_addr()
11041558Srgrimes{
11051558Srgrimes	int olen = so_mask.sa.sa_len;
11061558Srgrimes	register char *cp1 = olen + (char *)&so_mask, *cp2;
11071558Srgrimes
11081558Srgrimes	for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; )
11091558Srgrimes		if (*--cp1 != 0) {
11101558Srgrimes			so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask;
11111558Srgrimes			break;
11121558Srgrimes		}
11131558Srgrimes	if ((rtm_addrs & RTA_DST) == 0)
11141558Srgrimes		return;
11151558Srgrimes	switch (so_dst.sa.sa_family) {
111614092Swollman#ifdef NS
11171558Srgrimes	case AF_NS:
111814092Swollman#endif
11191558Srgrimes	case AF_INET:
112017046Sjulian	case AF_APPLETALK:
11211558Srgrimes	case 0:
11221558Srgrimes		return;
11231558Srgrimes	}
11241558Srgrimes	cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
11251558Srgrimes	cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
11261558Srgrimes	while (cp2 > cp1)
11271558Srgrimes		*--cp2 = 0;
11281558Srgrimes	cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
11291558Srgrimes	while (cp1 > so_dst.sa.sa_data)
11301558Srgrimes		*--cp1 &= *--cp2;
11311558Srgrimes}
11321558Srgrimes
11331558Srgrimeschar *msgtypes[] = {
11341558Srgrimes	"",
11351558Srgrimes	"RTM_ADD: Add Route",
11361558Srgrimes	"RTM_DELETE: Delete Route",
11371558Srgrimes	"RTM_CHANGE: Change Metrics or flags",
11381558Srgrimes	"RTM_GET: Report Metrics",
11391558Srgrimes	"RTM_LOSING: Kernel Suspects Partitioning",
11401558Srgrimes	"RTM_REDIRECT: Told to use different route",
11411558Srgrimes	"RTM_MISS: Lookup failed on this address",
11421558Srgrimes	"RTM_LOCK: fix specified metrics",
11431558Srgrimes	"RTM_OLDADD: caused by SIOCADDRT",
11441558Srgrimes	"RTM_OLDDEL: caused by SIOCDELRT",
11451558Srgrimes	"RTM_RESOLVE: Route created by cloning",
11461558Srgrimes	"RTM_NEWADDR: address being added to iface",
11471558Srgrimes	"RTM_DELADDR: address being removed from iface",
11481558Srgrimes	"RTM_IFINFO: iface status change",
114921465Swollman	"RTM_NEWMADDR: new multicast group membership on iface",
115021465Swollman	"RTM_DELMADDR: multicast group membership removed from iface",
11511558Srgrimes	0,
11521558Srgrimes};
11531558Srgrimes
11541558Srgrimeschar metricnames[] =
115515690Swollman"\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
115615690Swollman"\1mtu";
11571558Srgrimeschar routeflags[] =
115815690Swollman"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"
115915690Swollman"\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016"
116015690Swollman"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024CHAINDELETE"
116115690Swollman"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST";
11621558Srgrimeschar ifnetflags[] =
116315690Swollman"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
116415690Swollman"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
116515690Swollman"\017LINK2\020MULTICAST";
11661558Srgrimeschar addrnames[] =
11671558Srgrimes"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
11681558Srgrimes
11691558Srgrimesvoid
11701558Srgrimesprint_rtmsg(rtm, msglen)
11711558Srgrimes	register struct rt_msghdr *rtm;
11721558Srgrimes	int msglen;
11731558Srgrimes{
11741558Srgrimes	struct if_msghdr *ifm;
11751558Srgrimes	struct ifa_msghdr *ifam;
117621465Swollman#ifdef RTM_NEWMADDR
117721465Swollman	struct ifma_msghdr *ifmam;
117821465Swollman#endif
11791558Srgrimes
11801558Srgrimes	if (verbose == 0)
11811558Srgrimes		return;
11821558Srgrimes	if (rtm->rtm_version != RTM_VERSION) {
11831558Srgrimes		(void) printf("routing message version %d not understood\n",
11841558Srgrimes		    rtm->rtm_version);
11851558Srgrimes		return;
11861558Srgrimes	}
11871558Srgrimes	(void)printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen);
11881558Srgrimes	switch (rtm->rtm_type) {
11891558Srgrimes	case RTM_IFINFO:
11901558Srgrimes		ifm = (struct if_msghdr *)rtm;
11911558Srgrimes		(void) printf("if# %d, flags:", ifm->ifm_index);
11921558Srgrimes		bprintf(stdout, ifm->ifm_flags, ifnetflags);
11931558Srgrimes		pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
11941558Srgrimes		break;
11951558Srgrimes	case RTM_NEWADDR:
11961558Srgrimes	case RTM_DELADDR:
11971558Srgrimes		ifam = (struct ifa_msghdr *)rtm;
11981558Srgrimes		(void) printf("metric %d, flags:", ifam->ifam_metric);
11991558Srgrimes		bprintf(stdout, ifam->ifam_flags, routeflags);
12001558Srgrimes		pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
12011558Srgrimes		break;
120221465Swollman#ifdef RTM_NEWMADDR
120321465Swollman	case RTM_NEWMADDR:
120421465Swollman	case RTM_DELMADDR:
120521465Swollman		ifmam = (struct ifma_msghdr *)rtm;
120621465Swollman		pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs);
120721465Swollman		break;
120821465Swollman#endif
12091558Srgrimes	default:
121013171Swollman		(void) printf("pid: %ld, seq %d, errno %d, flags:",
121113171Swollman			(long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
12121558Srgrimes		bprintf(stdout, rtm->rtm_flags, routeflags);
12131558Srgrimes		pmsg_common(rtm);
12141558Srgrimes	}
12151558Srgrimes}
12161558Srgrimes
12171558Srgrimesvoid
12181558Srgrimesprint_getmsg(rtm, msglen)
12191558Srgrimes	register struct rt_msghdr *rtm;
12201558Srgrimes	int msglen;
12211558Srgrimes{
12221558Srgrimes	struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
12231558Srgrimes	struct sockaddr_dl *ifp = NULL;
12241558Srgrimes	register struct sockaddr *sa;
12251558Srgrimes	register char *cp;
12261558Srgrimes	register int i;
12271558Srgrimes
12281558Srgrimes	(void) printf("   route to: %s\n", routename(&so_dst));
12291558Srgrimes	if (rtm->rtm_version != RTM_VERSION) {
123013171Swollman		warnx("routing message version %d not understood",
123113171Swollman		     rtm->rtm_version);
12321558Srgrimes		return;
12331558Srgrimes	}
12341558Srgrimes	if (rtm->rtm_msglen > msglen) {
123537907Scharnier		warnx("message length mismatch, in packet %d, returned %d",
123613171Swollman		      rtm->rtm_msglen, msglen);
12371558Srgrimes	}
12381558Srgrimes	if (rtm->rtm_errno)  {
123913171Swollman		errno = rtm->rtm_errno;
124013171Swollman		warn("message indicates error %d", errno);
12411558Srgrimes		return;
12421558Srgrimes	}
12431558Srgrimes	cp = ((char *)(rtm + 1));
12441558Srgrimes	if (rtm->rtm_addrs)
12451558Srgrimes		for (i = 1; i; i <<= 1)
12461558Srgrimes			if (i & rtm->rtm_addrs) {
12471558Srgrimes				sa = (struct sockaddr *)cp;
12481558Srgrimes				switch (i) {
12491558Srgrimes				case RTA_DST:
12501558Srgrimes					dst = sa;
12511558Srgrimes					break;
12521558Srgrimes				case RTA_GATEWAY:
12531558Srgrimes					gate = sa;
12541558Srgrimes					break;
12551558Srgrimes				case RTA_NETMASK:
12561558Srgrimes					mask = sa;
12571558Srgrimes					break;
12581558Srgrimes				case RTA_IFP:
12591558Srgrimes					if (sa->sa_family == AF_LINK &&
12601558Srgrimes					   ((struct sockaddr_dl *)sa)->sdl_nlen)
12611558Srgrimes						ifp = (struct sockaddr_dl *)sa;
12621558Srgrimes					break;
12631558Srgrimes				}
12641558Srgrimes				ADVANCE(cp, sa);
12651558Srgrimes			}
12661558Srgrimes	if (dst && mask)
12671558Srgrimes		mask->sa_family = dst->sa_family;	/* XXX */
12681558Srgrimes	if (dst)
12691558Srgrimes		(void)printf("destination: %s\n", routename(dst));
12701558Srgrimes	if (mask) {
12711558Srgrimes		int savenflag = nflag;
12721558Srgrimes
12731558Srgrimes		nflag = 1;
12741558Srgrimes		(void)printf("       mask: %s\n", routename(mask));
12751558Srgrimes		nflag = savenflag;
12761558Srgrimes	}
12771558Srgrimes	if (gate && rtm->rtm_flags & RTF_GATEWAY)
12781558Srgrimes		(void)printf("    gateway: %s\n", routename(gate));
12791558Srgrimes	if (ifp)
12801558Srgrimes		(void)printf("  interface: %.*s\n",
12811558Srgrimes		    ifp->sdl_nlen, ifp->sdl_data);
12821558Srgrimes	(void)printf("      flags: ");
12831558Srgrimes	bprintf(stdout, rtm->rtm_flags, routeflags);
12841558Srgrimes
12851558Srgrimes#define lock(f)	((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
12861558Srgrimes#define msec(u)	(((u) + 500) / 1000)		/* usec to msec */
12871558Srgrimes
12881558Srgrimes	(void) printf("\n%s\n", "\
12891558Srgrimes recvpipe  sendpipe  ssthresh  rtt,msec    rttvar  hopcount      mtu     expire");
129013171Swollman	printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
129113171Swollman	printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
129213171Swollman	printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
129313171Swollman	printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
129413171Swollman	printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
129513171Swollman	printf("%8ld%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
129613171Swollman	printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
12971558Srgrimes	if (rtm->rtm_rmx.rmx_expire)
12981558Srgrimes		rtm->rtm_rmx.rmx_expire -= time(0);
129913171Swollman	printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
13001558Srgrimes#undef lock
13011558Srgrimes#undef msec
13021558Srgrimes#define	RTA_IGN	(RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
13031558Srgrimes	if (verbose)
13041558Srgrimes		pmsg_common(rtm);
13051558Srgrimes	else if (rtm->rtm_addrs &~ RTA_IGN) {
13061558Srgrimes		(void) printf("sockaddrs: ");
13071558Srgrimes		bprintf(stdout, rtm->rtm_addrs, addrnames);
13081558Srgrimes		putchar('\n');
13091558Srgrimes	}
13101558Srgrimes#undef	RTA_IGN
13111558Srgrimes}
13121558Srgrimes
13131558Srgrimesvoid
13141558Srgrimespmsg_common(rtm)
13151558Srgrimes	register struct rt_msghdr *rtm;
13161558Srgrimes{
13171558Srgrimes	(void) printf("\nlocks: ");
13181558Srgrimes	bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
13191558Srgrimes	(void) printf(" inits: ");
13201558Srgrimes	bprintf(stdout, rtm->rtm_inits, metricnames);
13211558Srgrimes	pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
13221558Srgrimes}
13231558Srgrimes
13241558Srgrimesvoid
13251558Srgrimespmsg_addrs(cp, addrs)
13261558Srgrimes	char	*cp;
13271558Srgrimes	int	addrs;
13281558Srgrimes{
13291558Srgrimes	register struct sockaddr *sa;
13301558Srgrimes	int i;
13311558Srgrimes
13321558Srgrimes	if (addrs == 0)
13331558Srgrimes		return;
13341558Srgrimes	(void) printf("\nsockaddrs: ");
13351558Srgrimes	bprintf(stdout, addrs, addrnames);
13361558Srgrimes	(void) putchar('\n');
13371558Srgrimes	for (i = 1; i; i <<= 1)
13381558Srgrimes		if (i & addrs) {
13391558Srgrimes			sa = (struct sockaddr *)cp;
13401558Srgrimes			(void) printf(" %s", routename(sa));
13411558Srgrimes			ADVANCE(cp, sa);
13421558Srgrimes		}
13431558Srgrimes	(void) putchar('\n');
13441558Srgrimes	(void) fflush(stdout);
13451558Srgrimes}
13461558Srgrimes
13471558Srgrimesvoid
13481558Srgrimesbprintf(fp, b, s)
13491558Srgrimes	register FILE *fp;
13501558Srgrimes	register int b;
13511558Srgrimes	register u_char *s;
13521558Srgrimes{
13531558Srgrimes	register int i;
13541558Srgrimes	int gotsome = 0;
13551558Srgrimes
13561558Srgrimes	if (b == 0)
13571558Srgrimes		return;
135813171Swollman	while ((i = *s++) != 0) {
13591558Srgrimes		if (b & (1 << (i-1))) {
13601558Srgrimes			if (gotsome == 0)
13611558Srgrimes				i = '<';
13621558Srgrimes			else
13631558Srgrimes				i = ',';
13641558Srgrimes			(void) putc(i, fp);
13651558Srgrimes			gotsome = 1;
13661558Srgrimes			for (; (i = *s) > 32; s++)
13671558Srgrimes				(void) putc(i, fp);
13681558Srgrimes		} else
13691558Srgrimes			while (*s > 32)
13701558Srgrimes				s++;
13711558Srgrimes	}
13721558Srgrimes	if (gotsome)
13731558Srgrimes		(void) putc('>', fp);
13741558Srgrimes}
13751558Srgrimes
13761558Srgrimesint
13771558Srgrimeskeyword(cp)
13781558Srgrimes	char *cp;
13791558Srgrimes{
13801558Srgrimes	register struct keytab *kt = keywords;
13811558Srgrimes
13821558Srgrimes	while (kt->kt_cp && strcmp(kt->kt_cp, cp))
13831558Srgrimes		kt++;
13841558Srgrimes	return kt->kt_i;
13851558Srgrimes}
13861558Srgrimes
13871558Srgrimesvoid
13881558Srgrimessodump(su, which)
13891558Srgrimes	register sup su;
13901558Srgrimes	char *which;
13911558Srgrimes{
13921558Srgrimes	switch (su->sa.sa_family) {
13931558Srgrimes	case AF_LINK:
13941558Srgrimes		(void) printf("%s: link %s; ",
13951558Srgrimes		    which, link_ntoa(&su->sdl));
13961558Srgrimes		break;
13971558Srgrimes	case AF_INET:
13981558Srgrimes		(void) printf("%s: inet %s; ",
13991558Srgrimes		    which, inet_ntoa(su->sin.sin_addr));
14001558Srgrimes		break;
140117046Sjulian	case AF_APPLETALK:
140217046Sjulian		(void) printf("%s: atalk %s; ",
140317046Sjulian		    which, atalk_ntoa(su->sat.sat_addr));
140417046Sjulian		break;
140514092Swollman#ifdef NS
14061558Srgrimes	case AF_NS:
14071558Srgrimes		(void) printf("%s: xns %s; ",
14081558Srgrimes		    which, ns_ntoa(su->sns.sns_addr));
14091558Srgrimes		break;
141014092Swollman#endif
14111558Srgrimes	}
14121558Srgrimes	(void) fflush(stdout);
14131558Srgrimes}
14141558Srgrimes
14151558Srgrimes/* States*/
14161558Srgrimes#define VIRGIN	0
14171558Srgrimes#define GOTONE	1
14181558Srgrimes#define GOTTWO	2
14191558Srgrimes/* Inputs */
14201558Srgrimes#define	DIGIT	(4*0)
14211558Srgrimes#define	END	(4*1)
14221558Srgrimes#define DELIM	(4*2)
14231558Srgrimes
14241558Srgrimesvoid
14251558Srgrimessockaddr(addr, sa)
14261558Srgrimes	register char *addr;
14271558Srgrimes	register struct sockaddr *sa;
14281558Srgrimes{
14291558Srgrimes	register char *cp = (char *)sa;
14301558Srgrimes	int size = sa->sa_len;
14311558Srgrimes	char *cplim = cp + size;
143213171Swollman	register int byte = 0, state = VIRGIN, new = 0 /* foil gcc */;
14331558Srgrimes
14341558Srgrimes	bzero(cp, size);
14351558Srgrimes	cp++;
14361558Srgrimes	do {
14371558Srgrimes		if ((*addr >= '0') && (*addr <= '9')) {
14381558Srgrimes			new = *addr - '0';
14391558Srgrimes		} else if ((*addr >= 'a') && (*addr <= 'f')) {
14401558Srgrimes			new = *addr - 'a' + 10;
14411558Srgrimes		} else if ((*addr >= 'A') && (*addr <= 'F')) {
14421558Srgrimes			new = *addr - 'A' + 10;
14431558Srgrimes		} else if (*addr == 0)
14441558Srgrimes			state |= END;
14451558Srgrimes		else
14461558Srgrimes			state |= DELIM;
14471558Srgrimes		addr++;
14481558Srgrimes		switch (state /* | INPUT */) {
14491558Srgrimes		case GOTTWO | DIGIT:
14501558Srgrimes			*cp++ = byte; /*FALLTHROUGH*/
14511558Srgrimes		case VIRGIN | DIGIT:
14521558Srgrimes			state = GOTONE; byte = new; continue;
14531558Srgrimes		case GOTONE | DIGIT:
14541558Srgrimes			state = GOTTWO; byte = new + (byte << 4); continue;
14551558Srgrimes		default: /* | DELIM */
14561558Srgrimes			state = VIRGIN; *cp++ = byte; byte = 0; continue;
14571558Srgrimes		case GOTONE | END:
14581558Srgrimes		case GOTTWO | END:
14591558Srgrimes			*cp++ = byte; /* FALLTHROUGH */
14601558Srgrimes		case VIRGIN | END:
14611558Srgrimes			break;
14621558Srgrimes		}
14631558Srgrimes		break;
14641558Srgrimes	} while (cp < cplim);
14651558Srgrimes	sa->sa_len = cp - (char *)sa;
14661558Srgrimes}
146717046Sjulian
146817046Sjulianint
146917046Sjulianatalk_aton(const char *text, struct at_addr *addr)
147017046Sjulian{
147117046Sjulian	u_int net, node;
147217046Sjulian
147317046Sjulian	if (sscanf(text, "%u.%u", &net, &node) != 2
147417046Sjulian	    || net > 0xffff || node > 0xff)
147517046Sjulian		return(0);
147617254Sjulian	addr->s_net = htons(net);
147717046Sjulian	addr->s_node = node;
147817046Sjulian	return(1);
147917046Sjulian}
148017046Sjulian
148117046Sjulianchar *
148217046Sjulianatalk_ntoa(struct at_addr at)
148317046Sjulian{
148417046Sjulian	static char buf[20];
148517046Sjulian
148617254Sjulian	(void) snprintf(buf, sizeof(buf), "%u.%u", ntohs(at.s_net), at.s_node);
148717046Sjulian	return(buf);
148817046Sjulian}
1489