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