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