config.c revision 1.1 1 /*
2 * The mrouted program is covered by the license in the accompanying file
3 * named "LICENSE". Use of the mrouted program represents acceptance of
4 * the terms and conditions listed in that file.
5 *
6 * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
7 * Leland Stanford Junior University.
8 *
9 *
10 * from: Id: config.c,v 1.3 1993/05/30 01:36:38 deering Exp
11 * $Id: config.c,v 1.1 1994/01/11 20:15:48 brezak Exp $
12 */
13
14 #ifndef lint
15 static char rcsid[] = "$Id: config.c,v 1.1 1994/01/11 20:15:48 brezak Exp $";
16 #endif
17
18 #include "defs.h"
19
20
21 char *configfilename = _PATH_MROUTED_CONF;
22
23
24 /*
25 * Forward declarations.
26 */
27 static char *next_word();
28
29
30 /*
31 * Query the kernel to find network interfaces that are multicast-capable
32 * and install them in the uvifs array.
33 */
34 void config_vifs_from_kernel()
35 {
36 struct ifreq ifbuf[32];
37 struct ifreq *ifrp, *ifend, *mp;
38 struct ifconf ifc;
39 register struct uvif *v;
40 register vifi_t vifi;
41 int i, n;
42 u_long addr, mask, subnet;
43 short flags;
44
45 ifc.ifc_buf = (char *)ifbuf;
46 ifc.ifc_len = sizeof(ifbuf);
47 if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
48 log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
49
50 ifrp = (struct ifreq *)ifbuf;
51 ifend = (struct ifreq *)((char *)ifbuf + ifc.ifc_len);
52 /*
53 * Loop through all of the interfaces.
54 */
55 for (; ifrp < ifend; ifrp = (struct ifreq *)((char *)ifrp + n)) {
56 struct ifreq ifr;
57 #if BSD >= 199006
58 n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
59 if (n < sizeof(*ifrp))
60 n = sizeof(*ifrp);
61 #else
62 n = sizeof(*ifrp);
63 #endif
64 /*
65 * Ignore any interface for an address family other than IP.
66 */
67 addr = ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr;
68 if (ifrp->ifr_addr.sa_family != AF_INET)
69 continue;
70
71 /*
72 * Need a template to preserve address info that is
73 * used below to locate the next entry. (Otherwise,
74 * SIOCGIFFLAGS stomps over it because the requests
75 * are returned in a union.)
76 */
77 bcopy(ifrp->ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
78
79 /*
80 * Ignore loopback interfaces and interfaces that do not support
81 * multicast.
82 */
83 if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
84 log(LOG_ERR, errno, "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
85 flags = ifr.ifr_flags;
86 if ((flags & (IFF_LOOPBACK|IFF_MULTICAST)) != IFF_MULTICAST) continue;
87
88 /*
89 * Ignore any interface whose address and mask do not define a
90 * valid subnet number, or whose address is of the form {subnet,0}
91 * or {subnet,-1}.
92 */
93 if (ioctl(udp_socket, SIOCGIFNETMASK, (char *)&ifr) < 0)
94 log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", ifr.ifr_name);
95 mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
96 subnet = addr & mask;
97 if (!inet_valid_subnet(subnet, mask) ||
98 addr == subnet ||
99 addr == (subnet | ~mask)) {
100 log(LOG_WARNING, 0,
101 "ignoring %s, has invalid address (%s) and/or mask (%08x)",
102 ifr.ifr_name, inet_fmt(addr, s1), ntohl(mask));
103 continue;
104 }
105
106 /*
107 * Ignore any interface that is connected to the same subnet as
108 * one already installed in the uvifs array.
109 */
110 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
111 if ((addr & v->uv_subnetmask) == v->uv_subnet ||
112 (v->uv_subnet & mask) == subnet) {
113 log(LOG_WARNING, 0, "ignoring %s, same subnet as %s",
114 ifr.ifr_name, v->uv_name);
115 break;
116 }
117 }
118 if (vifi != numvifs) continue;
119
120 /*
121 * If there is room in the uvifs array, install this interface.
122 */
123 if (numvifs == MAXVIFS) {
124 log(LOG_WARNING, 0, "too many vifs, ignoring %s", ifr.ifr_name);
125 continue;
126 }
127 v = &uvifs[numvifs];
128 v->uv_flags = 0;
129 v->uv_metric = DEFAULT_METRIC;
130 v->uv_threshold = DEFAULT_THRESHOLD;
131 v->uv_lcl_addr = addr;
132 v->uv_rmt_addr = 0;
133 v->uv_subnet = subnet;
134 v->uv_subnetmask = mask;
135 v->uv_subnetbcast = subnet | ~mask;
136 strncpy(v->uv_name, ifr.ifr_name, IFNAMSIZ);
137 v->uv_groups = NULL;
138 v->uv_neighbors = NULL;
139
140 log(LOG_INFO, 0, "installing %s (%s on subnet %s) as vif #%u",
141 v->uv_name, inet_fmt(addr, s1), inet_fmts(subnet, mask, s2),
142 numvifs);
143
144 ++numvifs;
145
146 /*
147 * If the interface is not yet up, set the vifs_down flag to
148 * remind us to check again later.
149 */
150 if (!(flags & IFF_UP)) {
151 v->uv_flags |= VIFF_DOWN;
152 vifs_down = TRUE;
153 }
154 }
155 }
156
157 static struct ifreq *
158 ifconfaddr(ifcp, a)
159 struct ifconf *ifcp;
160 u_long a;
161 {
162 int n;
163 struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf;
164 struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len);
165
166 while (ifrp < ifend) {
167 if (ifrp->ifr_addr.sa_family == AF_INET &&
168 ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == a)
169 return (ifrp);
170 #if BSD >= 199006
171 n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
172 if (n < sizeof(*ifrp))
173 ++ifrp;
174 else
175 ifrp = (struct ifreq *)((char *)ifrp + n);
176 #else
177 ++ifrp;
178 #endif
179 }
180 return (0);
181 }
182 /*
183 * Read the config file to learn about tunnel vifs and
184 * non-default phyint parameters.
185 */
186 void config_vifs_from_file()
187 {
188 FILE *f;
189 char linebuf[100];
190 char *w, *s, c;
191 u_long lcl_addr, rmt_addr;
192 struct ifconf ifc;
193 struct ifreq *ifr;
194 struct ifreq ffr;
195 int i;
196 u_int n;
197 struct ifreq ifbuf[32];
198 vifi_t vifi;
199 struct uvif *v;
200
201 f = fopen(configfilename, "r");
202 if (f == NULL) {
203 if (errno != ENOENT)
204 log(LOG_WARNING, errno, "can't open %s", configfilename);
205 return;
206 }
207
208 ifc.ifc_buf = (char *)ifbuf;
209 ifc.ifc_len = sizeof(ifbuf);
210 if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
211 log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
212
213 while (fgets(linebuf, sizeof(linebuf), f) != NULL) {
214
215 s = linebuf;
216 if (EQUAL((w = next_word(&s)), "")) {
217 /*
218 * blank or comment line; ignore
219 */
220 }
221
222 else if (EQUAL(w, "phyint")) {
223 /*
224 * phyint <local-addr> [disable] [metric <m>] [threshold <t>]
225 */
226
227 /*
228 * Parse the local address.
229 */
230 if (EQUAL((w = next_word(&s)), "")) {
231 log(LOG_WARNING, 0,
232 "missing phyint address in %s",
233 configfilename);
234 continue;
235 }
236 if ((lcl_addr = inet_parse(w)) == 0xffffffff ||
237 !inet_valid_host(lcl_addr)) {
238 log(LOG_WARNING, 0,
239 "invalid phyint address '%s' in %s",
240 w, configfilename);
241 continue;
242 }
243
244 /*
245 * Look up the vif with the specified local address.
246 */
247 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
248 if (!(v->uv_flags & VIFF_TUNNEL) &&
249 lcl_addr == v->uv_lcl_addr) {
250 break;
251 }
252 }
253 if (vifi == numvifs) {
254 log(LOG_WARNING, 0,
255 "phyint %s in %s is not a configured interface",
256 inet_fmt(lcl_addr, s1), configfilename);
257 continue;
258 }
259
260 /*
261 * Look for "disable", "metric" and "threshold" options.
262 */
263 while (!EQUAL((w = next_word(&s)), "")) {
264 if (EQUAL(w, "disable")) {
265 v->uv_flags |= VIFF_DISABLED;
266 }
267 else if (EQUAL(w, "metric")) {
268 if(EQUAL((w = next_word(&s)), "")) {
269 log(LOG_WARNING, 0,
270 "missing metric for phyint %s in %s",
271 inet_fmt(lcl_addr, s1), configfilename);
272 w = "garbage";
273 break;
274 }
275 if(sscanf(w, "%u%c", &n, &c) != 1 ||
276 n < 1 || n >= UNREACHABLE ) {
277 log(LOG_WARNING, 0,
278 "invalid metric '%s' for phyint %s in %s",
279 w, inet_fmt(lcl_addr, s1), configfilename);
280 break;
281 }
282 v->uv_metric = n;
283 }
284 else if (EQUAL(w, "threshold")) {
285 if(EQUAL((w = next_word(&s)), "")) {
286 log(LOG_WARNING, 0,
287 "missing threshold for phyint %s in %s",
288 inet_fmt(lcl_addr, s1), configfilename);
289 w = "garbage";
290 break;
291 }
292 if(sscanf(w, "%u%c", &n, &c) != 1 ||
293 n < 1 || n > 255 ) {
294 log(LOG_WARNING, 0,
295 "invalid threshold '%s' for phyint %s in %s",
296 w, inet_fmt(lcl_addr, s1), configfilename);
297 break;
298 }
299 v->uv_threshold = n;
300 }
301 else break;
302 }
303 if (!EQUAL(w, "")) continue;
304 }
305
306 else if (EQUAL(w, "tunnel")) {
307 /*
308 * tunnel <local-addr> <remote-addr> [srcrt] [metric <m>] [threshold <t>]
309 */
310
311 /*
312 * Parse the local address.
313 */
314 if (EQUAL((w = next_word(&s)), "")) {
315 log(LOG_WARNING, 0,
316 "missing tunnel local address in %s",
317 configfilename);
318 continue;
319 }
320 if ((lcl_addr = inet_parse(w)) == 0xffffffff ||
321 !inet_valid_host(lcl_addr)) {
322 log(LOG_WARNING, 0,
323 "invalid tunnel local address '%s' in %s",
324 w, configfilename);
325 continue;
326 }
327
328 /*
329 * Make sure the local address is one of ours.
330 */
331 ifr = ifconfaddr(&ifc, lcl_addr);
332 if (ifr == 0) {
333 log(LOG_WARNING, 0,
334 "tunnel local address %s in %s is not one of ours",
335 inet_fmt(lcl_addr, s1), configfilename);
336 continue;
337 }
338
339 /*
340 * Make sure the local address doesn't name a loopback interface..
341 */
342 strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ);
343 if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr) < 0) {
344 log(LOG_ERR, errno,
345 "ioctl SIOCGIFFLAGS for %s", ffr.ifr_name);
346 }
347 if (ffr.ifr_flags & IFF_LOOPBACK) {
348 log(LOG_WARNING, 0,
349 "tunnel local address %s in %s is a loopback interface",
350 inet_fmt(lcl_addr, s1), configfilename);
351 continue;
352 }
353
354 /*
355 * Parse the remote address.
356 */
357 if (EQUAL((w = next_word(&s)), "")) {
358 log(LOG_WARNING, 0,
359 "missing tunnel remote address in %s",
360 configfilename);
361 continue;
362 }
363 if ((rmt_addr = inet_parse(w)) == 0xffffffff ||
364 !inet_valid_host(rmt_addr)) {
365 log(LOG_WARNING, 0,
366 "invalid tunnel remote address %s in %s",
367 w, configfilename);
368 continue;
369 }
370
371 /*
372 * Make sure the remote address is not one of ours.
373 */
374 if (ifconfaddr(&ifc, rmt_addr) != 0) {
375 log(LOG_WARNING, 0,
376 "tunnel remote address %s in %s is one of ours",
377 inet_fmt(rmt_addr, s1), configfilename);
378 continue;
379 }
380
381 /*
382 * Make sure the remote address has not been used for another
383 * tunnel and does not belong to a subnet to which we have direct
384 * access on an enabled phyint.
385 */
386 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
387 if (v->uv_flags & VIFF_TUNNEL) {
388 if (rmt_addr == v->uv_rmt_addr) {
389 log(LOG_WARNING, 0,
390 "duplicate tunnel remote address %s in %s",
391 inet_fmt(rmt_addr, s1), configfilename);
392 break;
393 }
394 }
395 else if (!(v->uv_flags & VIFF_DISABLED)) {
396 if ((rmt_addr & v->uv_subnetmask) == v->uv_subnet) {
397 log(LOG_WARNING, 0,
398 "unnecessary tunnel remote address %s in %s",
399 inet_fmt(rmt_addr, s1), configfilename);
400 break;
401 }
402 }
403 }
404 if (vifi != numvifs) continue;
405
406 /*
407 * OK, let's initialize a uvif structure for the tunnel.
408 */
409 if (numvifs == MAXVIFS) {
410 log(LOG_WARNING, 0, "too many vifs, ignoring tunnel to %s",
411 inet_fmt(rmt_addr, s1));
412 continue;
413 }
414 v = &uvifs[numvifs];
415 v->uv_flags = VIFF_TUNNEL;
416 v->uv_metric = DEFAULT_METRIC;
417 v->uv_threshold = DEFAULT_THRESHOLD;
418 v->uv_lcl_addr = lcl_addr;
419 v->uv_rmt_addr = rmt_addr;
420 v->uv_subnet = 0;
421 v->uv_subnetmask = 0;
422 v->uv_subnetbcast = 0;
423 strncpy(v->uv_name, ffr.ifr_name, IFNAMSIZ);
424 v->uv_groups = NULL;
425 v->uv_neighbors = NULL;
426
427 /*
428 * Look for "metric" and "threshold" options.
429 */
430 while (!EQUAL((w = next_word(&s)), "")) {
431 if (EQUAL(w, "metric")) {
432 if(EQUAL((w = next_word(&s)), "")) {
433 log(LOG_WARNING, 0,
434 "missing metric for tunnel to %s in %s",
435 inet_fmt(rmt_addr, s1), configfilename);
436 w = "garbage";
437 break;
438 }
439 if(sscanf(w, "%u%c", &n, &c) != 1 ||
440 n < 1 || n >= UNREACHABLE ) {
441 log(LOG_WARNING, 0,
442 "invalid metric '%s' for tunnel to %s in %s",
443 w, inet_fmt(rmt_addr, s1), configfilename);
444 break;
445 }
446 v->uv_metric = n;
447 }
448 else if (EQUAL(w, "threshold")) {
449 if(EQUAL((w = next_word(&s)), "")) {
450 log(LOG_WARNING, 0,
451 "missing threshold for tunnel to %s in %s",
452 inet_fmt(rmt_addr, s1), configfilename);
453 w = "garbage";
454 break;
455 }
456 if(sscanf(w, "%u%c", &n, &c) != 1 ||
457 n < 1 || n > 255 ) {
458 log(LOG_WARNING, 0,
459 "invalid threshold '%s' for tunnel to %s in %s",
460 w, inet_fmt(rmt_addr, s1), configfilename);
461 break;
462 }
463 v->uv_threshold = n;
464 }
465 else if (EQUAL(w, "srcrt") || EQUAL(w, "sourceroute")) {
466 v->uv_flags |= VIFF_SRCRT;
467 }
468 else break;
469 }
470 if (!EQUAL(w, "")) continue;
471
472 log(LOG_INFO, 0,
473 "installing %stunnel from %s to %s as vif #%u",
474 v->uv_flags & VIFF_SRCRT? "srcrt " : "",
475 inet_fmt(lcl_addr, s1), inet_fmt(rmt_addr, s2), numvifs);
476
477 ++numvifs;
478
479 if (!(ffr.ifr_flags & IFF_UP)) {
480 v->uv_flags |= VIFF_DOWN;
481 vifs_down = TRUE;
482 }
483 }
484
485 else {
486 log(LOG_WARNING, 0,
487 "unknown command '%s' in %s", w, configfilename);
488 }
489 }
490
491 close(f);
492 }
493
494
495 /*
496 * Return a pointer to the next "word" in the string to which '*s' points,
497 * lower-cased and null terminated, and advance '*s' to point beyond the word.
498 * Words are separated by blanks and/or tabs, and the input string is
499 * considered to terminate at a newline, '#' (comment), or null character.
500 * If no words remain, a pointer to a null string ("") is returned.
501 * Warning: This function clobbers the input string.
502 */
503 static char *next_word(s)
504 char **s;
505 {
506 char *w;
507
508 w = *s;
509 while (*w == ' ' || *w == '\t')
510 ++w;
511
512 *s = w;
513 for(;;) {
514 switch (**s) {
515
516 case ' ' :
517 case '\t' : **s = '\0';
518 ++*s;
519 return (w);
520
521 case '\n' :
522 case '#' : **s = '\0';
523 return (w);
524
525 case '\0' : return (w);
526
527 default : if (isascii(**s) && isupper(**s))
528 **s = tolower(**s);
529 ++*s;
530 }
531 }
532 }
533