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