xref: /openbsd-src/usr.bin/netstat/route.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: route.c,v 1.40 2001/06/25 00:41:39 niklas 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.40 2001/06/25 00:41:39 niklas 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 	register 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 	register 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 	register struct rt_msghdr *rtm;
391 {
392 	register 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 	register char *cp = workbuf;
435 	size_t n;
436 
437 	switch (sa->sa_family) {
438 	case AF_INET:
439 	    {
440 		register struct sockaddr_in *sin = (struct sockaddr_in *)sa;
441 		register struct sockaddr_in *msin = (struct sockaddr_in *)mask;
442 
443 		cp = (sin->sin_addr.s_addr == 0) ? "default" :
444 		      ((flags & RTF_HOST) ?
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 		register 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 			register int i;
501 			register 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 				if (n >= workbuf + sizeof (workbuf) - cp)
510 					n = workbuf + sizeof (workbuf) - cp - 1;
511 				cp += n;
512 				cplim = ":";
513 			}
514 			cp = workbuf;
515 			break;
516 		    }
517 		default:
518 			cp = link_ntoa(sdl);
519 			break;
520 		}
521 		break;
522 	    }
523 
524 	case AF_APPLETALK:
525 	    {
526 		/* XXX could do better */
527 		cp = atalk_print(sa,11);
528 		break;
529 	    }
530 	default:
531 	    {
532 		register u_char *s = (u_char *)sa->sa_data, *slim;
533 
534 		slim = sa->sa_len + (u_char *) sa;
535 		cplim = cp + sizeof(workbuf) - 6;
536 		n = snprintf(cp, cplim - cp, "(%d)", sa->sa_family);
537 		if (n >= cplim - cp)
538 			n = cplim - cp - 1;
539 		cp += n;
540 		while (s < slim && cp < cplim) {
541 			n = snprintf(cp, workbuf + sizeof (workbuf) - cp,
542 			    " %02x", *s++);
543 			if (n >= workbuf + sizeof (workbuf) - cp)
544 				n = workbuf + sizeof (workbuf) - cp - 1;
545 			cp += n;
546 			if (s < slim) {
547 				n = snprintf(cp,
548 				    workbuf + sizeof (workbuf) - cp,
549 				    "%02x", *s++);
550 				if (n >= workbuf + sizeof (workbuf) - cp)
551 					n = workbuf + sizeof (workbuf) - cp - 1;
552 				cp += n;
553 			}
554 		}
555 		cp = workbuf;
556 	    }
557 	}
558 	if (width < 0 )
559 		printf("%s ", cp);
560 	else {
561 		if (nflag)
562 			printf("%-*s ", width, cp);
563 		else
564 			printf("%-*.*s ", width, width, cp);
565 	}
566 }
567 
568 static void
569 p_flags(f, format)
570 	register int f;
571 	char *format;
572 {
573 	char name[33], *flags;
574 	register struct bits *p = bits;
575 
576 	for (flags = name; p->b_mask; p++)
577 		if (p->b_mask & f)
578 			*flags++ = p->b_val;
579 	*flags = '\0';
580 	printf(format, name);
581 }
582 
583 static void
584 p_rtentry(rt)
585 	register struct rtentry *rt;
586 {
587 	static struct ifnet ifnet, *lastif;
588 	struct sockaddr_storage sock1, sock2;
589 	struct sockaddr *sa = (struct sockaddr *)&sock1;
590 	struct sockaddr *mask = (struct sockaddr *)&sock2;
591 
592 	bcopy(kgetsa(rt_key(rt)), sa, sizeof(struct sockaddr));
593 	if (sa->sa_len > sizeof(struct sockaddr))
594 		bcopy(kgetsa(rt_key(rt)), sa, sa->sa_len);
595 
596 	if (sa->sa_family == PF_KEY) {
597 		encap_print(rt);
598 		return;
599 	}
600 
601 	if (rt_mask(rt)) {
602 		bcopy(kgetsa(rt_mask(rt)), mask, sizeof(struct sockaddr));
603 		if (sa->sa_len > sizeof(struct sockaddr))
604 			bcopy(kgetsa(rt_mask(rt)), mask, sa->sa_len);
605 	} else
606 		mask = 0;
607 
608 	p_sockaddr(sa, mask, rt->rt_flags, WID_DST(sa->sa_family));
609 	p_sockaddr(kgetsa(rt->rt_gateway), 0, RTF_HOST, WID_GW(sa->sa_family));
610 	p_flags(rt->rt_flags, "%-6.6s ");
611 	printf("%6d %8ld ", rt->rt_refcnt, rt->rt_use);
612 	if (rt->rt_rmx.rmx_mtu)
613 		printf("%6ld ", rt->rt_rmx.rmx_mtu);
614 	else
615 		printf("%6s ", "-");
616 	putchar((rt->rt_rmx.rmx_locks & RTV_MTU) ? 'L' : ' ');
617 	if (rt->rt_ifp) {
618 		if (rt->rt_ifp != lastif) {
619 			kget(rt->rt_ifp, ifnet);
620 			lastif = rt->rt_ifp;
621 		}
622 		printf(" %.16s%s", ifnet.if_xname,
623 			rt->rt_nodes[0].rn_dupedkey ? " =>" : "");
624 	}
625 	putchar('\n');
626  	if (vflag) {
627  		printf("\texpire   %10lu%c  recvpipe %10ld%c  "
628 		       "sendpipe %10ld%c\n",
629  			rt->rt_rmx.rmx_expire,
630  			(rt->rt_rmx.rmx_locks & RTV_EXPIRE) ? 'L' : ' ',
631  			rt->rt_rmx.rmx_recvpipe,
632  			(rt->rt_rmx.rmx_locks & RTV_RPIPE) ? 'L' : ' ',
633  			rt->rt_rmx.rmx_sendpipe,
634  			(rt->rt_rmx.rmx_locks & RTV_SPIPE) ? 'L' : ' ');
635  		printf("\tssthresh %10lu%c  rtt      %10ld%c  "
636 		       "rttvar   %10ld%c\n",
637  			rt->rt_rmx.rmx_ssthresh,
638  			(rt->rt_rmx.rmx_locks & RTV_SSTHRESH) ? 'L' : ' ',
639  			rt->rt_rmx.rmx_rtt,
640  			(rt->rt_rmx.rmx_locks & RTV_RTT) ? 'L' : ' ',
641  			rt->rt_rmx.rmx_rttvar,
642 			(rt->rt_rmx.rmx_locks & RTV_RTTVAR) ? 'L' : ' ');
643  	}
644 }
645 
646 char *
647 routename(in)
648 	in_addr_t in;
649 {
650 	register char *cp;
651 	static char line[MAXHOSTNAMELEN];
652 	struct hostent *hp;
653 	static char domain[MAXHOSTNAMELEN];
654 	static int first = 1;
655 
656 	if (first) {
657 		first = 0;
658 		if (gethostname(domain, sizeof domain) == 0 &&
659 		    (cp = strchr(domain, '.')))
660 			(void) strcpy(domain, cp + 1);
661 		else
662 			domain[0] = 0;
663 	}
664 	cp = 0;
665 	if (!nflag) {
666 		hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
667 			AF_INET);
668 		if (hp) {
669 			if ((cp = strchr(hp->h_name, '.')) &&
670 			    !strcmp(cp + 1, domain))
671 				*cp = 0;
672 			cp = hp->h_name;
673 		}
674 	}
675 	if (cp) {
676 		strncpy(line, cp, sizeof(line) - 1);
677 		line[sizeof(line) - 1] = '\0';
678 	} else {
679 #define C(x)	((x) & 0xff)
680 		in = ntohl(in);
681 		snprintf(line, sizeof line, "%u.%u.%u.%u",
682 		    C(in >> 24), C(in >> 16), C(in >> 8), C(in));
683 	}
684 	return (line);
685 }
686 
687 /*
688  * Return the name of the network whose address is given.
689  * The address is assumed to be that of a net or subnet, not a host.
690  */
691 char *
692 netname(in, mask)
693 	in_addr_t in, mask;
694 {
695 	char *cp = 0;
696 	static char line[MAXHOSTNAMELEN];
697 	struct netent *np = 0;
698 	int mbits;
699 
700 	in = ntohl(in);
701 	mask = ntohl(mask);
702 	if (!nflag && in != INADDR_ANY) {
703 		if ((np = getnetbyaddr(in, AF_INET)) != NULL)
704 			cp = np->n_name;
705 	}
706 	mbits = mask ? 33 - ffs(mask) : 0;
707 	if (cp) {
708 		strncpy(line, cp, sizeof(line) - 1);
709 		line[sizeof(line) - 1] = '\0';
710 	} else if (mbits < 9)
711 		snprintf(line, sizeof line, "%u/%d", C(in >> 24), mbits);
712 	else if (mbits < 17)
713 		snprintf(line, sizeof line, "%u.%u/%d",
714 		    C(in >> 24) , C(in >> 16), mbits);
715 	else if (mbits < 25)
716 		snprintf(line, sizeof line, "%u.%u.%u/%d",
717 		    C(in >> 24), C(in >> 16), C(in >> 8), mbits);
718 	else
719 		snprintf(line, sizeof line, "%u.%u.%u.%u/%d", C(in >> 24),
720 			C(in >> 16), C(in >> 8), C(in), mbits);
721 	return (line);
722 }
723 
724 #ifdef INET6
725 char *
726 netname6(sa6, mask)
727 	struct sockaddr_in6 *sa6;
728 	struct in6_addr *mask;
729 {
730 	static char line[MAXHOSTNAMELEN + 1];
731 	struct sockaddr_in6 sin6;
732 	u_char *p;
733 	u_char *lim;
734 	int masklen, final = 0, illegal = 0;
735 	int i;
736 	char hbuf[NI_MAXHOST];
737 #ifdef NI_WITHSCOPEID
738 	int flag = NI_WITHSCOPEID;
739 #else
740 	int flag = 0;
741 #endif
742 	int error;
743 
744 	sin6 = *sa6;
745 
746 	masklen = 0;
747 	lim = (u_char *)(mask + 1);
748 	i = 0;
749 	if (mask) {
750 		for (p = (u_char *)mask; p < lim; p++) {
751 			if (final && *p) {
752 				illegal++;
753 				sin6.sin6_addr.s6_addr[i++] = 0x00;
754 				continue;
755 			}
756 
757 			switch (*p & 0xff) {
758 			case 0xff:
759 				masklen += 8;
760 				break;
761 			case 0xfe:
762 				masklen += 7;
763 				final++;
764 				break;
765 			case 0xfc:
766 				masklen += 6;
767 				final++;
768 				break;
769 			case 0xf8:
770 				masklen += 5;
771 				final++;
772 				break;
773 			case 0xf0:
774 				masklen += 4;
775 				final++;
776 				break;
777 			case 0xe0:
778 				masklen += 3;
779 				final++;
780 				break;
781 			case 0xc0:
782 				masklen += 2;
783 				final++;
784 				break;
785 			case 0x80:
786 				masklen += 1;
787 				final++;
788 				break;
789 			case 0x00:
790 				final++;
791 				break;
792 			default:
793 				final++;
794 				illegal++;
795 				break;
796 			}
797 
798 			if (!illegal)
799 				sin6.sin6_addr.s6_addr[i++] &= *p;
800 			else
801 				sin6.sin6_addr.s6_addr[i++] = 0x00;
802 		}
803 	} else
804 		masklen = 128;
805 
806 	if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr))
807 		return("default");
808 
809 	if (illegal)
810 		fprintf(stderr, "illegal prefixlen\n");
811 
812 	if (nflag)
813 		flag |= NI_NUMERICHOST;
814 	error = getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
815 	    hbuf, sizeof(hbuf), NULL, 0, flag);
816 	if (error)
817 		snprintf(hbuf, sizeof(hbuf), "invalid");
818 
819 	snprintf(line, sizeof(line), "%s/%d", hbuf, masklen);
820 	return line;
821 }
822 
823 char *
824 routename6(sa6)
825 	struct sockaddr_in6 *sa6;
826 {
827 	static char line[NI_MAXHOST];
828 #ifdef NI_WITHSCOPEID
829 	const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID;
830 #else
831 	const int niflag = NI_NUMERICHOST;
832 #endif
833 	if (getnameinfo((struct sockaddr *)sa6, sa6->sin6_len,
834 			line, sizeof(line), NULL, 0, niflag) != 0)
835 		strcpy(line, "");
836 	return line;
837 }
838 #endif /*INET6*/
839 
840 /*
841  * Print routing statistics
842  */
843 void
844 rt_stats(off)
845 	u_long off;
846 {
847 	struct rtstat rtstat;
848 
849 	if (off == 0) {
850 		printf("rtstat: symbol not in namelist\n");
851 		return;
852 	}
853 	kread(off, (char *)&rtstat, sizeof (rtstat));
854 	printf("routing:\n");
855 	printf("\t%u bad routing redirect%s\n",
856 		rtstat.rts_badredirect, plural(rtstat.rts_badredirect));
857 	printf("\t%u dynamically created route%s\n",
858 		rtstat.rts_dynamic, plural(rtstat.rts_dynamic));
859 	printf("\t%u new gateway%s due to redirects\n",
860 		rtstat.rts_newgateway, plural(rtstat.rts_newgateway));
861 	printf("\t%u destination%s found unreachable\n",
862 		rtstat.rts_unreach, plural(rtstat.rts_unreach));
863 	printf("\t%u use%s of a wildcard route\n",
864 		rtstat.rts_wildcard, plural(rtstat.rts_wildcard));
865 }
866 
867 short ns_nullh[] = {0,0,0};
868 short ns_bh[] = {-1,-1,-1};
869 
870 char *
871 ns_print(sa)
872 	register struct sockaddr *sa;
873 {
874 	register struct sockaddr_ns *sns = (struct sockaddr_ns*)sa;
875 	struct ns_addr work;
876 	union { union ns_net net_e; u_long long_e; } net;
877 	in_port_t port;
878 	static char mybuf[50], cport[10], chost[25];
879 	char *host = "";
880 	register char *p; register u_char *q;
881 
882 	work = sns->sns_addr;
883 	port = ntohs(work.x_port);
884 	work.x_port = 0;
885 	net.net_e = work.x_net;
886 	if (ns_nullhost(work) && net.long_e == 0) {
887 		if (port ) {
888 			snprintf(mybuf, sizeof mybuf, "*.%xH", port);
889 			upHex(mybuf);
890 		} else
891 			snprintf(mybuf, sizeof mybuf, "*.*");
892 		return (mybuf);
893 	}
894 
895 	if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) {
896 		host = "any";
897 	} else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) {
898 		host = "*";
899 	} else {
900 		q = work.x_host.c_host;
901 		snprintf(chost, sizeof chost, "%02x%02x%02x%02x%02x%02xH",
902 			q[0], q[1], q[2], q[3], q[4], q[5]);
903 		for (p = chost; *p == '0' && p < chost + 12; p++)
904 			continue;
905 		host = p;
906 	}
907 	if (port)
908 		snprintf(cport, sizeof cport, ".%xH", htons(port));
909 	else
910 		*cport = 0;
911 
912 	snprintf(mybuf, sizeof mybuf, "%xH.%s%s", ntohl(net.long_e),
913 	    host, cport);
914 	upHex(mybuf);
915 	return(mybuf);
916 }
917 
918 char *
919 ns_phost(sa)
920 	struct sockaddr *sa;
921 {
922 	register struct sockaddr_ns *sns = (struct sockaddr_ns *)sa;
923 	struct sockaddr_ns work;
924 	static union ns_net ns_zeronet;
925 	char *p;
926 
927 	work = *sns;
928 	work.sns_addr.x_port = 0;
929 	work.sns_addr.x_net = ns_zeronet;
930 
931 	p = ns_print((struct sockaddr *)&work);
932 	if (strncmp("0H.", p, 3) == 0) p += 3;
933 	return(p);
934 }
935 
936 u_short ipx_nullh[] = {0,0,0};
937 u_short ipx_bh[] = {0xffff,0xffff,0xffff};
938 
939 char *
940 ipx_print(sa)
941 	register struct sockaddr *sa;
942 {
943 	register struct sockaddr_ipx *sipx = (struct sockaddr_ipx*)sa;
944 	struct ipx_addr work;
945 	union { union ipx_net net_e; u_long long_e; } net;
946 	in_port_t port;
947 	static char mybuf[50], cport[10], chost[25];
948 	char *host = "";
949 	register char *q;
950 
951 	work = sipx->sipx_addr;
952 	port = ntohs(work.ipx_port);
953 	work.ipx_port = 0;
954 	net.net_e = work.ipx_net;
955 	if (ipx_nullhost(work) && net.long_e == 0) {
956 		if (port != 0) {
957 			snprintf(mybuf, sizeof mybuf, "*.%xH", port);
958 			upHex(mybuf);
959 		} else
960 			snprintf(mybuf, sizeof mybuf, "*.*");
961 		return (mybuf);
962 	}
963 
964 	if (bcmp(ipx_bh, work.ipx_host.c_host, 6) == 0) {
965 		host = "any";
966 	} else if (bcmp(ipx_nullh, work.ipx_host.c_host, 6) == 0) {
967 		host = "*";
968 	} else {
969 		q = work.ipx_host.c_host;
970 		snprintf(chost, sizeof chost, "%02x:%02x:%02x:%02x:%02x:%02x",
971 		    q[0], q[1], q[2], q[3], q[4], q[5]);
972 		host = chost;
973 	}
974 	if (port)
975 		snprintf(cport, sizeof cport, ".%xH", htons(port));
976 	else
977 		*cport = 0;
978 
979 	snprintf(mybuf, sizeof mybuf, "%xH.%s%s", ntohl(net.long_e),
980 	    host, cport);
981 	upHex(mybuf);
982 	return(mybuf);
983 }
984 
985 char *
986 ipx_phost(sa)
987 	struct sockaddr *sa;
988 {
989 	register struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)sa;
990 	struct sockaddr_ipx work;
991 	static union ipx_net ipx_zeronet;
992 	char *p;
993 
994 	work = *sipx;
995 	work.sipx_addr.ipx_port = 0;
996 	work.sipx_addr.ipx_net = ipx_zeronet;
997 
998 	p = ipx_print((struct sockaddr *)&work);
999 	if (strncmp("0H.", p, 3) == 0) p += 3;
1000 	return(p);
1001 }
1002 
1003 static void
1004 encap_print(rt)
1005 	register struct rtentry *rt;
1006 {
1007 	struct sockaddr_encap sen1, sen2, sen3;
1008         struct ipsec_policy ipo;
1009 
1010 #ifdef INET6
1011 	struct sockaddr_in6 s61, s62;
1012 	char ip6addr[64];
1013 #endif /* INET6 */
1014 
1015 	bcopy(kgetsa(rt_key(rt)), &sen1, sizeof(sen1));
1016 	bcopy(kgetsa(rt_mask(rt)), &sen2, sizeof(sen2));
1017 	bcopy(kgetsa(rt->rt_gateway), &sen3, sizeof(sen3));
1018 
1019         if (sen1.sen_type == SENT_IP4)
1020 	{
1021 	    printf("%-18s %-5u ", netname(sen1.sen_ip_src.s_addr,
1022 				          sen2.sen_ip_src.s_addr),
1023 	           ntohs(sen1.sen_sport));
1024 
1025 	    printf("%-18s %-5u %-5u ", netname(sen1.sen_ip_dst.s_addr,
1026 					       sen2.sen_ip_dst.s_addr),
1027 	           ntohs(sen1.sen_dport), sen1.sen_proto);
1028 	}
1029 
1030 #ifdef INET6
1031 	if (sen1.sen_type == SENT_IP6)
1032 	{
1033 	    bzero(&s61, sizeof(s61));
1034 	    bzero(&s62, sizeof(s62));
1035 	    s61.sin6_family = s62.sin6_family = AF_INET6;
1036 	    s61.sin6_len = s62.sin6_len = sizeof(s61);
1037 	    bcopy(&sen1.sen_ip6_src, &s61.sin6_addr, sizeof(struct in6_addr));
1038 	    bcopy(&sen2.sen_ip6_src, &s62.sin6_addr, sizeof(struct in6_addr));
1039 
1040 	    printf("%-42s %-5u ", netname6(&s61, &s62.sin6_addr),
1041 		   ntohs(sen1.sen_ip6_sport));
1042 
1043 	    bzero(&s61, sizeof(s61));
1044 	    bzero(&s62, sizeof(s62));
1045 	    s61.sin6_family = s62.sin6_family = AF_INET6;
1046 	    s61.sin6_len = s62.sin6_len = sizeof(s61);
1047 	    bcopy(&sen1.sen_ip6_dst, &s61.sin6_addr, sizeof(struct in6_addr));
1048 	    bcopy(&sen2.sen_ip6_dst, &s62.sin6_addr, sizeof(struct in6_addr));
1049 
1050 	    printf("%-42s %-5u %-5u ", netname6(&s61, &s62.sin6_addr),
1051 	           ntohs(sen1.sen_ip6_dport), sen1.sen_ip6_proto);
1052 	}
1053 #endif /* INET6 */
1054 
1055 	if (sen3.sen_type == SENT_IPSP)
1056         {
1057             char hostn[NI_MAXHOST];
1058 
1059 	    kget(sen3.sen_ipsp, ipo);
1060 
1061             getnameinfo(&ipo.ipo_dst.sa, ipo.ipo_dst.sa.sa_len,
1062                         hostn, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
1063 	    printf("%s", hostn);
1064 
1065             printf("/%-u", ipo.ipo_sproto);
1066 
1067             switch (ipo.ipo_type)
1068             {
1069                 case IPSP_IPSEC_REQUIRE:
1070                     printf("/require");
1071                     break;
1072 
1073                 case IPSP_IPSEC_ACQUIRE:
1074                     printf("/acquire");
1075                     break;
1076 
1077                 case IPSP_IPSEC_USE:
1078                     printf("/use");
1079                     break;
1080 
1081                 case IPSP_IPSEC_DONTACQ:
1082                     printf("/dontacq");
1083                     break;
1084 
1085                 case IPSP_PERMIT:
1086                     printf("/permit");
1087                     break;
1088 
1089                 case IPSP_DENY:
1090                     printf("/deny");
1091                     break;
1092 
1093                 default:
1094                     printf("/<unknown type!>");
1095             }
1096 
1097             if ((ipo.ipo_addr.sen_type == SENT_IP4 &&
1098                  ipo.ipo_addr.sen_direction == IPSP_DIRECTION_IN) ||
1099                 (ipo.ipo_addr.sen_type == SENT_IP6 &&
1100                  ipo.ipo_addr.sen_ip6_direction == IPSP_DIRECTION_IN))
1101               printf("/in\n");
1102             else
1103               if ((ipo.ipo_addr.sen_type == SENT_IP4 &&
1104                    ipo.ipo_addr.sen_direction == IPSP_DIRECTION_OUT) ||
1105                   (ipo.ipo_addr.sen_type == SENT_IP6 &&
1106                    ipo.ipo_addr.sen_ip6_direction == IPSP_DIRECTION_OUT))
1107                 printf("/out\n");
1108               else
1109                 printf("/<unknown>\n");
1110         }
1111 }
1112 
1113 void
1114 upHex(p0)
1115 	char *p0;
1116 {
1117 	register char *p = p0;
1118 	for (; *p; p++) switch (*p) {
1119 
1120 	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
1121 		*p += ('A' - 'a');
1122 	}
1123 }
1124