]>
git.saurik.com Git - apple/network_cmds.git/blob - route.tproj/route.c
2 * Copyright (c) 2008-2013 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * Copyright (c) 1983, 1989, 1991, 1993
30 * The Regents of the University of California. All rights reserved.
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 #include <sys/cdefs.h>
64 __unused
static const char copyright
[] =
65 "@(#) Copyright (c) 1983, 1989, 1991, 1993\n\
66 The Regents of the University of California. All rights reserved.\n";
69 #include <sys/param.h>
71 #include <sys/socket.h>
72 #include <sys/ioctl.h>
73 #include <sys/sysctl.h>
74 #include <sys/types.h>
77 #include <net/route.h>
78 #include <net/if_dl.h>
79 #include <netinet/in.h>
80 #include <arpa/inet.h>
104 struct sockaddr_in sin
;
106 struct sockaddr_in6 sin6
;
108 struct sockaddr_dl sdl
;
109 struct sockaddr_storage ss
; /* added to avoid memory overrun */
110 } so_dst
, so_gate
, so_mask
, so_genmask
, so_ifa
, so_ifp
;
112 typedef union sockunion
*sup
;
113 int pid
, rtm_addrs
, uid
;
115 int forcehost
, forcenet
, doflush
, nflag
, af
, qflag
, tflag
, keyword();
116 int iflag
, verbose
, aflen
= sizeof (struct sockaddr_in
);
117 int locking
, lockrest
, debugonly
;
118 struct rt_metrics rt_metrics
;
120 unsigned int ifscope
;
122 static const char *route_strerror(int);
123 const char *routename(), *netname();
124 void flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf();
125 void print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr();
126 int getaddr(), rtmsg(), x25_makemask();
128 extern char *iso_ntoa();
131 inet_makenetandmask(in_addr_t net
, struct sockaddr_in
*sin
,
132 struct sockaddr_in
*sin_mask
, in_addr_t bits
);
134 void usage
__P((const char *)) __dead2
;
141 warnx("bad keyword: %s", cp
);
142 (void) fprintf(stderr
,
143 "usage: route [-dnqtv] command [[modifiers] args]\n");
149 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
150 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
162 while ((ch
= getopt(argc
, argv
, "nqdtv")) != -1)
189 s
= open(_PATH_DEVNULL
, O_WRONLY
, 0);
191 s
= socket(PF_ROUTE
, SOCK_RAW
, 0);
193 err(EX_OSERR
, "socket");
196 switch (keyword(*argv
)) {
204 newroute(argc
, argv
);
213 flushroutes(argc
, argv
);
222 * Purge all entries in the routing tables not
223 * associated with network interfaces.
226 flushroutes(argc
, argv
)
231 int mib
[6], rlen
, seqno
;
232 char *buf
, *next
, *lim
;
233 register struct rt_msghdr
*rtm
;
236 errx(EX_NOPERM
, "must be root to alter routing table");
238 shutdown(s
, 0); /* Don't want to read back our messages */
241 if (argc
== 2 && **argv
== '-')
242 switch (keyword(*argv
+ 1)) {
261 mib
[2] = 0; /* protocol */
262 mib
[3] = 0; /* wildcard address family */
263 mib
[4] = NET_RT_DUMP
;
264 mib
[5] = 0; /* no flags */
265 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
266 err(EX_OSERR
, "route-sysctl-estimate");
267 if ((buf
= malloc(needed
)) == NULL
)
268 errx(EX_OSERR
, "malloc failed");
269 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0)
270 err(EX_OSERR
, "route-sysctl-get");
273 (void) printf("Examining routing table from sysctl\n");
275 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
276 rtm
= (struct rt_msghdr
*)next
;
278 print_rtmsg(rtm
, rtm
->rtm_msglen
);
279 if ((rtm
->rtm_flags
& RTF_GATEWAY
) == 0)
282 struct sockaddr
*sa
= (struct sockaddr
*)(rtm
+ 1);
284 if (sa
->sa_family
!= af
)
289 rtm
->rtm_type
= RTM_DELETE
;
290 rtm
->rtm_seq
= seqno
;
291 rlen
= write(s
, next
, rtm
->rtm_msglen
);
292 if (rlen
< (int)rtm
->rtm_msglen
) {
293 warn("write to routing socket");
294 (void) printf("got only %d for rlen\n", rlen
);
301 print_rtmsg(rtm
, rlen
);
303 struct sockaddr
*sa
= (struct sockaddr
*)(rtm
+ 1);
304 (void) printf("%-20.20s ", rtm
->rtm_flags
& RTF_HOST
?
305 routename(sa
) : netname(sa
));
306 sa
= (struct sockaddr
*)(ROUNDUP(sa
->sa_len
) + (char *)sa
);
307 (void) printf("%-20.20s ", routename(sa
));
308 (void) printf("done\n");
318 static char line
[MAXHOSTNAMELEN
+ 1];
320 static char domain
[MAXHOSTNAMELEN
+ 1];
321 static int first
= 1;
325 if (gethostname(domain
, MAXHOSTNAMELEN
) == 0 &&
326 (cp
= index(domain
, '.'))) {
327 domain
[MAXHOSTNAMELEN
] = '\0';
328 (void) memmove(domain
, cp
+ 1, strlen(cp
+ 1) + 1);
334 strlcpy(line
, "default", sizeof(line
));
335 else switch (sa
->sa_family
) {
339 in
= ((struct sockaddr_in
*)sa
)->sin_addr
;
342 if (in
.s_addr
== INADDR_ANY
|| sa
->sa_len
< 4)
344 if (cp
== 0 && !nflag
) {
345 hp
= gethostbyaddr((char *)&in
, sizeof (struct in_addr
),
348 if ((cp
= index(hp
->h_name
, '.')) &&
349 !strcmp(cp
+ 1, domain
))
355 strncpy(line
, cp
, sizeof(line
) - 1);
356 line
[sizeof(line
) - 1] = '\0';
358 /* XXX - why not inet_ntoa()? */
359 #define C(x) (unsigned)((x) & 0xff)
360 in
.s_addr
= ntohl(in
.s_addr
);
361 (void) snprintf(line
, sizeof(line
), "%u.%u.%u.%u", C(in
.s_addr
>> 24),
362 C(in
.s_addr
>> 16), C(in
.s_addr
>> 8), C(in
.s_addr
));
370 struct sockaddr_in6 sin6
; /* use static var for safety */
372 #ifdef NI_WITHSCOPEID
373 niflags
= NI_WITHSCOPEID
;
376 memset(&sin6
, 0, sizeof(sin6
));
377 memcpy(&sin6
, sa
, sa
->sa_len
);
378 sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
379 sin6
.sin6_family
= AF_INET6
;
381 if (sa
->sa_len
== sizeof(struct sockaddr_in6
) &&
382 (IN6_IS_ADDR_LINKLOCAL(&sin6
.sin6_addr
) ||
383 IN6_IS_ADDR_MC_NODELOCAL(&sin6
.sin6_addr
) ||
384 IN6_IS_ADDR_MC_LINKLOCAL(&sin6
.sin6_addr
)) &&
385 sin6
.sin6_scope_id
== 0) {
387 ntohs(*(u_int16_t
*)&sin6
.sin6_addr
.s6_addr
[2]);
388 sin6
.sin6_addr
.s6_addr
[2] = 0;
389 sin6
.sin6_addr
.s6_addr
[3] = 0;
393 niflags
|= NI_NUMERICHOST
;
394 if (getnameinfo((struct sockaddr
*)&sin6
, sin6
.sin6_len
,
395 line
, sizeof(line
), NULL
, 0, niflags
) != 0)
396 strncpy(line
, "invalid", sizeof(line
));
403 return (link_ntoa((struct sockaddr_dl
*)sa
));
406 { u_short
*s
= (u_short
*)sa
;
407 u_short
*slim
= s
+ ((sa
->sa_len
+ 1) >> 1);
408 char *cp
= line
+ snprintf(line
, sizeof(line
), "(%d)", sa
->sa_family
);
409 char *cpe
= line
+ sizeof(line
);
411 while (++s
< slim
&& cp
< cpe
) /* start with sa->sa_data */
412 cp
+= snprintf(cp
, cpe
- cp
, " %x", *s
);
420 * Return the name of the network whose address is given.
421 * The address is assumed to be that of a net, not a host.
428 static char line
[MAXHOSTNAMELEN
+ 1];
429 struct netent
*np
= NULL
;
430 register in_addr_t i
;
432 switch (sa
->sa_family
) {
436 in
= ((struct sockaddr_in
*)sa
)->sin_addr
;
438 i
= in
.s_addr
= ntohl(in
.s_addr
);
442 np
= getnetbyaddr(i
, AF_INET
);
446 #define C(x) (unsigned)((x) & 0xff)
448 strncpy(line
, cp
, sizeof(line
));
449 else if ((in
.s_addr
& 0xffffff) == 0)
450 (void) sprintf(line
, "%u", C(in
.s_addr
>> 24));
451 else if ((in
.s_addr
& 0xffff) == 0)
452 (void) sprintf(line
, "%u.%u", C(in
.s_addr
>> 24),
454 else if ((in
.s_addr
& 0xff) == 0)
455 (void) sprintf(line
, "%u.%u.%u", C(in
.s_addr
>> 24),
456 C(in
.s_addr
>> 16), C(in
.s_addr
>> 8));
458 (void) sprintf(line
, "%u.%u.%u.%u", C(in
.s_addr
>> 24),
459 C(in
.s_addr
>> 16), C(in
.s_addr
>> 8),
467 struct sockaddr_in6 sin6
; /* use static var for safety */
469 #ifdef NI_WITHSCOPEID
470 niflags
= NI_WITHSCOPEID
;
473 memset(&sin6
, 0, sizeof(sin6
));
474 memcpy(&sin6
, sa
, sa
->sa_len
);
475 sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
476 sin6
.sin6_family
= AF_INET6
;
478 if (sa
->sa_len
== sizeof(struct sockaddr_in6
) &&
479 (IN6_IS_ADDR_LINKLOCAL(&sin6
.sin6_addr
) ||
480 IN6_IS_ADDR_MC_NODELOCAL(&sin6
.sin6_addr
) ||
481 IN6_IS_ADDR_MC_LINKLOCAL(&sin6
.sin6_addr
)) &&
482 sin6
.sin6_scope_id
== 0) {
484 ntohs(*(u_int16_t
*)&sin6
.sin6_addr
.s6_addr
[2]);
485 sin6
.sin6_addr
.s6_addr
[2] = 0;
486 sin6
.sin6_addr
.s6_addr
[3] = 0;
490 niflags
|= NI_NUMERICHOST
;
491 if (getnameinfo((struct sockaddr
*)&sin6
, sin6
.sin6_len
,
492 line
, sizeof(line
), NULL
, 0, niflags
) != 0)
493 strncpy(line
, "invalid", sizeof(line
));
500 return (link_ntoa((struct sockaddr_dl
*)sa
));
504 { u_short
*s
= (u_short
*)sa
->sa_data
;
505 u_short
*slim
= s
+ ((sa
->sa_len
+ 1)>>1);
506 char *cp
= line
+ snprintf(line
, sizeof(line
), "af %d:", sa
->sa_family
);
507 char *cpe
= line
+ sizeof(line
);
509 while (s
< slim
&& cp
< cpe
)
510 cp
+= snprintf(cp
, cpe
- cp
, " %x", *s
++);
518 route_strerror(int error
)
523 return "not in table";
525 return "entry in use";
527 return "routing table overflow";
529 return (strerror(error
));
534 set_metric(value
, key
)
539 u_int noval
, *valp
= &noval
;
542 #define caseof(x, y, z) case x: valp = (u_int *)&rt_metrics.z; flag = y; break
543 caseof(K_MTU
, RTV_MTU
, rmx_mtu
);
544 caseof(K_HOPCOUNT
, RTV_HOPCOUNT
, rmx_hopcount
);
545 caseof(K_EXPIRE
, RTV_EXPIRE
, rmx_expire
);
546 caseof(K_RECVPIPE
, RTV_RPIPE
, rmx_recvpipe
);
547 caseof(K_SENDPIPE
, RTV_SPIPE
, rmx_sendpipe
);
548 caseof(K_SSTHRESH
, RTV_SSTHRESH
, rmx_ssthresh
);
549 caseof(K_RTT
, RTV_RTT
, rmx_rtt
);
550 caseof(K_RTTVAR
, RTV_RTTVAR
, rmx_rttvar
);
553 if (lockrest
|| locking
)
554 rt_metrics
.rmx_locks
|= flag
;
563 register char **argv
;
565 char *cmd
, *dest
= "", *gateway
= "";
566 int ishost
= 0, ret
, attempts
, oerrno
, flags
= RTF_STATIC
;
568 struct hostent
*hp
= 0;
571 errx(EX_NOPERM
, "must be root to alter routing table");
575 shutdown(s
, 0); /* Don't want to read back our messages */
577 if (**(++argv
)== '-') {
578 switch (key
= keyword(1 + *argv
)) {
581 aflen
= sizeof(struct sockaddr_dl
);
585 aflen
= sizeof(struct sockaddr_in
);
590 aflen
= sizeof(struct sockaddr_in6
);
595 aflen
= sizeof(union sockunion
);
602 flags
&= ~RTF_STATIC
;
620 flags
|= RTF_BLACKHOLE
;
629 flags
|= RTF_CLONING
;
632 flags
|= RTF_XRESOLVE
;
640 (void) getaddr(RTA_IFA
, *++argv
, 0);
645 (void) getaddr(RTA_IFP
, *++argv
, 0);
650 (void) getaddr(RTA_GENMASK
, *++argv
, 0);
655 (void) getaddr(RTA_GATEWAY
, *++argv
, 0);
660 ishost
= getaddr(RTA_DST
, *++argv
, &hp
);
666 (void) getaddr(RTA_NETMASK
, *++argv
, 0);
674 if (prefixlen(*++argv
) == -1) {
692 set_metric(*++argv
, key
);
697 if ((ifscope
= if_nametoindex(*++argv
)) != 0)
698 flags
|= RTF_IFSCOPE
;
700 errx(1, "bad interface name");
706 if ((rtm_addrs
& RTA_DST
) == 0) {
708 ishost
= getaddr(RTA_DST
, *argv
, &hp
);
709 } else if ((rtm_addrs
& RTA_GATEWAY
) == 0) {
711 (void) getaddr(RTA_GATEWAY
, *argv
, &hp
);
713 (void) getaddr(RTA_NETMASK
, *argv
, 0);
720 if (af
== AF_INET6
) {
721 rtm_addrs
&= ~RTA_NETMASK
;
722 memset((void *)&so_mask
, 0, sizeof(so_mask
));
732 flags
|= RTF_GATEWAY
;
733 if (so_mask
.sin
.sin_family
== AF_INET
) {
734 // make sure the mask is contiguous
736 for (i
= 0; i
< 32; i
++)
737 if (((so_mask
.sin
.sin_addr
.s_addr
) & ntohl((1 << i
))) != 0)
740 if (((so_mask
.sin
.sin_addr
.s_addr
) & ntohl((1 << i
))) == 0)
741 errx(EX_NOHOST
, "invalid mask: %s", inet_ntoa(so_mask
.sin
.sin_addr
));
743 for (attempts
= 1; ; attempts
++) {
745 if ((ret
= rtmsg(*cmd
, flags
)) == 0)
747 if (errno
!= ENETUNREACH
&& errno
!= ESRCH
)
749 if (af
== AF_INET
&& *gateway
&& hp
&& hp
->h_addr_list
[1]) {
751 bcopy(hp
->h_addr_list
[0], &so_gate
.sin
.sin_addr
,
752 MIN(hp
->h_length
, sizeof(so_gate
.sin
.sin_addr
)));
759 (void) printf("%s %s %s", cmd
, ishost
? "host" : "net", dest
);
761 (void) printf(": gateway %s", gateway
);
762 if (attempts
> 1 && ret
== 0 && af
== AF_INET
)
763 (void) printf(" (%s)", inet_ntoa(so_gate
.sin
.sin_addr
));
768 (void)printf(": %s\n", route_strerror(oerrno
));
773 inet_makenetandmask(in_addr_t net
, struct sockaddr_in
*sin
,
774 struct sockaddr_in
*sin_mask
, in_addr_t bits
)
778 rtm_addrs
|= RTA_NETMASK
;
780 * MSB of net should be meaningful. 0/0 is exception.
783 while ((net
& 0xff000000) == 0)
787 * If no /xx was specified we must calculate the
790 if ((bits
== 0) && (net
!= 0)) {
793 for(i
= 0, j
= 0xff; i
< 4; i
++) {
799 /* i holds the first non zero bit */
803 mask
= 0xffffffff << (32 - bits
);
805 sin
->sin_addr
.s_addr
= htonl(net
);
806 sin_mask
->sin_addr
.s_addr
= htonl(mask
);
807 sin_mask
->sin_len
= sizeof(struct sockaddr_in
);
808 sin_mask
->sin_family
= AF_INET
;
813 * XXX the function may need more improvement...
816 inet6_makenetandmask(struct sockaddr_in6
*sin6
, const char *plen
)
821 if (IN6_IS_ADDR_UNSPECIFIED(&sin6
->sin6_addr
) &&
822 sin6
->sin6_scope_id
== 0) {
824 } else if ((sin6
->sin6_addr
.s6_addr
[0] & 0xe0) == 0x20) {
825 /* aggregatable global unicast - RFC2374 */
826 memset(&in6
, 0, sizeof(in6
));
827 if (!memcmp(&sin6
->sin6_addr
.s6_addr
[8],
833 if (plen
== NULL
|| strcmp(plen
, "128") == 0)
835 rtm_addrs
|= RTA_NETMASK
;
842 * Interpret an argument as a network address of some kind,
843 * returning 1 if a host address, 0 if a network address.
846 getaddr(which
, s
, hpp
)
849 struct hostent
**hpp
;
851 register sup su
= NULL
;
856 int afamily
; /* local copy of af so we can change it */
860 aflen
= sizeof(struct sockaddr_in
);
871 struct ifaddrs
*ifap
, *ifa
;
872 struct sockaddr_dl
*sdl
= NULL
;
874 if (getifaddrs(&ifap
))
875 err(1, "getifaddrs");
877 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
878 if (ifa
->ifa_addr
->sa_family
!= AF_LINK
)
881 if (strcmp(s
, ifa
->ifa_name
))
884 sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
886 /* If we found it, then use it */
889 * Copy is safe since we have a
890 * sockaddr_storage member in sockunion{}.
891 * Note that we need to copy before calling
894 memcpy(&su
->sdl
, sdl
, sdl
->sdl_len
);
915 usage("internal error");
918 su
->sa
.sa_len
= aflen
;
919 su
->sa
.sa_family
= afamily
; /* cases that don't want it have left already */
920 if (strcmp(s
, "default") == 0) {
922 * Default is net 0.0.0.0/0
927 /* bzero(su, sizeof(*su)); *//* for readability */
928 (void) getaddr(RTA_NETMASK
, s
, 0);
932 /* bzero(su, sizeof(*su)); *//* for readability */
942 struct addrinfo hints
, *res
;
946 if (which
== RTA_DST
&& (q
= strchr(s
, '/')) != NULL
)
948 memset(&hints
, 0, sizeof(hints
));
949 hints
.ai_family
= afamily
; /*AF_INET6*/
950 hints
.ai_flags
= AI_NUMERICHOST
;
951 hints
.ai_socktype
= SOCK_DGRAM
; /*dummy*/
952 ecode
= getaddrinfo(s
, NULL
, &hints
, &res
);
953 if (ecode
!= 0 || res
->ai_family
!= AF_INET6
||
954 res
->ai_addrlen
!= sizeof(su
->sin6
)) {
955 (void) fprintf(stderr
, "%s: %s\n", s
,
956 gai_strerror(ecode
));
959 memcpy(&su
->sin6
, res
->ai_addr
, sizeof(su
->sin6
));
961 if ((IN6_IS_ADDR_LINKLOCAL(&su
->sin6
.sin6_addr
) ||
962 IN6_IS_ADDR_MC_NODELOCAL(&su
->sin6
.sin6_addr
) ||
963 IN6_IS_ADDR_MC_LINKLOCAL(&su
->sin6
.sin6_addr
)) &&
964 su
->sin6
.sin6_scope_id
) {
965 *(u_int16_t
*)&su
->sin6
.sin6_addr
.s6_addr
[2] =
966 htons(su
->sin6
.sin6_scope_id
);
967 su
->sin6
.sin6_scope_id
= 0;
971 if (hints
.ai_flags
== AI_NUMERICHOST
) {
974 if (which
== RTA_DST
)
975 return (inet6_makenetandmask(&su
->sin6
, q
));
984 link_addr(s
, &su
->sdl
);
989 su
->sa
.sa_len
= sizeof(*su
);
990 sockaddr(s
, &su
->sa
);
1003 if (q
&& which
== RTA_DST
) {
1005 if ((val
= inet_network(s
)) != INADDR_NONE
) {
1006 inet_makenetandmask(
1007 val
, &su
->sin
, (struct sockaddr_in
*)&so_mask
,
1008 strtoul(q
+1, 0, 0));
1013 if ((which
!= RTA_DST
|| forcenet
== 0) &&
1014 inet_aton(s
, &su
->sin
.sin_addr
)) {
1015 val
= su
->sin
.sin_addr
.s_addr
;
1016 if (which
!= RTA_DST
|| forcehost
||
1017 inet_lnaof(su
->sin
.sin_addr
) != INADDR_ANY
)
1024 if (which
== RTA_DST
&& forcehost
== 0 &&
1025 ((val
= inet_network(s
)) != INADDR_NONE
||
1026 ((np
= getnetbyname(s
)) != NULL
&& (val
= np
->n_net
) != 0))) {
1028 inet_makenetandmask(val
, &su
->sin
, (struct sockaddr_in
*)&so_mask
, 0);
1031 hp
= gethostbyname(s
);
1034 su
->sin
.sin_family
= hp
->h_addrtype
;
1035 bcopy(hp
->h_addr
, (char *)&su
->sin
.sin_addr
,
1036 MIN(hp
->h_length
, sizeof(su
->sin
.sin_addr
)));
1039 errx(EX_NOHOST
, "bad address: %s", s
);
1046 int len
= atoi(s
), q
, r
;
1050 rtm_addrs
|= RTA_NETMASK
;
1055 p
= (char *)&so_mask
.sin6
.sin6_addr
;
1060 p
= (char *)&so_mask
.sin
.sin_addr
;
1063 (void) fprintf(stderr
, "prefixlen not supported in this af\n");
1068 if (len
< 0 || max
< len
) {
1069 (void) fprintf(stderr
, "%s: bad value\n", s
);
1075 so_mask
.sa
.sa_family
= af
;
1076 so_mask
.sa
.sa_len
= aflen
;
1077 memset((void *)p
, 0, max
/ 8);
1079 memset((void *)p
, 0xff, q
);
1081 *((u_char
*)p
+ q
) = (0xff00 >> r
) & 0xff;
1093 char *buf
, *lim
, *next
;
1094 register struct rt_msghdr
*rtm
;
1098 mib
[2] = 0; /* protocol */
1099 mib
[3] = 0; /* wildcard address family */
1100 mib
[4] = NET_RT_IFLIST
;
1101 mib
[5] = 0; /* no flags */
1102 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
1103 err(EX_OSERR
, "route-sysctl-estimate");
1104 if ((buf
= malloc(needed
)) == NULL
)
1105 errx(EX_OSERR
, "malloc failed");
1106 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0)
1107 err(EX_OSERR
, "actual retrieval of interface table");
1109 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
1110 rtm
= (struct rt_msghdr
*)next
;
1111 print_rtmsg(rtm
, rtm
->rtm_msglen
);
1128 n
= read(s
, msg
, 2048);
1130 (void) printf("\ngot message of size %d on %s", n
, ctime(&now
));
1131 print_rtmsg((struct rt_msghdr
*)msg
, n
);
1136 struct rt_msghdr m_rtm
;
1146 register char *cp
= m_rtmsg
.m_space
;
1149 #define NEXTADDR(w, u) \
1150 if (rtm_addrs & (w)) {\
1151 l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\
1152 if (verbose) sodump(&(u),"u");\
1156 bzero((char *)&m_rtmsg
, sizeof(m_rtmsg
));
1159 else if (cmd
== 'c')
1161 else if (cmd
== 'g') {
1163 if (so_ifp
.sa
.sa_family
== 0) {
1164 so_ifp
.sa
.sa_family
= AF_LINK
;
1165 so_ifp
.sa
.sa_len
= sizeof(struct sockaddr_dl
);
1166 rtm_addrs
|= RTA_IFP
;
1170 #define rtm m_rtmsg.m_rtm
1172 rtm
.rtm_flags
= flags
;
1173 rtm
.rtm_version
= RTM_VERSION
;
1174 rtm
.rtm_seq
= ++seq
;
1175 rtm
.rtm_addrs
= rtm_addrs
;
1176 rtm
.rtm_rmx
= rt_metrics
;
1177 rtm
.rtm_inits
= rtm_inits
;
1178 rtm
.rtm_index
= ifscope
;
1180 if (rtm_addrs
& RTA_NETMASK
)
1182 NEXTADDR(RTA_DST
, so_dst
);
1183 NEXTADDR(RTA_GATEWAY
, so_gate
);
1184 NEXTADDR(RTA_NETMASK
, so_mask
);
1185 NEXTADDR(RTA_GENMASK
, so_genmask
);
1186 NEXTADDR(RTA_IFP
, so_ifp
);
1187 NEXTADDR(RTA_IFA
, so_ifa
);
1188 rtm
.rtm_msglen
= l
= cp
- (char *)&m_rtmsg
;
1190 print_rtmsg(&rtm
, l
);
1193 if ((rlen
= write(s
, (char *)&m_rtmsg
, l
)) < 0) {
1194 warnx("writing to routing socket: %s", route_strerror(errno
));
1197 if (cmd
== RTM_GET
) {
1199 l
= read(s
, (char *)&m_rtmsg
, sizeof(m_rtmsg
));
1200 } while (l
> 0 && (rtm
.rtm_seq
!= seq
|| rtm
.rtm_pid
!= pid
));
1202 warn("read from routing socket");
1204 print_getmsg(&rtm
, l
);
1213 int olen
= so_mask
.sa
.sa_len
;
1214 register char *cp1
= olen
+ (char *)&so_mask
, *cp2
;
1216 for (so_mask
.sa
.sa_len
= 0; cp1
> (char *)&so_mask
; )
1218 so_mask
.sa
.sa_len
= 1 + cp1
- (char *)&so_mask
;
1221 if ((rtm_addrs
& RTA_DST
) == 0)
1223 switch (so_dst
.sa
.sa_family
) {
1232 cp1
= so_mask
.sa
.sa_len
+ 1 + (char *)&so_dst
;
1233 cp2
= so_dst
.sa
.sa_len
+ 1 + (char *)&so_dst
;
1236 cp2
= so_mask
.sa
.sa_len
+ 1 + (char *)&so_mask
;
1237 while (cp1
> so_dst
.sa
.sa_data
)
1241 char *msgtypes
[] = {
1243 "RTM_ADD: Add Route",
1244 "RTM_DELETE: Delete Route",
1245 "RTM_CHANGE: Change Metrics or flags",
1246 "RTM_GET: Report Metrics",
1247 "RTM_LOSING: Kernel Suspects Partitioning",
1248 "RTM_REDIRECT: Told to use different route",
1249 "RTM_MISS: Lookup failed on this address",
1250 "RTM_LOCK: fix specified metrics",
1251 "RTM_OLDADD: caused by SIOCADDRT",
1252 "RTM_OLDDEL: caused by SIOCDELRT",
1253 "RTM_RESOLVE: Route created by cloning",
1254 "RTM_NEWADDR: address being added to iface",
1255 "RTM_DELADDR: address being removed from iface",
1256 "RTM_IFINFO: iface status change",
1257 "RTM_NEWMADDR: new multicast group membership on iface",
1258 "RTM_DELMADDR: multicast group membership removed from iface",
1262 char metricnames
[] =
1263 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
1266 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010DELCLONE"
1267 "\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016"
1268 "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024b024"
1269 "\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\031IFSCOPE\032CONDEMNED"
1270 "\033IFREF\034PROXY\035ROUTER";
1272 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
1273 "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
1274 "\017LINK2\020MULTICAST";
1276 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
1279 print_rtmsg(rtm
, msglen
)
1280 register struct rt_msghdr
*rtm
;
1283 struct if_msghdr
*ifm
;
1284 struct ifa_msghdr
*ifam
;
1286 struct ifma_msghdr
*ifmam
;
1291 if (rtm
->rtm_version
!= RTM_VERSION
) {
1292 (void) printf("routing message version %d not understood\n",
1296 (void)printf("%s: len %d, ", msgtypes
[rtm
->rtm_type
], rtm
->rtm_msglen
);
1297 switch (rtm
->rtm_type
) {
1299 ifm
= (struct if_msghdr
*)rtm
;
1300 (void) printf("if# %d, flags:", ifm
->ifm_index
);
1301 bprintf(stdout
, ifm
->ifm_flags
, ifnetflags
);
1302 pmsg_addrs((char *)(ifm
+ 1), ifm
->ifm_addrs
);
1306 ifam
= (struct ifa_msghdr
*)rtm
;
1307 (void) printf("metric %d, flags:", ifam
->ifam_metric
);
1308 bprintf(stdout
, ifam
->ifam_flags
, routeflags
);
1309 pmsg_addrs((char *)(ifam
+ 1), ifam
->ifam_addrs
);
1314 ifmam
= (struct ifma_msghdr
*)rtm
;
1315 pmsg_addrs((char *)(ifmam
+ 1), ifmam
->ifmam_addrs
);
1319 (void) printf("pid: %ld, seq %d, errno %d, ",
1320 (long)rtm
->rtm_pid
, rtm
->rtm_seq
, rtm
->rtm_errno
);
1321 if (rtm
->rtm_flags
& RTF_IFSCOPE
)
1322 (void) printf("ifscope %d, ", rtm
->rtm_index
);
1323 if (rtm
->rtm_flags
& RTF_IFREF
)
1324 (void) printf("ifref, ");
1325 (void) printf("flags:");
1326 bprintf(stdout
, rtm
->rtm_flags
, routeflags
);
1332 print_getmsg(rtm
, msglen
)
1333 register struct rt_msghdr
*rtm
;
1336 struct sockaddr
*dst
= NULL
, *gate
= NULL
, *mask
= NULL
;
1337 struct sockaddr_dl
*ifp
= NULL
;
1338 register struct sockaddr
*sa
;
1342 (void) printf(" route to: %s\n", routename(&so_dst
.sa
));
1343 if (rtm
->rtm_version
!= RTM_VERSION
) {
1344 warnx("routing message version %d not understood",
1348 if (rtm
->rtm_msglen
> msglen
) {
1349 warnx("message length mismatch, in packet %d, returned %d",
1350 rtm
->rtm_msglen
, msglen
);
1352 if (rtm
->rtm_errno
) {
1353 errno
= rtm
->rtm_errno
;
1354 warn("message indicates error %d", errno
);
1357 cp
= ((char *)(rtm
+ 1));
1359 for (i
= 1; i
; i
<<= 1)
1360 if (i
& rtm
->rtm_addrs
) {
1361 sa
= (struct sockaddr
*)cp
;
1373 if (sa
->sa_family
== AF_LINK
&&
1374 ((struct sockaddr_dl
*)sa
)->sdl_nlen
)
1375 ifp
= (struct sockaddr_dl
*)sa
;
1381 mask
->sa_family
= dst
->sa_family
; /* XXX */
1383 (void)printf("destination: %s\n", routename(dst
));
1385 int savenflag
= nflag
;
1388 (void)printf(" mask: %s\n", routename(mask
));
1391 if (gate
&& rtm
->rtm_flags
& RTF_GATEWAY
)
1392 (void)printf(" gateway: %s\n", routename(gate
));
1394 (void)printf(" interface: %.*s\n",
1395 ifp
->sdl_nlen
, ifp
->sdl_data
);
1396 (void)printf(" flags: ");
1397 bprintf(stdout
, rtm
->rtm_flags
, routeflags
);
1399 #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1400 #define msec(u) (((u) + 500) / 1000) /* usec to msec */
1402 (void) printf("\n%s\n", "\
1403 recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire");
1404 printf("%8u%c ", rtm
->rtm_rmx
.rmx_recvpipe
, lock(RPIPE
));
1405 printf("%8u%c ", rtm
->rtm_rmx
.rmx_sendpipe
, lock(SPIPE
));
1406 printf("%8u%c ", rtm
->rtm_rmx
.rmx_ssthresh
, lock(SSTHRESH
));
1407 printf("%8u%c ", msec(rtm
->rtm_rmx
.rmx_rtt
), lock(RTT
));
1408 printf("%8u%c ", msec(rtm
->rtm_rmx
.rmx_rttvar
), lock(RTTVAR
));
1409 printf("%8u%c ", rtm
->rtm_rmx
.rmx_hopcount
, lock(HOPCOUNT
));
1410 printf("%8u%c ", rtm
->rtm_rmx
.rmx_mtu
, lock(MTU
));
1411 if (rtm
->rtm_rmx
.rmx_expire
)
1412 rtm
->rtm_rmx
.rmx_expire
-= time(0);
1413 printf("%8d%c\n", rtm
->rtm_rmx
.rmx_expire
, lock(EXPIRE
));
1416 #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
1419 else if (rtm
->rtm_addrs
&~ RTA_IGN
) {
1420 (void) printf("sockaddrs: ");
1421 bprintf(stdout
, rtm
->rtm_addrs
, addrnames
);
1429 register struct rt_msghdr
*rtm
;
1431 (void) printf("\nlocks: ");
1432 bprintf(stdout
, rtm
->rtm_rmx
.rmx_locks
, metricnames
);
1433 (void) printf(" inits: ");
1434 bprintf(stdout
, rtm
->rtm_inits
, metricnames
);
1435 pmsg_addrs(((char *)(rtm
+ 1)), rtm
->rtm_addrs
);
1439 pmsg_addrs(cp
, addrs
)
1443 register struct sockaddr
*sa
;
1447 (void) putchar('\n');
1450 (void) printf("\nsockaddrs: ");
1451 bprintf(stdout
, addrs
, addrnames
);
1452 (void) putchar('\n');
1453 for (i
= 1; i
; i
<<= 1)
1455 sa
= (struct sockaddr
*)cp
;
1456 (void) printf(" %s", routename(sa
));
1459 (void) putchar('\n');
1460 (void) fflush(stdout
);
1474 while ((i
= *s
++) != 0) {
1475 if (b
& (1 << (i
-1))) {
1482 for (; (i
= *s
) > 32; s
++)
1489 (void) putc('>', fp
);
1496 register struct keytab
*kt
= keywords
;
1498 while (kt
->kt_cp
&& strcmp(kt
->kt_cp
, cp
))
1508 switch (su
->sa
.sa_family
) {
1510 (void) printf("%s: link %s; ",
1511 which
, link_ntoa(&su
->sdl
));
1514 (void) printf("%s: inet %s; ",
1515 which
, inet_ntoa(su
->sin
.sin_addr
));
1518 (void) fflush(stdout
);
1532 register char *addr
;
1533 register struct sockaddr
*sa
;
1535 register char *cp
= (char *)sa
;
1536 int size
= sa
->sa_len
;
1537 char *cplim
= cp
+ size
;
1538 register int byte
= 0, state
= VIRGIN
, new = 0 /* foil gcc */;
1543 if ((*addr
>= '0') && (*addr
<= '9')) {
1545 } else if ((*addr
>= 'a') && (*addr
<= 'f')) {
1546 new = *addr
- 'a' + 10;
1547 } else if ((*addr
>= 'A') && (*addr
<= 'F')) {
1548 new = *addr
- 'A' + 10;
1549 } else if (*addr
== 0)
1554 switch (state
/* | INPUT */) {
1555 case GOTTWO
| DIGIT
:
1556 *cp
++ = byte
; /*FALLTHROUGH*/
1557 case VIRGIN
| DIGIT
:
1558 state
= GOTONE
; byte
= new; continue;
1559 case GOTONE
| DIGIT
:
1560 state
= GOTTWO
; byte
= new + (byte
<< 4); continue;
1561 default: /* | DELIM */
1562 state
= VIRGIN
; *cp
++ = byte
; byte
= 0; continue;
1565 *cp
++ = byte
; /* FALLTHROUGH */
1570 } while (cp
< cplim
);
1571 sa
->sa_len
= cp
- (char *)sa
;