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