parse.y revision 1.67
1/*	$OpenBSD: parse.y,v 1.67 2018/11/01 00:18:44 sashan Exp $ */
2
3/*
4 * Copyright (c) 2013, 2015, 2016 Renato Westphal <renato@openbsd.org>
5 * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
6 * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
7 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
8 * Copyright (c) 2001 Markus Friedl.  All rights reserved.
9 * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
10 * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
11 *
12 * Permission to use, copy, modify, and distribute this software for any
13 * purpose with or without fee is hereby granted, provided that the above
14 * copyright notice and this permission notice appear in all copies.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
17 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
19 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
21 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
22 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 */
24
25%{
26#include <sys/stat.h>
27#include <arpa/inet.h>
28#include <ctype.h>
29#include <err.h>
30#include <unistd.h>
31#include <ifaddrs.h>
32#include <net/if_types.h>
33#include <limits.h>
34#include <stdio.h>
35#include <syslog.h>
36
37#include "ldpd.h"
38#include "ldpe.h"
39#include "lde.h"
40#include "log.h"
41
42struct file {
43	TAILQ_ENTRY(file)	 entry;
44	FILE			*stream;
45	char			*name;
46	size_t			 ungetpos;
47	size_t			 ungetsize;
48	u_char			*ungetbuf;
49	int			 eof_reached;
50	int			 lineno;
51	int			 errors;
52};
53TAILQ_HEAD(files, file);
54
55struct sym {
56	TAILQ_ENTRY(sym)	 entry;
57	int			 used;
58	int			 persist;
59	char			*nam;
60	char			*val;
61};
62TAILQ_HEAD(symhead, sym);
63
64struct config_defaults {
65	uint16_t	keepalive;
66	uint16_t	lhello_holdtime;
67	uint16_t	lhello_interval;
68	uint16_t	thello_holdtime;
69	uint16_t	thello_interval;
70	union ldpd_addr	trans_addr;
71	int		afflags;
72	uint8_t		pwflags;
73};
74
75typedef struct {
76	union {
77		int64_t		 number;
78		char		*string;
79	} v;
80	int lineno;
81} YYSTYPE;
82
83static int		 yyerror(const char *, ...)
84    __attribute__((__format__ (printf, 1, 2)))
85    __attribute__((__nonnull__ (1)));
86static int		 kw_cmp(const void *, const void *);
87static int		 lookup(char *);
88static int		 igetc(void);
89static int		 lgetc(int);
90void			 lungetc(int);
91static int		 findeol(void);
92static int		 yylex(void);
93static int		 check_file_secrecy(int, const char *);
94static struct file	*pushfile(const char *, int);
95static int		 popfile(void);
96static int		 yyparse(void);
97static int		 symset(const char *, const char *, int);
98static char		*symget(const char *);
99static struct iface	*conf_get_if(struct kif *);
100static struct tnbr	*conf_get_tnbr(union ldpd_addr *);
101static struct nbr_params *conf_get_nbrp(struct in_addr);
102static struct l2vpn	*conf_get_l2vpn(char *);
103static struct l2vpn_if	*conf_get_l2vpn_if(struct l2vpn *, struct kif *);
104static struct l2vpn_pw	*conf_get_l2vpn_pw(struct l2vpn *, struct kif *);
105int			 conf_check_rdomain(unsigned int);
106static void		 clear_config(struct ldpd_conf *xconf);
107static uint32_t		 get_rtr_id(void);
108static int		 get_address(const char *, union ldpd_addr *);
109static int		 get_af_address(const char *, int *, union ldpd_addr *);
110
111static struct file		*file, *topfile;
112static struct files		 files = TAILQ_HEAD_INITIALIZER(files);
113static struct symhead		 symhead = TAILQ_HEAD_INITIALIZER(symhead);
114static struct ldpd_conf		*conf;
115static int			 errors;
116
117static int			 af;
118static struct ldpd_af_conf	*af_conf;
119static struct iface		*iface;
120static struct iface_af		*ia;
121static struct tnbr		*tnbr;
122static struct nbr_params	*nbrp;
123static struct l2vpn		*l2vpn;
124static struct l2vpn_pw		*pw;
125
126static struct config_defaults	 globaldefs;
127static struct config_defaults	 afdefs;
128static struct config_defaults	 ifacedefs;
129static struct config_defaults	 tnbrdefs;
130static struct config_defaults	 pwdefs;
131static struct config_defaults	*defs;
132
133%}
134
135%token	INTERFACE TNEIGHBOR ROUTERID FIBUPDATE RDOMAIN EXPNULL
136%token	LHELLOHOLDTIME LHELLOINTERVAL
137%token	THELLOHOLDTIME THELLOINTERVAL
138%token	THELLOACCEPT AF IPV4 IPV6 GTSMENABLE GTSMHOPS
139%token	KEEPALIVE TRANSADDRESS TRANSPREFERENCE DSCISCOINTEROP
140%token	NEIGHBOR PASSWORD
141%token	L2VPN TYPE VPLS PWTYPE MTU BRIDGE
142%token	ETHERNET ETHERNETTAGGED STATUSTLV CONTROLWORD
143%token	PSEUDOWIRE NEIGHBORID NEIGHBORADDR PWID
144%token	EXTTAG
145%token	YES NO
146%token	INCLUDE
147%token	ERROR
148%token	<v.string>	STRING
149%token	<v.number>	NUMBER
150%type	<v.number>	yesno ldp_af l2vpn_type pw_type
151%type	<v.string>	string
152
153%%
154
155grammar		: /* empty */
156		| grammar include '\n'
157		| grammar '\n'
158		| grammar conf_main '\n'
159		| grammar varset '\n'
160		| grammar af '\n'
161		| grammar neighbor '\n'
162		| grammar l2vpn '\n'
163		| grammar error '\n'		{ file->errors++; }
164		;
165
166include		: INCLUDE STRING		{
167			struct file	*nfile;
168
169			if ((nfile = pushfile($2,
170			    !(global.cmd_opts & LDPD_OPT_NOACTION))) == NULL) {
171				yyerror("failed to include file %s", $2);
172				free($2);
173				YYERROR;
174			}
175			free($2);
176
177			file = nfile;
178			lungetc('\n');
179		}
180		;
181
182string		: string STRING	{
183			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
184				free($1);
185				free($2);
186				yyerror("string: asprintf");
187				YYERROR;
188			}
189			free($1);
190			free($2);
191		}
192		| STRING
193		;
194
195yesno		: YES	{ $$ = 1; }
196		| NO	{ $$ = 0; }
197		;
198
199ldp_af		: IPV4	{ $$ = AF_INET; }
200		| IPV6	{ $$ = AF_INET6; }
201		;
202
203l2vpn_type	: VPLS	{ $$ = L2VPN_TYPE_VPLS; }
204		;
205
206pw_type		: ETHERNET		{ $$ = PW_TYPE_ETHERNET; }
207		| ETHERNETTAGGED	{ $$ = PW_TYPE_ETHERNET_TAGGED; }
208		;
209
210varset		: STRING '=' string {
211			char *s = $1;
212			if (global.cmd_opts & LDPD_OPT_VERBOSE)
213				printf("%s = \"%s\"\n", $1, $3);
214			while (*s++) {
215				if (isspace((unsigned char)*s)) {
216					yyerror("macro name cannot contain "
217					    "whitespace");
218					free($1);
219					free($3);
220					YYERROR;
221				}
222			}
223			if (symset($1, $3, 0) == -1)
224				fatal("cannot store variable");
225			free($1);
226			free($3);
227		}
228		;
229
230conf_main	: ROUTERID STRING {
231			if (!inet_aton($2, &conf->rtr_id)) {
232				yyerror("error parsing router-id");
233				free($2);
234				YYERROR;
235			}
236			free($2);
237			if (bad_addr_v4(conf->rtr_id)) {
238				yyerror("invalid router-id");
239				YYERROR;
240			}
241		}
242		| FIBUPDATE yesno {
243			if ($2 == 0)
244				conf->flags |= F_LDPD_NO_FIB_UPDATE;
245			else
246				conf->flags &= ~F_LDPD_NO_FIB_UPDATE;
247		}
248		| RDOMAIN NUMBER {
249			if ($2 < 0 || $2 > RT_TABLEID_MAX) {
250				yyerror("invalid rdomain");
251				YYERROR;
252			}
253			conf->rdomain = $2;
254		}
255		| TRANSPREFERENCE ldp_af {
256			conf->trans_pref = $2;
257
258			switch (conf->trans_pref) {
259			case AF_INET:
260				conf->trans_pref = DUAL_STACK_LDPOV4;
261				break;
262			case AF_INET6:
263				conf->trans_pref = DUAL_STACK_LDPOV6;
264				break;
265			default:
266				yyerror("invalid address-family");
267				YYERROR;
268			}
269		}
270		| DSCISCOINTEROP yesno {
271			if ($2 == 1)
272				conf->flags |= F_LDPD_DS_CISCO_INTEROP;
273			else
274				conf->flags &= ~F_LDPD_DS_CISCO_INTEROP;
275		}
276		| af_defaults
277		| iface_defaults
278		| tnbr_defaults
279		;
280
281af		: AF ldp_af {
282			af = $2;
283			switch (af) {
284			case AF_INET:
285				af_conf = &conf->ipv4;
286				break;
287			case AF_INET6:
288				af_conf = &conf->ipv6;
289				break;
290			default:
291				yyerror("invalid address-family");
292				YYERROR;
293			}
294
295			afdefs = *defs;
296			defs = &afdefs;
297		} af_block {
298			af_conf->keepalive = defs->keepalive;
299			af_conf->thello_holdtime = defs->thello_holdtime;
300			af_conf->thello_interval = defs->thello_interval;
301			af_conf->flags = defs->afflags;
302			af_conf->flags |= F_LDPD_AF_ENABLED;
303			af_conf = NULL;
304			af = AF_UNSPEC;
305			defs = &globaldefs;
306		}
307		;
308
309af_block	: '{' optnl afopts_l '}'
310		| '{' optnl '}'
311		|
312		;
313
314afopts_l	: afopts_l afoptsl nl
315		| afoptsl optnl
316		;
317
318afoptsl		:  TRANSADDRESS STRING {
319			if (get_address($2, &af_conf->trans_addr) == -1) {
320				yyerror("error parsing transport-address");
321				free($2);
322				YYERROR;
323			}
324			free($2);
325			if (bad_addr(af, &af_conf->trans_addr)) {
326				yyerror("invalid transport-address");
327				YYERROR;
328			}
329			if (af == AF_INET6 &&
330			   IN6_IS_SCOPE_EMBED(&af_conf->trans_addr.v6)) {
331				yyerror("ipv6 transport-address can not be "
332				    "link-local");
333				YYERROR;
334			}
335		}
336		| GTSMENABLE yesno {
337			if ($2 == 0)
338				defs->afflags |= F_LDPD_AF_NO_GTSM;
339		}
340		| af_defaults
341		| iface_defaults
342		| tnbr_defaults
343		| interface
344		| tneighbor
345		;
346
347af_defaults	: THELLOACCEPT yesno {
348			if ($2 == 0)
349				defs->afflags &= ~F_LDPD_AF_THELLO_ACCEPT;
350			else
351				defs->afflags |= F_LDPD_AF_THELLO_ACCEPT;
352		}
353		| EXPNULL yesno {
354			if ($2 == 0)
355				defs->afflags &= ~F_LDPD_AF_EXPNULL;
356			else
357				defs->afflags |= F_LDPD_AF_EXPNULL;
358		}
359		| KEEPALIVE NUMBER {
360			if ($2 < MIN_KEEPALIVE || $2 > MAX_KEEPALIVE) {
361				yyerror("keepalive out of range (%d-%d)",
362				    MIN_KEEPALIVE, MAX_KEEPALIVE);
363				YYERROR;
364			}
365			defs->keepalive = $2;
366		}
367		;
368
369iface_defaults	: LHELLOHOLDTIME NUMBER {
370			if ($2 < MIN_HOLDTIME || $2 > MAX_HOLDTIME) {
371				yyerror("hello-holdtime out of range (%d-%d)",
372				    MIN_HOLDTIME, MAX_HOLDTIME);
373				YYERROR;
374			}
375			defs->lhello_holdtime = $2;
376		}
377		| LHELLOINTERVAL NUMBER {
378			if ($2 < MIN_HELLO_INTERVAL ||
379			    $2 > MAX_HELLO_INTERVAL) {
380				yyerror("hello-interval out of range (%d-%d)",
381				    MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL);
382				YYERROR;
383			}
384			defs->lhello_interval = $2;
385		}
386		;
387
388tnbr_defaults	: THELLOHOLDTIME NUMBER {
389			if ($2 < MIN_HOLDTIME || $2 > MAX_HOLDTIME) {
390				yyerror("hello-holdtime out of range (%d-%d)",
391				    MIN_HOLDTIME, MAX_HOLDTIME);
392				YYERROR;
393			}
394			defs->thello_holdtime = $2;
395		}
396		| THELLOINTERVAL NUMBER {
397			if ($2 < MIN_HELLO_INTERVAL ||
398			    $2 > MAX_HELLO_INTERVAL) {
399				yyerror("hello-interval out of range (%d-%d)",
400				    MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL);
401				YYERROR;
402			}
403			defs->thello_interval = $2;
404		}
405		;
406
407nbr_opts	: KEEPALIVE NUMBER {
408			if ($2 < MIN_KEEPALIVE || $2 > MAX_KEEPALIVE) {
409				yyerror("keepalive out of range (%d-%d)",
410				    MIN_KEEPALIVE, MAX_KEEPALIVE);
411				YYERROR;
412			}
413			nbrp->keepalive = $2;
414			nbrp->flags |= F_NBRP_KEEPALIVE;
415		}
416		| PASSWORD STRING {
417			if (strlcpy(nbrp->auth.md5key, $2,
418			    sizeof(nbrp->auth.md5key)) >=
419			    sizeof(nbrp->auth.md5key)) {
420				yyerror("tcp md5sig password too long: max %zu",
421				    sizeof(nbrp->auth.md5key) - 1);
422				free($2);
423				YYERROR;
424			}
425			nbrp->auth.md5key_len = strlen($2);
426			nbrp->auth.method = AUTH_MD5SIG;
427			free($2);
428		}
429		| GTSMENABLE yesno {
430			nbrp->flags |= F_NBRP_GTSM;
431			nbrp->gtsm_enabled = $2;
432		}
433		| GTSMHOPS NUMBER {
434			if ($2 < 1 || $2 > 255) {
435				yyerror("invalid number of hops %lld", $2);
436				YYERROR;
437			}
438			nbrp->gtsm_hops = $2;
439			nbrp->flags |= F_NBRP_GTSM_HOPS;
440		}
441		;
442
443pw_defaults	: STATUSTLV yesno {
444			if ($2 == 1)
445				defs->pwflags |= F_PW_STATUSTLV_CONF;
446			else
447				defs->pwflags &= ~F_PW_STATUSTLV_CONF;
448		}
449		| CONTROLWORD yesno {
450			if ($2 == 1)
451				defs->pwflags |= F_PW_CWORD_CONF;
452			else
453				defs->pwflags &= ~F_PW_CWORD_CONF;
454		}
455		;
456
457pwopts		: PWID NUMBER {
458			if ($2 < MIN_PWID_ID ||
459			    $2 > MAX_PWID_ID) {
460				yyerror("pw-id out of range (%d-%d)",
461				    MIN_PWID_ID, MAX_PWID_ID);
462				YYERROR;
463			}
464
465			pw->pwid = $2;
466		}
467		| NEIGHBORID STRING {
468			struct in_addr	 addr;
469
470			if (!inet_aton($2, &addr)) {
471				yyerror("error parsing neighbor-id");
472				free($2);
473				YYERROR;
474			}
475			free($2);
476			if (bad_addr_v4(addr)) {
477				yyerror("invalid neighbor-id");
478				YYERROR;
479			}
480
481			pw->lsr_id = addr;
482		}
483		| NEIGHBORADDR STRING {
484			int		 family;
485			union ldpd_addr	 addr;
486
487			if (get_af_address($2, &family, &addr) == -1) {
488				yyerror("error parsing neighbor address");
489				free($2);
490				YYERROR;
491			}
492			free($2);
493			if (bad_addr(family, &addr)) {
494				yyerror("invalid neighbor address");
495				YYERROR;
496			}
497			if (family == AF_INET6 &&
498			    IN6_IS_SCOPE_EMBED(&addr.v6)) {
499				yyerror("neighbor address can not be "
500				    "link-local");
501				YYERROR;
502			}
503
504			pw->af = family;
505			pw->addr = addr;
506		}
507		| pw_defaults
508		;
509
510pseudowire	: PSEUDOWIRE STRING {
511			struct kif	*kif;
512
513			if ((kif = kif_findname($2)) == NULL) {
514				yyerror("unknown interface %s", $2);
515				free($2);
516				YYERROR;
517			}
518			free($2);
519
520			if (kif->if_type != IFT_MPLSTUNNEL) {
521				yyerror("unsupported interface type on "
522				    "interface %s", kif->ifname);
523				YYERROR;
524			}
525
526			pw = conf_get_l2vpn_pw(l2vpn, kif);
527			if (pw == NULL)
528				YYERROR;
529
530			pwdefs = *defs;
531			defs = &pwdefs;
532		} pw_block {
533			struct l2vpn	*l;
534			struct l2vpn_pw *p;
535
536			/* check for errors */
537			if (pw->pwid == 0) {
538				yyerror("missing pseudowire id");
539				YYERROR;
540			}
541			if (pw->lsr_id.s_addr == INADDR_ANY) {
542				yyerror("missing pseudowire neighbor-id");
543				YYERROR;
544			}
545			LIST_FOREACH(l, &conf->l2vpn_list, entry) {
546				LIST_FOREACH(p, &l->pw_list, entry) {
547					if (pw != p &&
548					    pw->pwid == p->pwid &&
549					    pw->af == p->af &&
550					    pw->lsr_id.s_addr ==
551					    p->lsr_id.s_addr) {
552						yyerror("pseudowire already "
553						    "configured");
554						YYERROR;
555					}
556				}
557			}
558
559			/*
560			 * If the neighbor address is not specified, use the
561			 * neighbor id.
562			 */
563			if (pw->af == AF_UNSPEC) {
564				pw->af = AF_INET;
565				pw->addr.v4 = pw->lsr_id;
566			}
567
568			pw->flags = defs->pwflags;
569			pw = NULL;
570			defs = &globaldefs;
571		}
572		;
573
574pw_block	: '{' optnl pwopts_l '}'
575		| '{' optnl '}'
576		| /* nothing */
577		;
578
579pwopts_l	: pwopts_l pwopts nl
580		| pwopts optnl
581		;
582
583l2vpnopts	: PWTYPE pw_type {
584			l2vpn->pw_type = $2;
585		}
586		| MTU NUMBER {
587			if ($2 < MIN_L2VPN_MTU ||
588			    $2 > MAX_L2VPN_MTU) {
589				yyerror("l2vpn mtu out of range (%d-%d)",
590				    MIN_L2VPN_MTU, MAX_L2VPN_MTU);
591				YYERROR;
592			}
593			l2vpn->mtu = $2;
594		}
595		| pw_defaults
596		| BRIDGE STRING {
597			struct l2vpn	 *l;
598			struct kif	 *kif;
599
600			if ((kif = kif_findname($2)) == NULL) {
601				yyerror("unknown interface %s", $2);
602				free($2);
603				YYERROR;
604			}
605			free($2);
606
607			if (l2vpn->br_ifindex != 0) {
608				yyerror("bridge interface cannot be "
609				    "redefined on l2vpn %s", l2vpn->name);
610				YYERROR;
611			}
612
613			if (kif->if_type != IFT_BRIDGE) {
614				yyerror("unsupported interface type on "
615				    "interface %s", kif->ifname);
616				YYERROR;
617			}
618
619			LIST_FOREACH(l, &conf->l2vpn_list, entry) {
620				if (l->br_ifindex == kif->ifindex) {
621					yyerror("bridge %s is already being "
622					    "used by l2vpn %s", kif->ifname,
623					    l->name);
624					YYERROR;
625				}
626			}
627
628			l2vpn->br_ifindex = kif->ifindex;
629			strlcpy(l2vpn->br_ifname, kif->ifname,
630			    sizeof(l2vpn->br_ifname));
631		}
632		| INTERFACE STRING {
633			struct kif	*kif;
634			struct l2vpn_if	*lif;
635
636			if ((kif = kif_findname($2)) == NULL) {
637				yyerror("unknown interface %s", $2);
638				free($2);
639				YYERROR;
640			}
641			free($2);
642
643			lif = conf_get_l2vpn_if(l2vpn, kif);
644			if (lif == NULL)
645				YYERROR;
646		}
647		| pseudowire
648		;
649
650optnl		: '\n' optnl
651		|
652		;
653
654nl		: '\n' optnl		/* one newline or more */
655		;
656
657interface	: INTERFACE STRING	{
658			struct kif	*kif;
659
660			if ((kif = kif_findname($2)) == NULL) {
661				yyerror("unknown interface %s", $2);
662				free($2);
663				YYERROR;
664			}
665			free($2);
666
667			iface = conf_get_if(kif);
668			if (iface == NULL)
669				YYERROR;
670
671			ia = iface_af_get(iface, af);
672			if (ia->enabled) {
673				yyerror("interface %s already configured for "
674				    "address-family %s", kif->ifname,
675				    af_name(af));
676				YYERROR;
677			}
678			ia->enabled = 1;
679
680			ifacedefs = *defs;
681			defs = &ifacedefs;
682		} interface_block {
683			ia->hello_holdtime = defs->lhello_holdtime;
684			ia->hello_interval = defs->lhello_interval;
685			iface = NULL;
686			defs = &afdefs;
687		}
688		;
689
690interface_block	: '{' optnl interfaceopts_l '}'
691		| '{' optnl '}'
692		| /* nothing */
693		;
694
695interfaceopts_l	: interfaceopts_l iface_defaults nl
696		| iface_defaults optnl
697		;
698
699tneighbor	: TNEIGHBOR STRING	{
700			union ldpd_addr	 addr;
701
702			if (get_address($2, &addr) == -1) {
703				yyerror("error parsing targeted-neighbor "
704				    "address");
705				free($2);
706				YYERROR;
707			}
708			free($2);
709			if (bad_addr(af, &addr)) {
710				yyerror("invalid targeted-neighbor address");
711				YYERROR;
712			}
713			if (af == AF_INET6 &&
714			   IN6_IS_SCOPE_EMBED(&addr.v6)) {
715				yyerror("targeted-neighbor address can not be "
716				    "link-local");
717				YYERROR;
718			}
719
720			tnbr = conf_get_tnbr(&addr);
721			if (tnbr == NULL)
722				YYERROR;
723
724			tnbrdefs = *defs;
725			defs = &tnbrdefs;
726		} tneighbor_block {
727			tnbr->hello_holdtime = defs->thello_holdtime;
728			tnbr->hello_interval = defs->thello_interval;
729			tnbr = NULL;
730			defs = &afdefs;
731		}
732		;
733
734tneighbor_block	: '{' optnl tneighboropts_l '}'
735		| '{' optnl '}'
736		| /* nothing */
737		;
738
739tneighboropts_l	: tneighboropts_l tnbr_defaults nl
740		| tnbr_defaults optnl
741		;
742
743neighbor	: NEIGHBOR STRING	{
744			struct in_addr	 addr;
745
746			if (inet_aton($2, &addr) == 0) {
747				yyerror("error parsing neighbor-id");
748				free($2);
749				YYERROR;
750			}
751			free($2);
752			if (bad_addr_v4(addr)) {
753				yyerror("invalid neighbor-id");
754				YYERROR;
755			}
756
757			nbrp = conf_get_nbrp(addr);
758			if (nbrp == NULL)
759				YYERROR;
760		} neighbor_block {
761			nbrp = NULL;
762		}
763		;
764
765neighbor_block	: '{' optnl neighboropts_l '}'
766		| '{' optnl '}'
767		| /* nothing */
768		;
769
770neighboropts_l	: neighboropts_l nbr_opts nl
771		| nbr_opts optnl
772		;
773
774l2vpn		: L2VPN STRING TYPE l2vpn_type {
775			l2vpn = conf_get_l2vpn($2);
776			if (l2vpn == NULL)
777				YYERROR;
778			l2vpn->type = $4;
779		} l2vpn_block {
780			l2vpn = NULL;
781		}
782		;
783
784l2vpn_block	: '{' optnl l2vpnopts_l '}'
785		| '{' optnl '}'
786		| /* nothing */
787		;
788
789l2vpnopts_l	: l2vpnopts_l l2vpnopts nl
790		| l2vpnopts optnl
791		;
792
793%%
794
795struct keywords {
796	const char	*k_name;
797	int		 k_val;
798};
799
800static int
801yyerror(const char *fmt, ...)
802{
803	va_list		 ap;
804	char		*msg;
805
806	file->errors++;
807	va_start(ap, fmt);
808	if (vasprintf(&msg, fmt, ap) == -1)
809		fatalx("yyerror vasprintf");
810	va_end(ap);
811	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
812	free(msg);
813	return (0);
814}
815
816static int
817kw_cmp(const void *k, const void *e)
818{
819	return (strcmp(k, ((const struct keywords *)e)->k_name));
820}
821
822static int
823lookup(char *s)
824{
825	/* this has to be sorted always */
826	static const struct keywords keywords[] = {
827		{"address-family",		AF},
828		{"bridge",			BRIDGE},
829		{"control-word",		CONTROLWORD},
830		{"ds-cisco-interop",		DSCISCOINTEROP},
831		{"ethernet",			ETHERNET},
832		{"ethernet-tagged",		ETHERNETTAGGED},
833		{"explicit-null",		EXPNULL},
834		{"fib-update",			FIBUPDATE},
835		{"gtsm-enable",			GTSMENABLE},
836		{"gtsm-hops",			GTSMHOPS},
837		{"include",			INCLUDE},
838		{"interface",			INTERFACE},
839		{"ipv4",			IPV4},
840		{"ipv6",			IPV6},
841		{"keepalive",			KEEPALIVE},
842		{"l2vpn",			L2VPN},
843		{"link-hello-holdtime",		LHELLOHOLDTIME},
844		{"link-hello-interval",		LHELLOINTERVAL},
845		{"mtu",				MTU},
846		{"neighbor",			NEIGHBOR},
847		{"neighbor-addr",		NEIGHBORADDR},
848		{"neighbor-id",			NEIGHBORID},
849		{"no",				NO},
850		{"password",			PASSWORD},
851		{"pseudowire",			PSEUDOWIRE},
852		{"pw-id",			PWID},
853		{"pw-type",			PWTYPE},
854		{"rdomain",			RDOMAIN},
855		{"router-id",			ROUTERID},
856		{"status-tlv",			STATUSTLV},
857		{"targeted-hello-accept",	THELLOACCEPT},
858		{"targeted-hello-holdtime",	THELLOHOLDTIME},
859		{"targeted-hello-interval",	THELLOINTERVAL},
860		{"targeted-neighbor",		TNEIGHBOR},
861		{"transport-address",		TRANSADDRESS},
862		{"transport-preference",	TRANSPREFERENCE},
863		{"type",			TYPE},
864		{"vpls",			VPLS},
865		{"yes",				YES}
866	};
867	const struct keywords	*p;
868
869	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
870	    sizeof(keywords[0]), kw_cmp);
871
872	if (p)
873		return (p->k_val);
874	else
875		return (STRING);
876}
877
878#define START_EXPAND	1
879#define DONE_EXPAND	2
880
881static int	expanding;
882
883int
884igetc(void)
885{
886	int	c;
887
888	while (1) {
889		if (file->ungetpos > 0)
890			c = file->ungetbuf[--file->ungetpos];
891		else
892			c = getc(file->stream);
893
894		if (c == START_EXPAND)
895			expanding = 1;
896		else if (c == DONE_EXPAND)
897			expanding = 0;
898		else
899			break;
900	}
901	return (c);
902}
903
904static int
905lgetc(int quotec)
906{
907	int		c, next;
908
909	if (quotec) {
910		if ((c = igetc()) == EOF) {
911			yyerror("reached end of file while parsing "
912			    "quoted string");
913			if (file == topfile || popfile() == EOF)
914				return (EOF);
915			return (quotec);
916		}
917		return (c);
918	}
919
920	while ((c = igetc()) == '\\') {
921		next = igetc();
922		if (next != '\n') {
923			c = next;
924			break;
925		}
926		yylval.lineno = file->lineno;
927		file->lineno++;
928	}
929
930	if (c == EOF) {
931		/*
932		 * Fake EOL when hit EOF for the first time. This gets line
933		 * count right if last line in included file is syntactically
934		 * invalid and has no newline.
935		 */
936		if (file->eof_reached == 0) {
937			file->eof_reached = 1;
938			return ('\n');
939		}
940		while (c == EOF) {
941			if (file == topfile || popfile() == EOF)
942				return (EOF);
943			c = igetc();
944		}
945	}
946	return (c);
947}
948
949void
950lungetc(int c)
951{
952	if (c == EOF)
953		return;
954
955	if (file->ungetpos >= file->ungetsize) {
956		void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
957		if (p == NULL)
958			err(1, "%s", __func__);
959		file->ungetbuf = p;
960		file->ungetsize *= 2;
961	}
962	file->ungetbuf[file->ungetpos++] = c;
963}
964
965static int
966findeol(void)
967{
968	int	c;
969
970	/* skip to either EOF or the first real EOL */
971	while (1) {
972		c = lgetc(0);
973		if (c == '\n') {
974			file->lineno++;
975			break;
976		}
977		if (c == EOF)
978			break;
979	}
980	return (ERROR);
981}
982
983static int
984yylex(void)
985{
986	unsigned char	 buf[8096];
987	unsigned char	*p, *val;
988	int		 quotec, next, c;
989	int		 token;
990
991 top:
992	p = buf;
993	while ((c = lgetc(0)) == ' ' || c == '\t')
994		; /* nothing */
995
996	yylval.lineno = file->lineno;
997	if (c == '#')
998		while ((c = lgetc(0)) != '\n' && c != EOF)
999			; /* nothing */
1000	if (c == '$' && !expanding) {
1001		while (1) {
1002			if ((c = lgetc(0)) == EOF)
1003				return (0);
1004
1005			if (p + 1 >= buf + sizeof(buf) - 1) {
1006				yyerror("string too long");
1007				return (findeol());
1008			}
1009			if (isalnum(c) || c == '_') {
1010				*p++ = c;
1011				continue;
1012			}
1013			*p = '\0';
1014			lungetc(c);
1015			break;
1016		}
1017		val = symget(buf);
1018		if (val == NULL) {
1019			yyerror("macro '%s' not defined", buf);
1020			return (findeol());
1021		}
1022		p = val + strlen(val) - 1;
1023		lungetc(DONE_EXPAND);
1024		while (p >= val) {
1025			lungetc(*p);
1026			p--;
1027		}
1028		lungetc(START_EXPAND);
1029		goto top;
1030	}
1031
1032	switch (c) {
1033	case '\'':
1034	case '"':
1035		quotec = c;
1036		while (1) {
1037			if ((c = lgetc(quotec)) == EOF)
1038				return (0);
1039			if (c == '\n') {
1040				file->lineno++;
1041				continue;
1042			} else if (c == '\\') {
1043				if ((next = lgetc(quotec)) == EOF)
1044					return (0);
1045				if (next == quotec || next == ' ' ||
1046				    next == '\t')
1047					c = next;
1048				else if (next == '\n') {
1049					file->lineno++;
1050					continue;
1051				} else
1052					lungetc(next);
1053			} else if (c == quotec) {
1054				*p = '\0';
1055				break;
1056			} else if (c == '\0') {
1057				yyerror("syntax error");
1058				return (findeol());
1059			}
1060			if (p + 1 >= buf + sizeof(buf) - 1) {
1061				yyerror("string too long");
1062				return (findeol());
1063			}
1064			*p++ = c;
1065		}
1066		yylval.v.string = strdup(buf);
1067		if (yylval.v.string == NULL)
1068			err(1, "%s", __func__);
1069		return (STRING);
1070	}
1071
1072#define allowed_to_end_number(x) \
1073	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
1074
1075	if (c == '-' || isdigit(c)) {
1076		do {
1077			*p++ = c;
1078			if ((unsigned)(p-buf) >= sizeof(buf)) {
1079				yyerror("string too long");
1080				return (findeol());
1081			}
1082		} while ((c = lgetc(0)) != EOF && isdigit(c));
1083		lungetc(c);
1084		if (p == buf + 1 && buf[0] == '-')
1085			goto nodigits;
1086		if (c == EOF || allowed_to_end_number(c)) {
1087			const char *errstr = NULL;
1088
1089			*p = '\0';
1090			yylval.v.number = strtonum(buf, LLONG_MIN,
1091			    LLONG_MAX, &errstr);
1092			if (errstr) {
1093				yyerror("\"%s\" invalid number: %s",
1094				    buf, errstr);
1095				return (findeol());
1096			}
1097			return (NUMBER);
1098		} else {
1099 nodigits:
1100			while (p > buf + 1)
1101				lungetc(*--p);
1102			c = *--p;
1103			if (c == '-')
1104				return (c);
1105		}
1106	}
1107
1108#define allowed_in_string(x) \
1109	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
1110	x != '{' && x != '}' && \
1111	x != '!' && x != '=' && x != '#' && \
1112	x != ','))
1113
1114	if (isalnum(c) || c == ':' || c == '_') {
1115		do {
1116			*p++ = c;
1117			if ((unsigned)(p-buf) >= sizeof(buf)) {
1118				yyerror("string too long");
1119				return (findeol());
1120			}
1121		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
1122		lungetc(c);
1123		*p = '\0';
1124		if ((token = lookup(buf)) == STRING)
1125			if ((yylval.v.string = strdup(buf)) == NULL)
1126				err(1, "%s", __func__);
1127		return (token);
1128	}
1129	if (c == '\n') {
1130		yylval.lineno = file->lineno;
1131		file->lineno++;
1132	}
1133	if (c == EOF)
1134		return (0);
1135	return (c);
1136}
1137
1138static int
1139check_file_secrecy(int fd, const char *fname)
1140{
1141	struct stat	st;
1142
1143	if (fstat(fd, &st)) {
1144		log_warn("cannot stat %s", fname);
1145		return (-1);
1146	}
1147	if (st.st_uid != 0 && st.st_uid != getuid()) {
1148		log_warnx("%s: owner not root or current user", fname);
1149		return (-1);
1150	}
1151	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
1152		log_warnx("%s: group writable or world read/writable", fname);
1153		return (-1);
1154	}
1155	return (0);
1156}
1157
1158static struct file *
1159pushfile(const char *name, int secret)
1160{
1161	struct file	*nfile;
1162
1163	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
1164		log_warn("%s", __func__);
1165		return (NULL);
1166	}
1167	if ((nfile->name = strdup(name)) == NULL) {
1168		log_warn("%s", __func__);
1169		free(nfile);
1170		return (NULL);
1171	}
1172	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
1173		log_warn("%s: %s", __func__, nfile->name);
1174		free(nfile->name);
1175		free(nfile);
1176		return (NULL);
1177	} else if (secret &&
1178	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
1179		fclose(nfile->stream);
1180		free(nfile->name);
1181		free(nfile);
1182		return (NULL);
1183	}
1184	nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
1185	nfile->ungetsize = 16;
1186	nfile->ungetbuf = malloc(nfile->ungetsize);
1187	if (nfile->ungetbuf == NULL) {
1188		log_warn("%s", __func__);
1189		fclose(nfile->stream);
1190		free(nfile->name);
1191		free(nfile);
1192		return (NULL);
1193	}
1194	TAILQ_INSERT_TAIL(&files, nfile, entry);
1195	return (nfile);
1196}
1197
1198static int
1199popfile(void)
1200{
1201	struct file	*prev;
1202
1203	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
1204		prev->errors += file->errors;
1205
1206	TAILQ_REMOVE(&files, file, entry);
1207	fclose(file->stream);
1208	free(file->name);
1209	free(file->ungetbuf);
1210	free(file);
1211	file = prev;
1212	return (file ? 0 : EOF);
1213}
1214
1215struct ldpd_conf *
1216parse_config(char *filename)
1217{
1218	struct sym	*sym, *next;
1219
1220	conf = config_new_empty();
1221	conf->rdomain = 0;
1222	conf->trans_pref = DUAL_STACK_LDPOV6;
1223
1224	defs = &globaldefs;
1225	defs->keepalive = DEFAULT_KEEPALIVE;
1226	defs->lhello_holdtime = LINK_DFLT_HOLDTIME;
1227	defs->lhello_interval = DEFAULT_HELLO_INTERVAL;
1228	defs->thello_holdtime = TARGETED_DFLT_HOLDTIME;
1229	defs->thello_interval = DEFAULT_HELLO_INTERVAL;
1230	defs->pwflags = F_PW_STATUSTLV_CONF|F_PW_CWORD_CONF;
1231
1232	if ((file = pushfile(filename,
1233	    !(global.cmd_opts & LDPD_OPT_NOACTION))) == NULL) {
1234		free(conf);
1235		return (NULL);
1236	}
1237	topfile = file;
1238
1239	yyparse();
1240	errors = file->errors;
1241	popfile();
1242
1243	/* Free macros and check which have not been used. */
1244	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
1245		if ((global.cmd_opts & LDPD_OPT_VERBOSE2) && !sym->used)
1246			fprintf(stderr, "warning: macro '%s' not "
1247			    "used\n", sym->nam);
1248		if (!sym->persist) {
1249			free(sym->nam);
1250			free(sym->val);
1251			TAILQ_REMOVE(&symhead, sym, entry);
1252			free(sym);
1253		}
1254	}
1255
1256	/* check that all interfaces belong to the configured rdomain */
1257	errors += conf_check_rdomain(conf->rdomain);
1258
1259	/* free global config defaults */
1260	if (errors) {
1261		clear_config(conf);
1262		return (NULL);
1263	}
1264
1265	if (conf->rtr_id.s_addr == INADDR_ANY)
1266		conf->rtr_id.s_addr = get_rtr_id();
1267
1268	/* if the ipv4 transport-address is not set, use the router-id */
1269	if ((conf->ipv4.flags & F_LDPD_AF_ENABLED) &&
1270	    conf->ipv4.trans_addr.v4.s_addr == INADDR_ANY)
1271		conf->ipv4.trans_addr.v4 = conf->rtr_id;
1272
1273	return (conf);
1274}
1275
1276static int
1277symset(const char *nam, const char *val, int persist)
1278{
1279	struct sym	*sym;
1280
1281	TAILQ_FOREACH(sym, &symhead, entry) {
1282		if (strcmp(nam, sym->nam) == 0)
1283			break;
1284	}
1285
1286	if (sym != NULL) {
1287		if (sym->persist == 1)
1288			return (0);
1289		else {
1290			free(sym->nam);
1291			free(sym->val);
1292			TAILQ_REMOVE(&symhead, sym, entry);
1293			free(sym);
1294		}
1295	}
1296	if ((sym = calloc(1, sizeof(*sym))) == NULL)
1297		return (-1);
1298
1299	sym->nam = strdup(nam);
1300	if (sym->nam == NULL) {
1301		free(sym);
1302		return (-1);
1303	}
1304	sym->val = strdup(val);
1305	if (sym->val == NULL) {
1306		free(sym->nam);
1307		free(sym);
1308		return (-1);
1309	}
1310	sym->used = 0;
1311	sym->persist = persist;
1312	TAILQ_INSERT_TAIL(&symhead, sym, entry);
1313	return (0);
1314}
1315
1316int
1317cmdline_symset(char *s)
1318{
1319	char	*sym, *val;
1320	int	ret;
1321
1322	if ((val = strrchr(s, '=')) == NULL)
1323		return (-1);
1324	sym = strndup(s, val - s);
1325	if (sym == NULL)
1326		errx(1, "%s: strndup", __func__);
1327	ret = symset(sym, val + 1, 1);
1328	free(sym);
1329
1330	return (ret);
1331}
1332
1333static char *
1334symget(const char *nam)
1335{
1336	struct sym	*sym;
1337
1338	TAILQ_FOREACH(sym, &symhead, entry) {
1339		if (strcmp(nam, sym->nam) == 0) {
1340			sym->used = 1;
1341			return (sym->val);
1342		}
1343	}
1344	return (NULL);
1345}
1346
1347static struct iface *
1348conf_get_if(struct kif *kif)
1349{
1350	struct iface	*i;
1351	struct l2vpn	*l;
1352
1353	if (kif->if_type == IFT_LOOP ||
1354	    kif->if_type == IFT_CARP ||
1355	    kif->if_type == IFT_BRIDGE ||
1356	    kif->if_type == IFT_MPLSTUNNEL) {
1357		yyerror("unsupported interface type on interface %s",
1358		    kif->ifname);
1359		return (NULL);
1360	}
1361
1362	LIST_FOREACH(l, &conf->l2vpn_list, entry)
1363		if (l2vpn_if_find(l, kif->ifindex)) {
1364			yyerror("interface %s already configured under "
1365			    "l2vpn %s", kif->ifname, l->name);
1366			return (NULL);
1367		}
1368
1369	LIST_FOREACH(i, &conf->iface_list, entry)
1370		if (i->ifindex == kif->ifindex)
1371			return (i);
1372
1373	i = if_new(kif);
1374	LIST_INSERT_HEAD(&conf->iface_list, i, entry);
1375	return (i);
1376}
1377
1378static struct tnbr *
1379conf_get_tnbr(union ldpd_addr *addr)
1380{
1381	struct tnbr	*t;
1382
1383	t = tnbr_find(conf, af, addr);
1384	if (t) {
1385		yyerror("targeted neighbor %s already configured",
1386		    log_addr(af, addr));
1387		return (NULL);
1388	}
1389
1390	t = tnbr_new(conf, af, addr);
1391	t->flags |= F_TNBR_CONFIGURED;
1392	LIST_INSERT_HEAD(&conf->tnbr_list, t, entry);
1393	return (t);
1394}
1395
1396static struct nbr_params *
1397conf_get_nbrp(struct in_addr lsr_id)
1398{
1399	struct nbr_params	*n;
1400
1401	LIST_FOREACH(n, &conf->nbrp_list, entry) {
1402		if (n->lsr_id.s_addr == lsr_id.s_addr) {
1403			yyerror("neighbor %s already configured",
1404			    inet_ntoa(lsr_id));
1405			return (NULL);
1406		}
1407	}
1408
1409	n = nbr_params_new(lsr_id);
1410	LIST_INSERT_HEAD(&conf->nbrp_list, n, entry);
1411	return (n);
1412}
1413
1414static struct l2vpn *
1415conf_get_l2vpn(char *name)
1416{
1417	struct l2vpn	 *l;
1418
1419	if (l2vpn_find(conf, name)) {
1420		yyerror("l2vpn %s already configured", name);
1421		return (NULL);
1422	}
1423
1424	l = l2vpn_new(name);
1425	LIST_INSERT_HEAD(&conf->l2vpn_list, l, entry);
1426	return (l);
1427}
1428
1429static struct l2vpn_if *
1430conf_get_l2vpn_if(struct l2vpn *l, struct kif *kif)
1431{
1432	struct iface	*i;
1433	struct l2vpn	*ltmp;
1434	struct l2vpn_if	*f;
1435
1436	if (kif->if_type == IFT_LOOP ||
1437	    kif->if_type == IFT_CARP ||
1438	    kif->if_type == IFT_BRIDGE ||
1439	    kif->if_type == IFT_MPLSTUNNEL) {
1440		yyerror("unsupported interface type on interface %s",
1441		    kif->ifname);
1442		return (NULL);
1443	}
1444
1445	LIST_FOREACH(ltmp, &conf->l2vpn_list, entry)
1446		if (l2vpn_if_find(ltmp, kif->ifindex)) {
1447			yyerror("interface %s already configured under "
1448			    "l2vpn %s", kif->ifname, ltmp->name);
1449			return (NULL);
1450		}
1451
1452	LIST_FOREACH(i, &conf->iface_list, entry) {
1453		if (i->ifindex == kif->ifindex) {
1454			yyerror("interface %s already configured",
1455			    kif->ifname);
1456			return (NULL);
1457		}
1458	}
1459
1460	f = l2vpn_if_new(l, kif);
1461	LIST_INSERT_HEAD(&l2vpn->if_list, f, entry);
1462	return (f);
1463}
1464
1465static struct l2vpn_pw *
1466conf_get_l2vpn_pw(struct l2vpn *l, struct kif *kif)
1467{
1468	struct l2vpn	*ltmp;
1469	struct l2vpn_pw	*p;
1470
1471	LIST_FOREACH(ltmp, &conf->l2vpn_list, entry) {
1472		if (l2vpn_pw_find(ltmp, kif->ifindex)) {
1473			yyerror("pseudowire %s is already being "
1474			    "used by l2vpn %s", kif->ifname, ltmp->name);
1475			return (NULL);
1476		}
1477	}
1478
1479	p = l2vpn_pw_new(l, kif);
1480	LIST_INSERT_HEAD(&l2vpn->pw_list, p, entry);
1481	return (p);
1482}
1483
1484int
1485conf_check_rdomain(unsigned int rdomain)
1486{
1487	struct iface	*i;
1488	int		 errs = 0;
1489
1490	LIST_FOREACH(i, &conf->iface_list, entry) {
1491		if (i->rdomain != rdomain) {
1492			logit(LOG_CRIT, "interface %s not in rdomain %u",
1493			    i->name, rdomain);
1494			errs++;
1495		}
1496	}
1497
1498	return (errs);
1499}
1500
1501static void
1502clear_config(struct ldpd_conf *xconf)
1503{
1504	struct iface		*i;
1505	struct tnbr		*t;
1506	struct nbr_params	*n;
1507	struct l2vpn		*l;
1508	struct l2vpn_if		*f;
1509	struct l2vpn_pw		*p;
1510
1511	while ((i = LIST_FIRST(&xconf->iface_list)) != NULL) {
1512		LIST_REMOVE(i, entry);
1513		free(i);
1514	}
1515
1516	while ((t = LIST_FIRST(&xconf->tnbr_list)) != NULL) {
1517		LIST_REMOVE(t, entry);
1518		free(t);
1519	}
1520
1521	while ((n = LIST_FIRST(&xconf->nbrp_list)) != NULL) {
1522		LIST_REMOVE(n, entry);
1523		free(n);
1524	}
1525
1526	while ((l = LIST_FIRST(&xconf->l2vpn_list)) != NULL) {
1527		while ((f = LIST_FIRST(&l->if_list)) != NULL) {
1528			LIST_REMOVE(f, entry);
1529			free(f);
1530		}
1531		while ((p = LIST_FIRST(&l->pw_list)) != NULL) {
1532			LIST_REMOVE(p, entry);
1533			free(p);
1534		}
1535		LIST_REMOVE(l, entry);
1536		free(l);
1537	}
1538
1539	free(xconf);
1540}
1541
1542static uint32_t
1543get_rtr_id(void)
1544{
1545	struct ifaddrs		*ifap, *ifa;
1546	uint32_t		 ip = 0, cur, localnet;
1547
1548	localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
1549
1550	if (getifaddrs(&ifap) == -1) {
1551		log_warn("getifaddrs");
1552		return (0);
1553	}
1554
1555	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1556		if (strncmp(ifa->ifa_name, "carp", 4) == 0)
1557			continue;
1558		if (ifa->ifa_addr->sa_family != AF_INET)
1559			continue;
1560		cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
1561		if ((cur & localnet) == localnet)	/* skip 127/8 */
1562			continue;
1563		if (ntohl(cur) < ntohl(ip) || ip == 0)
1564			ip = cur;
1565	}
1566	freeifaddrs(ifap);
1567
1568	return (ip);
1569}
1570
1571static int
1572get_address(const char *s, union ldpd_addr *addr)
1573{
1574	switch (af) {
1575	case AF_INET:
1576		if (inet_pton(AF_INET, s, &addr->v4) != 1)
1577			return (-1);
1578		break;
1579	case AF_INET6:
1580		if (inet_pton(AF_INET6, s, &addr->v6) != 1)
1581			return (-1);
1582		break;
1583	default:
1584		return (-1);
1585	}
1586
1587	return (0);
1588}
1589
1590static int
1591get_af_address(const char *s, int *family, union ldpd_addr *addr)
1592{
1593	if (inet_pton(AF_INET, s, &addr->v4) == 1) {
1594		*family = AF_INET;
1595		return (0);
1596	}
1597
1598	if (inet_pton(AF_INET6, s, &addr->v6) == 1) {
1599		*family = AF_INET6;
1600		return (0);
1601	}
1602
1603	return (-1);
1604}
1605