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