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