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