1 /* $NetBSD: route.c,v 1.151 2015/03/23 18:33:17 roy Exp $ */
4 * Copyright (c) 1983, 1989, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1991, 1993\
35 The Regents of the University of California. All rights reserved.");
40 static char sccsid
[] = "@(#)route.c 8.6 (Berkeley) 4/28/95";
42 __RCSID("$NetBSD: route.c,v 1.151 2015/03/23 18:33:17 roy Exp $");
46 #include <sys/param.h>
48 #include <sys/socket.h>
49 #include <sys/ioctl.h>
51 #include <sys/sysctl.h>
54 #include <net/route.h>
55 #include <net/if_dl.h>
56 #include <net80211/ieee80211_netbsd.h>
57 #include <netinet/in.h>
58 #include <netatalk/at.h>
59 #include <netmpls/mpls.h>
60 #include <arpa/inet.h>
80 struct sockaddr_in sin
;
82 struct sockaddr_in6 sin6
;
84 struct sockaddr_at sat
;
85 struct sockaddr_dl sdl
;
87 struct sockaddr_mpls smpls
;
89 struct sockaddr_storage sstorage
;
92 typedef union sockunion
*sup
;
95 union sockunion
*so_dst
, *so_gate
, *so_mask
, *so_genmask
, *so_ifa
,
99 static const char *route_strerror(int);
100 static void set_metric(const char *, int);
101 static int newroute(int, char *const *);
102 static void inet_makenetandmask(u_int32_t
, struct sockaddr_in
*, struct sou
*);
104 static int inet6_makenetandmask(const struct sockaddr_in6
*, struct sou
*);
106 static int getaddr(int, const char *, struct hostent
**, struct sou
*);
107 static int flushroutes(int, char *const [], int);
108 static char *netmask_string(const struct sockaddr
*, int, int);
109 static int prefixlen(const char *, struct sou
*);
111 static void interfaces(void);
112 __dead
static void monitor(void);
113 static int print_getmsg(struct rt_msghdr
*, int, struct sou
*);
114 static const char *linkstate(struct if_msghdr
*);
115 static sup
readtag(sup
, const char *);
116 static void addtag(sup
, const char *, int);
118 static int rtmsg(int, int, struct sou
*);
119 static void mask_addr(struct sou
*);
120 static void print_rtmsg(struct rt_msghdr
*, int);
121 static void pmsg_common(struct rt_msghdr
*);
122 static void pmsg_addrs(const char *, int);
123 static void bprintf(FILE *, int, const char *);
124 static void sodump(sup
, const char *);
125 static void sockaddr(const char *, struct sockaddr
*);
129 int forcehost
, forcenet
, doflush
, af
;
130 int iflag
, Lflag
, nflag
, qflag
, tflag
, Sflag
, Tflag
;
131 int verbose
, aflen
= sizeof(struct sockaddr_in
), rtag
;
132 int locking
, lockrest
, debugonly
, shortoutput
;
133 struct rt_metrics rt_metrics
;
135 short ns_nullh
[] = {0,0,0};
136 short ns_bh
[] = {-1,-1,-1};
138 static const char opts
[] = "dfLnqSsTtv";
141 usage(const char *cp
)
145 warnx("botched keyword: %s", cp
);
146 (void)fprintf(stderr
,
147 "Usage: %s [-%s] cmd [[-<qualifers>] args]\n", getprogname(), opts
);
152 #define PRIETHER "02x:%02x:%02x:%02x:%02x:%02x"
153 #define PRIETHER_ARGS(__enaddr) (__enaddr)[0], (__enaddr)[1], (__enaddr)[2], \
154 (__enaddr)[3], (__enaddr)[4], (__enaddr)[5]
157 main(int argc
, char * const *argv
)
164 while ((ch
= getopt(argc
, argv
, opts
)) != -1)
204 if (prog_init
&& prog_init() == -1)
205 err(1, "init failed");
209 sock
= prog_open("/dev/null", O_WRONLY
, 0);
211 sock
= prog_socket(PF_ROUTE
, SOCK_RAW
, 0);
213 err(EXIT_FAILURE
, "socket");
231 (void)flushroutes(1, argv
, 0);
232 return newroute(argc
, argv
);
235 show(argc
, argv
, Lflag
|nflag
|Tflag
|verbose
);
245 return flushroutes(argc
, argv
, 0);
248 return flushroutes(argc
, argv
, 1);
257 netmask_string(const struct sockaddr
*mask
, int len
, int family
)
259 static char smask
[INET6_ADDRSTRLEN
];
260 struct sockaddr_in nsin
;
261 struct sockaddr_in6 nsin6
;
264 snprintf(smask
, sizeof(smask
), "%d", len
);
268 memset(&nsin
, 0, sizeof(nsin
));
269 memcpy(&nsin
, mask
, mask
->sa_len
);
270 snprintf(smask
, sizeof(smask
), "%s",
271 inet_ntoa(nsin
.sin_addr
));
274 memset(&nsin6
, 0, sizeof(nsin6
));
275 memcpy(&nsin6
, mask
, mask
->sa_len
);
276 inet_ntop(family
, &nsin6
.sin6_addr
, smask
,
280 snprintf(smask
, sizeof(smask
), "%s", any_ntoa(mask
));
287 * Purge all entries in the routing tables not
288 * associated with network interfaces.
291 flushroutes(int argc
, char * const argv
[], int doall
)
295 int flags
, mib
[6], rlen
, seqno
;
296 char *buf
, *next
, *lim
;
298 struct rt_msghdr
*rtm
;
302 /* Don't want to read back our messages */
303 prog_shutdown(sock
, SHUT_RD
);
304 parse_show_opts(argc
, argv
, &af
, &flags
, &afname
, false);
307 mib
[2] = 0; /* protocol */
308 mib
[3] = 0; /* wildcard address family */
309 mib
[4] = NET_RT_DUMP
;
310 mib
[5] = 0; /* no flags */
311 if (prog_sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
312 err(EXIT_FAILURE
, "route-sysctl-estimate");
315 if ((buf
= malloc(needed
)) == NULL
)
316 err(EXIT_FAILURE
, "malloc");
317 if (prog_sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0)
318 err(EXIT_FAILURE
, "actual retrieval of routing table");
322 (void)printf("Examining routing table from sysctl\n");
324 printf("(address family %s)\n", afname
);
329 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
330 rtm
= (struct rt_msghdr
*)next
;
331 sa
= (struct sockaddr
*)(rtm
+ 1);
333 print_rtmsg(rtm
, rtm
->rtm_msglen
);
334 if ((rtm
->rtm_flags
& flags
) != flags
)
336 if (!(rtm
->rtm_flags
& (RTF_GATEWAY
| RTF_STATIC
|
337 RTF_LLINFO
)) && !doall
)
341 * MINIX3 only: routes with the RTF_LOCAL flag are immutable,
342 * so do not try to delete them.
344 if (rtm
->rtm_flags
& RTF_LOCAL
)
346 #endif /* defined(__minix) */
347 if (af
!= AF_UNSPEC
&& sa
->sa_family
!= af
)
351 rtm
->rtm_type
= RTM_DELETE
;
352 rtm
->rtm_seq
= seqno
;
353 if ((rlen
= prog_write(sock
, next
,
354 rtm
->rtm_msglen
)) < 0) {
355 warnx("writing to routing socket: %s",
356 route_strerror(errno
));
359 if (rlen
< (int)rtm
->rtm_msglen
) {
360 warnx("write to routing socket, got %d for rlen", rlen
);
367 print_rtmsg(rtm
, rlen
);
369 (void)printf("%-20.20s ", netname(sa
, NULL
, nflag
));
370 sa
= (struct sockaddr
*)(RT_ROUNDUP(sa
->sa_len
) +
372 (void)printf("%-20.20s ", routename(sa
, nflag
));
373 (void)printf("done\n");
381 route_strerror(int error
)
386 return "not in table";
388 return "entry in use";
390 return "routing table overflow";
392 return strerror(error
);
397 set_metric(const char *value
, int key
)
400 uint64_t noval
, *valp
= &noval
;
403 #define caseof(x, y, z) \
404 case x: valp = (uint64_t *)&rt_metrics.z; flag = y; break
405 caseof(K_MTU
, RTV_MTU
, rmx_mtu
);
406 caseof(K_HOPCOUNT
, RTV_HOPCOUNT
, rmx_hopcount
);
407 caseof(K_EXPIRE
, RTV_EXPIRE
, rmx_expire
);
408 caseof(K_RECVPIPE
, RTV_RPIPE
, rmx_recvpipe
);
409 caseof(K_SENDPIPE
, RTV_SPIPE
, rmx_sendpipe
);
410 caseof(K_SSTHRESH
, RTV_SSTHRESH
, rmx_ssthresh
);
411 caseof(K_RTT
, RTV_RTT
, rmx_rtt
);
412 caseof(K_RTTVAR
, RTV_RTTVAR
, rmx_rttvar
);
415 if (lockrest
|| locking
)
416 rt_metrics
.rmx_locks
|= flag
;
419 *valp
= strtoul(value
, NULL
, 0);
423 newroute(int argc
, char *const *argv
)
425 const char *cmd
, *dest
= "", *gateway
= "";
426 int ishost
= 0, ret
, attempts
, oerrno
, flags
= RTF_STATIC
;
428 struct hostent
*hp
= 0;
429 struct sou sou
, *soup
= &sou
;
431 sou
.so_dst
= calloc(1, sizeof(union sockunion
));
432 sou
.so_gate
= calloc(1, sizeof(union sockunion
));
433 sou
.so_mask
= calloc(1, sizeof(union sockunion
));
434 sou
.so_genmask
= calloc(1, sizeof(union sockunion
));
435 sou
.so_ifa
= calloc(1, sizeof(union sockunion
));
436 sou
.so_ifp
= calloc(1, sizeof(union sockunion
));
437 sou
.so_mpls
= calloc(1, sizeof(union sockunion
));
439 if (sou
.so_dst
== NULL
|| sou
.so_gate
== NULL
|| sou
.so_mask
== NULL
||
440 sou
.so_genmask
== NULL
|| sou
.so_ifa
== NULL
|| sou
.so_ifp
== NULL
||
442 errx(EXIT_FAILURE
, "Cannot allocate memory");
447 /* Don't want to read back our messages */
448 prog_shutdown(sock
, SHUT_RD
);
451 if (**(++argv
)== '-') {
452 switch (key
= keyword(1 + *argv
)) {
456 aflen
= sizeof(union sockunion
);
462 aflen
= sizeof(struct sockaddr_at
);
468 aflen
= sizeof(struct sockaddr_in
);
474 aflen
= sizeof(struct sockaddr_in6
);
480 aflen
= sizeof(struct sockaddr_dl
);
486 aflen
= sizeof(struct sockaddr_mpls
);
492 aflen
= sizeof(struct sockaddr_mpls
);
493 (void)getaddr(RTA_TAG
, *++argv
, 0, soup
);
502 flags
&= ~RTF_STATIC
;
520 flags
&= ~RTF_REJECT
;
523 flags
|= RTF_BLACKHOLE
;
526 flags
&= ~RTF_BLACKHOLE
;
532 flags
&= ~RTF_CLONED
;
541 flags
|= RTF_ANNOUNCE
;
544 flags
|= RTF_CLONING
;
547 flags
&= ~RTF_CLONING
;
550 flags
|= RTF_XRESOLVE
;
558 (void)getaddr(RTA_IFA
, *++argv
, 0, soup
);
563 (void)getaddr(RTA_IFP
, *++argv
, 0, soup
);
568 (void)getaddr(RTA_GENMASK
, *++argv
, 0, soup
);
573 (void)getaddr(RTA_GATEWAY
, *++argv
, 0, soup
);
578 ishost
= getaddr(RTA_DST
, *++argv
, &hp
, soup
);
584 (void)getaddr(RTA_NETMASK
, *++argv
, 0, soup
);
592 ishost
= prefixlen(*++argv
, soup
);
604 set_metric(*++argv
, key
);
610 if ((rtm_addrs
& RTA_DST
) == 0) {
612 ishost
= getaddr(RTA_DST
, *argv
, &hp
, soup
);
613 } else if ((rtm_addrs
& RTA_GATEWAY
) == 0) {
615 (void)getaddr(RTA_GATEWAY
, *argv
, &hp
, soup
);
620 if (strcmp(*argv
, "0") == 0) {
623 "old usage of trailing 0",
624 "assuming route to if");
630 } else if (ret
> 0 && ret
< 10) {
633 "old usage of trailing digit",
634 "assuming route via gateway");
639 (void)getaddr(RTA_NETMASK
, *argv
, 0, soup
);
643 if ((rtm_addrs
& RTA_DST
) == 0)
644 errx(EXIT_FAILURE
, "missing destination specification");
645 if (*cmd
== 'a' && (rtm_addrs
& RTA_GATEWAY
) == 0)
646 errx(EXIT_FAILURE
, "missing gateway specification");
647 if (forcehost
&& forcenet
)
648 errx(EXIT_FAILURE
, "-host and -net conflict");
657 flags
|= RTF_GATEWAY
;
658 for (attempts
= 1; ; attempts
++) {
660 if ((ret
= rtmsg(*cmd
, flags
, soup
)) == 0)
662 if (errno
!= ENETUNREACH
&& errno
!= ESRCH
)
664 if (af
== AF_INET
&& *gateway
&& hp
&& hp
->h_addr_list
[1]) {
666 memmove(&soup
->so_gate
->sin
.sin_addr
, hp
->h_addr_list
[0],
675 (void)printf("%s %s %s", cmd
, ishost
? "host" : "net", dest
);
677 (void)printf(": gateway %s", gateway
);
678 if (attempts
> 1 && ret
== 0 && af
== AF_INET
)
679 (void)printf(" (%s)",
680 inet_ntoa(soup
->so_gate
->sin
.sin_addr
));
685 (void)printf(": %s\n", route_strerror(oerrno
));
690 free(sou
.so_genmask
);
699 inet_makenetandmask(const u_int32_t net
, struct sockaddr_in
* const isin
,
702 struct sockaddr_in
*sin
;
703 u_int32_t addr
, mask
= 0;
706 rtm_addrs
|= RTA_NETMASK
;
709 else if (net
< 128) {
710 addr
= net
<< IN_CLASSA_NSHIFT
;
711 mask
= IN_CLASSA_NET
;
712 } else if (net
< 192) {
713 addr
= net
<< IN_CLASSA_NSHIFT
;
714 mask
= IN_CLASSB_NET
;
715 } else if (net
< 224) {
716 addr
= net
<< IN_CLASSA_NSHIFT
;
717 mask
= IN_CLASSC_NET
;
718 } else if (net
< 256) {
719 addr
= net
<< IN_CLASSA_NSHIFT
;
720 mask
= IN_CLASSD_NET
;
721 } else if (net
< 49152) { /* 192 * 256 */
722 addr
= net
<< IN_CLASSB_NSHIFT
;
723 mask
= IN_CLASSB_NET
;
724 } else if (net
< 57344) { /* 224 * 256 */
725 addr
= net
<< IN_CLASSB_NSHIFT
;
726 mask
= IN_CLASSC_NET
;
727 } else if (net
< 65536) {
728 addr
= net
<< IN_CLASSB_NSHIFT
;
729 mask
= IN_CLASSB_NET
;
730 } else if (net
< 14680064L) { /* 224 * 65536 */
731 addr
= net
<< IN_CLASSC_NSHIFT
;
732 mask
= IN_CLASSC_NET
;
733 } else if (net
< 16777216L) {
734 addr
= net
<< IN_CLASSC_NSHIFT
;
735 mask
= IN_CLASSD_NET
;
738 if ((addr
& IN_CLASSA_HOST
) == 0)
739 mask
= IN_CLASSA_NET
;
740 else if ((addr
& IN_CLASSB_HOST
) == 0)
741 mask
= IN_CLASSB_NET
;
742 else if ((addr
& IN_CLASSC_HOST
) == 0)
743 mask
= IN_CLASSC_NET
;
747 isin
->sin_addr
.s_addr
= htonl(addr
);
748 sin
= &soup
->so_mask
->sin
;
749 sin
->sin_addr
.s_addr
= htonl(mask
);
752 cp
= (char *)(&sin
->sin_addr
+ 1);
753 while (*--cp
== 0 && cp
> (char *)sin
)
755 sin
->sin_len
= 1 + cp
- (char *)sin
;
756 sin
->sin_family
= AF_INET
;
761 * XXX the function may need more improvement...
764 inet6_makenetandmask(const struct sockaddr_in6
* const sin6
, struct sou
*soup
)
770 if (IN6_IS_ADDR_UNSPECIFIED(&sin6
->sin6_addr
) &&
771 sin6
->sin6_scope_id
== 0) {
773 } else if ((sin6
->sin6_addr
.s6_addr
[0] & 0xe0) == 0x20) {
774 /* aggregatable global unicast - RFC2374 */
775 memset(&in6
, 0, sizeof(in6
));
776 if (!memcmp(&sin6
->sin6_addr
.s6_addr
[8], &in6
.s6_addr
[8], 8))
780 if (!plen
|| strcmp(plen
, "128") == 0)
783 rtm_addrs
|= RTA_NETMASK
;
784 (void)prefixlen(plen
, soup
);
791 * Interpret an argument as a network address of some kind,
792 * returning 1 if a host address, 0 if a network address.
795 getaddr(int which
, const char *s
, struct hostent
**hpp
, struct sou
*soup
)
802 int afamily
; /* local copy of af so we can change it */
804 if (af
== AF_UNSPEC
) {
806 aflen
= sizeof(struct sockaddr_in
);
821 su
= soup
->so_genmask
;
829 su
->sa
.sa_family
= af
;
839 usage("Internal Error");
842 su
->sa
.sa_len
= aflen
;
843 su
->sa
.sa_family
= afamily
; /* cases that don't want it have left already */
844 if (strcmp(s
, "default") == 0) {
848 (void)getaddr(RTA_NETMASK
, s
, 0, soup
);
860 struct addrinfo hints
, *res
;
863 if (which
== RTA_DST
&& (slash
= (strrchr(s
, '/'))) != 0)
865 memset(&hints
, 0, sizeof(hints
));
866 hints
.ai_family
= afamily
; /*AF_INET6*/
867 hints
.ai_flags
= AI_NUMERICHOST
;
868 hints
.ai_socktype
= SOCK_DGRAM
; /*dummy*/
869 if (getaddrinfo(s
, "0", &hints
, &res
) != 0) {
875 if (getaddrinfo(s
, "0", &hints
, &res
) != 0)
876 errx(EXIT_FAILURE
, "%s: bad value", s
);
880 if (sizeof(su
->sin6
) != res
->ai_addrlen
)
881 errx(EXIT_FAILURE
, "%s: bad value", s
);
884 "%s: address resolved to multiple values", s
);
886 memcpy(&su
->sin6
, res
->ai_addr
, sizeof(su
->sin6
));
888 inet6_putscopeid(&su
->sin6
, INET6_IS_ADDR_LINKLOCAL
|
889 INET6_IS_ADDR_MC_LINKLOCAL
);
890 if (hints
.ai_flags
== AI_NUMERICHOST
) {
892 return prefixlen(slash
+ 1, soup
);
893 if (which
== RTA_DST
)
894 return inet6_makenetandmask(&su
->sin6
, soup
);
902 su
->sa
.sa_len
= sizeof(*su
);
903 sockaddr(s
, &su
->sa
);
911 errx(EXIT_FAILURE
, "bad address: %s", s
);
916 su
->sat
.sat_addr
.s_net
= val
;
920 su
->sat
.sat_addr
.s_node
= val
;
921 rtm_addrs
|= RTA_NETMASK
;
922 return(forcehost
|| su
->sat
.sat_addr
.s_node
!= 0);
924 if (which
== RTA_DST
)
925 soup
->so_dst
= readtag(su
, s
);
926 else if (which
== RTA_TAG
)
927 soup
->so_mpls
= readtag(su
, s
);
929 errx(EXIT_FAILURE
, "MPLS can be used only as "
935 link_addr(s
, &su
->sdl
);
947 if ((t
= strchr(s
, '/')) != NULL
&& which
== RTA_DST
) {
950 if ((val
= inet_addr(s
)) != INADDR_NONE
) {
951 inet_makenetandmask(htonl(val
), &su
->sin
, soup
);
952 return prefixlen(&t
[1], soup
);
955 if ((val
= inet_network(s
)) != INADDR_NONE
) {
956 inet_makenetandmask(val
, &su
->sin
, soup
);
957 return prefixlen(&t
[1], soup
);
962 if (inet_aton(s
, &su
->sin
.sin_addr
) &&
963 (which
!= RTA_DST
|| forcenet
== 0)) {
964 val
= su
->sin
.sin_addr
.s_addr
;
965 if (inet_lnaof(su
->sin
.sin_addr
) != INADDR_ANY
)
972 if ((val
= inet_network(s
)) != INADDR_NONE
||
973 ((np
= getnetbyname(s
)) != NULL
&& (val
= np
->n_net
) != 0)) {
975 if (which
== RTA_DST
)
976 inet_makenetandmask(val
, &su
->sin
, soup
);
979 hp
= gethostbyname(s
);
982 su
->sin
.sin_family
= hp
->h_addrtype
;
983 memmove(&su
->sin
.sin_addr
, hp
->h_addr
, hp
->h_length
);
986 errx(EXIT_FAILURE
, "%s: bad value", s
);
992 readtag(sup su
, const char *s
)
1000 errx(EXIT_FAILURE
, "%s: Cannot allocate memory", s
);
1002 for (uint i
= 0; i
< strlen(n
); i
++)
1006 #define MPLS_NEW_SIZE (sizeof(struct sockaddr_mpls) + \
1007 mplssize * sizeof(union mpls_shim))
1009 if (mplssize
!= 0 && sizeof(union sockunion
) < MPLS_NEW_SIZE
) {
1011 retsu
= malloc(MPLS_NEW_SIZE
);
1012 retsu
->smpls
.smpls_family
= AF_MPLS
;
1014 retsu
->smpls
.smpls_len
= MPLS_NEW_SIZE
;
1016 while ((p
= strchr(n
, ',')) != NULL
) {
1018 addtag(retsu
, n
, mplssize
);
1022 addtag(retsu
, n
, mplssize
);
1029 addtag(sup su
, const char *s
, int where
)
1031 union mpls_shim
*ms
= &su
->smpls
.smpls_addr
;
1033 if (atoi(s
) < 0 || atoi(s
) >= (1 << 20))
1034 errx(EXIT_FAILURE
, "%s: Bad tag", s
);
1035 ms
[where
].s_addr
= 0;
1036 ms
[where
].shim
.label
= atoi(s
);
1037 ms
[where
].s_addr
= htonl(ms
[where
].s_addr
);
1042 prefixlen(const char *s
, struct sou
*soup
)
1044 int max
, len
= atoi(s
);
1051 max
= sizeof(struct in_addr
) * 8;
1055 max
= sizeof(struct in6_addr
) * 8;
1059 errx(EXIT_FAILURE
, "prefixlen is not supported with af %d", af
);
1063 rtm_addrs
|= RTA_NETMASK
;
1064 if (len
< -1 || len
> max
)
1065 errx(EXIT_FAILURE
, "%s: bad value", s
);
1073 memset(soup
->so_mask
, 0, sizeof(*soup
->so_mask
));
1074 soup
->so_mask
->sin
.sin_family
= AF_INET
;
1075 soup
->so_mask
->sin
.sin_len
= sizeof(struct sockaddr_in
);
1076 soup
->so_mask
->sin
.sin_addr
.s_addr
= (len
== 0 ? 0
1077 : htonl(0xffffffff << (32 - len
)));
1081 soup
->so_mask
->sin6
.sin6_family
= AF_INET6
;
1082 soup
->so_mask
->sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
1083 memset(&soup
->so_mask
->sin6
.sin6_addr
, 0,
1084 sizeof(soup
->so_mask
->sin6
.sin6_addr
));
1086 memset(&soup
->so_mask
->sin6
.sin6_addr
, 0xff, q
);
1088 *((u_char
*)&soup
->so_mask
->sin6
.sin6_addr
+ q
) =
1089 (0xff00 >> r
) & 0xff;
1102 char *buf
, *lim
, *next
;
1103 struct rt_msghdr
*rtm
;
1107 mib
[2] = 0; /* protocol */
1108 mib
[3] = 0; /* wildcard address family */
1109 mib
[4] = NET_RT_IFLIST
;
1110 mib
[5] = 0; /* no flags */
1111 if (prog_sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
1112 err(EXIT_FAILURE
, "route-sysctl-estimate");
1114 if ((buf
= malloc(needed
)) == NULL
)
1115 err(EXIT_FAILURE
, "malloc");
1116 if (prog_sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0) {
1118 "actual retrieval of interface table");
1121 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
1122 rtm
= (struct rt_msghdr
*)next
;
1123 print_rtmsg(rtm
, rtm
->rtm_msglen
);
1135 struct rt_msghdr hdr
;
1145 n
= prog_read(sock
, &u
, sizeof(u
));
1147 (void)printf("got message of size %d on %s", n
, ctime(&now
));
1148 print_rtmsg(&u
.hdr
, n
);
1156 struct rt_msghdr m_rtm
;
1161 rtmsg(int cmd
, int flags
, struct sou
*soup
)
1165 char *cp
= m_rtmsg
.m_space
;
1168 #define NEXTADDR(w, u) \
1169 if (rtm_addrs & (w)) {\
1170 l = RT_ROUNDUP(u->sa.sa_len); memmove(cp, u, l); cp += l;\
1171 if (verbose && ! shortoutput) sodump(u,#u);\
1175 memset(&m_rtmsg
, 0, sizeof(m_rtmsg
));
1178 else if (cmd
== 'c')
1180 else if (cmd
== 'g') {
1185 if (soup
->so_ifp
->sa
.sa_family
== AF_UNSPEC
) {
1186 soup
->so_ifp
->sa
.sa_family
= AF_LINK
;
1187 soup
->so_ifp
->sa
.sa_len
= sizeof(struct sockaddr_dl
);
1188 rtm_addrs
|= RTA_IFP
;
1193 #define rtm m_rtmsg.m_rtm
1195 rtm
.rtm_flags
= flags
;
1196 rtm
.rtm_version
= RTM_VERSION
;
1197 rtm
.rtm_seq
= ++seq
;
1198 rtm
.rtm_addrs
= rtm_addrs
;
1199 rtm
.rtm_rmx
= rt_metrics
;
1200 rtm
.rtm_inits
= rtm_inits
;
1202 if (rtm_addrs
& RTA_NETMASK
)
1204 NEXTADDR(RTA_DST
, soup
->so_dst
);
1205 NEXTADDR(RTA_GATEWAY
, soup
->so_gate
);
1206 NEXTADDR(RTA_NETMASK
, soup
->so_mask
);
1207 NEXTADDR(RTA_GENMASK
, soup
->so_genmask
);
1208 NEXTADDR(RTA_IFP
, soup
->so_ifp
);
1209 NEXTADDR(RTA_IFA
, soup
->so_ifa
);
1211 NEXTADDR(RTA_TAG
, soup
->so_mpls
);
1213 rtm
.rtm_msglen
= l
= cp
- (char *)&m_rtmsg
;
1214 if (verbose
&& ! shortoutput
) {
1217 print_rtmsg(&rtm
, l
);
1221 if ((rlen
= prog_write(sock
, (char *)&m_rtmsg
, l
)) < 0) {
1222 warnx("writing to routing socket: %s", route_strerror(errno
));
1226 warnx("write to routing socket, got %d for rlen", rlen
);
1230 if (cmd
== RTM_GET
) {
1233 (char *)&m_rtmsg
, sizeof(m_rtmsg
));
1234 } while (l
> 0 && (rtm
.rtm_seq
!= seq
|| rtm
.rtm_pid
!= pid
));
1236 err(EXIT_FAILURE
, "read from routing socket");
1238 return print_getmsg(&rtm
, l
, soup
);
1246 mask_addr(struct sou
*soup
)
1248 int olen
= soup
->so_mask
->sa
.sa_len
;
1249 char *cp1
= olen
+ (char *)soup
->so_mask
, *cp2
;
1251 for (soup
->so_mask
->sa
.sa_len
= 0; cp1
> (char *)soup
->so_mask
; )
1253 soup
->so_mask
->sa
.sa_len
= 1 + cp1
- (char *)soup
->so_mask
;
1256 if ((rtm_addrs
& RTA_DST
) == 0)
1258 switch (soup
->so_dst
->sa
.sa_family
) {
1269 cp1
= soup
->so_mask
->sa
.sa_len
+ 1 + (char *)soup
->so_dst
;
1270 cp2
= soup
->so_dst
->sa
.sa_len
+ 1 + (char *)soup
->so_dst
;
1273 cp2
= soup
->so_mask
->sa
.sa_len
+ 1 + (char *)soup
->so_mask
;
1274 while (cp1
> soup
->so_dst
->sa
.sa_data
)
1278 const char * const msgtypes
[] = {
1279 [RTM_ADD
] = "RTM_ADD: Add Route",
1280 [RTM_DELETE
] = "RTM_DELETE: Delete Route",
1281 [RTM_CHANGE
] = "RTM_CHANGE: Change Metrics, Flags or Gateway",
1282 [RTM_GET
] = "RTM_GET: Report Metrics",
1283 [RTM_LOSING
] = "RTM_LOSING: Kernel Suspects Partitioning",
1284 [RTM_REDIRECT
] = "RTM_REDIRECT: Told to use different route",
1285 [RTM_MISS
] = "RTM_MISS: Lookup failed on this address",
1286 [RTM_LOCK
] = "RTM_LOCK: fix specified metrics",
1287 [RTM_OLDADD
] = "RTM_OLDADD: caused by SIOCADDRT",
1288 [RTM_OLDDEL
] = "RTM_OLDDEL: caused by SIOCDELRT",
1289 [RTM_RESOLVE
] = "RTM_RESOLVE: Route created by cloning",
1290 [RTM_NEWADDR
] = "RTM_NEWADDR: address being added to iface",
1291 [RTM_DELADDR
] = "RTM_DELADDR: address being removed from iface",
1292 [RTM_OOIFINFO
] = "RTM_OOIFINFO: iface status change (pre-1.5)",
1293 [RTM_OIFINFO
] = "RTM_OIFINFO: iface status change (pre-64bit time)",
1294 [RTM_IFANNOUNCE
] = "RTM_IFANNOUNCE: iface arrival/departure",
1295 [RTM_IEEE80211
] = "RTM_IEEE80211: IEEE80211 wireless event",
1296 [RTM_IFINFO
] = "RTM_IFINFO: iface status change",
1297 [RTM_CHGADDR
] = "RTM_CHGADDR: address being changed on iface",
1300 const char metricnames
[] =
1301 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
1302 const char routeflags
[] =
1303 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016CLONED\017PROTO2\020PROTO1\023LOCAL\024BROADCAST";
1304 const char ifnetflags
[] =
1305 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2\020MULTICAST";
1306 const char addrnames
[] =
1307 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011TAG";
1312 linkstate(struct if_msghdr
*ifm
)
1314 static char buf
[64];
1316 switch (ifm
->ifm_data
.ifi_link_state
) {
1317 case LINK_STATE_UNKNOWN
:
1318 return "carrier: unknown";
1319 case LINK_STATE_DOWN
:
1320 return "carrier: no carrier";
1322 return "carrier: active";
1324 (void)snprintf(buf
, sizeof(buf
), "carrier: 0x%x",
1325 ifm
->ifm_data
.ifi_link_state
);
1332 print_rtmsg(struct rt_msghdr
*rtm
, int msglen
)
1334 struct if_msghdr
*ifm
;
1335 struct ifa_msghdr
*ifam
;
1336 struct if_announcemsghdr
*ifan
;
1338 struct ieee80211_join_event join
;
1339 struct ieee80211_leave_event leave
;
1340 struct ieee80211_replay_event replay
;
1341 struct ieee80211_michael_event michael
;
1347 if (rtm
->rtm_version
!= RTM_VERSION
) {
1348 (void)printf("routing message version %d not understood\n",
1352 if (msgtypes
[rtm
->rtm_type
])
1353 (void)printf("%s: ", msgtypes
[rtm
->rtm_type
]);
1355 (void)printf("#%d: ", rtm
->rtm_type
);
1356 (void)printf("len %d, ", rtm
->rtm_msglen
);
1357 switch (rtm
->rtm_type
) {
1359 ifm
= (struct if_msghdr
*)rtm
;
1360 (void)printf("if# %d, %s, flags: ", ifm
->ifm_index
,
1367 bprintf(stdout
, ifm
->ifm_flags
, ifnetflags
);
1368 pmsg_addrs((char *)(ifm
+ 1), ifm
->ifm_addrs
);
1373 ifam
= (struct ifa_msghdr
*)rtm
;
1374 (void)printf("metric %d, flags: ", ifam
->ifam_metric
);
1375 bprintf(stdout
, ifam
->ifam_flags
, routeflags
);
1376 pmsg_addrs((char *)(ifam
+ 1), ifam
->ifam_addrs
);
1379 ifan
= (struct if_announcemsghdr
*)rtm
;
1380 (void)printf("if# %d, what: ", ifan
->ifan_index
);
1381 switch (ifan
->ifan_what
) {
1382 case RTM_IEEE80211_ASSOC
:
1383 printf("associate");
1385 case RTM_IEEE80211_REASSOC
:
1386 printf("re-associate");
1388 case RTM_IEEE80211_DISASSOC
:
1389 printf("disassociate");
1391 case RTM_IEEE80211_SCAN
:
1392 printf("scan complete");
1394 case RTM_IEEE80211_JOIN
:
1395 evlen
= sizeof(ev
.join
);
1398 case RTM_IEEE80211_LEAVE
:
1399 evlen
= sizeof(ev
.leave
);
1402 case RTM_IEEE80211_MICHAEL
:
1403 evlen
= sizeof(ev
.michael
);
1406 case RTM_IEEE80211_REPLAY
:
1407 evlen
= sizeof(ev
.replay
);
1412 printf("#%d", ifan
->ifan_what
);
1415 if (sizeof(*ifan
) + evlen
> ifan
->ifan_msglen
) {
1416 printf(" (truncated)\n");
1419 (void)memcpy(&ev
, (ifan
+ 1), evlen
);
1420 switch (ifan
->ifan_what
) {
1421 case RTM_IEEE80211_JOIN
:
1422 case RTM_IEEE80211_LEAVE
:
1423 printf(" mac %" PRIETHER
,
1424 PRIETHER_ARGS(ev
.join
.iev_addr
));
1426 case RTM_IEEE80211_REPLAY
:
1427 case RTM_IEEE80211_MICHAEL
:
1428 printf(" src %" PRIETHER
" dst %" PRIETHER
1429 " cipher %" PRIu8
" keyix %" PRIu8
,
1430 PRIETHER_ARGS(ev
.replay
.iev_src
),
1431 PRIETHER_ARGS(ev
.replay
.iev_dst
),
1432 ev
.replay
.iev_cipher
,
1433 ev
.replay
.iev_keyix
);
1434 if (ifan
->ifan_what
== RTM_IEEE80211_REPLAY
) {
1435 printf(" key rsc %#" PRIx64
1436 " frame rsc %#" PRIx64
,
1437 ev
.replay
.iev_keyrsc
, ev
.replay
.iev_rsc
);
1445 case RTM_IFANNOUNCE
:
1446 ifan
= (struct if_announcemsghdr
*)rtm
;
1447 (void)printf("if# %d, what: ", ifan
->ifan_index
);
1448 switch (ifan
->ifan_what
) {
1452 case IFAN_DEPARTURE
:
1453 printf("departure");
1456 printf("#%d", ifan
->ifan_what
);
1462 (void)printf("pid %d, seq %d, errno %d, flags: ",
1463 rtm
->rtm_pid
, rtm
->rtm_seq
, rtm
->rtm_errno
);
1464 bprintf(stdout
, rtm
->rtm_flags
, routeflags
);
1471 print_getmsg(struct rt_msghdr
*rtm
, int msglen
, struct sou
*soup
)
1473 struct sockaddr
*dst
= NULL
, *gate
= NULL
, *mask
= NULL
, *ifa
= NULL
, *mpls
= NULL
;
1474 struct sockaddr_dl
*ifp
= NULL
;
1475 struct sockaddr
*sa
;
1479 if (! shortoutput
) {
1480 (void)printf(" route to: %s\n",
1481 routename(&soup
->so_dst
->sa
, nflag
));
1483 if (rtm
->rtm_version
!= RTM_VERSION
) {
1484 warnx("routing message version %d not understood",
1488 if (rtm
->rtm_msglen
> msglen
) {
1489 warnx("message length mismatch, in packet %d, returned %d",
1490 rtm
->rtm_msglen
, msglen
);
1492 if (rtm
->rtm_errno
) {
1493 warnx("RTM_GET: %s (errno %d)",
1494 strerror(rtm
->rtm_errno
), rtm
->rtm_errno
);
1497 cp
= ((char *)(rtm
+ 1));
1499 for (i
= 1; i
; i
<<= 1)
1500 if (i
& rtm
->rtm_addrs
) {
1501 sa
= (struct sockaddr
*)cp
;
1513 if (sa
->sa_family
== AF_LINK
&&
1514 ((struct sockaddr_dl
*)sa
)->sdl_nlen
)
1515 ifp
= (struct sockaddr_dl
*)sa
;
1527 mask
->sa_family
= dst
->sa_family
; /* XXX */
1528 if (dst
&& ! shortoutput
)
1529 (void)printf("destination: %s\n",
1530 routename(dst
, nflag
));
1531 if (mask
&& ! shortoutput
) {
1532 int savenflag
= nflag
;
1535 (void)printf(" mask: %s\n",
1536 routename(mask
, nflag
));
1539 if (gate
&& rtm
->rtm_flags
& RTF_GATEWAY
) {
1542 name
= routename(gate
, nflag
);
1546 (void)printf("%s\n", name
);
1548 (void)printf(" gateway: %s\n", name
);
1552 name
= routename(mpls
, nflag
);
1556 printf("%s\n", name
);
1558 printf(" Tag: %s\n", name
);
1561 if (ifa
&& ! shortoutput
)
1562 (void)printf(" local addr: %s\n",
1563 routename(ifa
, nflag
));
1564 if (ifp
&& ! shortoutput
)
1565 (void)printf(" interface: %.*s\n",
1566 ifp
->sdl_nlen
, ifp
->sdl_data
);
1567 if (! shortoutput
) {
1568 (void)printf(" flags: ");
1569 bprintf(stdout
, rtm
->rtm_flags
, routeflags
);
1572 #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1573 #define msec(u) (((u) + 500) / 1000) /* usec to msec */
1575 if (! shortoutput
) {
1576 (void)printf("\n%s\n", "\
1577 recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire");
1578 printf("%8"PRId64
"%c ", rtm
->rtm_rmx
.rmx_recvpipe
, lock(RPIPE
));
1579 printf("%8"PRId64
"%c ", rtm
->rtm_rmx
.rmx_sendpipe
, lock(SPIPE
));
1580 printf("%8"PRId64
"%c ", rtm
->rtm_rmx
.rmx_ssthresh
, lock(SSTHRESH
));
1581 printf("%8"PRId64
"%c ", msec(rtm
->rtm_rmx
.rmx_rtt
), lock(RTT
));
1582 printf("%8"PRId64
"%c ", msec(rtm
->rtm_rmx
.rmx_rttvar
), lock(RTTVAR
));
1583 printf("%8"PRId64
"%c ", rtm
->rtm_rmx
.rmx_hopcount
, lock(HOPCOUNT
));
1584 printf("%8"PRId64
"%c ", rtm
->rtm_rmx
.rmx_mtu
, lock(MTU
));
1585 if (rtm
->rtm_rmx
.rmx_expire
)
1586 rtm
->rtm_rmx
.rmx_expire
-= time(0);
1587 printf("%8"PRId64
"%c\n", rtm
->rtm_rmx
.rmx_expire
, lock(EXPIRE
));
1591 #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
1594 return (rtm
->rtm_addrs
& RTF_GATEWAY
) == 0;
1597 else if (rtm
->rtm_addrs
&~ RTA_IGN
) {
1598 (void)printf("sockaddrs: ");
1599 bprintf(stdout
, rtm
->rtm_addrs
, addrnames
);
1608 pmsg_common(struct rt_msghdr
*rtm
)
1610 (void)printf("\nlocks: ");
1611 bprintf(stdout
, rtm
->rtm_rmx
.rmx_locks
, metricnames
);
1612 (void)printf(" inits: ");
1613 bprintf(stdout
, rtm
->rtm_inits
, metricnames
);
1614 pmsg_addrs((char *)(rtm
+ 1), rtm
->rtm_addrs
);
1618 extract_addrs(const char *cp
, int addrs
, const struct sockaddr
*sa
[], int *nmfp
)
1622 for (i
= 0; i
< RTAX_MAX
; i
++) {
1623 if ((1 << i
) & addrs
) {
1624 sa
[i
] = (const struct sockaddr
*)cp
;
1625 if ((i
== RTAX_DST
|| i
== RTAX_IFA
) &&
1627 nmf
= sa
[i
]->sa_family
;
1628 RT_ADVANCE(cp
, sa
[i
]);
1638 pmsg_addrs(const char *cp
, int addrs
)
1640 const struct sockaddr
*sa
[RTAX_MAX
];
1644 (void)printf("\nsockaddrs: ");
1645 bprintf(stdout
, addrs
, addrnames
);
1646 (void)putchar('\n');
1647 extract_addrs(cp
, addrs
, sa
, &nmf
);
1648 for (i
= 0; i
< RTAX_MAX
; i
++) {
1652 if (i
== RTAX_NETMASK
&& sa
[i
]->sa_len
)
1654 netmask_string(sa
[i
], -1, nmf
));
1657 routename(sa
[i
], nflag
));
1660 (void)putchar('\n');
1661 (void)fflush(stdout
);
1665 bprintf(FILE *fp
, int b
, const char *f
)
1669 const uint8_t *s
= (const uint8_t *)f
;
1675 while ((i
= *s
++) != 0) {
1676 if (b
& (1 << (i
-1))) {
1683 for (; (i
= *s
) > 32; s
++)
1690 (void)putc('>', fp
);
1694 keyword(const char *cp
)
1696 struct keytab
*kt
= keywords
;
1698 while (kt
->kt_cp
&& strcmp(kt
->kt_cp
, cp
))
1704 sodump(sup su
, const char *which
)
1707 char ntop_buf
[NI_MAXHOST
];
1710 switch (su
->sa
.sa_family
) {
1712 (void)printf("%s: inet %s; ",
1713 which
, inet_ntoa(su
->sin
.sin_addr
));
1717 (void)printf("%s: atalk %d.%d; ",
1718 which
, su
->sat
.sat_addr
.s_net
, su
->sat
.sat_addr
.s_node
);
1722 (void)printf("%s: link %s; ",
1723 which
, link_ntoa(&su
->sdl
));
1727 (void)printf("%s: inet6 %s; ",
1728 which
, inet_ntop(AF_INET6
, &su
->sin6
.sin6_addr
,
1729 ntop_buf
, sizeof(ntop_buf
)));
1736 const union mpls_shim
*pms
;
1737 int psize
= sizeof(struct sockaddr_mpls
);
1739 ms
.s_addr
= ntohl(su
->smpls
.smpls_addr
.s_addr
);
1740 printf("%s: mpls %u; ",
1741 which
, ms
.shim
.label
);
1743 pms
= &su
->smpls
.smpls_addr
;
1744 while(psize
< su
->smpls
.smpls_len
) {
1746 ms
.s_addr
= ntohl(pms
->s_addr
);
1747 printf("%u; ", ms
.shim
.label
);
1748 psize
+= sizeof(ms
);
1754 (void)printf("%s: (%d) %s; ",
1755 which
, su
->sa
.sa_family
, any_ntoa(&su
->sa
));
1757 (void)fflush(stdout
);
1770 sockaddr(const char *addr
, struct sockaddr
*sa
)
1772 char *cp
= (char *)sa
;
1773 int size
= sa
->sa_len
;
1774 char *cplim
= cp
+ size
;
1775 int byte
= 0, state
= VIRGIN
, new = 0;
1777 (void)memset(cp
, 0, size
);
1780 if ((*addr
>= '0') && (*addr
<= '9')) {
1782 } else if ((*addr
>= 'a') && (*addr
<= 'f')) {
1783 new = *addr
- 'a' + 10;
1784 } else if ((*addr
>= 'A') && (*addr
<= 'F')) {
1785 new = *addr
- 'A' + 10;
1786 } else if (*addr
== 0)
1791 switch (state
/* | INPUT */) {
1792 case GOTTWO
| DIGIT
:
1793 *cp
++ = byte
; /*FALLTHROUGH*/
1794 case VIRGIN
| DIGIT
:
1795 state
= GOTONE
; byte
= new; continue;
1796 case GOTONE
| DIGIT
:
1797 state
= GOTTWO
; byte
= new + (byte
<< 4); continue;
1798 default: /* | DELIM */
1799 state
= VIRGIN
; *cp
++ = byte
; byte
= 0; continue;
1802 *cp
++ = byte
; /* FALLTHROUGH */
1807 } while (cp
< cplim
);
1808 sa
->sa_len
= cp
- (char *)sa
;