2 * Copyright (c) 1983, 1989, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * @(#) Copyright (c) 1983, 1989, 1991, 1993 The Regents of the University of California. All rights reserved.
30 * @(#)route.c 8.6 (Berkeley) 4/28/95
31 * $FreeBSD: src/sbin/route/route.c,v 1.40.2.11 2003/02/27 23:10:10 ru Exp $
34 #include <sys/param.h>
35 #include <sys/socket.h>
36 #include <sys/ioctl.h>
37 #include <sys/sysctl.h>
38 #include <sys/types.h>
41 #include <net/route.h>
42 #include <net/if_dl.h>
43 #include <netinet/in.h>
44 #include <netinet/if_ether.h>
45 #include <arpa/inet.h>
48 #include <netproto/802_11/ieee80211_dragonfly.h>
49 #include <netproto/mpls/mpls.h>
68 struct sockaddr_in sin
;
70 struct sockaddr_in6 sin6
;
72 struct sockaddr_mpls smpls
;
73 struct sockaddr_dl sdl
;
74 struct sockaddr_inarp sinarp
;
75 struct sockaddr_storage ss
; /* added to avoid memory overrun */
76 } so_dst
, so_gate
, so_mask
, so_genmask
, so_ifa
, so_ifp
, so_mpls1
,
79 typedef union sockunion
*sup
;
84 static struct keytab
{
87 } const keywords
[] = {
92 static struct sockaddr_in so_gate_tried
;
93 static struct rt_metrics rt_metrics
;
94 static int pid
, rtm_addrs
;
96 static int forcehost
, forcenet
, af
, qflag
, tflag
;
97 static int iflag
, verbose
, aflen
= sizeof(struct sockaddr_in
);
98 static int locking
, lockrest
, debugonly
;
99 static int mplsop
, popcount
, pushcount
, swapcount
;
100 static u_long rtm_inits
;
103 static void flushroutes(int, char **);
104 static void set_metric(char *, int);
105 static void newroute(int, char **) __dead2
;
106 static void inet_makenetandmask(u_long
, struct sockaddr_in
*, u_long
);
107 static void interfaces(void);
108 static void monitor(void) __dead2
;
109 static void sockaddr(const char *, struct sockaddr
*);
110 static void sodump(sup
, const char *);
111 static void bprintf(FILE *, int, u_char
*);
112 static void print_getmsg(struct rt_msghdr
*, int);
113 static void print_rtmsg(struct rt_msghdr
*, int);
114 static void pmsg_common(struct rt_msghdr
*);
115 static void pmsg_addrs(char *, int);
116 static void mask_addr(void);
117 static int getaddr(int, const char *, struct hostent
**);
118 static int rtmsg(int, int);
119 static int prefixlen(const char *);
121 static int inet6_makenetandmask(struct sockaddr_in6
*, const char *);
124 #define PRIETHER "02x:%02x:%02x:%02x:%02x:%02x"
125 #define PRIETHER_ARGS(__enaddr) (__enaddr)[0], (__enaddr)[1], (__enaddr)[2], \
126 (__enaddr)[3], (__enaddr)[4], (__enaddr)[5]
129 usage(const char *cp
)
132 warnx("bad keyword: %s", cp
);
133 fprintf(stderr
, "usage: route [-dnqtvw] [-c cpu] command [[modifiers] args]\n");
139 main(int argc
, char **argv
)
146 while ((ch
= getopt(argc
, argv
, "c:wnqdtv")) != -1)
149 cpuflag
= strtol(optarg
, NULL
, 0);
179 s
= open(_PATH_DEVNULL
, O_WRONLY
, 0);
182 s
= socket(PF_ROUTE
, SOCK_RAW
, 0);
185 if (setsockopt(s
, SOL_SOCKET
, SO_RERROR
, &on
, sizeof(on
)) == -1)
190 err(EX_OSERR
, "socket");
192 switch (keyword(*argv
)) {
200 newroute(argc
, argv
);
212 flushroutes(argc
, argv
);
221 * Purge all entries in the routing tables not
222 * associated with network interfaces.
225 flushroutes(int argc
, char **argv
)
228 int mib
[7], rlen
, seqno
;
230 char *buf
, *next
, *lim
;
231 struct rt_msghdr
*rtm
;
234 errx(EX_NOPERM
, "must be root to alter routing table");
236 shutdown(s
, SHUT_RD
); /* Don't want to read back our messages */
239 if (argc
== 2 && **argv
== '-')
240 switch (keyword(*argv
+ 1)) {
262 mib
[2] = 0; /* protocol */
263 mib
[3] = 0; /* wildcard address family */
264 mib
[4] = NET_RT_DUMP
;
265 mib
[5] = 0; /* no flags */
272 if (sysctl(mib
, miblen
, NULL
, &needed
, NULL
, 0) < 0)
273 err(EX_OSERR
, "route-sysctl-estimate");
274 if ((buf
= malloc(needed
)) == NULL
)
275 errx(EX_OSERR
, "malloc failed");
276 if (sysctl(mib
, miblen
, buf
, &needed
, NULL
, 0) < 0)
277 err(EX_OSERR
, "route-sysctl-get");
280 printf("Examining routing table from sysctl\n");
282 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
283 rtm
= (struct rt_msghdr
*)next
;
285 print_rtmsg(rtm
, rtm
->rtm_msglen
);
286 if ((rtm
->rtm_flags
& RTF_GATEWAY
) == 0)
289 struct sockaddr
*sa
= (struct sockaddr
*)(rtm
+ 1);
291 if (sa
->sa_family
!= af
)
296 rtm
->rtm_type
= RTM_DELETE
;
297 rtm
->rtm_seq
= seqno
;
298 rlen
= write(s
, next
, rtm
->rtm_msglen
);
299 if (rlen
< (int)rtm
->rtm_msglen
) {
300 warn("write to routing socket");
301 printf("got only %d for rlen\n", rlen
);
308 print_rtmsg(rtm
, rlen
);
310 struct sockaddr
*sa
= (struct sockaddr
*)(rtm
+ 1);
312 printf("%-20s ", rtm
->rtm_flags
& RTF_HOST
?
313 routename(sa
) : netname(sa
));
315 printf("%-20.20s ", rtm
->rtm_flags
& RTF_HOST
?
316 routename(sa
) : netname(sa
));
318 sa
= (struct sockaddr
*)(RT_ROUNDUP(sa
->sa_len
) +
321 printf("%-20s ", routename(sa
));
323 printf("%-20.20s ", routename(sa
));
331 routename(struct sockaddr
*sa
)
334 static char line
[MAXHOSTNAMELEN
+ 1];
336 static char domain
[MAXHOSTNAMELEN
+ 1];
337 static int first
= 1;
341 if (gethostname(domain
, MAXHOSTNAMELEN
) == 0 &&
342 (cp
= strchr(domain
, '.'))) {
343 domain
[MAXHOSTNAMELEN
] = '\0';
344 strcpy(domain
, cp
+ 1);
350 strcpy(line
, "default");
351 else switch (sa
->sa_family
) {
355 in
= ((struct sockaddr_in
*)sa
)->sin_addr
;
358 if (in
.s_addr
== INADDR_ANY
|| sa
->sa_len
< 4)
360 if (cp
== NULL
&& !nflag
) {
361 hp
= gethostbyaddr(&in
, sizeof(struct in_addr
),
365 cptr
= strchr(hp
->h_name
, '.');
366 if (cptr
!= NULL
&& !wflag
&&
367 strcmp(cptr
+ 1, domain
) == 0)
373 strncpy(line
, cp
, sizeof(line
) - 1);
374 line
[sizeof(line
) - 1] = '\0';
376 sprintf(line
, "%s", inet_ntoa(in
));
383 struct sockaddr_in6 sin6
; /* use static var for safety */
385 #ifdef NI_WITHSCOPEID
386 niflags
= NI_WITHSCOPEID
;
389 memset(&sin6
, 0, sizeof(sin6
));
390 memcpy(&sin6
, sa
, sa
->sa_len
);
391 sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
392 sin6
.sin6_family
= AF_INET6
;
394 if (sa
->sa_len
== sizeof(struct sockaddr_in6
) &&
395 (IN6_IS_ADDR_LINKLOCAL(&sin6
.sin6_addr
) ||
396 IN6_IS_ADDR_MC_LINKLOCAL(&sin6
.sin6_addr
)) &&
397 sin6
.sin6_scope_id
== 0) {
399 ntohs(*(u_int16_t
*)&sin6
.sin6_addr
.s6_addr
[2]);
400 sin6
.sin6_addr
.s6_addr
[2] = 0;
401 sin6
.sin6_addr
.s6_addr
[3] = 0;
405 niflags
|= NI_NUMERICHOST
;
406 if (getnameinfo((struct sockaddr
*)&sin6
, sin6
.sin6_len
,
407 line
, sizeof(line
), NULL
, 0, niflags
) != 0)
408 strncpy(line
, "invalid", sizeof(line
));
415 return(link_ntoa((struct sockaddr_dl
*)sa
));
420 * Unknown address family; just render the raw
421 * data in sa->sa_data as hex values.
423 uint8_t *sp
= (uint8_t *)sa
->sa_data
;
424 uint8_t *splim
= (uint8_t *)sa
+ sa
->sa_len
;
425 char *cps
= line
+ sprintf(line
, "(%d)", sa
->sa_family
);
426 char *cpe
= line
+ sizeof(line
);
428 while (sp
< splim
&& cps
< cpe
)
429 cps
+= snprintf(cps
, cpe
- cps
, " %02x", *sp
++);
437 * Return the name of the network whose address is given.
438 * The address is assumed to be that of a net or subnet, not a host.
441 netname(struct sockaddr
*sa
)
443 const char *cp
= NULL
;
444 static char line
[MAXHOSTNAMELEN
+ 1];
445 struct netent
*np
= NULL
;
450 switch (sa
->sa_family
) {
454 in
= ((struct sockaddr_in
*)sa
)->sin_addr
;
456 i
= in
.s_addr
= ntohl(in
.s_addr
);
461 mask
= IN_CLASSA_NET
;
463 } else if (IN_CLASSB(i
)) {
464 mask
= IN_CLASSB_NET
;
467 mask
= IN_CLASSC_NET
;
471 * If there are more bits than the standard mask
472 * would suggest, subnets must be in use.
473 * Guess at the subnet mask, assuming reasonable
474 * width subnet fields.
476 while (in
.s_addr
&~ mask
)
477 mask
|= mask
>> subnetshift
;
478 net
= in
.s_addr
& mask
;
479 while ((mask
& 1) == 0)
480 mask
>>= 1, net
>>= 1;
481 np
= getnetbyaddr(net
, AF_INET
);
485 #define C(x) (unsigned)((x) & 0xff)
487 strncpy(line
, cp
, sizeof(line
));
488 else if ((in
.s_addr
& 0xffffff) == 0)
489 sprintf(line
, "%u", C(in
.s_addr
>> 24));
490 else if ((in
.s_addr
& 0xffff) == 0)
491 sprintf(line
, "%u.%u", C(in
.s_addr
>> 24),
493 else if ((in
.s_addr
& 0xff) == 0)
494 sprintf(line
, "%u.%u.%u", C(in
.s_addr
>> 24),
495 C(in
.s_addr
>> 16), C(in
.s_addr
>> 8));
497 sprintf(line
, "%u.%u.%u.%u", C(in
.s_addr
>> 24),
498 C(in
.s_addr
>> 16), C(in
.s_addr
>> 8),
507 struct sockaddr_in6 sin6
; /* use static var for safety */
509 #ifdef NI_WITHSCOPEID
510 niflags
= NI_WITHSCOPEID
;
513 memset(&sin6
, 0, sizeof(sin6
));
514 memcpy(&sin6
, sa
, sa
->sa_len
);
515 sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
516 sin6
.sin6_family
= AF_INET6
;
518 if (sa
->sa_len
== sizeof(struct sockaddr_in6
) &&
519 (IN6_IS_ADDR_LINKLOCAL(&sin6
.sin6_addr
) ||
520 IN6_IS_ADDR_MC_LINKLOCAL(&sin6
.sin6_addr
)) &&
521 sin6
.sin6_scope_id
== 0) {
523 ntohs(*(u_int16_t
*)&sin6
.sin6_addr
.s6_addr
[2]);
524 sin6
.sin6_addr
.s6_addr
[2] = 0;
525 sin6
.sin6_addr
.s6_addr
[3] = 0;
529 niflags
|= NI_NUMERICHOST
;
530 if (getnameinfo((struct sockaddr
*)&sin6
, sin6
.sin6_len
,
531 line
, sizeof(line
), NULL
, 0, niflags
) != 0)
532 strncpy(line
, "invalid", sizeof(line
));
539 return(link_ntoa((struct sockaddr_dl
*)sa
));
545 * Unknown address family; just render the raw
546 * data in sa->sa_data as hex values.
548 uint8_t *sp
= (uint8_t *)sa
->sa_data
;
549 uint8_t *splim
= (uint8_t *)sa
+ sa
->sa_len
;
550 char *cps
= line
+ sprintf(line
, "af %d:", sa
->sa_family
);
551 char *cpe
= line
+ sizeof(line
);
553 while (sp
< splim
&& cps
< cpe
)
554 cps
+= snprintf(cps
, cpe
- cps
, " %02x", *sp
++);
562 set_metric(char *value
, int key
)
565 u_long noval
, *valp
= &noval
;
568 #define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break
569 caseof(K_MTU
, RTV_MTU
, rmx_mtu
);
570 caseof(K_HOPCOUNT
, RTV_HOPCOUNT
, rmx_hopcount
);
571 caseof(K_EXPIRE
, RTV_EXPIRE
, rmx_expire
);
572 caseof(K_RECVPIPE
, RTV_RPIPE
, rmx_recvpipe
);
573 caseof(K_SENDPIPE
, RTV_SPIPE
, rmx_sendpipe
);
574 caseof(K_SSTHRESH
, RTV_SSTHRESH
, rmx_ssthresh
);
575 caseof(K_RTT
, RTV_RTT
, rmx_rtt
);
576 caseof(K_RTTVAR
, RTV_RTTVAR
, rmx_rttvar
);
577 caseof(K_MSL
, RTV_MSL
, rmx_msl
);
578 caseof(K_IWMAX
, RTV_IWMAXSEGS
, rmx_iwmaxsegs
);
579 caseof(K_IW
, RTV_IWCAPSEGS
, rmx_iwcapsegs
);
582 if (lockrest
|| locking
)
583 rt_metrics
.rmx_locks
|= flag
;
590 newroute(int argc
, char **argv
)
593 const char *err_str
, *dest
= "", *gateway
= "";
594 int ishost
= 0, proxy
= 0, ret
, attempts
, oerrno
, flags
= RTF_STATIC
;
596 struct hostent
*hp
= NULL
;
599 errx(EX_NOPERM
, "must be root to alter routing table");
603 shutdown(s
, SHUT_RD
); /* Don't want to read back our messages */
605 if (**(++argv
)== '-') {
606 switch (key
= keyword(1 + *argv
)) {
609 aflen
= sizeof(struct sockaddr_dl
);
613 aflen
= sizeof(struct sockaddr_in
);
618 aflen
= sizeof(struct sockaddr_in6
);
623 aflen
= sizeof(union sockunion
);
630 flags
&= ~RTF_STATIC
;
648 flags
|= RTF_BLACKHOLE
;
660 flags
|= RTF_CLONING
;
663 flags
|= RTF_XRESOLVE
;
671 getaddr(RTA_IFA
, *++argv
, 0);
676 getaddr(RTA_IFP
, *++argv
, 0);
681 getaddr(RTA_GENMASK
, *++argv
, 0);
686 getaddr(RTA_GATEWAY
, *++argv
, 0);
691 ishost
= getaddr(RTA_DST
, *++argv
, &hp
);
697 getaddr(RTA_NETMASK
, *++argv
, 0);
705 if (prefixlen(*++argv
) == -1) {
715 aflen
= sizeof(struct sockaddr_mpls
);
718 flags
|= RTF_MPLSOPS
;
720 mplsop
= MPLSLOP_POP
;
723 getaddr(RTA_MPLS1
, "", 0);
726 getaddr(RTA_MPLS2
, "", 0);
729 getaddr(RTA_MPLS3
, "", 0);
736 warnx("Push or swap after pop. Ignoring.");
740 mplsop
= MPLSLOP_PUSH
;
744 warnx("Swap after push. Ignoring.");
748 warnx("Too many swaps. Ignoring.");
751 mplsop
= MPLSLOP_SWAP
;
754 flags
|= RTF_MPLSOPS
;
756 aflen
= sizeof(struct sockaddr_mpls
);
759 switch(pushcount
+ swapcount
){
761 getaddr(RTA_MPLS1
, *++argv
, 0);
764 getaddr(RTA_MPLS2
, *++argv
, 0);
767 getaddr(RTA_MPLS3
, *++argv
, 0);
784 set_metric(*++argv
, key
);
790 if ((rtm_addrs
& RTA_DST
) == 0) {
792 ishost
= getaddr(RTA_DST
, *argv
, &hp
);
793 } else if ((rtm_addrs
& RTA_GATEWAY
) == 0) {
795 getaddr(RTA_GATEWAY
, *argv
, &hp
);
797 getaddr(RTA_NETMASK
, *argv
, 0);
805 if (af
== AF_INET6
) {
806 rtm_addrs
&= ~RTA_NETMASK
;
807 memset((void *)&so_mask
, 0, sizeof(so_mask
));
817 flags
|= RTF_GATEWAY
;
819 so_dst
.sinarp
.sin_other
= SIN_PROXY
;
820 flags
|= RTF_ANNOUNCE
;
822 for (attempts
= 1; ; attempts
++) {
824 if ((ret
= rtmsg(*cmd
, flags
)) == 0)
826 if (errno
!= ENETUNREACH
&& errno
!= ESRCH
)
828 if (af
== AF_INET
&& *gateway
!= '\0' &&
829 hp
!= NULL
&& hp
->h_addr_list
[1] != NULL
) {
830 so_gate_tried
= so_gate
.sin
;
832 memmove(&so_gate
.sin
.sin_addr
,
834 MIN((size_t)hp
->h_length
,
835 sizeof(so_gate
.sin
.sin_addr
)));
843 printf("%s %s %s", cmd
, ishost
? "host" : "net", dest
);
844 if (*gateway
!= '\0') {
845 printf(": gateway %s", gateway
);
846 if (attempts
> 1 && ret
== 0 && af
== AF_INET
) {
848 inet_ntoa(so_gate_tried
.sin_addr
));
856 err_str
= "not in table";
859 err_str
= "entry in use";
862 err_str
= "routing table overflow";
864 case EDQUOT
: /* handle recursion avoidance in
866 err_str
= "gateway uses the same route";
869 err_str
= strerror(oerrno
);
872 printf(": %s\n", err_str
);
879 inet_makenetandmask(u_long net
, struct sockaddr_in
*in
, u_long bits
)
881 u_long addr
, mask
= 0;
884 rtm_addrs
|= RTA_NETMASK
;
886 * XXX: This approach unable to handle 0.0.0.1/32 correctly
887 * as inet_network() converts 0.0.0.1 and 1 equally.
890 addr
= net
<< IN_CLASSA_NSHIFT
;
891 else if (net
<= 0xffff)
892 addr
= net
<< IN_CLASSB_NSHIFT
;
893 else if (net
<= 0xffffff)
894 addr
= net
<< IN_CLASSC_NSHIFT
;
899 mask
= 0xffffffff << (32 - bits
);
902 else if (IN_CLASSA(addr
))
903 mask
= IN_CLASSA_NET
;
904 else if (IN_CLASSB(addr
))
905 mask
= IN_CLASSB_NET
;
906 else if (IN_CLASSC(addr
))
907 mask
= IN_CLASSC_NET
;
908 else if (IN_MULTICAST(addr
))
909 mask
= IN_CLASSD_NET
;
913 in
->sin_addr
.s_addr
= htonl(addr
);
915 in
->sin_addr
.s_addr
= htonl(mask
);
918 cp
= (char *)(&in
->sin_addr
+ 1);
919 while (*--cp
== 0 && cp
> (char *)in
)
921 in
->sin_len
= 1 + cp
- (char *)in
;
926 * XXX the function may need more improvement...
929 inet6_makenetandmask(struct sockaddr_in6
*sin6
, const char *plen
)
934 if (IN6_IS_ADDR_UNSPECIFIED(&sin6
->sin6_addr
) &&
935 sin6
->sin6_scope_id
== 0) {
937 } else if ((sin6
->sin6_addr
.s6_addr
[0] & 0xe0) == 0x20) {
938 /* aggregatable global unicast - RFC2374 */
939 memset(&in6
, 0, sizeof(in6
));
940 if (memcmp(&sin6
->sin6_addr
.s6_addr
[8],
941 &in6
.s6_addr
[8], 8) == 0)
946 if (plen
== NULL
|| strcmp(plen
, "128") == 0)
948 rtm_addrs
|= RTA_NETMASK
;
955 * Interpret an argument as a network address of some kind,
956 * returning 1 if a host address, 0 if a network address.
959 getaddr(int which
, const char *str
, struct hostent
**hpp
)
966 int afamily
; /* local copy of af so we can change it */
970 aflen
= sizeof(struct sockaddr_in
);
981 struct ifaddrs
*ifap
, *ifa
;
982 struct sockaddr_dl
*sdl
= NULL
;
984 if (getifaddrs(&ifap
))
985 err(1, "getifaddrs");
987 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
988 if (ifa
->ifa_addr
->sa_family
!= AF_LINK
)
991 if (strcmp(str
, ifa
->ifa_name
) != 0)
994 sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
996 /* If we found it, then use it */
999 * Copy is safe since we have a
1000 * sockaddr_storage member in sockunion{}.
1001 * Note that we need to copy before calling
1004 * Interface routes are routed only by their
1005 * sdl_index or interface name (we provide
1006 * both here), not by the ARP address of the
1007 * local interface (alen, slen = 0).
1009 memcpy(&su
->sdl
, sdl
, sdl
->sdl_len
);
1010 su
->sdl
.sdl_alen
= 0;
1011 su
->sdl
.sdl_slen
= 0;
1041 usage("internal error");
1044 su
->sa
.sa_len
= aflen
;
1045 su
->sa
.sa_family
= afamily
; /* cases that don't want it have left
1047 if (strcmp(str
, "default") == 0) {
1049 * Default is net 0.0.0.0/0
1054 /* bzero(su, sizeof(*su)); *//* for readability */
1055 getaddr(RTA_NETMASK
, str
, 0);
1059 /* bzero(su, sizeof(*su)); *//* for readability */
1068 struct addrinfo hints
, *res
;
1071 if (which
== RTA_DST
&& (q
= strchr(str
, '/')) != NULL
)
1073 memset(&hints
, 0, sizeof(hints
));
1074 hints
.ai_family
= afamily
; /*AF_INET6*/
1075 hints
.ai_flags
= AI_NUMERICHOST
;
1076 hints
.ai_socktype
= SOCK_DGRAM
; /*dummy*/
1077 if (getaddrinfo(str
, "0", &hints
, &res
) != 0 ||
1078 res
->ai_family
!= AF_INET6
||
1079 res
->ai_addrlen
!= sizeof(su
->sin6
)) {
1080 fprintf(stderr
, "%s: bad value\n", str
);
1083 memcpy(&su
->sin6
, res
->ai_addr
, sizeof(su
->sin6
));
1085 if ((IN6_IS_ADDR_LINKLOCAL(&su
->sin6
.sin6_addr
) ||
1086 IN6_IS_ADDR_LINKLOCAL(&su
->sin6
.sin6_addr
)) &&
1087 su
->sin6
.sin6_scope_id
) {
1088 *(u_int16_t
*)&su
->sin6
.sin6_addr
.s6_addr
[2] =
1089 htons(su
->sin6
.sin6_scope_id
);
1090 su
->sin6
.sin6_scope_id
= 0;
1096 if (which
== RTA_DST
)
1097 return(inet6_makenetandmask(&su
->sin6
, q
));
1103 link_addr(str
, &su
->sdl
);
1107 su
->sa
.sa_len
= sizeof(*su
);
1108 sockaddr(str
, &su
->sa
);
1115 bzero(su
, sizeof(*su
));
1116 su
->sa
.sa_len
= sizeof(*su
);
1117 su
->sa
.sa_family
= AF_MPLS
;
1118 su
->smpls
.smpls_op
= mplsop
;
1119 if (mplsop
!= MPLSLOP_POP
&& mplsop
!= MPLSLOP_POPALL
&&
1121 if (sscanf(str
, "%u", &label
) != 1)
1122 errx(EX_NOHOST
, "bad address: %s", str
);
1123 su
->smpls
.smpls_label
= htonl(label
);
1137 q
= strchr(str
,'/');
1138 if (q
!= NULL
&& which
== RTA_DST
) {
1140 if ((val
= inet_network(str
)) != INADDR_NONE
) {
1141 inet_makenetandmask(
1142 val
, &su
->sin
, strtoul(q
+1, 0, 0));
1147 if ((which
!= RTA_DST
|| forcenet
== 0) &&
1148 inet_aton(str
, &su
->sin
.sin_addr
)) {
1149 val
= su
->sin
.sin_addr
.s_addr
;
1150 if (which
!= RTA_DST
||
1151 inet_lnaof(su
->sin
.sin_addr
) != INADDR_ANY
)
1158 if (which
== RTA_DST
&& forcehost
== 0 &&
1159 ((val
= inet_network(str
)) != INADDR_NONE
||
1160 ((np
= getnetbyname(str
)) != NULL
&& (val
= np
->n_net
) != 0))) {
1162 inet_makenetandmask(val
, &su
->sin
, 0);
1165 hp
= gethostbyname(str
);
1168 su
->sin
.sin_family
= hp
->h_addrtype
;
1169 memmove((char *)&su
->sin
.sin_addr
, hp
->h_addr
,
1170 MIN((size_t)hp
->h_length
, sizeof(su
->sin
.sin_addr
)));
1173 errx(EX_NOHOST
, "bad address: %s", str
);
1177 prefixlen(const char *len_str
)
1179 int len
= atoi(len_str
), q
, r
;
1183 rtm_addrs
|= RTA_NETMASK
;
1188 p
= (char *)&so_mask
.sin6
.sin6_addr
;
1193 p
= (char *)&so_mask
.sin
.sin_addr
;
1196 fprintf(stderr
, "prefixlen not supported in this af\n");
1201 if (len
< 0 || max
< len
) {
1202 fprintf(stderr
, "%s: bad value\n", len_str
);
1208 so_mask
.sa
.sa_family
= af
;
1209 so_mask
.sa
.sa_len
= aflen
;
1210 memset((void *)p
, 0, max
/ 8);
1212 memset((void *)p
, 0xff, q
);
1214 *((u_char
*)p
+ q
) = (0xff00 >> r
) & 0xff;
1226 char *buf
, *lim
, *next
;
1227 struct rt_msghdr
*rtm
;
1231 mib
[2] = 0; /* protocol */
1232 mib
[3] = 0; /* wildcard address family */
1233 mib
[4] = NET_RT_IFLIST
;
1234 mib
[5] = 0; /* no flags */
1235 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
1236 err(EX_OSERR
, "route-sysctl-estimate");
1237 if ((buf
= malloc(needed
)) == NULL
)
1238 errx(EX_OSERR
, "malloc failed");
1239 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0)
1240 err(EX_OSERR
, "actual retrieval of interface table");
1242 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
1243 rtm
= (struct rt_msghdr
*)next
;
1244 print_rtmsg(rtm
, rtm
->rtm_msglen
);
1262 n
= read(s
, msg
, sizeof(msg
));
1266 printf("\nsocket error %d on %s %s\n",
1267 error
, ctime(&now
), strerror(errno
));
1270 printf("\ngot message of size %d on %s", n
, ctime(&now
));
1271 print_rtmsg((struct rt_msghdr
*)msg
, n
);
1276 struct rt_msghdr m_rtm
;
1281 rtmsg(int cmd
, int flags
)
1285 char *cp
= m_rtmsg
.m_space
;
1288 #define NEXTADDR(w, u) \
1289 if (rtm_addrs & (w)) {\
1290 l = RT_ROUNDUP(u.sa.sa_len); memmove(cp, &(u), l); cp += l;\
1291 if (verbose) sodump(&(u),"u");\
1295 memset(&m_rtmsg
, 0, sizeof(m_rtmsg
));
1298 else if (cmd
== 'c')
1300 else if (cmd
== 'g') {
1302 if (so_ifp
.sa
.sa_family
== 0) {
1303 so_ifp
.sa
.sa_family
= AF_LINK
;
1304 so_ifp
.sa
.sa_len
= sizeof(struct sockaddr_dl
);
1305 rtm_addrs
|= RTA_IFP
;
1309 #define rtm m_rtmsg.m_rtm
1311 rtm
.rtm_flags
= flags
;
1312 rtm
.rtm_version
= RTM_VERSION
;
1313 rtm
.rtm_seq
= ++seq
;
1314 rtm
.rtm_addrs
= rtm_addrs
;
1315 rtm
.rtm_rmx
= rt_metrics
;
1316 rtm
.rtm_inits
= rtm_inits
;
1318 if (rtm_addrs
& RTA_NETMASK
)
1320 NEXTADDR(RTA_DST
, so_dst
);
1321 NEXTADDR(RTA_GATEWAY
, so_gate
);
1322 NEXTADDR(RTA_NETMASK
, so_mask
);
1323 NEXTADDR(RTA_GENMASK
, so_genmask
);
1324 NEXTADDR(RTA_IFP
, so_ifp
);
1325 NEXTADDR(RTA_IFA
, so_ifa
);
1326 NEXTADDR(RTA_MPLS1
, so_mpls1
);
1327 NEXTADDR(RTA_MPLS2
, so_mpls2
);
1328 NEXTADDR(RTA_MPLS3
, so_mpls3
);
1329 rtm
.rtm_msglen
= l
= cp
- (char *)&m_rtmsg
;
1331 print_rtmsg(&rtm
, l
);
1334 if ((rlen
= write(s
, (char *)&m_rtmsg
, l
)) < 0) {
1335 warn("writing to routing socket");
1338 if (cmd
== RTM_GET
) {
1340 l
= read(s
, (char *)&m_rtmsg
, sizeof(m_rtmsg
));
1341 } while (l
> 0 && (rtm
.rtm_seq
!= seq
|| rtm
.rtm_pid
!= pid
));
1343 warn("read from routing socket");
1345 print_getmsg(&rtm
, l
);
1354 int olen
= so_mask
.sa
.sa_len
;
1355 char *cp1
= olen
+ (char *)&so_mask
, *cp2
;
1357 for (so_mask
.sa
.sa_len
= 0; cp1
> (char *)&so_mask
; )
1359 so_mask
.sa
.sa_len
= 1 + cp1
- (char *)&so_mask
;
1362 if ((rtm_addrs
& RTA_DST
) == 0)
1364 switch (so_dst
.sa
.sa_family
) {
1372 cp1
= so_mask
.sa
.sa_len
+ 1 + (char *)&so_dst
;
1373 cp2
= so_dst
.sa
.sa_len
+ 1 + (char *)&so_dst
;
1376 cp2
= so_mask
.sa
.sa_len
+ 1 + (char *)&so_mask
;
1377 while (cp1
> so_dst
.sa
.sa_data
)
1381 const char *msgtypes
[] = {
1383 "RTM_ADD: Add Route",
1384 "RTM_DELETE: Delete Route",
1385 "RTM_CHANGE: Change Metrics or flags",
1386 "RTM_GET: Report Metrics",
1387 "RTM_LOSING: Kernel Suspects Partitioning",
1388 "RTM_REDIRECT: Told to use different route",
1389 "RTM_MISS: Lookup failed on this address",
1390 "RTM_LOCK: fix specified metrics",
1393 "RTM_RESOLVE: Route created by cloning",
1394 "RTM_NEWADDR: address being added to iface",
1395 "RTM_DELADDR: address being removed from iface",
1396 "RTM_IFINFO: iface status change",
1397 "RTM_NEWMADDR: new multicast group membership on iface",
1398 "RTM_DELMADDR: multicast group membership removed from iface",
1399 "RTM_IFANNOUNCE: interface arrival/departure",
1400 "RTM_IEEE80211: IEEE80211 wireless event",
1404 char metricnames
[] =
1405 "\013iw\012iwmax\011msl\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire"
1408 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"
1409 "\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016"
1410 "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024CHAINDELETE"
1411 "\025PINNED\026LOCAL\027BROADCAST\030MULTICAST";
1413 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
1414 "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
1415 "\017LINK2\020MULTICAST";
1417 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD"
1418 "\011MPLS1\012MPLS2\013MPLS3";
1421 linkstate(struct if_msghdr
*ifm
)
1423 static char buf
[64];
1425 switch (ifm
->ifm_data
.ifi_link_state
) {
1426 case LINK_STATE_UNKNOWN
:
1427 return "carrier: unknown";
1428 case LINK_STATE_DOWN
:
1429 return "carrier: no carrier";
1431 return "carrier: active";
1433 (void)snprintf(buf
, sizeof(buf
), "carrier: 0x%lx",
1434 ifm
->ifm_data
.ifi_link_state
);
1440 print_rtmsg(struct rt_msghdr
*rtm
, int msglen __unused
)
1442 struct if_msghdr
*ifm
;
1443 struct ifa_msghdr
*ifam
;
1445 struct ifma_msghdr
*ifmam
;
1447 struct if_announcemsghdr
*ifan
;
1449 struct ieee80211_join_event join
;
1450 struct ieee80211_leave_event leave
;
1451 struct ieee80211_replay_event replay
;
1452 struct ieee80211_michael_event michael
;
1458 if (rtm
->rtm_version
!= RTM_VERSION
) {
1459 printf("routing message version %d not understood\n",
1463 if (msgtypes
[rtm
->rtm_type
] != NULL
)
1464 printf("%s: ", msgtypes
[rtm
->rtm_type
]);
1466 printf("#%d: ", rtm
->rtm_type
);
1467 printf("len %d, ", rtm
->rtm_msglen
);
1468 switch (rtm
->rtm_type
) {
1470 ifm
= (struct if_msghdr
*)rtm
;
1471 printf("if# %d, %s, flags:", ifm
->ifm_index
, linkstate(ifm
));
1472 bprintf(stdout
, ifm
->ifm_flags
, ifnetflags
);
1473 pmsg_addrs((char *)(ifm
+ 1), ifm
->ifm_addrs
);
1477 ifam
= (struct ifa_msghdr
*)rtm
;
1478 printf("metric %d, flags:", ifam
->ifam_metric
);
1479 bprintf(stdout
, ifam
->ifam_flags
, routeflags
);
1480 pmsg_addrs((char *)(ifam
+ 1), ifam
->ifam_addrs
);
1485 ifmam
= (struct ifma_msghdr
*)rtm
;
1486 pmsg_addrs((char *)(ifmam
+ 1), ifmam
->ifmam_addrs
);
1490 ifan
= (struct if_announcemsghdr
*)rtm
;
1491 (void)printf("if# %d, what: ", ifan
->ifan_index
);
1492 switch (ifan
->ifan_what
) {
1493 case RTM_IEEE80211_ASSOC
:
1494 printf("associate");
1496 case RTM_IEEE80211_REASSOC
:
1497 printf("re-associate");
1499 case RTM_IEEE80211_DISASSOC
:
1500 printf("disassociate");
1502 case RTM_IEEE80211_SCAN
:
1503 printf("scan complete");
1505 case RTM_IEEE80211_JOIN
:
1506 evlen
= sizeof(ev
.join
);
1509 case RTM_IEEE80211_LEAVE
:
1510 evlen
= sizeof(ev
.leave
);
1513 case RTM_IEEE80211_MICHAEL
:
1514 evlen
= sizeof(ev
.michael
);
1517 case RTM_IEEE80211_REPLAY
:
1518 evlen
= sizeof(ev
.replay
);
1523 printf("#%d", ifan
->ifan_what
);
1526 if (sizeof(*ifan
) + evlen
> ifan
->ifan_msglen
) {
1527 printf(" (truncated)\n");
1530 (void)memcpy(&ev
, (ifan
+ 1), evlen
);
1531 switch (ifan
->ifan_what
) {
1532 case RTM_IEEE80211_JOIN
:
1533 case RTM_IEEE80211_LEAVE
:
1534 printf(" mac %" PRIETHER
,
1535 PRIETHER_ARGS(ev
.join
.iev_addr
));
1537 case RTM_IEEE80211_REPLAY
:
1538 case RTM_IEEE80211_MICHAEL
:
1539 printf(" src %" PRIETHER
" dst %" PRIETHER
1540 " cipher %" PRIu8
" keyix %" PRIu8
,
1541 PRIETHER_ARGS(ev
.replay
.iev_src
),
1542 PRIETHER_ARGS(ev
.replay
.iev_dst
),
1543 ev
.replay
.iev_cipher
,
1544 ev
.replay
.iev_keyix
);
1545 if (ifan
->ifan_what
== RTM_IEEE80211_REPLAY
) {
1546 printf(" key rsc %#" PRIx64
1547 " frame rsc %#" PRIx64
,
1548 ev
.replay
.iev_keyrsc
, ev
.replay
.iev_rsc
);
1556 case RTM_IFANNOUNCE
:
1557 ifan
= (struct if_announcemsghdr
*)rtm
;
1558 printf("if# %d, what: ", ifan
->ifan_index
);
1559 switch (ifan
->ifan_what
) {
1563 case IFAN_DEPARTURE
:
1564 printf("departure");
1567 printf("#%d", ifan
->ifan_what
);
1576 printf("pid: %ld, seq %d, errno %d, flags:",
1577 (long)rtm
->rtm_pid
, rtm
->rtm_seq
, rtm
->rtm_errno
);
1578 bprintf(stdout
, rtm
->rtm_flags
, routeflags
);
1585 print_getmsg(struct rt_msghdr
*rtm
, int msglen
)
1587 struct sockaddr
*dst
= NULL
, *gate
= NULL
, *mask
= NULL
;
1588 struct sockaddr_dl
*ifp
= NULL
;
1589 struct sockaddr
*sa
;
1593 printf(" route to: %s\n", routename(&so_dst
.sa
));
1594 if (rtm
->rtm_version
!= RTM_VERSION
) {
1595 warnx("routing message version %d not understood",
1599 if (rtm
->rtm_msglen
> msglen
) {
1600 warnx("message length mismatch, in packet %d, returned %d",
1601 rtm
->rtm_msglen
, msglen
);
1603 if (rtm
->rtm_errno
!= 0) {
1604 errno
= rtm
->rtm_errno
;
1605 warn("message indicates error %d", errno
);
1608 cp
= ((char *)(rtm
+ 1));
1610 for (i
= 1; i
!= 0; i
<<= 1)
1611 if (i
& rtm
->rtm_addrs
) {
1612 sa
= (struct sockaddr
*)cp
;
1624 if (sa
->sa_family
== AF_LINK
&&
1625 ((struct sockaddr_dl
*)sa
)->sdl_nlen
)
1626 ifp
= (struct sockaddr_dl
*)sa
;
1631 if (dst
!= NULL
&& mask
!= NULL
)
1632 mask
->sa_family
= dst
->sa_family
; /* XXX */
1634 printf("destination: %s\n", routename(dst
));
1636 int savenflag
= nflag
;
1639 printf(" mask: %s\n", routename(mask
));
1642 if (gate
!= NULL
&& rtm
->rtm_flags
& RTF_GATEWAY
)
1643 printf(" gateway: %s\n", routename(gate
));
1645 printf(" interface: %.*s\n",
1646 ifp
->sdl_nlen
, ifp
->sdl_data
);
1648 bprintf(stdout
, rtm
->rtm_flags
, routeflags
);
1650 #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1651 #define msec(u) (((u) + 500) / 1000) /* usec to msec */
1654 recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire msl,msec iwmax iw");
1655 printf("%8ld%c ", rtm
->rtm_rmx
.rmx_recvpipe
, lock(RPIPE
));
1656 printf("%8ld%c ", rtm
->rtm_rmx
.rmx_sendpipe
, lock(SPIPE
));
1657 printf("%8ld%c ", rtm
->rtm_rmx
.rmx_ssthresh
, lock(SSTHRESH
));
1658 printf("%8ld%c ", msec(rtm
->rtm_rmx
.rmx_rtt
), lock(RTT
));
1659 printf("%8ld%c ", msec(rtm
->rtm_rmx
.rmx_rttvar
), lock(RTTVAR
));
1660 printf("%8ld%c ", rtm
->rtm_rmx
.rmx_hopcount
, lock(HOPCOUNT
));
1661 printf("%8ld%c ", rtm
->rtm_rmx
.rmx_mtu
, lock(MTU
));
1662 if (rtm
->rtm_rmx
.rmx_expire
!= 0) {
1664 clock_gettime(CLOCK_MONOTONIC
, &sp
);
1665 rtm
->rtm_rmx
.rmx_expire
-= sp
.tv_sec
;
1667 printf("%8ld%c ", rtm
->rtm_rmx
.rmx_expire
, lock(EXPIRE
));
1668 printf("%8ld ", rtm
->rtm_rmx
.rmx_msl
);
1669 printf("%5ld ", rtm
->rtm_rmx
.rmx_iwmaxsegs
);
1670 printf("%3ld\n", rtm
->rtm_rmx
.rmx_iwcapsegs
);
1673 #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
1676 else if (rtm
->rtm_addrs
&~ RTA_IGN
) {
1677 printf("sockaddrs: ");
1678 bprintf(stdout
, rtm
->rtm_addrs
, addrnames
);
1685 pmsg_common(struct rt_msghdr
*rtm
)
1687 printf("\nlocks: ");
1688 bprintf(stdout
, rtm
->rtm_rmx
.rmx_locks
, metricnames
);
1690 bprintf(stdout
, rtm
->rtm_inits
, metricnames
);
1691 pmsg_addrs(((char *)(rtm
+ 1)), rtm
->rtm_addrs
);
1695 pmsg_addrs(char *cp
, int addrs
)
1697 struct sockaddr
*sa
;
1704 printf("\nsockaddrs: ");
1705 bprintf(stdout
, addrs
, addrnames
);
1707 for (i
= 1; i
!= 0; i
<<= 1)
1709 sa
= (struct sockaddr
*)cp
;
1710 printf(" %s", routename(sa
));
1718 bprintf(FILE *fp
, int b
, u_char
*str
)
1725 while ((i
= *str
++) != 0) {
1726 if (b
& (1 << (i
-1))) {
1733 for (; (i
= *str
) > 32; str
++)
1744 keyword(const char *cp
)
1746 const struct keytab
*kt
= keywords
;
1748 while (kt
->kt_cp
!= NULL
&& strcmp(kt
->kt_cp
, cp
) != 0)
1754 sodump(sup su
, const char *which
)
1756 switch (su
->sa
.sa_family
) {
1758 printf("%s: link %s; ",
1759 which
, link_ntoa(&su
->sdl
));
1762 printf("%s: inet %s; ",
1763 which
, inet_ntoa(su
->sin
.sin_addr
));
1779 sockaddr(const char *addr
, struct sockaddr
*sa
)
1781 char *cp
= (char *)sa
;
1782 int size
= sa
->sa_len
;
1783 char *cplim
= cp
+ size
;
1784 int byte
= 0, state
= VIRGIN
, new = 0 /* foil gcc */;
1786 memset(cp
, 0, size
);
1789 if ((*addr
>= '0') && (*addr
<= '9')) {
1791 } else if ((*addr
>= 'a') && (*addr
<= 'f')) {
1792 new = *addr
- 'a' + 10;
1793 } else if ((*addr
>= 'A') && (*addr
<= 'F')) {
1794 new = *addr
- 'A' + 10;
1795 } else if (*addr
== '\0')
1800 switch (state
/* | INPUT */) {
1801 case GOTTWO
| DIGIT
:
1802 *cp
++ = byte
; /*FALLTHROUGH*/
1803 case VIRGIN
| DIGIT
:
1804 state
= GOTONE
; byte
= new; continue;
1805 case GOTONE
| DIGIT
:
1806 state
= GOTTWO
; byte
= new + (byte
<< 4); continue;
1807 default: /* | DELIM */
1808 state
= VIRGIN
; *cp
++ = byte
; byte
= 0; continue;
1811 *cp
++ = byte
; /* FALLTHROUGH */
1816 } while (cp
< cplim
);
1817 sa
->sa_len
= cp
- (char *)sa
;