don't send net route to subnet gw's unless on subnet 0;
[unix-history] / usr / src / sbin / routed / startup.c
CommitLineData
5ff67f98
DF
1/*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
85d8a62e 7#ifndef lint
09069ad0 8static char sccsid[] = "@(#)startup.c 5.5 (Berkeley) %G%";
5ff67f98 9#endif not lint
85d8a62e
SL
10
11/*
12 * Routing Table Management Daemon
13 */
7fe7fe74 14#include "defs.h"
ad34083f 15#include <sys/ioctl.h>
85d8a62e 16#include <net/if.h>
69b7ef61 17#include <syslog.h>
85d8a62e
SL
18
19struct interface *ifnet;
85d8a62e 20int lookforinterfaces = 1;
85d8a62e 21int externalinterfaces = 0; /* # of remote and local interfaces */
85d8a62e
SL
22
23/*
04667a08
MK
24 * Find the network interfaces which have configured themselves.
25 * If the interface is present but not yet up (for example an
85d8a62e
SL
26 * ARPANET IMP), set the lookforinterfaces flag so we'll
27 * come back later and look again.
28 */
29ifinit()
30{
04667a08
MK
31 struct interface ifs, *ifp;
32 int s, n;
33 char buf[BUFSIZ];
34 struct ifconf ifc;
35 struct ifreq ifreq, *ifr;
36 struct sockaddr_in *sin;
37 u_long i;
85d8a62e 38
04667a08
MK
39 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
40 syslog(LOG_ERR, "socket: %m");
41 exit(1);
85d8a62e 42 }
04667a08
MK
43 ifc.ifc_len = sizeof (buf);
44 ifc.ifc_buf = buf;
45 if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
46 syslog(LOG_ERR, "ioctl (get interface configuration)");
47 close(s);
48 return (0);
49 }
50 ifr = ifc.ifc_req;
85d8a62e 51 lookforinterfaces = 0;
04667a08
MK
52 for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) {
53 bzero((char *)&ifs, sizeof(ifs));
54 ifs.int_addr = ifr->ifr_addr;
55 ifreq = *ifr;
56 if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
57 syslog(LOG_ERR, "ioctl (get interface flags)");
58 continue;
59 }
60 ifs.int_flags = ifreq.ifr_flags | IFF_INTERFACE;
5d6d4622
MK
61 /* no one cares about software loopback interfaces */
62 if (ifs.int_flags & IFF_LOOPBACK)
63 continue;
04667a08
MK
64 if ((ifs.int_flags & IFF_UP) == 0 ||
65 ifr->ifr_addr.sa_family == AF_UNSPEC) {
85d8a62e
SL
66 lookforinterfaces = 1;
67 continue;
68 }
69 /* already known to us? */
04667a08 70 if (if_ifwithaddr(&ifs.int_addr))
85d8a62e
SL
71 continue;
72 /* argh, this'll have to change sometime */
04667a08
MK
73 if (ifs.int_addr.sa_family != AF_INET)
74 continue;
75 if (ifs.int_flags & IFF_POINTOPOINT) {
76 if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
77 syslog(LOG_ERR, "ioctl (get dstaddr)");
78 continue;
79 }
80 ifs.int_dstaddr = ifreq.ifr_dstaddr;
81 }
82 if (ifs.int_flags & IFF_BROADCAST) {
83 if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
84 syslog(LOG_ERR, "ioctl (get broadaddr)");
85 continue;
86 }
87 ifs.int_broadaddr = ifreq.ifr_broadaddr;
88 }
5d6d4622
MK
89 if (ioctl(s, SIOCGIFMETRIC, (char *)&ifreq) < 0)
90 syslog(LOG_ERR, "ioctl (get metric)");
91 else
92 ifs.int_metric = ifreq.ifr_metric;
04667a08
MK
93 if (ioctl(s, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
94 syslog(LOG_ERR, "ioctl (get netmask)");
85d8a62e 95 continue;
04667a08
MK
96 }
97 sin = (struct sockaddr_in *)&ifreq.ifr_addr;
98 ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr);
99 sin = (struct sockaddr_in *)&ifs.int_addr;
100 i = ntohl(sin->sin_addr.s_addr);
101 if (IN_CLASSA(i))
102 ifs.int_netmask = IN_CLASSA_NET;
103 else if (IN_CLASSB(i))
104 ifs.int_netmask = IN_CLASSB_NET;
105 else
106 ifs.int_netmask = IN_CLASSC_NET;
107 ifs.int_net = i & ifs.int_netmask;
108 ifs.int_subnet = i & ifs.int_subnetmask;
4fad5a6e
MK
109 if (ifs.int_subnetmask != ifs.int_netmask)
110 ifs.int_flags |= IFF_SUBNET;
85d8a62e
SL
111 ifp = (struct interface *)malloc(sizeof (struct interface));
112 if (ifp == 0) {
113 printf("routed: out of memory\n");
114 break;
115 }
04667a08 116 *ifp = ifs;
85d8a62e
SL
117 /*
118 * Count the # of directly connected networks
119 * and point to point links which aren't looped
120 * back to ourself. This is used below to
121 * decide if we should be a routing ``supplier''.
122 */
04667a08
MK
123 if ((ifs.int_flags & IFF_POINTOPOINT) == 0 ||
124 if_ifwithaddr(&ifs.int_dstaddr) == 0)
85d8a62e 125 externalinterfaces++;
4ff053a6
MK
126 /*
127 * If we have a point-to-point link, we want to act
128 * as a supplier even if it's our only interface,
129 * as that's the only way our peer on the other end
130 * can tell that the link is up.
131 */
132 if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0)
133 supplier = 1;
04667a08 134 ifp->int_name = malloc(strlen(ifr->ifr_name) + 1);
85d8a62e
SL
135 if (ifp->int_name == 0) {
136 fprintf(stderr, "routed: ifinit: out of memory\n");
137 goto bad; /* ??? */
138 }
04667a08 139 strcpy(ifp->int_name, ifr->ifr_name);
85d8a62e
SL
140 ifp->int_next = ifnet;
141 ifnet = ifp;
142 traceinit(ifp);
143 addrouteforif(ifp);
144 }
145 if (externalinterfaces > 1 && supplier < 0)
146 supplier = 1;
04667a08 147 close(s);
85d8a62e
SL
148 return;
149bad:
150 sleep(60);
7fe7fe74 151 close(kmem), close(s);
85d8a62e
SL
152 execv("/etc/routed", argv0);
153 _exit(0177);
154}
155
4fad5a6e
MK
156/*
157 * Add route for interface if not currently installed.
158 * Create route to other end if a point-to-point link,
159 * otherwise a route to this (sub)network.
160 * INTERNET SPECIFIC.
161 */
85d8a62e
SL
162addrouteforif(ifp)
163 struct interface *ifp;
164{
165 struct sockaddr_in net;
166 struct sockaddr *dst;
167 int state, metric;
168 struct rt_entry *rt;
169
170 if (ifp->int_flags & IFF_POINTOPOINT)
171 dst = &ifp->int_dstaddr;
172 else {
173 bzero((char *)&net, sizeof (net));
174 net.sin_family = AF_INET;
04667a08 175 net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY);
85d8a62e
SL
176 dst = (struct sockaddr *)&net;
177 }
04667a08
MK
178 rt = rtfind(dst);
179 if (rt && (rt->rt_state & RTS_INTERFACE))
a7c33470 180 return;
85d8a62e
SL
181 if (rt)
182 rtdelete(rt);
04667a08
MK
183 if (ifp->int_transitions++ > 0)
184 syslog(LOG_ERR, "re-installing interface %s", ifp->int_name);
a7c33470 185 rtadd(dst, &ifp->int_addr, ifp->int_metric,
4fad5a6e
MK
186 ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE|IFF_SUBNET));
187
188 /*
189 * If interface on subnetted network,
190 * install route to network as well.
191 * This is meant for external viewers.
192 */
193 if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) {
194 net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
195 rt = rtfind(dst);
196 if (rt && (rt->rt_state & RTS_INTERFACE))
197 return;
198 rtadd(dst, &ifp->int_addr, ifp->int_metric,
199 (ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE) |
09069ad0 200 RTS_INTERNAL | RTS_SUBNET));
4fad5a6e 201 }
85d8a62e
SL
202}
203
204/*
205 * As a concession to the ARPANET we read a list of gateways
206 * from /etc/gateways and add them to our tables. This file
207 * exists at each ARPANET gateway and indicates a set of ``remote''
208 * gateways (i.e. a gateway which we can't immediately determine
209 * if it's present or not as we can do for those directly connected
210 * at the hardware level). If a gateway is marked ``passive''
211 * in the file, then we assume it doesn't have a routing process
212 * of our design and simply assume it's always present. Those
213 * not marked passive are treated as if they were directly
214 * connected -- they're added into the interface list so we'll
215 * send them routing updates.
216 */
217gwkludge()
218{
219 struct sockaddr_in dst, gate;
220 FILE *fp;
221 char *type, *dname, *gname, *qual, buf[BUFSIZ];
222 struct interface *ifp;
09069ad0 223 int metric, n;
ad34083f 224 struct rt_entry route;
85d8a62e
SL
225
226 fp = fopen("/etc/gateways", "r");
227 if (fp == NULL)
228 return;
229 qual = buf;
230 dname = buf + 64;
231 gname = buf + ((BUFSIZ - 64) / 3);
232 type = buf + (((BUFSIZ - 64) * 2) / 3);
233 bzero((char *)&dst, sizeof (dst));
234 bzero((char *)&gate, sizeof (gate));
ad34083f 235 bzero((char *)&route, sizeof(route));
85d8a62e
SL
236 /* format: {net | host} XX gateway XX metric DD [passive]\n */
237#define readentry(fp) \
238 fscanf((fp), "%s %s gateway %s metric %d %s\n", \
239 type, dname, gname, &metric, qual)
240 for (;;) {
09069ad0 241 if ((n = readentry(fp)) == EOF)
85d8a62e 242 break;
7fe7fe74 243 if (!getnetorhostname(type, dname, &dst))
85d8a62e 244 continue;
7fe7fe74 245 if (!gethostnameornumber(gname, &gate))
85d8a62e 246 continue;
ad34083f
MK
247 if (strcmp(qual, "passive") == 0) {
248 /*
249 * Passive entries aren't placed in our tables,
250 * only the kernel's, so we don't copy all of the
251 * external routing information within a net.
252 * Internal machines should use the default
253 * route to a suitable gateway (like us).
254 */
255 route.rt_dst = *(struct sockaddr *) &dst;
256 route.rt_router = *(struct sockaddr *) &gate;
257 route.rt_flags = RTF_UP;
258 if (strcmp(type, "host") == 0)
259 route.rt_flags |= RTF_HOST;
260 if (metric)
261 route.rt_flags |= RTF_GATEWAY;
262 (void) ioctl(s, SIOCADDRT, (char *)&route.rt_rt);
263 continue;
264 }
4fad5a6e
MK
265 if (strcmp(qual, "external") == 0) {
266 /*
267 * Entries marked external are handled
268 * by other means, e.g. EGP,
269 * and are placed in our tables only
270 * to prevent overriding them
271 * with something else.
272 */
273 rtadd(&dst, &gate, metric, RTS_EXTERNAL|RTS_PASSIVE);
09069ad0 274 continue;
4fad5a6e 275 }
ad34083f
MK
276 /* assume no duplicate entries */
277 externalinterfaces++;
85d8a62e
SL
278 ifp = (struct interface *)malloc(sizeof (*ifp));
279 bzero((char *)ifp, sizeof (*ifp));
280 ifp->int_flags = IFF_REMOTE;
281 /* can't identify broadcast capability */
282 ifp->int_net = inet_netof(dst.sin_addr);
283 if (strcmp(type, "host") == 0) {
284 ifp->int_flags |= IFF_POINTOPOINT;
285 ifp->int_dstaddr = *((struct sockaddr *)&dst);
286 }
85d8a62e
SL
287 ifp->int_addr = *((struct sockaddr *)&gate);
288 ifp->int_metric = metric;
289 ifp->int_next = ifnet;
290 ifnet = ifp;
291 addrouteforif(ifp);
292 }
293 fclose(fp);
294}
7fe7fe74
SL
295
296getnetorhostname(type, name, sin)
297 char *type, *name;
298 struct sockaddr_in *sin;
299{
300
301 if (strcmp(type, "net") == 0) {
302 struct netent *np = getnetbyname(name);
303 int n;
304
7fe7fe74
SL
305 if (np == 0)
306 n = inet_network(name);
20932249
SL
307 else {
308 if (np->n_addrtype != AF_INET)
309 return (0);
7fe7fe74 310 n = np->n_net;
04667a08
MK
311 /*
312 * getnetbyname returns right-adjusted value.
313 */
314 if (n < 128)
315 n <<= IN_CLASSA_NSHIFT;
316 else if (n < 65536)
317 n <<= IN_CLASSB_NSHIFT;
318 else
319 n <<= IN_CLASSC_NSHIFT;
20932249 320 }
7fe7fe74
SL
321 sin->sin_family = AF_INET;
322 sin->sin_addr = inet_makeaddr(n, INADDR_ANY);
323 return (1);
324 }
325 if (strcmp(type, "host") == 0) {
326 struct hostent *hp = gethostbyname(name);
327
7fe7fe74
SL
328 if (hp == 0)
329 sin->sin_addr.s_addr = inet_addr(name);
20932249
SL
330 else {
331 if (hp->h_addrtype != AF_INET)
332 return (0);
7fe7fe74 333 bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
20932249 334 }
7fe7fe74
SL
335 sin->sin_family = AF_INET;
336 return (1);
337 }
338 return (0);
339}
340
341gethostnameornumber(name, sin)
342 char *name;
343 struct sockaddr_in *sin;
344{
345 struct hostent *hp;
346
347 hp = gethostbyname(name);
348 if (hp) {
349 bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
350 sin->sin_family = hp->h_addrtype;
351 return (1);
352 }
353 sin->sin_addr.s_addr = inet_addr(name);
354 sin->sin_family = AF_INET;
355 return (sin->sin_addr.s_addr != -1);
356}