1 /* $NetBSD: route.c,v 1.118 2008/09/10 01:56:22 dyoung 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.118 2008/09/10 01:56:22 dyoung 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 <netiso/iso.h>
60 #include <arpa/inet.h>
78 struct sockaddr_in sin
;
80 struct sockaddr_in6 sin6
;
82 struct sockaddr_at sat
;
83 struct sockaddr_dl sdl
;
85 struct sockaddr_iso siso
;
89 typedef union sockunion
*sup
;
92 union sockunion so_dst
, so_gate
, so_mask
, so_genmask
, so_ifa
, so_ifp
;
95 static char *any_ntoa(const struct sockaddr
*);
96 static const char *route_strerror(int);
97 static void set_metric(const char *, int);
98 static int newroute(int, char *const *);
99 static void inet_makenetandmask(u_int32_t
, struct sockaddr_in
*, struct sou
*);
101 static int inet6_makenetandmask(const struct sockaddr_in6
*, struct sou
*);
103 static int getaddr(int, const char *, struct hostent
**, struct sou
*);
104 static int flushroutes(int, char *const [], int);
105 static int prefixlen(const char *, struct sou
*);
107 static void interfaces(void);
108 static void monitor(void);
109 static int print_getmsg(struct rt_msghdr
*, int, struct sou
*);
110 static const char *linkstate(struct if_msghdr
*);
112 static int rtmsg(int, int, struct sou
*);
113 static void mask_addr(struct sou
*);
114 static void print_rtmsg(struct rt_msghdr
*, int);
115 static void pmsg_common(struct rt_msghdr
*);
116 static void pmsg_addrs(const char *, int);
117 static void bprintf(FILE *, int, const char *);
118 static void sodump(sup
, const char *);
119 static void sockaddr(const char *, struct sockaddr
*);
123 int forcehost
, forcenet
, doflush
, nflag
, af
, qflag
, tflag
, Sflag
;
124 int iflag
, verbose
, aflen
= sizeof(struct sockaddr_in
);
125 int locking
, lockrest
, debugonly
, shortoutput
;
126 struct rt_metrics rt_metrics
;
128 short ns_nullh
[] = {0,0,0};
129 short ns_bh
[] = {-1,-1,-1};
133 usage(const char *cp
)
137 warnx("botched keyword: %s", cp
);
138 (void)fprintf(stderr
,
139 "Usage: %s [ -fnqSsv ] cmd [[ -<qualifers> ] args ]\n",
145 #define PRIETHER "02x:%02x:%02x:%02x:%02x:%02x"
146 #define PRIETHER_ARGS(__enaddr) (__enaddr)[0], (__enaddr)[1], (__enaddr)[2], \
147 (__enaddr)[3], (__enaddr)[4], (__enaddr)[5]
149 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
150 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
153 main(int argc
, char * const *argv
)
160 while ((ch
= getopt(argc
, argv
, "dfnqSstv")) != -1)
196 sock
= open("/dev/null", O_WRONLY
, 0);
198 sock
= socket(PF_ROUTE
, SOCK_RAW
, 0);
200 err(EXIT_FAILURE
, "socket");
218 (void)flushroutes(1, argv
, 0);
219 return newroute(argc
, argv
);
232 return flushroutes(argc
, argv
, 0);
235 return flushroutes(argc
, argv
, 1);
244 * Purge all entries in the routing tables not
245 * associated with network interfaces.
248 flushroutes(int argc
, char * const argv
[], int doall
)
252 int flags
, mib
[6], rlen
, seqno
;
253 char *buf
, *next
, *lim
;
255 struct rt_msghdr
*rtm
;
259 shutdown(sock
, SHUT_RD
); /* Don't want to read back our messages */
260 parse_show_opts(argc
, argv
, &af
, &flags
, &afname
, false);
263 mib
[2] = 0; /* protocol */
264 mib
[3] = 0; /* wildcard address family */
265 mib
[4] = NET_RT_DUMP
;
266 mib
[5] = 0; /* no flags */
267 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
268 err(EXIT_FAILURE
, "route-sysctl-estimate");
271 if ((buf
= malloc(needed
)) == NULL
)
272 err(EXIT_FAILURE
, "malloc");
273 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0)
274 err(EXIT_FAILURE
, "actual retrieval of routing table");
278 (void)printf("Examining routing table from sysctl\n");
280 printf("(address family %s)\n", afname
);
285 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
286 rtm
= (struct rt_msghdr
*)next
;
287 sa
= (struct sockaddr
*)(rtm
+ 1);
289 print_rtmsg(rtm
, rtm
->rtm_msglen
);
290 if ((rtm
->rtm_flags
& flags
) != flags
)
292 if (!(rtm
->rtm_flags
& (RTF_GATEWAY
| RTF_STATIC
|
293 RTF_LLINFO
)) && !doall
)
295 if (af
!= AF_UNSPEC
&& sa
->sa_family
!= af
)
299 rtm
->rtm_type
= RTM_DELETE
;
300 rtm
->rtm_seq
= seqno
;
301 if ((rlen
= write(sock
, next
, rtm
->rtm_msglen
)) < 0) {
302 warnx("writing to routing socket: %s",
303 route_strerror(errno
));
306 if (rlen
< (int)rtm
->rtm_msglen
) {
307 warnx("write to routing socket, got %d for rlen", rlen
);
314 print_rtmsg(rtm
, rlen
);
316 (void)printf("%-20.20s ",
317 routename(sa
, NULL
, rtm
->rtm_flags
));
318 sa
= (struct sockaddr
*)(ROUNDUP(sa
->sa_len
) +
320 (void)printf("%-20.20s ",
321 routename(sa
, NULL
, RTF_HOST
));
322 (void)printf("done\n");
330 static char hexlist
[] = "0123456789abcdef";
333 any_ntoa(const struct sockaddr
*sa
)
335 static char obuf
[3 * 256];
341 len
= sa
->sa_len
- offsetof(struct sockaddr
, sa_data
);
343 len
= sa
->sa_len
- ((struct sockaddr
*)&sa
->sa_data
- sa
);
349 *out
++ = hexlist
[(*in
>> 4) & 15];
350 *out
++ = hexlist
[(*in
++) & 15];
358 netmask_length(struct sockaddr
*nm
, int family
)
361 /* number of bits in a nibble */
362 _t
[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 },
363 /* good nibbles are 1111, 1110, 1100, 1000, 0000 */
364 _g
[] = { 1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,1 };
365 int mask
, good
, zeroes
, maskbytes
, bit
, i
;
366 unsigned char *maskdata
;
377 struct sockaddr_in
*nsin
= (struct sockaddr_in
*)nm
;
378 maskdata
= (unsigned char *)&nsin
->sin_addr
;
379 maskbytes
= nsin
->sin_len
-
380 ((caddr_t
)&nsin
->sin_addr
- (caddr_t
)nsin
);
384 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)nm
;
385 maskdata
= (unsigned char *)&sin6
->sin6_addr
;
386 maskbytes
= sin6
->sin6_len
-
387 ((caddr_t
)&sin6
->sin6_addr
- (caddr_t
)sin6
);
395 * Count the bits in the nibbles of the mask, and marking the
396 * netmask as not good (or at best, non-standard and very
397 * discouraged, in the case of AF_INET) if we find either of
398 * a nibble with non-contiguous bits, or a non-zero nibble
399 * after we've found a zero nibble.
401 for (i
= 0; i
< maskbytes
; i
++) {
403 mask
+= bit
= _t
[maskdata
[i
] >> 4];
404 good
&= _g
[maskdata
[i
] >> 4];
410 mask
+= bit
= _t
[maskdata
[i
] & 0xf];
411 good
&= _g
[maskdata
[i
] & 0xf];
419 * Always return the number of bits found, but as a negative
420 * if the mask wasn't one we like.
422 return good
? mask
: -mask
;
426 netmask_string(const struct sockaddr
*mask
, int len
, int family
)
428 static char smask
[INET6_ADDRSTRLEN
];
429 struct sockaddr_in nsin
;
430 struct sockaddr_in6 nsin6
;
433 snprintf(smask
, sizeof(smask
), "%d", len
);
437 memset(&nsin
, 0, sizeof(nsin
));
438 memcpy(&nsin
, mask
, mask
->sa_len
);
439 snprintf(smask
, sizeof(smask
), "%s",
440 inet_ntoa(nsin
.sin_addr
));
443 memset(&nsin6
, 0, sizeof(nsin6
));
444 memcpy(&nsin6
, mask
, mask
->sa_len
);
445 inet_ntop(family
, &nsin6
.sin6_addr
, smask
,
449 snprintf(smask
, sizeof(smask
), "%s", any_ntoa(mask
));
457 routename(const struct sockaddr
*sa
, struct sockaddr
*nm
, int flags
)
460 static char line
[50];
462 static char domain
[MAXHOSTNAMELEN
+ 1];
463 static int first
= 1;
467 if ((flags
& RTF_HOST
) == 0)
468 return netname(sa
, nm
);
472 if (gethostname(domain
, MAXHOSTNAMELEN
) == 0 &&
473 (cp
= strchr(domain
, '.')))
474 (void)strlcpy(domain
, cp
+ 1, sizeof(domain
));
480 strlcpy(line
, "default", sizeof(line
));
481 else switch (sa
->sa_family
) {
484 in
= ((const struct sockaddr_in
*)sa
)->sin_addr
;
485 nml
= netmask_length(nm
, AF_INET
);
488 if (in
.s_addr
== INADDR_ANY
|| sa
->sa_len
< 4) {
492 static char notdefault
[sizeof(NOTDEFSTRING
)];
494 snprintf(notdefault
, sizeof(notdefault
),
496 netmask_string(nm
, nml
, AF_INET
));
500 if (cp
== 0 && !nflag
) {
501 hp
= gethostbyaddr((char *)&in
, sizeof(struct in_addr
),
505 if ((ccp
= strchr(hp
->h_name
, '.')) &&
506 !strcmp(ccp
+ 1, domain
))
512 (void)strlcpy(line
, cp
, sizeof(line
));
514 (void)strlcpy(line
, inet_ntoa(in
), sizeof(line
));
518 return link_ntoa((const struct sockaddr_dl
*)sa
);
523 struct sockaddr_in6 sin6
;
525 char nihost
[NI_MAXHOST
];
529 niflags
|= NI_NUMERICHOST
;
530 memset(&sin6
, 0, sizeof(sin6
));
531 memcpy(&sin6
, sa
, sa
->sa_len
);
532 sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
533 sin6
.sin6_family
= AF_INET6
;
535 if (sa
->sa_len
== sizeof(struct sockaddr_in6
) &&
536 (IN6_IS_ADDR_LINKLOCAL(&sin6
.sin6_addr
) ||
537 IN6_IS_ADDR_MC_LINKLOCAL(&sin6
.sin6_addr
)) &&
538 sin6
.sin6_scope_id
== 0) {
540 ntohs(*(u_int16_t
*)&sin6
.sin6_addr
.s6_addr
[2]);
541 sin6
.sin6_addr
.s6_addr
[2] = 0;
542 sin6
.sin6_addr
.s6_addr
[3] = 0;
545 nml
= netmask_length(nm
, AF_INET6
);
546 if (IN6_IS_ADDR_UNSPECIFIED(&sin6
.sin6_addr
)) {
548 strlcpy(line
, "::", sizeof(line
));
550 /* noncontiguous never happens in ipv6 */
551 snprintf(line
, sizeof(line
), "::/%d", nml
);
553 else if (getnameinfo((struct sockaddr
*)&sin6
, sin6
.sin6_len
,
554 nihost
, sizeof(nihost
), NULL
, 0, niflags
) != 0)
555 strlcpy(line
, "invalid", sizeof(line
));
558 if (!nflag
&& (ccp
= strchr(nihost
, '.')) &&
559 strcmp(ccp
+ 1, domain
) == 0)
561 strlcpy(line
, nihost
, sizeof(line
));
569 (void)snprintf(line
, sizeof line
, "iso %s",
570 iso_ntoa(&((const struct sockaddr_iso
*)sa
)->siso_addr
));
574 (void)snprintf(line
, sizeof(line
), "atalk %d.%d",
575 ((const struct sockaddr_at
*)sa
)->sat_addr
.s_net
,
576 ((const struct sockaddr_at
*)sa
)->sat_addr
.s_node
);
581 (void)snprintf(line
, sizeof line
, "(%d) %s",
582 sa
->sa_family
, any_ntoa(sa
));
590 * Return the name of the network whose address is given.
591 * The address is assumed to be that of a net or subnet, not a host.
594 netname(const struct sockaddr
*sa
, struct sockaddr
*nm
)
597 static char line
[50];
598 struct netent
*np
= 0;
601 int subnetshift
, nml
;
604 switch (sa
->sa_family
) {
607 in
= ((const struct sockaddr_in
*)sa
)->sin_addr
;
608 i
= ntohl(in
.s_addr
);
609 nml
= netmask_length(nm
, AF_INET
);
614 static char notdefault
[sizeof(NOTDEFSTRING
)];
616 snprintf(notdefault
, sizeof(notdefault
),
618 netmask_string(nm
, nml
, AF_INET
));
624 mask
= IN_CLASSA_NET
;
626 } else if (IN_CLASSB(i
)) {
627 mask
= IN_CLASSB_NET
;
630 mask
= IN_CLASSC_NET
;
634 * If there are more bits than the standard mask
635 * would suggest, subnets must be in use.
636 * Guess at the subnet mask, assuming reasonable
637 * width subnet fields.
640 mask
= (int32_t)mask
>> subnetshift
;
642 while ((mask
& 1) == 0)
643 mask
>>= 1, net
>>= 1;
644 np
= getnetbyaddr(net
, AF_INET
);
649 (void)strlcpy(line
, cp
, sizeof(line
));
652 strlcpy(line
, inet_ntoa(in
), sizeof(line
));
654 snprintf(line
, sizeof(line
), "%s&%s",
656 netmask_string(nm
, nml
, AF_INET
));
658 snprintf(line
, sizeof(line
), "%s/%d",
665 return link_ntoa((const struct sockaddr_dl
*)sa
);
670 struct sockaddr_in6 sin6
;
675 niflags
|= NI_NUMERICHOST
;
676 memset(&sin6
, 0, sizeof(sin6
));
677 memcpy(&sin6
, sa
, sa
->sa_len
);
678 sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
679 sin6
.sin6_family
= AF_INET6
;
681 if (sa
->sa_len
== sizeof(struct sockaddr_in6
) &&
682 (IN6_IS_ADDR_LINKLOCAL(&sin6
.sin6_addr
) ||
683 IN6_IS_ADDR_MC_LINKLOCAL(&sin6
.sin6_addr
)) &&
684 sin6
.sin6_scope_id
== 0) {
686 ntohs(*(u_int16_t
*)&sin6
.sin6_addr
.s6_addr
[2]);
687 sin6
.sin6_addr
.s6_addr
[2] = 0;
688 sin6
.sin6_addr
.s6_addr
[3] = 0;
691 nml
= netmask_length(nm
, AF_INET6
);
692 if (IN6_IS_ADDR_UNSPECIFIED(&sin6
.sin6_addr
)) {
694 strlcpy(line
, "::", sizeof(line
));
696 /* noncontiguous never happens in ipv6 */
697 snprintf(line
, sizeof(line
), "::/%d", nml
);
699 else if (getnameinfo((struct sockaddr
*)&sin6
, sin6
.sin6_len
,
700 line
, sizeof(line
), NULL
, 0, niflags
) != 0)
701 strlcpy(line
, "invalid", sizeof(line
));
708 (void)snprintf(line
, sizeof line
, "iso %s",
709 iso_ntoa(&((const struct sockaddr_iso
*)sa
)->siso_addr
));
713 (void)snprintf(line
, sizeof(line
), "atalk %d.%d",
714 ((const struct sockaddr_at
*)sa
)->sat_addr
.s_net
,
715 ((const struct sockaddr_at
*)sa
)->sat_addr
.s_node
);
720 (void)snprintf(line
, sizeof line
, "af %d: %s",
721 sa
->sa_family
, any_ntoa(sa
));
728 route_strerror(int error
)
733 return "not in table";
735 return "entry in use";
737 return "routing table overflow";
739 return strerror(error
);
744 set_metric(const char *value
, int key
)
747 u_long noval
, *valp
= &noval
;
750 #define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break
751 caseof(K_MTU
, RTV_MTU
, rmx_mtu
);
752 caseof(K_HOPCOUNT
, RTV_HOPCOUNT
, rmx_hopcount
);
753 caseof(K_EXPIRE
, RTV_EXPIRE
, rmx_expire
);
754 caseof(K_RECVPIPE
, RTV_RPIPE
, rmx_recvpipe
);
755 caseof(K_SENDPIPE
, RTV_SPIPE
, rmx_sendpipe
);
756 caseof(K_SSTHRESH
, RTV_SSTHRESH
, rmx_ssthresh
);
757 caseof(K_RTT
, RTV_RTT
, rmx_rtt
);
758 caseof(K_RTTVAR
, RTV_RTTVAR
, rmx_rttvar
);
761 if (lockrest
|| locking
)
762 rt_metrics
.rmx_locks
|= flag
;
765 *valp
= strtoul(value
, NULL
, 0);
769 newroute(int argc
, char *const *argv
)
771 const char *cmd
, *dest
= "", *gateway
= "";
772 int ishost
= 0, ret
, attempts
, oerrno
, flags
= RTF_STATIC
;
774 struct hostent
*hp
= 0;
775 struct sou sou
, *soup
= &sou
;
777 memset(&sou
, 0, sizeof(sou
));
782 shutdown(sock
, SHUT_RD
); /* Don't want to read back our messages */
784 if (**(++argv
)== '-') {
785 switch (key
= keyword(1 + *argv
)) {
789 aflen
= sizeof(union sockunion
);
795 aflen
= sizeof(struct sockaddr_at
);
801 aflen
= sizeof(struct sockaddr_in
);
807 aflen
= sizeof(struct sockaddr_in6
);
813 aflen
= sizeof(struct sockaddr_dl
);
820 aflen
= sizeof(struct sockaddr_iso
);
829 flags
&= ~RTF_STATIC
;
847 flags
|= RTF_BLACKHOLE
;
853 flags
&= ~RTF_CLONED
;
862 flags
|= RTF_CLONING
;
865 flags
&= ~RTF_CLONING
;
868 flags
|= RTF_XRESOLVE
;
876 (void)getaddr(RTA_IFA
, *++argv
, 0, soup
);
881 (void)getaddr(RTA_IFP
, *++argv
, 0, soup
);
886 (void)getaddr(RTA_GENMASK
, *++argv
, 0, soup
);
891 (void)getaddr(RTA_GATEWAY
, *++argv
, 0, soup
);
896 ishost
= getaddr(RTA_DST
, *++argv
, &hp
, soup
);
902 (void)getaddr(RTA_NETMASK
, *++argv
, 0, soup
);
910 ishost
= prefixlen(*++argv
, soup
);
922 set_metric(*++argv
, key
);
928 if ((rtm_addrs
& RTA_DST
) == 0) {
930 ishost
= getaddr(RTA_DST
, *argv
, &hp
, soup
);
931 } else if ((rtm_addrs
& RTA_GATEWAY
) == 0) {
933 (void)getaddr(RTA_GATEWAY
, *argv
, &hp
, soup
);
938 if (strcmp(*argv
, "0") == 0) {
941 "old usage of trailing 0",
942 "assuming route to if");
948 } else if (ret
> 0 && ret
< 10) {
951 "old usage of trailing digit",
952 "assuming route via gateway");
957 (void)getaddr(RTA_NETMASK
, *argv
, 0, soup
);
961 if (forcehost
&& forcenet
)
962 errx(EXIT_FAILURE
, "-host and -net conflict");
971 flags
|= RTF_GATEWAY
;
972 for (attempts
= 1; ; attempts
++) {
974 if ((ret
= rtmsg(*cmd
, flags
, soup
)) == 0)
976 if (errno
!= ENETUNREACH
&& errno
!= ESRCH
)
978 if (af
== AF_INET
&& *gateway
&& hp
&& hp
->h_addr_list
[1]) {
980 memmove(&soup
->so_gate
.sin
.sin_addr
, hp
->h_addr_list
[0],
989 (void)printf("%s %s %s", cmd
, ishost
? "host" : "net", dest
);
991 (void)printf(": gateway %s", gateway
);
992 if (attempts
> 1 && ret
== 0 && af
== AF_INET
)
993 (void)printf(" (%s)",
994 inet_ntoa(soup
->so_gate
.sin
.sin_addr
));
999 (void)printf(": %s\n", route_strerror(oerrno
));
1005 inet_makenetandmask(const u_int32_t net
, struct sockaddr_in
* const isin
,
1008 struct sockaddr_in
*sin
;
1009 u_int32_t addr
, mask
= 0;
1012 rtm_addrs
|= RTA_NETMASK
;
1015 else if (net
< 128) {
1016 addr
= net
<< IN_CLASSA_NSHIFT
;
1017 mask
= IN_CLASSA_NET
;
1018 } else if (net
< 192) {
1019 addr
= net
<< IN_CLASSA_NSHIFT
;
1020 mask
= IN_CLASSB_NET
;
1021 } else if (net
< 224) {
1022 addr
= net
<< IN_CLASSA_NSHIFT
;
1023 mask
= IN_CLASSC_NET
;
1024 } else if (net
< 256) {
1025 addr
= net
<< IN_CLASSA_NSHIFT
;
1026 mask
= IN_CLASSD_NET
;
1027 } else if (net
< 49152) { /* 192 * 256 */
1028 addr
= net
<< IN_CLASSB_NSHIFT
;
1029 mask
= IN_CLASSB_NET
;
1030 } else if (net
< 57344) { /* 224 * 256 */
1031 addr
= net
<< IN_CLASSB_NSHIFT
;
1032 mask
= IN_CLASSC_NET
;
1033 } else if (net
< 65536) {
1034 addr
= net
<< IN_CLASSB_NSHIFT
;
1035 mask
= IN_CLASSB_NET
;
1036 } else if (net
< 14680064L) { /* 224 * 65536 */
1037 addr
= net
<< IN_CLASSC_NSHIFT
;
1038 mask
= IN_CLASSC_NET
;
1039 } else if (net
< 16777216L) {
1040 addr
= net
<< IN_CLASSC_NSHIFT
;
1041 mask
= IN_CLASSD_NET
;
1044 if ((addr
& IN_CLASSA_HOST
) == 0)
1045 mask
= IN_CLASSA_NET
;
1046 else if ((addr
& IN_CLASSB_HOST
) == 0)
1047 mask
= IN_CLASSB_NET
;
1048 else if ((addr
& IN_CLASSC_HOST
) == 0)
1049 mask
= IN_CLASSC_NET
;
1053 isin
->sin_addr
.s_addr
= htonl(addr
);
1054 sin
= &soup
->so_mask
.sin
;
1055 sin
->sin_addr
.s_addr
= htonl(mask
);
1057 sin
->sin_family
= 0;
1058 cp
= (char *)(&sin
->sin_addr
+ 1);
1059 while (*--cp
== 0 && cp
> (char *)sin
)
1061 sin
->sin_len
= 1 + cp
- (char *)sin
;
1062 sin
->sin_family
= AF_INET
;
1067 * XXX the function may need more improvement...
1070 inet6_makenetandmask(const struct sockaddr_in6
* const sin6
, struct sou
*soup
)
1073 struct in6_addr in6
;
1076 if (IN6_IS_ADDR_UNSPECIFIED(&sin6
->sin6_addr
) &&
1077 sin6
->sin6_scope_id
== 0) {
1079 } else if ((sin6
->sin6_addr
.s6_addr
[0] & 0xe0) == 0x20) {
1080 /* aggregatable global unicast - RFC2374 */
1081 memset(&in6
, 0, sizeof(in6
));
1082 if (!memcmp(&sin6
->sin6_addr
.s6_addr
[8], &in6
.s6_addr
[8], 8))
1086 if (!plen
|| strcmp(plen
, "128") == 0)
1089 rtm_addrs
|= RTA_NETMASK
;
1090 (void)prefixlen(plen
, soup
);
1097 * Interpret an argument as a network address of some kind,
1098 * returning 1 if a host address, 0 if a network address.
1101 getaddr(int which
, const char *s
, struct hostent
**hpp
, struct sou
*soup
)
1108 int afamily
; /* local copy of af so we can change it */
1110 if (af
== AF_UNSPEC
) {
1112 aflen
= sizeof(struct sockaddr_in
);
1121 su
= &soup
->so_gate
;
1124 su
= &soup
->so_mask
;
1127 su
= &soup
->so_genmask
;
1135 su
->sa
.sa_family
= af
;
1139 usage("Internal Error");
1142 su
->sa
.sa_len
= aflen
;
1143 su
->sa
.sa_family
= afamily
; /* cases that don't want it have left already */
1144 if (strcmp(s
, "default") == 0) {
1148 (void)getaddr(RTA_NETMASK
, s
, 0, soup
);
1160 struct addrinfo hints
, *res
;
1163 if (which
== RTA_DST
&& (slash
= (strrchr(s
, '/'))) != 0)
1165 memset(&hints
, 0, sizeof(hints
));
1166 hints
.ai_family
= afamily
; /*AF_INET6*/
1167 hints
.ai_flags
= AI_NUMERICHOST
;
1168 hints
.ai_socktype
= SOCK_DGRAM
; /*dummy*/
1169 if (getaddrinfo(s
, "0", &hints
, &res
) != 0) {
1175 if (getaddrinfo(s
, "0", &hints
, &res
) != 0)
1176 errx(EXIT_FAILURE
, "%s: bad value", s
);
1180 if (sizeof(su
->sin6
) != res
->ai_addrlen
)
1181 errx(EXIT_FAILURE
, "%s: bad value", s
);
1184 "%s: address resolved to multiple values", s
);
1186 memcpy(&su
->sin6
, res
->ai_addr
, sizeof(su
->sin6
));
1189 if ((IN6_IS_ADDR_LINKLOCAL(&su
->sin6
.sin6_addr
) ||
1190 IN6_IS_ADDR_MC_LINKLOCAL(&su
->sin6
.sin6_addr
)) &&
1191 su
->sin6
.sin6_scope_id
) {
1192 *(u_int16_t
*)&su
->sin6
.sin6_addr
.s6_addr
[2] =
1193 htons(su
->sin6
.sin6_scope_id
);
1194 su
->sin6
.sin6_scope_id
= 0;
1197 if (hints
.ai_flags
== AI_NUMERICHOST
) {
1199 return prefixlen(slash
+ 1, soup
);
1200 if (which
== RTA_DST
)
1201 return inet6_makenetandmask(&su
->sin6
, soup
);
1210 su
->siso
.siso_addr
= *iso_addr(s
);
1211 if (which
== RTA_NETMASK
|| which
== RTA_GENMASK
) {
1212 const char *cp
= TSEL(&su
->siso
);
1213 su
->siso
.siso_nlen
= 0;
1214 do {--cp
;} while ((cp
> (char *)su
) && (*cp
== 0));
1215 su
->siso
.siso_len
= 1 + cp
- (char *)su
;
1221 su
->sa
.sa_len
= sizeof(*su
);
1222 sockaddr(s
, &su
->sa
);
1227 t
= strchr (s
, '.');
1230 errx(EXIT_FAILURE
, "bad address: %s", s
);
1235 su
->sat
.sat_addr
.s_net
= val
;
1239 su
->sat
.sat_addr
.s_node
= val
;
1240 rtm_addrs
|= RTA_NETMASK
;
1241 return(forcehost
|| su
->sat
.sat_addr
.s_node
!= 0);
1245 link_addr(s
, &su
->sdl
);
1257 if ((t
= strchr(s
, '/')) != NULL
&& which
== RTA_DST
) {
1259 if (forcenet
== 0) {
1260 if ((val
= inet_addr(s
)) != INADDR_NONE
) {
1261 inet_makenetandmask(htonl(val
), &su
->sin
, soup
);
1262 return prefixlen(&t
[1], soup
);
1265 if ((val
= inet_network(s
)) != INADDR_NONE
) {
1266 inet_makenetandmask(val
, &su
->sin
, soup
);
1267 return prefixlen(&t
[1], soup
);
1272 if (inet_aton(s
, &su
->sin
.sin_addr
) &&
1273 (which
!= RTA_DST
|| forcenet
== 0)) {
1274 val
= su
->sin
.sin_addr
.s_addr
;
1275 if (inet_lnaof(su
->sin
.sin_addr
) != INADDR_ANY
)
1282 if ((val
= inet_network(s
)) != INADDR_NONE
||
1283 ((np
= getnetbyname(s
)) != NULL
&& (val
= np
->n_net
) != 0)) {
1285 if (which
== RTA_DST
)
1286 inet_makenetandmask(val
, &su
->sin
, soup
);
1289 hp
= gethostbyname(s
);
1292 su
->sin
.sin_family
= hp
->h_addrtype
;
1293 memmove(&su
->sin
.sin_addr
, hp
->h_addr
, hp
->h_length
);
1296 errx(EXIT_FAILURE
, "%s: bad value", s
);
1301 prefixlen(const char *s
, struct sou
*soup
)
1303 int len
= atoi(s
), q
, r
;
1308 max
= sizeof(struct in_addr
) * 8;
1312 max
= sizeof(struct in6_addr
) * 8;
1316 errx(EXIT_FAILURE
, "prefixlen is not supported with af %d", af
);
1320 rtm_addrs
|= RTA_NETMASK
;
1321 if (len
< -1 || len
> max
)
1322 errx(EXIT_FAILURE
, "%s: bad value", s
);
1328 memset(&soup
->so_mask
, 0, sizeof(soup
->so_mask
));
1329 soup
->so_mask
.sin
.sin_family
= AF_INET
;
1330 soup
->so_mask
.sin
.sin_len
= sizeof(struct sockaddr_in
);
1331 soup
->so_mask
.sin
.sin_addr
.s_addr
= (len
== 0 ? 0
1332 : htonl(0xffffffff << (32 - len
)));
1336 soup
->so_mask
.sin6
.sin6_family
= AF_INET6
;
1337 soup
->so_mask
.sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
1338 memset(&soup
->so_mask
.sin6
.sin6_addr
, 0,
1339 sizeof(soup
->so_mask
.sin6
.sin6_addr
));
1341 memset(&soup
->so_mask
.sin6
.sin6_addr
, 0xff, q
);
1343 *((u_char
*)&soup
->so_mask
.sin6
.sin6_addr
+ q
) =
1344 (0xff00 >> r
) & 0xff;
1357 char *buf
, *lim
, *next
;
1358 struct rt_msghdr
*rtm
;
1362 mib
[2] = 0; /* protocol */
1363 mib
[3] = 0; /* wildcard address family */
1364 mib
[4] = NET_RT_IFLIST
;
1365 mib
[5] = 0; /* no flags */
1366 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
1367 err(EXIT_FAILURE
, "route-sysctl-estimate");
1369 if ((buf
= malloc(needed
)) == NULL
)
1370 err(EXIT_FAILURE
, "malloc");
1371 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0) {
1373 "actual retrieval of interface table");
1376 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
1377 rtm
= (struct rt_msghdr
*)next
;
1378 print_rtmsg(rtm
, rtm
->rtm_msglen
);
1390 struct rt_msghdr hdr
;
1400 n
= read(sock
, &u
, sizeof(u
));
1402 (void)printf("got message of size %d on %s", n
, ctime(&now
));
1403 print_rtmsg(&u
.hdr
, n
);
1411 struct rt_msghdr m_rtm
;
1416 rtmsg(int cmd
, int flags
, struct sou
*soup
)
1420 char *cp
= m_rtmsg
.m_space
;
1423 #define NEXTADDR(w, u) \
1424 if (rtm_addrs & (w)) {\
1425 l = ROUNDUP(u.sa.sa_len); memmove(cp, &(u), l); cp += l;\
1426 if (verbose && ! shortoutput) sodump(&(u),#u);\
1430 memset(&m_rtmsg
, 0, sizeof(m_rtmsg
));
1433 else if (cmd
== 'c')
1435 else if (cmd
== 'g') {
1440 if (soup
->so_ifp
.sa
.sa_family
== AF_UNSPEC
) {
1441 soup
->so_ifp
.sa
.sa_family
= AF_LINK
;
1442 soup
->so_ifp
.sa
.sa_len
= sizeof(struct sockaddr_dl
);
1443 rtm_addrs
|= RTA_IFP
;
1448 #define rtm m_rtmsg.m_rtm
1450 rtm
.rtm_flags
= flags
;
1451 rtm
.rtm_version
= RTM_VERSION
;
1452 rtm
.rtm_seq
= ++seq
;
1453 rtm
.rtm_addrs
= rtm_addrs
;
1454 rtm
.rtm_rmx
= rt_metrics
;
1455 rtm
.rtm_inits
= rtm_inits
;
1457 if (rtm_addrs
& RTA_NETMASK
)
1459 NEXTADDR(RTA_DST
, soup
->so_dst
);
1460 NEXTADDR(RTA_GATEWAY
, soup
->so_gate
);
1461 NEXTADDR(RTA_NETMASK
, soup
->so_mask
);
1462 NEXTADDR(RTA_GENMASK
, soup
->so_genmask
);
1463 NEXTADDR(RTA_IFP
, soup
->so_ifp
);
1464 NEXTADDR(RTA_IFA
, soup
->so_ifa
);
1465 rtm
.rtm_msglen
= l
= cp
- (char *)&m_rtmsg
;
1466 if (verbose
&& ! shortoutput
) {
1469 print_rtmsg(&rtm
, l
);
1473 if ((rlen
= write(sock
, (char *)&m_rtmsg
, l
)) < 0) {
1474 warnx("writing to routing socket: %s", route_strerror(errno
));
1478 warnx("write to routing socket, got %d for rlen", rlen
);
1482 if (cmd
== RTM_GET
) {
1484 l
= read(sock
, (char *)&m_rtmsg
, sizeof(m_rtmsg
));
1485 } while (l
> 0 && (rtm
.rtm_seq
!= seq
|| rtm
.rtm_pid
!= pid
));
1487 err(EXIT_FAILURE
, "read from routing socket");
1489 return print_getmsg(&rtm
, l
, soup
);
1497 mask_addr(struct sou
*soup
)
1499 int olen
= soup
->so_mask
.sa
.sa_len
;
1500 char *cp1
= olen
+ (char *)&soup
->so_mask
, *cp2
;
1502 for (soup
->so_mask
.sa
.sa_len
= 0; cp1
> (char *)&soup
->so_mask
; )
1504 soup
->so_mask
.sa
.sa_len
= 1 + cp1
- (char *)&soup
->so_mask
;
1507 if ((rtm_addrs
& RTA_DST
) == 0)
1509 switch (soup
->so_dst
.sa
.sa_family
) {
1521 olen
= MIN(soup
->so_dst
.siso
.siso_nlen
,
1522 MAX(soup
->so_mask
.sa
.sa_len
- 6, 0));
1526 cp1
= soup
->so_mask
.sa
.sa_len
+ 1 + (char *)&soup
->so_dst
;
1527 cp2
= soup
->so_dst
.sa
.sa_len
+ 1 + (char *)&soup
->so_dst
;
1530 cp2
= soup
->so_mask
.sa
.sa_len
+ 1 + (char *)&soup
->so_mask
;
1531 while (cp1
> soup
->so_dst
.sa
.sa_data
)
1534 switch (soup
->so_dst
.sa
.sa_family
) {
1536 soup
->so_dst
.siso
.siso_nlen
= olen
;
1542 const char *msgtypes
[] = {
1544 "RTM_ADD: Add Route",
1545 "RTM_DELETE: Delete Route",
1546 "RTM_CHANGE: Change Metrics or flags",
1547 "RTM_GET: Report Metrics",
1548 "RTM_LOSING: Kernel Suspects Partitioning",
1549 "RTM_REDIRECT: Told to use different route",
1550 "RTM_MISS: Lookup failed on this address",
1551 "RTM_LOCK: fix specified metrics",
1552 "RTM_OLDADD: caused by SIOCADDRT",
1553 "RTM_OLDDEL: caused by SIOCDELRT",
1554 "RTM_RESOLVE: Route created by cloning",
1555 "RTM_NEWADDR: address being added to iface",
1556 "RTM_DELADDR: address being removed from iface",
1557 "RTM_OIFINFO: iface status change (pre-1.5)",
1558 "RTM_IFINFO: iface status change",
1559 "RTM_IFANNOUNCE: iface arrival/departure",
1560 "RTM_IEEE80211: IEEE80211 wireless event",
1564 const char metricnames
[] =
1565 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
1566 const char routeflags
[] =
1567 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016CLONED\017PROTO2\020PROTO1";
1568 const char ifnetflags
[] =
1569 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2\020MULTICAST";
1570 const char addrnames
[] =
1571 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
1576 linkstate(struct if_msghdr
*ifm
)
1578 static char buf
[64];
1580 switch (ifm
->ifm_data
.ifi_link_state
) {
1581 case LINK_STATE_UNKNOWN
:
1582 return "carrier: unknown";
1583 case LINK_STATE_DOWN
:
1584 return "carrier: no carrier";
1586 return "carrier: active";
1588 (void)snprintf(buf
, sizeof(buf
), "carrier: 0x%x",
1589 ifm
->ifm_data
.ifi_link_state
);
1596 print_rtmsg(struct rt_msghdr
*rtm
, int msglen
)
1598 struct if_msghdr
*ifm
;
1599 struct ifa_msghdr
*ifam
;
1600 struct if_announcemsghdr
*ifan
;
1602 struct ieee80211_join_event join
;
1603 struct ieee80211_leave_event leave
;
1604 struct ieee80211_replay_event replay
;
1605 struct ieee80211_michael_event michael
;
1611 if (rtm
->rtm_version
!= RTM_VERSION
) {
1612 (void)printf("routing message version %d not understood\n",
1616 if (msgtypes
[rtm
->rtm_type
])
1617 (void)printf("%s: ", msgtypes
[rtm
->rtm_type
]);
1619 (void)printf("#%d: ", rtm
->rtm_type
);
1620 (void)printf("len %d, ", rtm
->rtm_msglen
);
1621 switch (rtm
->rtm_type
) {
1623 ifm
= (struct if_msghdr
*)rtm
;
1624 (void)printf("if# %d, %s, flags: ", ifm
->ifm_index
,
1631 bprintf(stdout
, ifm
->ifm_flags
, ifnetflags
);
1632 pmsg_addrs((char *)(ifm
+ 1), ifm
->ifm_addrs
);
1636 ifam
= (struct ifa_msghdr
*)rtm
;
1637 (void)printf("metric %d, flags: ", ifam
->ifam_metric
);
1638 bprintf(stdout
, ifam
->ifam_flags
, routeflags
);
1639 pmsg_addrs((char *)(ifam
+ 1), ifam
->ifam_addrs
);
1642 ifan
= (struct if_announcemsghdr
*)rtm
;
1643 (void)printf("if# %d, what: ", ifan
->ifan_index
);
1644 switch (ifan
->ifan_what
) {
1645 case RTM_IEEE80211_ASSOC
:
1646 printf("associate");
1648 case RTM_IEEE80211_REASSOC
:
1649 printf("re-associate");
1651 case RTM_IEEE80211_DISASSOC
:
1652 printf("disassociate");
1654 case RTM_IEEE80211_SCAN
:
1655 printf("scan complete");
1657 case RTM_IEEE80211_JOIN
:
1658 evlen
= sizeof(ev
.join
);
1661 case RTM_IEEE80211_LEAVE
:
1662 evlen
= sizeof(ev
.leave
);
1665 case RTM_IEEE80211_MICHAEL
:
1666 evlen
= sizeof(ev
.michael
);
1669 case RTM_IEEE80211_REPLAY
:
1670 evlen
= sizeof(ev
.replay
);
1675 printf("#%d", ifan
->ifan_what
);
1678 if (sizeof(*ifan
) + evlen
> ifan
->ifan_msglen
) {
1679 printf(" (truncated)\n");
1682 (void)memcpy(&ev
, (ifan
+ 1), evlen
);
1683 switch (ifan
->ifan_what
) {
1684 case RTM_IEEE80211_JOIN
:
1685 case RTM_IEEE80211_LEAVE
:
1686 printf(" mac %" PRIETHER
,
1687 PRIETHER_ARGS(ev
.join
.iev_addr
));
1689 case RTM_IEEE80211_REPLAY
:
1690 case RTM_IEEE80211_MICHAEL
:
1691 printf(" src %" PRIETHER
" dst %" PRIETHER
1692 " cipher %" PRIu8
" keyix %" PRIu8
,
1693 PRIETHER_ARGS(ev
.replay
.iev_src
),
1694 PRIETHER_ARGS(ev
.replay
.iev_dst
),
1695 ev
.replay
.iev_cipher
,
1696 ev
.replay
.iev_keyix
);
1697 if (ifan
->ifan_what
== RTM_IEEE80211_REPLAY
) {
1698 printf(" key rsc %#" PRIx64
1699 " frame rsc %#" PRIx64
,
1700 ev
.replay
.iev_keyrsc
, ev
.replay
.iev_rsc
);
1708 case RTM_IFANNOUNCE
:
1709 ifan
= (struct if_announcemsghdr
*)rtm
;
1710 (void)printf("if# %d, what: ", ifan
->ifan_index
);
1711 switch (ifan
->ifan_what
) {
1715 case IFAN_DEPARTURE
:
1716 printf("departure");
1719 printf("#%d", ifan
->ifan_what
);
1725 (void)printf("pid %d, seq %d, errno %d, flags: ",
1726 rtm
->rtm_pid
, rtm
->rtm_seq
, rtm
->rtm_errno
);
1727 bprintf(stdout
, rtm
->rtm_flags
, routeflags
);
1734 print_getmsg(struct rt_msghdr
*rtm
, int msglen
, struct sou
*soup
)
1736 struct sockaddr
*dst
= NULL
, *gate
= NULL
, *mask
= NULL
, *ifa
= NULL
;
1737 struct sockaddr_dl
*ifp
= NULL
;
1738 struct sockaddr
*sa
;
1743 (void)printf(" route to: %s\n",
1744 routename(&soup
->so_dst
.sa
, NULL
, RTF_HOST
));
1745 if (rtm
->rtm_version
!= RTM_VERSION
) {
1746 warnx("routing message version %d not understood",
1750 if (rtm
->rtm_msglen
> msglen
) {
1751 warnx("message length mismatch, in packet %d, returned %d",
1752 rtm
->rtm_msglen
, msglen
);
1754 if (rtm
->rtm_errno
) {
1755 warnx("RTM_GET: %s (errno %d)",
1756 strerror(rtm
->rtm_errno
), rtm
->rtm_errno
);
1759 cp
= ((char *)(rtm
+ 1));
1761 for (i
= 1; i
; i
<<= 1)
1762 if (i
& rtm
->rtm_addrs
) {
1763 sa
= (struct sockaddr
*)cp
;
1775 if (sa
->sa_family
== AF_LINK
&&
1776 ((struct sockaddr_dl
*)sa
)->sdl_nlen
)
1777 ifp
= (struct sockaddr_dl
*)sa
;
1786 mask
->sa_family
= dst
->sa_family
; /* XXX */
1787 if (dst
&& ! shortoutput
)
1788 (void)printf("destination: %s\n",
1789 routename(dst
, mask
, RTF_HOST
));
1790 if (mask
&& ! shortoutput
) {
1791 int savenflag
= nflag
;
1794 (void)printf(" mask: %s\n",
1795 routename(mask
, NULL
, RTF_HOST
));
1798 if (gate
&& rtm
->rtm_flags
& RTF_GATEWAY
) {
1801 name
= routename(gate
, NULL
, RTF_HOST
);
1805 (void)printf("%s\n", name
);
1807 (void)printf(" gateway: %s\n", name
);
1809 if (ifa
&& ! shortoutput
)
1810 (void)printf(" local addr: %s\n",
1811 routename(ifa
, NULL
, RTF_HOST
));
1812 if (ifp
&& ! shortoutput
)
1813 (void)printf(" interface: %.*s\n",
1814 ifp
->sdl_nlen
, ifp
->sdl_data
);
1815 if (! shortoutput
) {
1816 (void)printf(" flags: ");
1817 bprintf(stdout
, rtm
->rtm_flags
, routeflags
);
1820 #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1821 #define msec(u) (((u) + 500) / 1000) /* usec to msec */
1823 if (! shortoutput
) {
1824 (void)printf("\n%s\n", "\
1825 recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire");
1826 printf("%8ld%c ", rtm
->rtm_rmx
.rmx_recvpipe
, lock(RPIPE
));
1827 printf("%8ld%c ", rtm
->rtm_rmx
.rmx_sendpipe
, lock(SPIPE
));
1828 printf("%8ld%c ", rtm
->rtm_rmx
.rmx_ssthresh
, lock(SSTHRESH
));
1829 printf("%8ld%c ", msec(rtm
->rtm_rmx
.rmx_rtt
), lock(RTT
));
1830 printf("%8ld%c ", msec(rtm
->rtm_rmx
.rmx_rttvar
), lock(RTTVAR
));
1831 printf("%8ld%c ", rtm
->rtm_rmx
.rmx_hopcount
, lock(HOPCOUNT
));
1832 printf("%8ld%c ", rtm
->rtm_rmx
.rmx_mtu
, lock(MTU
));
1833 if (rtm
->rtm_rmx
.rmx_expire
)
1834 rtm
->rtm_rmx
.rmx_expire
-= time(0);
1835 printf("%8ld%c\n", rtm
->rtm_rmx
.rmx_expire
, lock(EXPIRE
));
1839 #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
1842 return (rtm
->rtm_addrs
& RTF_GATEWAY
) == 0;
1845 else if (rtm
->rtm_addrs
&~ RTA_IGN
) {
1846 (void)printf("sockaddrs: ");
1847 bprintf(stdout
, rtm
->rtm_addrs
, addrnames
);
1856 pmsg_common(struct rt_msghdr
*rtm
)
1858 (void)printf("\nlocks: ");
1859 bprintf(stdout
, rtm
->rtm_rmx
.rmx_locks
, metricnames
);
1860 (void)printf(" inits: ");
1861 bprintf(stdout
, rtm
->rtm_inits
, metricnames
);
1862 pmsg_addrs((char *)(rtm
+ 1), rtm
->rtm_addrs
);
1866 extract_addrs(const char *cp
, int addrs
, const struct sockaddr
*sa
[], int *nmfp
)
1870 for (i
= 0; i
< RTAX_MAX
; i
++) {
1871 if ((1 << i
) & addrs
) {
1872 sa
[i
] = (const struct sockaddr
*)cp
;
1873 if ((i
== RTAX_DST
|| i
== RTAX_IFA
) &&
1875 nmf
= sa
[i
]->sa_family
;
1886 pmsg_addrs(const char *cp
, int addrs
)
1888 const struct sockaddr
*sa
[RTAX_MAX
];
1892 (void)printf("\nsockaddrs: ");
1893 bprintf(stdout
, addrs
, addrnames
);
1894 (void)putchar('\n');
1895 extract_addrs(cp
, addrs
, sa
, &nmf
);
1896 for (i
= 0; i
< RTAX_MAX
; i
++) {
1900 if (i
== RTAX_NETMASK
&& sa
[i
]->sa_len
)
1902 netmask_string(sa
[i
], -1, nmf
));
1905 routename(sa
[i
], NULL
, RTF_HOST
));
1908 (void)putchar('\n');
1909 (void)fflush(stdout
);
1913 bprintf(FILE *fp
, int b
, const char *f
)
1917 const uint8_t *s
= (const uint8_t *)f
;
1921 while ((i
= *s
++) != 0) {
1922 if (b
& (1 << (i
-1))) {
1929 for (; (i
= *s
) > 32; s
++)
1936 (void)putc('>', fp
);
1940 keyword(const char *cp
)
1942 struct keytab
*kt
= keywords
;
1944 while (kt
->kt_cp
&& strcmp(kt
->kt_cp
, cp
))
1950 sodump(sup su
, const char *which
)
1953 char ntop_buf
[NI_MAXHOST
];
1956 switch (su
->sa
.sa_family
) {
1958 (void)printf("%s: inet %s; ",
1959 which
, inet_ntoa(su
->sin
.sin_addr
));
1963 (void)printf("%s: atalk %d.%d; ",
1964 which
, su
->sat
.sat_addr
.s_net
, su
->sat
.sat_addr
.s_node
);
1968 (void)printf("%s: link %s; ",
1969 which
, link_ntoa(&su
->sdl
));
1973 (void)printf("%s: inet6 %s; ",
1974 which
, inet_ntop(AF_INET6
, &su
->sin6
.sin6_addr
,
1975 ntop_buf
, sizeof(ntop_buf
)));
1980 (void)printf("%s: iso %s; ",
1981 which
, iso_ntoa(&su
->siso
.siso_addr
));
1985 (void)printf("%s: (%d) %s; ",
1986 which
, su
->sa
.sa_family
, any_ntoa(&su
->sa
));
1988 (void)fflush(stdout
);
2001 sockaddr(const char *addr
, struct sockaddr
*sa
)
2003 char *cp
= (char *)sa
;
2004 int size
= sa
->sa_len
;
2005 char *cplim
= cp
+ size
;
2006 int byte
= 0, state
= VIRGIN
, new = 0;
2008 (void)memset(cp
, 0, size
);
2011 if ((*addr
>= '0') && (*addr
<= '9')) {
2013 } else if ((*addr
>= 'a') && (*addr
<= 'f')) {
2014 new = *addr
- 'a' + 10;
2015 } else if ((*addr
>= 'A') && (*addr
<= 'F')) {
2016 new = *addr
- 'A' + 10;
2017 } else if (*addr
== 0)
2022 switch (state
/* | INPUT */) {
2023 case GOTTWO
| DIGIT
:
2024 *cp
++ = byte
; /*FALLTHROUGH*/
2025 case VIRGIN
| DIGIT
:
2026 state
= GOTONE
; byte
= new; continue;
2027 case GOTONE
| DIGIT
:
2028 state
= GOTTWO
; byte
= new + (byte
<< 4); continue;
2029 default: /* | DELIM */
2030 state
= VIRGIN
; *cp
++ = byte
; byte
= 0; continue;
2033 *cp
++ = byte
; /* FALLTHROUGH */
2038 } while (cp
< cplim
);
2039 sa
->sa_len
= cp
- (char *)sa
;