Get ready for SO_OOBINLINE; Handle TELNET BREAK distinct from TELNET IP.
[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
5d6d4622 8static char sccsid[] = "@(#)startup.c 5.3 (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
SL
16#include <net/if.h>
17#include <nlist.h>
69b7ef61 18#include <syslog.h>
85d8a62e
SL
19
20struct interface *ifnet;
85d8a62e
SL
21int lookforinterfaces = 1;
22int performnlist = 1;
23int externalinterfaces = 0; /* # of remote and local interfaces */
85d8a62e
SL
24
25/*
04667a08
MK
26 * Find the network interfaces which have configured themselves.
27 * If the interface is present but not yet up (for example an
85d8a62e
SL
28 * ARPANET IMP), set the lookforinterfaces flag so we'll
29 * come back later and look again.
30 */
31ifinit()
32{
04667a08
MK
33 struct interface ifs, *ifp;
34 int s, n;
35 char buf[BUFSIZ];
36 struct ifconf ifc;
37 struct ifreq ifreq, *ifr;
38 struct sockaddr_in *sin;
39 u_long i;
85d8a62e 40
04667a08
MK
41 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
42 syslog(LOG_ERR, "socket: %m");
43 exit(1);
85d8a62e 44 }
04667a08
MK
45 ifc.ifc_len = sizeof (buf);
46 ifc.ifc_buf = buf;
47 if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
48 syslog(LOG_ERR, "ioctl (get interface configuration)");
49 close(s);
50 return (0);
51 }
52 ifr = ifc.ifc_req;
85d8a62e 53 lookforinterfaces = 0;
04667a08
MK
54 for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) {
55 bzero((char *)&ifs, sizeof(ifs));
56 ifs.int_addr = ifr->ifr_addr;
57 ifreq = *ifr;
58 if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
59 syslog(LOG_ERR, "ioctl (get interface flags)");
60 continue;
61 }
62 ifs.int_flags = ifreq.ifr_flags | IFF_INTERFACE;
5d6d4622
MK
63 /* no one cares about software loopback interfaces */
64 if (ifs.int_flags & IFF_LOOPBACK)
65 continue;
04667a08
MK
66 if ((ifs.int_flags & IFF_UP) == 0 ||
67 ifr->ifr_addr.sa_family == AF_UNSPEC) {
85d8a62e
SL
68 lookforinterfaces = 1;
69 continue;
70 }
71 /* already known to us? */
04667a08 72 if (if_ifwithaddr(&ifs.int_addr))
85d8a62e
SL
73 continue;
74 /* argh, this'll have to change sometime */
04667a08
MK
75 if (ifs.int_addr.sa_family != AF_INET)
76 continue;
77 if (ifs.int_flags & IFF_POINTOPOINT) {
78 if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
79 syslog(LOG_ERR, "ioctl (get dstaddr)");
80 continue;
81 }
82 ifs.int_dstaddr = ifreq.ifr_dstaddr;
83 }
84 if (ifs.int_flags & IFF_BROADCAST) {
85 if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
86 syslog(LOG_ERR, "ioctl (get broadaddr)");
87 continue;
88 }
89 ifs.int_broadaddr = ifreq.ifr_broadaddr;
90 }
5d6d4622
MK
91 if (ioctl(s, SIOCGIFMETRIC, (char *)&ifreq) < 0)
92 syslog(LOG_ERR, "ioctl (get metric)");
93 else
94 ifs.int_metric = ifreq.ifr_metric;
04667a08
MK
95 if (ioctl(s, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
96 syslog(LOG_ERR, "ioctl (get netmask)");
85d8a62e 97 continue;
04667a08
MK
98 }
99 sin = (struct sockaddr_in *)&ifreq.ifr_addr;
100 ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr);
101 sin = (struct sockaddr_in *)&ifs.int_addr;
102 i = ntohl(sin->sin_addr.s_addr);
103 if (IN_CLASSA(i))
104 ifs.int_netmask = IN_CLASSA_NET;
105 else if (IN_CLASSB(i))
106 ifs.int_netmask = IN_CLASSB_NET;
107 else
108 ifs.int_netmask = IN_CLASSC_NET;
109 ifs.int_net = i & ifs.int_netmask;
110 ifs.int_subnet = i & ifs.int_subnetmask;
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
156addrouteforif(ifp)
157 struct interface *ifp;
158{
159 struct sockaddr_in net;
160 struct sockaddr *dst;
161 int state, metric;
162 struct rt_entry *rt;
163
164 if (ifp->int_flags & IFF_POINTOPOINT)
165 dst = &ifp->int_dstaddr;
166 else {
167 bzero((char *)&net, sizeof (net));
168 net.sin_family = AF_INET;
04667a08 169 net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY);
85d8a62e
SL
170 dst = (struct sockaddr *)&net;
171 }
04667a08
MK
172 rt = rtfind(dst);
173 if (rt && (rt->rt_state & RTS_INTERFACE))
a7c33470 174 return;
85d8a62e
SL
175 if (rt)
176 rtdelete(rt);
04667a08
MK
177 if (ifp->int_transitions++ > 0)
178 syslog(LOG_ERR, "re-installing interface %s", ifp->int_name);
a7c33470
MK
179 rtadd(dst, &ifp->int_addr, ifp->int_metric,
180 ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE));
85d8a62e
SL
181}
182
183/*
184 * As a concession to the ARPANET we read a list of gateways
185 * from /etc/gateways and add them to our tables. This file
186 * exists at each ARPANET gateway and indicates a set of ``remote''
187 * gateways (i.e. a gateway which we can't immediately determine
188 * if it's present or not as we can do for those directly connected
189 * at the hardware level). If a gateway is marked ``passive''
190 * in the file, then we assume it doesn't have a routing process
191 * of our design and simply assume it's always present. Those
192 * not marked passive are treated as if they were directly
193 * connected -- they're added into the interface list so we'll
194 * send them routing updates.
195 */
196gwkludge()
197{
198 struct sockaddr_in dst, gate;
199 FILE *fp;
200 char *type, *dname, *gname, *qual, buf[BUFSIZ];
201 struct interface *ifp;
202 int metric;
ad34083f 203 struct rt_entry route;
85d8a62e
SL
204
205 fp = fopen("/etc/gateways", "r");
206 if (fp == NULL)
207 return;
208 qual = buf;
209 dname = buf + 64;
210 gname = buf + ((BUFSIZ - 64) / 3);
211 type = buf + (((BUFSIZ - 64) * 2) / 3);
212 bzero((char *)&dst, sizeof (dst));
213 bzero((char *)&gate, sizeof (gate));
ad34083f 214 bzero((char *)&route, sizeof(route));
85d8a62e
SL
215 /* format: {net | host} XX gateway XX metric DD [passive]\n */
216#define readentry(fp) \
217 fscanf((fp), "%s %s gateway %s metric %d %s\n", \
218 type, dname, gname, &metric, qual)
219 for (;;) {
85d8a62e
SL
220 if (readentry(fp) == EOF)
221 break;
7fe7fe74 222 if (!getnetorhostname(type, dname, &dst))
85d8a62e 223 continue;
7fe7fe74 224 if (!gethostnameornumber(gname, &gate))
85d8a62e 225 continue;
ad34083f
MK
226 if (strcmp(qual, "passive") == 0) {
227 /*
228 * Passive entries aren't placed in our tables,
229 * only the kernel's, so we don't copy all of the
230 * external routing information within a net.
231 * Internal machines should use the default
232 * route to a suitable gateway (like us).
233 */
234 route.rt_dst = *(struct sockaddr *) &dst;
235 route.rt_router = *(struct sockaddr *) &gate;
236 route.rt_flags = RTF_UP;
237 if (strcmp(type, "host") == 0)
238 route.rt_flags |= RTF_HOST;
239 if (metric)
240 route.rt_flags |= RTF_GATEWAY;
241 (void) ioctl(s, SIOCADDRT, (char *)&route.rt_rt);
242 continue;
243 }
244 /* assume no duplicate entries */
245 externalinterfaces++;
85d8a62e
SL
246 ifp = (struct interface *)malloc(sizeof (*ifp));
247 bzero((char *)ifp, sizeof (*ifp));
248 ifp->int_flags = IFF_REMOTE;
249 /* can't identify broadcast capability */
250 ifp->int_net = inet_netof(dst.sin_addr);
251 if (strcmp(type, "host") == 0) {
252 ifp->int_flags |= IFF_POINTOPOINT;
253 ifp->int_dstaddr = *((struct sockaddr *)&dst);
254 }
85d8a62e
SL
255 ifp->int_addr = *((struct sockaddr *)&gate);
256 ifp->int_metric = metric;
257 ifp->int_next = ifnet;
258 ifnet = ifp;
259 addrouteforif(ifp);
260 }
261 fclose(fp);
262}
7fe7fe74
SL
263
264getnetorhostname(type, name, sin)
265 char *type, *name;
266 struct sockaddr_in *sin;
267{
268
269 if (strcmp(type, "net") == 0) {
270 struct netent *np = getnetbyname(name);
271 int n;
272
7fe7fe74
SL
273 if (np == 0)
274 n = inet_network(name);
20932249
SL
275 else {
276 if (np->n_addrtype != AF_INET)
277 return (0);
7fe7fe74 278 n = np->n_net;
04667a08
MK
279 /*
280 * getnetbyname returns right-adjusted value.
281 */
282 if (n < 128)
283 n <<= IN_CLASSA_NSHIFT;
284 else if (n < 65536)
285 n <<= IN_CLASSB_NSHIFT;
286 else
287 n <<= IN_CLASSC_NSHIFT;
20932249 288 }
7fe7fe74
SL
289 sin->sin_family = AF_INET;
290 sin->sin_addr = inet_makeaddr(n, INADDR_ANY);
291 return (1);
292 }
293 if (strcmp(type, "host") == 0) {
294 struct hostent *hp = gethostbyname(name);
295
7fe7fe74
SL
296 if (hp == 0)
297 sin->sin_addr.s_addr = inet_addr(name);
20932249
SL
298 else {
299 if (hp->h_addrtype != AF_INET)
300 return (0);
7fe7fe74 301 bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
20932249 302 }
7fe7fe74
SL
303 sin->sin_family = AF_INET;
304 return (1);
305 }
306 return (0);
307}
308
309gethostnameornumber(name, sin)
310 char *name;
311 struct sockaddr_in *sin;
312{
313 struct hostent *hp;
314
315 hp = gethostbyname(name);
316 if (hp) {
317 bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
318 sin->sin_family = hp->h_addrtype;
319 return (1);
320 }
321 sin->sin_addr.s_addr = inet_addr(name);
322 sin->sin_family = AF_INET;
323 return (sin->sin_addr.s_addr != -1);
324}