* Copyright (c) 1983, 1988 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.
static char sccsid
[] = "@(#)startup.c 5.14 (Berkeley) %G%";
* Routing Table Management Daemon
int lookforinterfaces
= 1;
int externalinterfaces
= 0; /* # of remote and local interfaces */
int foundloopback
; /* valid flag for loopaddr */
struct sockaddr loopaddr
; /* our address on loopback */
* Find the network interfaces which have configured themselves.
* If the interface is present but not yet up (for example an
* ARPANET IMP), set the lookforinterfaces flag so we'll
* come back later and look again.
struct interface ifs
, *ifp
;
struct ifreq ifreq
, *ifr
;
if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
syslog(LOG_ERR
, "socket: %m");
ifc
.ifc_len
= sizeof (buf
);
if (ioctl(s
, SIOCGIFCONF
, (char *)&ifc
) < 0) {
syslog(LOG_ERR
, "ioctl (get interface configuration)");
for (n
= ifc
.ifc_len
/ sizeof (struct ifreq
); n
> 0; n
--, ifr
++) {
bzero((char *)&ifs
, sizeof(ifs
));
ifs
.int_addr
= ifr
->ifr_addr
;
if (ioctl(s
, SIOCGIFFLAGS
, (char *)&ifreq
) < 0) {
syslog(LOG_ERR
, "ioctl (get interface flags)");
ifs
.int_flags
= ifreq
.ifr_flags
| IFF_INTERFACE
;
if ((ifs
.int_flags
& IFF_UP
) == 0 ||
ifr
->ifr_addr
.sa_family
== AF_UNSPEC
) {
* This allows multiple point-to-point links
* to share a source address (possibly with one
* other link), but assumes that there will not be
* multiple links with the same destination address.
if (ifs
.int_flags
& IFF_POINTOPOINT
) {
if (if_ifwithdstaddr(&ifs
.int_dstaddr
))
} else if (if_ifwithaddr(&ifs
.int_addr
))
/* argh, this'll have to change sometime */
if (ifs
.int_addr
.sa_family
!= AF_INET
)
if (ifs
.int_flags
& IFF_LOOPBACK
) {
ifs
.int_flags
|= IFF_PASSIVE
;
for (ifp
= ifnet
; ifp
; ifp
= ifp
->int_next
)
if (ifp
->int_flags
& IFF_POINTOPOINT
)
if (ifs
.int_flags
& IFF_POINTOPOINT
) {
if (ioctl(s
, SIOCGIFDSTADDR
, (char *)&ifreq
) < 0) {
syslog(LOG_ERR
, "ioctl (get dstaddr)");
ifs
.int_dstaddr
= ifreq
.ifr_dstaddr
;
if (ifs
.int_flags
& IFF_BROADCAST
) {
if (ioctl(s
, SIOCGIFBRDADDR
, (char *)&ifreq
) < 0) {
syslog(LOG_ERR
, "ioctl (get broadaddr)");
ifs
.int_broadaddr
= ifreq
.ifr_broadaddr
;
if (ioctl(s
, SIOCGIFMETRIC
, (char *)&ifreq
) < 0)
syslog(LOG_ERR
, "ioctl (get metric)");
ifs
.int_metric
= ifreq
.ifr_metric
;
* Use a minimum metric of one;
* treat the interface metric (default 0)
* as an increment to the hop count of one.
if (ioctl(s
, SIOCGIFNETMASK
, (char *)&ifreq
) < 0) {
syslog(LOG_ERR
, "ioctl (get netmask)");
sin
= (struct sockaddr_in
*)&ifreq
.ifr_addr
;
ifs
.int_subnetmask
= ntohl(sin
->sin_addr
.s_addr
);
sin
= (struct sockaddr_in
*)&ifs
.int_addr
;
i
= ntohl(sin
->sin_addr
.s_addr
);
ifs
.int_netmask
= IN_CLASSA_NET
;
ifs
.int_netmask
= IN_CLASSB_NET
;
ifs
.int_netmask
= IN_CLASSC_NET
;
ifs
.int_net
= i
& ifs
.int_netmask
;
ifs
.int_subnet
= i
& ifs
.int_subnetmask
;
if (ifs
.int_subnetmask
!= ifs
.int_netmask
)
ifs
.int_flags
|= IFF_SUBNET
;
ifp
= (struct interface
*)malloc(sizeof (struct interface
));
printf("routed: out of memory\n");
* Count the # of directly connected networks
* and point to point links which aren't looped
* back to ourself. This is used below to
* decide if we should be a routing ``supplier''.
if ((ifs
.int_flags
& IFF_LOOPBACK
) == 0 &&
((ifs
.int_flags
& IFF_POINTOPOINT
) == 0 ||
if_ifwithaddr(&ifs
.int_dstaddr
) == 0))
* If we have a point-to-point link, we want to act
* as a supplier even if it's our only interface,
* as that's the only way our peer on the other end
* can tell that the link is up.
if ((ifs
.int_flags
& IFF_POINTOPOINT
) && supplier
< 0)
ifp
->int_name
= malloc(strlen(ifr
->ifr_name
) + 1);
if (ifp
->int_name
== 0) {
fprintf(stderr
, "routed: ifinit: out of memory\n");
syslog(LOG_ERR
, "routed: ifinit: out of memory\n");
strcpy(ifp
->int_name
, ifr
->ifr_name
);
if (externalinterfaces
> 1 && supplier
< 0)
* Add route for interface if not currently installed.
* Create route to other end if a point-to-point link,
* otherwise a route to this (sub)network.
register struct interface
*ifp
;
register struct rt_entry
*rt
;
if (ifp
->int_flags
& IFF_POINTOPOINT
)
bzero((char *)&net
, sizeof (net
));
net
.sin_family
= AF_INET
;
net
.sin_addr
= inet_makeaddr(ifp
->int_subnet
, INADDR_ANY
);
dst
= (struct sockaddr
*)&net
;
(rt
->rt_state
& (RTS_INTERFACE
| RTS_INTERNAL
)) == RTS_INTERFACE
)
* If interface on subnetted network,
* install route to network as well.
* This is meant for external viewers.
if ((ifp
->int_flags
& (IFF_SUBNET
|IFF_POINTOPOINT
)) == IFF_SUBNET
) {
net
.sin_addr
= inet_makeaddr(ifp
->int_net
, INADDR_ANY
);
rtadd(dst
, &ifp
->int_addr
, ifp
->int_metric
,
((ifp
->int_flags
& (IFF_INTERFACE
|IFF_REMOTE
)) |
RTS_PASSIVE
| RTS_INTERNAL
| RTS_SUBNET
));
else if ((rt
->rt_state
& (RTS_INTERNAL
|RTS_SUBNET
)) ==
(RTS_INTERNAL
|RTS_SUBNET
) &&
ifp
->int_metric
< rt
->rt_metric
)
rtchange(rt
, &rt
->rt_router
, ifp
->int_metric
);
if (ifp
->int_transitions
++ > 0)
syslog(LOG_ERR
, "re-installing interface %s", ifp
->int_name
);
(IFF_INTERFACE
| IFF_PASSIVE
| IFF_REMOTE
| IFF_SUBNET
);
if (ifp
->int_flags
& IFF_POINTOPOINT
&&
(ntohl(((struct sockaddr_in
*)&ifp
->int_dstaddr
)->sin_addr
.s_addr
) &
ifp
->int_netmask
) != ifp
->int_net
)
if (ifp
->int_flags
& IFF_LOOPBACK
)
rtadd(dst
, &ifp
->int_addr
, ifp
->int_metric
, state
);
if (ifp
->int_flags
& IFF_POINTOPOINT
&& foundloopback
)
* Add route to local end of point-to-point using loopback.
* If a route to this network is being sent to neighbors on other nets,
* mark this route as subnet so we don't have to propagate it too.
register struct interface
*ifp
;
state
= RTS_INTERFACE
| RTS_PASSIVE
;
/* look for route to logical network */
bzero((char *)&net
, sizeof (net
));
net
.sin_family
= AF_INET
;
net
.sin_addr
= inet_makeaddr(ifp
->int_net
, INADDR_ANY
);
dst
= (struct sockaddr
*)&net
;
if (rt
&& rt
->rt_state
& RTS_INTERNAL
)
if (rt
&& rt
->rt_state
& RTS_INTERFACE
)
rtadd(dst
, &loopaddr
, 1, state
);
* As a concession to the ARPANET we read a list of gateways
* from /etc/gateways and add them to our tables. This file
* exists at each ARPANET gateway and indicates a set of ``remote''
* gateways (i.e. a gateway which we can't immediately determine
* if it's present or not as we can do for those directly connected
* at the hardware level). If a gateway is marked ``passive''
* in the file, then we assume it doesn't have a routing process
* of our design and simply assume it's always present. Those
* not marked passive are treated as if they were directly
* connected -- they're added into the interface list so we'll
* send them routing updates.
* PASSIVE ENTRIES AREN'T NEEDED OR USED ON GATEWAYS RUNNING EGP.
struct sockaddr_in dst
, gate
;
char *type
, *dname
, *gname
, *qual
, buf
[BUFSIZ
];
fp
= fopen("/etc/gateways", "r");
gname
= buf
+ ((BUFSIZ
- 64) / 3);
type
= buf
+ (((BUFSIZ
- 64) * 2) / 3);
bzero((char *)&dst
, sizeof (dst
));
bzero((char *)&gate
, sizeof (gate
));
bzero((char *)&route
, sizeof(route
));
/* format: {net | host} XX gateway XX metric DD [passive | external]\n */
fscanf((fp), "%s %s gateway %s metric %d %s\n", \
type, dname, gname, &metric, qual)
if ((n
= readentry(fp
)) == EOF
)
if (!getnetorhostname(type
, dname
, &dst
))
if (!gethostnameornumber(gname
, &gate
))
if (metric
== 0) /* XXX */
if (strcmp(qual
, "passive") == 0) {
* Passive entries aren't placed in our tables,
* only the kernel's, so we don't copy all of the
* external routing information within a net.
* Internal machines should use the default
* route to a suitable gateway (like us).
route
.rt_dst
= *(struct sockaddr
*) &dst
;
route
.rt_router
= *(struct sockaddr
*) &gate
;
if (strcmp(type
, "host") == 0)
route
.rt_flags
|= RTF_HOST
;
route
.rt_flags
|= RTF_GATEWAY
;
(void) ioctl(s
, SIOCADDRT
, (char *)&route
.rt_rt
);
if (strcmp(qual
, "external") == 0) {
* Entries marked external are handled
* by other means, e.g. EGP,
* and are placed in our tables only
* to prevent overriding them
rtadd(&dst
, &gate
, metric
, RTS_EXTERNAL
|RTS_PASSIVE
);
/* assume no duplicate entries */
ifp
= (struct interface
*)malloc(sizeof (*ifp
));
bzero((char *)ifp
, sizeof (*ifp
));
ifp
->int_flags
= IFF_REMOTE
;
/* can't identify broadcast capability */
ifp
->int_net
= inet_netof(dst
.sin_addr
);
if (strcmp(type
, "host") == 0) {
ifp
->int_flags
|= IFF_POINTOPOINT
;
ifp
->int_dstaddr
= *((struct sockaddr
*)&dst
);
ifp
->int_addr
= *((struct sockaddr
*)&gate
);
ifp
->int_metric
= metric
;
getnetorhostname(type
, name
, sin
)
if (strcmp(type
, "net") == 0) {
struct netent
*np
= getnetbyname(name
);
if (np
->n_addrtype
!= AF_INET
)
* getnetbyname returns right-adjusted value.
sin
->sin_family
= AF_INET
;
sin
->sin_addr
= inet_makeaddr(n
, INADDR_ANY
);
if (strcmp(type
, "host") == 0) {
struct hostent
*hp
= gethostbyname(name
);
sin
->sin_addr
.s_addr
= inet_addr(name
);
if (hp
->h_addrtype
!= AF_INET
)
bcopy(hp
->h_addr
, &sin
->sin_addr
, hp
->h_length
);
sin
->sin_family
= AF_INET
;
gethostnameornumber(name
, sin
)
hp
= gethostbyname(name
);
bcopy(hp
->h_addr
, &sin
->sin_addr
, hp
->h_length
);
sin
->sin_family
= hp
->h_addrtype
;
sin
->sin_addr
.s_addr
= inet_addr(name
);
sin
->sin_family
= AF_INET
;
return (sin
->sin_addr
.s_addr
!= -1);