"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Bison source code syntax highlighting (style:
standard) with prefixed line numbers.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /* $OpenBSD: parse.y,v 1.67 2009/06/05 04:12:52 claudio Exp $ */
2
3 /*
4 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
5 * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
6 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
7 * Copyright (c) 2001 Markus Friedl. All rights reserved.
8 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
9 * Copyright (c) 2001 Theo de Raadt. All rights reserved.
10 *
11 * Permission to use, copy, modify, and distribute this software for any
12 * purpose with or without fee is hereby granted, provided that the above
13 * copyright notice and this permission notice appear in all copies.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 */
23
24 %{
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/stat.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #include <ctype.h>
31 #include <err.h>
32 #include <errno.h>
33 #include <unistd.h>
34 #include <ifaddrs.h>
35 #include <limits.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <string.h>
39
40 #include "ospf.h"
41 #include "ospfd.h"
42 #include "ospfe.h"
43 #include "log.h"
44
45 TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
46 static struct file {
47 TAILQ_ENTRY(file) entry;
48 FILE *stream;
49 char *name;
50 int lineno;
51 int errors;
52 } *file, *topfile;
53 struct file *pushfile(const char *, int);
54 int popfile(void);
55 int check_file_secrecy(int, const char *);
56 int yyparse(void);
57 int yylex(void);
58 int yyerror(const char *, ...);
59 int kw_cmp(const void *, const void *);
60 int lookup(char *);
61 int lgetc(int);
62 int lungetc(int);
63 int findeol(void);
64
65 TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
66 struct sym {
67 TAILQ_ENTRY(sym) entry;
68 int used;
69 int persist;
70 char *nam;
71 char *val;
72 };
73 int symset(const char *, const char *, int);
74 char *symget(const char *);
75
76 void clear_config(struct ospfd_conf *xconf);
77 u_int32_t get_rtr_id(void);
78 int host(const char *, struct in_addr *, struct in_addr *);
79
80 static struct ospfd_conf *conf;
81 static int errors = 0;
82
83 struct area *area = NULL;
84 struct iface *iface = NULL;
85
86 struct config_defaults {
87 char auth_key[MAX_SIMPLE_AUTH_LEN];
88 struct auth_md_head md_list;
89 u_int32_t dead_interval;
90 u_int16_t transmit_delay;
91 u_int16_t hello_interval;
92 u_int16_t rxmt_interval;
93 u_int16_t metric;
94 enum auth_type auth_type;
95 u_int8_t auth_keyid;
96 u_int8_t priority;
97 };
98
99 struct config_defaults globaldefs;
100 struct config_defaults areadefs;
101 struct config_defaults ifacedefs;
102 struct config_defaults *defs;
103
104 struct area *conf_get_area(struct in_addr);
105 struct iface *conf_get_if(struct kif *, struct kif_addr *);
106
107 typedef struct {
108 union {
109 int64_t number;
110 char *string;
111 struct redistribute *redist;
112 } v;
113 int lineno;
114 } YYSTYPE;
115
116 %}
117
118 %token AREA INTERFACE ROUTERID FIBUPDATE REDISTRIBUTE RTLABEL RDOMAIN
119 %token RFC1583COMPAT STUB ROUTER SPFDELAY SPFHOLDTIME EXTTAG
120 %token AUTHKEY AUTHTYPE AUTHMD AUTHMDKEYID
121 %token METRIC PASSIVE
122 %token HELLOINTERVAL TRANSMITDELAY
123 %token RETRANSMITINTERVAL ROUTERDEADTIME ROUTERPRIORITY
124 %token SET TYPE
125 %token YES NO
126 %token DEMOTE
127 %token ERROR
128 %token <v.string> STRING
129 %token <v.number> NUMBER
130 %type <v.number> yesno no optlist optlist_l option demotecount
131 %type <v.string> string
132 %type <v.redist> redistribute
133
134 %%
135
136 grammar : /* empty */
137 | grammar '\n'
138 | grammar conf_main '\n'
139 | grammar varset '\n'
140 | grammar area '\n'
141 | grammar error '\n' { file->errors++; }
142 ;
143
144 string : string STRING {
145 if (asprintf(&$$, "%s %s", $1, $2) == -1) {
146 free($1);
147 free($2);
148 yyerror("string: asprintf");
149 YYERROR;
150 }
151 free($1);
152 free($2);
153 }
154 | STRING
155 ;
156
157 yesno : YES { $$ = 1; }
158 | NO { $$ = 0; }
159 ;
160
161 no : /* empty */ { $$ = 0; }
162 | NO { $$ = 1; }
163 ;
164
165 varset : STRING '=' string {
166 if (conf->opts & OSPFD_OPT_VERBOSE)
167 printf("%s = \"%s\"\n", $1, $3);
168 if (symset($1, $3, 0) == -1)
169 fatal("cannot store variable");
170 free($1);
171 free($3);
172 }
173 ;
174
175 conf_main : ROUTERID STRING {
176 if (!inet_aton($2, &conf->rtr_id)) {
177 yyerror("error parsing router-id");
178 free($2);
179 YYERROR;
180 }
181 free($2);
182 }
183 | FIBUPDATE yesno {
184 if ($2 == 0)
185 conf->flags |= OSPFD_FLAG_NO_FIB_UPDATE;
186 else
187 conf->flags &= ~OSPFD_FLAG_NO_FIB_UPDATE;
188 }
189 | redistribute {
190 SIMPLEQ_INSERT_TAIL(&conf->redist_list, $1, entry);
191 conf->redistribute = 1;
192 }
193 | RTLABEL STRING EXTTAG NUMBER {
194 if ($4 < 0 || $4 > UINT_MAX) {
195 yyerror("invalid external route tag");
196 free($2);
197 YYERROR;
198 }
199 rtlabel_tag(rtlabel_name2id($2), $4);
200 free($2);
201 }
202 | RDOMAIN NUMBER {
203 if ($2 < 0 || $2 > RT_TABLEID_MAX) {
204 yyerror("invalid rdomain");
205 YYERROR;
206 }
207 conf->rdomain = $2;
208 }
209 | RFC1583COMPAT yesno {
210 conf->rfc1583compat = $2;
211 }
212 | SPFDELAY NUMBER {
213 if ($2 < MIN_SPF_DELAY || $2 > MAX_SPF_DELAY) {
214 yyerror("spf-delay out of range "
215 "(%d-%d)", MIN_SPF_DELAY,
216 MAX_SPF_DELAY);
217 YYERROR;
218 }
219 conf->spf_delay = $2;
220 }
221 | SPFHOLDTIME NUMBER {
222 if ($2 < MIN_SPF_HOLDTIME || $2 > MAX_SPF_HOLDTIME) {
223 yyerror("spf-holdtime out of range "
224 "(%d-%d)", MIN_SPF_HOLDTIME,
225 MAX_SPF_HOLDTIME);
226 YYERROR;
227 }
228 conf->spf_hold_time = $2;
229 }
230 | STUB ROUTER yesno {
231 if ($3)
232 conf->flags |= OSPFD_FLAG_STUB_ROUTER;
233 else
234 /* allow to force non stub mode */
235 conf->flags &= ~OSPFD_FLAG_STUB_ROUTER;
236 }
237 | defaults
238 ;
239
240
241 redistribute : no REDISTRIBUTE NUMBER '/' NUMBER optlist {
242 struct redistribute *r;
243
244 if ((r = calloc(1, sizeof(*r))) == NULL)
245 fatal(NULL);
246 r->type = REDIST_ADDR;
247 if ($3 < 0 || $3 > 255 || $5 < 1 || $5 > 32) {
248 yyerror("bad network: %llu/%llu", $3, $5);
249 free(r);
250 YYERROR;
251 }
252 r->addr.s_addr = htonl($3 << IN_CLASSA_NSHIFT);
253 r->mask.s_addr = prefixlen2mask($5);
254
255 if ($1)
256 r->type |= REDIST_NO;
257 r->metric = $6;
258 $$ = r;
259 }
260 | no REDISTRIBUTE STRING optlist {
261 struct redistribute *r;
262
263 if ((r = calloc(1, sizeof(*r))) == NULL)
264 fatal(NULL);
265 if (!strcmp($3, "default"))
266 r->type = REDIST_DEFAULT;
267 else if (!strcmp($3, "static"))
268 r->type = REDIST_STATIC;
269 else if (!strcmp($3, "connected"))
270 r->type = REDIST_CONNECTED;
271 else if (host($3, &r->addr, &r->mask))
272 r->type = REDIST_ADDR;
273 else {
274 yyerror("unknown redistribute type");
275 free($3);
276 free(r);
277 YYERROR;
278 }
279
280 if ($1)
281 r->type |= REDIST_NO;
282 r->metric = $4;
283 free($3);
284 $$ = r;
285 }
286 | no REDISTRIBUTE RTLABEL STRING optlist {
287 struct redistribute *r;
288
289 if ((r = calloc(1, sizeof(*r))) == NULL)
290 fatal(NULL);
291 r->type = REDIST_LABEL;
292 r->label = rtlabel_name2id($4);
293 if ($1)
294 r->type |= REDIST_NO;
295 r->metric = $5;
296 free($4);
297
298 $$ = r;
299 }
300 ;
301
302 optlist : /* empty */ { $$ = DEFAULT_REDIST_METRIC; }
303 | SET option {
304 $$ = $2;
305 if (($$ & LSA_METRIC_MASK) == 0)
306 $$ |= DEFAULT_REDIST_METRIC;
307 }
308 | SET optnl '{' optnl optlist_l optnl '}' {
309 $$ = $5;
310 if (($$ & LSA_METRIC_MASK) == 0)
311 $$ |= DEFAULT_REDIST_METRIC;
312 }
313 ;
314
315 optlist_l : optlist_l comma option {
316 if ($1 & LSA_ASEXT_E_FLAG && $3 & LSA_ASEXT_E_FLAG) {
317 yyerror("redistribute type already defined");
318 YYERROR;
319 }
320 if ($1 & LSA_METRIC_MASK && $3 & LSA_METRIC_MASK) {
321 yyerror("redistribute metric already defined");
322 YYERROR;
323 }
324 $$ = $1 | $3;
325 }
326 | option { $$ = $1; }
327 ;
328
329 option : METRIC NUMBER {
330 if ($2 == 0 || $2 > MAX_METRIC) {
331 yyerror("invalid redistribute metric");
332 YYERROR;
333 }
334 $$ = $2;
335 }
336 | TYPE NUMBER {
337 switch ($2) {
338 case 1:
339 $$ = 0;
340 break;
341 case 2:
342 $$ = LSA_ASEXT_E_FLAG;
343 break;
344 default:
345 yyerror("only external type 1 and 2 allowed");
346 YYERROR;
347 }
348 }
349 ;
350
351 authmd : AUTHMD NUMBER STRING {
352 if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) {
353 yyerror("auth-md key-id out of range "
354 "(%d-%d)", MIN_MD_ID, MAX_MD_ID);
355 free($3);
356 YYERROR;
357 }
358 if (strlen($3) > MD5_DIGEST_LENGTH) {
359 yyerror("auth-md key length out of range "
360 "(max length %d)",
361 MD5_DIGEST_LENGTH);
362 free($3);
363 YYERROR;
364 }
365 md_list_add(&defs->md_list, $2, $3);
366 free($3);
367 }
368
369 authmdkeyid : AUTHMDKEYID NUMBER {
370 if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) {
371 yyerror("auth-md-keyid out of range "
372 "(%d-%d)", MIN_MD_ID, MAX_MD_ID);
373 YYERROR;
374 }
375 defs->auth_keyid = $2;
376 }
377
378 authtype : AUTHTYPE STRING {
379 enum auth_type type;
380
381 if (!strcmp($2, "none"))
382 type = AUTH_NONE;
383 else if (!strcmp($2, "simple"))
384 type = AUTH_SIMPLE;
385 else if (!strcmp($2, "crypt"))
386 type = AUTH_CRYPT;
387 else {
388 yyerror("unknown auth-type");
389 free($2);
390 YYERROR;
391 }
392 free($2);
393 defs->auth_type = type;
394 }
395 ;
396
397 authkey : AUTHKEY STRING {
398 if (strlen($2) > MAX_SIMPLE_AUTH_LEN) {
399 yyerror("auth-key too long (max length %d)",
400 MAX_SIMPLE_AUTH_LEN);
401 free($2);
402 YYERROR;
403 }
404 strncpy(defs->auth_key, $2,
405 sizeof(defs->auth_key));
406 free($2);
407 }
408 ;
409
410 defaults : METRIC NUMBER {
411 if ($2 < MIN_METRIC || $2 > MAX_METRIC) {
412 yyerror("metric out of range (%d-%d)",
413 MIN_METRIC, MAX_METRIC);
414 YYERROR;
415 }
416 defs->metric = $2;
417 }
418 | ROUTERPRIORITY NUMBER {
419 if ($2 < MIN_PRIORITY || $2 > MAX_PRIORITY) {
420 yyerror("router-priority out of range (%d-%d)",
421 MIN_PRIORITY, MAX_PRIORITY);
422 YYERROR;
423 }
424 defs->priority = $2;
425 }
426 | ROUTERDEADTIME NUMBER {
427 if ($2 < MIN_RTR_DEAD_TIME || $2 > MAX_RTR_DEAD_TIME) {
428 yyerror("router-dead-time out of range (%d-%d)",
429 MIN_RTR_DEAD_TIME, MAX_RTR_DEAD_TIME);
430 YYERROR;
431 }
432 defs->dead_interval = $2;
433 }
434 | TRANSMITDELAY NUMBER {
435 if ($2 < MIN_TRANSMIT_DELAY ||
436 $2 > MAX_TRANSMIT_DELAY) {
437 yyerror("transmit-delay out of range (%d-%d)",
438 MIN_TRANSMIT_DELAY, MAX_TRANSMIT_DELAY);
439 YYERROR;
440 }
441 defs->transmit_delay = $2;
442 }
443 | HELLOINTERVAL NUMBER {
444 if ($2 < MIN_HELLO_INTERVAL ||
445 $2 > MAX_HELLO_INTERVAL) {
446 yyerror("hello-interval out of range (%d-%d)",
447 MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL);
448 YYERROR;
449 }
450 defs->hello_interval = $2;
451 }
452 | RETRANSMITINTERVAL NUMBER {
453 if ($2 < MIN_RXMT_INTERVAL || $2 > MAX_RXMT_INTERVAL) {
454 yyerror("retransmit-interval out of range "
455 "(%d-%d)", MIN_RXMT_INTERVAL,
456 MAX_RXMT_INTERVAL);
457 YYERROR;
458 }
459 defs->rxmt_interval = $2;
460 }
461 | authtype
462 | authkey
463 | authmdkeyid
464 | authmd
465 ;
466
467 optnl : '\n' optnl
468 |
469 ;
470
471 nl : '\n' optnl /* one newline or more */
472 ;
473
474 comma : ','
475 | /*empty*/
476 ;
477
478 area : AREA STRING {
479 struct in_addr id;
480 if (inet_aton($2, &id) == 0) {
481 yyerror("error parsing area");
482 free($2);
483 YYERROR;
484 }
485 free($2);
486 area = conf_get_area(id);
487
488 memcpy(&areadefs, defs, sizeof(areadefs));
489 md_list_copy(&areadefs.md_list, &defs->md_list);
490 defs = &areadefs;
491 } '{' optnl areaopts_l '}' {
492 area = NULL;
493 md_list_clr(&defs->md_list);
494 defs = &globaldefs;
495 }
496 ;
497
498 demotecount : NUMBER { $$ = $1; }
499 | /*empty*/ { $$ = 1; }
500 ;
501
502 areaopts_l : areaopts_l areaoptsl nl
503 | areaoptsl optnl
504 ;
505
506 areaoptsl : interface
507 | DEMOTE STRING demotecount {
508 if ($3 < 1 || $3 > 255) {
509 yyerror("demote count out of range (1-255)");
510 free($2);
511 YYERROR;
512 }
513 area->demote_level = $3;
514 if (strlcpy(area->demote_group, $2,
515 sizeof(area->demote_group)) >=
516 sizeof(area->demote_group)) {
517 yyerror("demote group name \"%s\" too long");
518 free($2);
519 YYERROR;
520 }
521 free($2);
522 if (carp_demote_init(area->demote_group,
523 conf->opts & OSPFD_OPT_FORCE_DEMOTE) == -1) {
524 yyerror("error initializing group \"%s\"",
525 area->demote_group);
526 YYERROR;
527 }
528 }
529 | defaults
530 | STUB { area->stub = 1; }
531 | STUB redistribute {
532 area->stub = 1;
533 if ($2->type != REDIST_DEFAULT) {
534 yyerror("bad redistribute option");
535 YYERROR;
536 }
537 if (!SIMPLEQ_EMPTY(&area->redist_list)) {
538 yyerror("area redistribute option only "
539 "allowed once");
540 YYERROR;
541 }
542 SIMPLEQ_INSERT_TAIL(&area->redist_list, $2, entry);
543 }
544 ;
545
546 interface : INTERFACE STRING {
547 struct kif *kif;
548 struct kif_addr *ka = NULL;
549 char *s;
550 struct in_addr addr;
551
552 s = strchr($2, ':');
553 if (s) {
554 *s++ = '\0';
555 if (inet_aton(s, &addr) == 0) {
556 yyerror(
557 "error parsing interface address");
558 free($2);
559 YYERROR;
560 }
561 } else
562 addr.s_addr = 0;
563
564 if ((kif = kif_findname($2, addr, &ka)) == NULL) {
565 yyerror("unknown interface %s", $2);
566 free($2);
567 YYERROR;
568 }
569 if (ka == NULL) {
570 if (s)
571 yyerror("address %s not configured on "
572 "interface %s", s, $2);
573 else
574 yyerror("unnumbered interface %s", $2);
575 free($2);
576 YYERROR;
577 }
578 free($2);
579 iface = conf_get_if(kif, ka);
580 if (iface == NULL)
581 YYERROR;
582 iface->area = area;
583 LIST_INSERT_HEAD(&area->iface_list, iface, entry);
584
585 memcpy(&ifacedefs, defs, sizeof(ifacedefs));
586 md_list_copy(&ifacedefs.md_list, &defs->md_list);
587 defs = &ifacedefs;
588 } interface_block {
589 iface->dead_interval = defs->dead_interval;
590 iface->transmit_delay = defs->transmit_delay;
591 iface->hello_interval = defs->hello_interval;
592 iface->rxmt_interval = defs->rxmt_interval;
593 iface->metric = defs->metric;
594 iface->priority = defs->priority;
595 iface->auth_type = defs->auth_type;
596 iface->auth_keyid = defs->auth_keyid;
597 memcpy(iface->auth_key, defs->auth_key,
598 sizeof(iface->auth_key));
599 md_list_copy(&iface->auth_md_list, &defs->md_list);
600 md_list_clr(&defs->md_list);
601 iface = NULL;
602 /* interface is always part of an area */
603 defs = &areadefs;
604 }
605 ;
606
607 interface_block : '{' optnl interfaceopts_l '}'
608 | '{' optnl '}'
609 |
610 ;
611
612 interfaceopts_l : interfaceopts_l interfaceoptsl nl
613 | interfaceoptsl optnl
614 ;
615
616 interfaceoptsl : PASSIVE { iface->passive = 1; }
617 | DEMOTE STRING {
618 if (strlcpy(iface->demote_group, $2,
619 sizeof(iface->demote_group)) >=
620 sizeof(iface->demote_group)) {
621 yyerror("demote group name \"%s\" too long");
622 free($2);
623 YYERROR;
624 }
625 free($2);
626 if (carp_demote_init(iface->demote_group,
627 conf->opts & OSPFD_OPT_FORCE_DEMOTE) == -1) {
628 yyerror("error initializing group \"%s\"",
629 iface->demote_group);
630 YYERROR;
631 }
632 }
633 | defaults
634 ;
635
636 %%
637
638 struct keywords {
639 const char *k_name;
640 int k_val;
641 };
642
643 int
644 yyerror(const char *fmt, ...)
645 {
646 va_list ap;
647
648 file->errors++;
649 va_start(ap, fmt);
650 fprintf(stderr, "%s:%d: ", file->name, yylval.lineno);
651 vfprintf(stderr, fmt, ap);
652 fprintf(stderr, "\n");
653 va_end(ap);
654 return (0);
655 }
656
657 int
658 kw_cmp(const void *k, const void *e)
659 {
660 return (strcmp(k, ((const struct keywords *)e)->k_name));
661 }
662
663 int
664 lookup(char *s)
665 {
666 /* this has to be sorted always */
667 static const struct keywords keywords[] = {
668 {"area", AREA},
669 {"auth-key", AUTHKEY},
670 {"auth-md", AUTHMD},
671 {"auth-md-keyid", AUTHMDKEYID},
672 {"auth-type", AUTHTYPE},
673 {"demote", DEMOTE},
674 {"external-tag", EXTTAG},
675 {"fib-update", FIBUPDATE},
676 {"hello-interval", HELLOINTERVAL},
677 {"interface", INTERFACE},
678 {"metric", METRIC},
679 {"no", NO},
680 {"passive", PASSIVE},
681 {"rdomain", RDOMAIN},
682 {"redistribute", REDISTRIBUTE},
683 {"retransmit-interval", RETRANSMITINTERVAL},
684 {"rfc1583compat", RFC1583COMPAT},
685 {"router", ROUTER},
686 {"router-dead-time", ROUTERDEADTIME},
687 {"router-id", ROUTERID},
688 {"router-priority", ROUTERPRIORITY},
689 {"rtlabel", RTLABEL},
690 {"set", SET},
691 {"spf-delay", SPFDELAY},
692 {"spf-holdtime", SPFHOLDTIME},
693 {"stub", STUB},
694 {"transmit-delay", TRANSMITDELAY},
695 {"type", TYPE},
696 {"yes", YES}
697 };
698 const struct keywords *p;
699
700 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
701 sizeof(keywords[0]), kw_cmp);
702
703 if (p)
704 return (p->k_val);
705 else
706 return (STRING);
707 }
708
709 #define MAXPUSHBACK 128
710
711 char *parsebuf;
712 int parseindex;
713 char pushback_buffer[MAXPUSHBACK];
714 int pushback_index = 0;
715
716 int
717 lgetc(int quotec)
718 {
719 int c, next;
720
721 if (parsebuf) {
722 /* Read character from the parsebuffer instead of input. */
723 if (parseindex >= 0) {
724 c = parsebuf[parseindex++];
725 if (c != '\0')
726 return (c);
727 parsebuf = NULL;
728 } else
729 parseindex++;
730 }
731
732 if (pushback_index)
733 return (pushback_buffer[--pushback_index]);
734
735 if (quotec) {
736 if ((c = getc(file->stream)) == EOF) {
737 yyerror("reached end of file while parsing "
738 "quoted string");
739 if (file == topfile || popfile() == EOF)
740 return (EOF);
741 return (quotec);
742 }
743 return (c);
744 }
745
746 while ((c = getc(file->stream)) == '\\') {
747 next = getc(file->stream);
748 if (next != '\n') {
749 c = next;
750 break;
751 }
752 yylval.lineno = file->lineno;
753 file->lineno++;
754 }
755
756 while (c == EOF) {
757 if (file == topfile || popfile() == EOF)
758 return (EOF);
759 c = getc(file->stream);
760 }
761 return (c);
762 }
763
764 int
765 lungetc(int c)
766 {
767 if (c == EOF)
768 return (EOF);
769 if (parsebuf) {
770 parseindex--;
771 if (parseindex >= 0)
772 return (c);
773 }
774 if (pushback_index < MAXPUSHBACK-1)
775 return (pushback_buffer[pushback_index++] = c);
776 else
777 return (EOF);
778 }
779
780 int
781 findeol(void)
782 {
783 int c;
784
785 parsebuf = NULL;
786
787 /* skip to either EOF or the first real EOL */
788 while (1) {
789 if (pushback_index)
790 c = pushback_buffer[--pushback_index];
791 else
792 c = lgetc(0);
793 if (c == '\n') {
794 file->lineno++;
795 break;
796 }
797 if (c == EOF)
798 break;
799 }
800 return (ERROR);
801 }
802
803 int
804 yylex(void)
805 {
806 char buf[8096];
807 char *p, *val;
808 int quotec, next, c;
809 int token;
810
811 top:
812 p = buf;
813 while ((c = lgetc(0)) == ' ' || c == '\t')
814 ; /* nothing */
815
816 yylval.lineno = file->lineno;
817 if (c == '#')
818 while ((c = lgetc(0)) != '\n' && c != EOF)
819 ; /* nothing */
820 if (c == '$' && parsebuf == NULL) {
821 while (1) {
822 if ((c = lgetc(0)) == EOF)
823 return (0);
824
825 if (p + 1 >= buf + sizeof(buf) - 1) {
826 yyerror("string too long");
827 return (findeol());
828 }
829 if (isalnum(c) || c == '_') {
830 *p++ = (char)c;
831 continue;
832 }
833 *p = '\0';
834 lungetc(c);
835 break;
836 }
837 val = symget(buf);
838 if (val == NULL) {
839 yyerror("macro '%s' not defined", buf);
840 return (findeol());
841 }
842 parsebuf = val;
843 parseindex = 0;
844 goto top;
845 }
846
847 switch (c) {
848 case '\'':
849 case '"':
850 quotec = c;
851 while (1) {
852 if ((c = lgetc(quotec)) == EOF)
853 return (0);
854 if (c == '\n') {
855 file->lineno++;
856 continue;
857 } else if (c == '\\') {
858 if ((next = lgetc(quotec)) == EOF)
859 return (0);
860 if (next == quotec || c == ' ' || c == '\t')
861 c = next;
862 else if (next == '\n')
863 continue;
864 else
865 lungetc(next);
866 } else if (c == quotec) {
867 *p = '\0';
868 break;
869 }
870 if (p + 1 >= buf + sizeof(buf) - 1) {
871 yyerror("string too long");
872 return (findeol());
873 }
874 *p++ = (char)c;
875 }
876 yylval.v.string = strdup(buf);
877 if (yylval.v.string == NULL)
878 err(1, "yylex: strdup");
879 return (STRING);
880 }
881
882 #define allowed_to_end_number(x) \
883 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
884
885 if (c == '-' || isdigit(c)) {
886 do {
887 *p++ = c;
888 if ((unsigned)(p-buf) >= sizeof(buf)) {
889 yyerror("string too long");
890 return (findeol());
891 }
892 } while ((c = lgetc(0)) != EOF && isdigit(c));
893 lungetc(c);
894 if (p == buf + 1 && buf[0] == '-')
895 goto nodigits;
896 if (c == EOF || allowed_to_end_number(c)) {
897 const char *errstr = NULL;
898
899 *p = '\0';
900 yylval.v.number = strtonum(buf, LLONG_MIN,
901 LLONG_MAX, &errstr);
902 if (errstr) {
903 yyerror("\"%s\" invalid number: %s",
904 buf, errstr);
905 return (findeol());
906 }
907 return (NUMBER);
908 } else {
909 nodigits:
910 while (p > buf + 1)
911 lungetc(*--p);
912 c = *--p;
913 if (c == '-')
914 return (c);
915 }
916 }
917
918 #define allowed_in_string(x) \
919 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
920 x != '{' && x != '}' && \
921 x != '!' && x != '=' && x != '#' && \
922 x != ','))
923
924 if (isalnum(c) || c == ':' || c == '_') {
925 do {
926 *p++ = c;
927 if ((unsigned)(p-buf) >= sizeof(buf)) {
928 yyerror("string too long");
929 return (findeol());
930 }
931 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
932 lungetc(c);
933 *p = '\0';
934 if ((token = lookup(buf)) == STRING)
935 if ((yylval.v.string = strdup(buf)) == NULL)
936 err(1, "yylex: strdup");
937 return (token);
938 }
939 if (c == '\n') {
940 yylval.lineno = file->lineno;
941 file->lineno++;
942 }
943 if (c == EOF)
944 return (0);
945 return (c);
946 }
947
948 int
949 check_file_secrecy(int fd, const char *fname)
950 {
951 struct stat st;
952
953 if (fstat(fd, &st)) {
954 log_warn("cannot stat %s", fname);
955 return (-1);
956 }
957 if (st.st_uid != 0 && st.st_uid != getuid()) {
958 log_warnx("%s: owner not root or current user", fname);
959 return (-1);
960 }
961 if (st.st_mode & (S_IRWXG | S_IRWXO)) {
962 log_warnx("%s: group/world readable/writeable", fname);
963 return (-1);
964 }
965 return (0);
966 }
967
968 struct file *
969 pushfile(const char *name, int secret)
970 {
971 struct file *nfile;
972
973 if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
974 log_warn("malloc");
975 return (NULL);
976 }
977 if ((nfile->name = strdup(name)) == NULL) {
978 log_warn("malloc");
979 free(nfile);
980 return (NULL);
981 }
982 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
983 log_warn("%s", nfile->name);
984 free(nfile->name);
985 free(nfile);
986 return (NULL);
987 } else if (secret &&
988 check_file_secrecy(fileno(nfile->stream), nfile->name)) {
989 fclose(nfile->stream);
990 free(nfile->name);
991 free(nfile);
992 return (NULL);
993 }
994 nfile->lineno = 1;
995 TAILQ_INSERT_TAIL(&files, nfile, entry);
996 return (nfile);
997 }
998
999 int
1000 popfile(void)
1001 {
1002 struct file *prev;
1003
1004 if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
1005 prev->errors += file->errors;
1006
1007 TAILQ_REMOVE(&files, file, entry);
1008 fclose(file->stream);
1009 free(file->name);
1010 free(file);
1011 file = prev;
1012 return (file ? 0 : EOF);
1013 }
1014
1015 struct ospfd_conf *
1016 parse_config(char *filename, int opts)
1017 {
1018 struct sym *sym, *next;
1019
1020 if ((conf = calloc(1, sizeof(struct ospfd_conf))) == NULL)
1021 fatal("parse_config");
1022 conf->opts = opts;
1023 if (conf->opts & OSPFD_OPT_STUB_ROUTER)
1024 conf->flags |= OSPFD_FLAG_STUB_ROUTER;
1025
1026 bzero(&globaldefs, sizeof(globaldefs));
1027 defs = &globaldefs;
1028 TAILQ_INIT(&defs->md_list);
1029 defs->dead_interval = DEFAULT_RTR_DEAD_TIME;
1030 defs->transmit_delay = DEFAULT_TRANSMIT_DELAY;
1031 defs->hello_interval = DEFAULT_HELLO_INTERVAL;
1032 defs->rxmt_interval = DEFAULT_RXMT_INTERVAL;
1033 defs->metric = DEFAULT_METRIC;
1034 defs->priority = DEFAULT_PRIORITY;
1035
1036 conf->spf_delay = DEFAULT_SPF_DELAY;
1037 conf->spf_hold_time = DEFAULT_SPF_HOLDTIME;
1038 conf->spf_state = SPF_IDLE;
1039
1040 if ((file = pushfile(filename, !(conf->opts & OSPFD_OPT_NOACTION))) == NULL) {
1041 free(conf);
1042 return (NULL);
1043 }
1044 topfile = file;
1045
1046 LIST_INIT(&conf->area_list);
1047 LIST_INIT(&conf->cand_list);
1048 SIMPLEQ_INIT(&conf->redist_list);
1049
1050 yyparse();
1051 errors = file->errors;
1052 popfile();
1053
1054 /* Free macros and check which have not been used. */
1055 for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
1056 next = TAILQ_NEXT(sym, entry);
1057 if ((conf->opts & OSPFD_OPT_VERBOSE2) && !sym->used)
1058 fprintf(stderr, "warning: macro '%s' not "
1059 "used\n", sym->nam);
1060 if (!sym->persist) {
1061 free(sym->nam);
1062 free(sym->val);
1063 TAILQ_REMOVE(&symhead, sym, entry);
1064 free(sym);
1065 }
1066 }
1067
1068 /* free global config defaults */
1069 md_list_clr(&globaldefs.md_list);
1070
1071 if (errors) {
1072 clear_config(conf);
1073 return (NULL);
1074 }
1075
1076 if (conf->rtr_id.s_addr == 0)
1077 conf->rtr_id.s_addr = get_rtr_id();
1078
1079 return (conf);
1080 }
1081
1082 int
1083 symset(const char *nam, const char *val, int persist)
1084 {
1085 struct sym *sym;
1086
1087 for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
1088 sym = TAILQ_NEXT(sym, entry))
1089 ; /* nothing */
1090
1091 if (sym != NULL) {
1092 if (sym->persist == 1)
1093 return (0);
1094 else {
1095 free(sym->nam);
1096 free(sym->val);
1097 TAILQ_REMOVE(&symhead, sym, entry);
1098 free(sym);
1099 }
1100 }
1101 if ((sym = calloc(1, sizeof(*sym))) == NULL)
1102 return (-1);
1103
1104 sym->nam = strdup(nam);
1105 if (sym->nam == NULL) {
1106 free(sym);
1107 return (-1);
1108 }
1109 sym->val = strdup(val);
1110 if (sym->val == NULL) {
1111 free(sym->nam);
1112 free(sym);
1113 return (-1);
1114 }
1115 sym->used = 0;
1116 sym->persist = persist;
1117 TAILQ_INSERT_TAIL(&symhead, sym, entry);
1118 return (0);
1119 }
1120
1121 int
1122 cmdline_symset(char *s)
1123 {
1124 char *sym, *val;
1125 int ret;
1126 size_t len;
1127
1128 if ((val = strrchr(s, '=')) == NULL)
1129 return (-1);
1130
1131 len = strlen(s) - strlen(val) + 1;
1132 if ((sym = malloc(len)) == NULL)
1133 errx(1, "cmdline_symset: malloc");
1134
1135 strlcpy(sym, s, len);
1136
1137 ret = symset(sym, val + 1, 1);
1138 free(sym);
1139
1140 return (ret);
1141 }
1142
1143 char *
1144 symget(const char *nam)
1145 {
1146 struct sym *sym;
1147
1148 TAILQ_FOREACH(sym, &symhead, entry)
1149 if (strcmp(nam, sym->nam) == 0) {
1150 sym->used = 1;
1151 return (sym->val);
1152 }
1153 return (NULL);
1154 }
1155
1156 struct area *
1157 conf_get_area(struct in_addr id)
1158 {
1159 struct area *a;
1160
1161 a = area_find(conf, id);
1162 if (a)
1163 return (a);
1164 a = area_new();
1165 LIST_INSERT_HEAD(&conf->area_list, a, entry);
1166
1167 a->id.s_addr = id.s_addr;
1168
1169 return (a);
1170 }
1171
1172 struct iface *
1173 conf_get_if(struct kif *kif, struct kif_addr *ka)
1174 {
1175 struct area *a;
1176 struct iface *i;
1177
1178 LIST_FOREACH(a, &conf->area_list, entry)
1179 LIST_FOREACH(i, &a->iface_list, entry)
1180 if (i->ifindex == kif->ifindex &&
1181 i->addr.s_addr == ka->addr.s_addr) {
1182 yyerror("interface %s already configured",
1183 kif->ifname);
1184 return (NULL);
1185 }
1186
1187 i = if_new(kif, ka);
1188 i->auth_keyid = 1;
1189
1190 return (i);
1191 }
1192
1193 void
1194 clear_config(struct ospfd_conf *xconf)
1195 {
1196 struct area *a;
1197
1198 while ((a = LIST_FIRST(&xconf->area_list)) != NULL) {
1199 LIST_REMOVE(a, entry);
1200 area_del(a);
1201 }
1202
1203 free(xconf);
1204 }
1205
1206 u_int32_t
1207 get_rtr_id(void)
1208 {
1209 struct ifaddrs *ifap, *ifa;
1210 u_int32_t ip = 0, cur, localnet;
1211
1212 localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
1213
1214 if (getifaddrs(&ifap) == -1)
1215 fatal("getifaddrs");
1216
1217 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1218 if (ifa->ifa_addr->sa_family != AF_INET)
1219 continue;
1220 cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
1221 if ((cur & localnet) == localnet) /* skip 127/8 */
1222 continue;
1223 if (ntohl(cur) < ntohl(ip) || ip == 0)
1224 ip = cur;
1225 }
1226 freeifaddrs(ifap);
1227
1228 if (ip == 0)
1229 fatal("router-id is 0.0.0.0");
1230
1231 return (ip);
1232 }
1233
1234 int
1235 host(const char *s, struct in_addr *addr, struct in_addr *mask)
1236 {
1237 struct in_addr ina;
1238 int bits = 32;
1239
1240 bzero(&ina, sizeof(struct in_addr));
1241 if (strrchr(s, '/') != NULL) {
1242 if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
1243 return (0);
1244 } else {
1245 if (inet_pton(AF_INET, s, &ina) != 1)
1246 return (0);
1247 }
1248
1249 addr->s_addr = ina.s_addr;
1250 mask->s_addr = prefixlen2mask(bits);
1251
1252 return (1);
1253 }