xref: /netbsd/sbin/route/rtutil.c (revision d866c9e7)
1*d866c9e7Schristos /*	$NetBSD: rtutil.c,v 1.11 2020/08/29 19:27:40 christos Exp $	*/
2bb06da56Schristos /*	$OpenBSD: show.c,v 1.1 2006/05/27 19:16:37 claudio Exp $	*/
3bb06da56Schristos 
4bb06da56Schristos /*
5bb06da56Schristos  * Copyright (c) 1983, 1988, 1993
6bb06da56Schristos  *	The Regents of the University of California.  All rights reserved.
7bb06da56Schristos  *
8bb06da56Schristos  * Redistribution and use in source and binary forms, with or without
9bb06da56Schristos  * modification, are permitted provided that the following conditions
10bb06da56Schristos  * are met:
11bb06da56Schristos  * 1. Redistributions of source code must retain the above copyright
12bb06da56Schristos  *    notice, this list of conditions and the following disclaimer.
13bb06da56Schristos  * 2. Redistributions in binary form must reproduce the above copyright
14bb06da56Schristos  *    notice, this list of conditions and the following disclaimer in the
15bb06da56Schristos  *    documentation and/or other materials provided with the distribution.
16bb06da56Schristos  * 3. Neither the name of the University nor the names of its contributors
17bb06da56Schristos  *    may be used to endorse or promote products derived from this software
18bb06da56Schristos  *    without specific prior written permission.
19bb06da56Schristos  *
20bb06da56Schristos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21bb06da56Schristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22bb06da56Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23bb06da56Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24bb06da56Schristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25bb06da56Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26bb06da56Schristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27bb06da56Schristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28bb06da56Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29bb06da56Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30bb06da56Schristos  * SUCH DAMAGE.
31bb06da56Schristos  */
32bb06da56Schristos 
33bb06da56Schristos #include <sys/param.h>
34bb06da56Schristos #include <sys/protosw.h>
35bb06da56Schristos #include <sys/socket.h>
36bb06da56Schristos #include <sys/sysctl.h>
37bb06da56Schristos 
38bb06da56Schristos #include <net/if.h>
39bb06da56Schristos #include <net/if_dl.h>
40bb06da56Schristos #include <net/if_types.h>
41bb06da56Schristos #include <net/pfvar.h>
42bb06da56Schristos #include <net/pfkeyv2.h>
43bb06da56Schristos #include <net/route.h>
44bb06da56Schristos #include <netinet/in.h>
45bb06da56Schristos #include <netinet/if_ether.h>
46bb06da56Schristos #include <netatalk/at.h>
47bb06da56Schristos #include <netmpls/mpls.h>
48bb06da56Schristos #include <arpa/inet.h>
49bb06da56Schristos 
50bb06da56Schristos #include <err.h>
51bb06da56Schristos #include <errno.h>
52bb06da56Schristos #include <netdb.h>
53bb06da56Schristos #include <stdio.h>
54bb06da56Schristos #include <stddef.h>
55bb06da56Schristos #include <stdlib.h>
56bb06da56Schristos #include <string.h>
57bb06da56Schristos #include <unistd.h>
58bb06da56Schristos 
59bb06da56Schristos #include "prog_ops.h"
60bb06da56Schristos #include "rtutil.h"
61bb06da56Schristos 
62bb06da56Schristos #define PLEN    (LONG_BIT / 4 + 2)
63bb06da56Schristos #define PFKEYV2_CHUNK sizeof(u_int64_t)
64bb06da56Schristos static char *link_print(const struct sockaddr *);
65bb06da56Schristos 
66bb06da56Schristos /*
67bb06da56Schristos  * Definitions for showing gateway flags.
68bb06da56Schristos  */
69bb06da56Schristos struct bits {
70bb06da56Schristos 	int	b_mask;
71bb06da56Schristos 	char	b_val;
72bb06da56Schristos };
73bb06da56Schristos static const struct bits bits[] = {
74bb06da56Schristos 	{ RTF_UP,	'U' },
75bb06da56Schristos 	{ RTF_GATEWAY,	'G' },
76bb06da56Schristos 	{ RTF_HOST,	'H' },
77bb06da56Schristos 	{ RTF_REJECT,	'R' },
78bb06da56Schristos 	{ RTF_BLACKHOLE, 'B' },
79bb06da56Schristos 	{ RTF_DYNAMIC,	'D' },
80bb06da56Schristos 	{ RTF_MODIFIED,	'M' },
81bb06da56Schristos 	{ RTF_DONE,	'd' }, /* Completed -- for routing messages only */
82bb06da56Schristos 	{ RTF_MASK,	'm' }, /* Mask Present -- for routing messages only */
832c3eb313Sozaki-r 	/* { RTF_CLONING,	'C' }, */
842c3eb313Sozaki-r 	{ RTF_CONNECTED, 'C' },
852c3eb313Sozaki-r 	/* { RTF_XRESOLVE,	'X' }, */
86*d866c9e7Schristos 	{ RTF_LLDATA,	'L' },
87bb06da56Schristos 	{ RTF_STATIC,	'S' },
88bb06da56Schristos 	{ RTF_PROTO1,	'1' },
89bb06da56Schristos 	{ RTF_PROTO2,	'2' },
90bb06da56Schristos 	/* { RTF_PROTO3,	'3' }, */
912c3eb313Sozaki-r 	/* { RTF_CLONED,	'c' }, */
92bb06da56Schristos 	/* { RTF_JUMBO,	'J' }, */
93bb06da56Schristos 	{ RTF_ANNOUNCE,	'p' },
942a0e0fd4Sroy 	{ RTF_LOCAL, 'l'},
95260c0658Sroy 	{ RTF_BROADCAST, 'b'},
96bb06da56Schristos 	{ 0, 0 }
97bb06da56Schristos };
98bb06da56Schristos 
99bb06da56Schristos #ifndef SMALL
100bb06da56Schristos static void p_tag(const struct sockaddr *sa);
101bb06da56Schristos #endif
102bb06da56Schristos static void p_rtentry(struct rt_msghdr *, int, int);
103bb06da56Schristos 
104bb06da56Schristos /*
105bb06da56Schristos  * Print routing tables.
106bb06da56Schristos  */
107bb06da56Schristos void
p_rttables(int paf,int flags,int pflags,int interesting)108bb06da56Schristos p_rttables(int paf, int flags, int pflags, int interesting)
109bb06da56Schristos {
110bb06da56Schristos 	struct rt_msghdr *rtm;
111bb06da56Schristos 	char *buf = NULL, *next, *lim = NULL;
112bb06da56Schristos 	size_t needed;
113bb06da56Schristos 	int mib[6];
114bb06da56Schristos 	struct sockaddr *sa;
115bb06da56Schristos 
116bb06da56Schristos 	mib[0] = CTL_NET;
117bb06da56Schristos 	mib[1] = PF_ROUTE;
118bb06da56Schristos 	mib[2] = 0;
119bb06da56Schristos 	mib[3] = paf;
120bb06da56Schristos 	mib[4] = NET_RT_DUMP;
121bb06da56Schristos 	mib[5] = 0;
122bb06da56Schristos 	if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
123bb06da56Schristos 		err(1, "route-sysctl-estimate");
124bb06da56Schristos 	if (needed > 0) {
125bb06da56Schristos 		if ((buf = malloc(needed)) == 0)
126bb06da56Schristos 			err(1, NULL);
127bb06da56Schristos 		if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
128bb06da56Schristos 			err(1, "sysctl of routing table");
129bb06da56Schristos 		lim = buf + needed;
130bb06da56Schristos 	}
131bb06da56Schristos 
132bb06da56Schristos 	printf("Routing tables\n");
133bb06da56Schristos 
134bb06da56Schristos 	if (buf) {
135bb06da56Schristos 		for (next = buf; next < lim; next += rtm->rtm_msglen) {
136bb06da56Schristos 			rtm = (struct rt_msghdr *)next;
137bb06da56Schristos 			sa = (struct sockaddr *)(rtm + 1);
138bb06da56Schristos 			if ((rtm->rtm_flags & pflags) != pflags)
139bb06da56Schristos 				continue;
140bb06da56Schristos 			if (paf != AF_UNSPEC && sa->sa_family != paf)
141bb06da56Schristos 				continue;
142bb06da56Schristos 			p_rtentry(rtm, flags, interesting);
143bb06da56Schristos 		}
144bb06da56Schristos 		free(buf);
145bb06da56Schristos 		buf = NULL;
146bb06da56Schristos 	}
147bb06da56Schristos 
148bb06da56Schristos 	if (paf != 0 && paf != PF_KEY)
149bb06da56Schristos 		return;
150bb06da56Schristos 
151bb06da56Schristos #if 0 /* XXX-elad */
152bb06da56Schristos 	mib[0] = CTL_NET;
153bb06da56Schristos 	mib[1] = PF_KEY;
154bb06da56Schristos 	mib[2] = PF_KEY_V2;
155bb06da56Schristos 	mib[3] = NET_KEY_SPD_DUMP;
156bb06da56Schristos 	mib[4] = mib[5] = 0;
157bb06da56Schristos 
158bb06da56Schristos 	if (prog_sysctl(mib, 4, NULL, &needed, NULL, 0) == -1) {
159bb06da56Schristos 		if (errno == ENOPROTOOPT)
160bb06da56Schristos 			return;
161bb06da56Schristos 		err(1, "spd-sysctl-estimate");
162bb06da56Schristos 	}
163bb06da56Schristos 	if (needed > 0) {
164bb06da56Schristos 		if ((buf = malloc(needed)) == 0)
165bb06da56Schristos 			err(1, NULL);
166bb06da56Schristos 		if (prog_sysctl(mib, 4, buf, &needed, NULL, 0) == -1)
167bb06da56Schristos 			err(1,"sysctl of spd");
168bb06da56Schristos 		lim = buf + needed;
169bb06da56Schristos 	}
170bb06da56Schristos 
171bb06da56Schristos 	if (buf) {
172bb06da56Schristos 		printf("\nEncap:\n");
173bb06da56Schristos 
174bb06da56Schristos 		for (next = buf; next < lim; next += msg->sadb_msg_len *
175bb06da56Schristos 		    PFKEYV2_CHUNK) {
176bb06da56Schristos 			msg = (struct sadb_msg *)next;
177bb06da56Schristos 			if (msg->sadb_msg_len == 0)
178bb06da56Schristos 				break;
179bb06da56Schristos 			p_pfkentry(msg);
180bb06da56Schristos 		}
181bb06da56Schristos 		free(buf);
182bb06da56Schristos 		buf = NULL;
183bb06da56Schristos 	}
184bb06da56Schristos #endif /* 0 */
185bb06da56Schristos }
186bb06da56Schristos 
187bb06da56Schristos /*
188bb06da56Schristos  * column widths; each followed by one space
189bb06da56Schristos  * width of destination/gateway column
190daf4d720Schristos  * strlen("fe80::aaaa:bbbb:cccc:dddd@gif0") == 30, strlen("/128") == 4 = 34
191daf4d720Schristos  * strlen("aaaa:bbbb:cccc:dddd:eeee:ffff:gggg:hhhh") == 39
192bb06da56Schristos  */
193bb06da56Schristos #ifndef INET6
194bb06da56Schristos #define	WID_DST(af)	18	/* width of destination column */
195bb06da56Schristos #define	WID_GW(af)	18	/* width of gateway column */
196bb06da56Schristos #else
197daf4d720Schristos #define	WID_DST(af)	((af) == AF_INET6 ? ((flags & RT_NFLAG) ? 39 : 18) : 18)
198bb06da56Schristos #define	WID_GW(af)	((af) == AF_INET6 ? ((flags & RT_NFLAG) ? 30 : 18) : 18)
199bb06da56Schristos #endif
200bb06da56Schristos 
201bb06da56Schristos /*
202bb06da56Schristos  * Print header for routing table columns.
203bb06da56Schristos  */
204bb06da56Schristos void
p_rthdr(int paf,int flags)205bb06da56Schristos p_rthdr(int paf, int flags)
206bb06da56Schristos {
207bb06da56Schristos #ifndef SMALL
208bb06da56Schristos 	if (flags & RT_AFLAG)
209bb06da56Schristos 		printf("%-*.*s ", PLEN, PLEN, "Address");
210bb06da56Schristos 	if (paf == PF_KEY) {
211bb06da56Schristos 		printf("%-18s %-5s %-18s %-5s %-5s %-22s\n",
212bb06da56Schristos 		    "Source", "Port", "Destination",
213bb06da56Schristos 		    "Port", "Proto", "SA(Address/Proto/Type/Direction)");
214bb06da56Schristos 		return;
215bb06da56Schristos 	}
216bb06da56Schristos 	if (flags & RT_TFLAG) {
217bb06da56Schristos 	    printf("%-*.*s %-*.*s %-6.6s %6.6s %8.8s %6.6s %7.7s"
218bb06da56Schristos 		" %s\n", WID_DST(paf), WID_DST(paf), "Destination",
219bb06da56Schristos 		WID_GW(paf), WID_GW(paf), "Gateway",
220bb06da56Schristos 		"Flags", "Refs", "Use", "Mtu", "Tag", "Interface");
221bb06da56Schristos 	    return;
222bb06da56Schristos 	}
223bb06da56Schristos #endif
224bb06da56Schristos #ifndef SMALL
225bb06da56Schristos 	printf("%-*.*s %-*.*s %-6.6s %6.6s %8.8s %6.6s %s\n",
226bb06da56Schristos 	    WID_DST(paf), WID_DST(paf), "Destination",
227bb06da56Schristos 	    WID_GW(paf), WID_GW(paf), "Gateway",
228bb06da56Schristos 	    "Flags", "Refs", "Use", "Mtu", "Interface");
229bb06da56Schristos #else
230bb06da56Schristos 	printf("%-*.*s %-*.*s %-6.6s\n",
231bb06da56Schristos 	    WID_DST(paf), WID_DST(paf), "Destination",
232bb06da56Schristos 	    WID_GW(paf), WID_GW(paf), "Gateway",
233bb06da56Schristos 	    "Flags");
234bb06da56Schristos #endif
235bb06da56Schristos }
236bb06da56Schristos 
237bb06da56Schristos static void
get_rtaddrs(int addrs,struct sockaddr * sa,struct sockaddr ** rti_info)238bb06da56Schristos get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
239bb06da56Schristos {
240bb06da56Schristos 	int	i;
241bb06da56Schristos 
242bb06da56Schristos 	for (i = 0; i < RTAX_MAX; i++) {
243bb06da56Schristos 		if (addrs & (1 << i)) {
244bb06da56Schristos 			rti_info[i] = sa;
245bb06da56Schristos 			sa = (struct sockaddr *)((char *)(sa) +
246bb06da56Schristos 			    RT_ROUNDUP(sa->sa_len));
247bb06da56Schristos 		} else
248bb06da56Schristos 			rti_info[i] = NULL;
249bb06da56Schristos 	}
250bb06da56Schristos }
251bb06da56Schristos 
252bb06da56Schristos /*
253bb06da56Schristos  * Print a routing table entry.
254bb06da56Schristos  */
255bb06da56Schristos static void
p_rtentry(struct rt_msghdr * rtm,int flags,int interesting)256bb06da56Schristos p_rtentry(struct rt_msghdr *rtm, int flags, int interesting)
257bb06da56Schristos {
258bb06da56Schristos 	static int	 old_af = -1;
259bb06da56Schristos 	struct sockaddr	*sa = (struct sockaddr *)(rtm + 1);
260bb06da56Schristos 	struct sockaddr	*mask, *rti_info[RTAX_MAX];
261bb06da56Schristos #ifndef SMALL
262bb06da56Schristos 	char		 ifbuf[IF_NAMESIZE];
263bb06da56Schristos #endif
264bb06da56Schristos 
265*d866c9e7Schristos 	if ((flags & RT_LFLAG) && (rtm->rtm_flags & RTF_LLDATA))
266b5c2da7fSozaki-r 		return;
267b5c2da7fSozaki-r 
268bb06da56Schristos 	if (old_af != sa->sa_family) {
269bb06da56Schristos 		old_af = sa->sa_family;
270bb06da56Schristos 		p_family(sa->sa_family);
271bb06da56Schristos 		p_rthdr(sa->sa_family, flags);
272bb06da56Schristos 	}
273bb06da56Schristos 	get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
274bb06da56Schristos 
275bb06da56Schristos 	mask = rti_info[RTAX_NETMASK];
276bb06da56Schristos 	if ((sa = rti_info[RTAX_DST]) == NULL)
277bb06da56Schristos 		return;
278bb06da56Schristos 
279bb06da56Schristos 	p_sockaddr(sa, mask, rtm->rtm_flags, WID_DST(sa->sa_family), flags);
280bb06da56Schristos 	p_sockaddr(rti_info[RTAX_GATEWAY], NULL, RTF_HOST,
281bb06da56Schristos 	    WID_GW(sa->sa_family), flags);
282bb06da56Schristos 	p_flags(rtm->rtm_flags & interesting);
283bb06da56Schristos #if 0 /* XXX-elad */
284bb06da56Schristos 	printf("%6d %8"PRId64" ", (int)rtm->rtm_rmx.rmx_refcnt,
285bb06da56Schristos 	    rtm->rtm_rmx.rmx_pksent);
286bb06da56Schristos #else
287bb06da56Schristos 	printf("%6s %8s ", "-", "-");
288bb06da56Schristos #endif
289bb06da56Schristos #ifndef SMALL
290bb06da56Schristos 	if (rtm->rtm_rmx.rmx_mtu)
291bb06da56Schristos 		printf("%6"PRId64, rtm->rtm_rmx.rmx_mtu);
292bb06da56Schristos 	else
293bb06da56Schristos 		printf("%6s", "-");
294bb06da56Schristos 	putchar((rtm->rtm_rmx.rmx_locks & RTV_MTU) ? 'L' : ' ');
295bb06da56Schristos 	if (flags & RT_TFLAG)
296bb06da56Schristos 		p_tag(rti_info[RTAX_TAG]);
297bb06da56Schristos 	printf(" %.16s", if_indextoname(rtm->rtm_index, ifbuf));
298bb06da56Schristos 	putchar('\n');
299bb06da56Schristos 	if (flags & RT_VFLAG)
300bb06da56Schristos 		p_rtrmx(&rtm->rtm_rmx);
3019d61912cSmanu #else
3029d61912cSmanu 	putchar('\n');
303bb06da56Schristos #endif
304bb06da56Schristos }
305bb06da56Schristos 
306bb06da56Schristos /*
307bb06da56Schristos  * Print address family header before a section of the routing table.
308bb06da56Schristos  */
309bb06da56Schristos void
p_family(int paf)310bb06da56Schristos p_family(int paf)
311bb06da56Schristos {
312bb06da56Schristos 	const char *afname;
313bb06da56Schristos 
314bb06da56Schristos 	switch (paf) {
315bb06da56Schristos 	case AF_INET:
316bb06da56Schristos 		afname = "Internet";
317bb06da56Schristos 		break;
318bb06da56Schristos #ifdef INET6
319bb06da56Schristos 	case AF_INET6:
320bb06da56Schristos 		afname = "Internet6";
321bb06da56Schristos 		break;
322bb06da56Schristos #endif
323bb06da56Schristos 	case PF_KEY:
324bb06da56Schristos 		afname = "Encap";
325bb06da56Schristos 		break;
326bb06da56Schristos 	case AF_APPLETALK:
327bb06da56Schristos 		afname = "AppleTalk";
328bb06da56Schristos 		break;
329bb06da56Schristos #ifndef SMALL
330bb06da56Schristos 	case AF_MPLS:
331bb06da56Schristos 		afname = "MPLS";
332bb06da56Schristos 		break;
333bb06da56Schristos #endif
334bb06da56Schristos 	default:
335bb06da56Schristos 		afname = NULL;
336bb06da56Schristos 		break;
337bb06da56Schristos 	}
338bb06da56Schristos 	if (afname)
339bb06da56Schristos 		printf("\n%s:\n", afname);
340bb06da56Schristos 	else
341bb06da56Schristos 		printf("\nProtocol Family %d:\n", paf);
342bb06da56Schristos }
343bb06da56Schristos 
344bb06da56Schristos void
p_sockaddr(const struct sockaddr * sa,const struct sockaddr * mask,int rflags,int width,int flags)345bb06da56Schristos p_sockaddr(const struct sockaddr *sa, const struct sockaddr *mask, int rflags,
346bb06da56Schristos     int width, int flags)
347bb06da56Schristos {
348bb06da56Schristos 	char *cp;
349bb06da56Schristos 
350bb06da56Schristos 	switch (sa->sa_family) {
351bb06da56Schristos #ifdef INET6
352bb06da56Schristos 	case AF_INET6:
353bb06da56Schristos 	    {
354bb06da56Schristos 		struct sockaddr_in6 sa6 = *(const struct sockaddr_in6 *)sa;
355bb06da56Schristos 
356bb06da56Schristos 		inet6_getscopeid(&sa6, INET6_IS_ADDR_LINKLOCAL|
357bb06da56Schristos 		    INET6_IS_ADDR_MC_LINKLOCAL);
358bb06da56Schristos 		if (rflags & RTF_HOST)
359bb06da56Schristos 			cp = routename((const struct sockaddr *)&sa6, flags);
360bb06da56Schristos 		else
361bb06da56Schristos 			cp = netname((const struct sockaddr *)&sa6, mask, flags);
362bb06da56Schristos 		break;
363bb06da56Schristos 	    }
364bb06da56Schristos #endif
365bb06da56Schristos 	default:
366bb06da56Schristos 		if ((rflags & RTF_HOST) || mask == NULL)
367bb06da56Schristos 			cp = routename(sa, flags);
368bb06da56Schristos 		else
369bb06da56Schristos 			cp = netname(sa, mask, flags);
370bb06da56Schristos 		break;
371bb06da56Schristos 	}
372bb06da56Schristos 	if (width < 0)
373bb06da56Schristos 		printf("%s", cp);
374bb06da56Schristos 	else {
375bb06da56Schristos 		if (flags & RT_NFLAG)
376bb06da56Schristos 			printf("%-*s ", width, cp);
377bb06da56Schristos 		else
378bb06da56Schristos 			printf("%-*.*s ", width, width, cp);
379bb06da56Schristos 	}
380bb06da56Schristos }
381bb06da56Schristos 
382bb06da56Schristos void
p_flags(int f)383bb06da56Schristos p_flags(int f)
384bb06da56Schristos {
385bb06da56Schristos 	char name[33], *flags;
386bb06da56Schristos 	const struct bits *p = bits;
387bb06da56Schristos 
388bb06da56Schristos 	for (flags = name; p->b_mask && flags < &name[sizeof(name) - 2]; p++)
389bb06da56Schristos 		if (p->b_mask & f)
390bb06da56Schristos 			*flags++ = p->b_val;
391bb06da56Schristos 	*flags = '\0';
392bb06da56Schristos 	printf("%-6.6s ", name);
393bb06da56Schristos }
394bb06da56Schristos 
395bb06da56Schristos #ifndef SMALL
396bb06da56Schristos void
p_rtrmx(const struct rt_metrics * rmx)397bb06da56Schristos p_rtrmx(const struct rt_metrics *rmx)
398bb06da56Schristos {
399bb06da56Schristos 	printf("\texpire   %10"PRId64"%c  recvpipe %10"PRIu64"%c  "
400bb06da56Schristos 	    "sendpipe %10"PRIu64"%c\n",
401bb06da56Schristos 	    (int64_t)rmx->rmx_expire,
402bb06da56Schristos 	    (rmx->rmx_locks & RTV_EXPIRE) ? 'L' : ' ', rmx->rmx_recvpipe,
403bb06da56Schristos 	    (rmx->rmx_locks & RTV_RPIPE) ? 'L' : ' ', rmx->rmx_sendpipe,
404bb06da56Schristos 	    (rmx->rmx_locks & RTV_SPIPE) ? 'L' : ' ');
405bb06da56Schristos 	printf("\tssthresh %10"PRIu64"%c  rtt      %10"PRIu64"%c  "
406bb06da56Schristos 	    "rttvar   %10"PRIu64"%c\n", rmx->rmx_ssthresh,
407bb06da56Schristos 	    (rmx->rmx_locks & RTV_SSTHRESH) ? 'L' : ' ',
408bb06da56Schristos 	    rmx->rmx_rtt, (rmx->rmx_locks & RTV_RTT) ? 'L' : ' ',
409bb06da56Schristos 	    rmx->rmx_rttvar, (rmx->rmx_locks & RTV_RTTVAR) ? 'L' : ' ');
410bb06da56Schristos 	printf("\thopcount %10"PRIu64"%c\n",
411bb06da56Schristos 	    rmx->rmx_hopcount, (rmx->rmx_locks & RTV_HOPCOUNT) ? 'L' : ' ');
412bb06da56Schristos }
413bb06da56Schristos 
414bb06da56Schristos static void
p_tag(const struct sockaddr * sa)415bb06da56Schristos p_tag(const struct sockaddr *sa)
416bb06da56Schristos {
417bb06da56Schristos 	char *line;
418bb06da56Schristos 
419bb06da56Schristos 	if (sa == NULL || sa->sa_family != AF_MPLS) {
420bb06da56Schristos 		printf("%7s", "-");
421bb06da56Schristos 		return;
422bb06da56Schristos 	}
423bb06da56Schristos 	line = mpls_ntoa(sa);
424bb06da56Schristos 	if (strlen(line) < 7)
425bb06da56Schristos 		printf("%7s", line);
426bb06da56Schristos 	else
427bb06da56Schristos 		printf("%s", line);
428bb06da56Schristos }
429bb06da56Schristos #endif
430bb06da56Schristos 
431bb06da56Schristos static char line[MAXHOSTNAMELEN];
432bb06da56Schristos static char domain[MAXHOSTNAMELEN];
433bb06da56Schristos 
434bb06da56Schristos char *
routename(const struct sockaddr * sa,int flags)435bb06da56Schristos routename(const struct sockaddr *sa, int flags)
436bb06da56Schristos {
437bb06da56Schristos 	char *cp = NULL;
438bb06da56Schristos 	static int first = 1;
439bb06da56Schristos 
440bb06da56Schristos 	if (first) {
441bb06da56Schristos 		first = 0;
442bb06da56Schristos 		if (gethostname(domain, sizeof(domain)) == 0 &&
443bb06da56Schristos 		    (cp = strchr(domain, '.')))
444bb06da56Schristos 			(void)strlcpy(domain, cp + 1, sizeof(domain));
445bb06da56Schristos 		else
446bb06da56Schristos 			domain[0] = '\0';
447bb06da56Schristos 		cp = NULL;
448bb06da56Schristos 	}
449bb06da56Schristos 
450bb06da56Schristos 	if (sa->sa_len == 0) {
451bb06da56Schristos 		(void)strlcpy(line, "default", sizeof(line));
452bb06da56Schristos 		return (line);
453bb06da56Schristos 	}
454bb06da56Schristos 
455bb06da56Schristos 	switch (sa->sa_family) {
456bb06da56Schristos 	case AF_INET:
457bb06da56Schristos 		return routename4(
458bb06da56Schristos 		    ((const struct sockaddr_in *)sa)->sin_addr.s_addr,
459bb06da56Schristos 		    flags);
460bb06da56Schristos #ifdef INET6
461bb06da56Schristos 	case AF_INET6:
462bb06da56Schristos 	    {
463bb06da56Schristos 		struct sockaddr_in6 sin6;
464bb06da56Schristos 
465bb06da56Schristos 		memset(&sin6, 0, sizeof(sin6));
466bb06da56Schristos 		memcpy(&sin6, sa, sa->sa_len);
467bb06da56Schristos 		sin6.sin6_len = sizeof(struct sockaddr_in6);
468bb06da56Schristos 		sin6.sin6_family = AF_INET6;
469bb06da56Schristos 		if (sa->sa_len == sizeof(struct sockaddr_in6))
470bb06da56Schristos 			inet6_getscopeid(&sin6, INET6_IS_ADDR_LINKLOCAL|
471bb06da56Schristos 			    INET6_IS_ADDR_MC_LINKLOCAL);
472bb06da56Schristos 		return routename6(&sin6, flags);
473bb06da56Schristos 	    }
474bb06da56Schristos #endif
475bb06da56Schristos 	case AF_LINK:
476bb06da56Schristos 		return link_print(sa);
477bb06da56Schristos 
478bb06da56Schristos #ifndef SMALL
479bb06da56Schristos 	case AF_MPLS:
480bb06da56Schristos 		return mpls_ntoa(sa);
481bb06da56Schristos 
482bb06da56Schristos 	case AF_APPLETALK:
483bb06da56Schristos 		(void)snprintf(line, sizeof(line), "atalk %d.%d",
484bb06da56Schristos 		    ((const struct sockaddr_at *)sa)->sat_addr.s_net,
485bb06da56Schristos 		    ((const struct sockaddr_at *)sa)->sat_addr.s_node);
486bb06da56Schristos 		break;
487bb06da56Schristos #endif
488bb06da56Schristos 
489bb06da56Schristos #if 0 /* XXX-elad */
490bb06da56Schristos 	case AF_UNSPEC:
491bb06da56Schristos 		if (sa->sa_len == sizeof(struct sockaddr_rtlabel)) {
492bb06da56Schristos 			static char name[RTLABEL_LEN];
493bb06da56Schristos 			struct sockaddr_rtlabel *sr;
494bb06da56Schristos 
495bb06da56Schristos 			sr = (struct sockaddr_rtlabel *)sa;
496bb06da56Schristos 			strlcpy(name, sr->sr_label, sizeof(name));
497bb06da56Schristos 			return (name);
498bb06da56Schristos 		}
499bb06da56Schristos 		/* FALLTHROUGH */
500bb06da56Schristos #endif
501bb06da56Schristos 	default:
502bb06da56Schristos 		(void)snprintf(line, sizeof(line), "(%d) %s",
503bb06da56Schristos 		    sa->sa_family, any_ntoa(sa));
504bb06da56Schristos 		break;
505bb06da56Schristos 	}
506bb06da56Schristos 	return (line);
507bb06da56Schristos }
508bb06da56Schristos 
509bb06da56Schristos char *
routename4(in_addr_t in,int flags)510bb06da56Schristos routename4(in_addr_t in, int flags)
511bb06da56Schristos {
512bb06da56Schristos 	const char	*cp = NULL;
513bb06da56Schristos 	struct in_addr	 ina;
514bb06da56Schristos 	struct hostent	*hp;
515bb06da56Schristos 
516bb06da56Schristos 	if (in == INADDR_ANY)
517bb06da56Schristos 		cp = "default";
518bb06da56Schristos 	if (!cp && (flags & RT_NFLAG) == 0) {
519bb06da56Schristos 		if ((hp = gethostbyaddr((char *)&in,
520bb06da56Schristos 		    sizeof(in), AF_INET)) != NULL) {
521bb06da56Schristos 			char *p;
522bb06da56Schristos 			if ((p = strchr(hp->h_name, '.')) &&
523bb06da56Schristos 			    !strcmp(p + 1, domain))
524bb06da56Schristos 				*p = '\0';
525bb06da56Schristos 			cp = hp->h_name;
526bb06da56Schristos 		}
527bb06da56Schristos 	}
528bb06da56Schristos 	ina.s_addr = in;
529bb06da56Schristos 	strlcpy(line, cp ? cp : inet_ntoa(ina), sizeof(line));
530bb06da56Schristos 
531bb06da56Schristos 	return (line);
532bb06da56Schristos }
533bb06da56Schristos 
534bb06da56Schristos #ifdef INET6
535bb06da56Schristos char *
routename6(const struct sockaddr_in6 * sin6,int flags)536bb06da56Schristos routename6(const struct sockaddr_in6 *sin6, int flags)
537bb06da56Schristos {
538bb06da56Schristos 	int	 niflags = 0;
539bb06da56Schristos 
540bb06da56Schristos 	if ((flags & RT_NFLAG))
541bb06da56Schristos 		niflags |= NI_NUMERICHOST;
542bb06da56Schristos 	else
543bb06da56Schristos 		niflags |= NI_NOFQDN;
544bb06da56Schristos 
545bb06da56Schristos 	if (getnameinfo((const struct sockaddr *)sin6, sin6->sin6_len,
546bb06da56Schristos 	    line, sizeof(line), NULL, 0, niflags) != 0)
547bb06da56Schristos 		strncpy(line, "invalid", sizeof(line));
548bb06da56Schristos 
549bb06da56Schristos 	return (line);
550bb06da56Schristos }
551bb06da56Schristos #endif
552bb06da56Schristos 
553bb06da56Schristos /*
554bb06da56Schristos  * Return the name of the network whose address is given.
555bb06da56Schristos  * The address is assumed to be that of a net or subnet, not a host.
556bb06da56Schristos  */
557bb06da56Schristos char *
netname4(const struct sockaddr_in * sa4,const struct sockaddr_in * mask,int flags)55814f2cc91Schristos netname4(const struct sockaddr_in* sa4, const struct sockaddr_in *mask, int flags)
559bb06da56Schristos {
560bb06da56Schristos 	const char *cp = NULL;
561bb06da56Schristos 	struct netent *np = NULL;
562bb06da56Schristos 	int mbits;
56314f2cc91Schristos 	in_addr_t in = sa4->sin_addr.s_addr;
56414f2cc91Schristos 
56514f2cc91Schristos 	if (mask) {
56614f2cc91Schristos 		in_addr_t m = mask->sin_addr.s_addr ;
56714f2cc91Schristos 		m = ntohl(m);
56814f2cc91Schristos 		mbits = m ? 33 - ffs(m) : 0;
56914f2cc91Schristos 	} else
57014f2cc91Schristos 		mbits = 0;
571bb06da56Schristos 
572bb06da56Schristos 	in = ntohl(in);
57314f2cc91Schristos 	if (in == INADDR_ANY && !mbits)
57414f2cc91Schristos 		cp = "default";
57514f2cc91Schristos 	else if (!(flags & RT_NFLAG) && in != INADDR_ANY) {
576bb06da56Schristos 		if ((np = getnetbyaddr(in, AF_INET)) != NULL)
577bb06da56Schristos 			cp = np->n_name;
578bb06da56Schristos 	}
579bb06da56Schristos 	if (cp)
580bb06da56Schristos 		strlcpy(line, cp, sizeof(line));
581bb06da56Schristos #define C(x)	((x) & 0xff)
582bb06da56Schristos 	else if (mbits < 9)
583bb06da56Schristos 		snprintf(line, sizeof(line), "%u/%d", C(in >> 24), mbits);
584bb06da56Schristos 	else if (mbits < 17)
585bb06da56Schristos 		snprintf(line, sizeof(line), "%u.%u/%d",
586bb06da56Schristos 		    C(in >> 24) , C(in >> 16), mbits);
587bb06da56Schristos 	else if (mbits < 25)
588bb06da56Schristos 		snprintf(line, sizeof(line), "%u.%u.%u/%d",
589bb06da56Schristos 		    C(in >> 24), C(in >> 16), C(in >> 8), mbits);
590bb06da56Schristos 	else
591bb06da56Schristos 		snprintf(line, sizeof(line), "%u.%u.%u.%u/%d", C(in >> 24),
592bb06da56Schristos 		    C(in >> 16), C(in >> 8), C(in), mbits);
593bb06da56Schristos #undef C
59414f2cc91Schristos 	return line;
595bb06da56Schristos }
596bb06da56Schristos 
597bb06da56Schristos #ifdef INET6
598bb06da56Schristos char *
netname6(const struct sockaddr_in6 * sa6,const struct sockaddr_in6 * mask,int flags)599bb06da56Schristos netname6(const struct sockaddr_in6 *sa6, const struct sockaddr_in6 *mask, int flags)
600bb06da56Schristos {
601bb06da56Schristos 	struct sockaddr_in6 sin6;
602bb06da56Schristos 	const u_char *p;
603bb06da56Schristos 	int masklen, final = 0, illegal = 0;
604bb06da56Schristos 	int i, lim, flag, error;
605bb06da56Schristos 	char hbuf[NI_MAXHOST];
606bb06da56Schristos 
607bb06da56Schristos 	sin6 = *sa6;
608bb06da56Schristos 
609bb06da56Schristos 	flag = 0;
610bb06da56Schristos 	masklen = 0;
611bb06da56Schristos 	if (mask) {
612bb06da56Schristos 		lim = mask->sin6_len - offsetof(struct sockaddr_in6, sin6_addr);
613bb06da56Schristos 		if (lim < 0)
614bb06da56Schristos 			lim = 0;
615bb06da56Schristos 		else if (lim > (int)sizeof(struct in6_addr))
616bb06da56Schristos 			lim = sizeof(struct in6_addr);
617bb06da56Schristos 		for (p = (const u_char *)&mask->sin6_addr, i = 0; i < lim; p++) {
618bb06da56Schristos 			if (final && *p) {
619bb06da56Schristos 				illegal++;
620bb06da56Schristos 				sin6.sin6_addr.s6_addr[i++] = 0x00;
621bb06da56Schristos 				continue;
622bb06da56Schristos 			}
623bb06da56Schristos 
624bb06da56Schristos 			switch (*p & 0xff) {
625bb06da56Schristos 			case 0xff:
626bb06da56Schristos 				masklen += 8;
627bb06da56Schristos 				break;
628bb06da56Schristos 			case 0xfe:
629bb06da56Schristos 				masklen += 7;
630bb06da56Schristos 				final++;
631bb06da56Schristos 				break;
632bb06da56Schristos 			case 0xfc:
633bb06da56Schristos 				masklen += 6;
634bb06da56Schristos 				final++;
635bb06da56Schristos 				break;
636bb06da56Schristos 			case 0xf8:
637bb06da56Schristos 				masklen += 5;
638bb06da56Schristos 				final++;
639bb06da56Schristos 				break;
640bb06da56Schristos 			case 0xf0:
641bb06da56Schristos 				masklen += 4;
642bb06da56Schristos 				final++;
643bb06da56Schristos 				break;
644bb06da56Schristos 			case 0xe0:
645bb06da56Schristos 				masklen += 3;
646bb06da56Schristos 				final++;
647bb06da56Schristos 				break;
648bb06da56Schristos 			case 0xc0:
649bb06da56Schristos 				masklen += 2;
650bb06da56Schristos 				final++;
651bb06da56Schristos 				break;
652bb06da56Schristos 			case 0x80:
653bb06da56Schristos 				masklen += 1;
654bb06da56Schristos 				final++;
655bb06da56Schristos 				break;
656bb06da56Schristos 			case 0x00:
657bb06da56Schristos 				final++;
658bb06da56Schristos 				break;
659bb06da56Schristos 			default:
660bb06da56Schristos 				final++;
661bb06da56Schristos 				illegal++;
662bb06da56Schristos 				break;
663bb06da56Schristos 			}
664bb06da56Schristos 
665bb06da56Schristos 			if (!illegal)
666bb06da56Schristos 				sin6.sin6_addr.s6_addr[i++] &= *p;
667bb06da56Schristos 			else
668bb06da56Schristos 				sin6.sin6_addr.s6_addr[i++] = 0x00;
669bb06da56Schristos 		}
670bb06da56Schristos 		while (i < (int)sizeof(struct in6_addr))
671bb06da56Schristos 			sin6.sin6_addr.s6_addr[i++] = 0x00;
672bb06da56Schristos 	} else
673bb06da56Schristos 		masklen = 128;
674bb06da56Schristos 
675bb06da56Schristos 	if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) {
676bb06da56Schristos 		snprintf(line, sizeof(line), "default");
677bb06da56Schristos 		return (line);
678bb06da56Schristos 	}
679bb06da56Schristos 
680bb06da56Schristos 	if (illegal)
681bb06da56Schristos 		warnx("illegal prefixlen");
682bb06da56Schristos 
683bb06da56Schristos 	if (flags & RT_NFLAG)
684bb06da56Schristos 		flag |= NI_NUMERICHOST;
685bb06da56Schristos 	error = getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
686bb06da56Schristos 	    hbuf, sizeof(hbuf), NULL, 0, flag);
687bb06da56Schristos 	if (error)
688bb06da56Schristos 		snprintf(hbuf, sizeof(hbuf), "invalid");
689bb06da56Schristos 
690bb06da56Schristos 	snprintf(line, sizeof(line), "%s/%d", hbuf, masklen);
691bb06da56Schristos 	return (line);
692bb06da56Schristos }
693bb06da56Schristos #endif
694bb06da56Schristos 
695bb06da56Schristos /*
696bb06da56Schristos  * Return the name of the network whose address is given.
697bb06da56Schristos  * The address is assumed to be that of a net or subnet, not a host.
698bb06da56Schristos  */
699bb06da56Schristos char *
netname(const struct sockaddr * sa,const struct sockaddr * mask,int flags)700bb06da56Schristos netname(const struct sockaddr *sa, const struct sockaddr *mask, int flags)
701bb06da56Schristos {
702bb06da56Schristos 	switch (sa->sa_family) {
703bb06da56Schristos 
704bb06da56Schristos 	case AF_INET:
70514f2cc91Schristos 		return netname4((const struct sockaddr_in *)sa,
70614f2cc91Schristos 		    (const struct sockaddr_in *)mask, flags);
707bb06da56Schristos #ifdef INET6
708bb06da56Schristos 	case AF_INET6:
709bb06da56Schristos 		return netname6((const struct sockaddr_in6 *)sa,
710bb06da56Schristos 		    (const struct sockaddr_in6 *)mask, flags);
711bb06da56Schristos #endif
712bb06da56Schristos 	case AF_LINK:
713bb06da56Schristos 		return link_print(sa);
714bb06da56Schristos 	default:
715bb06da56Schristos 		snprintf(line, sizeof(line), "af %d: %s",
716bb06da56Schristos 		    sa->sa_family, any_ntoa(sa));
717bb06da56Schristos 		break;
718bb06da56Schristos 	}
719bb06da56Schristos 	return (line);
720bb06da56Schristos }
721bb06da56Schristos 
722bb06da56Schristos static const char hexlist[] = "0123456789abcdef";
723bb06da56Schristos 
724bb06da56Schristos char *
any_ntoa(const struct sockaddr * sa)725bb06da56Schristos any_ntoa(const struct sockaddr *sa)
726bb06da56Schristos {
727bb06da56Schristos 	static char obuf[240];
728bb06da56Schristos 	const char *in = sa->sa_data;
729bb06da56Schristos 	char *out = obuf;
730bb06da56Schristos 	int len = sa->sa_len - offsetof(struct sockaddr, sa_data);
731bb06da56Schristos 
732bb06da56Schristos 	*out++ = 'Q';
733bb06da56Schristos 	do {
734bb06da56Schristos 		*out++ = hexlist[(*in >> 4) & 15];
735bb06da56Schristos 		*out++ = hexlist[(*in++)    & 15];
736bb06da56Schristos 		*out++ = '.';
737bb06da56Schristos 	} while (--len > 0 && (out + 3) < &obuf[sizeof(obuf) - 1]);
738bb06da56Schristos 	out[-1] = '\0';
739bb06da56Schristos 	return (obuf);
740bb06da56Schristos }
741bb06da56Schristos 
742bb06da56Schristos static char *
link_print(const struct sockaddr * sa)743bb06da56Schristos link_print(const struct sockaddr *sa)
744bb06da56Schristos {
745bb06da56Schristos 	const struct sockaddr_dl *sdl = (const struct sockaddr_dl *)sa;
746bb06da56Schristos 	const u_char *lla = (const u_char *)sdl->sdl_data + sdl->sdl_nlen;
747bb06da56Schristos 
748bb06da56Schristos 	if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
749bb06da56Schristos 	    sdl->sdl_slen == 0) {
750bb06da56Schristos 		(void)snprintf(line, sizeof(line), "link#%d", sdl->sdl_index);
751bb06da56Schristos 		return (line);
752bb06da56Schristos 	}
753bb06da56Schristos 	switch (sdl->sdl_type) {
754bb06da56Schristos 	case IFT_ETHER:
755bb06da56Schristos 	case IFT_CARP:
756bb06da56Schristos 		return ether_ntoa((const struct ether_addr *)lla);
757bb06da56Schristos 	default:
758bb06da56Schristos 		return link_ntoa(sdl);
759bb06da56Schristos 	}
760bb06da56Schristos }
761bb06da56Schristos 
762bb06da56Schristos #ifndef SMALL
763bb06da56Schristos char *
mpls_ntoa(const struct sockaddr * sa)764bb06da56Schristos mpls_ntoa(const struct sockaddr *sa)
765bb06da56Schristos {
766bb06da56Schristos 	static char obuf[16];
767bb06da56Schristos 	size_t olen;
768bb06da56Schristos 	const union mpls_shim *pms;
769bb06da56Schristos 	union mpls_shim ms;
770bb06da56Schristos 	int psize = sizeof(struct sockaddr_mpls);
771bb06da56Schristos 
772bb06da56Schristos 	pms = &((const struct sockaddr_mpls*)sa)->smpls_addr;
773bb06da56Schristos 	ms.s_addr = ntohl(pms->s_addr);
774bb06da56Schristos 
775bb06da56Schristos 	snprintf(obuf, sizeof(obuf), "%u", ms.shim.label);
776bb06da56Schristos 
777bb06da56Schristos 	while(psize < sa->sa_len) {
778bb06da56Schristos 		pms++;
779bb06da56Schristos 		ms.s_addr = ntohl(pms->s_addr);
780bb06da56Schristos 		olen = strlen(obuf);
781bb06da56Schristos 		snprintf(obuf + olen, sizeof(obuf) - olen, ",%u",
782bb06da56Schristos 		    ms.shim.label);
783bb06da56Schristos 		psize+=sizeof(ms);
784bb06da56Schristos 	}
785bb06da56Schristos 	return obuf;
786bb06da56Schristos }
787bb06da56Schristos #endif
788bb06da56Schristos 
789bb06da56Schristos void
p_addr(const struct sockaddr * sa,const struct sockaddr * mask,int rflags,int flags)790bb06da56Schristos p_addr(const struct sockaddr *sa, const struct sockaddr *mask, int rflags, int flags)
791bb06da56Schristos {
792bb06da56Schristos 	p_sockaddr(sa, mask, rflags, WID_DST(sa->sa_family), flags);
793bb06da56Schristos }
794bb06da56Schristos 
795bb06da56Schristos void
p_gwaddr(const struct sockaddr * sa,int gwaf,int flags)796bb06da56Schristos p_gwaddr(const struct sockaddr *sa, int gwaf, int flags)
797bb06da56Schristos {
798bb06da56Schristos 	p_sockaddr(sa, 0, RTF_HOST, WID_GW(gwaf), flags);
799bb06da56Schristos }
800