1 /* $NetBSD: rtutil.c,v 1.6 2015/03/23 18:33:17 roy Exp $ */
2 /* $OpenBSD: show.c,v 1.1 2006/05/27 19:16:37 claudio Exp $ */
5 * Copyright (c) 1983, 1988, 1993
6 * The Regents of the University of California. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include <sys/param.h>
34 #include <sys/protosw.h>
35 #include <sys/socket.h>
37 #include <sys/sysctl.h>
40 #include <net/if_dl.h>
41 #include <net/if_types.h>
42 #include <net/pfvar.h>
43 #include <net/pfkeyv2.h>
44 #include <net/route.h>
45 #include <netinet/in.h>
46 #include <netinet/if_ether.h>
47 #include <netatalk/at.h>
48 #include <netmpls/mpls.h>
49 #include <arpa/inet.h>
64 #define PLEN (LONG_BIT / 4 + 2)
65 #define PFKEYV2_CHUNK sizeof(u_int64_t)
66 static char *link_print(const struct sockaddr
*);
69 * Definitions for showing gateway flags.
75 static const struct bits bits
[] = {
80 { RTF_BLACKHOLE
, 'B' },
82 { RTF_MODIFIED
, 'M' },
83 { RTF_DONE
, 'd' }, /* Completed -- for routing messages only */
84 { RTF_MASK
, 'm' }, /* Mask Present -- for routing messages only */
86 { RTF_XRESOLVE
, 'X' },
91 /* { RTF_PROTO3, '3' }, */
93 /* { RTF_JUMBO, 'J' }, */
94 { RTF_ANNOUNCE
, 'p' },
96 { RTF_BROADCAST
, 'b'},
101 static void p_tag(const struct sockaddr
*sa
);
103 static void p_rtentry(struct rt_msghdr
*, int, int);
106 * Print routing tables.
109 p_rttables(int paf
, int flags
, int pflags
, int interesting
)
111 struct rt_msghdr
*rtm
;
112 char *buf
= NULL
, *next
, *lim
= NULL
;
121 mib
[4] = NET_RT_DUMP
;
123 if (prog_sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
124 err(1, "route-sysctl-estimate");
126 if ((buf
= malloc(needed
)) == 0)
128 if (prog_sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0)
129 err(1, "sysctl of routing table");
133 printf("Routing tables\n");
136 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
137 rtm
= (struct rt_msghdr
*)next
;
138 sa
= (struct sockaddr
*)(rtm
+ 1);
139 if ((rtm
->rtm_flags
& pflags
) != pflags
)
141 if (paf
!= AF_UNSPEC
&& sa
->sa_family
!= paf
)
143 p_rtentry(rtm
, flags
, interesting
);
149 if (paf
!= 0 && paf
!= PF_KEY
)
156 mib
[3] = NET_KEY_SPD_DUMP
;
159 if (prog_sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) == -1) {
160 if (errno
== ENOPROTOOPT
)
162 err(1, "spd-sysctl-estimate");
165 if ((buf
= malloc(needed
)) == 0)
167 if (prog_sysctl(mib
, 4, buf
, &needed
, NULL
, 0) == -1)
168 err(1,"sysctl of spd");
173 printf("\nEncap:\n");
175 for (next
= buf
; next
< lim
; next
+= msg
->sadb_msg_len
*
177 msg
= (struct sadb_msg
*)next
;
178 if (msg
->sadb_msg_len
== 0)
189 * column widths; each followed by one space
190 * width of destination/gateway column
191 * strlen("fe80::aaaa:bbbb:cccc:dddd@gif0") == 30, strlen("/128") == 4 = 34
192 * strlen("aaaa:bbbb:cccc:dddd:eeee:ffff:gggg:hhhh") == 39
195 #define WID_DST(af) 18 /* width of destination column */
196 #define WID_GW(af) 18 /* width of gateway column */
198 #define WID_DST(af) ((af) == AF_INET6 ? ((flags & RT_NFLAG) ? 39 : 18) : 18)
199 #define WID_GW(af) ((af) == AF_INET6 ? ((flags & RT_NFLAG) ? 30 : 18) : 18)
203 * Print header for routing table columns.
206 p_rthdr(int paf
, int flags
)
209 if (flags
& RT_AFLAG
)
210 printf("%-*.*s ", PLEN
, PLEN
, "Address");
212 printf("%-18s %-5s %-18s %-5s %-5s %-22s\n",
213 "Source", "Port", "Destination",
214 "Port", "Proto", "SA(Address/Proto/Type/Direction)");
217 if (flags
& RT_TFLAG
) {
218 printf("%-*.*s %-*.*s %-6.6s %6.6s %8.8s %6.6s %7.7s"
219 " %s\n", WID_DST(paf
), WID_DST(paf
), "Destination",
220 WID_GW(paf
), WID_GW(paf
), "Gateway",
221 "Flags", "Refs", "Use", "Mtu", "Tag", "Interface");
226 printf("%-*.*s %-*.*s %-6.6s %6.6s %8.8s %6.6s %s\n",
227 WID_DST(paf
), WID_DST(paf
), "Destination",
228 WID_GW(paf
), WID_GW(paf
), "Gateway",
229 "Flags", "Refs", "Use", "Mtu", "Interface");
231 printf("%-*.*s %-*.*s %-6.6s\n",
232 WID_DST(paf
), WID_DST(paf
), "Destination",
233 WID_GW(paf
), WID_GW(paf
), "Gateway",
239 get_rtaddrs(int addrs
, struct sockaddr
*sa
, struct sockaddr
**rti_info
)
243 for (i
= 0; i
< RTAX_MAX
; i
++) {
244 if (addrs
& (1 << i
)) {
246 sa
= (struct sockaddr
*)((char *)(sa
) +
247 RT_ROUNDUP(sa
->sa_len
));
254 * Print a routing table entry.
257 p_rtentry(struct rt_msghdr
*rtm
, int flags
, int interesting
)
259 static int old_af
= -1;
260 struct sockaddr
*sa
= (struct sockaddr
*)(rtm
+ 1);
261 struct sockaddr
*mask
, *rti_info
[RTAX_MAX
];
263 char ifbuf
[IF_NAMESIZE
];
266 if ((flags
& RT_LFLAG
) && (rtm
->rtm_flags
& RTF_LLINFO
))
269 if (old_af
!= sa
->sa_family
) {
270 old_af
= sa
->sa_family
;
271 p_family(sa
->sa_family
);
272 p_rthdr(sa
->sa_family
, flags
);
274 get_rtaddrs(rtm
->rtm_addrs
, sa
, rti_info
);
276 mask
= rti_info
[RTAX_NETMASK
];
277 if ((sa
= rti_info
[RTAX_DST
]) == NULL
)
280 p_sockaddr(sa
, mask
, rtm
->rtm_flags
, WID_DST(sa
->sa_family
), flags
);
281 p_sockaddr(rti_info
[RTAX_GATEWAY
], NULL
, RTF_HOST
,
282 WID_GW(sa
->sa_family
), flags
);
283 p_flags(rtm
->rtm_flags
& interesting
);
285 printf("%6d %8"PRId64
" ", (int)rtm
->rtm_rmx
.rmx_refcnt
,
286 rtm
->rtm_rmx
.rmx_pksent
);
288 printf("%6s %8s ", "-", "-");
291 if (rtm
->rtm_rmx
.rmx_mtu
)
292 printf("%6"PRId64
, rtm
->rtm_rmx
.rmx_mtu
);
295 putchar((rtm
->rtm_rmx
.rmx_locks
& RTV_MTU
) ? 'L' : ' ');
296 if (flags
& RT_TFLAG
)
297 p_tag(rti_info
[RTAX_TAG
]);
298 printf(" %.16s", if_indextoname(rtm
->rtm_index
, ifbuf
));
300 if (flags
& RT_VFLAG
)
301 p_rtrmx(&rtm
->rtm_rmx
);
306 * Print address family header before a section of the routing table.
319 afname
= "Internet6";
326 afname
= "AppleTalk";
338 printf("\n%s:\n", afname
);
340 printf("\nProtocol Family %d:\n", paf
);
344 p_sockaddr(const struct sockaddr
*sa
, const struct sockaddr
*mask
, int rflags
,
345 int width
, int flags
)
349 switch (sa
->sa_family
) {
353 struct sockaddr_in6 sa6
= *(const struct sockaddr_in6
*)sa
;
355 inet6_getscopeid(&sa6
, INET6_IS_ADDR_LINKLOCAL
|
356 INET6_IS_ADDR_MC_LINKLOCAL
);
357 if (rflags
& RTF_HOST
)
358 cp
= routename((const struct sockaddr
*)&sa6
, flags
);
360 cp
= netname((const struct sockaddr
*)&sa6
, mask
, flags
);
365 if ((rflags
& RTF_HOST
) || mask
== NULL
)
366 cp
= routename(sa
, flags
);
368 cp
= netname(sa
, mask
, flags
);
374 if (flags
& RT_NFLAG
)
375 printf("%-*s ", width
, cp
);
377 printf("%-*.*s ", width
, width
, cp
);
384 char name
[33], *flags
;
385 const struct bits
*p
= bits
;
387 for (flags
= name
; p
->b_mask
&& flags
< &name
[sizeof(name
) - 2]; p
++)
391 printf("%-6.6s ", name
);
396 p_rtrmx(const struct rt_metrics
*rmx
)
398 printf("\texpire %10"PRId64
"%c recvpipe %10"PRIu64
"%c "
399 "sendpipe %10"PRIu64
"%c\n",
400 (int64_t)rmx
->rmx_expire
,
401 (rmx
->rmx_locks
& RTV_EXPIRE
) ? 'L' : ' ', rmx
->rmx_recvpipe
,
402 (rmx
->rmx_locks
& RTV_RPIPE
) ? 'L' : ' ', rmx
->rmx_sendpipe
,
403 (rmx
->rmx_locks
& RTV_SPIPE
) ? 'L' : ' ');
404 printf("\tssthresh %10"PRIu64
"%c rtt %10"PRIu64
"%c "
405 "rttvar %10"PRIu64
"%c\n", rmx
->rmx_ssthresh
,
406 (rmx
->rmx_locks
& RTV_SSTHRESH
) ? 'L' : ' ',
407 rmx
->rmx_rtt
, (rmx
->rmx_locks
& RTV_RTT
) ? 'L' : ' ',
408 rmx
->rmx_rttvar
, (rmx
->rmx_locks
& RTV_RTTVAR
) ? 'L' : ' ');
409 printf("\thopcount %10"PRIu64
"%c\n",
410 rmx
->rmx_hopcount
, (rmx
->rmx_locks
& RTV_HOPCOUNT
) ? 'L' : ' ');
414 p_tag(const struct sockaddr
*sa
)
418 if (sa
== NULL
|| sa
->sa_family
!= AF_MPLS
) {
422 line
= mpls_ntoa(sa
);
423 if (strlen(line
) < 7)
430 static char line
[MAXHOSTNAMELEN
];
431 static char domain
[MAXHOSTNAMELEN
];
434 routename(const struct sockaddr
*sa
, int flags
)
437 static int first
= 1;
441 if (gethostname(domain
, sizeof(domain
)) == 0 &&
442 (cp
= strchr(domain
, '.')))
443 (void)strlcpy(domain
, cp
+ 1, sizeof(domain
));
449 if (sa
->sa_len
== 0) {
450 (void)strlcpy(line
, "default", sizeof(line
));
454 switch (sa
->sa_family
) {
457 ((const struct sockaddr_in
*)sa
)->sin_addr
.s_addr
,
462 struct sockaddr_in6 sin6
;
464 memset(&sin6
, 0, sizeof(sin6
));
465 memcpy(&sin6
, sa
, sa
->sa_len
);
466 sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
467 sin6
.sin6_family
= AF_INET6
;
468 if (sa
->sa_len
== sizeof(struct sockaddr_in6
))
471 * Local MINIX3 fix for a NetBSD issue: inet6_getscopeid()
472 * is sometimes called twice in a row when printing routing
473 * tables, discarding the scope ID the second time..
475 if (sin6
.sin6_scope_id
== 0)
476 #endif /* defined(__minix) */
477 inet6_getscopeid(&sin6
, INET6_IS_ADDR_LINKLOCAL
|
478 INET6_IS_ADDR_MC_LINKLOCAL
);
479 return routename6(&sin6
, flags
);
483 return link_print(sa
);
487 return mpls_ntoa(sa
);
490 (void)snprintf(line
, sizeof(line
), "atalk %d.%d",
491 ((const struct sockaddr_at
*)sa
)->sat_addr
.s_net
,
492 ((const struct sockaddr_at
*)sa
)->sat_addr
.s_node
);
498 if (sa
->sa_len
== sizeof(struct sockaddr_rtlabel
)) {
499 static char name
[RTLABEL_LEN
];
500 struct sockaddr_rtlabel
*sr
;
502 sr
= (struct sockaddr_rtlabel
*)sa
;
503 strlcpy(name
, sr
->sr_label
, sizeof(name
));
509 (void)snprintf(line
, sizeof(line
), "(%d) %s",
510 sa
->sa_family
, any_ntoa(sa
));
517 routename4(in_addr_t in
, int flags
)
519 const char *cp
= NULL
;
523 if (in
== INADDR_ANY
)
525 if (!cp
&& (flags
& RT_NFLAG
) == 0) {
526 if ((hp
= gethostbyaddr((char *)&in
,
527 sizeof(in
), AF_INET
)) != NULL
) {
529 if ((p
= strchr(hp
->h_name
, '.')) &&
530 !strcmp(p
+ 1, domain
))
536 strlcpy(line
, cp
? cp
: inet_ntoa(ina
), sizeof(line
));
543 routename6(const struct sockaddr_in6
*sin6
, int flags
)
547 if ((flags
& RT_NFLAG
))
548 niflags
|= NI_NUMERICHOST
;
550 niflags
|= NI_NOFQDN
;
552 if (getnameinfo((const struct sockaddr
*)sin6
, sin6
->sin6_len
,
553 line
, sizeof(line
), NULL
, 0, niflags
) != 0)
554 strncpy(line
, "invalid", sizeof(line
));
561 * Return the name of the network whose address is given.
562 * The address is assumed to be that of a net or subnet, not a host.
565 netname4(const struct sockaddr_in
* sa4
, const struct sockaddr_in
*mask
, int flags
)
567 const char *cp
= NULL
;
568 struct netent
*np
= NULL
;
570 in_addr_t in
= sa4
->sin_addr
.s_addr
;
573 in_addr_t m
= mask
->sin_addr
.s_addr
;
575 mbits
= m
? 33 - ffs(m
) : 0;
580 if (in
== INADDR_ANY
&& !mbits
)
582 else if (!(flags
& RT_NFLAG
) && in
!= INADDR_ANY
) {
583 if ((np
= getnetbyaddr(in
, AF_INET
)) != NULL
)
587 strlcpy(line
, cp
, sizeof(line
));
588 #define C(x) ((x) & 0xff)
590 snprintf(line
, sizeof(line
), "%u/%d", C(in
>> 24), mbits
);
592 snprintf(line
, sizeof(line
), "%u.%u/%d",
593 C(in
>> 24) , C(in
>> 16), mbits
);
595 snprintf(line
, sizeof(line
), "%u.%u.%u/%d",
596 C(in
>> 24), C(in
>> 16), C(in
>> 8), mbits
);
598 snprintf(line
, sizeof(line
), "%u.%u.%u.%u/%d", C(in
>> 24),
599 C(in
>> 16), C(in
>> 8), C(in
), mbits
);
606 netname6(const struct sockaddr_in6
*sa6
, const struct sockaddr_in6
*mask
, int flags
)
608 struct sockaddr_in6 sin6
;
610 int masklen
, final
= 0, illegal
= 0;
611 int i
, lim
, flag
, error
;
612 char hbuf
[NI_MAXHOST
];
619 lim
= mask
->sin6_len
- offsetof(struct sockaddr_in6
, sin6_addr
);
622 else if (lim
> (int)sizeof(struct in6_addr
))
623 lim
= sizeof(struct in6_addr
);
624 for (p
= (const u_char
*)&mask
->sin6_addr
, i
= 0; i
< lim
; p
++) {
627 sin6
.sin6_addr
.s6_addr
[i
++] = 0x00;
673 sin6
.sin6_addr
.s6_addr
[i
++] &= *p
;
675 sin6
.sin6_addr
.s6_addr
[i
++] = 0x00;
677 while (i
< (int)sizeof(struct in6_addr
))
678 sin6
.sin6_addr
.s6_addr
[i
++] = 0x00;
682 if (masklen
== 0 && IN6_IS_ADDR_UNSPECIFIED(&sin6
.sin6_addr
)) {
683 snprintf(line
, sizeof(line
), "default");
688 warnx("illegal prefixlen");
690 if (flags
& RT_NFLAG
)
691 flag
|= NI_NUMERICHOST
;
692 error
= getnameinfo((struct sockaddr
*)&sin6
, sin6
.sin6_len
,
693 hbuf
, sizeof(hbuf
), NULL
, 0, flag
);
695 snprintf(hbuf
, sizeof(hbuf
), "invalid");
697 snprintf(line
, sizeof(line
), "%s/%d", hbuf
, masklen
);
703 * Return the name of the network whose address is given.
704 * The address is assumed to be that of a net or subnet, not a host.
707 netname(const struct sockaddr
*sa
, const struct sockaddr
*mask
, int flags
)
709 switch (sa
->sa_family
) {
712 return netname4((const struct sockaddr_in
*)sa
,
713 (const struct sockaddr_in
*)mask
, flags
);
716 return netname6((const struct sockaddr_in6
*)sa
,
717 (const struct sockaddr_in6
*)mask
, flags
);
720 return link_print(sa
);
722 snprintf(line
, sizeof(line
), "af %d: %s",
723 sa
->sa_family
, any_ntoa(sa
));
729 static const char hexlist
[] = "0123456789abcdef";
732 any_ntoa(const struct sockaddr
*sa
)
734 static char obuf
[240];
735 const char *in
= sa
->sa_data
;
737 int len
= sa
->sa_len
- offsetof(struct sockaddr
, sa_data
);
741 *out
++ = hexlist
[(*in
>> 4) & 15];
742 *out
++ = hexlist
[(*in
++) & 15];
744 } while (--len
> 0 && (out
+ 3) < &obuf
[sizeof(obuf
) - 1]);
750 link_print(const struct sockaddr
*sa
)
752 const struct sockaddr_dl
*sdl
= (const struct sockaddr_dl
*)sa
;
753 const u_char
*lla
= (const u_char
*)sdl
->sdl_data
+ sdl
->sdl_nlen
;
755 if (sdl
->sdl_nlen
== 0 && sdl
->sdl_alen
== 0 &&
756 sdl
->sdl_slen
== 0) {
757 (void)snprintf(line
, sizeof(line
), "link#%d", sdl
->sdl_index
);
760 switch (sdl
->sdl_type
) {
763 return ether_ntoa((const struct ether_addr
*)lla
);
765 return link_ntoa(sdl
);
771 mpls_ntoa(const struct sockaddr
*sa
)
773 static char obuf
[16];
775 const union mpls_shim
*pms
;
777 int psize
= sizeof(struct sockaddr_mpls
);
779 pms
= &((const struct sockaddr_mpls
*)sa
)->smpls_addr
;
780 ms
.s_addr
= ntohl(pms
->s_addr
);
782 snprintf(obuf
, sizeof(obuf
), "%u", ms
.shim
.label
);
784 while(psize
< sa
->sa_len
) {
786 ms
.s_addr
= ntohl(pms
->s_addr
);
788 snprintf(obuf
+ olen
, sizeof(obuf
) - olen
, ",%u",
797 p_addr(const struct sockaddr
*sa
, const struct sockaddr
*mask
, int rflags
, int flags
)
799 p_sockaddr(sa
, mask
, rflags
, WID_DST(sa
->sa_family
), flags
);
803 p_gwaddr(const struct sockaddr
*sa
, int gwaf
, int flags
)
805 p_sockaddr(sa
, 0, RTF_HOST
, WID_GW(gwaf
), flags
);