route.c revision 78064
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[] =
4550476Speter  "$FreeBSD: head/sbin/route/route.c 78064 2001-06-11 12:39:29Z ume $";
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>
5351639Sbillf#include <sys/types.h>
541558Srgrimes
551558Srgrimes#include <net/if.h>
561558Srgrimes#include <net/route.h>
571558Srgrimes#include <net/if_dl.h>
581558Srgrimes#include <netinet/in.h>
5917046Sjulian#include <netatalk/at.h>
6014092Swollman#ifdef NS
611558Srgrimes#include <netns/ns.h>
6214092Swollman#endif
631558Srgrimes#include <arpa/inet.h>
641558Srgrimes#include <netdb.h>
651558Srgrimes
6620287Swollman#include <ctype.h>
6720287Swollman#include <err.h>
681558Srgrimes#include <errno.h>
6969793Sobrien#include <paths.h>
701558Srgrimes#include <stdio.h>
711558Srgrimes#include <stdlib.h>
721558Srgrimes#include <string.h>
7313171Swollman#include <sysexits.h>
7420287Swollman#include <unistd.h>
7578064Sume#include <ifaddrs.h>
761558Srgrimes
771558Srgrimesstruct keytab {
781558Srgrimes	char	*kt_cp;
791558Srgrimes	int	kt_i;
801558Srgrimes} keywords[] = {
811558Srgrimes#include "keywords.h"
821558Srgrimes	{0, 0}
831558Srgrimes};
841558Srgrimes
851558Srgrimesstruct	ortentry route;
861558Srgrimesunion	sockunion {
871558Srgrimes	struct	sockaddr sa;
881558Srgrimes	struct	sockaddr_in sin;
8954263Sshin#ifdef INET6
9054263Sshin	struct	sockaddr_in6 sin6;
9154263Sshin#endif
9217046Sjulian	struct	sockaddr_at sat;
9314092Swollman#ifdef NS
941558Srgrimes	struct	sockaddr_ns sns;
9514092Swollman#endif
961558Srgrimes	struct	sockaddr_dl sdl;
9778064Sume	struct	sockaddr_storage ss; /* added to avoid memory overrun */
981558Srgrimes} so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
991558Srgrimes
1001558Srgrimestypedef union sockunion *sup;
1011558Srgrimesint	pid, rtm_addrs, uid;
1021558Srgrimesint	s;
1031558Srgrimesint	forcehost, forcenet, doflush, nflag, af, qflag, tflag, keyword();
1041558Srgrimesint	iflag, verbose, aflen = sizeof (struct sockaddr_in);
1051558Srgrimesint	locking, lockrest, debugonly;
1061558Srgrimesstruct	rt_metrics rt_metrics;
1071558Srgrimesu_long  rtm_inits;
10817046Sjulianint	atalk_aton __P((const char *, struct at_addr *));
10917046Sjulianchar	*atalk_ntoa __P((struct at_addr));
11078064Sumeconst char	*routename(), *netname();
1111558Srgrimesvoid	flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf();
1121558Srgrimesvoid	print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr();
1131558Srgrimesint	getaddr(), rtmsg(), x25_makemask();
11454263Sshinint	prefixlen();
11551639Sbillfextern	char *iso_ntoa();
1161558Srgrimes
11718286Sbdevoid usage __P((const char *)) __dead2;
11813171Swollman
11918286Sbdevoid
1201558Srgrimesusage(cp)
12113171Swollman	const char *cp;
1221558Srgrimes{
1231558Srgrimes	if (cp)
12413171Swollman		warnx("bad keyword: %s", cp);
1251558Srgrimes	(void) fprintf(stderr,
12637907Scharnier	    "usage: route [-dnqtv] command [[modifiers] args]\n");
12713171Swollman	exit(EX_USAGE);
1281558Srgrimes	/* NOTREACHED */
1291558Srgrimes}
1301558Srgrimes
1311558Srgrimes#define ROUNDUP(a) \
1321558Srgrimes	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
1331558Srgrimes#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
1341558Srgrimes
1351558Srgrimesint
1361558Srgrimesmain(argc, argv)
1371558Srgrimes	int argc;
1381558Srgrimes	char **argv;
1391558Srgrimes{
1401558Srgrimes	int ch;
1411558Srgrimes
1421558Srgrimes	if (argc < 2)
1431558Srgrimes		usage((char *)NULL);
1441558Srgrimes
14537907Scharnier	while ((ch = getopt(argc, argv, "nqdtv")) != -1)
1461558Srgrimes		switch(ch) {
1471558Srgrimes		case 'n':
1481558Srgrimes			nflag = 1;
1491558Srgrimes			break;
1501558Srgrimes		case 'q':
1511558Srgrimes			qflag = 1;
1521558Srgrimes			break;
1531558Srgrimes		case 'v':
1541558Srgrimes			verbose = 1;
1551558Srgrimes			break;
1561558Srgrimes		case 't':
1571558Srgrimes			tflag = 1;
1581558Srgrimes			break;
1591558Srgrimes		case 'd':
1601558Srgrimes			debugonly = 1;
1611558Srgrimes			break;
1621558Srgrimes		case '?':
1631558Srgrimes		default:
1641558Srgrimes			usage((char *)NULL);
1651558Srgrimes		}
1661558Srgrimes	argc -= optind;
1671558Srgrimes	argv += optind;
1681558Srgrimes
1691558Srgrimes	pid = getpid();
1701558Srgrimes	uid = getuid();
1711558Srgrimes	if (tflag)
17269793Sobrien		s = open(_PATH_DEVNULL, O_WRONLY, 0);
1731558Srgrimes	else
1741558Srgrimes		s = socket(PF_ROUTE, SOCK_RAW, 0);
1751558Srgrimes	if (s < 0)
17613171Swollman		err(EX_OSERR, "socket");
17719209Sfenner	setuid(uid);
1781558Srgrimes	if (*argv)
1791558Srgrimes		switch (keyword(*argv)) {
1801558Srgrimes		case K_GET:
1811558Srgrimes			uid = 0;
1821558Srgrimes			/* FALLTHROUGH */
1831558Srgrimes
1841558Srgrimes		case K_CHANGE:
1851558Srgrimes		case K_ADD:
1861558Srgrimes		case K_DELETE:
1871558Srgrimes			newroute(argc, argv);
1881558Srgrimes			/* NOTREACHED */
1891558Srgrimes
1901558Srgrimes		case K_MONITOR:
1911558Srgrimes			monitor();
1921558Srgrimes			/* NOTREACHED */
1931558Srgrimes
1941558Srgrimes		case K_FLUSH:
1951558Srgrimes			flushroutes(argc, argv);
1961558Srgrimes			exit(0);
1971558Srgrimes			/* NOTREACHED */
1981558Srgrimes		}
1991558Srgrimes	usage(*argv);
2001558Srgrimes	/* NOTREACHED */
2011558Srgrimes}
2021558Srgrimes
2031558Srgrimes/*
2041558Srgrimes * Purge all entries in the routing tables not
2051558Srgrimes * associated with network interfaces.
2061558Srgrimes */
2071558Srgrimesvoid
2081558Srgrimesflushroutes(argc, argv)
2091558Srgrimes	int argc;
2101558Srgrimes	char *argv[];
2111558Srgrimes{
2121558Srgrimes	size_t needed;
2131558Srgrimes	int mib[6], rlen, seqno;
2141558Srgrimes	char *buf, *next, *lim;
2151558Srgrimes	register struct rt_msghdr *rtm;
2161558Srgrimes
2171558Srgrimes	if (uid) {
21813171Swollman		errx(EX_NOPERM, "must be root to alter routing table");
2191558Srgrimes	}
2201558Srgrimes	shutdown(s, 0); /* Don't want to read back our messages */
2211558Srgrimes	if (argc > 1) {
2221558Srgrimes		argv++;
2231558Srgrimes		if (argc == 2 && **argv == '-')
2241558Srgrimes		    switch (keyword(*argv + 1)) {
2251558Srgrimes			case K_INET:
2261558Srgrimes				af = AF_INET;
2271558Srgrimes				break;
22854263Sshin#ifdef INET6
22954263Sshin			case K_INET6:
23054263Sshin				af = AF_INET6;
23154263Sshin				break;
23254263Sshin#endif
23317046Sjulian			case K_ATALK:
23417046Sjulian				af = AF_APPLETALK;
23517046Sjulian				break;
23614092Swollman#ifdef NS
2371558Srgrimes			case K_XNS:
2381558Srgrimes				af = AF_NS;
2391558Srgrimes				break;
24014092Swollman#endif
2411558Srgrimes			case K_LINK:
2421558Srgrimes				af = AF_LINK;
2431558Srgrimes				break;
2441558Srgrimes			default:
2451558Srgrimes				goto bad;
2461558Srgrimes		} else
2471558Srgrimesbad:			usage(*argv);
2481558Srgrimes	}
2491558Srgrimes	mib[0] = CTL_NET;
2501558Srgrimes	mib[1] = PF_ROUTE;
2511558Srgrimes	mib[2] = 0;		/* protocol */
2521558Srgrimes	mib[3] = 0;		/* wildcard address family */
2531558Srgrimes	mib[4] = NET_RT_DUMP;
2541558Srgrimes	mib[5] = 0;		/* no flags */
2551558Srgrimes	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
25613171Swollman		err(EX_OSERR, "route-sysctl-estimate");
2571558Srgrimes	if ((buf = malloc(needed)) == NULL)
25837907Scharnier		errx(EX_OSERR, "malloc failed");
2591558Srgrimes	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
26013171Swollman		err(EX_OSERR, "route-sysctl-get");
2611558Srgrimes	lim = buf + needed;
2621558Srgrimes	if (verbose)
2631558Srgrimes		(void) printf("Examining routing table from sysctl\n");
2641558Srgrimes	seqno = 0;		/* ??? */
2651558Srgrimes	for (next = buf; next < lim; next += rtm->rtm_msglen) {
2661558Srgrimes		rtm = (struct rt_msghdr *)next;
2671558Srgrimes		if (verbose)
2681558Srgrimes			print_rtmsg(rtm, rtm->rtm_msglen);
2691558Srgrimes		if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
2701558Srgrimes			continue;
2711558Srgrimes		if (af) {
2721558Srgrimes			struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
2731558Srgrimes
2741558Srgrimes			if (sa->sa_family != af)
2751558Srgrimes				continue;
2761558Srgrimes		}
2771558Srgrimes		if (debugonly)
2781558Srgrimes			continue;
2791558Srgrimes		rtm->rtm_type = RTM_DELETE;
2801558Srgrimes		rtm->rtm_seq = seqno;
2811558Srgrimes		rlen = write(s, next, rtm->rtm_msglen);
2821558Srgrimes		if (rlen < (int)rtm->rtm_msglen) {
28313171Swollman			warn("write to routing socket");
2841558Srgrimes			(void) printf("got only %d for rlen\n", rlen);
2851558Srgrimes			break;
2861558Srgrimes		}
2871558Srgrimes		seqno++;
2881558Srgrimes		if (qflag)
2891558Srgrimes			continue;
2901558Srgrimes		if (verbose)
2911558Srgrimes			print_rtmsg(rtm, rlen);
2921558Srgrimes		else {
2931558Srgrimes			struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
2941558Srgrimes			(void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
2951558Srgrimes			    routename(sa) : netname(sa));
29678064Sume			sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
2971558Srgrimes			(void) printf("%-20.20s ", routename(sa));
2981558Srgrimes			(void) printf("done\n");
2991558Srgrimes		}
3001558Srgrimes	}
3011558Srgrimes}
3021558Srgrimes
30378064Sumeconst char *
3041558Srgrimesroutename(sa)
3051558Srgrimes	struct sockaddr *sa;
3061558Srgrimes{
3071558Srgrimes	register char *cp;
30819209Sfenner	static char line[MAXHOSTNAMELEN + 1];
3091558Srgrimes	struct hostent *hp;
3101558Srgrimes	static char domain[MAXHOSTNAMELEN + 1];
3111558Srgrimes	static int first = 1;
31214092Swollman#ifdef NS
3131558Srgrimes	char *ns_print();
31414092Swollman#endif
3151558Srgrimes
3161558Srgrimes	if (first) {
3171558Srgrimes		first = 0;
3181558Srgrimes		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
31919209Sfenner		    (cp = index(domain, '.'))) {
32019209Sfenner			domain[MAXHOSTNAMELEN] = '\0';
3211558Srgrimes			(void) strcpy(domain, cp + 1);
32219209Sfenner		} else
3231558Srgrimes			domain[0] = 0;
3241558Srgrimes	}
3251558Srgrimes
3261558Srgrimes	if (sa->sa_len == 0)
3271558Srgrimes		strcpy(line, "default");
3281558Srgrimes	else switch (sa->sa_family) {
3291558Srgrimes
3301558Srgrimes	case AF_INET:
3311558Srgrimes	    {	struct in_addr in;
3321558Srgrimes		in = ((struct sockaddr_in *)sa)->sin_addr;
3331558Srgrimes
3341558Srgrimes		cp = 0;
3351558Srgrimes		if (in.s_addr == INADDR_ANY || sa->sa_len < 4)
3361558Srgrimes			cp = "default";
3371558Srgrimes		if (cp == 0 && !nflag) {
3381558Srgrimes			hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
3391558Srgrimes				AF_INET);
3401558Srgrimes			if (hp) {
3411558Srgrimes				if ((cp = index(hp->h_name, '.')) &&
3421558Srgrimes				    !strcmp(cp + 1, domain))
3431558Srgrimes					*cp = 0;
3441558Srgrimes				cp = hp->h_name;
3451558Srgrimes			}
3461558Srgrimes		}
34731958Simp		if (cp) {
34831958Simp			strncpy(line, cp, sizeof(line) - 1);
34931958Simp			line[sizeof(line) - 1] = '\0';
35077873Sru		} else
35177873Sru			(void) sprintf(line, "%s", inet_ntoa(in));
3521558Srgrimes		break;
3531558Srgrimes	    }
3541558Srgrimes
35554263Sshin#ifdef INET6
35654263Sshin	case AF_INET6:
35778064Sume	{
35878064Sume		struct sockaddr_in6 sin6; /* use static var for safety */
35978064Sume		int niflags = 0;
36078064Sume#ifdef NI_WITHSCOPEID
36178064Sume		niflags = NI_WITHSCOPEID;
36254263Sshin#endif
36354263Sshin
36478064Sume		memset(&sin6, 0, sizeof(sin6));
36578064Sume		memcpy(&sin6, sa, sa->sa_len);
36678064Sume		sin6.sin6_len = sizeof(struct sockaddr_in6);
36778064Sume		sin6.sin6_family = AF_INET6;
36878064Sume#ifdef __KAME__
36978064Sume		if (sa->sa_len == sizeof(struct sockaddr_in6) &&
37078064Sume		    (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
37178064Sume		     IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
37278064Sume		    sin6.sin6_scope_id == 0) {
37378064Sume			sin6.sin6_scope_id =
37478064Sume			    ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
37578064Sume			sin6.sin6_addr.s6_addr[2] = 0;
37678064Sume			sin6.sin6_addr.s6_addr[3] = 0;
37778064Sume		}
37878064Sume#endif
37978064Sume		if (nflag)
38078064Sume			niflags |= NI_NUMERICHOST;
38178064Sume		if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
38278064Sume		    line, sizeof(line), NULL, 0, niflags) != 0)
38378064Sume			strncpy(line, "invalid", sizeof(line));
38478064Sume
38578064Sume		return(line);
38678064Sume	}
38778064Sume#endif
38878064Sume
38917046Sjulian	case AF_APPLETALK:
39017046Sjulian		(void) snprintf(line, sizeof(line), "atalk %s",
39117046Sjulian			atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
39217046Sjulian		break;
39317046Sjulian
39414092Swollman#ifdef NS
3951558Srgrimes	case AF_NS:
3961558Srgrimes		return (ns_print((struct sockaddr_ns *)sa));
39714092Swollman#endif
3981558Srgrimes
3991558Srgrimes	case AF_LINK:
4001558Srgrimes		return (link_ntoa((struct sockaddr_dl *)sa));
4011558Srgrimes
4021558Srgrimes	default:
4031558Srgrimes	    {	u_short *s = (u_short *)sa;
4041558Srgrimes		u_short *slim = s + ((sa->sa_len + 1) >> 1);
4051558Srgrimes		char *cp = line + sprintf(line, "(%d)", sa->sa_family);
40619209Sfenner		char *cpe = line + sizeof(line);
4071558Srgrimes
40819209Sfenner		while (++s < slim && cp < cpe) /* start with sa->sa_data */
40919209Sfenner			cp += snprintf(cp, cpe - cp, " %x", *s);
4101558Srgrimes		break;
4111558Srgrimes	    }
4121558Srgrimes	}
4131558Srgrimes	return (line);
4141558Srgrimes}
4151558Srgrimes
4161558Srgrimes/*
4171558Srgrimes * Return the name of the network whose address is given.
4181558Srgrimes * The address is assumed to be that of a net or subnet, not a host.
4191558Srgrimes */
42078064Sumeconst char *
4211558Srgrimesnetname(sa)
4221558Srgrimes	struct sockaddr *sa;
4231558Srgrimes{
4241558Srgrimes	char *cp = 0;
42519209Sfenner	static char line[MAXHOSTNAMELEN + 1];
4261558Srgrimes	struct netent *np = 0;
4271558Srgrimes	u_long net, mask;
4281558Srgrimes	register u_long i;
4291558Srgrimes	int subnetshift;
43014092Swollman#ifdef NS
4311558Srgrimes	char *ns_print();
43214092Swollman#endif
4331558Srgrimes
4341558Srgrimes	switch (sa->sa_family) {
4351558Srgrimes
4361558Srgrimes	case AF_INET:
4371558Srgrimes	    {	struct in_addr in;
4381558Srgrimes		in = ((struct sockaddr_in *)sa)->sin_addr;
4391558Srgrimes
4401558Srgrimes		i = in.s_addr = ntohl(in.s_addr);
4411558Srgrimes		if (in.s_addr == 0)
4421558Srgrimes			cp = "default";
4431558Srgrimes		else if (!nflag) {
4441558Srgrimes			if (IN_CLASSA(i)) {
4451558Srgrimes				mask = IN_CLASSA_NET;
4461558Srgrimes				subnetshift = 8;
4471558Srgrimes			} else if (IN_CLASSB(i)) {
4481558Srgrimes				mask = IN_CLASSB_NET;
4491558Srgrimes				subnetshift = 8;
4501558Srgrimes			} else {
4511558Srgrimes				mask = IN_CLASSC_NET;
4521558Srgrimes				subnetshift = 4;
4531558Srgrimes			}
4541558Srgrimes			/*
4551558Srgrimes			 * If there are more bits than the standard mask
4561558Srgrimes			 * would suggest, subnets must be in use.
4571558Srgrimes			 * Guess at the subnet mask, assuming reasonable
4581558Srgrimes			 * width subnet fields.
4591558Srgrimes			 */
4601558Srgrimes			while (in.s_addr &~ mask)
4611558Srgrimes				mask = (long)mask >> subnetshift;
4621558Srgrimes			net = in.s_addr & mask;
4631558Srgrimes			while ((mask & 1) == 0)
4641558Srgrimes				mask >>= 1, net >>= 1;
4651558Srgrimes			np = getnetbyaddr(net, AF_INET);
4661558Srgrimes			if (np)
4671558Srgrimes				cp = np->n_name;
4681558Srgrimes		}
46977873Sru#define C(x)	(unsigned)((x) & 0xff)
4701558Srgrimes		if (cp)
47119209Sfenner			strncpy(line, cp, sizeof(line));
4721558Srgrimes		else if ((in.s_addr & 0xffffff) == 0)
4731558Srgrimes			(void) sprintf(line, "%u", C(in.s_addr >> 24));
4741558Srgrimes		else if ((in.s_addr & 0xffff) == 0)
4751558Srgrimes			(void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
4761558Srgrimes			    C(in.s_addr >> 16));
4771558Srgrimes		else if ((in.s_addr & 0xff) == 0)
4781558Srgrimes			(void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
4791558Srgrimes			    C(in.s_addr >> 16), C(in.s_addr >> 8));
4801558Srgrimes		else
4811558Srgrimes			(void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
4821558Srgrimes			    C(in.s_addr >> 16), C(in.s_addr >> 8),
4831558Srgrimes			    C(in.s_addr));
48477873Sru#undef C
4851558Srgrimes		break;
4861558Srgrimes	    }
4871558Srgrimes
48854263Sshin#ifdef INET6
48954263Sshin	case AF_INET6:
49078064Sume	{
49178064Sume		struct sockaddr_in6 sin6; /* use static var for safety */
49278064Sume		int niflags = 0;
49378064Sume#ifdef NI_WITHSCOPEID
49478064Sume		niflags = NI_WITHSCOPEID;
49554263Sshin#endif
49654263Sshin
49778064Sume		memset(&sin6, 0, sizeof(sin6));
49878064Sume		memcpy(&sin6, sa, sa->sa_len);
49978064Sume		sin6.sin6_len = sizeof(struct sockaddr_in6);
50078064Sume		sin6.sin6_family = AF_INET6;
50178064Sume#ifdef __KAME__
50278064Sume		if (sa->sa_len == sizeof(struct sockaddr_in6) &&
50378064Sume		    (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
50478064Sume		     IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
50578064Sume		    sin6.sin6_scope_id == 0) {
50678064Sume			sin6.sin6_scope_id =
50778064Sume			    ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
50878064Sume			sin6.sin6_addr.s6_addr[2] = 0;
50978064Sume			sin6.sin6_addr.s6_addr[3] = 0;
51078064Sume		}
51178064Sume#endif
51278064Sume		if (nflag)
51378064Sume			niflags |= NI_NUMERICHOST;
51478064Sume		if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
51578064Sume		    line, sizeof(line), NULL, 0, niflags) != 0)
51678064Sume			strncpy(line, "invalid", sizeof(line));
51778064Sume
51878064Sume		return(line);
51978064Sume	}
52078064Sume#endif
52178064Sume
52217046Sjulian	case AF_APPLETALK:
52317046Sjulian		(void) snprintf(line, sizeof(line), "atalk %s",
52417046Sjulian			atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
52517046Sjulian		break;
52617046Sjulian
52714092Swollman#ifdef NS
5281558Srgrimes	case AF_NS:
5291558Srgrimes		return (ns_print((struct sockaddr_ns *)sa));
5301558Srgrimes		break;
53114092Swollman#endif
5321558Srgrimes
5331558Srgrimes	case AF_LINK:
5341558Srgrimes		return (link_ntoa((struct sockaddr_dl *)sa));
5351558Srgrimes
5361558Srgrimes
5371558Srgrimes	default:
5381558Srgrimes	    {	u_short *s = (u_short *)sa->sa_data;
5391558Srgrimes		u_short *slim = s + ((sa->sa_len + 1)>>1);
5401558Srgrimes		char *cp = line + sprintf(line, "af %d:", sa->sa_family);
54119209Sfenner		char *cpe = line + sizeof(line);
5421558Srgrimes
54319209Sfenner		while (s < slim && cp < cpe)
54419209Sfenner			cp += snprintf(cp, cpe - cp, " %x", *s++);
5451558Srgrimes		break;
5461558Srgrimes	    }
5471558Srgrimes	}
5481558Srgrimes	return (line);
5491558Srgrimes}
5501558Srgrimes
5511558Srgrimesvoid
5521558Srgrimesset_metric(value, key)
5531558Srgrimes	char *value;
5541558Srgrimes	int key;
5551558Srgrimes{
5561558Srgrimes	int flag = 0;
5571558Srgrimes	u_long noval, *valp = &noval;
5581558Srgrimes
5591558Srgrimes	switch (key) {
5601558Srgrimes#define caseof(x, y, z)	case x: valp = &rt_metrics.z; flag = y; break
5611558Srgrimes	caseof(K_MTU, RTV_MTU, rmx_mtu);
5621558Srgrimes	caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
5631558Srgrimes	caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
5641558Srgrimes	caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
5651558Srgrimes	caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
5661558Srgrimes	caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
5671558Srgrimes	caseof(K_RTT, RTV_RTT, rmx_rtt);
5681558Srgrimes	caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
5691558Srgrimes	}
5701558Srgrimes	rtm_inits |= flag;
5711558Srgrimes	if (lockrest || locking)
5721558Srgrimes		rt_metrics.rmx_locks |= flag;
5731558Srgrimes	if (locking)
5741558Srgrimes		locking = 0;
5751558Srgrimes	*valp = atoi(value);
5761558Srgrimes}
5771558Srgrimes
5781558Srgrimesvoid
5791558Srgrimesnewroute(argc, argv)
5801558Srgrimes	int argc;
5811558Srgrimes	register char **argv;
5821558Srgrimes{
5831558Srgrimes	char *cmd, *dest = "", *gateway = "", *err;
5841558Srgrimes	int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC;
5851558Srgrimes	int key;
5861558Srgrimes	struct hostent *hp = 0;
5871558Srgrimes
5881558Srgrimes	if (uid) {
58913171Swollman		errx(EX_NOPERM, "must be root to alter routing table");
5901558Srgrimes	}
5911558Srgrimes	cmd = argv[0];
5921558Srgrimes	if (*cmd != 'g')
5931558Srgrimes		shutdown(s, 0); /* Don't want to read back our messages */
5941558Srgrimes	while (--argc > 0) {
5951558Srgrimes		if (**(++argv)== '-') {
5961558Srgrimes			switch (key = keyword(1 + *argv)) {
5971558Srgrimes			case K_LINK:
5981558Srgrimes				af = AF_LINK;
5991558Srgrimes				aflen = sizeof(struct sockaddr_dl);
6001558Srgrimes				break;
6011558Srgrimes			case K_INET:
6021558Srgrimes				af = AF_INET;
6031558Srgrimes				aflen = sizeof(struct sockaddr_in);
6041558Srgrimes				break;
60554263Sshin#ifdef INET6
60654263Sshin			case K_INET6:
60754263Sshin				af = AF_INET6;
60854263Sshin				aflen = sizeof(struct sockaddr_in6);
60954263Sshin				break;
61054263Sshin#endif
61117046Sjulian			case K_ATALK:
61217046Sjulian				af = AF_APPLETALK;
61317046Sjulian				aflen = sizeof(struct sockaddr_at);
61417046Sjulian				break;
6151558Srgrimes			case K_SA:
6161558Srgrimes				af = PF_ROUTE;
6171558Srgrimes				aflen = sizeof(union sockunion);
6181558Srgrimes				break;
61914092Swollman#ifdef NS
6201558Srgrimes			case K_XNS:
6211558Srgrimes				af = AF_NS;
6221558Srgrimes				aflen = sizeof(struct sockaddr_ns);
6231558Srgrimes				break;
62414092Swollman#endif
6251558Srgrimes			case K_IFACE:
6261558Srgrimes			case K_INTERFACE:
6271558Srgrimes				iflag++;
6282787Spst				break;
6291558Srgrimes			case K_NOSTATIC:
6301558Srgrimes				flags &= ~RTF_STATIC;
6311558Srgrimes				break;
63217591Sjulian			case K_LLINFO:
63317591Sjulian				flags |= RTF_LLINFO;
63417591Sjulian				break;
6351558Srgrimes			case K_LOCK:
6361558Srgrimes				locking = 1;
6371558Srgrimes				break;
6381558Srgrimes			case K_LOCKREST:
6391558Srgrimes				lockrest = 1;
6401558Srgrimes				break;
6411558Srgrimes			case K_HOST:
6421558Srgrimes				forcehost++;
6431558Srgrimes				break;
6441558Srgrimes			case K_REJECT:
6451558Srgrimes				flags |= RTF_REJECT;
6461558Srgrimes				break;
6471558Srgrimes			case K_BLACKHOLE:
6481558Srgrimes				flags |= RTF_BLACKHOLE;
6491558Srgrimes				break;
6501558Srgrimes			case K_PROTO1:
6511558Srgrimes				flags |= RTF_PROTO1;
6521558Srgrimes				break;
6531558Srgrimes			case K_PROTO2:
6541558Srgrimes				flags |= RTF_PROTO2;
6551558Srgrimes				break;
6561558Srgrimes			case K_CLONING:
6571558Srgrimes				flags |= RTF_CLONING;
6581558Srgrimes				break;
6591558Srgrimes			case K_XRESOLVE:
6601558Srgrimes				flags |= RTF_XRESOLVE;
6611558Srgrimes				break;
6621558Srgrimes			case K_STATIC:
6631558Srgrimes				flags |= RTF_STATIC;
6641558Srgrimes				break;
6651558Srgrimes			case K_IFA:
66647668Sru				if (!--argc)
66747668Sru					usage((char *)NULL);
6681558Srgrimes				(void) getaddr(RTA_IFA, *++argv, 0);
6691558Srgrimes				break;
6701558Srgrimes			case K_IFP:
67147668Sru				if (!--argc)
67247668Sru					usage((char *)NULL);
6731558Srgrimes				(void) getaddr(RTA_IFP, *++argv, 0);
6741558Srgrimes				break;
6751558Srgrimes			case K_GENMASK:
67647668Sru				if (!--argc)
67747668Sru					usage((char *)NULL);
6781558Srgrimes				(void) getaddr(RTA_GENMASK, *++argv, 0);
6791558Srgrimes				break;
6801558Srgrimes			case K_GATEWAY:
68147668Sru				if (!--argc)
68247668Sru					usage((char *)NULL);
6831558Srgrimes				(void) getaddr(RTA_GATEWAY, *++argv, 0);
6841558Srgrimes				break;
6851558Srgrimes			case K_DST:
68647668Sru				if (!--argc)
68747668Sru					usage((char *)NULL);
6881558Srgrimes				ishost = getaddr(RTA_DST, *++argv, &hp);
6891558Srgrimes				dest = *argv;
6901558Srgrimes				break;
6911558Srgrimes			case K_NETMASK:
69247668Sru				if (!--argc)
69347668Sru					usage((char *)NULL);
6941558Srgrimes				(void) getaddr(RTA_NETMASK, *++argv, 0);
6951558Srgrimes				/* FALLTHROUGH */
6961558Srgrimes			case K_NET:
6971558Srgrimes				forcenet++;
6981558Srgrimes				break;
69954263Sshin			case K_PREFIXLEN:
70054263Sshin				if (!--argc)
70154263Sshin					usage((char *)NULL);
70254263Sshin				if (prefixlen(*++argv) == -1) {
70354263Sshin					forcenet = 0;
70454263Sshin					ishost = 1;
70554263Sshin				} else {
70654263Sshin					forcenet = 1;
70754263Sshin					ishost = 0;
70854263Sshin				}
70954263Sshin				break;
7101558Srgrimes			case K_MTU:
7111558Srgrimes			case K_HOPCOUNT:
7121558Srgrimes			case K_EXPIRE:
7131558Srgrimes			case K_RECVPIPE:
7141558Srgrimes			case K_SENDPIPE:
7151558Srgrimes			case K_SSTHRESH:
7161558Srgrimes			case K_RTT:
7171558Srgrimes			case K_RTTVAR:
71847668Sru				if (!--argc)
71947668Sru					usage((char *)NULL);
7201558Srgrimes				set_metric(*++argv, key);
7211558Srgrimes				break;
7221558Srgrimes			default:
7231558Srgrimes				usage(1+*argv);
7241558Srgrimes			}
7251558Srgrimes		} else {
7261558Srgrimes			if ((rtm_addrs & RTA_DST) == 0) {
7271558Srgrimes				dest = *argv;
7281558Srgrimes				ishost = getaddr(RTA_DST, *argv, &hp);
7291558Srgrimes			} else if ((rtm_addrs & RTA_GATEWAY) == 0) {
7301558Srgrimes				gateway = *argv;
7311558Srgrimes				(void) getaddr(RTA_GATEWAY, *argv, &hp);
7321558Srgrimes			} else {
7331558Srgrimes				(void) getaddr(RTA_NETMASK, *argv, 0);
7341558Srgrimes			}
7351558Srgrimes		}
7361558Srgrimes	}
73754263Sshin	if (forcehost) {
7381558Srgrimes		ishost = 1;
73954263Sshin#ifdef INET6
74054263Sshin		if (af == AF_INET6) {
74154263Sshin			rtm_addrs &= ~RTA_NETMASK;
74254263Sshin			memset((void *)&so_mask, 0, sizeof(so_mask));
74354263Sshin		}
74454263Sshin#endif
74554263Sshin	}
7461558Srgrimes	if (forcenet)
7471558Srgrimes		ishost = 0;
7481558Srgrimes	flags |= RTF_UP;
7491558Srgrimes	if (ishost)
7501558Srgrimes		flags |= RTF_HOST;
7511558Srgrimes	if (iflag == 0)
7521558Srgrimes		flags |= RTF_GATEWAY;
7531558Srgrimes	for (attempts = 1; ; attempts++) {
7541558Srgrimes		errno = 0;
7551558Srgrimes		if ((ret = rtmsg(*cmd, flags)) == 0)
7561558Srgrimes			break;
7571558Srgrimes		if (errno != ENETUNREACH && errno != ESRCH)
7581558Srgrimes			break;
7591558Srgrimes		if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
7601558Srgrimes			hp->h_addr_list++;
7611558Srgrimes			bcopy(hp->h_addr_list[0], &so_gate.sin.sin_addr,
76231958Simp			    MIN(hp->h_length, sizeof(so_gate.sin.sin_addr)));
7631558Srgrimes		} else
7641558Srgrimes			break;
7651558Srgrimes	}
7661558Srgrimes	if (*cmd == 'g')
7671558Srgrimes		exit(0);
7681558Srgrimes	oerrno = errno;
7691558Srgrimes	(void) printf("%s %s %s", cmd, ishost? "host" : "net", dest);
7701558Srgrimes	if (*gateway) {
7711558Srgrimes		(void) printf(": gateway %s", gateway);
7721558Srgrimes		if (attempts > 1 && ret == 0 && af == AF_INET)
7731558Srgrimes		    (void) printf(" (%s)",
7741558Srgrimes			inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
7751558Srgrimes	}
77677873Sru	if (ret == 0) {
7771558Srgrimes		(void) printf("\n");
77877873Sru		exit(0);
77977873Sru	} else {
7801558Srgrimes		switch (oerrno) {
7811558Srgrimes		case ESRCH:
7821558Srgrimes			err = "not in table";
7831558Srgrimes			break;
7841558Srgrimes		case EBUSY:
7851558Srgrimes			err = "entry in use";
7861558Srgrimes			break;
7871558Srgrimes		case ENOBUFS:
7881558Srgrimes			err = "routing table overflow";
7891558Srgrimes			break;
79077908Sru		case EDQUOT: /* handle recursion avoidance in rt_setgate() */
79177908Sru			err = "gateway uses the same route";
79277908Sru			break;
7931558Srgrimes		default:
7941558Srgrimes			err = strerror(oerrno);
7951558Srgrimes			break;
7961558Srgrimes		}
7971558Srgrimes		(void) printf(": %s\n", err);
79877873Sru		exit(1);
7991558Srgrimes	}
8001558Srgrimes}
8011558Srgrimes
8021558Srgrimesvoid
80324558Sphkinet_makenetandmask(net, sin, bits)
80424558Sphk	u_long net, bits;
8051558Srgrimes	register struct sockaddr_in *sin;
8061558Srgrimes{
8071558Srgrimes	u_long addr, mask = 0;
8081558Srgrimes	register char *cp;
8091558Srgrimes
8101558Srgrimes	rtm_addrs |= RTA_NETMASK;
81177904Sru	if (net == 0)
81266448Sru		mask = addr = 0;
81366448Sru	else if (net < 128) {
8141558Srgrimes		addr = net << IN_CLASSA_NSHIFT;
8151558Srgrimes		mask = IN_CLASSA_NET;
8161558Srgrimes	} else if (net < 65536) {
8171558Srgrimes		addr = net << IN_CLASSB_NSHIFT;
8181558Srgrimes		mask = IN_CLASSB_NET;
8191558Srgrimes	} else if (net < 16777216L) {
8201558Srgrimes		addr = net << IN_CLASSC_NSHIFT;
8211558Srgrimes		mask = IN_CLASSC_NET;
8221558Srgrimes	} else {
8231558Srgrimes		addr = net;
8241558Srgrimes		if ((addr & IN_CLASSA_HOST) == 0)
8251558Srgrimes			mask =  IN_CLASSA_NET;
8261558Srgrimes		else if ((addr & IN_CLASSB_HOST) == 0)
8271558Srgrimes			mask =  IN_CLASSB_NET;
8281558Srgrimes		else if ((addr & IN_CLASSC_HOST) == 0)
8291558Srgrimes			mask =  IN_CLASSC_NET;
8301558Srgrimes		else
8311558Srgrimes			mask = -1;
8321558Srgrimes	}
83377904Sru	if (bits)
83477904Sru		mask = 0xffffffff << (32 - bits);
8351558Srgrimes	sin->sin_addr.s_addr = htonl(addr);
8361558Srgrimes	sin = &so_mask.sin;
8371558Srgrimes	sin->sin_addr.s_addr = htonl(mask);
8381558Srgrimes	sin->sin_len = 0;
8391558Srgrimes	sin->sin_family = 0;
8401558Srgrimes	cp = (char *)(&sin->sin_addr + 1);
8411558Srgrimes	while (*--cp == 0 && cp > (char *)sin)
8421558Srgrimes		;
8431558Srgrimes	sin->sin_len = 1 + cp - (char *)sin;
8441558Srgrimes}
8451558Srgrimes
8461558Srgrimes/*
8471558Srgrimes * Interpret an argument as a network address of some kind,
8481558Srgrimes * returning 1 if a host address, 0 if a network address.
8491558Srgrimes */
8501558Srgrimesint
8511558Srgrimesgetaddr(which, s, hpp)
8521558Srgrimes	int which;
8531558Srgrimes	char *s;
8541558Srgrimes	struct hostent **hpp;
8551558Srgrimes{
8561558Srgrimes	register sup su;
8571558Srgrimes	struct hostent *hp;
8581558Srgrimes	struct netent *np;
8591558Srgrimes	u_long val;
86066449Sru	char *q;
86154263Sshin	int afamily;  /* local copy of af so we can change it */
8621558Srgrimes
8631558Srgrimes	if (af == 0) {
8641558Srgrimes		af = AF_INET;
8651558Srgrimes		aflen = sizeof(struct sockaddr_in);
8661558Srgrimes	}
86754263Sshin	afamily = af;
8681558Srgrimes	rtm_addrs |= which;
8691558Srgrimes	switch (which) {
8701558Srgrimes	case RTA_DST:
8711558Srgrimes		su = &so_dst;
8721558Srgrimes		break;
8731558Srgrimes	case RTA_GATEWAY:
8741558Srgrimes		su = &so_gate;
87517486Sjulian		if (iflag) {
87678064Sume			struct ifaddrs *ifap, *ifa;
87778064Sume			struct sockaddr_dl *sdl = NULL;
87817486Sjulian
87978064Sume			if (getifaddrs(&ifap))
88078064Sume				err(1, "getifaddrs");
88117486Sjulian
88278064Sume			for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
88378064Sume				if (ifa->ifa_addr->sa_family != AF_LINK)
88478064Sume					continue;
88517486Sjulian
88678064Sume				if (strcmp(s, ifa->ifa_name) ||
88778064Sume				    (ifa->ifa_flags & IFF_POINTOPOINT) == 0)
88878064Sume					continue;
88978064Sume
89078064Sume				sdl = (struct sockaddr_dl *)ifa->ifa_addr;
89117486Sjulian			}
89217486Sjulian			/* If we found it, then use it */
89317486Sjulian			if (sdl) {
89478064Sume				/*
89578064Sume				 * Copy is safe since we have a
89678064Sume				 * sockaddr_storage member in sockunion{}.
89778064Sume				 * Note that we need to copy before calling
89878064Sume				 * freeifaddrs().
89978064Sume				 */
90078064Sume				memcpy(&su->sdl, sdl, sdl->sdl_len);
90178064Sume			}
90278064Sume			freeifaddrs(ifap);
90378064Sume			if (sdl)
90417486Sjulian				return(1);
90517486Sjulian		}
9061558Srgrimes		break;
9071558Srgrimes	case RTA_NETMASK:
9081558Srgrimes		su = &so_mask;
9091558Srgrimes		break;
9101558Srgrimes	case RTA_GENMASK:
9111558Srgrimes		su = &so_genmask;
9121558Srgrimes		break;
9131558Srgrimes	case RTA_IFP:
9141558Srgrimes		su = &so_ifp;
91554263Sshin		afamily = AF_LINK;
9161558Srgrimes		break;
9171558Srgrimes	case RTA_IFA:
9181558Srgrimes		su = &so_ifa;
9191558Srgrimes		break;
9201558Srgrimes	default:
92137907Scharnier		usage("internal error");
9221558Srgrimes		/*NOTREACHED*/
9231558Srgrimes	}
9241558Srgrimes	su->sa.sa_len = aflen;
92554263Sshin	su->sa.sa_family = afamily; /* cases that don't want it have left already */
9261558Srgrimes	if (strcmp(s, "default") == 0) {
92727500Sjulian		/*
92827500Sjulian		 * Default is net 0.0.0.0/0
92927500Sjulian		 */
9301558Srgrimes		switch (which) {
9311558Srgrimes		case RTA_DST:
9321558Srgrimes			forcenet++;
93327500Sjulian			/* bzero(su, sizeof(*su)); *//* for readability */
9341558Srgrimes			(void) getaddr(RTA_NETMASK, s, 0);
9351558Srgrimes			break;
9361558Srgrimes		case RTA_NETMASK:
9371558Srgrimes		case RTA_GENMASK:
93827500Sjulian			/* bzero(su, sizeof(*su)); *//* for readability */
9391558Srgrimes		}
9401558Srgrimes		return (0);
9411558Srgrimes	}
94254263Sshin	switch (afamily) {
94354263Sshin#ifdef INET6
94454263Sshin	case AF_INET6:
94578064Sume	{
94657108Sshin		struct addrinfo hints, *res;
94757108Sshin
94878064Sume		memset(&hints, 0, sizeof(hints));
94978064Sume		hints.ai_family = afamily;	/*AF_INET6*/
95078064Sume		hints.ai_flags = AI_NUMERICHOST;
95178064Sume		hints.ai_socktype = SOCK_DGRAM;		/*dummy*/
95278064Sume		if (getaddrinfo(s, "0", &hints, &res) != 0 ||
95378064Sume		    res->ai_family != AF_INET6 ||
95478064Sume		    res->ai_addrlen != sizeof(su->sin6)) {
95578064Sume			(void) fprintf(stderr, "%s: bad value\n", s);
95654263Sshin			exit(1);
95754263Sshin		}
95878064Sume		memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
95978064Sume#ifdef __KAME__
96078064Sume		if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) ||
96178064Sume		     IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr)) &&
96278064Sume		    su->sin6.sin6_scope_id) {
96378064Sume			*(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] =
96478064Sume				htons(su->sin6.sin6_scope_id);
96578064Sume			su->sin6.sin6_scope_id = 0;
96678064Sume		}
96754263Sshin#endif
96878064Sume		freeaddrinfo(res);
96978064Sume		return (0);
97078064Sume	}
97178064Sume#endif /* INET6 */
97254263Sshin
97314092Swollman#ifdef NS
9741558Srgrimes	case AF_NS:
9751558Srgrimes		if (which == RTA_DST) {
9761558Srgrimes			extern short ns_bh[3];
9771558Srgrimes			struct sockaddr_ns *sms = &(so_mask.sns);
9781558Srgrimes			bzero((char *)sms, sizeof(*sms));
9791558Srgrimes			sms->sns_family = 0;
9801558Srgrimes			sms->sns_len = 6;
9811558Srgrimes			sms->sns_addr.x_net = *(union ns_net *)ns_bh;
9821558Srgrimes			rtm_addrs |= RTA_NETMASK;
9831558Srgrimes		}
9841558Srgrimes		su->sns.sns_addr = ns_addr(s);
9851558Srgrimes		return (!ns_nullhost(su->sns.sns_addr));
98614092Swollman#endif
9871558Srgrimes
9881558Srgrimes
98917046Sjulian	case AF_APPLETALK:
99017046Sjulian		if (!atalk_aton(s, &su->sat.sat_addr))
99117046Sjulian			errx(EX_NOHOST, "bad address: %s", s);
99217265Sjulian		rtm_addrs |= RTA_NETMASK;
99317265Sjulian		return(forcehost || su->sat.sat_addr.s_node != 0);
99417046Sjulian
9951558Srgrimes	case AF_LINK:
9961558Srgrimes		link_addr(s, &su->sdl);
9971558Srgrimes		return (1);
9981558Srgrimes
9991558Srgrimes
10001558Srgrimes	case PF_ROUTE:
10011558Srgrimes		su->sa.sa_len = sizeof(*su);
10021558Srgrimes		sockaddr(s, &su->sa);
10031558Srgrimes		return (1);
10041558Srgrimes
10051558Srgrimes	case AF_INET:
10061558Srgrimes	default:
10071558Srgrimes		break;
10081558Srgrimes	}
10091558Srgrimes
10101558Srgrimes	if (hpp == NULL)
10111558Srgrimes		hpp = &hp;
10121558Srgrimes	*hpp = NULL;
101324558Sphk
101424558Sphk	q = strchr(s,'/');
101524558Sphk	if (q && which == RTA_DST) {
101624558Sphk		*q = '\0';
101777904Sru		if ((val = inet_network(s)) != INADDR_NONE) {
101824558Sphk			inet_makenetandmask(
101977904Sru				val, &su->sin, strtoul(q+1, 0, 0));
102024558Sphk			return (0);
102124558Sphk		}
102266449Sru		*q = '/';
102324558Sphk	}
102466449Sru	if ((which != RTA_DST || forcenet == 0) &&
102566449Sru	    (val = inet_addr(s)) != INADDR_NONE) {
10261558Srgrimes		su->sin.sin_addr.s_addr = val;
102766449Sru		if (which != RTA_DST ||
102866449Sru		    inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
10291558Srgrimes			return (1);
10301558Srgrimes		else {
10311558Srgrimes			val = ntohl(val);
10321558Srgrimes			goto netdone;
10331558Srgrimes		}
10341558Srgrimes	}
103566449Sru	if (which == RTA_DST && forcehost == 0 &&
103666449Sru	    ((val = inet_network(s)) != INADDR_NONE ||
103766449Sru	    ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0))) {
10381558Srgrimesnetdone:
103966449Sru		inet_makenetandmask(val, &su->sin, 0);
10401558Srgrimes		return (0);
10411558Srgrimes	}
10421558Srgrimes	hp = gethostbyname(s);
10431558Srgrimes	if (hp) {
10441558Srgrimes		*hpp = hp;
10451558Srgrimes		su->sin.sin_family = hp->h_addrtype;
104631958Simp		bcopy(hp->h_addr, (char *)&su->sin.sin_addr,
104732008Simp		    MIN(hp->h_length, sizeof(su->sin.sin_addr)));
10481558Srgrimes		return (1);
10491558Srgrimes	}
105013515Smpp	errx(EX_NOHOST, "bad address: %s", s);
10511558Srgrimes}
10521558Srgrimes
105354263Sshinint
105454263Sshinprefixlen(s)
105554263Sshin	char *s;
105654263Sshin{
105754263Sshin	int len = atoi(s), q, r;
105854263Sshin	int max;
105954263Sshin	char *p;
10601558Srgrimes
106154263Sshin	rtm_addrs |= RTA_NETMASK;
106254263Sshin	switch (af) {
106354263Sshin#ifdef INET6
106454263Sshin	case AF_INET6:
106554263Sshin		max = 128;
106654263Sshin		p = (char *)&so_mask.sin6.sin6_addr;
106754263Sshin		break;
106854263Sshin#endif
106954263Sshin	case AF_INET:
107054263Sshin		max = 32;
107154263Sshin		p = (char *)&so_mask.sin.sin_addr;
107254263Sshin		break;
107354263Sshin	default:
107454263Sshin		(void) fprintf(stderr, "prefixlen not supported in this af\n");
107554263Sshin		exit(1);
107654263Sshin		/*NOTREACHED*/
107754263Sshin	}
107854263Sshin
107954263Sshin	if (len < 0 || max < len) {
108054263Sshin		(void) fprintf(stderr, "%s: bad value\n", s);
108154263Sshin		exit(1);
108254263Sshin	}
108354263Sshin
108454263Sshin	q = len >> 3;
108554263Sshin	r = len & 7;
108654263Sshin	so_mask.sa.sa_family = af;
108754263Sshin	so_mask.sa.sa_len = aflen;
108854263Sshin	memset((void *)p, 0, max / 8);
108954263Sshin	if (q > 0)
109054263Sshin		memset((void *)p, 0xff, q);
109154263Sshin	if (r > 0)
109254263Sshin		*((u_char *)p + q) = (0xff00 >> r) & 0xff;
109354263Sshin	if (len == max)
109454263Sshin		return -1;
109554263Sshin	else
109654263Sshin		return len;
109754263Sshin}
109854263Sshin
109914092Swollman#ifdef NS
11001558Srgrimesshort ns_nullh[] = {0,0,0};
11011558Srgrimesshort ns_bh[] = {-1,-1,-1};
11021558Srgrimes
11031558Srgrimeschar *
11041558Srgrimesns_print(sns)
11051558Srgrimes	struct sockaddr_ns *sns;
11061558Srgrimes{
11071558Srgrimes	struct ns_addr work;
11081558Srgrimes	union { union ns_net net_e; u_long long_e; } net;
11091558Srgrimes	u_short port;
111022953Sroberto	static char mybuf[50+MAXHOSTNAMELEN], cport[10], chost[25];
11111558Srgrimes	char *host = "";
11121558Srgrimes	register char *p;
11131558Srgrimes	register u_char *q;
11141558Srgrimes
11151558Srgrimes	work = sns->sns_addr;
11161558Srgrimes	port = ntohs(work.x_port);
11171558Srgrimes	work.x_port = 0;
11181558Srgrimes	net.net_e  = work.x_net;
11191558Srgrimes	if (ns_nullhost(work) && net.long_e == 0) {
11201558Srgrimes		if (!port)
11211558Srgrimes			return ("*.*");
11221558Srgrimes		(void) sprintf(mybuf, "*.%XH", port);
11231558Srgrimes		return (mybuf);
11241558Srgrimes	}
11251558Srgrimes
11261558Srgrimes	if (bcmp((char *)ns_bh, (char *)work.x_host.c_host, 6) == 0)
11271558Srgrimes		host = "any";
11281558Srgrimes	else if (bcmp((char *)ns_nullh, (char *)work.x_host.c_host, 6) == 0)
11291558Srgrimes		host = "*";
11301558Srgrimes	else {
11311558Srgrimes		q = work.x_host.c_host;
11321558Srgrimes		(void) sprintf(chost, "%02X%02X%02X%02X%02X%02XH",
11331558Srgrimes			q[0], q[1], q[2], q[3], q[4], q[5]);
11341558Srgrimes		for (p = chost; *p == '0' && p < chost + 12; p++)
11351558Srgrimes			/* void */;
11361558Srgrimes		host = p;
11371558Srgrimes	}
11381558Srgrimes	if (port)
11391558Srgrimes		(void) sprintf(cport, ".%XH", htons(port));
11401558Srgrimes	else
11411558Srgrimes		*cport = 0;
11421558Srgrimes
114354263Sshin	(void) snprintf(mybuf, sizeof(mybuf), "%lxH.%s%s",
114454263Sshin			(unsigned long)ntohl(net.long_e),
114554263Sshin			host, cport);
11461558Srgrimes	return (mybuf);
11471558Srgrimes}
114814092Swollman#endif
11491558Srgrimes
11501558Srgrimesvoid
11511558Srgrimesinterfaces()
11521558Srgrimes{
11531558Srgrimes	size_t needed;
11541558Srgrimes	int mib[6];
11551558Srgrimes	char *buf, *lim, *next;
11561558Srgrimes	register struct rt_msghdr *rtm;
11571558Srgrimes
11581558Srgrimes	mib[0] = CTL_NET;
11591558Srgrimes	mib[1] = PF_ROUTE;
11601558Srgrimes	mib[2] = 0;		/* protocol */
11611558Srgrimes	mib[3] = 0;		/* wildcard address family */
11621558Srgrimes	mib[4] = NET_RT_IFLIST;
11631558Srgrimes	mib[5] = 0;		/* no flags */
11641558Srgrimes	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
116513171Swollman		err(EX_OSERR, "route-sysctl-estimate");
11661558Srgrimes	if ((buf = malloc(needed)) == NULL)
116737907Scharnier		errx(EX_OSERR, "malloc failed");
11681558Srgrimes	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
116913171Swollman		err(EX_OSERR, "actual retrieval of interface table");
11701558Srgrimes	lim = buf + needed;
11711558Srgrimes	for (next = buf; next < lim; next += rtm->rtm_msglen) {
11721558Srgrimes		rtm = (struct rt_msghdr *)next;
11731558Srgrimes		print_rtmsg(rtm, rtm->rtm_msglen);
11741558Srgrimes	}
11751558Srgrimes}
11761558Srgrimes
11771558Srgrimesvoid
11781558Srgrimesmonitor()
11791558Srgrimes{
11801558Srgrimes	int n;
11811558Srgrimes	char msg[2048];
11821558Srgrimes
11831558Srgrimes	verbose = 1;
11841558Srgrimes	if (debugonly) {
11851558Srgrimes		interfaces();
11861558Srgrimes		exit(0);
11871558Srgrimes	}
11881558Srgrimes	for(;;) {
118954263Sshin		time_t now;
11901558Srgrimes		n = read(s, msg, 2048);
119154263Sshin		now = time(NULL);
119271061Sphk		(void) printf("\ngot message of size %d on %s", n, ctime(&now));
11931558Srgrimes		print_rtmsg((struct rt_msghdr *)msg, n);
11941558Srgrimes	}
11951558Srgrimes}
11961558Srgrimes
11971558Srgrimesstruct {
11981558Srgrimes	struct	rt_msghdr m_rtm;
11991558Srgrimes	char	m_space[512];
12001558Srgrimes} m_rtmsg;
12011558Srgrimes
12021558Srgrimesint
12031558Srgrimesrtmsg(cmd, flags)
12041558Srgrimes	int cmd, flags;
12051558Srgrimes{
12061558Srgrimes	static int seq;
12071558Srgrimes	int rlen;
12081558Srgrimes	register char *cp = m_rtmsg.m_space;
12091558Srgrimes	register int l;
12101558Srgrimes
12111558Srgrimes#define NEXTADDR(w, u) \
12121558Srgrimes	if (rtm_addrs & (w)) {\
12131558Srgrimes	    l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\
12141558Srgrimes	    if (verbose) sodump(&(u),"u");\
12151558Srgrimes	}
12161558Srgrimes
12171558Srgrimes	errno = 0;
12181558Srgrimes	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
12191558Srgrimes	if (cmd == 'a')
12201558Srgrimes		cmd = RTM_ADD;
12211558Srgrimes	else if (cmd == 'c')
12221558Srgrimes		cmd = RTM_CHANGE;
12231558Srgrimes	else if (cmd == 'g') {
12241558Srgrimes		cmd = RTM_GET;
12251558Srgrimes		if (so_ifp.sa.sa_family == 0) {
122613171Swollman			so_ifp.sa.sa_family = AF_LINK;
122713171Swollman			so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
12281558Srgrimes			rtm_addrs |= RTA_IFP;
12291558Srgrimes		}
12301558Srgrimes	} else
12311558Srgrimes		cmd = RTM_DELETE;
12321558Srgrimes#define rtm m_rtmsg.m_rtm
12331558Srgrimes	rtm.rtm_type = cmd;
12341558Srgrimes	rtm.rtm_flags = flags;
12351558Srgrimes	rtm.rtm_version = RTM_VERSION;
12361558Srgrimes	rtm.rtm_seq = ++seq;
12371558Srgrimes	rtm.rtm_addrs = rtm_addrs;
12381558Srgrimes	rtm.rtm_rmx = rt_metrics;
12391558Srgrimes	rtm.rtm_inits = rtm_inits;
12401558Srgrimes
12411558Srgrimes	if (rtm_addrs & RTA_NETMASK)
12421558Srgrimes		mask_addr();
12431558Srgrimes	NEXTADDR(RTA_DST, so_dst);
12441558Srgrimes	NEXTADDR(RTA_GATEWAY, so_gate);
12451558Srgrimes	NEXTADDR(RTA_NETMASK, so_mask);
12461558Srgrimes	NEXTADDR(RTA_GENMASK, so_genmask);
12471558Srgrimes	NEXTADDR(RTA_IFP, so_ifp);
12481558Srgrimes	NEXTADDR(RTA_IFA, so_ifa);
12491558Srgrimes	rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
12501558Srgrimes	if (verbose)
12511558Srgrimes		print_rtmsg(&rtm, l);
12521558Srgrimes	if (debugonly)
12531558Srgrimes		return (0);
12541558Srgrimes	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
125537907Scharnier		warn("writing to routing socket");
12561558Srgrimes		return (-1);
12571558Srgrimes	}
12581558Srgrimes	if (cmd == RTM_GET) {
12591558Srgrimes		do {
12601558Srgrimes			l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
12611558Srgrimes		} while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
12621558Srgrimes		if (l < 0)
126313171Swollman			warn("read from routing socket");
12641558Srgrimes		else
12651558Srgrimes			print_getmsg(&rtm, l);
12661558Srgrimes	}
12671558Srgrimes#undef rtm
12681558Srgrimes	return (0);
12691558Srgrimes}
12701558Srgrimes
12711558Srgrimesvoid
12721558Srgrimesmask_addr()
12731558Srgrimes{
12741558Srgrimes	int olen = so_mask.sa.sa_len;
12751558Srgrimes	register char *cp1 = olen + (char *)&so_mask, *cp2;
12761558Srgrimes
12771558Srgrimes	for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; )
12781558Srgrimes		if (*--cp1 != 0) {
12791558Srgrimes			so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask;
12801558Srgrimes			break;
12811558Srgrimes		}
12821558Srgrimes	if ((rtm_addrs & RTA_DST) == 0)
12831558Srgrimes		return;
12841558Srgrimes	switch (so_dst.sa.sa_family) {
128514092Swollman#ifdef NS
12861558Srgrimes	case AF_NS:
128714092Swollman#endif
12881558Srgrimes	case AF_INET:
128954263Sshin#ifdef INET6
129054263Sshin	case AF_INET6:
129154263Sshin#endif
129217046Sjulian	case AF_APPLETALK:
12931558Srgrimes	case 0:
12941558Srgrimes		return;
12951558Srgrimes	}
12961558Srgrimes	cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
12971558Srgrimes	cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
12981558Srgrimes	while (cp2 > cp1)
12991558Srgrimes		*--cp2 = 0;
13001558Srgrimes	cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
13011558Srgrimes	while (cp1 > so_dst.sa.sa_data)
13021558Srgrimes		*--cp1 &= *--cp2;
13031558Srgrimes}
13041558Srgrimes
13051558Srgrimeschar *msgtypes[] = {
13061558Srgrimes	"",
13071558Srgrimes	"RTM_ADD: Add Route",
13081558Srgrimes	"RTM_DELETE: Delete Route",
13091558Srgrimes	"RTM_CHANGE: Change Metrics or flags",
13101558Srgrimes	"RTM_GET: Report Metrics",
13111558Srgrimes	"RTM_LOSING: Kernel Suspects Partitioning",
13121558Srgrimes	"RTM_REDIRECT: Told to use different route",
13131558Srgrimes	"RTM_MISS: Lookup failed on this address",
13141558Srgrimes	"RTM_LOCK: fix specified metrics",
13151558Srgrimes	"RTM_OLDADD: caused by SIOCADDRT",
13161558Srgrimes	"RTM_OLDDEL: caused by SIOCDELRT",
13171558Srgrimes	"RTM_RESOLVE: Route created by cloning",
13181558Srgrimes	"RTM_NEWADDR: address being added to iface",
13191558Srgrimes	"RTM_DELADDR: address being removed from iface",
13201558Srgrimes	"RTM_IFINFO: iface status change",
132121465Swollman	"RTM_NEWMADDR: new multicast group membership on iface",
132221465Swollman	"RTM_DELMADDR: multicast group membership removed from iface",
13231558Srgrimes	0,
13241558Srgrimes};
13251558Srgrimes
13261558Srgrimeschar metricnames[] =
132715690Swollman"\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
132815690Swollman"\1mtu";
13291558Srgrimeschar routeflags[] =
133015690Swollman"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"
133115690Swollman"\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016"
133215690Swollman"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024CHAINDELETE"
133315690Swollman"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST";
13341558Srgrimeschar ifnetflags[] =
133515690Swollman"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
133615690Swollman"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
133715690Swollman"\017LINK2\020MULTICAST";
13381558Srgrimeschar addrnames[] =
13391558Srgrimes"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
13401558Srgrimes
13411558Srgrimesvoid
13421558Srgrimesprint_rtmsg(rtm, msglen)
13431558Srgrimes	register struct rt_msghdr *rtm;
13441558Srgrimes	int msglen;
13451558Srgrimes{
13461558Srgrimes	struct if_msghdr *ifm;
13471558Srgrimes	struct ifa_msghdr *ifam;
134821465Swollman#ifdef RTM_NEWMADDR
134921465Swollman	struct ifma_msghdr *ifmam;
135021465Swollman#endif
13511558Srgrimes
13521558Srgrimes	if (verbose == 0)
13531558Srgrimes		return;
13541558Srgrimes	if (rtm->rtm_version != RTM_VERSION) {
13551558Srgrimes		(void) printf("routing message version %d not understood\n",
13561558Srgrimes		    rtm->rtm_version);
13571558Srgrimes		return;
13581558Srgrimes	}
13591558Srgrimes	(void)printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen);
13601558Srgrimes	switch (rtm->rtm_type) {
13611558Srgrimes	case RTM_IFINFO:
13621558Srgrimes		ifm = (struct if_msghdr *)rtm;
13631558Srgrimes		(void) printf("if# %d, flags:", ifm->ifm_index);
13641558Srgrimes		bprintf(stdout, ifm->ifm_flags, ifnetflags);
13651558Srgrimes		pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
13661558Srgrimes		break;
13671558Srgrimes	case RTM_NEWADDR:
13681558Srgrimes	case RTM_DELADDR:
13691558Srgrimes		ifam = (struct ifa_msghdr *)rtm;
13701558Srgrimes		(void) printf("metric %d, flags:", ifam->ifam_metric);
13711558Srgrimes		bprintf(stdout, ifam->ifam_flags, routeflags);
13721558Srgrimes		pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
13731558Srgrimes		break;
137421465Swollman#ifdef RTM_NEWMADDR
137521465Swollman	case RTM_NEWMADDR:
137621465Swollman	case RTM_DELMADDR:
137721465Swollman		ifmam = (struct ifma_msghdr *)rtm;
137821465Swollman		pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs);
137921465Swollman		break;
138021465Swollman#endif
13811558Srgrimes	default:
138213171Swollman		(void) printf("pid: %ld, seq %d, errno %d, flags:",
138313171Swollman			(long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
13841558Srgrimes		bprintf(stdout, rtm->rtm_flags, routeflags);
13851558Srgrimes		pmsg_common(rtm);
13861558Srgrimes	}
13871558Srgrimes}
13881558Srgrimes
13891558Srgrimesvoid
13901558Srgrimesprint_getmsg(rtm, msglen)
13911558Srgrimes	register struct rt_msghdr *rtm;
13921558Srgrimes	int msglen;
13931558Srgrimes{
13941558Srgrimes	struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
13951558Srgrimes	struct sockaddr_dl *ifp = NULL;
13961558Srgrimes	register struct sockaddr *sa;
13971558Srgrimes	register char *cp;
13981558Srgrimes	register int i;
13991558Srgrimes
14001558Srgrimes	(void) printf("   route to: %s\n", routename(&so_dst));
14011558Srgrimes	if (rtm->rtm_version != RTM_VERSION) {
140213171Swollman		warnx("routing message version %d not understood",
140313171Swollman		     rtm->rtm_version);
14041558Srgrimes		return;
14051558Srgrimes	}
14061558Srgrimes	if (rtm->rtm_msglen > msglen) {
140737907Scharnier		warnx("message length mismatch, in packet %d, returned %d",
140813171Swollman		      rtm->rtm_msglen, msglen);
14091558Srgrimes	}
14101558Srgrimes	if (rtm->rtm_errno)  {
141113171Swollman		errno = rtm->rtm_errno;
141213171Swollman		warn("message indicates error %d", errno);
14131558Srgrimes		return;
14141558Srgrimes	}
14151558Srgrimes	cp = ((char *)(rtm + 1));
14161558Srgrimes	if (rtm->rtm_addrs)
14171558Srgrimes		for (i = 1; i; i <<= 1)
14181558Srgrimes			if (i & rtm->rtm_addrs) {
14191558Srgrimes				sa = (struct sockaddr *)cp;
14201558Srgrimes				switch (i) {
14211558Srgrimes				case RTA_DST:
14221558Srgrimes					dst = sa;
14231558Srgrimes					break;
14241558Srgrimes				case RTA_GATEWAY:
14251558Srgrimes					gate = sa;
14261558Srgrimes					break;
14271558Srgrimes				case RTA_NETMASK:
14281558Srgrimes					mask = sa;
14291558Srgrimes					break;
14301558Srgrimes				case RTA_IFP:
14311558Srgrimes					if (sa->sa_family == AF_LINK &&
14321558Srgrimes					   ((struct sockaddr_dl *)sa)->sdl_nlen)
14331558Srgrimes						ifp = (struct sockaddr_dl *)sa;
14341558Srgrimes					break;
14351558Srgrimes				}
14361558Srgrimes				ADVANCE(cp, sa);
14371558Srgrimes			}
14381558Srgrimes	if (dst && mask)
14391558Srgrimes		mask->sa_family = dst->sa_family;	/* XXX */
14401558Srgrimes	if (dst)
14411558Srgrimes		(void)printf("destination: %s\n", routename(dst));
14421558Srgrimes	if (mask) {
14431558Srgrimes		int savenflag = nflag;
14441558Srgrimes
14451558Srgrimes		nflag = 1;
14461558Srgrimes		(void)printf("       mask: %s\n", routename(mask));
14471558Srgrimes		nflag = savenflag;
14481558Srgrimes	}
14491558Srgrimes	if (gate && rtm->rtm_flags & RTF_GATEWAY)
14501558Srgrimes		(void)printf("    gateway: %s\n", routename(gate));
14511558Srgrimes	if (ifp)
14521558Srgrimes		(void)printf("  interface: %.*s\n",
14531558Srgrimes		    ifp->sdl_nlen, ifp->sdl_data);
14541558Srgrimes	(void)printf("      flags: ");
14551558Srgrimes	bprintf(stdout, rtm->rtm_flags, routeflags);
14561558Srgrimes
14571558Srgrimes#define lock(f)	((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
14581558Srgrimes#define msec(u)	(((u) + 500) / 1000)		/* usec to msec */
14591558Srgrimes
14601558Srgrimes	(void) printf("\n%s\n", "\
14611558Srgrimes recvpipe  sendpipe  ssthresh  rtt,msec    rttvar  hopcount      mtu     expire");
146213171Swollman	printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
146313171Swollman	printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
146413171Swollman	printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
146513171Swollman	printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
146613171Swollman	printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
146713171Swollman	printf("%8ld%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
146813171Swollman	printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
14691558Srgrimes	if (rtm->rtm_rmx.rmx_expire)
14701558Srgrimes		rtm->rtm_rmx.rmx_expire -= time(0);
147113171Swollman	printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
14721558Srgrimes#undef lock
14731558Srgrimes#undef msec
14741558Srgrimes#define	RTA_IGN	(RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
14751558Srgrimes	if (verbose)
14761558Srgrimes		pmsg_common(rtm);
14771558Srgrimes	else if (rtm->rtm_addrs &~ RTA_IGN) {
14781558Srgrimes		(void) printf("sockaddrs: ");
14791558Srgrimes		bprintf(stdout, rtm->rtm_addrs, addrnames);
14801558Srgrimes		putchar('\n');
14811558Srgrimes	}
14821558Srgrimes#undef	RTA_IGN
14831558Srgrimes}
14841558Srgrimes
14851558Srgrimesvoid
14861558Srgrimespmsg_common(rtm)
14871558Srgrimes	register struct rt_msghdr *rtm;
14881558Srgrimes{
14891558Srgrimes	(void) printf("\nlocks: ");
14901558Srgrimes	bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
14911558Srgrimes	(void) printf(" inits: ");
14921558Srgrimes	bprintf(stdout, rtm->rtm_inits, metricnames);
14931558Srgrimes	pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
14941558Srgrimes}
14951558Srgrimes
14961558Srgrimesvoid
14971558Srgrimespmsg_addrs(cp, addrs)
14981558Srgrimes	char	*cp;
14991558Srgrimes	int	addrs;
15001558Srgrimes{
15011558Srgrimes	register struct sockaddr *sa;
15021558Srgrimes	int i;
15031558Srgrimes
150471061Sphk	if (addrs == 0) {
150571061Sphk		(void) putchar('\n');
15061558Srgrimes		return;
150771061Sphk	}
15081558Srgrimes	(void) printf("\nsockaddrs: ");
15091558Srgrimes	bprintf(stdout, addrs, addrnames);
15101558Srgrimes	(void) putchar('\n');
15111558Srgrimes	for (i = 1; i; i <<= 1)
15121558Srgrimes		if (i & addrs) {
15131558Srgrimes			sa = (struct sockaddr *)cp;
15141558Srgrimes			(void) printf(" %s", routename(sa));
15151558Srgrimes			ADVANCE(cp, sa);
15161558Srgrimes		}
15171558Srgrimes	(void) putchar('\n');
15181558Srgrimes	(void) fflush(stdout);
15191558Srgrimes}
15201558Srgrimes
15211558Srgrimesvoid
15221558Srgrimesbprintf(fp, b, s)
15231558Srgrimes	register FILE *fp;
15241558Srgrimes	register int b;
15251558Srgrimes	register u_char *s;
15261558Srgrimes{
15271558Srgrimes	register int i;
15281558Srgrimes	int gotsome = 0;
15291558Srgrimes
15301558Srgrimes	if (b == 0)
15311558Srgrimes		return;
153213171Swollman	while ((i = *s++) != 0) {
15331558Srgrimes		if (b & (1 << (i-1))) {
15341558Srgrimes			if (gotsome == 0)
15351558Srgrimes				i = '<';
15361558Srgrimes			else
15371558Srgrimes				i = ',';
15381558Srgrimes			(void) putc(i, fp);
15391558Srgrimes			gotsome = 1;
15401558Srgrimes			for (; (i = *s) > 32; s++)
15411558Srgrimes				(void) putc(i, fp);
15421558Srgrimes		} else
15431558Srgrimes			while (*s > 32)
15441558Srgrimes				s++;
15451558Srgrimes	}
15461558Srgrimes	if (gotsome)
15471558Srgrimes		(void) putc('>', fp);
15481558Srgrimes}
15491558Srgrimes
15501558Srgrimesint
15511558Srgrimeskeyword(cp)
15521558Srgrimes	char *cp;
15531558Srgrimes{
15541558Srgrimes	register struct keytab *kt = keywords;
15551558Srgrimes
15561558Srgrimes	while (kt->kt_cp && strcmp(kt->kt_cp, cp))
15571558Srgrimes		kt++;
15581558Srgrimes	return kt->kt_i;
15591558Srgrimes}
15601558Srgrimes
15611558Srgrimesvoid
15621558Srgrimessodump(su, which)
15631558Srgrimes	register sup su;
15641558Srgrimes	char *which;
15651558Srgrimes{
15661558Srgrimes	switch (su->sa.sa_family) {
15671558Srgrimes	case AF_LINK:
15681558Srgrimes		(void) printf("%s: link %s; ",
15691558Srgrimes		    which, link_ntoa(&su->sdl));
15701558Srgrimes		break;
15711558Srgrimes	case AF_INET:
15721558Srgrimes		(void) printf("%s: inet %s; ",
15731558Srgrimes		    which, inet_ntoa(su->sin.sin_addr));
15741558Srgrimes		break;
157517046Sjulian	case AF_APPLETALK:
157617046Sjulian		(void) printf("%s: atalk %s; ",
157717046Sjulian		    which, atalk_ntoa(su->sat.sat_addr));
157817046Sjulian		break;
157914092Swollman#ifdef NS
15801558Srgrimes	case AF_NS:
15811558Srgrimes		(void) printf("%s: xns %s; ",
15821558Srgrimes		    which, ns_ntoa(su->sns.sns_addr));
15831558Srgrimes		break;
158414092Swollman#endif
15851558Srgrimes	}
15861558Srgrimes	(void) fflush(stdout);
15871558Srgrimes}
15881558Srgrimes
15891558Srgrimes/* States*/
15901558Srgrimes#define VIRGIN	0
15911558Srgrimes#define GOTONE	1
15921558Srgrimes#define GOTTWO	2
15931558Srgrimes/* Inputs */
15941558Srgrimes#define	DIGIT	(4*0)
15951558Srgrimes#define	END	(4*1)
15961558Srgrimes#define DELIM	(4*2)
15971558Srgrimes
15981558Srgrimesvoid
15991558Srgrimessockaddr(addr, sa)
16001558Srgrimes	register char *addr;
16011558Srgrimes	register struct sockaddr *sa;
16021558Srgrimes{
16031558Srgrimes	register char *cp = (char *)sa;
16041558Srgrimes	int size = sa->sa_len;
16051558Srgrimes	char *cplim = cp + size;
160613171Swollman	register int byte = 0, state = VIRGIN, new = 0 /* foil gcc */;
16071558Srgrimes
16081558Srgrimes	bzero(cp, size);
16091558Srgrimes	cp++;
16101558Srgrimes	do {
16111558Srgrimes		if ((*addr >= '0') && (*addr <= '9')) {
16121558Srgrimes			new = *addr - '0';
16131558Srgrimes		} else if ((*addr >= 'a') && (*addr <= 'f')) {
16141558Srgrimes			new = *addr - 'a' + 10;
16151558Srgrimes		} else if ((*addr >= 'A') && (*addr <= 'F')) {
16161558Srgrimes			new = *addr - 'A' + 10;
16171558Srgrimes		} else if (*addr == 0)
16181558Srgrimes			state |= END;
16191558Srgrimes		else
16201558Srgrimes			state |= DELIM;
16211558Srgrimes		addr++;
16221558Srgrimes		switch (state /* | INPUT */) {
16231558Srgrimes		case GOTTWO | DIGIT:
16241558Srgrimes			*cp++ = byte; /*FALLTHROUGH*/
16251558Srgrimes		case VIRGIN | DIGIT:
16261558Srgrimes			state = GOTONE; byte = new; continue;
16271558Srgrimes		case GOTONE | DIGIT:
16281558Srgrimes			state = GOTTWO; byte = new + (byte << 4); continue;
16291558Srgrimes		default: /* | DELIM */
16301558Srgrimes			state = VIRGIN; *cp++ = byte; byte = 0; continue;
16311558Srgrimes		case GOTONE | END:
16321558Srgrimes		case GOTTWO | END:
16331558Srgrimes			*cp++ = byte; /* FALLTHROUGH */
16341558Srgrimes		case VIRGIN | END:
16351558Srgrimes			break;
16361558Srgrimes		}
16371558Srgrimes		break;
16381558Srgrimes	} while (cp < cplim);
16391558Srgrimes	sa->sa_len = cp - (char *)sa;
16401558Srgrimes}
164117046Sjulian
164217046Sjulianint
164317046Sjulianatalk_aton(const char *text, struct at_addr *addr)
164417046Sjulian{
164517046Sjulian	u_int net, node;
164617046Sjulian
164717046Sjulian	if (sscanf(text, "%u.%u", &net, &node) != 2
164817046Sjulian	    || net > 0xffff || node > 0xff)
164917046Sjulian		return(0);
165017254Sjulian	addr->s_net = htons(net);
165117046Sjulian	addr->s_node = node;
165217046Sjulian	return(1);
165317046Sjulian}
165417046Sjulian
165517046Sjulianchar *
165617046Sjulianatalk_ntoa(struct at_addr at)
165717046Sjulian{
165817046Sjulian	static char buf[20];
165917046Sjulian
166017254Sjulian	(void) snprintf(buf, sizeof(buf), "%u.%u", ntohs(at.s_net), at.s_node);
166117046Sjulian	return(buf);
166217046Sjulian}
1663