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