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