xref: /openbsd/usr.bin/netstat/route.c (revision fd84ef7e)
1 /*	$OpenBSD: route.c,v 1.43 2001/11/19 19:02:15 mpech Exp $	*/
2 /*	$NetBSD: route.c,v 1.15 1996/05/07 02:55:06 thorpej Exp $	*/
3 
4 /*
5  * Copyright (c) 1983, 1988, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "from: @(#)route.c	8.3 (Berkeley) 3/9/94";
40 #else
41 static char *rcsid = "$OpenBSD: route.c,v 1.43 2001/11/19 19:02:15 mpech Exp $";
42 #endif
43 #endif /* not lint */
44 
45 #include <sys/param.h>
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48 #include <sys/mbuf.h>
49 
50 #include <net/if.h>
51 #include <net/if_dl.h>
52 #include <net/if_types.h>
53 #define _KERNEL
54 #include <net/route.h>
55 #undef _KERNEL
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
58 
59 #include <netns/ns.h>
60 
61 #include <netipx/ipx.h>
62 
63 #include <netatalk/at.h>
64 
65 #include <sys/sysctl.h>
66 
67 #include <arpa/inet.h>
68 
69 #include <limits.h>
70 #include <netdb.h>
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <unistd.h>
75 
76 #ifndef INET
77 #define INET
78 #endif
79 
80 #include <sys/socket.h>
81 #include <netinet/ip_ipsp.h>
82 #include "netstat.h"
83 
84 #define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d)))
85 
86 /* alignment constraint for routing socket */
87 #define ROUNDUP(a) \
88 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
89 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
90 
91 /*
92  * Definitions for showing gateway flags.
93  */
94 struct bits {
95 	short	b_mask;
96 	char	b_val;
97 } bits[] = {
98 	{ RTF_UP,	'U' },
99 	{ RTF_GATEWAY,	'G' },
100 	{ RTF_HOST,	'H' },
101 	{ RTF_REJECT,	'R' },
102 	{ RTF_BLACKHOLE, 'B' },
103 	{ RTF_DYNAMIC,	'D' },
104 	{ RTF_MODIFIED,	'M' },
105 	{ RTF_DONE,	'd' }, /* Completed -- for routing messages only */
106 	{ RTF_MASK,	'm' }, /* Mask Present -- for routing messages only */
107 	{ RTF_CLONING,	'C' },
108 	{ RTF_XRESOLVE,	'X' },
109 	{ RTF_LLINFO,	'L' },
110 	{ RTF_STATIC,	'S' },
111 	{ RTF_PROTO1,	'1' },
112 	{ RTF_PROTO2,	'2' },
113 	{ RTF_PROTO3,	'3' },
114 	{ 0 }
115 };
116 
117 static union {
118 	struct		sockaddr u_sa;
119 	u_int32_t	u_data[64];
120 	int		u_dummy;	/* force word-alignment */
121 } pt_u;
122 
123 int	do_rtent = 0;
124 struct	rtentry rtentry;
125 struct	radix_node rnode;
126 struct	radix_mask rmask;
127 
128 int	NewTree = 0;
129 
130 static struct sockaddr *kgetsa __P((struct sockaddr *));
131 static void p_tree __P((struct radix_node *));
132 static void p_rtnode __P(());
133 static void ntreestuff __P(());
134 static void np_rtentry __P((struct rt_msghdr *));
135 static void p_sockaddr __P((struct sockaddr *, struct sockaddr *, int, int));
136 static void p_flags __P((int, char *));
137 static void p_rtentry __P((struct rtentry *));
138 static void encap_print __P((struct rtentry *));
139 
140 /*
141  * Print routing tables.
142  */
143 void
144 routepr(rtree)
145 	u_long rtree;
146 {
147 	struct radix_node_head *rnh, head;
148 	int i;
149 
150 	printf("Routing tables\n");
151 
152 	if (Aflag == 0 && NewTree)
153 		ntreestuff();
154 	else {
155 		if (rtree == 0) {
156 			printf("rt_tables: symbol not in namelist\n");
157 			return;
158 		}
159 
160 		kget(rtree, rt_tables);
161 		for (i = 0; i <= AF_MAX; i++) {
162 			if ((rnh = rt_tables[i]) == 0)
163 				continue;
164 			kget(rnh, head);
165 			if (i == AF_UNSPEC) {
166 				if (Aflag && af == 0) {
167 					printf("Netmasks:\n");
168 					p_tree(head.rnh_treetop);
169 				}
170 			} else if (af == AF_UNSPEC || af == i) {
171 				pr_family(i);
172 				do_rtent = 1;
173 				if (i != PF_KEY)
174 					pr_rthdr(i);
175 				else
176 					pr_encaphdr();
177 				p_tree(head.rnh_treetop);
178 			}
179 		}
180 	}
181 }
182 
183 /*
184  * Print address family header before a section of the routing table.
185  */
186 void
187 pr_family(af)
188 	int af;
189 {
190 	char *afname;
191 
192 	switch (af) {
193 	case AF_INET:
194 		afname = "Internet";
195 		break;
196 #ifdef INET6
197 	case AF_INET6:
198 		afname = "Internet6";
199 		break;
200 #endif
201 	case AF_NS:
202 		afname = "XNS";
203 		break;
204 	case AF_IPX:
205 		afname = "IPX";
206 		break;
207 	case AF_ISO:
208 		afname = "ISO";
209 		break;
210 	case AF_CCITT:
211 		afname = "X.25";
212 		break;
213 	case PF_KEY:
214 		afname = "Encap";
215 		break;
216 	case AF_APPLETALK:
217 		afname = "AppleTalk";
218 		break;
219 	default:
220 		afname = NULL;
221 		break;
222 	}
223 	if (afname)
224 		printf("\n%s:\n", afname);
225 	else
226 		printf("\nProtocol Family %d:\n", af);
227 }
228 
229 /* column widths; each followed by one space */
230 #ifndef INET6
231 #define	WID_DST(af)	18	/* width of destination column */
232 #define	WID_GW(af)	18	/* width of gateway column */
233 #else
234 /* width of destination/gateway column */
235 #ifdef KAME_SCOPEID
236 /* strlen("fe80::aaaa:bbbb:cccc:dddd@gif0") == 30, strlen("/128") == 4 */
237 #define	WID_DST(af)	((af) == AF_INET6 ? (nflag ? 34 : 18) : 18)
238 #define	WID_GW(af)	((af) == AF_INET6 ? (nflag ? 30 : 18) : 18)
239 #else
240 /* strlen("fe80::aaaa:bbbb:cccc:dddd") == 25, strlen("/128") == 4 */
241 #define	WID_DST(af)	((af) == AF_INET6 ? (nflag ? 29 : 18) : 18)
242 #define	WID_GW(af)	((af) == AF_INET6 ? (nflag ? 25 : 18) : 18)
243 #endif
244 #endif /* INET6 */
245 
246 /*
247  * Print header for routing table columns.
248  */
249 void
250 pr_rthdr(af)
251 	int af;
252 {
253 
254 	if (Aflag)
255 		printf("%-*.*s ", PLEN, PLEN, "Address");
256 	printf("%-*.*s %-*.*s %-6.6s  %6.6s  %6.6s %6.6s  %s\n",
257 		WID_DST(af), WID_DST(af), "Destination",
258 		WID_GW(af), WID_GW(af), "Gateway",
259 		"Flags", "Refs", "Use", "Mtu", "Interface");
260 }
261 
262 /*
263  * Print header for PF_KEY entries.
264  */
265 void
266 pr_encaphdr()
267 {
268 	if (Aflag)
269 		printf("%-*s ", PLEN, "Address");
270 	printf("%-18s %-5s %-18s %-5s %-5s %-22s\n",
271 	    "Source", "Port", "Destination",
272 	    "Port", "Proto", "SA(Address/Proto/Type/Direction)");
273 }
274 
275 static struct sockaddr *
276 kgetsa(dst)
277 	struct sockaddr *dst;
278 {
279 
280 	kget(dst, pt_u.u_sa);
281 	if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa))
282 		kread((u_long)dst, (char *)pt_u.u_data, pt_u.u_sa.sa_len);
283 	return (&pt_u.u_sa);
284 }
285 
286 static void
287 p_tree(rn)
288 	struct radix_node *rn;
289 {
290 
291 again:
292 	kget(rn, rnode);
293 	if (rnode.rn_b < 0) {
294 		if (Aflag)
295 			printf("%-16p ", rn);
296 		if (rnode.rn_flags & RNF_ROOT) {
297 			if (Aflag)
298 				printf("(root node)%s",
299 				    rnode.rn_dupedkey ? " =>\n" : "\n");
300 		} else if (do_rtent) {
301 			kget(rn, rtentry);
302 			p_rtentry(&rtentry);
303 			if (Aflag)
304 				p_rtnode();
305 		} else {
306 			p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key),
307 			    0, 0, 44);
308 			putchar('\n');
309 		}
310 		if ((rn = rnode.rn_dupedkey))
311 			goto again;
312 	} else {
313 		if (Aflag && do_rtent) {
314 			printf("%-16p ", rn);
315 			p_rtnode();
316 		}
317 		rn = rnode.rn_r;
318 		p_tree(rnode.rn_l);
319 		p_tree(rn);
320 	}
321 }
322 
323 char	nbuf[25];
324 
325 static void
326 p_rtnode()
327 {
328 	struct radix_mask *rm = rnode.rn_mklist;
329 
330 	if (rnode.rn_b < 0) {
331 		if (rnode.rn_mask) {
332 			printf("\t  mask ");
333 			p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask),
334 			    0, 0, -1);
335 		} else if (rm == 0)
336 			return;
337 	} else {
338 		snprintf(nbuf, sizeof nbuf, "(%d)", rnode.rn_b);
339 		printf("%6.6s %16p : %16p", nbuf, rnode.rn_l,
340 		    rnode.rn_r);
341 	}
342 	while (rm) {
343 		kget(rm, rmask);
344 		snprintf(nbuf, sizeof nbuf, " %d refs, ", rmask.rm_refs);
345 		printf(" mk = %16p {(%d),%s",
346 			rm, -1 - rmask.rm_b, rmask.rm_refs ? nbuf : " ");
347 		p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask), 0, 0, -1);
348 		putchar('}');
349 		if ((rm = rmask.rm_mklist))
350 			printf(" ->");
351 	}
352 	putchar('\n');
353 }
354 
355 static void
356 ntreestuff()
357 {
358 	size_t needed;
359 	int mib[6];
360 	char *buf, *next, *lim;
361 	struct rt_msghdr *rtm;
362 
363 	mib[0] = CTL_NET;
364 	mib[1] = PF_ROUTE;
365 	mib[2] = 0;
366 	mib[3] = 0;
367 	mib[4] = NET_RT_DUMP;
368 	mib[5] = 0;
369 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
370 		perror("route-sysctl-estimate");
371 		exit(1);
372 	}
373 	if ((buf = malloc(needed)) == 0) {
374 		printf("out of space\n");
375 		exit(1);
376 	}
377         if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
378 		perror("sysctl of routing table");
379 		exit(1);
380 	}
381 	lim = buf + needed;
382 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
383 		rtm = (struct rt_msghdr *)next;
384 		np_rtentry(rtm);
385 	}
386 }
387 
388 static void
389 np_rtentry(rtm)
390 	struct rt_msghdr *rtm;
391 {
392 	struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
393 #ifdef notdef
394 	static int masks_done, banner_printed;
395 #endif
396 	static int old_af;
397 	int af = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST;
398 
399 #ifdef notdef
400 	/* for the moment, netmasks are skipped over */
401 	if (!banner_printed) {
402 		printf("Netmasks:\n");
403 		banner_printed = 1;
404 	}
405 	if (masks_done == 0) {
406 		if (rtm->rtm_addrs != RTA_DST ) {
407 			masks_done = 1;
408 			af = sa->sa_family;
409 		}
410 	} else
411 #endif
412 		af = sa->sa_family;
413 	if (af != old_af) {
414 		pr_family(af);
415 		old_af = af;
416 	}
417 	if (rtm->rtm_addrs == RTA_DST)
418 		p_sockaddr(sa, 0, 0, 36);
419 	else {
420 		p_sockaddr(sa, 0, rtm->rtm_flags, 16);
421 		sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
422 		p_sockaddr(sa, 0, 0, 18);
423 	}
424 	p_flags(rtm->rtm_flags & interesting, "%-6.6s ");
425 	putchar('\n');
426 }
427 
428 static void
429 p_sockaddr(sa, mask, flags, width)
430 	struct sockaddr *sa, *mask;
431 	int flags, width;
432 {
433 	char workbuf[128], *cplim;
434 	char *cp = workbuf;
435 	size_t n;
436 
437 	switch (sa->sa_family) {
438 	case AF_INET:
439 	    {
440 		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
441 		struct sockaddr_in *msin = (struct sockaddr_in *)mask;
442 
443 		cp = (sin->sin_addr.s_addr == 0) ? "default" :
444 		      ((flags & RTF_HOST) || mask == NULL ?
445 			routename(sin->sin_addr.s_addr) :
446 			netname(sin->sin_addr.s_addr, msin->sin_addr.s_addr));
447 
448 		break;
449 	    }
450 
451 #ifdef INET6
452 	case AF_INET6:
453 	    {
454 		struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
455 #ifdef KAME_SCOPEID
456 		struct in6_addr *in6 = &sa6->sin6_addr;
457 
458 		/*
459 		 * XXX: This is a special workaround for KAME kernels.
460 		 * sin6_scope_id field of SA should be set in the future.
461 		 */
462 		if (IN6_IS_ADDR_LINKLOCAL(in6) ||
463 		    IN6_IS_ADDR_MC_LINKLOCAL(in6)) {
464 		    /* XXX: override is ok? */
465 		    sa6->sin6_scope_id = (u_int32_t)ntohs(*(u_short *)&in6->s6_addr[2]);
466 		    *(u_short *)&in6->s6_addr[2] = 0;
467 		}
468 #endif
469 
470 		if (flags & RTF_HOST)
471 			cp = routename6(sa6);
472 		else if (mask) {
473 			cp = netname6(sa6,
474 				&((struct sockaddr_in6 *)mask)->sin6_addr);
475 		} else
476 			cp = netname6(sa6, NULL);
477 		break;
478 	    }
479 #endif
480 
481 	case AF_NS:
482 		cp = ns_print(sa);
483 		break;
484 
485 	case AF_IPX:
486 		cp = ipx_print(sa);
487 		break;
488 
489 	case AF_LINK:
490 	    {
491 		struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
492 
493 		if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
494 		    sdl->sdl_slen == 0)
495 			(void) snprintf(workbuf, sizeof workbuf,
496 			    "link#%d", sdl->sdl_index);
497 		else switch (sdl->sdl_type) {
498 		case IFT_ETHER:
499 		    {
500 			int i;
501 			u_char *lla = (u_char *)sdl->sdl_data +
502 			    sdl->sdl_nlen;
503 
504 			cplim = "";
505 			for (i = 0; i < sdl->sdl_alen; i++, lla++) {
506 				n = snprintf(cp,
507 				    workbuf + sizeof (workbuf) - cp,
508 				    "%s%x", cplim, *lla);
509 				cplim = ":";
510 				if (n == -1)	/* What else to do ? */
511 				  continue;
512 				if (n >= workbuf + sizeof (workbuf) - cp)
513 					n = workbuf + sizeof (workbuf) - cp - 1;
514 				cp += n;
515 			}
516 			cp = workbuf;
517 			break;
518 		    }
519 		default:
520 			cp = link_ntoa(sdl);
521 			break;
522 		}
523 		break;
524 	    }
525 
526 	case AF_APPLETALK:
527 	    {
528 		/* XXX could do better */
529 		cp = atalk_print(sa,11);
530 		break;
531 	    }
532 	default:
533 	    {
534 		u_char *s = (u_char *)sa->sa_data, *slim;
535 
536 		slim = sa->sa_len + (u_char *) sa;
537 		cplim = cp + sizeof(workbuf) - 6;
538 		n = snprintf(cp, cplim - cp, "(%d)", sa->sa_family);
539 		if (n >= cplim - cp)
540 			n = cplim - cp - 1;
541 		if (n > 0)
542 			cp += n;
543 		while (s < slim && cp < cplim) {
544 			n = snprintf(cp, workbuf + sizeof (workbuf) - cp,
545 			    " %02x", *s++);
546 			if (n >= workbuf + sizeof (workbuf) - cp)
547 				n = workbuf + sizeof (workbuf) - cp - 1;
548 			if (n > 0)
549 				cp += n;
550 			if (s < slim) {
551 				n = snprintf(cp,
552 				    workbuf + sizeof (workbuf) - cp,
553 				    "%02x", *s++);
554 				if (n >= workbuf + sizeof (workbuf) - cp)
555 					n = workbuf + sizeof (workbuf) - cp - 1;
556 				if (n > 0)
557 					cp += n;
558 			}
559 		}
560 		cp = workbuf;
561 	    }
562 	}
563 	if (width < 0 )
564 		printf("%s ", cp);
565 	else {
566 		if (nflag)
567 			printf("%-*s ", width, cp);
568 		else
569 			printf("%-*.*s ", width, width, cp);
570 	}
571 }
572 
573 static void
574 p_flags(f, format)
575 	int f;
576 	char *format;
577 {
578 	char name[33], *flags;
579 	struct bits *p = bits;
580 
581 	for (flags = name; p->b_mask; p++)
582 		if (p->b_mask & f)
583 			*flags++ = p->b_val;
584 	*flags = '\0';
585 	printf(format, name);
586 }
587 
588 static void
589 p_rtentry(rt)
590 	struct rtentry *rt;
591 {
592 	static struct ifnet ifnet, *lastif;
593 	struct sockaddr_storage sock1, sock2;
594 	struct sockaddr *sa = (struct sockaddr *)&sock1;
595 	struct sockaddr *mask = (struct sockaddr *)&sock2;
596 
597 	bcopy(kgetsa(rt_key(rt)), sa, sizeof(struct sockaddr));
598 	if (sa->sa_len > sizeof(struct sockaddr))
599 		bcopy(kgetsa(rt_key(rt)), sa, sa->sa_len);
600 
601 	if (sa->sa_family == PF_KEY) {
602 		encap_print(rt);
603 		return;
604 	}
605 
606 	if (rt_mask(rt)) {
607 		bcopy(kgetsa(rt_mask(rt)), mask, sizeof(struct sockaddr));
608 		if (sa->sa_len > sizeof(struct sockaddr))
609 			bcopy(kgetsa(rt_mask(rt)), mask, sa->sa_len);
610 	} else
611 		mask = 0;
612 
613 	p_sockaddr(sa, mask, rt->rt_flags, WID_DST(sa->sa_family));
614 	p_sockaddr(kgetsa(rt->rt_gateway), 0, RTF_HOST, WID_GW(sa->sa_family));
615 	p_flags(rt->rt_flags, "%-6.6s ");
616 	printf("%6d %8ld ", rt->rt_refcnt, rt->rt_use);
617 	if (rt->rt_rmx.rmx_mtu)
618 		printf("%6ld ", rt->rt_rmx.rmx_mtu);
619 	else
620 		printf("%6s ", "-");
621 	putchar((rt->rt_rmx.rmx_locks & RTV_MTU) ? 'L' : ' ');
622 	if (rt->rt_ifp) {
623 		if (rt->rt_ifp != lastif) {
624 			kget(rt->rt_ifp, ifnet);
625 			lastif = rt->rt_ifp;
626 		}
627 		printf(" %.16s%s", ifnet.if_xname,
628 			rt->rt_nodes[0].rn_dupedkey ? " =>" : "");
629 	}
630 	putchar('\n');
631  	if (vflag) {
632  		printf("\texpire   %10lu%c  recvpipe %10ld%c  "
633 		       "sendpipe %10ld%c\n",
634  			rt->rt_rmx.rmx_expire,
635  			(rt->rt_rmx.rmx_locks & RTV_EXPIRE) ? 'L' : ' ',
636  			rt->rt_rmx.rmx_recvpipe,
637  			(rt->rt_rmx.rmx_locks & RTV_RPIPE) ? 'L' : ' ',
638  			rt->rt_rmx.rmx_sendpipe,
639  			(rt->rt_rmx.rmx_locks & RTV_SPIPE) ? 'L' : ' ');
640  		printf("\tssthresh %10lu%c  rtt      %10ld%c  "
641 		       "rttvar   %10ld%c\n",
642  			rt->rt_rmx.rmx_ssthresh,
643  			(rt->rt_rmx.rmx_locks & RTV_SSTHRESH) ? 'L' : ' ',
644  			rt->rt_rmx.rmx_rtt,
645  			(rt->rt_rmx.rmx_locks & RTV_RTT) ? 'L' : ' ',
646  			rt->rt_rmx.rmx_rttvar,
647 			(rt->rt_rmx.rmx_locks & RTV_RTTVAR) ? 'L' : ' ');
648  	}
649 }
650 
651 char *
652 routename(in)
653 	in_addr_t in;
654 {
655 	char *cp;
656 	static char line[MAXHOSTNAMELEN];
657 	struct hostent *hp;
658 	static char domain[MAXHOSTNAMELEN];
659 	static int first = 1;
660 
661 	if (first) {
662 		first = 0;
663 		if (gethostname(domain, sizeof domain) == 0 &&
664 		    (cp = strchr(domain, '.')))
665 			(void) strcpy(domain, cp + 1);
666 		else
667 			domain[0] = 0;
668 	}
669 	cp = 0;
670 	if (!nflag) {
671 		hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
672 			AF_INET);
673 		if (hp) {
674 			if ((cp = strchr(hp->h_name, '.')) &&
675 			    !strcmp(cp + 1, domain))
676 				*cp = 0;
677 			cp = hp->h_name;
678 		}
679 	}
680 	if (cp) {
681 		strncpy(line, cp, sizeof(line) - 1);
682 		line[sizeof(line) - 1] = '\0';
683 	} else {
684 #define C(x)	((x) & 0xff)
685 		in = ntohl(in);
686 		snprintf(line, sizeof line, "%u.%u.%u.%u",
687 		    C(in >> 24), C(in >> 16), C(in >> 8), C(in));
688 	}
689 	return (line);
690 }
691 
692 /*
693  * Return the name of the network whose address is given.
694  * The address is assumed to be that of a net or subnet, not a host.
695  */
696 char *
697 netname(in, mask)
698 	in_addr_t in, mask;
699 {
700 	char *cp = 0;
701 	static char line[MAXHOSTNAMELEN];
702 	struct netent *np = 0;
703 	int mbits;
704 
705 	in = ntohl(in);
706 	mask = ntohl(mask);
707 	if (!nflag && in != INADDR_ANY) {
708 		if ((np = getnetbyaddr(in, AF_INET)) != NULL)
709 			cp = np->n_name;
710 	}
711 	mbits = mask ? 33 - ffs(mask) : 0;
712 	if (cp) {
713 		strncpy(line, cp, sizeof(line) - 1);
714 		line[sizeof(line) - 1] = '\0';
715 	} else if (mbits < 9)
716 		snprintf(line, sizeof line, "%u/%d", C(in >> 24), mbits);
717 	else if (mbits < 17)
718 		snprintf(line, sizeof line, "%u.%u/%d",
719 		    C(in >> 24) , C(in >> 16), mbits);
720 	else if (mbits < 25)
721 		snprintf(line, sizeof line, "%u.%u.%u/%d",
722 		    C(in >> 24), C(in >> 16), C(in >> 8), mbits);
723 	else
724 		snprintf(line, sizeof line, "%u.%u.%u.%u/%d", C(in >> 24),
725 			C(in >> 16), C(in >> 8), C(in), mbits);
726 	return (line);
727 }
728 
729 #ifdef INET6
730 char *
731 netname6(sa6, mask)
732 	struct sockaddr_in6 *sa6;
733 	struct in6_addr *mask;
734 {
735 	static char line[MAXHOSTNAMELEN + 1];
736 	struct sockaddr_in6 sin6;
737 	u_char *p;
738 	u_char *lim;
739 	int masklen, final = 0, illegal = 0;
740 	int i;
741 	char hbuf[NI_MAXHOST];
742 #ifdef NI_WITHSCOPEID
743 	int flag = NI_WITHSCOPEID;
744 #else
745 	int flag = 0;
746 #endif
747 	int error;
748 
749 	sin6 = *sa6;
750 
751 	masklen = 0;
752 	lim = (u_char *)(mask + 1);
753 	i = 0;
754 	if (mask) {
755 		for (p = (u_char *)mask; p < lim; p++) {
756 			if (final && *p) {
757 				illegal++;
758 				sin6.sin6_addr.s6_addr[i++] = 0x00;
759 				continue;
760 			}
761 
762 			switch (*p & 0xff) {
763 			case 0xff:
764 				masklen += 8;
765 				break;
766 			case 0xfe:
767 				masklen += 7;
768 				final++;
769 				break;
770 			case 0xfc:
771 				masklen += 6;
772 				final++;
773 				break;
774 			case 0xf8:
775 				masklen += 5;
776 				final++;
777 				break;
778 			case 0xf0:
779 				masklen += 4;
780 				final++;
781 				break;
782 			case 0xe0:
783 				masklen += 3;
784 				final++;
785 				break;
786 			case 0xc0:
787 				masklen += 2;
788 				final++;
789 				break;
790 			case 0x80:
791 				masklen += 1;
792 				final++;
793 				break;
794 			case 0x00:
795 				final++;
796 				break;
797 			default:
798 				final++;
799 				illegal++;
800 				break;
801 			}
802 
803 			if (!illegal)
804 				sin6.sin6_addr.s6_addr[i++] &= *p;
805 			else
806 				sin6.sin6_addr.s6_addr[i++] = 0x00;
807 		}
808 	} else
809 		masklen = 128;
810 
811 	if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr))
812 		return("default");
813 
814 	if (illegal)
815 		fprintf(stderr, "illegal prefixlen\n");
816 
817 	if (nflag)
818 		flag |= NI_NUMERICHOST;
819 	error = getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
820 	    hbuf, sizeof(hbuf), NULL, 0, flag);
821 	if (error)
822 		snprintf(hbuf, sizeof(hbuf), "invalid");
823 
824 	snprintf(line, sizeof(line), "%s/%d", hbuf, masklen);
825 	return line;
826 }
827 
828 char *
829 routename6(sa6)
830 	struct sockaddr_in6 *sa6;
831 {
832 	static char line[NI_MAXHOST];
833 #ifdef NI_WITHSCOPEID
834 	const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID;
835 #else
836 	const int niflag = NI_NUMERICHOST;
837 #endif
838 	if (getnameinfo((struct sockaddr *)sa6, sa6->sin6_len,
839 			line, sizeof(line), NULL, 0, niflag) != 0)
840 		strcpy(line, "");
841 	return line;
842 }
843 #endif /*INET6*/
844 
845 /*
846  * Print routing statistics
847  */
848 void
849 rt_stats(off)
850 	u_long off;
851 {
852 	struct rtstat rtstat;
853 
854 	if (off == 0) {
855 		printf("rtstat: symbol not in namelist\n");
856 		return;
857 	}
858 	kread(off, (char *)&rtstat, sizeof (rtstat));
859 	printf("routing:\n");
860 	printf("\t%u bad routing redirect%s\n",
861 		rtstat.rts_badredirect, plural(rtstat.rts_badredirect));
862 	printf("\t%u dynamically created route%s\n",
863 		rtstat.rts_dynamic, plural(rtstat.rts_dynamic));
864 	printf("\t%u new gateway%s due to redirects\n",
865 		rtstat.rts_newgateway, plural(rtstat.rts_newgateway));
866 	printf("\t%u destination%s found unreachable\n",
867 		rtstat.rts_unreach, plural(rtstat.rts_unreach));
868 	printf("\t%u use%s of a wildcard route\n",
869 		rtstat.rts_wildcard, plural(rtstat.rts_wildcard));
870 }
871 
872 short ns_nullh[] = {0,0,0};
873 short ns_bh[] = {-1,-1,-1};
874 
875 char *
876 ns_print(sa)
877 	struct sockaddr *sa;
878 {
879 	struct sockaddr_ns *sns = (struct sockaddr_ns*)sa;
880 	struct ns_addr work;
881 	union { union ns_net net_e; u_long long_e; } net;
882 	in_port_t port;
883 	static char mybuf[50], cport[10], chost[25];
884 	char *host = "";
885 	char *p;
886 	u_char *q;
887 
888 	work = sns->sns_addr;
889 	port = ntohs(work.x_port);
890 	work.x_port = 0;
891 	net.net_e = work.x_net;
892 	if (ns_nullhost(work) && net.long_e == 0) {
893 		if (port ) {
894 			snprintf(mybuf, sizeof mybuf, "*.%xH", port);
895 			upHex(mybuf);
896 		} else
897 			snprintf(mybuf, sizeof mybuf, "*.*");
898 		return (mybuf);
899 	}
900 
901 	if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) {
902 		host = "any";
903 	} else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) {
904 		host = "*";
905 	} else {
906 		q = work.x_host.c_host;
907 		snprintf(chost, sizeof chost, "%02x%02x%02x%02x%02x%02xH",
908 			q[0], q[1], q[2], q[3], q[4], q[5]);
909 		for (p = chost; *p == '0' && p < chost + 12; p++)
910 			continue;
911 		host = p;
912 	}
913 	if (port)
914 		snprintf(cport, sizeof cport, ".%xH", htons(port));
915 	else
916 		*cport = 0;
917 
918 	snprintf(mybuf, sizeof mybuf, "%xH.%s%s", ntohl(net.long_e),
919 	    host, cport);
920 	upHex(mybuf);
921 	return(mybuf);
922 }
923 
924 char *
925 ns_phost(sa)
926 	struct sockaddr *sa;
927 {
928 	struct sockaddr_ns *sns = (struct sockaddr_ns *)sa;
929 	struct sockaddr_ns work;
930 	static union ns_net ns_zeronet;
931 	char *p;
932 
933 	work = *sns;
934 	work.sns_addr.x_port = 0;
935 	work.sns_addr.x_net = ns_zeronet;
936 
937 	p = ns_print((struct sockaddr *)&work);
938 	if (strncmp("0H.", p, 3) == 0) p += 3;
939 	return(p);
940 }
941 
942 u_short ipx_nullh[] = {0,0,0};
943 u_short ipx_bh[] = {0xffff,0xffff,0xffff};
944 
945 char *
946 ipx_print(sa)
947 	struct sockaddr *sa;
948 {
949 	struct sockaddr_ipx *sipx = (struct sockaddr_ipx*)sa;
950 	struct ipx_addr work;
951 	union { union ipx_net net_e; u_long long_e; } net;
952 	in_port_t port;
953 	static char mybuf[50], cport[10], chost[25];
954 	char *host = "";
955 	char *q;
956 
957 	work = sipx->sipx_addr;
958 	port = ntohs(work.ipx_port);
959 	work.ipx_port = 0;
960 	net.net_e = work.ipx_net;
961 	if (ipx_nullhost(work) && net.long_e == 0) {
962 		if (port != 0) {
963 			snprintf(mybuf, sizeof mybuf, "*.%xH", port);
964 			upHex(mybuf);
965 		} else
966 			snprintf(mybuf, sizeof mybuf, "*.*");
967 		return (mybuf);
968 	}
969 
970 	if (bcmp(ipx_bh, work.ipx_host.c_host, 6) == 0) {
971 		host = "any";
972 	} else if (bcmp(ipx_nullh, work.ipx_host.c_host, 6) == 0) {
973 		host = "*";
974 	} else {
975 		q = work.ipx_host.c_host;
976 		snprintf(chost, sizeof chost, "%02x:%02x:%02x:%02x:%02x:%02x",
977 		    q[0], q[1], q[2], q[3], q[4], q[5]);
978 		host = chost;
979 	}
980 	if (port)
981 		snprintf(cport, sizeof cport, ".%xH", htons(port));
982 	else
983 		*cport = 0;
984 
985 	snprintf(mybuf, sizeof mybuf, "%xH.%s%s", ntohl(net.long_e),
986 	    host, cport);
987 	upHex(mybuf);
988 	return(mybuf);
989 }
990 
991 char *
992 ipx_phost(sa)
993 	struct sockaddr *sa;
994 {
995 	struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)sa;
996 	struct sockaddr_ipx work;
997 	static union ipx_net ipx_zeronet;
998 	char *p;
999 
1000 	work = *sipx;
1001 	work.sipx_addr.ipx_port = 0;
1002 	work.sipx_addr.ipx_net = ipx_zeronet;
1003 
1004 	p = ipx_print((struct sockaddr *)&work);
1005 	if (strncmp("0H.", p, 3) == 0) p += 3;
1006 	return(p);
1007 }
1008 
1009 static void
1010 encap_print(rt)
1011 	struct rtentry *rt;
1012 {
1013 	struct sockaddr_encap sen1, sen2, sen3;
1014         struct ipsec_policy ipo;
1015 
1016 #ifdef INET6
1017 	struct sockaddr_in6 s61, s62;
1018 	char ip6addr[64];
1019 #endif /* INET6 */
1020 
1021 	bcopy(kgetsa(rt_key(rt)), &sen1, sizeof(sen1));
1022 	bcopy(kgetsa(rt_mask(rt)), &sen2, sizeof(sen2));
1023 	bcopy(kgetsa(rt->rt_gateway), &sen3, sizeof(sen3));
1024 
1025         if (sen1.sen_type == SENT_IP4)
1026 	{
1027 	    printf("%-18s %-5u ", netname(sen1.sen_ip_src.s_addr,
1028 				          sen2.sen_ip_src.s_addr),
1029 	           ntohs(sen1.sen_sport));
1030 
1031 	    printf("%-18s %-5u %-5u ", netname(sen1.sen_ip_dst.s_addr,
1032 					       sen2.sen_ip_dst.s_addr),
1033 	           ntohs(sen1.sen_dport), sen1.sen_proto);
1034 	}
1035 
1036 #ifdef INET6
1037 	if (sen1.sen_type == SENT_IP6)
1038 	{
1039 	    bzero(&s61, sizeof(s61));
1040 	    bzero(&s62, sizeof(s62));
1041 	    s61.sin6_family = s62.sin6_family = AF_INET6;
1042 	    s61.sin6_len = s62.sin6_len = sizeof(s61);
1043 	    bcopy(&sen1.sen_ip6_src, &s61.sin6_addr, sizeof(struct in6_addr));
1044 	    bcopy(&sen2.sen_ip6_src, &s62.sin6_addr, sizeof(struct in6_addr));
1045 
1046 	    printf("%-42s %-5u ", netname6(&s61, &s62.sin6_addr),
1047 		   ntohs(sen1.sen_ip6_sport));
1048 
1049 	    bzero(&s61, sizeof(s61));
1050 	    bzero(&s62, sizeof(s62));
1051 	    s61.sin6_family = s62.sin6_family = AF_INET6;
1052 	    s61.sin6_len = s62.sin6_len = sizeof(s61);
1053 	    bcopy(&sen1.sen_ip6_dst, &s61.sin6_addr, sizeof(struct in6_addr));
1054 	    bcopy(&sen2.sen_ip6_dst, &s62.sin6_addr, sizeof(struct in6_addr));
1055 
1056 	    printf("%-42s %-5u %-5u ", netname6(&s61, &s62.sin6_addr),
1057 	           ntohs(sen1.sen_ip6_dport), sen1.sen_ip6_proto);
1058 	}
1059 #endif /* INET6 */
1060 
1061 	if (sen3.sen_type == SENT_IPSP)
1062         {
1063             char hostn[NI_MAXHOST];
1064 
1065 	    kget(sen3.sen_ipsp, ipo);
1066 
1067             getnameinfo(&ipo.ipo_dst.sa, ipo.ipo_dst.sa.sa_len,
1068                         hostn, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
1069 	    printf("%s", hostn);
1070 
1071             printf("/%-u", ipo.ipo_sproto);
1072 
1073             switch (ipo.ipo_type)
1074             {
1075                 case IPSP_IPSEC_REQUIRE:
1076                     printf("/require");
1077                     break;
1078 
1079                 case IPSP_IPSEC_ACQUIRE:
1080                     printf("/acquire");
1081                     break;
1082 
1083                 case IPSP_IPSEC_USE:
1084                     printf("/use");
1085                     break;
1086 
1087                 case IPSP_IPSEC_DONTACQ:
1088                     printf("/dontacq");
1089                     break;
1090 
1091                 case IPSP_PERMIT:
1092                     printf("/permit");
1093                     break;
1094 
1095                 case IPSP_DENY:
1096                     printf("/deny");
1097                     break;
1098 
1099                 default:
1100                     printf("/<unknown type!>");
1101             }
1102 
1103             if ((ipo.ipo_addr.sen_type == SENT_IP4 &&
1104                  ipo.ipo_addr.sen_direction == IPSP_DIRECTION_IN) ||
1105                 (ipo.ipo_addr.sen_type == SENT_IP6 &&
1106                  ipo.ipo_addr.sen_ip6_direction == IPSP_DIRECTION_IN))
1107               printf("/in\n");
1108             else
1109               if ((ipo.ipo_addr.sen_type == SENT_IP4 &&
1110                    ipo.ipo_addr.sen_direction == IPSP_DIRECTION_OUT) ||
1111                   (ipo.ipo_addr.sen_type == SENT_IP6 &&
1112                    ipo.ipo_addr.sen_ip6_direction == IPSP_DIRECTION_OUT))
1113                 printf("/out\n");
1114               else
1115                 printf("/<unknown>\n");
1116         }
1117 }
1118 
1119 void
1120 upHex(p0)
1121 	char *p0;
1122 {
1123 	char *p = p0;
1124 	for (; *p; p++) switch (*p) {
1125 
1126 	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
1127 		*p += ('A' - 'a');
1128 	}
1129 }
1130