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