cfparse.y revision 1.4 1 %{
2 /* $NetBSD: cfparse.y,v 1.4 1995/12/10 10:06:57 mycroft Exp $ */
3
4 /*
5 * Configuration file parser for mrouted.
6 *
7 * Written by Bill Fenner, NRL, 1994
8 */
9 #include <stdio.h>
10 #ifdef __STDC__
11 #include <stdarg.h>
12 #else
13 #include <string.h>
14 #include <varargs.h>
15 #endif
16 #include "defs.h"
17 #include <netdb.h>
18
19 /*
20 * Local function declarations
21 */
22 static void fatal __P((char *fmt, ...));
23 static void warn __P((char *fmt, ...));
24 static void yyerror __P((char *s));
25 static char * next_word __P((void));
26 static int yylex __P((void));
27 static u_int32_t valid_if __P((char *s));
28 static struct ifreq * ifconfaddr __P((struct ifconf *ifcp, u_int32_t a));
29 int yyparse __P((void));
30
31 static FILE *f;
32
33 extern int udp_socket;
34 char *configfilename = _PATH_MROUTED_CONF;
35
36 extern int cache_lifetime;
37 extern int max_prune_lifetime;
38
39 static int lineno;
40 static struct ifreq ifbuf[32];
41 static struct ifconf ifc;
42
43 static struct uvif *v;
44
45 static int order;
46
47 struct addrmask {
48 u_int32_t addr;
49 int mask;
50 };
51
52 struct boundnam {
53 char *name;
54 struct addrmask bound;
55 };
56
57 #define MAXBOUNDS 20
58
59 struct boundnam boundlist[MAXBOUNDS]; /* Max. of 20 named boundaries */
60 int numbounds = 0; /* Number of named boundaries */
61
62 %}
63
64 %union
65 {
66 int num;
67 char *ptr;
68 struct addrmask addrmask;
69 u_int32_t addr;
70 };
71
72 %token CACHE_LIFETIME PRUNING
73 %token PHYINT TUNNEL NAME
74 %token DISABLE IGMPV1 SRCRT
75 %token METRIC THRESHOLD RATE_LIMIT BOUNDARY NETMASK ALTNET
76 %token SYSNAM SYSCONTACT SYSVERSION SYSLOCATION
77 %token <num> BOOLEAN
78 %token <num> NUMBER
79 %token <ptr> STRING
80 %token <addrmask> ADDRMASK
81 %token <addr> ADDR
82
83 %type <addr> interface addrname
84 %type <addrmask> bound boundary addrmask
85
86 %start conf
87
88 %%
89
90 conf : stmts
91 ;
92
93 stmts : /* Empty */
94 | stmts stmt
95 ;
96
97 stmt : error
98 | PHYINT interface {
99
100 vifi_t vifi;
101
102 if (order)
103 fatal("phyints must appear before tunnels");
104
105 for (vifi = 0, v = uvifs;
106 vifi < numvifs;
107 ++vifi, ++v)
108 if (!(v->uv_flags & VIFF_TUNNEL) &&
109 $2 == v->uv_lcl_addr)
110 break;
111
112 if (vifi == numvifs)
113 fatal("%s is not a configured interface",
114 inet_fmt($2,s1));
115
116 }
117 ifmods
118 | TUNNEL interface addrname {
119
120 struct ifreq *ifr;
121 struct ifreq ffr;
122 vifi_t vifi;
123
124 order++;
125
126 ifr = ifconfaddr(&ifc, $2);
127 if (ifr == 0)
128 fatal("Tunnel local address %s is not mine",
129 inet_fmt($2, s1));
130
131 strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ);
132 if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr)<0)
133 fatal("ioctl SIOCGIFFLAGS on %s",ffr.ifr_name);
134 if (ffr.ifr_flags & IFF_LOOPBACK)
135 fatal("Tunnel local address %s is a loopback interface",
136 inet_fmt($2, s1));
137
138 if (ifconfaddr(&ifc, $3) != 0)
139 fatal("Tunnel remote address %s is one of mine",
140 inet_fmt($3, s1));
141
142 for (vifi = 0, v = uvifs;
143 vifi < numvifs;
144 ++vifi, ++v)
145 if (v->uv_flags & VIFF_TUNNEL) {
146 if ($3 == v->uv_rmt_addr)
147 fatal("Duplicate tunnel to %s",
148 inet_fmt($3, s1));
149 } else if (!(v->uv_flags & VIFF_DISABLED)) {
150 if (($3 & v->uv_subnetmask) == v->uv_subnet)
151 fatal("Unnecessary tunnel to %s",
152 inet_fmt($3,s1));
153 }
154
155 if (numvifs == MAXVIFS)
156 fatal("too many vifs");
157
158 v = &uvifs[numvifs];
159 v->uv_flags = VIFF_TUNNEL;
160 v->uv_metric = DEFAULT_METRIC;
161 v->uv_rate_limit= DEFAULT_TUN_RATE_LIMIT;
162 v->uv_threshold = DEFAULT_THRESHOLD;
163 v->uv_lcl_addr = $2;
164 v->uv_rmt_addr = $3;
165 v->uv_subnet = 0;
166 v->uv_subnetmask= 0;
167 v->uv_subnetbcast= 0;
168 strncpy(v->uv_name, ffr.ifr_name, IFNAMSIZ);
169 v->uv_groups = NULL;
170 v->uv_neighbors = NULL;
171 v->uv_acl = NULL;
172 v->uv_addrs = NULL;
173
174 if (!(ffr.ifr_flags & IFF_UP)) {
175 v->uv_flags |= VIFF_DOWN;
176 vifs_down = TRUE;
177 }
178 }
179 tunnelmods
180 {
181 log(LOG_INFO, 0,
182 "installing tunnel from %s to %s as vif #%u - rate=%d",
183 inet_fmt($2, s1), inet_fmt($3, s2),
184 numvifs, v->uv_rate_limit);
185
186 ++numvifs;
187 }
188 | PRUNING BOOLEAN { pruning = $2; }
189 | CACHE_LIFETIME NUMBER { cache_lifetime = $2;
190 max_prune_lifetime = cache_lifetime * 2;
191 }
192 | NAME STRING boundary { if (numbounds >= MAXBOUNDS) {
193 fatal("Too many named boundaries (max %d)", MAXBOUNDS);
194 }
195
196 boundlist[numbounds].name = malloc(strlen($2) + 1);
197 strcpy(boundlist[numbounds].name, $2);
198 boundlist[numbounds++].bound = $3;
199 }
200 | SYSNAM STRING {
201 #ifdef SNMP
202 set_sysName($2);
203 #endif /* SNMP */
204 }
205 | SYSCONTACT STRING {
206 #ifdef SNMP
207 set_sysContact($2);
208 #endif /* SNMP */
209 }
210 | SYSVERSION STRING {
211 #ifdef SNMP
212 set_sysVersion($2);
213 #endif /* SNMP */
214 }
215 | SYSLOCATION STRING {
216 #ifdef SNMP
217 set_sysLocation($2);
218 #endif /* SNMP */
219 }
220 ;
221
222 tunnelmods : /* empty */
223 | tunnelmods tunnelmod
224 ;
225
226 tunnelmod : mod
227 | SRCRT { fatal("Source-route tunnels not supported"); }
228 ;
229
230 ifmods : /* empty */
231 | ifmods ifmod
232 ;
233
234 ifmod : mod
235 | DISABLE { v->uv_flags |= VIFF_DISABLED; }
236 | IGMPV1 { v->uv_flags |= VIFF_IGMPV1; }
237 | NETMASK addrname {
238 u_int32_t subnet, mask;
239
240 mask = $2;
241 subnet = v->uv_lcl_addr & mask;
242 if (!inet_valid_subnet(subnet, mask))
243 fatal("Invalid netmask");
244 v->uv_subnet = subnet;
245 v->uv_subnetmask = mask;
246 v->uv_subnetbcast = subnet | ~mask;
247 }
248 | NETMASK {
249
250 warn("Expected address after netmask keyword, ignored");
251
252 }
253 | ALTNET addrmask {
254
255 struct phaddr *ph;
256
257 ph = (struct phaddr *)malloc(sizeof(struct phaddr));
258 if (ph == NULL)
259 fatal("out of memory");
260 if ($2.mask) {
261 VAL_TO_MASK(ph->pa_subnetmask, $2.mask);
262 } else
263 ph->pa_subnetmask = v->uv_subnetmask;
264 ph->pa_subnet = $2.addr & ph->pa_subnetmask;
265 ph->pa_subnetbcast = ph->pa_subnet | ~ph->pa_subnetmask;
266 if ($2.addr & ~ph->pa_subnetmask)
267 warn("Extra subnet %s/%d has host bits set",
268 inet_fmt($2.addr,s1), $2.mask);
269 ph->pa_next = v->uv_addrs;
270 v->uv_addrs = ph;
271
272 }
273 | ALTNET {
274
275 warn("Expected address after altnet keyword, ignored");
276
277 }
278 ;
279
280 mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
281 fatal("Invalid threshold %d",$2);
282 v->uv_threshold = $2;
283 }
284 | THRESHOLD {
285
286 warn("Expected number after threshold keyword, ignored");
287
288 }
289 | METRIC NUMBER { if ($2 < 1 || $2 > UNREACHABLE)
290 fatal("Invalid metric %d",$2);
291 v->uv_metric = $2;
292 }
293 | METRIC {
294
295 warn("Expected number after metric keyword, ignored");
296
297 }
298 | RATE_LIMIT NUMBER { if ($2 > MAX_RATE_LIMIT)
299 fatal("Invalid rate_limit %d",$2);
300 v->uv_rate_limit = $2;
301 }
302 | RATE_LIMIT {
303
304 warn("Expected number after rate_limit keyword, ignored");
305
306 }
307 | BOUNDARY bound {
308
309 struct vif_acl *v_acl;
310
311 v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
312 if (v_acl == NULL)
313 fatal("out of memory");
314 VAL_TO_MASK(v_acl->acl_mask, $2.mask);
315 v_acl->acl_addr = $2.addr & v_acl->acl_mask;
316 if ($2.addr & ~v_acl->acl_mask)
317 warn("Boundary spec %s/%d has host bits set",
318 inet_fmt($2.addr,s1),$2.mask);
319 v_acl->acl_next = v->uv_acl;
320 v->uv_acl = v_acl;
321
322 }
323 | BOUNDARY {
324
325 warn("Expected boundary spec after boundary keyword, ignored");
326
327 }
328 ;
329
330 interface : ADDR { $$ = $1; }
331 | STRING {
332 $$ = valid_if($1);
333 if ($$ == 0)
334 fatal("Invalid interface name %s",$1);
335 }
336 ;
337
338 addrname : ADDR { $$ = $1; }
339 | STRING { struct hostent *hp;
340
341 if ((hp = gethostbyname($1)) == NULL)
342 fatal("No such host %s", $1);
343
344 if (hp->h_addr_list[1])
345 fatal("Hostname %s does not %s",
346 $1, "map to a unique address");
347
348 bcopy(hp->h_addr_list[0], &$$,
349 hp->h_length);
350 }
351
352 bound : boundary { $$ = $1; }
353 | STRING { int i;
354
355 for (i=0; i < numbounds; i++) {
356 if (!strcmp(boundlist[i].name, $1)) {
357 $$ = boundlist[i].bound;
358 break;
359 }
360 }
361 if (i == numbounds) {
362 fatal("Invalid boundary name %s",$1);
363 }
364 }
365 ;
366
367 boundary : ADDRMASK {
368
369 if ((ntohl($1.addr) & 0xff000000) != 0xef000000) {
370 fatal("Boundaries must be 239.x.x.x, not %s/%d",
371 inet_fmt($1.addr, s1), $1.mask);
372 }
373 $$ = $1;
374
375 }
376 ;
377
378 addrmask : ADDRMASK { $$ = $1; }
379 | ADDR { $$.addr = $1; $$.mask = 0; }
380 ;
381 %%
382 #ifdef __STDC__
383 static void
384 fatal(char *fmt, ...)
385 {
386 va_list ap;
387 char buf[200];
388
389 va_start(ap, fmt);
390 #else
391 /*VARARGS1*/
392 static void
393 fatal(fmt, va_alist)
394 char *fmt;
395 va_dcl
396 {
397 va_list ap;
398 char buf[200];
399
400 va_start(ap);
401 #endif
402 vsprintf(buf, fmt, ap);
403 va_end(ap);
404
405 log(LOG_ERR,0,"%s: %s near line %d", configfilename, buf, lineno);
406 }
407
408 #ifdef __STDC__
409 static void
410 warn(char *fmt, ...)
411 {
412 va_list ap;
413 char buf[200];
414
415 va_start(ap, fmt);
416 #else
417 /*VARARGS1*/
418 static void
419 warn(fmt, va_alist)
420 char *fmt;
421 va_dcl
422 {
423 va_list ap;
424 char buf[200];
425
426 va_start(ap);
427 #endif
428 vsprintf(buf, fmt, ap);
429 va_end(ap);
430
431 log(LOG_WARNING,0,"%s: %s near line %d", configfilename, buf, lineno);
432 }
433
434 static void
435 yyerror(s)
436 char *s;
437 {
438 log(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno);
439 }
440
441 static char *
442 next_word()
443 {
444 static char buf[1024];
445 static char *p=NULL;
446 extern FILE *f;
447 char *q;
448
449 while (1) {
450 if (!p || !*p) {
451 lineno++;
452 if (fgets(buf, sizeof(buf), f) == NULL)
453 return NULL;
454 p = buf;
455 }
456 while (*p && (*p == ' ' || *p == '\t')) /* skip whitespace */
457 p++;
458 if (*p == '#') {
459 p = NULL; /* skip comments */
460 continue;
461 }
462 q = p;
463 #ifdef SNMP
464 if (*p == '"') {
465 p++;
466 while (*p && *p != '"' && *p != '\n')
467 p++; /* find next whitespace */
468 if (*p == '"')
469 p++;
470 } else
471 #endif
472 while (*p && *p != ' ' && *p != '\t' && *p != '\n')
473 p++; /* find next whitespace */
474 *p++ = '\0'; /* null-terminate string */
475
476 if (!*q) {
477 p = NULL;
478 continue; /* if 0-length string, read another line */
479 }
480
481 return q;
482 }
483 }
484
485 static int
486 yylex()
487 {
488 int n;
489 u_int32_t addr;
490 char *q;
491
492 if ((q = next_word()) == NULL) {
493 return 0;
494 }
495
496 if (!strcmp(q,"cache_lifetime"))
497 return CACHE_LIFETIME;
498 if (!strcmp(q,"pruning"))
499 return PRUNING;
500 if (!strcmp(q,"phyint"))
501 return PHYINT;
502 if (!strcmp(q,"tunnel"))
503 return TUNNEL;
504 if (!strcmp(q,"disable"))
505 return DISABLE;
506 if (!strcmp(q,"metric"))
507 return METRIC;
508 if (!strcmp(q,"threshold"))
509 return THRESHOLD;
510 if (!strcmp(q,"rate_limit"))
511 return RATE_LIMIT;
512 if (!strcmp(q,"srcrt") || !strcmp(q,"sourceroute"))
513 return SRCRT;
514 if (!strcmp(q,"boundary"))
515 return BOUNDARY;
516 if (!strcmp(q,"netmask"))
517 return NETMASK;
518 if (!strcmp(q,"igmpv1"))
519 return IGMPV1;
520 if (!strcmp(q,"altnet"))
521 return ALTNET;
522 if (!strcmp(q,"name"))
523 return NAME;
524 if (!strcmp(q,"on") || !strcmp(q,"yes")) {
525 yylval.num = 1;
526 return BOOLEAN;
527 }
528 if (!strcmp(q,"off") || !strcmp(q,"no")) {
529 yylval.num = 0;
530 return BOOLEAN;
531 }
532 if (sscanf(q,"%[.0-9]/%d%c",s1,&n,s2) == 2) {
533 if ((addr = inet_parse(s1)) != 0xffffffff) {
534 yylval.addrmask.mask = n;
535 yylval.addrmask.addr = addr;
536 return ADDRMASK;
537 }
538 /* fall through to returning STRING */
539 }
540 if (sscanf(q,"%[.0-9]%c",s1,s2) == 1) {
541 if ((addr = inet_parse(s1)) != 0xffffffff &&
542 inet_valid_host(addr)) {
543 yylval.addr = addr;
544 return ADDR;
545 }
546 }
547 if (sscanf(q,"0x%8x%c",&n,s1) == 1) {
548 yylval.addr = n;
549 return ADDR;
550 }
551 if (sscanf(q,"%d%c",&n,s1) == 1) {
552 yylval.num = n;
553 return NUMBER;
554 }
555 #ifdef SNMP
556 if (!strcmp(q,"sysName"))
557 return SYSNAM;
558 if (!strcmp(q,"sysContact"))
559 return SYSCONTACT;
560 if (!strcmp(q,"sysVersion"))
561 return SYSVERSION;
562 if (!strcmp(q,"sysLocation"))
563 return SYSLOCATION;
564 if (*q=='"') {
565 if (q[ strlen(q)-1 ]=='"')
566 q[ strlen(q)-1 ]='\0'; /* trash trailing quote */
567 yylval.ptr = q+1;
568 return STRING;
569 }
570 #endif
571 yylval.ptr = q;
572 return STRING;
573 }
574
575 void
576 config_vifs_from_file()
577 {
578 extern FILE *f;
579
580 order = 0;
581 numbounds = 0;
582 lineno = 0;
583
584 if ((f = fopen(configfilename, "r")) == NULL) {
585 if (errno != ENOENT)
586 log(LOG_ERR, errno, "can't open %s", configfilename);
587 return;
588 }
589
590 ifc.ifc_buf = (char *)ifbuf;
591 ifc.ifc_len = sizeof(ifbuf);
592 if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
593 log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
594
595 yyparse();
596
597 fclose(f);
598 }
599
600 static u_int32_t
601 valid_if(s)
602 char *s;
603 {
604 register vifi_t vifi;
605 register struct uvif *v;
606
607 for (vifi=0, v=uvifs; vifi<numvifs; vifi++, v++)
608 if (!strcmp(v->uv_name, s))
609 return v->uv_lcl_addr;
610
611 return 0;
612 }
613
614 static struct ifreq *
615 ifconfaddr(ifcp, a)
616 struct ifconf *ifcp;
617 u_int32_t a;
618 {
619 int n;
620 struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf;
621 struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len);
622
623 while (ifrp < ifend) {
624 if (ifrp->ifr_addr.sa_family == AF_INET &&
625 ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == a)
626 return (ifrp);
627 #if (defined(BSD) && (BSD >= 199006))
628 n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
629 if (n < sizeof(*ifrp))
630 ++ifrp;
631 else
632 ifrp = (struct ifreq *)((char *)ifrp + n);
633 #else
634 ++ifrp;
635 #endif
636 }
637 return (0);
638 }
639