* Copyright (c) 1983, 1989 The Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)route.c 5.35 (Berkeley) 6/27/91";
#include <netccitt/x25.h>
struct sockaddr_iso siso
;
struct sockaddr_x25 sx25
;
} so_dst
, so_gate
, so_mask
, so_genmask
, so_ifa
, so_ifp
;
union sockunion
*so_addrs
[] =
{ &so_dst
, &so_gate
, &so_mask
, &so_genmask
, &so_ifp
, &so_ifa
, 0};
typedef union sockunion
*sup
;
int forcehost
, forcenet
, doflush
, nflag
, af
, qflag
, tflag
, Cflag
, keyword();
int iflag
, verbose
, aflen
= sizeof (struct sockaddr_in
);
int locking
, lockrest
, debugonly
;
struct sockaddr_in sin
= { sizeof(sin
), AF_INET
};
struct rt_metrics rt_metrics
;
struct in_addr
inet_makeaddr();
char *routename(), *netname();
void flushroutes(), newroute(), monitor(), sockaddr();
void print_getmsg(), print_rtmsg(), pmsg_common(), sodump(), bprintf();
extern char *inet_ntoa(), *iso_ntoa(), *link_ntoa();
(void) fprintf(stderr
, "route: botched keyword: %s\n", cp
);
"usage: route [ -Cnqv ] cmd [[ -<qualifers> ] args ]\n");
(void) fprintf(stderr
, "route: ");
(void) fprintf(stderr
, "%s: ", s
);
(void) fprintf(stderr
, "%s\n", strerror(sverrno
));
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
while ((ch
= getopt(argc
, argv
, "Cnqtv")) != EOF
)
Cflag
= 1; /* Use old ioctls. */
s
= open("/dev/null", O_WRONLY
, 0);
s
= socket(AF_INET
, SOCK_RAW
, 0);
s
= socket(PF_ROUTE
, SOCK_RAW
, 0);
switch (keyword(*argv
)) {
usage("change or get with -C");
* Purge all entries in the routing tables not
* associated with network interfaces.
register struct rt_msghdr
*rtm
;
quit("must be root to alter routing table");
shutdown(s
, 0); /* Don't want to read back our messages */
if (argc
== 2 && **argv
== '-')
switch (keyword(*argv
+ 1)) {
if ((needed
= getkerninfo(KINFO_RT_DUMP
, 0, 0, 0)) < 0)
quit("route-getkerninfo-estimate");
if ((buf
= malloc(needed
)) == NULL
)
if ((rlen
= getkerninfo(KINFO_RT_DUMP
, buf
, &needed
, 0)) < 0)
quit("actual retrieval of routing table");
for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
rtm
= (struct rt_msghdr
*)next
;
if ((rtm
->rtm_flags
& RTF_GATEWAY
) == 0)
struct sockaddr
*sa
= (struct sockaddr
*)(rtm
+ 1);
rtm
->rtm_type
= RTM_DELETE
;
rlen
= write(s
, next
, rtm
->rtm_msglen
);
if (rlen
< (int)rtm
->rtm_msglen
) {
"route: write to routing socket: %s\n",
(void) printf("got only %d for rlen\n", rlen
);
struct sockaddr
*sa
= (struct sockaddr
*)(rtm
+ 1);
(void) printf("%-20.20s ", rtm
->rtm_flags
& RTF_HOST
?
routename(sa
) : netname(sa
));
sa
= (struct sockaddr
*)(sa
->sa_len
+ (char *)sa
);
(void) printf("%-20.20s ", routename(sa
));
static char domain
[MAXHOSTNAMELEN
+ 1];
if (gethostname(domain
, MAXHOSTNAMELEN
) == 0 &&
(cp
= index(domain
, '.')))
(void) strcpy(domain
, cp
+ 1);
in
= ((struct sockaddr_in
*)sa
)->sin_addr
;
if (in
.s_addr
== INADDR_ANY
)
hp
= gethostbyaddr((char *)&in
, sizeof (struct in_addr
),
if ((cp
= index(hp
->h_name
, '.')) &&
#define C(x) ((x) & 0xff)
in
.s_addr
= ntohl(in
.s_addr
);
(void) sprintf(line
, "%u.%u.%u.%u", C(in
.s_addr
>> 24),
C(in
.s_addr
>> 16), C(in
.s_addr
>> 8), C(in
.s_addr
));
return (ns_print((struct sockaddr_ns
*)sa
));
return (link_ntoa((struct sockaddr_dl
*)sa
));
(void) sprintf(line
, "iso %s",
iso_ntoa(&((struct sockaddr_iso
*)sa
)->siso_addr
));
{ u_short
*s
= (u_short
*)sa
->sa_data
;
u_short
*slim
= s
+ ((sa
->sa_len
+ 1) >> 1);
char *cp
= line
+ sprintf(line
, "(%d)", sa
->sa_family
);
cp
+= sprintf(cp
, " %x", *s
++);
* Return the name of the network whose address is given.
* The address is assumed to be that of a net or subnet, not a host.
in
= ((struct sockaddr_in
*)sa
)->sin_addr
;
i
= in
.s_addr
= ntohl(in
.s_addr
);
} else if (IN_CLASSB(i
)) {
* If there are more bits than the standard mask
* would suggest, subnets must be in use.
* Guess at the subnet mask, assuming reasonable
while (in
.s_addr
&~ mask
)
mask
= (long)mask
>> subnetshift
;
np
= getnetbyaddr(net
, AF_INET
);
else if ((in
.s_addr
& 0xffffff) == 0)
(void) sprintf(line
, "%u", C(in
.s_addr
>> 24));
else if ((in
.s_addr
& 0xffff) == 0)
(void) sprintf(line
, "%u.%u", C(in
.s_addr
>> 24),
else if ((in
.s_addr
& 0xff) == 0)
(void) sprintf(line
, "%u.%u.%u", C(in
.s_addr
>> 24),
C(in
.s_addr
>> 16), C(in
.s_addr
>> 8));
(void) sprintf(line
, "%u.%u.%u.%u", C(in
.s_addr
>> 24),
C(in
.s_addr
>> 16), C(in
.s_addr
>> 8),
return (ns_print((struct sockaddr_ns
*)sa
));
return (link_ntoa((struct sockaddr_dl
*)sa
));
(void) sprintf(line
, "iso %s",
iso_ntoa(&((struct sockaddr_iso
*)sa
)->siso_addr
));
{ u_short
*s
= (u_short
*)sa
->sa_data
;
u_short
*slim
= s
+ ((sa
->sa_len
+ 1)>>1);
char *cp
= line
+ sprintf(line
, "af %d:", sa
->sa_family
);
cp
+= sprintf(cp
, " %x", *s
++);
u_long noval
, *valp
= &noval
;
#define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break
caseof(K_MTU
, RTV_MTU
, rmx_mtu
);
caseof(K_HOPCOUNT
, RTV_HOPCOUNT
, rmx_hopcount
);
caseof(K_EXPIRE
, RTV_EXPIRE
, rmx_expire
);
caseof(K_RECVPIPE
, RTV_RPIPE
, rmx_recvpipe
);
caseof(K_SENDPIPE
, RTV_SPIPE
, rmx_sendpipe
);
caseof(K_SSTHRESH
, RTV_SSTHRESH
, rmx_ssthresh
);
caseof(K_RTT
, RTV_RTT
, rmx_rtt
);
caseof(K_RTTVAR
, RTV_RTTVAR
, rmx_rttvar
);
rt_metrics
.rmx_locks
|= flag
;
char *cmd
, *dest
= "", *gateway
= "", *err
;
int ishost
= 0, ret
, attempts
, oerrno
, flags
= 0;
quit("must be root to alter routing table");
shutdown(s
, 0); /* Don't want to read back our messages */
switch (key
= keyword(1 + *argv
)) {
aflen
= sizeof(struct sockaddr_dl
);
aflen
= sizeof(struct sockaddr_iso
);
aflen
= sizeof(struct sockaddr_in
);
aflen
= sizeof(struct sockaddr_x25
);
aflen
= sizeof(union sockunion
);
aflen
= sizeof(struct sockaddr_ns
);
(void) getaddr(RTA_IFA
, *++argv
, 0);
(void) getaddr(RTA_IFP
, *++argv
, 0);
(void) getaddr(RTA_GENMASK
, *++argv
, 0);
(void) getaddr(RTA_GATEWAY
, *++argv
, 0);
ishost
= getaddr(RTA_DST
, *++argv
, &hp
);
(void) getaddr(RTA_NETMASK
, *++argv
, 0);
set_metric(*++argv
, key
);
if ((rtm_addrs
& RTA_DST
) == 0) {
ishost
= getaddr(RTA_DST
, *argv
, &hp
);
} else if ((rtm_addrs
& RTA_GATEWAY
) == 0) {
(void) getaddr(RTA_GATEWAY
, *argv
, &hp
);
printf("%s,%s", "old usage of trailing 0",
"assuming route to if\n");
} else if (ret
> 0 && ret
< 10) {
printf("old usage of trailing digit, ");
printf("assuming route via gateway\n");
(void) getaddr(RTA_NETMASK
, *argv
, 0);
for (attempts
= 1; ; attempts
++) {
if (Cflag
&& (af
== AF_INET
|| af
== AF_NS
)) {
route
.rt_dst
= so_dst
.sa
;
route
.rt_gateway
= so_gate
.sa
;
if ((ret
= ioctl(s
, *cmd
== 'a' ? SIOCADDRT
: SIOCDELRT
,
if ((ret
= rtmsg(*cmd
, flags
)) == 0)
if (errno
!= ENETUNREACH
&& errno
!= ESRCH
)
if (af
== AF_INET
&& hp
&& hp
->h_addr_list
[1]) {
bcopy(hp
->h_addr_list
[0], (caddr_t
)&so_dst
.sin
.sin_addr
,
(void) printf("%s %s %s: gateway %s", cmd
, ishost
? "host" : "net",
if (attempts
> 1 && ret
== 0)
inet_ntoa(((struct sockaddr_in
*)&route
.rt_gateway
)->sin_addr
));
err
= "routing table overflow";
(void) printf(": %s\n", err
);
inet_makenetandmask(net
, sin
)
register struct sockaddr_in
*sin
;
rtm_addrs
|= RTA_NETMASK
;
addr
= net
<< IN_CLASSA_NSHIFT
;
} else if (net
< 65536) {
addr
= net
<< IN_CLASSB_NSHIFT
;
} else if (net
< 16777216L) {
addr
= net
<< IN_CLASSC_NSHIFT
;
if ((addr
& IN_CLASSA_HOST
) == 0)
else if ((addr
& IN_CLASSB_HOST
) == 0)
else if ((addr
& IN_CLASSC_HOST
) == 0)
sin
->sin_addr
.s_addr
= htonl(addr
);
sin
->sin_addr
.s_addr
= htonl(mask
);
cp
= (char *)(&sin
->sin_addr
+ 1);
while (*--cp
== 0 && cp
> (char *)sin
)
sin
->sin_len
= 1 + cp
- (char *)sin
;
* Interpret an argument as a network address of some kind,
* returning 1 if a host address, 0 if a network address.
struct ns_addr
ns_addr();
struct iso_addr
*iso_addr();
aflen
= sizeof(struct sockaddr_in
);
case RTA_DST
: su
= so_addrs
[0]; su
->sa
.sa_family
= af
; break;
case RTA_GATEWAY
: su
= so_addrs
[1]; su
->sa
.sa_family
= af
; break;
case RTA_NETMASK
: su
= so_addrs
[2]; break;
case RTA_GENMASK
: su
= so_addrs
[3]; break;
case RTA_IFP
: su
= so_addrs
[4]; su
->sa
.sa_family
= af
; break;
case RTA_IFA
: su
= so_addrs
[5]; su
->sa
.sa_family
= af
; break;
default: usage("Internal Error"); /*NOTREACHED*/
if (strcmp(s
, "default") == 0) {
(void) getaddr(RTA_NETMASK
, s
, 0);
if (((val
= inet_addr(s
)) != -1) &&
(which
!= RTA_DST
|| forcenet
== 0)) {
su
->sin
.sin_addr
.s_addr
= val
;
if (inet_lnaof(su
->sin
.sin_addr
) != INADDR_ANY
)
out
: if (which
== RTA_DST
)
inet_makenetandmask(val
, &su
->sin
);
su
->sin
.sin_family
= hp
->h_addrtype
;
bcopy(hp
->h_addr
, (char *)&su
->sin
.sin_addr
, hp
->h_length
);
(void) fprintf(stderr
, "%s: bad value\n", s
);
struct sockaddr_ns
*sms
= &(so_mask
.sns
);
bzero((char *)sms
, sizeof(*sms
));
sms
->sns_addr
.x_net
= *(union ns_net
*)ns_bh
;
rtm_addrs
|= RTA_NETMASK
;
su
->sns
.sns_addr
= ns_addr(s
);
return (!ns_nullhost(su
->sns
.sns_addr
));
su
->siso
.siso_addr
= *iso_addr(s
);
if (which
== RTA_NETMASK
|| which
== RTA_GENMASK
) {
register char *cp
= (char *)TSEL(&su
->siso
);
do {--cp
;} while ((cp
> (char *)su
) && (*cp
== 0));
su
->siso
.siso_len
= 1 + cp
- (char *)su
;
ccitt_addr(s
, &su
->sx25
);
su
->sa
.sa_len
= sizeof(*su
);
short ns_nullh
[] = {0,0,0};
short ns_bh
[] = {-1,-1,-1};
union { union ns_net net_e
; u_long long_e
; } net
;
static char mybuf
[50], cport
[10], chost
[25];
port
= ntohs(work
.x_port
);
if (ns_nullhost(work
) && net
.long_e
== 0) {
(void) sprintf(mybuf
, "*.%XH", port
);
if (bcmp((char *)ns_bh
, (char *)work
.x_host
.c_host
, 6) == 0)
else if (bcmp((char *)ns_nullh
, (char *)work
.x_host
.c_host
, 6) == 0)
(void) sprintf(chost
, "%02X%02X%02X%02X%02X%02XH",
q
[0], q
[1], q
[2], q
[3], q
[4], q
[5]);
for (p
= chost
; *p
== '0' && p
< chost
+ 12; p
++)
(void) sprintf(cport
, ".%XH", htons(port
));
(void) sprintf(mybuf
,"%XH.%s%s", ntohl(net
.long_e
), host
, cport
);
(void) printf("got message of size %d\n", n
);
print_rtmsg((struct rt_msghdr
*)msg
);
register char *cp
= m_rtmsg
.m_space
;
l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\
if (verbose) sodump(&(u),"u");\
bzero((char *)&m_rtmsg
, sizeof(m_rtmsg
));
#define rtm m_rtmsg.m_rtm
rtm
.rtm_version
= RTM_VERSION
;
rtm
.rtm_addrs
= rtm_addrs
;
rtm
.rtm_rmx
= rt_metrics
;
rtm
.rtm_inits
= rtm_inits
;
if (rtm_addrs
& RTA_NETMASK
)
NEXTADDR(RTA_DST
, so_dst
);
NEXTADDR(RTA_GATEWAY
, so_gate
);
NEXTADDR(RTA_NETMASK
, so_mask
);
NEXTADDR(RTA_GENMASK
, so_genmask
);
NEXTADDR(RTA_IFP
, so_ifp
);
NEXTADDR(RTA_IFA
, so_ifa
);
rtm
.rtm_msglen
= l
= cp
- (char *)&m_rtmsg
;
if ((rlen
= write(s
, (char *)&m_rtmsg
, l
)) < 0) {
perror("writing to routing socket");
l
= read(s
, (char *)&m_rtmsg
, sizeof(m_rtmsg
));
} while (l
> 0 && (rtm
.rtm_seq
!= seq
|| rtm
.rtm_pid
!= pid
));
"route: read from routing socket: %s\n",
register char *cp1
, *cp2
;
if ((rtm_addrs
& RTA_DST
) == 0)
switch(so_dst
.sa
.sa_family
) {
case AF_NS
: case AF_INET
: case 0:
olen
= MIN(so_dst
.siso
.siso_nlen
, so_mask
.sa
.sa_len
- 6);
cp1
= so_mask
.sa
.sa_len
+ 1 + (char *)&so_dst
;
cp2
= so_dst
.sa
.sa_len
+ 1 + (char *)&so_dst
;
cp2
= so_mask
.sa
.sa_len
+ 1 + (char *)&so_mask
;
while (cp1
> so_dst
.sa
.sa_data
)
switch(so_dst
.sa
.sa_family
) {
so_dst
.siso
.siso_nlen
= olen
;
"RTM_DELETE: Delete Route",
"RTM_CHANGE: Change Metrics or flags",
"RTM_GET: Report Metrics",
"RTM_LOSING: Kernel Suspects Partitioning",
"RTM_REDIRECT: Told to use different route",
"RTM_MISS: Lookup failed on this address",
"RTM_LOCK: fix specified metrics",
"RTM_OLDADD: caused by SIOCADDRT",
"RTM_OLDDEL: caused by SIOCDELRT",
"\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE\013LLINFO\017PROTO2\020PROTO1";
register struct rt_msghdr
*rtm
;
if (rtm
->rtm_version
!= RTM_VERSION
) {
(void) printf("routing message version %d not understood\n",
(void) printf("%s\npid: %d, len %d, seq %d, errno %d, flags:",
msgtypes
[rtm
->rtm_type
], rtm
->rtm_pid
, rtm
->rtm_msglen
,
rtm
->rtm_seq
, rtm
->rtm_errno
);
bprintf(stdout
, rtm
->rtm_flags
, routeflags
);
print_getmsg(rtm
, msglen
)
register struct rt_msghdr
*rtm
;
if (rtm
->rtm_version
!= RTM_VERSION
) {
(void)printf("routing message version %d not understood\n",
if (rtm
->rtm_msglen
> msglen
) {
(void)printf("get length mismatch, in packet %d, returned %d\n",
rtm
->rtm_msglen
, msglen
);
(void) printf("RTM_GET: errno %d, flags:", rtm
->rtm_errno
);
bprintf(stdout
, rtm
->rtm_flags
, routeflags
);
(void) printf("\nmetric values:\n ");
printf("%s: %d%s", __STRING(f), rtm->rtm_rmx.__CONCAT(rmx_,f), e)
register struct rt_msghdr
*rtm
;
register struct sockaddr
*sa
;
(void) printf("\nlocks: ");
bprintf(stdout
, rtm
->rtm_rmx
.rmx_locks
, metricnames
);
(void) printf(" inits: ");
bprintf(stdout
, rtm
->rtm_inits
, metricnames
);
(void) printf("\nsockaddrs: ");
bprintf(stdout
, rtm
->rtm_addrs
,
"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR");
cp
= ((char *)(rtm
+ 1));
if (i
& rtm
->rtm_addrs
) {
sa
= (struct sockaddr
*)cp
;
(void) printf(" %s", routename(sa
));
for (; (i
= *s
) > 32; s
++)
register struct keytab
*kt
= keywords
;
while (kt
->kt_cp
&& strcmp(kt
->kt_cp
, cp
))
switch (su
->sa
.sa_family
) {
(void) printf("%s: link %s; ",
which
, link_ntoa(&su
->sdl
));
(void) printf("%s: iso %s; ",
which
, iso_ntoa(&su
->siso
.siso_addr
));
(void) printf("%s: inet %s; ",
which
, inet_ntoa(su
->sin
.sin_addr
));
(void) printf("%s: xns %s; ",
which
, ns_ntoa(su
->sns
.sns_addr
));
register struct sockaddr
*sa
;
register char *cp
= (char *)sa
;
register int byte
= 0, state
= VIRGIN
, new;
if ((*addr
>= '0') && (*addr
<= '9')) {
} else if ((*addr
>= 'a') && (*addr
<= 'f')) {
} else if ((*addr
>= 'A') && (*addr
<= 'F')) {
switch (state
/* | INPUT */) {
*cp
++ = byte
; /*FALLTHROUGH*/
state
= GOTONE
; byte
= new; continue;
state
= GOTTWO
; byte
= new + (byte
<< 4); continue;
state
= VIRGIN
; *cp
++ = byte
; byte
= 0; continue;
*cp
++ = byte
; /* FALLTHROUGH */
sa
->sa_len
= cp
- (char *)sa
;