* Copyright (c) 1983, 1989 The Regents of the University of California.
* Redistribution and use in source and binary forms are permitted provided
* that: (1) source distributions retain this entire copyright notice and
* comment, and (2) distributions including binaries display the following
* acknowledgement: ``This product includes software developed by the
* University of California, Berkeley and its contributors'' in the
* documentation or other materials provided with the distribution and in
* all advertising materials mentioning features or use of this software.
* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)route.c 5.27 (Berkeley) 6/22/90";
struct sockaddr_iso siso
;
} so_dst
, so_gate
, so_mask
, so_genmask
, so_ifa
, so_ifp
, *so_addrs
[] =
{ &so_dst
, &so_gate
, &so_mask
, &so_genmask
, &so_ifa
, &so_ifp
, 0};
typedef union sockunion
*sup
;
int forcehost
, forcenet
, doflush
, nflag
, af
, qflag
, 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 *malloc(), *routename(), *netname();
extern char *iso_ntoa(), *link_ntoa();
(lseek(kmem, (off_t)(p), 0), read(kmem, (char *)&(d), sizeof (d)))
"usage: route [ -nqCv ] cmd [[ -<qualifers> ] args ]\n");
if (cp
) fprintf(stderr
, "(botched keyword: %s)\n", cp
);
for (; argc
> 0 && argv
[0][0] == '-'; argc
--, argv
++) {
for (argvp
= argv
[0]++; *argvp
; argvp
++)
Cflag
++; /* Use old ioctls */
s
= socket(AF_INET
, SOCK_RAW
, 0);
s
= socket(PF_ROUTE
, SOCK_RAW
, 0);
if (argc
> 0) switch (keyword(*argv
)) {
* Purge all entries in the routing tables not
* associated with network interfaces.
int bufsize
, needed
, seqno
, rlen
;
register struct rt_msghdr
*rtm
;
shutdown(s
, 0); /* Don't want to read back our messages */
if (argc
== 2 && **argv
== '-') switch (keyword(1 + *argv
)) {
case K_INET
: af
= AF_INET
; break;
case K_XNS
: af
= AF_NS
; break;
case K_LINK
: af
= AF_LINK
; break;
case K_ISO
: case K_OSI
: af
= AF_ISO
; break;
if ((needed
= getkerninfo(KINFO_RT_DUMP
, 0, 0, 0)) < 0)
{ perror("route-getkerninfo-estimate"); exit(1);}
if ((buf
= malloc(needed
)) == 0)
{ printf("out of space\n");; exit(1);}
if ((rlen
= getkerninfo(KINFO_RT_DUMP
, buf
, &needed
, 0)) < 0)
{ perror("actual retrieval of routing table"); exit(1);}
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
;
if ((rlen
= write(s
, next
, rtm
->rtm_msglen
)) < 0) {
perror("writing to routing socket");
printf("got only %d for rlen\n", rlen
);
struct sockaddr
*sa
= &m
.m_u
.u_sa
;
printf("%-20.20s ", (rtm
->rtm_flags
& RTF_HOST
) ?
routename(sa
) : netname(sa
));
sa
= (struct sockaddr
*)(sa
->sa_len
+ (char *)sa
);
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(&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
);
n
= 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
);
n
= 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
, *mask
;
int ishost
, metric
= 0, ret
, attempts
, oerrno
, flags
= 0, next
;
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_ns
);
(void) getaddr(RTA_NETMASK
, *++argv
, 0);
(void) getaddr(RTA_GENMASK
, *++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 (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 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
)
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 *)(1 + &(sin
->sin_addr
));
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.
register union sockunion
*su
;
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;
default: usage("Internal Error"); /*NOTREACHED*/
if (strcmp(s
, "default") == 0) {
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
, &su
->sin
.sin_addr
, hp
->h_length
);
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
;
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
);
register char *cp
= m_rtmsg
.m_space
;
bzero((char *)&m_rtmsg
, sizeof(m_rtmsg
));
m_rtmsg
.m_rtm
.rtm_flags
= flags
;
m_rtmsg
.m_rtm
.rtm_version
= RTM_VERSION
;
m_rtmsg
.m_rtm
.rtm_seq
= ++seq
;
m_rtmsg
.m_rtm
.rtm_addrs
= rtm_addrs
;
m_rtmsg
.m_rtm
.rtm_rmx
= rt_metrics
;
m_rtmsg
.m_rtm
.rtm_inits
= rtm_inits
;
#define ROUND(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
#define NEXTADDR(w, u) { if (rtm_addrs & (w)) {l = (u).sa.sa_len;\
if(verbose)sodump(&(u),"u");if(l == 0) l = sizeof(int); l = ROUND(l);\
bcopy((char *)&(u), cp, l); cp += l;}}
NEXTADDR(RTA_DST
, so_dst
);
NEXTADDR(RTA_GATEWAY
, so_gate
);
NEXTADDR(RTA_NETMASK
, so_mask
);
NEXTADDR(RTA_GENMASK
, so_genmask
);
m_rtmsg
.m_rtm
.rtm_msglen
= l
= cp
- (char *)&m_rtmsg
;
m_rtmsg
.m_rtm
.rtm_type
= cmd
;
print_rtmsg(&m_rtmsg
.m_rtm
, l
);
if ((rlen
= write(s
, (char *)&m_rtmsg
, l
)) < 0) {
perror("writing to routing socket");
printf("got only %d for rlen\n", rlen
);
"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\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE";
#define ROUNDUP(a) ((char *)(1 + (((((int)a)) - 1) | (sizeof(long) - 1))))
register struct rt_msghdr
*rtm
;
register struct sockaddr
*sa
;
if (rtm
->rtm_version
!= RTM_VERSION
) {
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
, routeflags
);
printf("\nlocks: "); bprintf(stdout
, rtm
->rtm_rmx
.rmx_locks
, metricnames
);
printf(" inits: "); bprintf(stdout
, rtm
->rtm_inits
, metricnames
);
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
;
printf(" %s", routename(sa
));
cp
= ROUNDUP(cp
+ sa
->sa_len
);
if (gotsome
== 0) i
= '<'; else i
= ',';
for (; (i
= *s
) > 32; s
++)
register struct keytab
*kt
= keywords
;
while (kt
->kt_cp
&& strcmp(kt
->kt_cp
, cp
))
register union sockunion
*su
;
switch (su
->sa
.sa_family
) {
printf("%s: link %s; ", which
, link_ntoa(&su
->sdl
));
printf("%s: iso %s; ", which
, iso_ntoa(&su
->siso
.siso_addr
));
printf("%s: inet %s; ", which
, inet_ntoa(su
->sin
.sin_addr
));
printf("%s: xns %s; ", which
, ns_ntoa(&su
->sns
.sns_addr
));