xref: /original-bsd/sbin/routed/startup.c (revision f052b07a)
1 /*
2  * Copyright (c) 1983, 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)startup.c	5.14 (Berkeley) 06/18/88";
20 #endif /* not lint */
21 
22 /*
23  * Routing Table Management Daemon
24  */
25 #include "defs.h"
26 #include <sys/ioctl.h>
27 #include <net/if.h>
28 #include <syslog.h>
29 
30 struct	interface *ifnet;
31 int	lookforinterfaces = 1;
32 int	externalinterfaces = 0;		/* # of remote and local interfaces */
33 int	foundloopback;			/* valid flag for loopaddr */
34 struct	sockaddr loopaddr;		/* our address on loopback */
35 
36 /*
37  * Find the network interfaces which have configured themselves.
38  * If the interface is present but not yet up (for example an
39  * ARPANET IMP), set the lookforinterfaces flag so we'll
40  * come back later and look again.
41  */
42 ifinit()
43 {
44 	struct interface ifs, *ifp;
45 	int s, n;
46 	char buf[BUFSIZ];
47         struct ifconf ifc;
48         struct ifreq ifreq, *ifr;
49         struct sockaddr_in *sin;
50 	u_long i;
51 
52 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
53 		syslog(LOG_ERR, "socket: %m");
54 		exit(1);
55 	}
56         ifc.ifc_len = sizeof (buf);
57         ifc.ifc_buf = buf;
58         if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
59                 syslog(LOG_ERR, "ioctl (get interface configuration)");
60 		close(s);
61                 return (0);
62         }
63         ifr = ifc.ifc_req;
64 	lookforinterfaces = 0;
65         for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) {
66 		bzero((char *)&ifs, sizeof(ifs));
67 		ifs.int_addr = ifr->ifr_addr;
68 		ifreq = *ifr;
69                 if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
70                         syslog(LOG_ERR, "ioctl (get interface flags)");
71                         continue;
72                 }
73 		ifs.int_flags = ifreq.ifr_flags | IFF_INTERFACE;
74 		if ((ifs.int_flags & IFF_UP) == 0 ||
75 		    ifr->ifr_addr.sa_family == AF_UNSPEC) {
76 			lookforinterfaces = 1;
77 			continue;
78 		}
79 		/*
80 		 * already known to us?
81 		 * This allows multiple point-to-point links
82 		 * to share a source address (possibly with one
83 		 * other link), but assumes that there will not be
84 		 * multiple links with the same destination address.
85 		 */
86 		if (ifs.int_flags & IFF_POINTOPOINT) {
87 			if (if_ifwithdstaddr(&ifs.int_dstaddr))
88 				continue;
89 		} else if (if_ifwithaddr(&ifs.int_addr))
90 			continue;
91 		/* argh, this'll have to change sometime */
92 		if (ifs.int_addr.sa_family != AF_INET)
93 			continue;
94 		if (ifs.int_flags & IFF_LOOPBACK) {
95 			ifs.int_flags |= IFF_PASSIVE;
96 			foundloopback = 1;
97 			loopaddr = ifs.int_addr;
98 			for (ifp = ifnet; ifp; ifp = ifp->int_next)
99 			    if (ifp->int_flags & IFF_POINTOPOINT)
100 				add_ptopt_localrt(ifp);
101 		}
102                 if (ifs.int_flags & IFF_POINTOPOINT) {
103                         if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
104                                 syslog(LOG_ERR, "ioctl (get dstaddr)");
105                                 continue;
106 			}
107 			ifs.int_dstaddr = ifreq.ifr_dstaddr;
108 		}
109                 if (ifs.int_flags & IFF_BROADCAST) {
110                         if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
111                                 syslog(LOG_ERR, "ioctl (get broadaddr)");
112                                 continue;
113                         }
114 			ifs.int_broadaddr = ifreq.ifr_broadaddr;
115 		}
116 		if (ioctl(s, SIOCGIFMETRIC, (char *)&ifreq) < 0)
117 			syslog(LOG_ERR, "ioctl (get metric)");
118 		else
119 			ifs.int_metric = ifreq.ifr_metric;
120 		/*
121 		 * Use a minimum metric of one;
122 		 * treat the interface metric (default 0)
123 		 * as an increment to the hop count of one.
124 		 */
125 		ifs.int_metric++;
126 		if (ioctl(s, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
127 			syslog(LOG_ERR, "ioctl (get netmask)");
128 			continue;
129 		}
130 		sin = (struct sockaddr_in *)&ifreq.ifr_addr;
131 		ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr);
132 		sin = (struct sockaddr_in *)&ifs.int_addr;
133 		i = ntohl(sin->sin_addr.s_addr);
134 		if (IN_CLASSA(i))
135 			ifs.int_netmask = IN_CLASSA_NET;
136 		else if (IN_CLASSB(i))
137 			ifs.int_netmask = IN_CLASSB_NET;
138 		else
139 			ifs.int_netmask = IN_CLASSC_NET;
140 		ifs.int_net = i & ifs.int_netmask;
141 		ifs.int_subnet = i & ifs.int_subnetmask;
142 		if (ifs.int_subnetmask != ifs.int_netmask)
143 			ifs.int_flags |= IFF_SUBNET;
144 		ifp = (struct interface *)malloc(sizeof (struct interface));
145 		if (ifp == 0) {
146 			printf("routed: out of memory\n");
147 			break;
148 		}
149 		*ifp = ifs;
150 		/*
151 		 * Count the # of directly connected networks
152 		 * and point to point links which aren't looped
153 		 * back to ourself.  This is used below to
154 		 * decide if we should be a routing ``supplier''.
155 		 */
156 		if ((ifs.int_flags & IFF_LOOPBACK) == 0 &&
157 		    ((ifs.int_flags & IFF_POINTOPOINT) == 0 ||
158 		    if_ifwithaddr(&ifs.int_dstaddr) == 0))
159 			externalinterfaces++;
160 		/*
161 		 * If we have a point-to-point link, we want to act
162 		 * as a supplier even if it's our only interface,
163 		 * as that's the only way our peer on the other end
164 		 * can tell that the link is up.
165 		 */
166 		if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0)
167 			supplier = 1;
168 		ifp->int_name = malloc(strlen(ifr->ifr_name) + 1);
169 		if (ifp->int_name == 0) {
170 			fprintf(stderr, "routed: ifinit: out of memory\n");
171 			syslog(LOG_ERR, "routed: ifinit: out of memory\n");
172 			return;
173 		}
174 		strcpy(ifp->int_name, ifr->ifr_name);
175 		ifp->int_next = ifnet;
176 		ifnet = ifp;
177 		traceinit(ifp);
178 		addrouteforif(ifp);
179 	}
180 	if (externalinterfaces > 1 && supplier < 0)
181 		supplier = 1;
182 	close(s);
183 }
184 
185 /*
186  * Add route for interface if not currently installed.
187  * Create route to other end if a point-to-point link,
188  * otherwise a route to this (sub)network.
189  * INTERNET SPECIFIC.
190  */
191 addrouteforif(ifp)
192 	register struct interface *ifp;
193 {
194 	struct sockaddr_in net;
195 	struct sockaddr *dst;
196 	int state;
197 	register struct rt_entry *rt;
198 
199 	if (ifp->int_flags & IFF_POINTOPOINT)
200 		dst = &ifp->int_dstaddr;
201 	else {
202 		bzero((char *)&net, sizeof (net));
203 		net.sin_family = AF_INET;
204 		net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY);
205 		dst = (struct sockaddr *)&net;
206 	}
207 	rt = rtfind(dst);
208 	if (rt &&
209 	    (rt->rt_state & (RTS_INTERFACE | RTS_INTERNAL)) == RTS_INTERFACE)
210 		return;
211 	if (rt)
212 		rtdelete(rt);
213 	/*
214 	 * If interface on subnetted network,
215 	 * install route to network as well.
216 	 * This is meant for external viewers.
217 	 */
218 	if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) {
219 		struct in_addr subnet;
220 
221 		subnet = net.sin_addr;
222 		net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
223 		rt = rtfind(dst);
224 		if (rt == 0)
225 			rtadd(dst, &ifp->int_addr, ifp->int_metric,
226 			    ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) |
227 			    RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET));
228 		else if ((rt->rt_state & (RTS_INTERNAL|RTS_SUBNET)) ==
229 		    (RTS_INTERNAL|RTS_SUBNET) &&
230 		    ifp->int_metric < rt->rt_metric)
231 			rtchange(rt, &rt->rt_router, ifp->int_metric);
232 		net.sin_addr = subnet;
233 	}
234 	if (ifp->int_transitions++ > 0)
235 		syslog(LOG_ERR, "re-installing interface %s", ifp->int_name);
236 	state = ifp->int_flags &
237 	    (IFF_INTERFACE | IFF_PASSIVE | IFF_REMOTE | IFF_SUBNET);
238 	if (ifp->int_flags & IFF_POINTOPOINT &&
239 	    (ntohl(((struct sockaddr_in *)&ifp->int_dstaddr)->sin_addr.s_addr) &
240 	    ifp->int_netmask) != ifp->int_net)
241 		state &= ~RTS_SUBNET;
242 	if (ifp->int_flags & IFF_LOOPBACK)
243 		state |= RTS_EXTERNAL;
244 	rtadd(dst, &ifp->int_addr, ifp->int_metric, state);
245 	if (ifp->int_flags & IFF_POINTOPOINT && foundloopback)
246 		add_ptopt_localrt(ifp);
247 }
248 
249 /*
250  * Add route to local end of point-to-point using loopback.
251  * If a route to this network is being sent to neighbors on other nets,
252  * mark this route as subnet so we don't have to propagate it too.
253  */
254 add_ptopt_localrt(ifp)
255 	register struct interface *ifp;
256 {
257 	struct rt_entry *rt;
258 	struct sockaddr *dst;
259 	struct sockaddr_in net;
260 	int state;
261 
262 	state = RTS_INTERFACE | RTS_PASSIVE;
263 
264 	/* look for route to logical network */
265 	bzero((char *)&net, sizeof (net));
266 	net.sin_family = AF_INET;
267 	net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
268 	dst = (struct sockaddr *)&net;
269 	rt = rtfind(dst);
270 	if (rt && rt->rt_state & RTS_INTERNAL)
271 		state |= RTS_SUBNET;
272 
273 	dst = &ifp->int_addr;
274 	if (rt = rtfind(dst)) {
275 		if (rt && rt->rt_state & RTS_INTERFACE)
276 			return;
277 		rtdelete(rt);
278 	}
279 	rtadd(dst, &loopaddr, 1, state);
280 }
281 
282 /*
283  * As a concession to the ARPANET we read a list of gateways
284  * from /etc/gateways and add them to our tables.  This file
285  * exists at each ARPANET gateway and indicates a set of ``remote''
286  * gateways (i.e. a gateway which we can't immediately determine
287  * if it's present or not as we can do for those directly connected
288  * at the hardware level).  If a gateway is marked ``passive''
289  * in the file, then we assume it doesn't have a routing process
290  * of our design and simply assume it's always present.  Those
291  * not marked passive are treated as if they were directly
292  * connected -- they're added into the interface list so we'll
293  * send them routing updates.
294  *
295  * PASSIVE ENTRIES AREN'T NEEDED OR USED ON GATEWAYS RUNNING EGP.
296  */
297 gwkludge()
298 {
299 	struct sockaddr_in dst, gate;
300 	FILE *fp;
301 	char *type, *dname, *gname, *qual, buf[BUFSIZ];
302 	struct interface *ifp;
303 	int metric, n;
304 	struct rt_entry route;
305 
306 	fp = fopen("/etc/gateways", "r");
307 	if (fp == NULL)
308 		return;
309 	qual = buf;
310 	dname = buf + 64;
311 	gname = buf + ((BUFSIZ - 64) / 3);
312 	type = buf + (((BUFSIZ - 64) * 2) / 3);
313 	bzero((char *)&dst, sizeof (dst));
314 	bzero((char *)&gate, sizeof (gate));
315 	bzero((char *)&route, sizeof(route));
316 /* format: {net | host} XX gateway XX metric DD [passive | external]\n */
317 #define	readentry(fp) \
318 	fscanf((fp), "%s %s gateway %s metric %d %s\n", \
319 		type, dname, gname, &metric, qual)
320 	for (;;) {
321 		if ((n = readentry(fp)) == EOF)
322 			break;
323 		if (!getnetorhostname(type, dname, &dst))
324 			continue;
325 		if (!gethostnameornumber(gname, &gate))
326 			continue;
327 		if (metric == 0)			/* XXX */
328 			metric = 1;
329 		if (strcmp(qual, "passive") == 0) {
330 			/*
331 			 * Passive entries aren't placed in our tables,
332 			 * only the kernel's, so we don't copy all of the
333 			 * external routing information within a net.
334 			 * Internal machines should use the default
335 			 * route to a suitable gateway (like us).
336 			 */
337 			route.rt_dst = *(struct sockaddr *) &dst;
338 			route.rt_router = *(struct sockaddr *) &gate;
339 			route.rt_flags = RTF_UP;
340 			if (strcmp(type, "host") == 0)
341 				route.rt_flags |= RTF_HOST;
342 			if (metric)
343 				route.rt_flags |= RTF_GATEWAY;
344 			(void) ioctl(s, SIOCADDRT, (char *)&route.rt_rt);
345 			continue;
346 		}
347 		if (strcmp(qual, "external") == 0) {
348 			/*
349 			 * Entries marked external are handled
350 			 * by other means, e.g. EGP,
351 			 * and are placed in our tables only
352 			 * to prevent overriding them
353 			 * with something else.
354 			 */
355 			rtadd(&dst, &gate, metric, RTS_EXTERNAL|RTS_PASSIVE);
356 			continue;
357 		}
358 		/* assume no duplicate entries */
359 		externalinterfaces++;
360 		ifp = (struct interface *)malloc(sizeof (*ifp));
361 		bzero((char *)ifp, sizeof (*ifp));
362 		ifp->int_flags = IFF_REMOTE;
363 		/* can't identify broadcast capability */
364 		ifp->int_net = inet_netof(dst.sin_addr);
365 		if (strcmp(type, "host") == 0) {
366 			ifp->int_flags |= IFF_POINTOPOINT;
367 			ifp->int_dstaddr = *((struct sockaddr *)&dst);
368 		}
369 		ifp->int_addr = *((struct sockaddr *)&gate);
370 		ifp->int_metric = metric;
371 		ifp->int_next = ifnet;
372 		ifnet = ifp;
373 		addrouteforif(ifp);
374 	}
375 	fclose(fp);
376 }
377 
378 getnetorhostname(type, name, sin)
379 	char *type, *name;
380 	struct sockaddr_in *sin;
381 {
382 
383 	if (strcmp(type, "net") == 0) {
384 		struct netent *np = getnetbyname(name);
385 		int n;
386 
387 		if (np == 0)
388 			n = inet_network(name);
389 		else {
390 			if (np->n_addrtype != AF_INET)
391 				return (0);
392 			n = np->n_net;
393 			/*
394 			 * getnetbyname returns right-adjusted value.
395 			 */
396 			if (n < 128)
397 				n <<= IN_CLASSA_NSHIFT;
398 			else if (n < 65536)
399 				n <<= IN_CLASSB_NSHIFT;
400 			else
401 				n <<= IN_CLASSC_NSHIFT;
402 		}
403 		sin->sin_family = AF_INET;
404 		sin->sin_addr = inet_makeaddr(n, INADDR_ANY);
405 		return (1);
406 	}
407 	if (strcmp(type, "host") == 0) {
408 		struct hostent *hp = gethostbyname(name);
409 
410 		if (hp == 0)
411 			sin->sin_addr.s_addr = inet_addr(name);
412 		else {
413 			if (hp->h_addrtype != AF_INET)
414 				return (0);
415 			bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
416 		}
417 		sin->sin_family = AF_INET;
418 		return (1);
419 	}
420 	return (0);
421 }
422 
423 gethostnameornumber(name, sin)
424 	char *name;
425 	struct sockaddr_in *sin;
426 {
427 	struct hostent *hp;
428 
429 	hp = gethostbyname(name);
430 	if (hp) {
431 		bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
432 		sin->sin_family = hp->h_addrtype;
433 		return (1);
434 	}
435 	sin->sin_addr.s_addr = inet_addr(name);
436 	sin->sin_family = AF_INET;
437 	return (sin->sin_addr.s_addr != -1);
438 }
439