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