* Copyright (c) 1983, 1989 The Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)route.c 5.17 (Berkeley) %G%";
struct sockaddr_iso siso
;
} so_dst
, so_gate
, so_mask
;
int forcehost
, forcenet
, doflush
, nflag
, xnsflag
, qflag
, Cflag
= 1;
int iflag
, osiflag
, verbose
;
struct sockaddr_in sin
= { sizeof(sin
), AF_INET
};
struct in_addr
inet_makeaddr();
char *malloc(), *vmunix
= _PATH_UNIX
;
(lseek(kmem, (off_t)(p), 0), read(kmem, (char *)&(d), sizeof (d)))
"usage: route [ -n ] [ -f ] [ cmd [ net | host ] args ]\n"),
for (; argc
> 0 && argv
[0][0] == '-'; argc
--, argv
++) {
for (argvp
= argv
[0]++; *argvp
; argvp
++)
Cflag
++; /* Use old ioctls */
Cflag
= 0; /* Use routing socket */
s
= socket(AF_INET
, SOCK_RAW
, 0);
s
= socket(PF_ROUTE
, SOCK_RAW
, 0);
if (strcmp(*argv
, "add") == 0)
else if (strcmp(*argv
, "delete") == 0)
else if (strcmp(*argv
, "change") == 0)
changeroute(argc
-1, argv
+1);
else if (strcmp(*argv
, "monitor") == 0)
fprintf(stderr
, "%s: huh?\n", *argv
);
* Purge all entries in the routing tables not
* associated with network interfaces.
register struct ortentry
*rt
;
struct mbuf mb
, **routehash
;
int rthashsize
, i
, doinghost
= 1;
char *routename(), *netname(), *strerror();
kmem
= open(_PATH_KMEM
, O_RDONLY
, 0);
"route: %s: %s\n", _PATH_KMEM
, strerror(errno
));
return (treestuff(nl
[N_RTREE
].n_value
));
if (nl
[N_RTHOST
].n_value
== 0) {
"route: \"rthost\", symbol not in namelist\n");
if (nl
[N_RTNET
].n_value
== 0) {
"route: \"rtnet\", symbol not in namelist\n");
if (nl
[N_RTHASHSIZE
].n_value
== 0) {
"route: \"rthashsize\", symbol not in namelist\n");
kget(nl
[N_RTHASHSIZE
].n_value
, rthashsize
);
routehash
= (struct mbuf
**)malloc(rthashsize
*sizeof (struct mbuf
*));
lseek(kmem
, nl
[N_RTHOST
].n_value
, 0);
read(kmem
, routehash
, rthashsize
*sizeof (struct mbuf
*));
printf("Flushing routing tables:\n");
for (i
= 0; i
< rthashsize
; i
++) {
d_ortentry((struct ortentry
*)(mb
.m_dat
), doinghost
);
lseek(kmem
, nl
[N_RTNET
].n_value
, 0);
read(kmem
, routehash
, rthashsize
*sizeof (struct mbuf
*));
typedef u_char blob
[128];
} firstbatch
, *curbatch
= &firstbatch
;
register struct rtentry
*rt
;
if ((rnode
.rn_flags
& RNF_ROOT
) == 0) {
register struct rtbatch
*b
= curbatch
;
if ((rnode
.rn_flags
& RNF_ACTIVE
) == 0) {
printf("Dead entry in tree: %x\n", rn
);
R_Malloc(b
->nb
, struct rtbatch
*,
printf("out of space\n");
if (dst
->sa_len
> sizeof (*dst
))
kget(rt_key(rt
), x
->dst
);
rt
->rt_nodes
->rn_key
= (char *)dst
;
kget(rt
->rt_gateway
, x
->gate
.sa
);
if (x
->gate
.sa
.sa_len
> sizeof (*dst
))
kget(rt
->rt_gateway
, x
->gate
);
rt
->rt_gateway
= &x
->gate
.sa
;
kget(rt_mask(rt
), x
->mask
.sa
);
if (x
->mask
.sa
.sa_len
> sizeof(x
->mask
.sa
))
kget(rt_mask(rt
), x
->mask
);
rt
->rt_nodes
->rn_mask
= (char *)&x
->mask
.sa
;
w_tree(rnode
.rn_dupedkey
);
struct radix_node_head
*rnh
, head
;
register struct rtbatch
*b
;
for (kget(rtree
, rnh
); rnh
; rnh
= head
.rnh_next
) {
w_tree(head
.rnh_treetop
);
for (b
= &firstbatch
; b
; b
= b
->nb
)
for (i
= 0; i
< b
->ifree
; i
++)
d_rtentry(&(b
->x
[i
].rt
));
register struct ortentry
*rt
;
int doinghost
= rt
->rt_flags
& RTF_HOST
;
if (rt
->rt_flags
& RTF_GATEWAY
) {
printf("%-20.20s ", doinghost
?
printf("%-20.20s ", routename(&rt
->rt_gateway
));
if (ioctl(s
, SIOCDELRT
, (caddr_t
)rt
) < 0) {
(void) ioctl(s
, SIOCDELRT
, (caddr_t
)rt
);
struct ortentry ortentry
;
register struct rtentry
*rt
;
int doinghost
= rt
->rt_flags
& RTF_HOST
;
ortentry
.rt_flags
= rt
->rt_flags
;
ortentry
.rt_dst
= *(rt_key(rt
));
ortentry
.rt_gateway
= *(rt
->rt_gateway
);
if (rt
->rt_flags
& RTF_GATEWAY
) {
result
= rtmsg('d', rt_key(rt
), rt
->rt_gateway
,
rt_mask(rt
), rt
->rt_flags
);
result
= ioctl(s
, SIOCDELRT
, (caddr_t
)&ortentry
);
printf("%-20.20s ", doinghost
?
routename(rt_key(rt
)) : netname(rt_key(rt
)));
printf("%-20.20s ", routename(rt
->rt_gateway
));
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(&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
));
{ u_short
*s
= (u_short
*)sa
->sa_data
;
(void)sprintf(line
, "(%d) %x %x %x %x %x %x %x",
sa
->sa_family
, s
[0], s
[1], s
[2], s
[3], s
[4], s
[5], s
[6]);
* 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
));
{ u_short
*s
= (u_short
*)sa
->sa_data
;
(void)sprintf(line
, "af %d: %x %x %x %x %x %x %x",
sa
->sa_family
, s
[0], s
[1], s
[2], s
[3], s
[4], s
[5], s
[6]);
char *cmd
, *dest
, *gateway
, *mask
;
int ishost
, metric
= 0, ret
, attempts
, oerrno
, flags
= 0;
if ((strcmp(argv
[1], "host")) == 0) {
} else if ((strcmp(argv
[1], "net")) == 0) {
ishost
= getaddr(argv
[1], &so_dst
.sa
, &so_mask
.sa
,
(void) getaddr(argv
[2], &so_gate
.sa
, 0, &hp
, &gateway
, 0);
if ((Cflag
== 0) && argc
== 4) {
printf("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(argv
[3], &so_mask
.sa
, 0, &hp
, &mask
, 0);
for (attempts
= 1; ; attempts
++) {
route
.rt_dst
= so_dst
.sa
;
route
.rt_gateway
= so_gate
.sa
;
if ((ret
= ioctl(s
, *cmd
== 'a' ? SIOCADDRT
: SIOCDELRT
,
if ((ret
= rtmsg(*cmd
, &so_dst
.sa
, &so_gate
.sa
,
(ishost
? 0 : &so_mask
.sa
), flags
)) == 0)
if (errno
!= ENETUNREACH
&& errno
!= ESRCH
)
if (hp
&& hp
->h_addr_list
[1]) {
bcopy(hp
->h_addr_list
[0], (caddr_t
)&so_dst
.sin
.sin_addr
,
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
));
printf("not supported\n");
printf("not in table\n");
printf("entry in use\n");
printf("routing table overflow\n");
printf("ioctl returns %d\n", errno
);
sav
= malloc(strlen(s
) + 1);
fprintf("route: out of memory\n");
inet_makenetandmask(net
, sin
, sockmask
)
struct sockaddr_in
*sin
, *sockmask
;
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
));
register char *cp
= (char *)&(sockmask
->sin_port
);
register char *cpbase
= (char *)&(sockmask
->sin_addr
);
sockmask
->sin_addr
.s_addr
= htonl(mask
);
sockmask
->sin_family
= 0;
sockmask
->sin_len
= 1 + cp
- (caddr_t
)sockmask
;
* Interpret an argument as a network address of some kind,
* returning 1 if a host address, 0 if a network address.
getaddr(s
, sin
, sockmask
, hpp
, name
, isnet
)
struct sockaddr_in
*sin
, *sockmask
;
struct sockaddr_ns
*sns
= (struct sockaddr_ns
*)sin
;
struct ns_addr
ns_addr();
if (strcmp(s
, "default") == 0) {
sin
->sin_family
= AF_INET
;
sin
->sin_len
= sizeof(*sin
);
sin
->sin_addr
.s_addr
= val
;
if (inet_lnaof(sin
->sin_addr
) != INADDR_ANY
)
*name
= savestr(np
->n_name
);
sin
->sin_family
= hp
->h_addrtype
;
bcopy(hp
->h_addr
, &sin
->sin_addr
, hp
->h_length
);
*name
= savestr(hp
->h_name
);
fprintf(stderr
, "%s: bad value\n", s
);
inet_makenetandmask(val
, sin
, sockmask
);
bzero((char *)sns
, sizeof(*sns
));
sns
->sns_len
= sizeof (*sns
);
struct sockaddr_ns
*sms
= (struct sockaddr_ns
*)sockmask
;
bzero((char *)sms
, sizeof(*sns
));
sms
->sns_addr
.x_net
= *(union ns_net
*)ns_bh
;
sns
->sns_addr
= ns_addr(s
);
return (!ns_nullhost(sns
->sns_addr
));
struct sockaddr_iso
*siso
= (struct sockaddr_iso
*)sin
;
struct iso_addr
iso_addr();
siso
->siso_family
= AF_ISO
;
siso
->siso_len
= sizeof(*siso
);
siso
->siso_addr
= iso_addr(s
);
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];
register char *p
; register u_char
*q
; u_char
*q_lim
;
port
= ntohs(work
.x_port
);
if (ns_nullhost(work
) && net
.long_e
== 0) {
(void)sprintf(mybuf
, "*.%xH", port
);
(void)sprintf(mybuf
, "*.*");
if (bcmp(ns_bh
, work
.x_host
.c_host
, 6) == 0) {
} else if (bcmp(ns_nullh
, 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
);
for (; *p
; p
++) switch (*p
) {
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
printf("got message of size %d\n", n
);
print_rtmsg((struct rt_msghdr
*)msg
, n
);
struct sockaddr_in m_dst
, m_gateway
, m_mask
;
rtmsg(cmd
, dst
, gateway
, mask
, flags
)
struct sockaddr_in
*dst
, *gateway
, *mask
;
int len
= sizeof(m_rtmsg
), rlen
;
bzero((char *)&m_rtmsg
, sizeof(m_rtmsg
));
m_rtmsg
.m_rtm
.rtm_flags
= flags
;
m_rtmsg
.m_rtm
.rtm_version
= 1;
m_rtmsg
.m_rtm
.rtm_seq
= ++seq
;
m_rtmsg
.m_gateway
= *gateway
;
m_rtmsg
.m_rtm
.rtm_count
= 3;
m_rtmsg
.m_rtm
.rtm_count
= 2;
m_rtmsg
.m_rtm
.rtm_msglen
= len
;
m_rtmsg
.m_rtm
.rtm_type
= cmd
;
if ((rlen
= write(s
, (char *)&m_rtmsg
, len
)) < 0) {
perror("writing to routing socket");
printf("got only %d for rlen\n", rlen
);
if ((rlen
= read(s
, (char *)&m_rtmsg
, len
)) < 0) {
perror("reading from routing socket");
printf("got only %d for rlen\n", rlen
);
if ((m_rtmsg
.m_rtm
.rtm_pid
!= pid
) ||
(m_rtmsg
.m_rtm
.rtm_seq
!= seq
)) {
printf("Got response for somebody else's request");
print_rtmsg( &m_rtmsg
.m_rtm
, rlen
);
if ((m_rtmsg
.m_rtm
.rtm_flags
& RTF_DONE
) == 0) {
errno
= m_rtmsg
.m_rtm
.rtm_errno
;
perror("response from routing socket turned down");
"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\7sendpipe\4recvpipe\3expire\2hopcount\1mtu";
#define ROUNDUP(a) ((char *)(1 + (((((int)a)) - 1) | (sizeof(long) - 1))))
register struct rt_msghdr
*rtm
;
register struct sockaddr
*sa
;
if (rtm
->rtm_version
!= 1) {
printf("routing message version %d not understood\n",
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
,
"\1UP\2GATEWAY\3HOST\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT");
printf("\nlocks: "); bprintf(stdout
, rtm
->rtm_locks
, metricnames
);
printf(" inits: "); bprintf(stdout
, rtm
->rtm_inits
, metricnames
);
printf("\n%d sockaddrs: ", i
);
cp
= ((char *)(rtm
+ 1));
sa
= (struct sockaddr
*)cp
;
printf(" %s", routename(sa
));
cp
= ROUNDUP(cp
+ sa
->sa_len
);
if (gotsome
== 0) i
= '<'; else i
= ',';
for (; (i
= *s
) > 32; s
++)