xref: /titanic_44/usr/src/cmd/cmd-inet/usr.sbin/route.c (revision 7a23074e5a0337b4d20bc593de1aa7ad34701913)
1 /*
2  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
7 /* All Rights Reserved  	*/
8 
9 /* Copyright (c) 1990  Mentat Inc. */
10 
11 /*
12  *
13  * Copyright (c) 1983, 1989, 1991, 1993
14  *	The Regents of the University of California.  All rights reserved.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following disclaimer in the
23  *    documentation and/or other materials provided with the distribution.
24  * 3. All advertising materials mentioning features or use of this software
25  *    must display the following acknowledgement:
26  *	This product includes software developed by the University of
27  *	California, Berkeley and its contributors.
28  * 4. Neither the name of the University nor the names of its contributors
29  *    may be used to endorse or promote products derived from this software
30  *    without specific prior written permission.
31  *
32  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42  * SUCH DAMAGE.
43  *
44  *	@(#)route.c	8.6 (Berkeley) 4/28/95
45  *	@(#)linkaddr.c	8.1 (Berkeley) 6/4/93
46  */
47 
48 #pragma ident	"%Z%%M%	%I%	%E% SMI"
49 
50 #include <sys/param.h>
51 #include <sys/file.h>
52 #include <sys/socket.h>
53 #include <sys/ioctl.h>
54 #include <sys/stream.h>
55 #include <sys/tihdr.h>
56 #include <sys/sysmacros.h>
57 
58 #include <net/if.h>
59 #include <net/route.h>
60 #include <net/if_dl.h>
61 #include <netinet/in.h>
62 #include <arpa/inet.h>
63 #include <netdb.h>
64 #include <inet/mib2.h>
65 #include <inet/ip.h>
66 
67 #include <locale.h>
68 
69 #include <errno.h>
70 #include <unistd.h>
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <stropts.h>
75 #include <fcntl.h>
76 #include <assert.h>
77 
78 static struct keytab {
79 	char	*kt_cp;
80 	int	kt_i;
81 } keywords[] = {
82 #define	K_ADD		1
83 	{"add",		K_ADD},
84 #define	K_BLACKHOLE	2
85 	{"blackhole",	K_BLACKHOLE},
86 #define	K_CHANGE	3
87 	{"change",	K_CHANGE},
88 #define	K_CLONING	4
89 	{"cloning",	K_CLONING},
90 #define	K_DELETE	5
91 	{"delete",	K_DELETE},
92 #define	K_DST		6
93 	{"dst",		K_DST},
94 #define	K_EXPIRE	7
95 	{"expire",	K_EXPIRE},
96 #define	K_FLUSH		8
97 	{"flush",	K_FLUSH},
98 #define	K_GATEWAY	9
99 	{"gateway",	K_GATEWAY},
100 #define	K_GET		11
101 	{"get",		K_GET},
102 #define	K_HOPCOUNT	12
103 	{"hopcount",	K_HOPCOUNT},
104 #define	K_HOST		13
105 	{"host",	K_HOST},
106 #define	K_IFA		14
107 	{"ifa",		K_IFA},
108 #define	K_IFACE		15
109 	{"iface",	K_IFACE},
110 #define	K_IFP		16
111 	{"ifp",		K_IFP},
112 #define	K_INET		17
113 	{"inet",	K_INET},
114 #define	K_INET6		18
115 	{"inet6",	K_INET6},
116 #define	K_INTERFACE	19
117 	{"interface",	K_INTERFACE},
118 #define	K_LINK		20
119 	{"link",	K_LINK},
120 #define	K_LOCK		21
121 	{"lock",	K_LOCK},
122 #define	K_LOCKREST	22
123 	{"lockrest",	K_LOCKREST},
124 #define	K_MASK		23
125 	{"mask",	K_MASK},
126 #define	K_MONITOR	24
127 	{"monitor",	K_MONITOR},
128 #define	K_MTU		25
129 	{"mtu",		K_MTU},
130 #define	K_NET		26
131 	{"net",		K_NET},
132 #define	K_NETMASK	27
133 	{"netmask",	K_NETMASK},
134 #define	K_NOSTATIC	28
135 	{"nostatic",	K_NOSTATIC},
136 #define	K_PRIVATE	29
137 	{"private",	K_PRIVATE},
138 #define	K_PROTO1	30
139 	{"proto1",	K_PROTO1},
140 #define	K_PROTO2	31
141 	{"proto2",	K_PROTO2},
142 #define	K_RECVPIPE	32
143 	{"recvpipe",	K_RECVPIPE},
144 #define	K_REJECT	33
145 	{"reject",	K_REJECT},
146 #define	K_RTT		34
147 	{"rtt",		K_RTT},
148 #define	K_RTTVAR	35
149 	{"rttvar",	K_RTTVAR},
150 #define	K_SA		36
151 	{"sa",		K_SA},
152 #define	K_SENDPIPE	37
153 	{"sendpipe",	K_SENDPIPE},
154 #define	K_SSTHRESH	38
155 	{"ssthresh",	K_SSTHRESH},
156 #define	K_STATIC	39
157 	{"static",	K_STATIC},
158 #define	K_XRESOLVE	40
159 	{"xresolve",	K_XRESOLVE},
160 #define	K_MULTIRT	41
161 	{"multirt",	K_MULTIRT},
162 #define	K_SETSRC	42
163 	{"setsrc",	K_SETSRC},
164 	{0, 0}
165 };
166 
167 static union	sockunion {
168 	struct	sockaddr sa;
169 	struct	sockaddr_in sin;
170 	struct	sockaddr_dl sdl;
171 	struct	sockaddr_in6 sin6;
172 } so_dst, so_gate, so_mask, so_ifa, so_ifp, so_src;
173 
174 typedef struct	mib_item_s {
175 	struct mib_item_s	*next_item;
176 	long			group;
177 	long			mib_id;
178 	long			length;
179 	intmax_t		*valp;
180 } mib_item_t;
181 
182 typedef union sockunion *sup;
183 
184 static void		bprintf(FILE *fp, int b, char *s);
185 static void		delRouteEntry(mib2_ipRouteEntry_t *rp,
186     mib2_ipv6RouteEntry_t *rp6, int seqno);
187 static void		flushroutes(int argc, char *argv[]);
188 static boolean_t	getaddr(int which, char *s, struct hostent **hpp);
189 static boolean_t	in6_getaddr(char *s, struct sockaddr_in6 *sin6,
190     int *plenp, struct hostent **hpp);
191 static boolean_t	in_getaddr(char *s, struct sockaddr_in *sin,
192     int *plenp, int which, struct hostent **hpp);
193 static int		in_getprefixlen(char *addr, int max_plen);
194 static boolean_t	in_prefixlentomask(int prefixlen, int maxlen,
195     uchar_t *mask);
196 static void		inet_makenetandmask(in_addr_t net,
197     struct sockaddr_in *sin);
198 static in_addr_t	inet_makesubnetmask(in_addr_t addr, in_addr_t mask);
199 static int		keyword(char *cp);
200 static void		link_addr(const char *addr, struct sockaddr_dl *sdl);
201 static char		*link_ntoa(const struct sockaddr_dl *sdl);
202 static mib_item_t	*mibget(int sd);
203 static char		*netname(struct sockaddr *sa);
204 static int		newroute(int argc, char **argv);
205 static void		pmsg_addrs(char *cp, int addrs);
206 static void		pmsg_common(struct rt_msghdr *rtm);
207 static void		print_getmsg(struct rt_msghdr *rtm, int msglen);
208 static void		print_rtmsg(struct rt_msghdr *rtm, int msglen);
209 static void		quit(char *s, int err);
210 static char		*routename(struct sockaddr *sa);
211 static void		rtmonitor(int argc, char *argv[]);
212 static int		rtmsg(int cmd, int flags);
213 static int		salen(struct sockaddr *sa);
214 static void		set_metric(char *value, int key);
215 static void		sockaddr(char *addr, struct sockaddr *sa);
216 static void		sodump(sup su, char *which);
217 static void		usage(char *cp);
218 
219 static int		pid, rtm_addrs;
220 static int		s;
221 static boolean_t	forcehost, forcenet, nflag;
222 static int		af = AF_INET;
223 static boolean_t	qflag, tflag;
224 static boolean_t	iflag, verbose;
225 static boolean_t	locking, lockrest, debugonly;
226 static boolean_t	fflag;
227 static struct		rt_metrics rt_metrics;
228 static ulong_t		rtm_inits;
229 static int		masklen;
230 
231 static struct {
232 	struct	rt_msghdr m_rtm;
233 	char	m_space[512];
234 } m_rtmsg;
235 
236 /*
237  * Sizes of data structures extracted from the base mib.
238  * This allows the size of the tables entries to grow while preserving
239  * binary compatibility.
240  */
241 static int ipRouteEntrySize;
242 static int ipv6RouteEntrySize;
243 
244 #define	ROUNDUP_LONG(a) \
245 	((a) > 0 ? (1 + (((a) - 1) | (sizeof (long) - 1))) : sizeof (long))
246 #define	ADVANCE(x, n) ((x) += ROUNDUP_LONG(salen(n)))
247 #define	C(x)	((x) & 0xff)
248 
249 /*
250  * return values from in_getprefixlen()
251  */
252 #define	BAD_ADDR	-1	/* prefix is invalid */
253 #define	NO_PREFIX	-2	/* no prefix was found */
254 
255 void
256 usage(char *cp)
257 {
258 	if (cp != NULL)
259 		(void) fprintf(stderr, gettext("route: botched keyword: %s\n"),
260 		    cp);
261 	(void) fprintf(stderr,
262 	    gettext("usage: route [ -fnqv ] cmd [[ -<qualifers> ] args ]\n"));
263 	exit(1);
264 	/* NOTREACHED */
265 }
266 
267 void
268 quit(char *s, int sverrno)
269 {
270 	(void) fprintf(stderr, "route: ");
271 	if (s != NULL)
272 		(void) fprintf(stderr, "%s: ", s);
273 	(void) fprintf(stderr, "%s\n", strerror(sverrno));
274 	exit(sverrno);
275 	/* NOTREACHED */
276 }
277 
278 int
279 main(int argc, char **argv)
280 {
281 	extern int optind;
282 	int ch;
283 	int key;
284 
285 	(void) setlocale(LC_ALL, "");
286 
287 #if !defined(TEXT_DOMAIN)
288 #define	TEXT_DOMAIN "SYS_TEST"
289 #endif
290 	(void) textdomain(TEXT_DOMAIN);
291 
292 	if (argc < 2)
293 		usage((char *)NULL);
294 
295 	while ((ch = getopt(argc, argv, "nqdtvf")) != EOF) {
296 		switch (ch) {
297 		case 'n':
298 			nflag = B_TRUE;
299 			break;
300 		case 'q':
301 			qflag = B_TRUE;
302 			break;
303 		case 'v':
304 			verbose = B_TRUE;
305 			break;
306 		case 't':
307 			tflag = B_TRUE;
308 			break;
309 		case 'd':
310 			debugonly = B_TRUE;
311 			break;
312 		case 'f':
313 			fflag = B_TRUE;
314 			break;
315 		case '?':
316 		default:
317 			usage((char *)NULL);
318 			/* NOTREACHED */
319 		}
320 	}
321 	argc -= optind;
322 	argv += optind;
323 
324 	pid = getpid();
325 	if (tflag)
326 		s = open("/dev/null", O_WRONLY);
327 	else
328 		s = socket(PF_ROUTE, SOCK_RAW, 0);
329 	if (s < 0)
330 		quit("socket", errno);
331 	if (fflag) {
332 		/*
333 		 * Accept an address family keyword after the -f.  Since the
334 		 * default address family is AF_INET, reassign af only for the
335 		 * other valid address families.
336 		 */
337 		if (*argv != NULL) {
338 			switch (key = keyword(*argv)) {
339 			case K_INET:
340 			case K_INET6:
341 				if (key == K_INET6)
342 					af = AF_INET6;
343 				/* Skip over the address family parameter. */
344 				argc--;
345 				argv++;
346 				break;
347 			}
348 		}
349 		flushroutes(0, NULL);
350 	}
351 	if (*argv != NULL) {
352 		switch (keyword(*argv)) {
353 		case K_GET:
354 		case K_CHANGE:
355 		case K_ADD:
356 		case K_DELETE:
357 			return (newroute(argc, argv));
358 
359 		case K_MONITOR:
360 			rtmonitor(argc, argv);
361 			/* NOTREACHED */
362 
363 		case K_FLUSH:
364 			flushroutes(argc, argv);
365 			exit(0);
366 			/* NOTREACHED */
367 		}
368 	}
369 	if (!fflag)
370 		usage(*argv);
371 	return (0);
372 }
373 
374 /*
375  * Purge all entries in the routing tables not
376  * associated with network interfaces.
377  */
378 void
379 flushroutes(int argc, char *argv[])
380 {
381 	int seqno;
382 	int sd;	/* mib stream */
383 	mib_item_t	*item;
384 	mib2_ipRouteEntry_t *rp;
385 	mib2_ipv6RouteEntry_t *rp6;
386 	int oerrno;
387 	int off = 0;
388 	int on = 1;
389 
390 	if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&off,
391 	    sizeof (off)) < 0)
392 		quit("setsockopt", errno);
393 	if (argc > 1) {
394 		argv++;
395 		if (argc == 2 && **argv == '-') {
396 			/*
397 			 * The address family (preceded by a dash) may be used
398 			 * to flush the routes of that particular family.
399 			 */
400 			switch (keyword(*argv + 1)) {
401 			case K_INET:
402 				af = AF_INET;
403 				break;
404 			case K_LINK:
405 				af = AF_LINK;
406 				break;
407 			case K_INET6:
408 				af = AF_INET6;
409 				break;
410 			default:
411 				usage(*argv);
412 				/* NOTREACHED */
413 			}
414 		} else {
415 			usage(*argv);
416 		}
417 	}
418 	sd = open("/dev/ip", O_RDWR);
419 	oerrno = errno;
420 	if (sd < 0) {
421 		switch (errno) {
422 		case EACCES:
423 			(void) fprintf(stderr,
424 			    gettext("route: flush: insufficient privileges\n"));
425 			exit(oerrno);
426 			/* NOTREACHED */
427 		default:
428 			quit(gettext("can't open mib stream"), oerrno);
429 			/* NOTREACHED */
430 		}
431 	}
432 	if ((item = mibget(sd)) == NULL)
433 		quit("mibget", errno);
434 	if (verbose) {
435 		(void) printf("Examining routing table from "
436 		    "T_SVR4_OPTMGMT_REQ\n");
437 	}
438 	seqno = 0;		/* ??? */
439 	switch (af) {
440 	case AF_INET:
441 		/* Extract ipRouteEntrySize */
442 		for (; item != NULL; item = item->next_item) {
443 			if (item->mib_id != 0)
444 				continue;
445 			if (item->group == MIB2_IP) {
446 				ipRouteEntrySize =
447 				    ((mib2_ip_t *)item->valp)->ipRouteEntrySize;
448 				assert(IS_P2ALIGNED(ipRouteEntrySize,
449 				    sizeof (mib2_ipRouteEntry_t *)));
450 				break;
451 			}
452 		}
453 		if (ipRouteEntrySize == 0) {
454 			(void) fprintf(stderr,
455 			    gettext("ipRouteEntrySize can't be determined.\n"));
456 			exit(1);
457 		}
458 		for (; item != NULL; item = item->next_item) {
459 			/*
460 			 * skip all the other trash that comes up the mib stream
461 			 */
462 			if (item->group != MIB2_IP ||
463 			    item->mib_id != MIB2_IP_ROUTE)
464 				continue;
465 			for (rp = (mib2_ipRouteEntry_t *)item->valp;
466 			    (char *)rp < (char *)item->valp + item->length;
467 			    /* LINTED */
468 			    rp = (mib2_ipRouteEntry_t *)
469 				((char *)rp + ipRouteEntrySize)) {
470 				delRouteEntry(rp, NULL, seqno);
471 				seqno++;
472 			}
473 			break;
474 		}
475 		break;
476 	case AF_INET6:
477 		/* Extract ipv6RouteEntrySize */
478 		for (; item != NULL; item = item->next_item) {
479 			if (item->mib_id != 0)
480 				continue;
481 			if (item->group == MIB2_IP6) {
482 				ipv6RouteEntrySize =
483 				    ((mib2_ipv6IfStatsEntry_t *)item->valp)->
484 					ipv6RouteEntrySize;
485 				assert(IS_P2ALIGNED(ipv6RouteEntrySize,
486 				    sizeof (mib2_ipv6RouteEntry_t *)));
487 				break;
488 			}
489 		}
490 		if (ipv6RouteEntrySize == 0) {
491 			(void) fprintf(stderr, gettext(
492 			    "ipv6RouteEntrySize cannot be determined.\n"));
493 			exit(1);
494 		}
495 		for (; item != NULL; item = item->next_item) {
496 			/*
497 			 * skip all the other trash that comes up the mib stream
498 			 */
499 			if (item->group != MIB2_IP6 ||
500 			    item->mib_id != MIB2_IP6_ROUTE)
501 				continue;
502 			for (rp6 = (mib2_ipv6RouteEntry_t *)item->valp;
503 			    (char *)rp6 < (char *)item->valp + item->length;
504 			    /* LINTED */
505 			    rp6 = (mib2_ipv6RouteEntry_t *)
506 				((char *)rp6 + ipv6RouteEntrySize)) {
507 				delRouteEntry(NULL, rp6, seqno);
508 				seqno++;
509 			}
510 			break;
511 		}
512 		break;
513 	}
514 
515 	if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&on,
516 	    sizeof (on)) < 0)
517 		quit("setsockopt", errno);
518 }
519 
520 /*
521  * Given the contents of a mib_item_t of id type MIB2_IP_ROUTE or
522  * MIB2_IP6_ROUTE, construct and send an RTM_DELETE routing socket message in
523  * order to facilitate the flushing of RTF_GATEWAY routes.
524  */
525 static void
526 delRouteEntry(mib2_ipRouteEntry_t *rp, mib2_ipv6RouteEntry_t *rp6, int seqno)
527 {
528 	char *cp;
529 	int ire_type;
530 	int rlen;
531 	struct rt_msghdr *rtm;
532 	struct sockaddr_in sin;
533 	struct sockaddr_in6 sin6;
534 	int slen;
535 
536 	if (rp != NULL)
537 		ire_type = rp->ipRouteInfo.re_ire_type;
538 	else
539 		ire_type = rp6->ipv6RouteInfo.re_ire_type;
540 	if (ire_type != IRE_DEFAULT &&
541 	    ire_type != IRE_PREFIX &&
542 	    ire_type != IRE_HOST &&
543 	    ire_type != IRE_HOST_REDIRECT)
544 		return;
545 
546 	rtm = &m_rtmsg.m_rtm;
547 	(void) memset(rtm, 0, sizeof (m_rtmsg));
548 	rtm->rtm_type = RTM_DELETE;
549 	rtm->rtm_seq = seqno;
550 	rtm->rtm_flags |= RTF_GATEWAY;
551 	rtm->rtm_version = RTM_VERSION;
552 	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
553 	cp = m_rtmsg.m_space;
554 	if (rp != NULL) {
555 		slen = sizeof (struct sockaddr_in);
556 		if (rp->ipRouteMask == IP_HOST_MASK)
557 			rtm->rtm_flags |= RTF_HOST;
558 		(void) memset(&sin, 0, slen);
559 		sin.sin_family = AF_INET;
560 		sin.sin_addr.s_addr = rp->ipRouteDest;
561 		(void) memmove(cp, &sin, slen);
562 		cp += slen;
563 		sin.sin_addr.s_addr = rp->ipRouteNextHop;
564 		(void) memmove(cp, &sin, slen);
565 		cp += slen;
566 		sin.sin_addr.s_addr = rp->ipRouteMask;
567 		(void) memmove(cp, &sin, slen);
568 		cp += slen;
569 	} else {
570 		slen = sizeof (struct sockaddr_in6);
571 		if (rp6->ipv6RoutePfxLength == IPV6_ABITS)
572 			rtm->rtm_flags |= RTF_HOST;
573 		(void) memset(&sin6, 0, slen);
574 		sin6.sin6_family = AF_INET6;
575 		sin6.sin6_addr = rp6->ipv6RouteDest;
576 		(void) memmove(cp, &sin6, slen);
577 		cp += slen;
578 		sin6.sin6_addr = rp6->ipv6RouteNextHop;
579 		(void) memmove(cp, &sin6, slen);
580 		cp += slen;
581 		(void) memset(&sin6.sin6_addr, 0, sizeof (sin6.sin6_addr));
582 		(void) in_prefixlentomask(rp6->ipv6RoutePfxLength, IPV6_ABITS,
583 		    (uchar_t *)&sin6.sin6_addr.s6_addr);
584 		(void) memmove(cp, &sin6, slen);
585 		cp += slen;
586 	}
587 	rtm->rtm_msglen = cp - (char *)&m_rtmsg;
588 	if (debugonly) {
589 		/*
590 		 * In debugonly mode, the routing socket message to delete the
591 		 * current entry is not actually sent.  However if verbose is
592 		 * also set, the routing socket message that would have been
593 		 * is printed.
594 		 */
595 		if (verbose)
596 			print_rtmsg(rtm, rtm->rtm_msglen);
597 		return;
598 	}
599 
600 	rlen = write(s, (char *)&m_rtmsg, rtm->rtm_msglen);
601 	if (rlen < (int)rtm->rtm_msglen) {
602 		if (rlen < 0) {
603 			(void) fprintf(stderr,
604 			    gettext("route: write to routing socket: %s\n"),
605 			    strerror(errno));
606 		} else {
607 			(void) fprintf(stderr, gettext("route: write to "
608 			    "routing socket got only %d for rlen\n"), rlen);
609 		}
610 		return;
611 	}
612 	if (qflag) {
613 		/*
614 		 * In quiet mode, nothing is printed at all (unless the write()
615 		 * itself failed.
616 		 */
617 		return;
618 	}
619 	if (verbose) {
620 		print_rtmsg(rtm, rlen);
621 	} else {
622 		struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
623 
624 		(void) printf("%-20.20s ",
625 		    rtm->rtm_flags & RTF_HOST ? routename(sa) :
626 			netname(sa));
627 		/* LINTED */
628 		sa = (struct sockaddr *)(salen(sa) + (char *)sa);
629 		(void) printf("%-20.20s ", routename(sa));
630 		(void) printf("done\n");
631 	}
632 }
633 
634 /*
635  * Return the name of the host whose address is given.
636  */
637 char *
638 routename(struct sockaddr *sa)
639 {
640 	char *cp;
641 	static char line[MAXHOSTNAMELEN + 1];
642 	struct hostent *hp = NULL;
643 	static char domain[MAXHOSTNAMELEN + 1];
644 	static boolean_t first = B_TRUE;
645 	struct in_addr in;
646 	struct in6_addr in6;
647 	int error_num;
648 	ushort_t *s;
649 	ushort_t *slim;
650 
651 	if (first) {
652 		first = B_FALSE;
653 		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
654 		    (cp = strchr(domain, '.')))
655 			(void) strcpy(domain, cp + 1);
656 		else
657 			domain[0] = 0;
658 	}
659 
660 	if (salen(sa) == 0) {
661 		(void) strcpy(line, "default");
662 		return (line);
663 	}
664 	switch (sa->sa_family) {
665 
666 	case AF_INET:
667 		/* LINTED */
668 		in = ((struct sockaddr_in *)sa)->sin_addr;
669 
670 		cp = NULL;
671 		if (in.s_addr == INADDR_ANY)
672 			cp = "default";
673 		if (cp == NULL && !nflag) {
674 			hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
675 				AF_INET);
676 			if (hp != NULL) {
677 				if (((cp = strchr(hp->h_name, '.')) != NULL) &&
678 				    (strcmp(cp + 1, domain) == 0))
679 					*cp = 0;
680 				cp = hp->h_name;
681 			}
682 		}
683 		if (cp != NULL) {
684 			(void) strncpy(line, cp, MAXHOSTNAMELEN);
685 			line[MAXHOSTNAMELEN] = '\0';
686 		} else {
687 			in.s_addr = ntohl(in.s_addr);
688 			(void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
689 			    C(in.s_addr >> 16), C(in.s_addr >> 8),
690 			    C(in.s_addr));
691 		}
692 		break;
693 
694 	case AF_LINK:
695 		return (link_ntoa((struct sockaddr_dl *)sa));
696 
697 	case AF_INET6:
698 		/* LINTED */
699 		in6 = ((struct sockaddr_in6 *)sa)->sin6_addr;
700 
701 		cp = NULL;
702 		if (IN6_IS_ADDR_UNSPECIFIED(&in6))
703 			cp = "default";
704 		if (cp == NULL && !nflag) {
705 			hp = getipnodebyaddr((char *)&in6,
706 				sizeof (struct in6_addr), AF_INET6, &error_num);
707 			if (hp != NULL) {
708 				if (((cp = strchr(hp->h_name, '.')) != NULL) &&
709 				    (strcmp(cp + 1, domain) == 0))
710 					*cp = 0;
711 				cp = hp->h_name;
712 			}
713 		}
714 		if (cp != NULL) {
715 			(void) strncpy(line, cp, MAXHOSTNAMELEN);
716 			line[MAXHOSTNAMELEN] = '\0';
717 		} else {
718 			(void) inet_ntop(AF_INET6, (void *)&in6, line,
719 			    INET6_ADDRSTRLEN);
720 		}
721 		if (hp != NULL)
722 			freehostent(hp);
723 
724 		break;
725 
726 	default:
727 		s = (ushort_t *)sa;
728 
729 		slim = s + ((salen(sa) + 1) >> 1);
730 		cp = line + sprintf(line, "(%d)", sa->sa_family);
731 
732 		while (++s < slim) /* start with sa->sa_data */
733 			cp += sprintf(cp, " %x", *s);
734 		break;
735 	}
736 	return (line);
737 }
738 
739 /*
740  * Return the name of the network whose address is given.
741  * The address is assumed to be that of a net or subnet, not a host.
742  */
743 static char *
744 netname(struct sockaddr *sa)
745 {
746 	char *cp = NULL;
747 	static char line[MAXHOSTNAMELEN + 1];
748 	struct netent *np;
749 	in_addr_t net, mask;
750 	int subnetshift;
751 	struct in_addr in;
752 	ushort_t *s;
753 	ushort_t *slim;
754 
755 	switch (sa->sa_family) {
756 
757 	case AF_INET:
758 		/* LINTED */
759 		in = ((struct sockaddr_in *)sa)->sin_addr;
760 
761 		in.s_addr = ntohl(in.s_addr);
762 		if (in.s_addr == INADDR_ANY) {
763 			cp = "default";
764 		} else if (!nflag) {
765 			if (IN_CLASSA(in.s_addr)) {
766 				mask = IN_CLASSA_NET;
767 				subnetshift = 8;
768 			} else if (IN_CLASSB(in.s_addr)) {
769 				mask = IN_CLASSB_NET;
770 				subnetshift = 8;
771 			} else {
772 				mask = IN_CLASSC_NET;
773 				subnetshift = 4;
774 			}
775 			/*
776 			 * If there are more bits than the standard mask
777 			 * would suggest, subnets must be in use.
778 			 * Guess at the subnet mask, assuming reasonable
779 			 * width subnet fields.
780 			 */
781 			while (in.s_addr &~ mask)
782 				mask = (long)mask >> subnetshift;
783 			net = in.s_addr & mask;
784 			while ((mask & 1) == 0)
785 				mask >>= 1, net >>= 1;
786 			np = getnetbyaddr(net, AF_INET);
787 			if (np != NULL)
788 				cp = np->n_name;
789 		}
790 		if (cp != NULL) {
791 			(void) strncpy(line, cp, MAXHOSTNAMELEN);
792 			line[MAXHOSTNAMELEN] = '\0';
793 		} else if ((in.s_addr & 0xffffff) == 0) {
794 			(void) sprintf(line, "%u", C(in.s_addr >> 24));
795 		} else if ((in.s_addr & 0xffff) == 0) {
796 			(void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
797 			    C(in.s_addr >> 16));
798 		} else if ((in.s_addr & 0xff) == 0) {
799 			(void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
800 			    C(in.s_addr >> 16), C(in.s_addr >> 8));
801 		} else {
802 			(void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
803 			    C(in.s_addr >> 16), C(in.s_addr >> 8),
804 			    C(in.s_addr));
805 		}
806 		break;
807 
808 	case AF_LINK:
809 		return (link_ntoa((struct sockaddr_dl *)sa));
810 
811 	case AF_INET6:
812 		return (routename(sa));
813 
814 	default:
815 		/* LINTED */
816 		s = (ushort_t *)sa->sa_data;
817 
818 		slim = s + ((salen(sa) + 1) >> 1);
819 		cp = line + sprintf(line, "af %d:", sa->sa_family);
820 
821 		while (s < slim)
822 			cp += sprintf(cp, " %x", *s++);
823 		break;
824 	}
825 	return (line);
826 }
827 
828 void
829 set_metric(char *value, int key)
830 {
831 	int flag = 0;
832 	uint_t noval, *valp = &noval;
833 
834 	switch (key) {
835 #define	caseof(x, y, z)	case (x): valp = &rt_metrics.z; flag = (y); break
836 	caseof(K_MTU, RTV_MTU, rmx_mtu);
837 	caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
838 	caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
839 	caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
840 	caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
841 	caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
842 	caseof(K_RTT, RTV_RTT, rmx_rtt);
843 	caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
844 #undef	caseof
845 	}
846 	rtm_inits |= flag;
847 	if (lockrest || locking)
848 		rt_metrics.rmx_locks |= flag;
849 	if (locking)
850 		locking = B_FALSE;
851 	*valp = atoi(value);
852 }
853 
854 int
855 newroute(int argc, char **argv)
856 {
857 	char *cmd, *dest = "", *gateway = "", *err;
858 	boolean_t ishost = B_FALSE;
859 	int ret, attempts, oerrno, flags = RTF_STATIC;
860 	int key;
861 	struct hostent *hp = NULL;
862 	static char obuf[INET6_ADDRSTRLEN];
863 
864 	cmd = argv[0];
865 	if (*cmd != 'g' && !tflag) {
866 		/* Don't want to read back our messages */
867 		(void) shutdown(s, 0);
868 	}
869 	while (--argc > 0) {
870 		key = keyword(*(++argv));
871 		if (key == K_HOST) {
872 			forcehost = B_TRUE;
873 		} else if (key == K_NET) {
874 			forcenet = B_TRUE;
875 		} else if (**(argv) == '-') {
876 			switch (key = keyword(1 + *argv)) {
877 			case K_LINK:
878 				af = AF_LINK;
879 				break;
880 			case K_INET:
881 				af = AF_INET;
882 				break;
883 			case K_SA:
884 				af = PF_ROUTE;
885 				break;
886 			case K_INET6:
887 				af = AF_INET6;
888 				break;
889 			case K_IFACE:
890 			case K_INTERFACE:
891 				iflag = B_TRUE;
892 				/* FALLTHROUGH */
893 			case K_NOSTATIC:
894 				flags &= ~RTF_STATIC;
895 				break;
896 			case K_LOCK:
897 				locking = B_TRUE;
898 				break;
899 			case K_LOCKREST:
900 				lockrest = B_TRUE;
901 				break;
902 			case K_HOST:
903 				forcehost = B_TRUE;
904 				break;
905 			case K_REJECT:
906 				flags |= RTF_REJECT;
907 				break;
908 			case K_BLACKHOLE:
909 				flags |= RTF_BLACKHOLE;
910 				break;
911 			case K_PROTO1:
912 				flags |= RTF_PROTO1;
913 				break;
914 			case K_PROTO2:
915 				flags |= RTF_PROTO2;
916 				break;
917 			case K_CLONING:
918 				flags |= RTF_CLONING;
919 				break;
920 			case K_XRESOLVE:
921 				flags |= RTF_XRESOLVE;
922 				break;
923 			case K_STATIC:
924 				flags |= RTF_STATIC;
925 				break;
926 			case K_IFA:
927 				argc--;
928 				(void) getaddr(RTA_IFA, *++argv, NULL);
929 				break;
930 			case K_IFP:
931 				argc--;
932 				(void) getaddr(RTA_IFP, *++argv, NULL);
933 				break;
934 			case K_GATEWAY:
935 				/*
936 				 * For the gateway parameter, retrieve the
937 				 * pointer to the struct hostent so that all
938 				 * possible addresses can be tried until one
939 				 * is successful.
940 				 */
941 				argc--;
942 				gateway = *++argv;
943 				(void) getaddr(RTA_GATEWAY, *argv, &hp);
944 				break;
945 			case K_DST:
946 				argc--;
947 				ishost = getaddr(RTA_DST, *++argv, NULL);
948 				dest = *argv;
949 				break;
950 			case K_NETMASK:
951 				argc--;
952 				(void) getaddr(RTA_NETMASK, *++argv, NULL);
953 				/* FALLTHROUGH */
954 			case K_NET:
955 				forcenet = B_TRUE;
956 				break;
957 			case K_MTU:
958 			case K_HOPCOUNT:
959 			case K_EXPIRE:
960 			case K_RECVPIPE:
961 			case K_SENDPIPE:
962 			case K_SSTHRESH:
963 			case K_RTT:
964 			case K_RTTVAR:
965 				argc--;
966 				set_metric(*++argv, key);
967 				break;
968 			case K_PRIVATE:
969 				flags |= RTF_PRIVATE;
970 				break;
971 			case K_MULTIRT:
972 				flags |= RTF_MULTIRT;
973 				break;
974 			case K_SETSRC:
975 				argc--;
976 				(void) getaddr(RTA_SRC, *++argv, NULL);
977 				flags |= RTF_SETSRC;
978 				break;
979 			default:
980 				usage(*argv + 1);
981 				/* NOTREACHED */
982 			}
983 		} else {
984 			if ((rtm_addrs & RTA_DST) == 0) {
985 				dest = *argv;
986 				ishost = getaddr(RTA_DST, *argv, NULL);
987 			} else if ((rtm_addrs & RTA_GATEWAY) == 0) {
988 				/*
989 				 * For the gateway parameter, retrieve the
990 				 * pointer to the struct hostent so that all
991 				 * possible addresses can be tried until one
992 				 * is successful.
993 				 */
994 				gateway = *argv;
995 				(void) getaddr(RTA_GATEWAY, *argv, &hp);
996 			} else {
997 				ulong_t metric = strtoul(*argv, &err, 10);
998 
999 				/*
1000 				 * Assume that a regular number is a metric.
1001 				 * Needed for compatibility with old route
1002 				 * command syntax.
1003 				 */
1004 				if (*argv != err && *err == '\0' &&
1005 				    metric < 0x80000000ul) {
1006 					iflag = (metric == 0);
1007 					if (verbose) {
1008 						(void) printf("old usage of "
1009 						    "trailing number, assuming "
1010 						    "route %s\n", iflag ?
1011 						    "to if" : "via gateway");
1012 					}
1013 					continue;
1014 				}
1015 				(void) getaddr(RTA_NETMASK, *argv, NULL);
1016 			}
1017 		}
1018 	}
1019 	if ((rtm_addrs & RTA_DST) == 0) {
1020 		(void) fprintf(stderr,
1021 		    gettext("route: destination required following command\n"));
1022 		usage((char *)NULL);
1023 	} else if ((*cmd == 'a' || *cmd == 'd') &&
1024 	    (rtm_addrs & RTA_GATEWAY) == 0) {
1025 		(void) fprintf(stderr,
1026 		    gettext("route: gateway required for add or delete "
1027 		    "command\n"));
1028 		usage((char *)NULL);
1029 	}
1030 
1031 	/*
1032 	 * If the netmask has been specified use it to determine RTF_HOST.
1033 	 * Otherwise rely on the "-net" and "-host" specifiers.
1034 	 * Final fallback is whether ot not any bits were set in the address
1035 	 * past the classful network component.
1036 	 */
1037 	if (rtm_addrs & RTA_NETMASK) {
1038 		if ((af == AF_INET &&
1039 			so_mask.sin.sin_addr.s_addr == IP_HOST_MASK) ||
1040 		    (af == AF_INET6 && masklen == IPV6_ABITS))
1041 			forcehost = B_TRUE;
1042 		else
1043 			forcenet = B_TRUE;
1044 	}
1045 	if (forcehost)
1046 		ishost = B_TRUE;
1047 	if (forcenet)
1048 		ishost = B_FALSE;
1049 	flags |= RTF_UP;
1050 	if (ishost)
1051 		flags |= RTF_HOST;
1052 	if (!iflag)
1053 		flags |= RTF_GATEWAY;
1054 	for (attempts = 1; ; attempts++) {
1055 		errno = 0;
1056 		if ((ret = rtmsg(*cmd, flags)) == 0)
1057 			break;
1058 		if (errno != ENETUNREACH && errno != ESRCH)
1059 			break;
1060 		if (*gateway != '\0' && hp != NULL &&
1061 		    hp->h_addr_list[attempts] != NULL) {
1062 			switch (af) {
1063 			case AF_INET:
1064 				(void) memmove(&so_gate.sin.sin_addr,
1065 				    hp->h_addr_list[attempts], hp->h_length);
1066 				continue;
1067 			case AF_INET6:
1068 				(void) memmove(&so_gate.sin6.sin6_addr,
1069 				    hp->h_addr_list[attempts], hp->h_length);
1070 				continue;
1071 			}
1072 		}
1073 		break;
1074 	}
1075 	oerrno = errno;
1076 	if (*cmd != 'g') {
1077 		(void) printf("%s %s %s", cmd, ishost ? "host" : "net", dest);
1078 		if (*gateway != '\0') {
1079 			switch (af) {
1080 			case AF_INET:
1081 				if (nflag) {
1082 					(void) printf(": gateway %s",
1083 					    inet_ntoa(so_gate.sin.sin_addr));
1084 				} else if (attempts > 1 && ret == 0) {
1085 					(void) printf(": gateway %s (%s)",
1086 					    gateway,
1087 					    inet_ntoa(so_gate.sin.sin_addr));
1088 				} else {
1089 					(void) printf(": gateway %s", gateway);
1090 				}
1091 				break;
1092 			case AF_INET6:
1093 				if (inet_ntop(AF_INET6,
1094 				    (void *)&so_gate.sin6.sin6_addr, obuf,
1095 				    INET6_ADDRSTRLEN) != NULL) {
1096 					if (nflag) {
1097 						(void) printf(": gateway %s",
1098 						    obuf);
1099 					} else if (attempts > 1 && ret == 0) {
1100 						(void) printf(": gateway %s "
1101 						    "(%s)",
1102 						    gateway, obuf);
1103 					}
1104 					break;
1105 				}
1106 				/* FALLTHROUGH */
1107 			default:
1108 				(void) printf(": gateway %s", gateway);
1109 				break;
1110 			}
1111 		}
1112 		if (ret == 0)
1113 			(void) printf("\n");
1114 	}
1115 	if (ret != 0) {
1116 		if (*cmd == 'g') {
1117 			if (nflag) {
1118 				switch (af) {
1119 				case AF_INET:
1120 					(void) printf(" %s",
1121 					    inet_ntoa(so_dst.sin.sin_addr));
1122 					break;
1123 				case AF_INET6:
1124 					if (inet_ntop(AF_INET6,
1125 					    (void *)&so_dst.sin6.sin6_addr,
1126 					    obuf, INET6_ADDRSTRLEN) != NULL) {
1127 						(void) printf(" %s", obuf);
1128 						break;
1129 					}
1130 					/* FALLTHROUGH */
1131 				default:
1132 					(void) printf("%s", dest);
1133 					break;
1134 				}
1135 			} else {
1136 				(void) printf("%s", dest);
1137 			}
1138 		}
1139 		switch (oerrno) {
1140 		case ESRCH:
1141 			err = "not in table";
1142 			break;
1143 		case EBUSY:
1144 			err = "entry in use";
1145 			break;
1146 		case ENOBUFS:
1147 			err = "routing table overflow";
1148 			break;
1149 		case EEXIST:
1150 			err = "entry exists";
1151 			break;
1152 		case EPERM:
1153 			err = "insufficient privileges";
1154 			break;
1155 		default:
1156 			err = strerror(oerrno);
1157 			break;
1158 		}
1159 		(void) printf(": %s\n", err);
1160 	}
1161 	/*
1162 	 * In the case of AF_INET6, one of the getipnodebyX() functions was used
1163 	 * so free the allocated hostent.
1164 	 */
1165 	if (af == AF_INET6 && hp != NULL)
1166 		freehostent(hp);
1167 
1168 	return (oerrno);
1169 }
1170 
1171 
1172 /*
1173  * Convert a network number to the corresponding IP address.
1174  * If the RTA_NETMASK hasn't been specified yet set it based
1175  * on the class of address.
1176  */
1177 static void
1178 inet_makenetandmask(in_addr_t net, struct sockaddr_in *sin)
1179 {
1180 	in_addr_t addr, mask;
1181 	char *cp;
1182 
1183 	if (net == 0) {
1184 		mask = addr = 0;
1185 	} else if (net < 128) {
1186 		addr = net << IN_CLASSA_NSHIFT;
1187 		mask = IN_CLASSA_NET;
1188 	} else if (net < 65536) {
1189 		addr = net << IN_CLASSB_NSHIFT;
1190 		mask = IN_CLASSB_NET;
1191 	} else if (net < 16777216L) {
1192 		addr = net << IN_CLASSC_NSHIFT;
1193 		mask = IN_CLASSC_NET;
1194 	} else {
1195 		addr = net;
1196 		if ((addr & IN_CLASSA_HOST) == 0)
1197 			mask =  IN_CLASSA_NET;
1198 		else if ((addr & IN_CLASSB_HOST) == 0)
1199 			mask =  IN_CLASSB_NET;
1200 		else if ((addr & IN_CLASSC_HOST) == 0)
1201 			mask =  IN_CLASSC_NET;
1202 		else {
1203 			if (IN_CLASSA(addr))
1204 				mask =  IN_CLASSA_NET;
1205 			else if (IN_CLASSB(addr))
1206 				mask =  IN_CLASSB_NET;
1207 			else if (IN_CLASSC(addr))
1208 				mask =  IN_CLASSC_NET;
1209 			else
1210 				mask = IP_HOST_MASK;
1211 			mask = inet_makesubnetmask(addr, mask);
1212 		}
1213 	}
1214 	sin->sin_addr.s_addr = htonl(addr);
1215 
1216 	if (!(rtm_addrs & RTA_NETMASK)) {
1217 		rtm_addrs |= RTA_NETMASK;
1218 		sin = &so_mask.sin;
1219 		sin->sin_addr.s_addr = htonl(mask);
1220 		sin->sin_family = AF_INET;
1221 		cp = (char *)(&sin->sin_addr + 1);
1222 		while (*--cp == 0 && cp > (char *)sin)
1223 			;
1224 	}
1225 }
1226 
1227 static in_addr_t
1228 inet_makesubnetmask(in_addr_t addr, in_addr_t mask)
1229 {
1230 	int n;
1231 	struct ifconf ifc;
1232 	struct ifreq ifreq;
1233 	struct ifreq *ifr;
1234 	struct sockaddr_in *sin;
1235 	char *buf;
1236 	int numifs;
1237 	size_t bufsize;
1238 	int iosoc;
1239 	in_addr_t if_addr, if_mask;
1240 	in_addr_t if_subnetmask = 0;
1241 	short if_flags;
1242 
1243 	if (mask == 0)
1244 		return (0);
1245 	if ((iosoc = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1246 		quit("socket", errno);
1247 	if (ioctl(iosoc, SIOCGIFNUM, (char *)&numifs) < 0)
1248 		quit("ioctl", errno);
1249 	bufsize = numifs * sizeof (struct ifreq);
1250 	buf = malloc(bufsize);
1251 	if (buf == NULL)
1252 		quit("malloc", errno);
1253 	(void) memset(&ifc, 0, sizeof (ifc));
1254 	ifc.ifc_len = bufsize;
1255 	ifc.ifc_buf = buf;
1256 	if (ioctl(iosoc, SIOCGIFCONF, (char *)&ifc) < 0)
1257 		quit("ioctl (get interface configuration)", errno);
1258 	/* Let's check to see if this is maybe a local subnet route. */
1259 	ifr = ifc.ifc_req;
1260 	for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) {
1261 		ifreq = *ifr;
1262 		/* LINTED */
1263 		sin = (struct sockaddr_in *)&ifr->ifr_addr;
1264 		if_addr = ntohl(sin->sin_addr.s_addr);
1265 
1266 		if (ioctl(iosoc, SIOCGIFFLAGS, (char *)&ifreq) < 0)
1267 			quit("ioctl (get interface flags)", errno);
1268 		if ((ifreq.ifr_flags & IFF_UP) == 0)
1269 			continue;
1270 		if_flags = ifreq.ifr_flags;
1271 
1272 		if (ioctl(iosoc, SIOCGIFNETMASK, (char *)&ifreq) < 0)
1273 			quit("ioctl (get netmask)", errno);
1274 		/* LINTED */
1275 		sin = (struct sockaddr_in *)&ifreq.ifr_addr;
1276 		if_mask = ntohl(sin->sin_addr.s_addr);
1277 		if ((if_addr & mask) == (addr & mask)) {
1278 			/*
1279 			 * Don't trust pt-pt interfaces if there are
1280 			 * other interfaces.
1281 			 */
1282 			if (if_flags & IFF_POINTOPOINT) {
1283 				if_subnetmask = if_mask;
1284 				continue;
1285 			}
1286 			/*
1287 			 * Fine.  Just assume the same net mask as the
1288 			 * directly attached subnet interface is using.
1289 			 */
1290 			return (if_mask);
1291 		}
1292 	}
1293 	if (if_subnetmask != 0)
1294 		return (if_subnetmask);
1295 	return (mask);
1296 }
1297 
1298 /*
1299  * Interpret an argument as a network address of some kind,
1300  * returning B_TRUE if a host address, B_FALSE if a network address.
1301  *
1302  * If the address family is one looked up in getaddr() using one of the
1303  * getipnodebyX() functions (currently only AF_INET6), then callers should
1304  * freehostent() the returned "struct hostent" pointer if one was passed in.
1305  */
1306 static boolean_t
1307 getaddr(int which, char *s, struct hostent **hpp)
1308 {
1309 	sup su;
1310 	struct hostent *hp;
1311 	boolean_t ret;
1312 
1313 	if (s == NULL) {
1314 		(void) fprintf(stderr,
1315 		    gettext("route: argument required following keyword\n"));
1316 		usage((char *)NULL);
1317 	}
1318 	if (hpp == NULL)
1319 		hpp = &hp;
1320 	*hpp = NULL;
1321 	rtm_addrs |= which;
1322 	switch (which) {
1323 	case RTA_DST:
1324 		su = &so_dst;
1325 		su->sa.sa_family = af;
1326 		break;
1327 	case RTA_GATEWAY:
1328 		su = &so_gate;
1329 		su->sa.sa_family = af;
1330 		break;
1331 	case RTA_NETMASK:
1332 		su = &so_mask;
1333 		su->sa.sa_family = af;
1334 		break;
1335 	case RTA_IFP:
1336 		so_ifp.sdl.sdl_index = if_nametoindex(s);
1337 		if (so_ifp.sdl.sdl_index == 0) {
1338 			if (errno == ENXIO) {
1339 				(void) fprintf(stderr,
1340 				    gettext("route: %s: no such interface\n"),
1341 					s);
1342 				exit(1);
1343 			} else {
1344 				quit("if_nametoindex", errno);
1345 			}
1346 		}
1347 		so_ifp.sdl.sdl_family = AF_LINK;
1348 		return (B_FALSE);
1349 		/*
1350 		 * RTA_SRC has overloaded meaning. It can represent the
1351 		 * src address of incoming or outgoing packets.
1352 		 */
1353 	case RTA_IFA:
1354 		su = &so_ifa;
1355 		su->sa.sa_family = af;
1356 		break;
1357 	case RTA_SRC:
1358 		su = &so_src;
1359 		su->sa.sa_family = af;
1360 		break;
1361 	default:
1362 		/* NOTREACHED */
1363 		quit(gettext("Internal Error"), EINVAL);
1364 		/* NOTREACHED */
1365 	}
1366 	if (strcmp(s, "default") == 0) {
1367 		if (which == RTA_DST) {
1368 			forcenet = B_TRUE;
1369 			(void) getaddr(RTA_NETMASK, s, NULL);
1370 		}
1371 		if (which == RTA_SRC) {
1372 			return (B_TRUE);
1373 		}
1374 		return (B_FALSE);
1375 	}
1376 	switch (af) {
1377 	case AF_LINK:
1378 		link_addr(s, &su->sdl);
1379 		return (B_TRUE);
1380 	case PF_ROUTE:
1381 		sockaddr(s, &su->sa);
1382 		return (B_TRUE);
1383 	case AF_INET6:
1384 		switch (which) {
1385 		case RTA_DST:
1386 			if (s[0] == '/') {
1387 				(void) fprintf(stderr,
1388 				    gettext("route: %s: unexpected '/'\n"), s);
1389 				exit(1);
1390 			}
1391 			ret = in6_getaddr(s, &su->sin6, &masklen, hpp);
1392 			switch (masklen) {
1393 			case NO_PREFIX:
1394 				/* Nothing there - ok */
1395 				return (ret);
1396 			case BAD_ADDR:
1397 				(void) fprintf(stderr,
1398 				    gettext("route: bad prefix length in %s\n"),
1399 					s);
1400 				exit(1);
1401 				/* NOTREACHED */
1402 			default:
1403 				(void) memset(&so_mask.sin6.sin6_addr, 0,
1404 				    sizeof (so_mask.sin6.sin6_addr));
1405 				if (!in_prefixlentomask(masklen, IPV6_ABITS,
1406 				    (uchar_t *)&so_mask.sin6.sin6_addr)) {
1407 					(void) fprintf(stderr,
1408 					    gettext("route: bad prefix length: "
1409 					    "%d\n"), masklen);
1410 					exit(1);
1411 				}
1412 				break;
1413 			}
1414 			so_mask.sin6.sin6_family = af;
1415 			rtm_addrs |= RTA_NETMASK;
1416 			return (ret);
1417 		case RTA_GATEWAY:
1418 		case RTA_IFA:
1419 		case RTA_SRC:
1420 			ret = in6_getaddr(s, &su->sin6, NULL, hpp);
1421 			return (ret);
1422 		case RTA_NETMASK:
1423 			(void) fprintf(stderr,
1424 			    gettext("route: -netmask not supported for IPv6: "
1425 			    "use <prefix>/<prefix-length> instead"));
1426 			exit(1);
1427 			/* NOTREACHED */
1428 		default:
1429 			quit(gettext("Internal Error"), EINVAL);
1430 			/* NOTREACHED */
1431 		}
1432 	case AF_INET:
1433 		switch (which) {
1434 		case RTA_DST:
1435 			if (s[0] == '/') {
1436 				(void) fprintf(stderr,
1437 				    gettext("route: %s: unexpected '/'\n"), s);
1438 				exit(1);
1439 			}
1440 			ret = in_getaddr(s, &su->sin, &masklen, which, hpp);
1441 			switch (masklen) {
1442 			case NO_PREFIX:
1443 				/* Nothing there - ok */
1444 				return (ret);
1445 			case BAD_ADDR:
1446 				(void) fprintf(stderr,
1447 				    gettext("route: bad prefix length in %s\n"),
1448 					    s);
1449 				exit(1);
1450 				/* NOTREACHED */
1451 			default:
1452 				(void) memset(&so_mask.sin.sin_addr, 0,
1453 				    sizeof (so_mask.sin.sin_addr));
1454 				if (!in_prefixlentomask(masklen, IP_ABITS,
1455 				    (uchar_t *)&so_mask.sin.sin_addr)) {
1456 					(void) fprintf(stderr,
1457 					    gettext("route: bad prefix length: "
1458 					    "%d\n"), masklen);
1459 					exit(1);
1460 				}
1461 				break;
1462 			}
1463 			so_mask.sin.sin_family = af;
1464 			rtm_addrs |= RTA_NETMASK;
1465 			return (ret);
1466 		case RTA_GATEWAY:
1467 		case RTA_IFA:
1468 		case RTA_NETMASK:
1469 		case RTA_SRC:
1470 			ret = in_getaddr(s, &su->sin, NULL, which, hpp);
1471 			return (ret);
1472 		default:
1473 			quit(gettext("Internal Error"), EINVAL);
1474 			/* NOTREACHED */
1475 		}
1476 	default:
1477 		quit(gettext("Internal Error"), EINVAL);
1478 		/* NOTREACHED */
1479 	}
1480 
1481 }
1482 
1483 /*
1484  * Interpret an argument as an IPv4 network address of some kind,
1485  * returning B_TRUE if a host address, B_FALSE if a network address.
1486  * Note that this *always* tries host interpretation before network
1487  * interpretation.
1488  *
1489  * If the plenp argument is non-NULL, allow <addr>/<n> syntax and
1490  * pass out <n> in *plenp.
1491  * If <n> doesn't parse return BAD_ADDR as *plenp.
1492  * If no /<n> is present return NO_PREFIX as *plenp.
1493  */
1494 static boolean_t
1495 in_getaddr(char *s, struct sockaddr_in *sin, int *plenp, int which,
1496     struct hostent **hpp)
1497 {
1498 	struct hostent *hp;
1499 	struct netent *np;
1500 	in_addr_t val;
1501 	char str[BUFSIZ];
1502 
1503 	(void) strncpy(str, s, sizeof (str));
1504 
1505 	/*
1506 	 * Look for '/'<n> is plenp
1507 	 */
1508 	if (plenp != NULL) {
1509 		char *cp;
1510 
1511 		*plenp = in_getprefixlen(str, IP_ABITS);
1512 		if (*plenp == BAD_ADDR)
1513 			return (B_FALSE);
1514 		cp = strchr(str, '/');
1515 		if (cp != NULL)
1516 			*cp = '\0';
1517 	} else if (strchr(str, '/') != NULL) {
1518 		(void) fprintf(stderr, gettext("route: %s: unexpected '/'\n"),
1519 			str);
1520 		exit(1);
1521 	}
1522 
1523 	(void) memset(sin, 0, sizeof (*sin));
1524 	sin->sin_family = AF_INET;
1525 
1526 	/*
1527 	 * Note: only the route destination can be a network, so we treat
1528 	 * all other addresses as though "-net" was not specified.
1529 	 */
1530 	if ((((val = inet_addr(str)) != (in_addr_t)-1) ||
1531 	    strcmp(str, "255.255.255.255") == 0) &&
1532 	    (which != RTA_DST || !forcenet)) {
1533 		sin->sin_addr.s_addr = val;
1534 		if (inet_lnaof(sin->sin_addr) != INADDR_ANY ||
1535 		    forcehost)
1536 			return (B_TRUE);
1537 		val = ntohl(val);
1538 		if (which == RTA_DST)
1539 			inet_makenetandmask(val, sin);
1540 		return (B_FALSE);
1541 	}
1542 	if (!forcehost && (val = inet_network(str)) != (in_addr_t)-1) {
1543 		if (which == RTA_DST)
1544 			inet_makenetandmask(val, sin);
1545 		return (B_FALSE);
1546 	}
1547 	if ((which != RTA_DST || !forcenet) &&
1548 	    (hp = gethostbyname(str)) != NULL) {
1549 		*hpp = hp;
1550 		(void) memmove(&sin->sin_addr, hp->h_addr,
1551 		    hp->h_length);
1552 		return (B_TRUE);
1553 	}
1554 	if (!forcehost && (np = getnetbyname(str)) != NULL &&
1555 	    (val = np->n_net) != 0) {
1556 		if (which == RTA_DST)
1557 			inet_makenetandmask(val, sin);
1558 		return (B_FALSE);
1559 	}
1560 	(void) fprintf(stderr, gettext("%s: bad value\n"), s);
1561 	exit(1);
1562 	/* NOTREACHED */
1563 }
1564 
1565 /*
1566  * Interpret an argument as an IPv6 network address of some kind,
1567  * returning B_TRUE if a host address, B_FALSE if a network address.
1568  *
1569  * If the last argument is non-NULL allow a <addr>/<n> syntax and
1570  * pass out <n> in *plenp.
1571  * If <n> doesn't parse return BAD_ADDR as *plenp.
1572  * If no /<n> is present return NO_PREFIX as *plenp.
1573  */
1574 static boolean_t
1575 in6_getaddr(char *s, struct sockaddr_in6 *sin6, int *plenp,
1576     struct hostent **hpp)
1577 {
1578 	struct hostent *hp;
1579 	char str[BUFSIZ];
1580 	int error_num;
1581 
1582 	(void) strncpy(str, s, sizeof (str));
1583 
1584 	/*
1585 	 * Look for '/'<n> is plenp
1586 	 */
1587 	if (plenp != NULL) {
1588 		char *cp;
1589 
1590 		*plenp = in_getprefixlen(str, IPV6_ABITS);
1591 		if (*plenp == BAD_ADDR)
1592 			return (B_FALSE);
1593 		cp = strchr(str, '/');
1594 		if (cp != NULL)
1595 			*cp = '\0';
1596 	} else if (strchr(str, '/') != NULL) {
1597 		(void) fprintf(stderr, gettext("route: %s: unexpected '/'\n"),
1598 			str);
1599 		exit(1);
1600 	}
1601 
1602 	(void) memset(sin6, 0, sizeof (struct sockaddr_in6));
1603 	sin6->sin6_family = AF_INET6;
1604 
1605 	hp = getipnodebyname(str, AF_INET6, 0, &error_num);
1606 	if (hp != NULL) {
1607 		*hpp = hp;
1608 		(void) memmove(&sin6->sin6_addr, hp->h_addr, hp->h_length);
1609 		return (B_TRUE);
1610 	}
1611 	if (error_num == TRY_AGAIN) {
1612 		(void) fprintf(stderr, gettext("route: %s: bad address (try "
1613 		    "again later)\n"), s);
1614 	} else {
1615 		(void) fprintf(stderr, gettext("route: %s: bad address\n"), s);
1616 	}
1617 	exit(1);
1618 	/* NOTREACHED */
1619 }
1620 
1621 /*
1622  * If "slash" is zero this parses the whole string as
1623  * an integer. With "slash" non zero it parses the tail part as an integer.
1624  *
1625  * If it is not a valid integer this returns BAD_ADDR.
1626  * If there is /<n> present this returns NO_PREFIX.
1627  */
1628 int
1629 in_getprefixlen(char *addr, int max_plen)
1630 {
1631 	int prefixlen;
1632 	char *str, *end;
1633 
1634 	str = strchr(addr, '/');
1635 	if (str == NULL)
1636 		return (NO_PREFIX);
1637 	str++;
1638 
1639 	prefixlen = strtol(str, &end, 10);
1640 	if (prefixlen < 0)
1641 		return (BAD_ADDR);
1642 	if (str == end)
1643 		return (BAD_ADDR);
1644 	if (max_plen != 0 && max_plen < prefixlen)
1645 		return (BAD_ADDR);
1646 	else
1647 		return (prefixlen);
1648 }
1649 
1650 /*
1651  * Convert a prefix length to a mask.
1652  * Returns B_TRUE if ok. B_FALSE otherwise.
1653  * Assumes the mask array is zeroed by the caller.
1654  */
1655 boolean_t
1656 in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask)
1657 {
1658 	if (prefixlen < 0 || prefixlen > maxlen)
1659 		return (B_FALSE);
1660 
1661 	while (prefixlen > 0) {
1662 		if (prefixlen >= 8) {
1663 			*mask++ = 0xFF;
1664 			prefixlen -= 8;
1665 			continue;
1666 		}
1667 		*mask |= 1 << (8 - prefixlen);
1668 		prefixlen--;
1669 	}
1670 	return (B_TRUE);
1671 }
1672 
1673 void
1674 rtmonitor(int argc, char *argv[])
1675 {
1676 	int n;
1677 	intmax_t msg[2048 / sizeof (intmax_t)];
1678 
1679 	if (tflag)
1680 		exit(0);
1681 	verbose = B_TRUE;
1682 	if (argc > 1) {
1683 		argv++;
1684 		if (argc == 2 && **argv == '-') {
1685 			switch (keyword(*argv + 1)) {
1686 			case K_INET:
1687 				af = AF_INET;
1688 				break;
1689 			case K_LINK:
1690 				af = AF_LINK;
1691 				break;
1692 			case K_INET6:
1693 				af = AF_INET6;
1694 				break;
1695 			default:
1696 				usage(*argv);
1697 				/* NOTREACHED */
1698 			}
1699 		} else {
1700 			usage(*argv);
1701 		}
1702 		(void) close(s);
1703 		s = socket(PF_ROUTE, SOCK_RAW, af);
1704 		if (s < 0)
1705 			quit("socket", errno);
1706 	}
1707 	for (;;) {
1708 		n = read(s, msg, sizeof (msg));
1709 		if (n <= 0)
1710 			quit("read", errno);
1711 		(void) printf("got message of size %d\n", n);
1712 		print_rtmsg((struct rt_msghdr *)msg, n);
1713 	}
1714 }
1715 
1716 int
1717 rtmsg(int cmd, int flags)
1718 {
1719 	static int seq;
1720 	int rlen;
1721 	char *cp = m_rtmsg.m_space;
1722 	int l;
1723 
1724 	errno = 0;
1725 	(void) memset(&m_rtmsg, 0, sizeof (m_rtmsg));
1726 	if (cmd == 'a') {
1727 		cmd = RTM_ADD;
1728 	} else if (cmd == 'c') {
1729 		cmd = RTM_CHANGE;
1730 	} else if (cmd == 'g') {
1731 		cmd = RTM_GET;
1732 		if (so_ifp.sa.sa_family == 0) {
1733 			so_ifp.sa.sa_family = AF_LINK;
1734 			rtm_addrs |= RTA_IFP;
1735 		}
1736 	} else {
1737 		cmd = RTM_DELETE;
1738 	}
1739 #define	rtm m_rtmsg.m_rtm
1740 	rtm.rtm_type = cmd;
1741 	rtm.rtm_flags = flags;
1742 	rtm.rtm_version = RTM_VERSION;
1743 	rtm.rtm_seq = ++seq;
1744 	rtm.rtm_addrs = rtm_addrs;
1745 	rtm.rtm_rmx = rt_metrics;
1746 	rtm.rtm_inits = rtm_inits;
1747 
1748 #define	NEXTADDR(w, u) \
1749 	if (rtm_addrs & (w)) { \
1750 		l = ROUNDUP_LONG(salen(&u.sa)); \
1751 		(void) memmove(cp, &(u), l); \
1752 		cp += l; \
1753 		if (verbose) \
1754 			sodump(&(u), #u); \
1755 	}
1756 	NEXTADDR(RTA_DST, so_dst);
1757 	NEXTADDR(RTA_GATEWAY, so_gate);
1758 	NEXTADDR(RTA_NETMASK, so_mask);
1759 	NEXTADDR(RTA_IFP, so_ifp);
1760 	NEXTADDR(RTA_IFA, so_ifa);
1761 	/*
1762 	 * RTA_SRC has overloaded meaning. It can represent the
1763 	 * src address of incoming or outgoing packets.
1764 	 */
1765 	NEXTADDR(RTA_SRC, so_src);
1766 #undef	NEXTADDR
1767 	rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
1768 	if (verbose)
1769 		print_rtmsg(&rtm, l);
1770 	if (debugonly)
1771 		return (0);
1772 	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
1773 		switch (errno) {
1774 		case ESRCH:
1775 		case EBUSY:
1776 		case ENOBUFS:
1777 		case EEXIST:
1778 		case ENETUNREACH:
1779 		case EHOSTUNREACH:
1780 		case EPERM:
1781 			break;
1782 		default:
1783 			perror(gettext("writing to routing socket"));
1784 			break;
1785 		}
1786 		return (-1);
1787 	} else if (rlen < (int)rtm.rtm_msglen) {
1788 		(void) fprintf(stderr,
1789 		    gettext("route: write to routing socket got only %d for "
1790 		    "len\n"), rlen);
1791 		return (-1);
1792 	}
1793 	if (cmd == RTM_GET) {
1794 		do {
1795 			l = read(s, (char *)&m_rtmsg, sizeof (m_rtmsg));
1796 		} while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
1797 		if (l < 0) {
1798 			(void) fprintf(stderr,
1799 			    gettext("route: read from routing socket: %s\n"),
1800 			    strerror(errno));
1801 		} else {
1802 			print_getmsg(&rtm, l);
1803 		}
1804 	}
1805 #undef rtm
1806 	return (0);
1807 }
1808 
1809 static char *msgtypes[] = {
1810 	"",
1811 	"RTM_ADD: Add Route",
1812 	"RTM_DELETE: Delete Route",
1813 	"RTM_CHANGE: Change Metrics or flags",
1814 	"RTM_GET: Report Metrics",
1815 	"RTM_LOSING: Kernel Suspects Partitioning",
1816 	"RTM_REDIRECT: Told to use different route",
1817 	"RTM_MISS: Lookup failed on this address",
1818 	"RTM_LOCK: fix specified metrics",
1819 	"RTM_OLDADD: caused by SIOCADDRT",
1820 	"RTM_OLDDEL: caused by SIOCDELRT",
1821 	"RTM_RESOLVE: Route created by cloning",
1822 	"RTM_NEWADDR: address being added to iface",
1823 	"RTM_DELADDR: address being removed from iface",
1824 	"RTM_IFINFO: iface status change",
1825 	0,
1826 };
1827 
1828 #define	NMSGTYPES (sizeof (msgtypes) / sizeof (msgtypes[0]))
1829 
1830 static char metricnames[] =
1831 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
1832 	"\1mtu";
1833 static char routeflags[] =
1834 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"
1835 	"\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE"
1836 	"\016PRIVATE\017PROTO2\020PROTO1\021MULTIRT\022SETSRC";
1837 static char ifnetflags[] =
1838 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP"
1839 	"\011PPROMISC\012ALLMULTI\013INTELLIGENT\014MULTICAST"
1840 	"\015MULTI_BCAST\016UNNUMBERED\017DHCP\020PRIVATE"
1841 	"\021NOXMIT\022NOLOCAL\023DEPRECATED\024ADDRCONF"
1842 	"\025ROUTER\026NONUD\027ANYCAST\030NORTEXCH\031IPv4\032IPv6"
1843 	"\033MIP\034NOFAILOVER\035FAILED\036STANDBY\037INACTIVE\040OFFLINE"
1844 	"\041XRESOLV\042COS\043PREFERRED\044TEMPORARY";
1845 static char addrnames[] =
1846 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC";
1847 
1848 void
1849 print_rtmsg(struct rt_msghdr *rtm, int msglen)
1850 {
1851 	struct if_msghdr *ifm;
1852 	struct ifa_msghdr *ifam;
1853 
1854 	if (!verbose)
1855 		return;
1856 	if (rtm->rtm_version != RTM_VERSION) {
1857 		(void) printf("routing message version %d not understood\n",
1858 		    rtm->rtm_version);
1859 		return;
1860 	}
1861 	if (rtm->rtm_msglen > (ushort_t)msglen) {
1862 		(void) printf("message length mismatch, in packet %d, "
1863 		    "returned %d\n",
1864 		    rtm->rtm_msglen, msglen);
1865 	}
1866 	/*
1867 	 * Since rtm->rtm_type is unsigned, we'll just check the case of zero
1868 	 * and the upper-bound of (NMSGTYPES - 1).
1869 	 */
1870 	if (rtm->rtm_type == 0 || rtm->rtm_type >= (NMSGTYPES - 1)) {
1871 		(void) printf("routing message type %d not understood\n",
1872 		    rtm->rtm_type);
1873 		return;
1874 	}
1875 	(void) printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen);
1876 	switch (rtm->rtm_type) {
1877 	case RTM_IFINFO:
1878 		ifm = (struct if_msghdr *)rtm;
1879 		(void) printf("if# %d, flags:", ifm->ifm_index);
1880 		bprintf(stdout, ifm->ifm_flags, ifnetflags);
1881 		pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
1882 		break;
1883 	case RTM_NEWADDR:
1884 	case RTM_DELADDR:
1885 		ifam = (struct ifa_msghdr *)rtm;
1886 		(void) printf("metric %d, flags:", ifam->ifam_metric);
1887 		bprintf(stdout, ifam->ifam_flags, routeflags);
1888 		pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
1889 		break;
1890 	default:
1891 		(void) printf("pid: %ld, seq %d, errno %d, flags:",
1892 			rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1893 		bprintf(stdout, rtm->rtm_flags, routeflags);
1894 		pmsg_common(rtm);
1895 	}
1896 }
1897 
1898 void
1899 print_getmsg(struct rt_msghdr *rtm, int msglen)
1900 {
1901 	struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *src = NULL;
1902 	struct sockaddr_dl *ifp = NULL;
1903 	struct sockaddr *sa;
1904 	char *cp;
1905 	int i;
1906 
1907 	(void) printf("   route to: %s\n", routename(&so_dst.sa));
1908 	if (rtm->rtm_version != RTM_VERSION) {
1909 		(void) fprintf(stderr,
1910 		    gettext("routing message version %d not understood\n"),
1911 		    rtm->rtm_version);
1912 		return;
1913 	}
1914 	if (rtm->rtm_msglen > (ushort_t)msglen) {
1915 		(void) fprintf(stderr,
1916 		    gettext("message length mismatch, in packet %d, "
1917 			"returned %d\n"), rtm->rtm_msglen, msglen);
1918 	}
1919 	if (rtm->rtm_errno)  {
1920 		(void) fprintf(stderr, "RTM_GET: %s (errno %d)\n",
1921 		    strerror(rtm->rtm_errno), rtm->rtm_errno);
1922 		return;
1923 	}
1924 	cp = ((char *)(rtm + 1));
1925 	if (rtm->rtm_addrs != 0) {
1926 		for (i = 1; i != 0; i <<= 1) {
1927 			if (i & rtm->rtm_addrs) {
1928 				/* LINTED */
1929 				sa = (struct sockaddr *)cp;
1930 				switch (i) {
1931 				case RTA_DST:
1932 					dst = sa;
1933 					break;
1934 				case RTA_GATEWAY:
1935 					gate = sa;
1936 					break;
1937 				case RTA_NETMASK:
1938 					mask = sa;
1939 					break;
1940 				case RTA_IFP:
1941 					if (sa->sa_family == AF_LINK &&
1942 					    ((struct sockaddr_dl *)sa)->
1943 						sdl_nlen != 0)
1944 						ifp = (struct sockaddr_dl *)sa;
1945 					break;
1946 				case RTA_SRC:
1947 					src = sa;
1948 					break;
1949 				}
1950 				ADVANCE(cp, sa);
1951 			}
1952 		}
1953 	}
1954 	if (dst != NULL && mask != NULL)
1955 		mask->sa_family = dst->sa_family;	/* XXX */
1956 	if (dst != NULL)
1957 		(void) printf("destination: %s\n", routename(dst));
1958 	if (mask != NULL) {
1959 		boolean_t savenflag = nflag;
1960 
1961 		nflag = B_TRUE;
1962 		(void) printf("       mask: %s\n", routename(mask));
1963 		nflag = savenflag;
1964 	}
1965 	if (gate != NULL && rtm->rtm_flags & RTF_GATEWAY)
1966 		(void) printf("    gateway: %s\n", routename(gate));
1967 	if (src != NULL && rtm->rtm_flags & RTF_SETSRC)
1968 		(void) printf("     setsrc: %s\n", routename(src));
1969 	if (ifp != NULL) {
1970 		if (verbose) {
1971 			int i;
1972 
1973 			(void) printf("  interface: %.*s index %d address ",
1974 			    ifp->sdl_nlen, ifp->sdl_data, ifp->sdl_index);
1975 			for (i = ifp->sdl_nlen;
1976 			    i < ifp->sdl_nlen + ifp->sdl_alen;
1977 			    i++) {
1978 				(void) printf("%02x ",
1979 				    ifp->sdl_data[i] & 0xFF);
1980 			}
1981 			(void) printf("\n");
1982 		} else {
1983 			(void) printf("  interface: %.*s\n",
1984 			    ifp->sdl_nlen, ifp->sdl_data);
1985 		}
1986 	}
1987 	(void) printf("      flags: ");
1988 	bprintf(stdout, rtm->rtm_flags, routeflags);
1989 
1990 #define	lock(f)	((rtm->rtm_rmx.rmx_locks & RTV_ ## f) ? 'L' : ' ')
1991 #define	msec(u)	(((u) + 500) / 1000)		/* usec to msec */
1992 
1993 	(void) printf("\n%s\n", " recvpipe  sendpipe  ssthresh    rtt,ms "
1994 	    "rttvar,ms  hopcount      mtu     expire");
1995 	(void) printf("%8d%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
1996 	(void) printf("%8d%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
1997 	(void) printf("%8d%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
1998 	(void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
1999 	(void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
2000 	(void) printf("%8d%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
2001 	(void) printf("%8d%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
2002 	if (rtm->rtm_rmx.rmx_expire)
2003 		rtm->rtm_rmx.rmx_expire -= time(0);
2004 	(void) printf("%8d%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
2005 #undef lock
2006 #undef msec
2007 #define	RTA_IGN	\
2008 	(RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD|RTA_SRC)
2009 	if (verbose) {
2010 		pmsg_common(rtm);
2011 	} else if (rtm->rtm_addrs &~ RTA_IGN) {
2012 		(void) printf("sockaddrs: ");
2013 		bprintf(stdout, rtm->rtm_addrs, addrnames);
2014 		(void) putchar('\n');
2015 	}
2016 #undef	RTA_IGN
2017 }
2018 
2019 void
2020 pmsg_common(struct rt_msghdr *rtm)
2021 {
2022 	(void) printf("\nlocks: ");
2023 	bprintf(stdout, (int)rtm->rtm_rmx.rmx_locks, metricnames);
2024 	(void) printf(" inits: ");
2025 	bprintf(stdout, (int)rtm->rtm_inits, metricnames);
2026 	pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
2027 }
2028 
2029 void
2030 pmsg_addrs(char *cp, int addrs)
2031 {
2032 	struct sockaddr *sa;
2033 	int i;
2034 
2035 	if (addrs == 0)
2036 		return;
2037 	(void) printf("\nsockaddrs: ");
2038 	bprintf(stdout, addrs, addrnames);
2039 	(void) putchar('\n');
2040 	for (i = 1; i != 0; i <<= 1) {
2041 		if (i & addrs) {
2042 			/* LINTED */
2043 			sa = (struct sockaddr *)cp;
2044 			(void) printf(" %s", routename(sa));
2045 			ADVANCE(cp, sa);
2046 		}
2047 	}
2048 	(void) putchar('\n');
2049 	(void) fflush(stdout);
2050 }
2051 
2052 void
2053 bprintf(FILE *fp, int b, char *s)
2054 {
2055 	int i;
2056 	boolean_t gotsome = B_FALSE;
2057 
2058 	if (b == 0)
2059 		return;
2060 	while ((i = *s++) != 0) {
2061 		if (b & (1 << (i - 1))) {
2062 			if (!gotsome)
2063 				i = '<';
2064 			else
2065 				i = ',';
2066 			(void) putc(i, fp);
2067 			gotsome = B_TRUE;
2068 			for (; (i = *s) > ' '; s++)
2069 				(void) putc(i, fp);
2070 		} else {
2071 			while (*s > ' ')
2072 				s++;
2073 		}
2074 	}
2075 	if (gotsome)
2076 		(void) putc('>', fp);
2077 }
2078 
2079 int
2080 keyword(char *cp)
2081 {
2082 	struct keytab *kt = keywords;
2083 
2084 	while (kt->kt_cp && strcmp(kt->kt_cp, cp))
2085 		kt++;
2086 	return (kt->kt_i);
2087 }
2088 
2089 void
2090 sodump(sup su, char *which)
2091 {
2092 	static char obuf[INET6_ADDRSTRLEN];
2093 
2094 	switch (su->sa.sa_family) {
2095 	case AF_LINK:
2096 		(void) printf("%s: link %s; ",
2097 		    which, link_ntoa(&su->sdl));
2098 		break;
2099 	case AF_INET:
2100 		(void) printf("%s: inet %s; ",
2101 		    which, inet_ntoa(su->sin.sin_addr));
2102 		break;
2103 	case AF_INET6:
2104 		if (inet_ntop(AF_INET6, (void *)&su->sin6.sin6_addr, obuf,
2105 		    INET6_ADDRSTRLEN) != NULL) {
2106 			(void) printf("%s: inet6 %s; ", which, obuf);
2107 			break;
2108 		}
2109 		/* FALLTHROUGH */
2110 	default:
2111 		quit(gettext("Internal Error"), EINVAL);
2112 		/* NOTREACHED */
2113 	}
2114 	(void) fflush(stdout);
2115 }
2116 
2117 /* States */
2118 #define	VIRGIN	0
2119 #define	GOTONE	1
2120 #define	GOTTWO	2
2121 #define	RESET	3
2122 /* Inputs */
2123 #define	DIGIT	(4*0)
2124 #define	END	(4*1)
2125 #define	DELIM	(4*2)
2126 #define	LETTER	(4*3)
2127 
2128 void
2129 sockaddr(char *addr, struct sockaddr *sa)
2130 {
2131 	char *cp = (char *)sa;
2132 	int size = salen(sa);
2133 	char *cplim = cp + size;
2134 	int byte = 0, state = VIRGIN, new;
2135 
2136 	(void) memset(cp, 0, size);
2137 	cp++;
2138 	do {
2139 		if ((*addr >= '0') && (*addr <= '9')) {
2140 			new = *addr - '0';
2141 		} else if ((*addr >= 'a') && (*addr <= 'f')) {
2142 			new = *addr - 'a' + 10;
2143 		} else if ((*addr >= 'A') && (*addr <= 'F')) {
2144 			new = *addr - 'A' + 10;
2145 		} else if (*addr == 0) {
2146 			state |= END;
2147 		} else {
2148 			state |= DELIM;
2149 		}
2150 		addr++;
2151 		switch (state /* | INPUT */) {
2152 		case GOTTWO | DIGIT:
2153 			*cp++ = byte;
2154 			/* FALLTHROUGH */
2155 		case VIRGIN | DIGIT:
2156 			state = GOTONE; byte = new; continue;
2157 		case GOTONE | DIGIT:
2158 			state = GOTTWO; byte = new + (byte << 4); continue;
2159 		default: /* | DELIM */
2160 			state = VIRGIN; *cp++ = byte; byte = 0; continue;
2161 		case GOTONE | END:
2162 		case GOTTWO | END:
2163 			*cp++ = byte;
2164 			/* FALLTHROUGH */
2165 		case VIRGIN | END:
2166 			break;
2167 		}
2168 		break;
2169 	} while (cp < cplim);
2170 }
2171 
2172 int
2173 salen(struct sockaddr *sa)
2174 {
2175 	switch (sa->sa_family) {
2176 	case AF_INET:
2177 		return (sizeof (struct sockaddr_in));
2178 	case AF_LINK:
2179 		return (sizeof (struct sockaddr_dl));
2180 	case AF_INET6:
2181 		return (sizeof (struct sockaddr_in6));
2182 	default:
2183 		return (sizeof (struct sockaddr));
2184 	}
2185 }
2186 
2187 void
2188 link_addr(const char *addr, struct sockaddr_dl *sdl)
2189 {
2190 	char *cp = sdl->sdl_data;
2191 	char *cplim = sizeof (struct sockaddr_dl) + (char *)sdl;
2192 	int byte = 0, state = VIRGIN, new;
2193 
2194 	(void) memset(sdl, 0, sizeof (struct sockaddr_dl));
2195 	sdl->sdl_family = AF_LINK;
2196 	do {
2197 		state &= ~LETTER;
2198 		if ((*addr >= '0') && (*addr <= '9')) {
2199 			new = *addr - '0';
2200 		} else if ((*addr >= 'a') && (*addr <= 'f')) {
2201 			new = *addr - 'a' + 10;
2202 		} else if ((*addr >= 'A') && (*addr <= 'F')) {
2203 			new = *addr - 'A' + 10;
2204 		} else if (*addr == 0) {
2205 			state |= END;
2206 		} else if (state == VIRGIN &&
2207 		    (((*addr >= 'A') && (*addr <= 'Z')) ||
2208 		    ((*addr >= 'a') && (*addr <= 'z')))) {
2209 			state |= LETTER;
2210 		} else {
2211 			state |= DELIM;
2212 		}
2213 		addr++;
2214 		switch (state /* | INPUT */) {
2215 		case VIRGIN | DIGIT:
2216 		case VIRGIN | LETTER:
2217 			*cp++ = addr[-1];
2218 			continue;
2219 		case VIRGIN | DELIM:
2220 			state = RESET;
2221 			sdl->sdl_nlen = cp - sdl->sdl_data;
2222 			continue;
2223 		case GOTTWO | DIGIT:
2224 			*cp++ = byte;
2225 			/* FALLTHROUGH */
2226 		case RESET | DIGIT:
2227 			state = GOTONE;
2228 			byte = new;
2229 			continue;
2230 		case GOTONE | DIGIT:
2231 			state = GOTTWO;
2232 			byte = new + (byte << 4);
2233 			continue;
2234 		default: /* | DELIM */
2235 			state = RESET;
2236 			*cp++ = byte;
2237 			byte = 0;
2238 			continue;
2239 		case GOTONE | END:
2240 		case GOTTWO | END:
2241 			*cp++ = byte;
2242 			/* FALLTHROUGH */
2243 		case RESET | END:
2244 			break;
2245 		}
2246 		break;
2247 	} while (cp < cplim);
2248 	sdl->sdl_alen = cp - LLADDR(sdl);
2249 }
2250 
2251 static char hexlist[] = "0123456789abcdef";
2252 
2253 char *
2254 link_ntoa(const struct sockaddr_dl *sdl)
2255 {
2256 	static char obuf[64];
2257 	char *out = obuf;
2258 	int i;
2259 	uchar_t *in = (uchar_t *)LLADDR(sdl);
2260 	uchar_t *inlim = in + sdl->sdl_alen;
2261 	boolean_t firsttime = B_TRUE;
2262 
2263 	if (sdl->sdl_nlen) {
2264 		(void) memcpy(obuf, sdl->sdl_data, sdl->sdl_nlen);
2265 		out += sdl->sdl_nlen;
2266 		if (sdl->sdl_alen)
2267 			*out++ = ':';
2268 	}
2269 	while (in < inlim) {
2270 		if (firsttime)
2271 			firsttime = B_FALSE;
2272 		else
2273 			*out++ = '.';
2274 		i = *in++;
2275 		if (i > 0xf) {
2276 			out[1] = hexlist[i & 0xf];
2277 			i >>= 4;
2278 			out[0] = hexlist[i];
2279 			out += 2;
2280 		} else {
2281 			*out++ = hexlist[i];
2282 		}
2283 	}
2284 	*out = 0;
2285 	return (obuf);
2286 }
2287 
2288 static mib_item_t *
2289 mibget(int sd)
2290 {
2291 	intmax_t		buf[512 / sizeof (intmax_t)];
2292 	int			flags;
2293 	int			i, j, getcode;
2294 	struct strbuf		ctlbuf, databuf;
2295 	struct T_optmgmt_req	*tor = (struct T_optmgmt_req *)buf;
2296 	struct T_optmgmt_ack	*toa = (struct T_optmgmt_ack *)buf;
2297 	struct T_error_ack	*tea = (struct T_error_ack *)buf;
2298 	struct opthdr		*req;
2299 	mib_item_t		*first_item = NULL;
2300 	mib_item_t		*last_item  = NULL;
2301 	mib_item_t		*temp;
2302 
2303 	tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
2304 	tor->OPT_offset = sizeof (struct T_optmgmt_req);
2305 	tor->OPT_length = sizeof (struct opthdr);
2306 	tor->MGMT_flags = T_CURRENT;
2307 	req = (struct opthdr *)&tor[1];
2308 	req->level = MIB2_IP;		/* any MIB2_xxx value ok here */
2309 	req->name  = 0;
2310 	req->len   = 0;
2311 
2312 	ctlbuf.buf = (char *)buf;
2313 	ctlbuf.len = tor->OPT_length + tor->OPT_offset;
2314 	flags = 0;
2315 	if (putmsg(sd, &ctlbuf, NULL, flags) < 0) {
2316 		perror("mibget: putmsg (ctl)");
2317 		return (NULL);
2318 	}
2319 	/*
2320 	 * each reply consists of a ctl part for one fixed structure
2321 	 * or table, as defined in mib2.h.  The format is a T_OPTMGMT_ACK,
2322 	 * containing an opthdr structure.  level/name identify the entry,
2323 	 * len is the size of the data part of the message.
2324 	 */
2325 	req = (struct opthdr *)&toa[1];
2326 	ctlbuf.maxlen = sizeof (buf);
2327 	for (j = 1; ; j++) {
2328 		flags = 0;
2329 		getcode = getmsg(sd, &ctlbuf, NULL, &flags);
2330 		if (getcode < 0) {
2331 			perror("mibget: getmsg (ctl)");
2332 			if (verbose) {
2333 				(void) fprintf(stderr,
2334 				    "#   level   name    len\n");
2335 				i = 0;
2336 				for (last_item = first_item; last_item != NULL;
2337 				    last_item = last_item->next_item) {
2338 					(void) printf("%d  %4ld   %5ld   %ld\n",
2339 					    ++i, last_item->group,
2340 					    last_item->mib_id,
2341 					    last_item->length);
2342 				}
2343 			}
2344 			break;
2345 		}
2346 		if (getcode == 0 &&
2347 		    ctlbuf.len >= sizeof (struct T_optmgmt_ack) &&
2348 		    toa->PRIM_type == T_OPTMGMT_ACK &&
2349 		    toa->MGMT_flags == T_SUCCESS &&
2350 		    req->len == 0) {
2351 			if (verbose) {
2352 				(void) printf("mibget getmsg() %d returned EOD "
2353 				    "(level %lu, name %lu)\n", j, req->level,
2354 				    req->name);
2355 			}
2356 			return (first_item);		/* this is EOD msg */
2357 		}
2358 
2359 		if (ctlbuf.len >= sizeof (struct T_error_ack) &&
2360 		    tea->PRIM_type == T_ERROR_ACK) {
2361 			(void) fprintf(stderr, gettext("mibget %d gives "
2362 			    "T_ERROR_ACK: TLI_error = 0x%lx, UNIX_error = "
2363 			    "0x%lx\n"), j, tea->TLI_error, tea->UNIX_error);
2364 			errno = (tea->TLI_error == TSYSERR)
2365 				? tea->UNIX_error : EPROTO;
2366 			break;
2367 		}
2368 
2369 		if (getcode != MOREDATA ||
2370 		    ctlbuf.len < sizeof (struct T_optmgmt_ack) ||
2371 		    toa->PRIM_type != T_OPTMGMT_ACK ||
2372 		    toa->MGMT_flags != T_SUCCESS) {
2373 			(void) printf("mibget getmsg(ctl) %d returned %d, "
2374 			    "ctlbuf.len = %d, PRIM_type = %ld\n",
2375 			    j, getcode, ctlbuf.len, toa->PRIM_type);
2376 			if (toa->PRIM_type == T_OPTMGMT_ACK) {
2377 				(void) printf("T_OPTMGMT_ACK: "
2378 				    "MGMT_flags = 0x%lx, req->len = %ld\n",
2379 				    toa->MGMT_flags, req->len);
2380 			}
2381 			errno = ENOMSG;
2382 			break;
2383 		}
2384 
2385 		temp = malloc(sizeof (mib_item_t));
2386 		if (temp == NULL) {
2387 			perror("mibget: malloc");
2388 			break;
2389 		}
2390 		if (last_item != NULL)
2391 			last_item->next_item = temp;
2392 		else
2393 			first_item = temp;
2394 		last_item = temp;
2395 		last_item->next_item = NULL;
2396 		last_item->group = req->level;
2397 		last_item->mib_id = req->name;
2398 		last_item->length = req->len;
2399 		last_item->valp = malloc(req->len);
2400 		if (verbose) {
2401 			(void) printf("msg %d:  group = %4ld   mib_id = %5ld   "
2402 			    "length = %ld\n",
2403 			    j, last_item->group, last_item->mib_id,
2404 			    last_item->length);
2405 		}
2406 
2407 		databuf.maxlen = last_item->length;
2408 		databuf.buf    = (char *)last_item->valp;
2409 		databuf.len    = 0;
2410 		flags = 0;
2411 		getcode = getmsg(sd, NULL, &databuf, &flags);
2412 		if (getcode < 0) {
2413 			perror("mibget: getmsg (data)");
2414 			break;
2415 		} else if (getcode != 0) {
2416 			(void) printf("mibget getmsg(data) returned %d, "
2417 			    "databuf.maxlen = %d, databuf.len = %d\n",
2418 			    getcode, databuf.maxlen, databuf.len);
2419 			break;
2420 		}
2421 	}
2422 
2423 	/*
2424 	 * On error, free all the allocated mib_item_t objects.
2425 	 */
2426 	while (first_item != NULL) {
2427 		last_item = first_item;
2428 		first_item = first_item->next_item;
2429 		free(last_item);
2430 	}
2431 	return (NULL);
2432 }
2433