Commit | Line | Data |
---|---|---|
85d8a62e | 1 | #ifndef lint |
69b7ef61 | 2 | static char sccsid[] = "@(#)startup.c 4.7 (Berkeley) %G%"; |
85d8a62e SL |
3 | #endif |
4 | ||
5 | /* | |
6 | * Routing Table Management Daemon | |
7 | */ | |
7fe7fe74 | 8 | #include "defs.h" |
ad34083f | 9 | #include <sys/ioctl.h> |
85d8a62e SL |
10 | #include <net/if.h> |
11 | #include <nlist.h> | |
69b7ef61 | 12 | #include <syslog.h> |
85d8a62e SL |
13 | |
14 | struct interface *ifnet; | |
15 | int kmem = -1; | |
16 | int lookforinterfaces = 1; | |
17 | int performnlist = 1; | |
18 | int externalinterfaces = 0; /* # of remote and local interfaces */ | |
ad34083f | 19 | int gateway = 0; /* 1 if we are a gateway to parts beyond */ |
85d8a62e SL |
20 | |
21 | struct nlist nl[] = { | |
22 | #define N_IFNET 0 | |
23 | { "_ifnet" }, | |
7fe7fe74 | 24 | { "" }, |
85d8a62e SL |
25 | }; |
26 | ||
27 | /* | |
28 | * Probe the kernel through /dev/kmem to find the network | |
29 | * interfaces which have configured themselves. If the | |
30 | * interface is present but not yet up (for example an | |
31 | * ARPANET IMP), set the lookforinterfaces flag so we'll | |
32 | * come back later and look again. | |
33 | */ | |
34 | ifinit() | |
35 | { | |
36 | struct interface *ifp; | |
37 | struct ifnet ifs, *next; | |
38 | char name[32], *cp, *index(); | |
39 | ||
40 | if (performnlist) { | |
41 | nlist("/vmunix", nl); | |
42 | if (nl[N_IFNET].n_value == 0) { | |
43 | printf("ifnet: not in namelist\n"); | |
44 | goto bad; | |
45 | } | |
46 | performnlist = 0; | |
f804e046 | 47 | if (gateway > 0) |
ad34083f | 48 | rtdefault(); |
85d8a62e SL |
49 | } |
50 | if (kmem < 0) { | |
51 | kmem = open("/dev/kmem", 0); | |
52 | if (kmem < 0) { | |
53 | perror("/dev/kmem"); | |
54 | goto bad; | |
55 | } | |
56 | } | |
57 | if (lseek(kmem, (long)nl[N_IFNET].n_value, 0) == -1 || | |
58 | read(kmem, (char *)&next, sizeof (next)) != sizeof (next)) { | |
59 | printf("ifnet: error reading kmem\n"); | |
60 | goto bad; | |
61 | } | |
62 | lookforinterfaces = 0; | |
63 | while (next) { | |
64 | if (lseek(kmem, (long)next, 0) == -1 || | |
65 | read(kmem, (char *)&ifs, sizeof (ifs)) != sizeof (ifs)) { | |
66 | perror("read"); | |
67 | goto bad; | |
68 | } | |
69 | next = ifs.if_next; | |
70 | if ((ifs.if_flags & IFF_UP) == 0) { | |
71 | lookforinterfaces = 1; | |
72 | continue; | |
73 | } | |
74 | /* already known to us? */ | |
75 | if (if_ifwithaddr(&ifs.if_addr)) | |
76 | continue; | |
77 | /* argh, this'll have to change sometime */ | |
78 | if (ifs.if_addr.sa_family != AF_INET) | |
79 | continue; | |
80 | /* no one cares about software loopback interfaces */ | |
81 | if (ifs.if_net == LOOPBACKNET) | |
82 | continue; | |
83 | ifp = (struct interface *)malloc(sizeof (struct interface)); | |
84 | if (ifp == 0) { | |
85 | printf("routed: out of memory\n"); | |
86 | break; | |
87 | } | |
88 | /* | |
89 | * Count the # of directly connected networks | |
90 | * and point to point links which aren't looped | |
91 | * back to ourself. This is used below to | |
92 | * decide if we should be a routing ``supplier''. | |
93 | */ | |
94 | if ((ifs.if_flags & IFF_POINTOPOINT) == 0 || | |
95 | if_ifwithaddr(&ifs.if_dstaddr) == 0) | |
96 | externalinterfaces++; | |
ad34083f MK |
97 | if ((ifs.if_flags & IFF_LOCAL) == 0 && gateway == 0) { |
98 | /* | |
99 | * If we have an interface to a non-local network, | |
100 | * we are a candidate for use as a gateway. | |
101 | */ | |
102 | gateway = 1; | |
103 | rtdefault(); | |
104 | } | |
85d8a62e SL |
105 | lseek(kmem, ifs.if_name, 0); |
106 | read(kmem, name, sizeof (name)); | |
107 | name[sizeof (name) - 1] = '\0'; | |
108 | cp = index(name, '\0'); | |
109 | *cp++ = ifs.if_unit + '0'; | |
110 | *cp = '\0'; | |
111 | ifp->int_name = malloc(strlen(name) + 1); | |
112 | if (ifp->int_name == 0) { | |
113 | fprintf(stderr, "routed: ifinit: out of memory\n"); | |
114 | goto bad; /* ??? */ | |
115 | } | |
116 | strcpy(ifp->int_name, name); | |
117 | ifp->int_addr = ifs.if_addr; | |
118 | ifp->int_flags = ifs.if_flags | IFF_INTERFACE; | |
119 | /* this works because broadaddr overlaps dstaddr */ | |
120 | ifp->int_broadaddr = ifs.if_broadaddr; | |
121 | ifp->int_net = ifs.if_net; | |
122 | ifp->int_metric = 0; | |
123 | ifp->int_next = ifnet; | |
124 | ifnet = ifp; | |
125 | traceinit(ifp); | |
126 | addrouteforif(ifp); | |
127 | } | |
128 | if (externalinterfaces > 1 && supplier < 0) | |
129 | supplier = 1; | |
130 | return; | |
131 | bad: | |
132 | sleep(60); | |
7fe7fe74 | 133 | close(kmem), close(s); |
85d8a62e SL |
134 | execv("/etc/routed", argv0); |
135 | _exit(0177); | |
136 | } | |
137 | ||
138 | addrouteforif(ifp) | |
139 | struct interface *ifp; | |
140 | { | |
141 | struct sockaddr_in net; | |
142 | struct sockaddr *dst; | |
143 | int state, metric; | |
144 | struct rt_entry *rt; | |
145 | ||
146 | if (ifp->int_flags & IFF_POINTOPOINT) | |
147 | dst = &ifp->int_dstaddr; | |
148 | else { | |
149 | bzero((char *)&net, sizeof (net)); | |
150 | net.sin_family = AF_INET; | |
151 | net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY); | |
152 | dst = (struct sockaddr *)&net; | |
153 | } | |
69b7ef61 MK |
154 | if (ifp->int_transitions++ > 0) |
155 | syslog(LOG_ERR, "re-installing interface %s", ifp->int_name); | |
85d8a62e SL |
156 | rt = rtlookup(dst); |
157 | rtadd(dst, &ifp->int_addr, ifp->int_metric, | |
158 | ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE)); | |
159 | if (rt) | |
160 | rtdelete(rt); | |
161 | } | |
162 | ||
163 | /* | |
164 | * As a concession to the ARPANET we read a list of gateways | |
165 | * from /etc/gateways and add them to our tables. This file | |
166 | * exists at each ARPANET gateway and indicates a set of ``remote'' | |
167 | * gateways (i.e. a gateway which we can't immediately determine | |
168 | * if it's present or not as we can do for those directly connected | |
169 | * at the hardware level). If a gateway is marked ``passive'' | |
170 | * in the file, then we assume it doesn't have a routing process | |
171 | * of our design and simply assume it's always present. Those | |
172 | * not marked passive are treated as if they were directly | |
173 | * connected -- they're added into the interface list so we'll | |
174 | * send them routing updates. | |
175 | */ | |
176 | gwkludge() | |
177 | { | |
178 | struct sockaddr_in dst, gate; | |
179 | FILE *fp; | |
180 | char *type, *dname, *gname, *qual, buf[BUFSIZ]; | |
181 | struct interface *ifp; | |
182 | int metric; | |
ad34083f | 183 | struct rt_entry route; |
85d8a62e SL |
184 | |
185 | fp = fopen("/etc/gateways", "r"); | |
186 | if (fp == NULL) | |
187 | return; | |
188 | qual = buf; | |
189 | dname = buf + 64; | |
190 | gname = buf + ((BUFSIZ - 64) / 3); | |
191 | type = buf + (((BUFSIZ - 64) * 2) / 3); | |
192 | bzero((char *)&dst, sizeof (dst)); | |
193 | bzero((char *)&gate, sizeof (gate)); | |
ad34083f | 194 | bzero((char *)&route, sizeof(route)); |
85d8a62e SL |
195 | /* format: {net | host} XX gateway XX metric DD [passive]\n */ |
196 | #define readentry(fp) \ | |
197 | fscanf((fp), "%s %s gateway %s metric %d %s\n", \ | |
198 | type, dname, gname, &metric, qual) | |
199 | for (;;) { | |
85d8a62e SL |
200 | if (readentry(fp) == EOF) |
201 | break; | |
7fe7fe74 | 202 | if (!getnetorhostname(type, dname, &dst)) |
85d8a62e | 203 | continue; |
7fe7fe74 | 204 | if (!gethostnameornumber(gname, &gate)) |
85d8a62e | 205 | continue; |
ad34083f MK |
206 | if (strcmp(qual, "passive") == 0) { |
207 | /* | |
208 | * Passive entries aren't placed in our tables, | |
209 | * only the kernel's, so we don't copy all of the | |
210 | * external routing information within a net. | |
211 | * Internal machines should use the default | |
212 | * route to a suitable gateway (like us). | |
213 | */ | |
214 | route.rt_dst = *(struct sockaddr *) &dst; | |
215 | route.rt_router = *(struct sockaddr *) &gate; | |
216 | route.rt_flags = RTF_UP; | |
217 | if (strcmp(type, "host") == 0) | |
218 | route.rt_flags |= RTF_HOST; | |
219 | if (metric) | |
220 | route.rt_flags |= RTF_GATEWAY; | |
221 | (void) ioctl(s, SIOCADDRT, (char *)&route.rt_rt); | |
222 | continue; | |
223 | } | |
224 | /* assume no duplicate entries */ | |
225 | externalinterfaces++; | |
85d8a62e SL |
226 | ifp = (struct interface *)malloc(sizeof (*ifp)); |
227 | bzero((char *)ifp, sizeof (*ifp)); | |
228 | ifp->int_flags = IFF_REMOTE; | |
229 | /* can't identify broadcast capability */ | |
230 | ifp->int_net = inet_netof(dst.sin_addr); | |
231 | if (strcmp(type, "host") == 0) { | |
232 | ifp->int_flags |= IFF_POINTOPOINT; | |
233 | ifp->int_dstaddr = *((struct sockaddr *)&dst); | |
234 | } | |
85d8a62e SL |
235 | ifp->int_addr = *((struct sockaddr *)&gate); |
236 | ifp->int_metric = metric; | |
237 | ifp->int_next = ifnet; | |
238 | ifnet = ifp; | |
239 | addrouteforif(ifp); | |
240 | } | |
241 | fclose(fp); | |
242 | } | |
7fe7fe74 SL |
243 | |
244 | getnetorhostname(type, name, sin) | |
245 | char *type, *name; | |
246 | struct sockaddr_in *sin; | |
247 | { | |
248 | ||
249 | if (strcmp(type, "net") == 0) { | |
250 | struct netent *np = getnetbyname(name); | |
251 | int n; | |
252 | ||
7fe7fe74 SL |
253 | if (np == 0) |
254 | n = inet_network(name); | |
20932249 SL |
255 | else { |
256 | if (np->n_addrtype != AF_INET) | |
257 | return (0); | |
7fe7fe74 | 258 | n = np->n_net; |
20932249 | 259 | } |
7fe7fe74 SL |
260 | sin->sin_family = AF_INET; |
261 | sin->sin_addr = inet_makeaddr(n, INADDR_ANY); | |
262 | return (1); | |
263 | } | |
264 | if (strcmp(type, "host") == 0) { | |
265 | struct hostent *hp = gethostbyname(name); | |
266 | ||
7fe7fe74 SL |
267 | if (hp == 0) |
268 | sin->sin_addr.s_addr = inet_addr(name); | |
20932249 SL |
269 | else { |
270 | if (hp->h_addrtype != AF_INET) | |
271 | return (0); | |
7fe7fe74 | 272 | bcopy(hp->h_addr, &sin->sin_addr, hp->h_length); |
20932249 | 273 | } |
7fe7fe74 SL |
274 | sin->sin_family = AF_INET; |
275 | return (1); | |
276 | } | |
277 | return (0); | |
278 | } | |
279 | ||
280 | gethostnameornumber(name, sin) | |
281 | char *name; | |
282 | struct sockaddr_in *sin; | |
283 | { | |
284 | struct hostent *hp; | |
285 | ||
286 | hp = gethostbyname(name); | |
287 | if (hp) { | |
288 | bcopy(hp->h_addr, &sin->sin_addr, hp->h_length); | |
289 | sin->sin_family = hp->h_addrtype; | |
290 | return (1); | |
291 | } | |
292 | sin->sin_addr.s_addr = inet_addr(name); | |
293 | sin->sin_family = AF_INET; | |
294 | return (sin->sin_addr.s_addr != -1); | |
295 | } |