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