xref: /openbsd/usr.sbin/ldpd/parse.y (revision 91f110e0)
1 /*	$OpenBSD: parse.y,v 1.20 2014/01/22 00:21:16 henning Exp $ */
2 
3 /*
4  * Copyright (c) 2004, 2005, 2008 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 <net/if_types.h>
36 #include <limits.h>
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <syslog.h>
41 
42 #include "ldp.h"
43 #include "ldpd.h"
44 #include "ldpe.h"
45 #include "log.h"
46 
47 TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
48 static struct file {
49 	TAILQ_ENTRY(file)	 entry;
50 	FILE			*stream;
51 	char			*name;
52 	int			 lineno;
53 	int			 errors;
54 } *file, *topfile;
55 struct file	*pushfile(const char *, int);
56 int		 popfile(void);
57 int		 check_file_secrecy(int, const char *);
58 int		 yyparse(void);
59 int		 yylex(void);
60 int		 yyerror(const char *, ...);
61 int		 kw_cmp(const void *, const void *);
62 int		 lookup(char *);
63 int		 lgetc(int);
64 int		 lungetc(int);
65 int		 findeol(void);
66 
67 TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
68 struct sym {
69 	TAILQ_ENTRY(sym)	 entry;
70 	int			 used;
71 	int			 persist;
72 	char			*nam;
73 	char			*val;
74 };
75 
76 int		 symset(const char *, const char *, int);
77 char		*symget(const char *);
78 
79 void		 clear_config(struct ldpd_conf *xconf);
80 u_int32_t	 get_rtr_id(void);
81 int		 host(const char *, struct in_addr *, struct in_addr *);
82 
83 static struct ldpd_conf	*conf;
84 static int			 errors = 0;
85 
86 struct iface	*iface = NULL;
87 struct tnbr	*tnbr = NULL;
88 
89 struct config_defaults {
90 	u_int16_t	lhello_holdtime;
91 	u_int16_t	lhello_interval;
92 	u_int16_t	thello_holdtime;
93 	u_int16_t	thello_interval;
94 };
95 
96 struct config_defaults	 globaldefs;
97 struct config_defaults	 ifacedefs;
98 struct config_defaults	 tnbrdefs;
99 struct config_defaults	*defs;
100 
101 struct iface	*conf_get_if(struct kif *);
102 struct tnbr	*conf_get_tnbr(struct in_addr);
103 
104 typedef struct {
105 	union {
106 		int64_t		 number;
107 		char		*string;
108 	} v;
109 	int lineno;
110 } YYSTYPE;
111 
112 %}
113 
114 %token	INTERFACE TNEIGHBOR ROUTERID FIBUPDATE
115 %token	LHELLOHOLDTIME LHELLOINTERVAL
116 %token	THELLOHOLDTIME THELLOINTERVAL
117 %token	THELLOACCEPT
118 %token	KEEPALIVE
119 %token	DISTRIBUTION RETENTION ADVERTISEMENT
120 %token	EXTTAG
121 %token	YES NO
122 %token	ERROR
123 %token	<v.string>	STRING
124 %token	<v.number>	NUMBER
125 %type	<v.number>	yesno
126 %type	<v.string>	string
127 
128 %%
129 
130 grammar		: /* empty */
131 		| grammar '\n'
132 		| grammar conf_main '\n'
133 		| grammar varset '\n'
134 		| grammar interface '\n'
135 		| grammar tneighbor '\n'
136 		| grammar error '\n'		{ file->errors++; }
137 		;
138 
139 string		: string STRING	{
140 			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
141 				free($1);
142 				free($2);
143 				yyerror("string: asprintf");
144 				YYERROR;
145 			}
146 			free($1);
147 			free($2);
148 		}
149 		| STRING
150 		;
151 
152 yesno		: YES	{ $$ = 1; }
153 		| NO	{ $$ = 0; }
154 		;
155 
156 varset		: STRING '=' string {
157 			if (conf->opts & LDPD_OPT_VERBOSE)
158 				printf("%s = \"%s\"\n", $1, $3);
159 			if (symset($1, $3, 0) == -1)
160 				fatal("cannot store variable");
161 			free($1);
162 			free($3);
163 		}
164 		;
165 
166 conf_main	: ROUTERID STRING {
167 			if (!inet_aton($2, &conf->rtr_id)) {
168 				yyerror("error parsing router-id");
169 				free($2);
170 				YYERROR;
171 			}
172 			free($2);
173 		}
174 		| FIBUPDATE yesno {
175 			if ($2 == 0)
176 				conf->flags |= LDPD_FLAG_NO_FIB_UPDATE;
177 			else
178 				conf->flags &= ~LDPD_FLAG_NO_FIB_UPDATE;
179 		}
180 		| DISTRIBUTION STRING {
181 			conf->mode &= ~(MODE_DIST_INDEPENDENT |
182 			    MODE_DIST_ORDERED);
183 
184 			if (!strcmp($2, "independent"))
185 				conf->mode |= MODE_DIST_INDEPENDENT;
186 			else if (!strcmp($2, "ordered"))
187 				conf->mode |= MODE_DIST_ORDERED;
188 			else {
189 				yyerror("unknown distribution type");
190 				free($2);
191 				YYERROR;
192 			}
193 		}
194 		| RETENTION STRING {
195 			conf->mode &= ~(MODE_RET_CONSERVATIVE |
196 			    MODE_RET_LIBERAL);
197 
198 			if (!strcmp($2, "conservative"))
199 				conf->mode |= MODE_RET_CONSERVATIVE;
200 			else if (!strcmp($2, "liberal"))
201 				conf->mode |= MODE_RET_LIBERAL;
202 			else {
203 				yyerror("unknown retention type");
204 				free($2);
205 				YYERROR;
206 			}
207 		}
208 		| ADVERTISEMENT STRING {
209 			conf->mode &= ~(MODE_ADV_ONDEMAND |
210 			    MODE_ADV_UNSOLICITED);
211 
212 			if (!strcmp($2, "ondemand"))
213 				conf->mode |= MODE_ADV_ONDEMAND;
214 			else if (!strcmp($2, "unsolicited"))
215 				conf->mode |= MODE_ADV_UNSOLICITED;
216 			else {
217 				yyerror("unknown retention type");
218 				free($2);
219 				YYERROR;
220 			}
221 		}
222 		| THELLOACCEPT yesno {
223 			if ($2 == 0)
224 				conf->flags &= ~LDPD_FLAG_TH_ACCEPT;
225 			else
226 				conf->flags |= LDPD_FLAG_TH_ACCEPT;
227 		}
228 		| KEEPALIVE NUMBER {
229 			if ($2 < MIN_KEEPALIVE ||
230 			    $2 > MAX_KEEPALIVE) {
231 				yyerror("keepalive out of range (%d-%d)",
232 				    MIN_KEEPALIVE, MAX_KEEPALIVE);
233 				YYERROR;
234 			}
235 			conf->keepalive = $2;
236 		}
237 		| iface_defaults
238 		| tnbr_defaults
239 		;
240 iface_defaults	: LHELLOHOLDTIME NUMBER {
241 			if ($2 < MIN_HOLDTIME ||
242 			    $2 > MAX_HOLDTIME) {
243 				yyerror("hello holdtime out of range (%d-%d)",
244 				    MIN_HOLDTIME, MAX_HOLDTIME);
245 				YYERROR;
246 			}
247 			defs->lhello_holdtime = $2;
248 		}
249 		| LHELLOINTERVAL NUMBER {
250 			if ($2 < MIN_HELLO_INTERVAL ||
251 			    $2 > MAX_HELLO_INTERVAL) {
252 				yyerror("hello-interval out of range (%d-%d)",
253 				    MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL);
254 				YYERROR;
255 			}
256 			defs->lhello_interval = $2;
257 		}
258 		;
259 
260 tnbr_defaults	: THELLOHOLDTIME NUMBER {
261 			if ($2 < MIN_HOLDTIME ||
262 			    $2 > MAX_HOLDTIME) {
263 				yyerror("hello holdtime out of range (%d-%d)",
264 				    MIN_HOLDTIME, MAX_HOLDTIME);
265 				YYERROR;
266 			}
267 			conf->thello_holdtime = $2;
268 			defs->thello_holdtime = $2;
269 		}
270 		| THELLOINTERVAL NUMBER {
271 			if ($2 < MIN_HELLO_INTERVAL ||
272 			    $2 > MAX_HELLO_INTERVAL) {
273 				yyerror("hello-interval out of range (%d-%d)",
274 				    MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL);
275 				YYERROR;
276 			}
277 			conf->thello_interval = $2;
278 			defs->thello_interval = $2;
279 		}
280 		;
281 
282 optnl		: '\n' optnl
283 		|
284 		;
285 
286 nl		: '\n' optnl		/* one newline or more */
287 		;
288 
289 interface	: INTERFACE STRING	{
290 			struct kif	*kif;
291 
292 			if ((kif = kif_findname($2)) == NULL) {
293 				yyerror("unknown interface %s", $2);
294 				free($2);
295 				YYERROR;
296 			}
297 			free($2);
298 			iface = conf_get_if(kif);
299 			if (iface == NULL)
300 				YYERROR;
301 			if (iface->media_type == IFT_LOOP ||
302 			    iface->media_type == IFT_CARP) {
303 				yyerror("unsupported interface type on "
304 				    "interface %s", iface->name);
305 				YYERROR;
306 			}
307 			LIST_INSERT_HEAD(&conf->iface_list, iface, entry);
308 
309 			memcpy(&ifacedefs, defs, sizeof(ifacedefs));
310 			defs = &ifacedefs;
311 		} interface_block {
312 			iface->hello_holdtime = defs->lhello_holdtime;
313 			iface->hello_interval = defs->lhello_interval;
314 			iface = NULL;
315 
316 			defs = &globaldefs;
317 		}
318 		;
319 
320 interface_block	: '{' optnl interfaceopts_l '}'
321 		| '{' optnl '}'
322 		| /* nothing */
323 		;
324 
325 interfaceopts_l	: interfaceopts_l iface_defaults nl
326 		| iface_defaults optnl
327 		;
328 
329 tneighbor	: TNEIGHBOR STRING	{
330 			struct in_addr	 addr;
331 
332 			if (inet_aton($2, &addr) == 0) {
333 				yyerror(
334 				    "error parsing neighbor address");
335 				free($2);
336 				YYERROR;
337 			}
338 			free($2);
339 
340 			tnbr = conf_get_tnbr(addr);
341 			if (tnbr == NULL)
342 				YYERROR;
343 			LIST_INSERT_HEAD(&conf->tnbr_list, tnbr, entry);
344 
345 			memcpy(&tnbrdefs, defs, sizeof(tnbrdefs));
346 			defs = &tnbrdefs;
347 		} tneighbor_block {
348 			tnbr->hello_holdtime = defs->thello_holdtime;
349 			tnbr->hello_interval = defs->thello_interval;
350 			tnbr = NULL;
351 
352 			defs = &globaldefs;
353 		}
354 		;
355 
356 tneighbor_block	: '{' optnl tneighboropts_l '}'
357 		| '{' optnl '}'
358 		| /* nothing */
359 		;
360 
361 tneighboropts_l	: tneighboropts_l tnbr_defaults nl
362 		| tnbr_defaults optnl
363 		;
364 
365 %%
366 
367 struct keywords {
368 	const char	*k_name;
369 	int		 k_val;
370 };
371 
372 int
373 yyerror(const char *fmt, ...)
374 {
375 	va_list		 ap;
376 	char		*nfmt;
377 
378 	file->errors++;
379 	va_start(ap, fmt);
380 	if (asprintf(&nfmt, "%s:%d: %s", file->name, yylval.lineno, fmt) == -1)
381 		fatalx("yyerror asprintf");
382 	vlog(LOG_CRIT, nfmt, ap);
383 	va_end(ap);
384 	free(nfmt);
385 	return (0);
386 }
387 
388 int
389 kw_cmp(const void *k, const void *e)
390 {
391 	return (strcmp(k, ((const struct keywords *)e)->k_name));
392 }
393 
394 int
395 lookup(char *s)
396 {
397 	/* this has to be sorted always */
398 	static const struct keywords keywords[] = {
399 		{"advertisement",		ADVERTISEMENT},
400 		{"distribution",		DISTRIBUTION},
401 		{"external-tag",		EXTTAG},
402 		{"fib-update",			FIBUPDATE},
403 		{"interface",			INTERFACE},
404 		{"keepalive",			KEEPALIVE},
405 		{"link-hello-holdtime",		LHELLOHOLDTIME},
406 		{"link-hello-interval",		LHELLOINTERVAL},
407 		{"no",				NO},
408 		{"retention",			RETENTION},
409 		{"router-id",			ROUTERID},
410 		{"targeted-hello-accept",	THELLOACCEPT},
411 		{"targeted-hello-holdtime",	THELLOHOLDTIME},
412 		{"targeted-hello-interval",	THELLOINTERVAL},
413 		{"targeted-neighbor",		TNEIGHBOR},
414 		{"yes",				YES}
415 	};
416 	const struct keywords	*p;
417 
418 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
419 	    sizeof(keywords[0]), kw_cmp);
420 
421 	if (p)
422 		return (p->k_val);
423 	else
424 		return (STRING);
425 }
426 
427 #define MAXPUSHBACK	128
428 
429 u_char	*parsebuf;
430 int	 parseindex;
431 u_char	 pushback_buffer[MAXPUSHBACK];
432 int	 pushback_index = 0;
433 
434 int
435 lgetc(int quotec)
436 {
437 	int		c, next;
438 
439 	if (parsebuf) {
440 		/* Read character from the parsebuffer instead of input. */
441 		if (parseindex >= 0) {
442 			c = parsebuf[parseindex++];
443 			if (c != '\0')
444 				return (c);
445 			parsebuf = NULL;
446 		} else
447 			parseindex++;
448 	}
449 
450 	if (pushback_index)
451 		return (pushback_buffer[--pushback_index]);
452 
453 	if (quotec) {
454 		if ((c = getc(file->stream)) == EOF) {
455 			yyerror("reached end of file while parsing "
456 			    "quoted string");
457 			if (file == topfile || popfile() == EOF)
458 				return (EOF);
459 			return (quotec);
460 		}
461 		return (c);
462 	}
463 
464 	while ((c = getc(file->stream)) == '\\') {
465 		next = getc(file->stream);
466 		if (next != '\n') {
467 			c = next;
468 			break;
469 		}
470 		yylval.lineno = file->lineno;
471 		file->lineno++;
472 	}
473 
474 	while (c == EOF) {
475 		if (file == topfile || popfile() == EOF)
476 			return (EOF);
477 		c = getc(file->stream);
478 	}
479 	return (c);
480 }
481 
482 int
483 lungetc(int c)
484 {
485 	if (c == EOF)
486 		return (EOF);
487 	if (parsebuf) {
488 		parseindex--;
489 		if (parseindex >= 0)
490 			return (c);
491 	}
492 	if (pushback_index < MAXPUSHBACK-1)
493 		return (pushback_buffer[pushback_index++] = c);
494 	else
495 		return (EOF);
496 }
497 
498 int
499 findeol(void)
500 {
501 	int	c;
502 
503 	parsebuf = NULL;
504 	pushback_index = 0;
505 
506 	/* skip to either EOF or the first real EOL */
507 	while (1) {
508 		c = lgetc(0);
509 		if (c == '\n') {
510 			file->lineno++;
511 			break;
512 		}
513 		if (c == EOF)
514 			break;
515 	}
516 	return (ERROR);
517 }
518 
519 int
520 yylex(void)
521 {
522 	u_char	 buf[8096];
523 	u_char	*p, *val;
524 	int	 quotec, next, c;
525 	int	 token;
526 
527 top:
528 	p = buf;
529 	while ((c = lgetc(0)) == ' ' || c == '\t')
530 		; /* nothing */
531 
532 	yylval.lineno = file->lineno;
533 	if (c == '#')
534 		while ((c = lgetc(0)) != '\n' && c != EOF)
535 			; /* nothing */
536 	if (c == '$' && parsebuf == NULL) {
537 		while (1) {
538 			if ((c = lgetc(0)) == EOF)
539 				return (0);
540 
541 			if (p + 1 >= buf + sizeof(buf) - 1) {
542 				yyerror("string too long");
543 				return (findeol());
544 			}
545 			if (isalnum(c) || c == '_') {
546 				*p++ = c;
547 				continue;
548 			}
549 			*p = '\0';
550 			lungetc(c);
551 			break;
552 		}
553 		val = symget(buf);
554 		if (val == NULL) {
555 			yyerror("macro '%s' not defined", buf);
556 			return (findeol());
557 		}
558 		parsebuf = val;
559 		parseindex = 0;
560 		goto top;
561 	}
562 
563 	switch (c) {
564 	case '\'':
565 	case '"':
566 		quotec = c;
567 		while (1) {
568 			if ((c = lgetc(quotec)) == EOF)
569 				return (0);
570 			if (c == '\n') {
571 				file->lineno++;
572 				continue;
573 			} else if (c == '\\') {
574 				if ((next = lgetc(quotec)) == EOF)
575 					return (0);
576 				if (next == quotec || c == ' ' || c == '\t')
577 					c = next;
578 				else if (next == '\n') {
579 					file->lineno++;
580 					continue;
581 				} else
582 					lungetc(next);
583 			} else if (c == quotec) {
584 				*p = '\0';
585 				break;
586 			}
587 			if (p + 1 >= buf + sizeof(buf) - 1) {
588 				yyerror("string too long");
589 				return (findeol());
590 			}
591 			*p++ = c;
592 		}
593 		yylval.v.string = strdup(buf);
594 		if (yylval.v.string == NULL)
595 			err(1, "yylex: strdup");
596 		return (STRING);
597 	}
598 
599 #define allowed_to_end_number(x) \
600 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
601 
602 	if (c == '-' || isdigit(c)) {
603 		do {
604 			*p++ = c;
605 			if ((unsigned)(p-buf) >= sizeof(buf)) {
606 				yyerror("string too long");
607 				return (findeol());
608 			}
609 		} while ((c = lgetc(0)) != EOF && isdigit(c));
610 		lungetc(c);
611 		if (p == buf + 1 && buf[0] == '-')
612 			goto nodigits;
613 		if (c == EOF || allowed_to_end_number(c)) {
614 			const char *errstr = NULL;
615 
616 			*p = '\0';
617 			yylval.v.number = strtonum(buf, LLONG_MIN,
618 			    LLONG_MAX, &errstr);
619 			if (errstr) {
620 				yyerror("\"%s\" invalid number: %s",
621 				    buf, errstr);
622 				return (findeol());
623 			}
624 			return (NUMBER);
625 		} else {
626 nodigits:
627 			while (p > buf + 1)
628 				lungetc(*--p);
629 			c = *--p;
630 			if (c == '-')
631 				return (c);
632 		}
633 	}
634 
635 #define allowed_in_string(x) \
636 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
637 	x != '{' && x != '}' && \
638 	x != '!' && x != '=' && x != '#' && \
639 	x != ','))
640 
641 	if (isalnum(c) || c == ':' || c == '_') {
642 		do {
643 			*p++ = c;
644 			if ((unsigned)(p-buf) >= sizeof(buf)) {
645 				yyerror("string too long");
646 				return (findeol());
647 			}
648 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
649 		lungetc(c);
650 		*p = '\0';
651 		if ((token = lookup(buf)) == STRING)
652 			if ((yylval.v.string = strdup(buf)) == NULL)
653 				err(1, "yylex: strdup");
654 		return (token);
655 	}
656 	if (c == '\n') {
657 		yylval.lineno = file->lineno;
658 		file->lineno++;
659 	}
660 	if (c == EOF)
661 		return (0);
662 	return (c);
663 }
664 
665 int
666 check_file_secrecy(int fd, const char *fname)
667 {
668 	struct stat	st;
669 
670 	if (fstat(fd, &st)) {
671 		log_warn("cannot stat %s", fname);
672 		return (-1);
673 	}
674 	if (st.st_uid != 0 && st.st_uid != getuid()) {
675 		log_warnx("%s: owner not root or current user", fname);
676 		return (-1);
677 	}
678 	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
679 		log_warnx("%s: group writable or world read/writable", fname);
680 		return (-1);
681 	}
682 	return (0);
683 }
684 
685 struct file *
686 pushfile(const char *name, int secret)
687 {
688 	struct file	*nfile;
689 
690 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
691 		log_warn("malloc");
692 		return (NULL);
693 	}
694 	if ((nfile->name = strdup(name)) == NULL) {
695 		log_warn("strdup");
696 		free(nfile);
697 		return (NULL);
698 	}
699 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
700 		log_warn("%s", nfile->name);
701 		free(nfile->name);
702 		free(nfile);
703 		return (NULL);
704 	} else if (secret &&
705 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
706 		fclose(nfile->stream);
707 		free(nfile->name);
708 		free(nfile);
709 		return (NULL);
710 	}
711 	nfile->lineno = 1;
712 	TAILQ_INSERT_TAIL(&files, nfile, entry);
713 	return (nfile);
714 }
715 
716 int
717 popfile(void)
718 {
719 	struct file	*prev;
720 
721 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
722 		prev->errors += file->errors;
723 
724 	TAILQ_REMOVE(&files, file, entry);
725 	fclose(file->stream);
726 	free(file->name);
727 	free(file);
728 	file = prev;
729 	return (file ? 0 : EOF);
730 }
731 
732 struct ldpd_conf *
733 parse_config(char *filename, int opts)
734 {
735 	struct sym	*sym, *next;
736 
737 	if ((conf = calloc(1, sizeof(struct ldpd_conf))) == NULL)
738 		fatal("parse_config");
739 	conf->opts = opts;
740 	conf->keepalive = DEFAULT_KEEPALIVE;
741 
742 	bzero(&globaldefs, sizeof(globaldefs));
743 	defs = &globaldefs;
744 	defs->lhello_holdtime = LINK_DFLT_HOLDTIME;
745 	defs->lhello_interval = DEFAULT_HELLO_INTERVAL;
746 	defs->thello_holdtime = TARGETED_DFLT_HOLDTIME;
747 	defs->thello_interval = DEFAULT_HELLO_INTERVAL;
748 	conf->thello_holdtime = TARGETED_DFLT_HOLDTIME;
749 	conf->thello_interval = DEFAULT_HELLO_INTERVAL;
750 
751 	conf->mode = (MODE_DIST_INDEPENDENT | MODE_RET_LIBERAL |
752 	    MODE_ADV_UNSOLICITED);
753 
754 	if ((file = pushfile(filename, !(conf->opts & LDPD_OPT_NOACTION))) == NULL) {
755 		free(conf);
756 		return (NULL);
757 	}
758 	topfile = file;
759 
760 	yyparse();
761 	errors = file->errors;
762 	popfile();
763 
764 	/* Free macros and check which have not been used. */
765 	for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
766 		next = TAILQ_NEXT(sym, entry);
767 		if ((conf->opts & LDPD_OPT_VERBOSE2) && !sym->used)
768 			fprintf(stderr, "warning: macro '%s' not "
769 			    "used\n", sym->nam);
770 		if (!sym->persist) {
771 			free(sym->nam);
772 			free(sym->val);
773 			TAILQ_REMOVE(&symhead, sym, entry);
774 			free(sym);
775 		}
776 	}
777 
778 	/* free global config defaults */
779 	if (errors) {
780 		clear_config(conf);
781 		return (NULL);
782 	}
783 
784 	if (conf->rtr_id.s_addr == 0)
785 		conf->rtr_id.s_addr = get_rtr_id();
786 
787 	return (conf);
788 }
789 
790 int
791 symset(const char *nam, const char *val, int persist)
792 {
793 	struct sym	*sym;
794 
795 	for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
796 	    sym = TAILQ_NEXT(sym, entry))
797 		;	/* nothing */
798 
799 	if (sym != NULL) {
800 		if (sym->persist == 1)
801 			return (0);
802 		else {
803 			free(sym->nam);
804 			free(sym->val);
805 			TAILQ_REMOVE(&symhead, sym, entry);
806 			free(sym);
807 		}
808 	}
809 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
810 		return (-1);
811 
812 	sym->nam = strdup(nam);
813 	if (sym->nam == NULL) {
814 		free(sym);
815 		return (-1);
816 	}
817 	sym->val = strdup(val);
818 	if (sym->val == NULL) {
819 		free(sym->nam);
820 		free(sym);
821 		return (-1);
822 	}
823 	sym->used = 0;
824 	sym->persist = persist;
825 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
826 	return (0);
827 }
828 
829 int
830 cmdline_symset(char *s)
831 {
832 	char	*sym, *val;
833 	int	ret;
834 	size_t	len;
835 
836 	if ((val = strrchr(s, '=')) == NULL)
837 		return (-1);
838 
839 	len = strlen(s) - strlen(val) + 1;
840 	if ((sym = malloc(len)) == NULL)
841 		errx(1, "cmdline_symset: malloc");
842 
843 	strlcpy(sym, s, len);
844 
845 	ret = symset(sym, val + 1, 1);
846 	free(sym);
847 
848 	return (ret);
849 }
850 
851 char *
852 symget(const char *nam)
853 {
854 	struct sym	*sym;
855 
856 	TAILQ_FOREACH(sym, &symhead, entry)
857 		if (strcmp(nam, sym->nam) == 0) {
858 			sym->used = 1;
859 			return (sym->val);
860 		}
861 	return (NULL);
862 }
863 
864 struct iface *
865 conf_get_if(struct kif *kif)
866 {
867 	struct iface	*i;
868 
869 	LIST_FOREACH(i, &conf->iface_list, entry) {
870 		if (i->ifindex == kif->ifindex) {
871 			yyerror("interface %s already configured",
872 			    kif->ifname);
873 			return (NULL);
874 		}
875 	}
876 
877 	i = if_new(kif);
878 
879 	return (i);
880 }
881 
882 struct tnbr *
883 conf_get_tnbr(struct in_addr addr)
884 {
885 	struct tnbr	*t;
886 
887 	LIST_FOREACH(t, &conf->tnbr_list, entry) {
888 		if (t->addr.s_addr == addr.s_addr) {
889 			yyerror("targeted neighbor %s already configured",
890 			    inet_ntoa(addr));
891 			return (NULL);
892 		}
893 	}
894 
895 	t = tnbr_new(conf, addr, 1);
896 
897 	return (t);
898 }
899 
900 void
901 clear_config(struct ldpd_conf *xconf)
902 {
903 	struct iface	*i;
904 
905 	while ((i = LIST_FIRST(&conf->iface_list)) != NULL) {
906 		LIST_REMOVE(i, entry);
907 		if_del(i);
908 	}
909 
910 	free(xconf);
911 }
912 
913 u_int32_t
914 get_rtr_id(void)
915 {
916 	struct ifaddrs		*ifap, *ifa;
917 	u_int32_t		 ip = 0, cur, localnet;
918 
919 	localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
920 
921 	if (getifaddrs(&ifap) == -1)
922 		fatal("getifaddrs");
923 
924 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
925 		if (strncmp(ifa->ifa_name, "carp", 4) == 0)
926 			continue;
927 		if (ifa->ifa_addr->sa_family != AF_INET)
928 			continue;
929 		cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
930 		if ((cur & localnet) == localnet)	/* skip 127/8 */
931 			continue;
932 		if (cur > ip || ip == 0)
933 			ip = cur;
934 	}
935 	freeifaddrs(ifap);
936 
937 	if (ip == 0)
938 		fatal("router-id is 0.0.0.0");
939 
940 	return (ip);
941 }
942 
943 int
944 host(const char *s, struct in_addr *addr, struct in_addr *mask)
945 {
946 	struct in_addr		 ina;
947 	int			 bits = 32;
948 
949 	bzero(&ina, sizeof(struct in_addr));
950 	if (strrchr(s, '/') != NULL) {
951 		if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
952 			return (0);
953 	} else {
954 		if (inet_pton(AF_INET, s, &ina) != 1)
955 			return (0);
956 	}
957 
958 	addr->s_addr = ina.s_addr;
959 	mask->s_addr = prefixlen2mask(bits);
960 
961 	return (1);
962 }
963