xref: /openbsd/usr.sbin/rad/parse.y (revision 30ca3407)
1*30ca3407Sflorian /*	$OpenBSD: parse.y,v 1.23 2024/05/17 06:50:14 florian Exp $	*/
253293e44Sflorian 
353293e44Sflorian /*
453293e44Sflorian  * Copyright (c) 2018 Florian Obser <florian@openbsd.org>
553293e44Sflorian  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
653293e44Sflorian  * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
753293e44Sflorian  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
853293e44Sflorian  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
953293e44Sflorian  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
1053293e44Sflorian  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
1153293e44Sflorian  *
1253293e44Sflorian  * Permission to use, copy, modify, and distribute this software for any
1353293e44Sflorian  * purpose with or without fee is hereby granted, provided that the above
1453293e44Sflorian  * copyright notice and this permission notice appear in all copies.
1553293e44Sflorian  *
1653293e44Sflorian  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1753293e44Sflorian  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1853293e44Sflorian  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1953293e44Sflorian  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2053293e44Sflorian  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2153293e44Sflorian  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2253293e44Sflorian  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2353293e44Sflorian  */
2453293e44Sflorian 
2553293e44Sflorian %{
2653293e44Sflorian #include <sys/types.h>
2753293e44Sflorian #include <sys/queue.h>
2853293e44Sflorian #include <sys/socket.h>
2953293e44Sflorian #include <sys/stat.h>
3053293e44Sflorian 
3153293e44Sflorian #include <netinet/in.h>
32639a58baSflorian #include <netinet/icmp6.h>
3353293e44Sflorian #include <net/if.h>
3453293e44Sflorian 
3553293e44Sflorian #include <arpa/inet.h>
3653293e44Sflorian 
3753293e44Sflorian #include <ctype.h>
3853293e44Sflorian #include <err.h>
3953293e44Sflorian #include <errno.h>
4053293e44Sflorian #include <event.h>
4153293e44Sflorian #include <imsg.h>
4253293e44Sflorian #include <limits.h>
4353293e44Sflorian #include <stdarg.h>
4453293e44Sflorian #include <stdio.h>
4553293e44Sflorian #include <string.h>
4653293e44Sflorian #include <syslog.h>
4753293e44Sflorian #include <unistd.h>
4853293e44Sflorian 
4953293e44Sflorian #include "log.h"
5053293e44Sflorian #include "rad.h"
5153293e44Sflorian #include "frontend.h"
5253293e44Sflorian 
5353293e44Sflorian TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
5453293e44Sflorian static struct file {
5553293e44Sflorian 	TAILQ_ENTRY(file)	 entry;
5653293e44Sflorian 	FILE			*stream;
5753293e44Sflorian 	char			*name;
5853293e44Sflorian 	size_t	 		 ungetpos;
5953293e44Sflorian 	size_t			 ungetsize;
6053293e44Sflorian 	u_char			*ungetbuf;
6153293e44Sflorian 	int			 eof_reached;
6253293e44Sflorian 	int			 lineno;
6353293e44Sflorian 	int			 errors;
6453293e44Sflorian } *file, *topfile;
6553293e44Sflorian struct file	*pushfile(const char *, int);
6653293e44Sflorian int		 popfile(void);
6753293e44Sflorian int		 check_file_secrecy(int, const char *);
6853293e44Sflorian int		 yyparse(void);
6953293e44Sflorian int		 yylex(void);
7053293e44Sflorian int		 yyerror(const char *, ...)
7153293e44Sflorian     __attribute__((__format__ (printf, 1, 2)))
7253293e44Sflorian     __attribute__((__nonnull__ (1)));
7353293e44Sflorian int		 kw_cmp(const void *, const void *);
7453293e44Sflorian int		 lookup(char *);
7553293e44Sflorian int		 igetc(void);
7653293e44Sflorian int		 lgetc(int);
7753293e44Sflorian void		 lungetc(int);
7853293e44Sflorian int		 findeol(void);
7953293e44Sflorian 
8053293e44Sflorian TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
8153293e44Sflorian struct sym {
8253293e44Sflorian 	TAILQ_ENTRY(sym)	 entry;
8353293e44Sflorian 	int			 used;
8453293e44Sflorian 	int			 persist;
8553293e44Sflorian 	char			*nam;
8653293e44Sflorian 	char			*val;
8753293e44Sflorian };
8853293e44Sflorian 
8953293e44Sflorian int	 symset(const char *, const char *, int);
9053293e44Sflorian char	*symget(const char *);
9153293e44Sflorian 
9253293e44Sflorian void	 clear_config(struct rad_conf *xconf);
9353293e44Sflorian 
9453293e44Sflorian static struct rad_conf		*conf;
9553293e44Sflorian static struct ra_options_conf	*ra_options;
9653293e44Sflorian static int			 errors;
9753293e44Sflorian 
9853293e44Sflorian static struct ra_iface_conf	*ra_iface_conf;
9953293e44Sflorian static struct ra_prefix_conf	*ra_prefix_conf;
1005207bb19Sflorian static struct ra_pref64_conf	*ra_pref64_conf;
10153293e44Sflorian 
10253293e44Sflorian struct ra_prefix_conf	*conf_get_ra_prefix(struct in6_addr*, int);
1035207bb19Sflorian struct ra_pref64_conf	*conf_get_ra_pref64(struct in6_addr*, int);
10453293e44Sflorian struct ra_iface_conf	*conf_get_ra_iface(char *);
1058815eebdSflorian void			 copy_dns_options(const struct ra_options_conf *,
1068815eebdSflorian 			    struct ra_options_conf *);
1075207bb19Sflorian void			 copy_pref64_options(const struct ra_options_conf *,
1085207bb19Sflorian 			    struct ra_options_conf *);
10953293e44Sflorian 
11053293e44Sflorian typedef struct {
11153293e44Sflorian 	union {
11253293e44Sflorian 		int64_t		 number;
11353293e44Sflorian 		char		*string;
11453293e44Sflorian 	} v;
11553293e44Sflorian 	int lineno;
11653293e44Sflorian } YYSTYPE;
11753293e44Sflorian 
11853293e44Sflorian %}
11953293e44Sflorian 
12053293e44Sflorian %token	RA_IFACE YES NO INCLUDE ERROR
12153293e44Sflorian %token	DEFAULT ROUTER HOP LIMIT MANAGED ADDRESS
12253293e44Sflorian %token	CONFIGURATION OTHER LIFETIME REACHABLE TIME RETRANS TIMER
123639a58baSflorian %token	AUTO PREFIX VALID PREFERENCE PREFERRED LIFETIME ONLINK AUTONOMOUS
124639a58baSflorian %token	ADDRESS_CONFIGURATION DNS NAMESERVER SEARCH MTU NAT64 HIGH MEDIUM LOW
125*30ca3407Sflorian %token	SOURCE LINK_LAYER
12653293e44Sflorian 
12753293e44Sflorian %token	<v.string>	STRING
12853293e44Sflorian %token	<v.number>	NUMBER
12953293e44Sflorian %type	<v.number>	yesno
13053293e44Sflorian %type	<v.string>	string
13153293e44Sflorian 
13253293e44Sflorian %%
13353293e44Sflorian 
13453293e44Sflorian grammar		: /* empty */
13553293e44Sflorian 		| grammar include '\n'
13653293e44Sflorian 		| grammar '\n'
13753293e44Sflorian 		| grammar { ra_options = &conf->ra_options; } conf_main '\n'
13853293e44Sflorian 		| grammar varset '\n'
13953293e44Sflorian 		| grammar ra_iface '\n'
14053293e44Sflorian 		| grammar error '\n'		{ file->errors++; }
14153293e44Sflorian 		;
14253293e44Sflorian 
14353293e44Sflorian include		: INCLUDE STRING		{
14453293e44Sflorian 			struct file	*nfile;
14553293e44Sflorian 
1463a682461Sflorian 			if ((nfile = pushfile($2, 0)) == NULL) {
14753293e44Sflorian 				yyerror("failed to include file %s", $2);
14853293e44Sflorian 				free($2);
14953293e44Sflorian 				YYERROR;
15053293e44Sflorian 			}
15153293e44Sflorian 			free($2);
15253293e44Sflorian 
15353293e44Sflorian 			file = nfile;
15453293e44Sflorian 			lungetc('\n');
15553293e44Sflorian 		}
15653293e44Sflorian 		;
15753293e44Sflorian 
15853293e44Sflorian string		: string STRING	{
15953293e44Sflorian 			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
16053293e44Sflorian 				free($1);
16153293e44Sflorian 				free($2);
16253293e44Sflorian 				yyerror("string: asprintf");
16353293e44Sflorian 				YYERROR;
16453293e44Sflorian 			}
16553293e44Sflorian 			free($1);
16653293e44Sflorian 			free($2);
16753293e44Sflorian 		}
16853293e44Sflorian 		| STRING
16953293e44Sflorian 		;
17053293e44Sflorian 
17153293e44Sflorian yesno		: YES	{ $$ = 1; }
17253293e44Sflorian 		| NO	{ $$ = 0; }
17353293e44Sflorian 		;
17453293e44Sflorian 
17553293e44Sflorian varset		: STRING '=' string		{
17653293e44Sflorian 			char *s = $1;
17753293e44Sflorian 			if (cmd_opts & OPT_VERBOSE)
17853293e44Sflorian 				printf("%s = \"%s\"\n", $1, $3);
17953293e44Sflorian 			while (*s++) {
18053293e44Sflorian 				if (isspace((unsigned char)*s)) {
18153293e44Sflorian 					yyerror("macro name cannot contain "
18253293e44Sflorian 					    "whitespace");
183570434efSotto 					free($1);
184570434efSotto 					free($3);
18553293e44Sflorian 					YYERROR;
18653293e44Sflorian 				}
18753293e44Sflorian 			}
18853293e44Sflorian 			if (symset($1, $3, 0) == -1)
18953293e44Sflorian 				fatal("cannot store variable");
19053293e44Sflorian 			free($1);
19153293e44Sflorian 			free($3);
19253293e44Sflorian 		}
19353293e44Sflorian 		;
19453293e44Sflorian 
19553293e44Sflorian conf_main	: ra_opt_block {
19653293e44Sflorian 			ra_options = &conf->ra_options;
19753293e44Sflorian 		}
19853293e44Sflorian 		;
19953293e44Sflorian 
20053293e44Sflorian ra_opt_block	: DEFAULT ROUTER yesno {
20153293e44Sflorian 			ra_options->dfr = $3;
20253293e44Sflorian 		}
20353293e44Sflorian 		| HOP LIMIT NUMBER {
20453293e44Sflorian 			ra_options->cur_hl = $3;
20553293e44Sflorian 		}
20653293e44Sflorian 		| MANAGED ADDRESS CONFIGURATION yesno {
20753293e44Sflorian 			ra_options->m_flag = $4;
20853293e44Sflorian 		}
20953293e44Sflorian 		| OTHER CONFIGURATION yesno {
21053293e44Sflorian 			ra_options->o_flag = $3;
21153293e44Sflorian 		}
21253293e44Sflorian 		| ROUTER LIFETIME NUMBER {
21353293e44Sflorian 			ra_options->router_lifetime = $3;
21453293e44Sflorian 		}
215639a58baSflorian 		| ROUTER PREFERENCE HIGH {
216639a58baSflorian 			ra_options->rtpref = ND_RA_FLAG_RTPREF_HIGH;
217639a58baSflorian 		}
218639a58baSflorian 		| ROUTER PREFERENCE MEDIUM {
219639a58baSflorian 			ra_options->rtpref = ND_RA_FLAG_RTPREF_MEDIUM;
220639a58baSflorian 		}
221639a58baSflorian 		| ROUTER PREFERENCE LOW {
222639a58baSflorian 			ra_options->rtpref = ND_RA_FLAG_RTPREF_LOW;
223639a58baSflorian 		}
22453293e44Sflorian 		| REACHABLE TIME NUMBER {
22553293e44Sflorian 			ra_options->reachable_time = $3;
22653293e44Sflorian 		}
22753293e44Sflorian 		| RETRANS TIMER NUMBER {
22853293e44Sflorian 			ra_options->retrans_timer = $3;
22953293e44Sflorian 		}
230*30ca3407Sflorian 		| SOURCE LINK_LAYER ADDRESS yesno {
231*30ca3407Sflorian 			ra_options->source_link_addr = $4;
232*30ca3407Sflorian 		}
233cea17583Sbket 		| MTU NUMBER {
234cea17583Sbket 			ra_options->mtu = $2;
235cea17583Sbket 		}
2365207bb19Sflorian 		| NAT64 PREFIX STRING {
2375207bb19Sflorian 			struct in6_addr	 addr;
2385207bb19Sflorian 			int		 prefixlen;
2395207bb19Sflorian 			char		*p;
2405207bb19Sflorian 			const char	*errstr;
2415207bb19Sflorian 
2425207bb19Sflorian 			memset(&addr, 0, sizeof(addr));
2435207bb19Sflorian 			p = strchr($3, '/');
2445207bb19Sflorian 			if (p != NULL) {
2455207bb19Sflorian 				*p++ = '\0';
2465207bb19Sflorian 				prefixlen = strtonum(p, 0, 128, &errstr);
2475207bb19Sflorian 				if (errstr != NULL) {
2485207bb19Sflorian 					yyerror("error parsing prefix "
2495207bb19Sflorian 					    "\"%s/%s\"", $3, p);
2505207bb19Sflorian 					free($3);
2515207bb19Sflorian 					YYERROR;
2525207bb19Sflorian 				}
2535207bb19Sflorian 			} else
2545207bb19Sflorian 				prefixlen = 96;
2555207bb19Sflorian 
2565207bb19Sflorian 			switch (prefixlen) {
2575207bb19Sflorian 			case 96:
2585207bb19Sflorian 			case 64:
2595207bb19Sflorian 			case 56:
2605207bb19Sflorian 			case 48:
2615207bb19Sflorian 			case 40:
2625207bb19Sflorian 			case 32:
2635207bb19Sflorian 				break;
2645207bb19Sflorian 			default:
2655207bb19Sflorian 				yyerror("invalid nat64 prefix length: %d",
2665207bb19Sflorian 				    prefixlen);
2675207bb19Sflorian 				YYERROR;
2685207bb19Sflorian 				break;
2695207bb19Sflorian 			}
2705207bb19Sflorian 			if(inet_pton(AF_INET6, $3, &addr) == 0) {
2715207bb19Sflorian 				yyerror("error parsing prefix \"%s/%d\"", $3,
2725207bb19Sflorian 				    prefixlen);
2735207bb19Sflorian 				free($3);
2745207bb19Sflorian 				YYERROR;
2755207bb19Sflorian 			}
2765207bb19Sflorian 			mask_prefix(&addr, prefixlen);
2775207bb19Sflorian 			ra_pref64_conf = conf_get_ra_pref64(&addr, prefixlen);
2785207bb19Sflorian 		} ra_pref64_block {
2795207bb19Sflorian 			ra_pref64_conf = NULL;
2805207bb19Sflorian 		}
2818815eebdSflorian 		| DNS dns_block
28253293e44Sflorian 		;
28353293e44Sflorian 
28453293e44Sflorian optnl		: '\n' optnl		/* zero or more newlines */
28553293e44Sflorian 		| /*empty*/
28653293e44Sflorian 		;
28753293e44Sflorian 
28853293e44Sflorian nl		: '\n' optnl		/* one or more newlines */
28953293e44Sflorian 		;
29053293e44Sflorian 
29153293e44Sflorian ra_iface	: RA_IFACE STRING {
29253293e44Sflorian 			ra_iface_conf = conf_get_ra_iface($2);
29353293e44Sflorian 			/* set auto prefix defaults */
29453293e44Sflorian 			ra_iface_conf->autoprefix = conf_get_ra_prefix(NULL, 0);
29553293e44Sflorian 			ra_options = &ra_iface_conf->ra_options;
29653293e44Sflorian 		} ra_iface_block {
29753293e44Sflorian 			ra_iface_conf = NULL;
2988815eebdSflorian 			ra_options = &conf->ra_options;
29953293e44Sflorian 		}
30053293e44Sflorian 		;
30153293e44Sflorian 
30253293e44Sflorian ra_iface_block	: '{' optnl ra_ifaceopts_l '}'
30353293e44Sflorian 		| '{' optnl '}'
30453293e44Sflorian 		| /* empty */
30553293e44Sflorian 		;
30653293e44Sflorian 
30753293e44Sflorian ra_ifaceopts_l	: ra_ifaceopts_l ra_ifaceoptsl nl
30853293e44Sflorian 		| ra_ifaceoptsl optnl
30953293e44Sflorian 		;
31053293e44Sflorian 
31153293e44Sflorian ra_ifaceoptsl	: NO AUTO PREFIX {
31253293e44Sflorian 			free(ra_iface_conf->autoprefix);
31353293e44Sflorian 			ra_iface_conf->autoprefix = NULL;
31453293e44Sflorian 		}
31553293e44Sflorian 		| AUTO PREFIX {
31653293e44Sflorian 			if (ra_iface_conf->autoprefix == NULL)
31753293e44Sflorian 				ra_iface_conf->autoprefix =
318cddacf98Sflorian 				    conf_get_ra_prefix(NULL, 0);
319cddacf98Sflorian 			ra_prefix_conf = ra_iface_conf->autoprefix;
32053293e44Sflorian 		} ra_prefix_block {
32153293e44Sflorian 			ra_prefix_conf = NULL;
32253293e44Sflorian 		}
32353293e44Sflorian 		| PREFIX STRING {
32453293e44Sflorian 			struct in6_addr	 addr;
32553293e44Sflorian 			int		 prefixlen;
3268bc29b82Sflorian 			char		*p;
3278bc29b82Sflorian 			const char	*errstr;
32853293e44Sflorian 
32953293e44Sflorian 			memset(&addr, 0, sizeof(addr));
3308bc29b82Sflorian 			p = strchr($2, '/');
3318bc29b82Sflorian 			if (p != NULL) {
3328bc29b82Sflorian 				*p++ = '\0';
3338bc29b82Sflorian 				prefixlen = strtonum(p, 0, 128, &errstr);
3348bc29b82Sflorian 				if (errstr != NULL) {
3358bc29b82Sflorian 					yyerror("error parsing prefix "
3368bc29b82Sflorian 					    "\"%s/%s\"", $2, p);
33753293e44Sflorian 					free($2);
33853293e44Sflorian 					YYERROR;
33953293e44Sflorian 				}
3408bc29b82Sflorian 			} else
341b2ae623dSbluhm 				prefixlen = 64;
3428bc29b82Sflorian 			if(inet_pton(AF_INET6, $2, &addr) == 0) {
3438bc29b82Sflorian 				yyerror("error parsing prefix \"%s/%d\"", $2,
3448bc29b82Sflorian 				    prefixlen);
3458bc29b82Sflorian 				free($2);
3468bc29b82Sflorian 				YYERROR;
3478bc29b82Sflorian 			}
34853293e44Sflorian 			mask_prefix(&addr, prefixlen);
34953293e44Sflorian 			ra_prefix_conf = conf_get_ra_prefix(&addr, prefixlen);
35053293e44Sflorian 		} ra_prefix_block {
35153293e44Sflorian 			ra_prefix_conf = NULL;
35253293e44Sflorian 		}
35353293e44Sflorian 		| ra_opt_block
35453293e44Sflorian 		;
35553293e44Sflorian 
35653293e44Sflorian ra_prefix_block	: '{' optnl ra_prefixopts_l '}'
35753293e44Sflorian 		| '{' optnl '}'
35853293e44Sflorian 		| /* empty */
35953293e44Sflorian 		;
36053293e44Sflorian 
36153293e44Sflorian ra_prefixopts_l	: ra_prefixopts_l ra_prefixoptsl nl
36253293e44Sflorian 		| ra_prefixoptsl optnl
36353293e44Sflorian 		;
36453293e44Sflorian 
36553293e44Sflorian ra_prefixoptsl	: VALID LIFETIME NUMBER {
36653293e44Sflorian 			ra_prefix_conf->vltime = $3;
36753293e44Sflorian 		}
36853293e44Sflorian 		| PREFERRED LIFETIME NUMBER {
36953293e44Sflorian 			ra_prefix_conf->pltime = $3;
37053293e44Sflorian 		}
37153293e44Sflorian 		| ONLINK yesno {
37253293e44Sflorian 			ra_prefix_conf->lflag = $2;
37353293e44Sflorian 		}
37453293e44Sflorian 		| AUTONOMOUS ADDRESS_CONFIGURATION yesno {
37553293e44Sflorian 			ra_prefix_conf->aflag = $3;
37653293e44Sflorian 		}
37753293e44Sflorian 		;
3785207bb19Sflorian 
3795207bb19Sflorian ra_pref64_block	: '{' optnl ra_pref64opts_l '}'
3805207bb19Sflorian 		| '{' optnl '}'
3815207bb19Sflorian 		| /* empty */
3825207bb19Sflorian 		;
3835207bb19Sflorian 
3845207bb19Sflorian ra_pref64opts_l	: ra_pref64opts_l ra_pref64optsl nl
3855207bb19Sflorian 		| ra_pref64optsl optnl
3865207bb19Sflorian 		;
3875207bb19Sflorian 
3885207bb19Sflorian ra_pref64optsl	: LIFETIME NUMBER {
3895207bb19Sflorian 			if ($2 < 0 || $2 > 65528) {
3905207bb19Sflorian 				yyerror("Invalid nat64 prefix lifetime: %lld",
3915207bb19Sflorian 				    $2);
3925207bb19Sflorian 				YYERROR;
3935207bb19Sflorian 			}
3945207bb19Sflorian 			ra_pref64_conf->ltime = $2;
3955207bb19Sflorian 		}
3965207bb19Sflorian 		;
3975207bb19Sflorian 
3984c40b7e8Sflorian dns_block	: '{' optnl dnsopts_l '}'
3994c40b7e8Sflorian 		| '{' optnl '}'
4004c40b7e8Sflorian 		| /* empty */
4014c40b7e8Sflorian 		;
40253293e44Sflorian 
4034c40b7e8Sflorian dnsopts_l	: dnsopts_l dnsoptsl nl
4044c40b7e8Sflorian 		| dnsoptsl optnl
4054c40b7e8Sflorian 		;
4064c40b7e8Sflorian 
4074c40b7e8Sflorian dnsoptsl	: LIFETIME NUMBER {
4088815eebdSflorian 			ra_options->rdns_lifetime = $2;
4094c40b7e8Sflorian 		}
4108fe22fd3Sflorian 		| NAMESERVER nserver_block
4114c40b7e8Sflorian 		| SEARCH search_block
4124c40b7e8Sflorian 		;
4138fe22fd3Sflorian nserver_block	: '{' optnl nserveropts_l '}'
4144c40b7e8Sflorian 			| '{' optnl '}'
4158fe22fd3Sflorian 			| nserveroptsl
4164c40b7e8Sflorian 			| /* empty */
4174c40b7e8Sflorian 			;
4184c40b7e8Sflorian 
4198fe22fd3Sflorian nserveropts_l	: nserveropts_l nserveroptsl optnl
4208fe22fd3Sflorian 		| nserveroptsl optnl
4214c40b7e8Sflorian 		;
4224c40b7e8Sflorian 
4238fe22fd3Sflorian nserveroptsl	: STRING {
4244c40b7e8Sflorian 			struct ra_rdnss_conf	*ra_rdnss_conf;
4254c40b7e8Sflorian 			struct in6_addr		 addr;
4264c40b7e8Sflorian 
4274c40b7e8Sflorian 			memset(&addr, 0, sizeof(addr));
4284c40b7e8Sflorian 			if (inet_pton(AF_INET6, $1, &addr)
4294c40b7e8Sflorian 			    != 1) {
4308fe22fd3Sflorian 				yyerror("error parsing nameserver address %s",
4314c40b7e8Sflorian 				    $1);
4324c40b7e8Sflorian 				free($1);
4334c40b7e8Sflorian 				YYERROR;
4344c40b7e8Sflorian 			}
4354c40b7e8Sflorian 			if ((ra_rdnss_conf = calloc(1, sizeof(*ra_rdnss_conf)))
4364c40b7e8Sflorian 			    == NULL)
4374c40b7e8Sflorian 				err(1, "%s", __func__);
4384c40b7e8Sflorian 			memcpy(&ra_rdnss_conf->rdnss, &addr, sizeof(addr));
4398815eebdSflorian 			SIMPLEQ_INSERT_TAIL(&ra_options->ra_rdnss_list,
4404c40b7e8Sflorian 			    ra_rdnss_conf, entry);
4418815eebdSflorian 			ra_options->rdnss_count++;
4424c40b7e8Sflorian 		}
4434c40b7e8Sflorian 		;
4444c40b7e8Sflorian search_block	: '{' optnl searchopts_l '}'
4454c40b7e8Sflorian 		| '{' optnl '}'
4464c40b7e8Sflorian 		| searchoptsl
4474c40b7e8Sflorian 		| /* empty */
4484c40b7e8Sflorian 		;
4494c40b7e8Sflorian 
4504c40b7e8Sflorian searchopts_l	: searchopts_l searchoptsl optnl
4514c40b7e8Sflorian 		| searchoptsl optnl
4524c40b7e8Sflorian 		;
4534c40b7e8Sflorian 
4544c40b7e8Sflorian searchoptsl	: STRING {
4554c40b7e8Sflorian 			struct ra_dnssl_conf	*ra_dnssl_conf;
4564c40b7e8Sflorian 			size_t			 len;
4574c40b7e8Sflorian 
4584c40b7e8Sflorian 			if ((ra_dnssl_conf = calloc(1,
4594c40b7e8Sflorian 			    sizeof(*ra_dnssl_conf))) == NULL)
4604c40b7e8Sflorian 				err(1, "%s", __func__);
4614c40b7e8Sflorian 
4624c40b7e8Sflorian 			if ((len = strlcpy(ra_dnssl_conf->search, $1,
463895a1e8bSjsg 			    sizeof(ra_dnssl_conf->search))) >=
4644c40b7e8Sflorian 			    sizeof(ra_dnssl_conf->search)) {
4654c40b7e8Sflorian 				yyerror("search string too long");
4664c40b7e8Sflorian 				free($1);
4674c40b7e8Sflorian 				YYERROR;
4684c40b7e8Sflorian 			}
4694c40b7e8Sflorian 			if (ra_dnssl_conf->search[len] != '.') {
4704c40b7e8Sflorian 				if ((len = strlcat(ra_dnssl_conf->search, ".",
4714c40b7e8Sflorian 				    sizeof(ra_dnssl_conf->search))) >
4724c40b7e8Sflorian 				    sizeof(ra_dnssl_conf->search)) {
4734c40b7e8Sflorian 					yyerror("search string too long");
4744c40b7e8Sflorian 					free($1);
4754c40b7e8Sflorian 					YYERROR;
4764c40b7e8Sflorian 				}
4774c40b7e8Sflorian 			}
4788815eebdSflorian 			SIMPLEQ_INSERT_TAIL(&ra_options->ra_dnssl_list,
4794c40b7e8Sflorian 			    ra_dnssl_conf, entry);
4808815eebdSflorian 			ra_options->dnssl_len += len + 1;
4814c40b7e8Sflorian 		}
4824c40b7e8Sflorian 		;
48353293e44Sflorian %%
48453293e44Sflorian 
48553293e44Sflorian struct keywords {
48653293e44Sflorian 	const char	*k_name;
48753293e44Sflorian 	int		 k_val;
48853293e44Sflorian };
48953293e44Sflorian 
49053293e44Sflorian int
yyerror(const char * fmt,...)49153293e44Sflorian yyerror(const char *fmt, ...)
49253293e44Sflorian {
49353293e44Sflorian 	va_list		 ap;
49453293e44Sflorian 	char		*msg;
49553293e44Sflorian 
49653293e44Sflorian 	file->errors++;
49753293e44Sflorian 	va_start(ap, fmt);
49853293e44Sflorian 	if (vasprintf(&msg, fmt, ap) == -1)
49953293e44Sflorian 		fatalx("yyerror vasprintf");
50053293e44Sflorian 	va_end(ap);
50153293e44Sflorian 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
50253293e44Sflorian 	free(msg);
50353293e44Sflorian 	return (0);
50453293e44Sflorian }
50553293e44Sflorian 
50653293e44Sflorian int
kw_cmp(const void * k,const void * e)50753293e44Sflorian kw_cmp(const void *k, const void *e)
50853293e44Sflorian {
50953293e44Sflorian 	return (strcmp(k, ((const struct keywords *)e)->k_name));
51053293e44Sflorian }
51153293e44Sflorian 
51253293e44Sflorian int
lookup(char * s)51353293e44Sflorian lookup(char *s)
51453293e44Sflorian {
51553293e44Sflorian 	/* This has to be sorted always. */
51653293e44Sflorian 	static const struct keywords keywords[] = {
51753293e44Sflorian 		{"address",		ADDRESS},
51853293e44Sflorian 		{"address-configuration",	ADDRESS_CONFIGURATION},
51953293e44Sflorian 		{"auto",		AUTO},
52053293e44Sflorian 		{"autonomous",		AUTONOMOUS},
52153293e44Sflorian 		{"configuration",	CONFIGURATION},
52253293e44Sflorian 		{"default",		DEFAULT},
5234c40b7e8Sflorian 		{"dns",			DNS},
524639a58baSflorian 		{"high",		HIGH},
52553293e44Sflorian 		{"hop",			HOP},
52653293e44Sflorian 		{"include",		INCLUDE},
52753293e44Sflorian 		{"interface",		RA_IFACE},
52853293e44Sflorian 		{"lifetime",		LIFETIME},
52953293e44Sflorian 		{"limit",		LIMIT},
530*30ca3407Sflorian 		{"link-layer",		LINK_LAYER},
531639a58baSflorian 		{"low",			LOW},
53253293e44Sflorian 		{"managed",		MANAGED},
533639a58baSflorian 		{"medium",		MEDIUM},
534cea17583Sbket 		{"mtu",			MTU},
5358fe22fd3Sflorian 		{"nameserver",		NAMESERVER},
5365207bb19Sflorian 		{"nat64",		NAT64},
53753293e44Sflorian 		{"no",			NO},
53853293e44Sflorian 		{"on-link",		ONLINK},
53953293e44Sflorian 		{"other",		OTHER},
540639a58baSflorian 		{"preference",		PREFERENCE},
54153293e44Sflorian 		{"preferred",		PREFERRED},
54253293e44Sflorian 		{"prefix",		PREFIX},
54353293e44Sflorian 		{"reachable",		REACHABLE},
54453293e44Sflorian 		{"retrans",		RETRANS},
54553293e44Sflorian 		{"router",		ROUTER},
5464c40b7e8Sflorian 		{"search",		SEARCH},
547*30ca3407Sflorian 		{"source",		SOURCE},
54853293e44Sflorian 		{"time",		TIME},
54953293e44Sflorian 		{"timer",		TIMER},
55053293e44Sflorian 		{"valid",		VALID},
55153293e44Sflorian 		{"yes",			YES},
55253293e44Sflorian 	};
55353293e44Sflorian 	const struct keywords	*p;
55453293e44Sflorian 
55553293e44Sflorian 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
55653293e44Sflorian 	    sizeof(keywords[0]), kw_cmp);
55753293e44Sflorian 
55853293e44Sflorian 	if (p)
55953293e44Sflorian 		return (p->k_val);
56053293e44Sflorian 	else
56153293e44Sflorian 		return (STRING);
56253293e44Sflorian }
56353293e44Sflorian 
56453293e44Sflorian #define START_EXPAND	1
56553293e44Sflorian #define DONE_EXPAND	2
56653293e44Sflorian 
56753293e44Sflorian static int	expanding;
56853293e44Sflorian 
56953293e44Sflorian int
igetc(void)57053293e44Sflorian igetc(void)
57153293e44Sflorian {
57253293e44Sflorian 	int	c;
57353293e44Sflorian 
57453293e44Sflorian 	while (1) {
57553293e44Sflorian 		if (file->ungetpos > 0)
57653293e44Sflorian 			c = file->ungetbuf[--file->ungetpos];
57753293e44Sflorian 		else
57853293e44Sflorian 			c = getc(file->stream);
57953293e44Sflorian 
58053293e44Sflorian 		if (c == START_EXPAND)
58153293e44Sflorian 			expanding = 1;
58253293e44Sflorian 		else if (c == DONE_EXPAND)
58353293e44Sflorian 			expanding = 0;
58453293e44Sflorian 		else
58553293e44Sflorian 			break;
58653293e44Sflorian 	}
58753293e44Sflorian 	return (c);
58853293e44Sflorian }
58953293e44Sflorian 
59053293e44Sflorian int
lgetc(int quotec)59153293e44Sflorian lgetc(int quotec)
59253293e44Sflorian {
59353293e44Sflorian 	int		c, next;
59453293e44Sflorian 
59553293e44Sflorian 	if (quotec) {
59653293e44Sflorian 		if ((c = igetc()) == EOF) {
59753293e44Sflorian 			yyerror("reached end of file while parsing "
59853293e44Sflorian 			    "quoted string");
59953293e44Sflorian 			if (file == topfile || popfile() == EOF)
60053293e44Sflorian 				return (EOF);
60153293e44Sflorian 			return (quotec);
60253293e44Sflorian 		}
60353293e44Sflorian 		return (c);
60453293e44Sflorian 	}
60553293e44Sflorian 
60653293e44Sflorian 	while ((c = igetc()) == '\\') {
60753293e44Sflorian 		next = igetc();
60853293e44Sflorian 		if (next != '\n') {
60953293e44Sflorian 			c = next;
61053293e44Sflorian 			break;
61153293e44Sflorian 		}
61253293e44Sflorian 		yylval.lineno = file->lineno;
61353293e44Sflorian 		file->lineno++;
61453293e44Sflorian 	}
61553293e44Sflorian 
61653293e44Sflorian 	if (c == EOF) {
61753293e44Sflorian 		/*
61853293e44Sflorian 		 * Fake EOL when hit EOF for the first time. This gets line
61953293e44Sflorian 		 * count right if last line in included file is syntactically
62053293e44Sflorian 		 * invalid and has no newline.
62153293e44Sflorian 		 */
62253293e44Sflorian 		if (file->eof_reached == 0) {
62353293e44Sflorian 			file->eof_reached = 1;
62453293e44Sflorian 			return ('\n');
62553293e44Sflorian 		}
62653293e44Sflorian 		while (c == EOF) {
62753293e44Sflorian 			if (file == topfile || popfile() == EOF)
62853293e44Sflorian 				return (EOF);
62953293e44Sflorian 			c = igetc();
63053293e44Sflorian 		}
63153293e44Sflorian 	}
63253293e44Sflorian 	return (c);
63353293e44Sflorian }
63453293e44Sflorian 
63553293e44Sflorian void
lungetc(int c)63653293e44Sflorian lungetc(int c)
63753293e44Sflorian {
63853293e44Sflorian 	if (c == EOF)
63953293e44Sflorian 		return;
64053293e44Sflorian 
64153293e44Sflorian 	if (file->ungetpos >= file->ungetsize) {
64253293e44Sflorian 		void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
64353293e44Sflorian 		if (p == NULL)
64453293e44Sflorian 			err(1, "lungetc");
64553293e44Sflorian 		file->ungetbuf = p;
64653293e44Sflorian 		file->ungetsize *= 2;
64753293e44Sflorian 	}
64853293e44Sflorian 	file->ungetbuf[file->ungetpos++] = c;
64953293e44Sflorian }
65053293e44Sflorian 
65153293e44Sflorian int
findeol(void)65253293e44Sflorian findeol(void)
65353293e44Sflorian {
65453293e44Sflorian 	int	c;
65553293e44Sflorian 
65653293e44Sflorian 	/* Skip to either EOF or the first real EOL. */
65753293e44Sflorian 	while (1) {
65853293e44Sflorian 		c = lgetc(0);
65953293e44Sflorian 		if (c == '\n') {
66053293e44Sflorian 			file->lineno++;
66153293e44Sflorian 			break;
66253293e44Sflorian 		}
66353293e44Sflorian 		if (c == EOF)
66453293e44Sflorian 			break;
66553293e44Sflorian 	}
66653293e44Sflorian 	return (ERROR);
66753293e44Sflorian }
66853293e44Sflorian 
66953293e44Sflorian int
yylex(void)67053293e44Sflorian yylex(void)
67153293e44Sflorian {
67208f6ba19Snaddy 	char	 buf[8096];
67308f6ba19Snaddy 	char	*p, *val;
67453293e44Sflorian 	int	 quotec, next, c;
67553293e44Sflorian 	int	 token;
67653293e44Sflorian 
67753293e44Sflorian top:
67853293e44Sflorian 	p = buf;
67953293e44Sflorian 	while ((c = lgetc(0)) == ' ' || c == '\t')
68053293e44Sflorian 		; /* nothing */
68153293e44Sflorian 
68253293e44Sflorian 	yylval.lineno = file->lineno;
68353293e44Sflorian 	if (c == '#')
68453293e44Sflorian 		while ((c = lgetc(0)) != '\n' && c != EOF)
68553293e44Sflorian 			; /* nothing */
68653293e44Sflorian 	if (c == '$' && !expanding) {
68753293e44Sflorian 		while (1) {
68853293e44Sflorian 			if ((c = lgetc(0)) == EOF)
68953293e44Sflorian 				return (0);
69053293e44Sflorian 
69153293e44Sflorian 			if (p + 1 >= buf + sizeof(buf) - 1) {
69253293e44Sflorian 				yyerror("string too long");
69353293e44Sflorian 				return (findeol());
69453293e44Sflorian 			}
69553293e44Sflorian 			if (isalnum(c) || c == '_') {
69653293e44Sflorian 				*p++ = c;
69753293e44Sflorian 				continue;
69853293e44Sflorian 			}
69953293e44Sflorian 			*p = '\0';
70053293e44Sflorian 			lungetc(c);
70153293e44Sflorian 			break;
70253293e44Sflorian 		}
70353293e44Sflorian 		val = symget(buf);
70453293e44Sflorian 		if (val == NULL) {
70553293e44Sflorian 			yyerror("macro '%s' not defined", buf);
70653293e44Sflorian 			return (findeol());
70753293e44Sflorian 		}
70853293e44Sflorian 		p = val + strlen(val) - 1;
70953293e44Sflorian 		lungetc(DONE_EXPAND);
71053293e44Sflorian 		while (p >= val) {
71108f6ba19Snaddy 			lungetc((unsigned char)*p);
71253293e44Sflorian 			p--;
71353293e44Sflorian 		}
71453293e44Sflorian 		lungetc(START_EXPAND);
71553293e44Sflorian 		goto top;
71653293e44Sflorian 	}
71753293e44Sflorian 
71853293e44Sflorian 	switch (c) {
71953293e44Sflorian 	case '\'':
72053293e44Sflorian 	case '"':
72153293e44Sflorian 		quotec = c;
72253293e44Sflorian 		while (1) {
72353293e44Sflorian 			if ((c = lgetc(quotec)) == EOF)
72453293e44Sflorian 				return (0);
72553293e44Sflorian 			if (c == '\n') {
72653293e44Sflorian 				file->lineno++;
72753293e44Sflorian 				continue;
72853293e44Sflorian 			} else if (c == '\\') {
72953293e44Sflorian 				if ((next = lgetc(quotec)) == EOF)
73053293e44Sflorian 					return (0);
731a1533359Ssashan 				if (next == quotec || next == ' ' ||
732a1533359Ssashan 				    next == '\t')
73353293e44Sflorian 					c = next;
73453293e44Sflorian 				else if (next == '\n') {
73553293e44Sflorian 					file->lineno++;
73653293e44Sflorian 					continue;
73753293e44Sflorian 				} else
73853293e44Sflorian 					lungetc(next);
73953293e44Sflorian 			} else if (c == quotec) {
74053293e44Sflorian 				*p = '\0';
74153293e44Sflorian 				break;
74253293e44Sflorian 			} else if (c == '\0') {
74353293e44Sflorian 				yyerror("syntax error");
74453293e44Sflorian 				return (findeol());
74553293e44Sflorian 			}
74653293e44Sflorian 			if (p + 1 >= buf + sizeof(buf) - 1) {
74753293e44Sflorian 				yyerror("string too long");
74853293e44Sflorian 				return (findeol());
74953293e44Sflorian 			}
75053293e44Sflorian 			*p++ = c;
75153293e44Sflorian 		}
75253293e44Sflorian 		yylval.v.string = strdup(buf);
75353293e44Sflorian 		if (yylval.v.string == NULL)
75453293e44Sflorian 			err(1, "yylex: strdup");
75553293e44Sflorian 		return (STRING);
75653293e44Sflorian 	}
75753293e44Sflorian 
75853293e44Sflorian #define allowed_to_end_number(x) \
75953293e44Sflorian 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
76053293e44Sflorian 
76153293e44Sflorian 	if (c == '-' || isdigit(c)) {
76253293e44Sflorian 		do {
76353293e44Sflorian 			*p++ = c;
764915c3f33Sderaadt 			if ((size_t)(p-buf) >= sizeof(buf)) {
76553293e44Sflorian 				yyerror("string too long");
76653293e44Sflorian 				return (findeol());
76753293e44Sflorian 			}
76853293e44Sflorian 		} while ((c = lgetc(0)) != EOF && isdigit(c));
76953293e44Sflorian 		lungetc(c);
77053293e44Sflorian 		if (p == buf + 1 && buf[0] == '-')
77153293e44Sflorian 			goto nodigits;
77253293e44Sflorian 		if (c == EOF || allowed_to_end_number(c)) {
77353293e44Sflorian 			const char *errstr = NULL;
77453293e44Sflorian 
77553293e44Sflorian 			*p = '\0';
77653293e44Sflorian 			yylval.v.number = strtonum(buf, LLONG_MIN,
77753293e44Sflorian 			    LLONG_MAX, &errstr);
77853293e44Sflorian 			if (errstr) {
77953293e44Sflorian 				yyerror("\"%s\" invalid number: %s",
78053293e44Sflorian 				    buf, errstr);
78153293e44Sflorian 				return (findeol());
78253293e44Sflorian 			}
78353293e44Sflorian 			return (NUMBER);
78453293e44Sflorian 		} else {
78553293e44Sflorian nodigits:
78653293e44Sflorian 			while (p > buf + 1)
78708f6ba19Snaddy 				lungetc((unsigned char)*--p);
78808f6ba19Snaddy 			c = (unsigned char)*--p;
78953293e44Sflorian 			if (c == '-')
79053293e44Sflorian 				return (c);
79153293e44Sflorian 		}
79253293e44Sflorian 	}
79353293e44Sflorian 
79453293e44Sflorian #define allowed_in_string(x) \
79553293e44Sflorian 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
79653293e44Sflorian 	x != '{' && x != '}' && \
79753293e44Sflorian 	x != '!' && x != '=' && x != '#' && \
79853293e44Sflorian 	x != ','))
79953293e44Sflorian 
80053293e44Sflorian 	if (isalnum(c) || c == ':' || c == '_') {
80153293e44Sflorian 		do {
80253293e44Sflorian 			*p++ = c;
803915c3f33Sderaadt 			if ((size_t)(p-buf) >= sizeof(buf)) {
80453293e44Sflorian 				yyerror("string too long");
80553293e44Sflorian 				return (findeol());
80653293e44Sflorian 			}
80753293e44Sflorian 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
80853293e44Sflorian 		lungetc(c);
80953293e44Sflorian 		*p = '\0';
81053293e44Sflorian 		if ((token = lookup(buf)) == STRING)
81153293e44Sflorian 			if ((yylval.v.string = strdup(buf)) == NULL)
81253293e44Sflorian 				err(1, "yylex: strdup");
81353293e44Sflorian 		return (token);
81453293e44Sflorian 	}
81553293e44Sflorian 	if (c == '\n') {
81653293e44Sflorian 		yylval.lineno = file->lineno;
81753293e44Sflorian 		file->lineno++;
81853293e44Sflorian 	}
81953293e44Sflorian 	if (c == EOF)
82053293e44Sflorian 		return (0);
82153293e44Sflorian 	return (c);
82253293e44Sflorian }
82353293e44Sflorian 
82453293e44Sflorian int
check_file_secrecy(int fd,const char * fname)82553293e44Sflorian check_file_secrecy(int fd, const char *fname)
82653293e44Sflorian {
82753293e44Sflorian 	struct stat	st;
82853293e44Sflorian 
82953293e44Sflorian 	if (fstat(fd, &st)) {
83053293e44Sflorian 		log_warn("cannot stat %s", fname);
83153293e44Sflorian 		return (-1);
83253293e44Sflorian 	}
83353293e44Sflorian 	if (st.st_uid != 0 && st.st_uid != getuid()) {
83453293e44Sflorian 		log_warnx("%s: owner not root or current user", fname);
83553293e44Sflorian 		return (-1);
83653293e44Sflorian 	}
83753293e44Sflorian 	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
83853293e44Sflorian 		log_warnx("%s: group writable or world read/writable", fname);
83953293e44Sflorian 		return (-1);
84053293e44Sflorian 	}
84153293e44Sflorian 	return (0);
84253293e44Sflorian }
84353293e44Sflorian 
84453293e44Sflorian struct file *
pushfile(const char * name,int secret)84553293e44Sflorian pushfile(const char *name, int secret)
84653293e44Sflorian {
84753293e44Sflorian 	struct file	*nfile;
84853293e44Sflorian 
84953293e44Sflorian 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
85053293e44Sflorian 		log_warn("calloc");
85153293e44Sflorian 		return (NULL);
85253293e44Sflorian 	}
85353293e44Sflorian 	if ((nfile->name = strdup(name)) == NULL) {
85453293e44Sflorian 		log_warn("strdup");
85553293e44Sflorian 		free(nfile);
85653293e44Sflorian 		return (NULL);
85753293e44Sflorian 	}
85853293e44Sflorian 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
85953293e44Sflorian 		log_warn("%s", nfile->name);
86053293e44Sflorian 		free(nfile->name);
86153293e44Sflorian 		free(nfile);
86253293e44Sflorian 		return (NULL);
86353293e44Sflorian 	} else if (secret &&
86453293e44Sflorian 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
86553293e44Sflorian 		fclose(nfile->stream);
86653293e44Sflorian 		free(nfile->name);
86753293e44Sflorian 		free(nfile);
86853293e44Sflorian 		return (NULL);
86953293e44Sflorian 	}
87053293e44Sflorian 	nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
87153293e44Sflorian 	nfile->ungetsize = 16;
87253293e44Sflorian 	nfile->ungetbuf = malloc(nfile->ungetsize);
87353293e44Sflorian 	if (nfile->ungetbuf == NULL) {
87453293e44Sflorian 		log_warn("malloc");
87553293e44Sflorian 		fclose(nfile->stream);
87653293e44Sflorian 		free(nfile->name);
87753293e44Sflorian 		free(nfile);
87853293e44Sflorian 		return (NULL);
87953293e44Sflorian 	}
88053293e44Sflorian 	TAILQ_INSERT_TAIL(&files, nfile, entry);
88153293e44Sflorian 	return (nfile);
88253293e44Sflorian }
88353293e44Sflorian 
88453293e44Sflorian int
popfile(void)88553293e44Sflorian popfile(void)
88653293e44Sflorian {
88753293e44Sflorian 	struct file	*prev;
88853293e44Sflorian 
88953293e44Sflorian 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
89053293e44Sflorian 		prev->errors += file->errors;
89153293e44Sflorian 
89253293e44Sflorian 	TAILQ_REMOVE(&files, file, entry);
89353293e44Sflorian 	fclose(file->stream);
89453293e44Sflorian 	free(file->name);
89553293e44Sflorian 	free(file->ungetbuf);
89653293e44Sflorian 	free(file);
89753293e44Sflorian 	file = prev;
89853293e44Sflorian 	return (file ? 0 : EOF);
89953293e44Sflorian }
90053293e44Sflorian 
90153293e44Sflorian struct rad_conf *
parse_config(char * filename)90253293e44Sflorian parse_config(char *filename)
90353293e44Sflorian {
90453293e44Sflorian 	struct sym		*sym, *next;
9058815eebdSflorian 	struct ra_iface_conf	*iface;
90653293e44Sflorian 
90753293e44Sflorian 	conf = config_new_empty();
90853293e44Sflorian 	ra_options = NULL;
90953293e44Sflorian 
9103a682461Sflorian 	file = pushfile(filename, 0);
91153293e44Sflorian 	if (file == NULL) {
91253293e44Sflorian 		free(conf);
91353293e44Sflorian 		return (NULL);
91453293e44Sflorian 	}
91553293e44Sflorian 	topfile = file;
91653293e44Sflorian 
91753293e44Sflorian 	yyparse();
91853293e44Sflorian 	errors = file->errors;
91953293e44Sflorian 	popfile();
92053293e44Sflorian 
92153293e44Sflorian 	/* Free macros and check which have not been used. */
92253293e44Sflorian 	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
92353293e44Sflorian 		if ((cmd_opts & OPT_VERBOSE2) && !sym->used)
92453293e44Sflorian 			fprintf(stderr, "warning: macro '%s' not used\n",
92553293e44Sflorian 			    sym->nam);
92653293e44Sflorian 		if (!sym->persist) {
92753293e44Sflorian 			free(sym->nam);
92853293e44Sflorian 			free(sym->val);
92953293e44Sflorian 			TAILQ_REMOVE(&symhead, sym, entry);
93053293e44Sflorian 			free(sym);
93153293e44Sflorian 		}
93253293e44Sflorian 	}
93353293e44Sflorian 
93453293e44Sflorian 	if (errors) {
93553293e44Sflorian 		clear_config(conf);
93653293e44Sflorian 		return (NULL);
93753293e44Sflorian 	}
93853293e44Sflorian 
9398815eebdSflorian 	if (!SIMPLEQ_EMPTY(&conf->ra_options.ra_rdnss_list) ||
9408815eebdSflorian 	    !SIMPLEQ_EMPTY(&conf->ra_options.ra_dnssl_list)) {
9418815eebdSflorian 		SIMPLEQ_FOREACH(iface, &conf->ra_iface_list, entry)
9428815eebdSflorian 			copy_dns_options(&conf->ra_options,
9438815eebdSflorian 			    &iface->ra_options);
9448815eebdSflorian 	}
9458815eebdSflorian 
9465207bb19Sflorian 	if (!SIMPLEQ_EMPTY(&conf->ra_options.ra_pref64_list)) {
9475207bb19Sflorian 		SIMPLEQ_FOREACH(iface, &conf->ra_iface_list, entry)
9485207bb19Sflorian 			copy_pref64_options(&conf->ra_options,
9495207bb19Sflorian 			    &iface->ra_options);
9505207bb19Sflorian 	}
9515207bb19Sflorian 
95253293e44Sflorian 	return (conf);
95353293e44Sflorian }
95453293e44Sflorian 
9558815eebdSflorian void
copy_dns_options(const struct ra_options_conf * src,struct ra_options_conf * dst)9568815eebdSflorian copy_dns_options(const struct ra_options_conf *src, struct ra_options_conf *dst)
9578815eebdSflorian {
9588815eebdSflorian 	struct ra_rdnss_conf	*ra_rdnss, *nra_rdnss;
9598815eebdSflorian 	struct ra_dnssl_conf	*ra_dnssl, *nra_dnssl;
9608815eebdSflorian 
9618815eebdSflorian 	if (SIMPLEQ_EMPTY(&dst->ra_rdnss_list)) {
9628815eebdSflorian 		SIMPLEQ_FOREACH(ra_rdnss, &src->ra_rdnss_list, entry) {
9638815eebdSflorian 			if ((nra_rdnss = calloc(1, sizeof(*nra_rdnss))) == NULL)
9649226b761Sflorian 				err(1, "%s", __func__);
9658815eebdSflorian 			memcpy(nra_rdnss, ra_rdnss, sizeof(*nra_rdnss));
9668815eebdSflorian 			SIMPLEQ_INSERT_TAIL(&dst->ra_rdnss_list, nra_rdnss,
9678815eebdSflorian 			    entry);
9688815eebdSflorian 		}
9698815eebdSflorian 		dst->rdnss_count = src->rdnss_count;
9708815eebdSflorian 	}
9718815eebdSflorian 	if (SIMPLEQ_EMPTY(&dst->ra_dnssl_list)) {
9728815eebdSflorian 		SIMPLEQ_FOREACH(ra_dnssl, &src->ra_dnssl_list, entry) {
9738815eebdSflorian 			if ((nra_dnssl = calloc(1, sizeof(*nra_dnssl))) == NULL)
9749226b761Sflorian 				err(1, "%s", __func__);
9758815eebdSflorian 			memcpy(nra_dnssl, ra_dnssl, sizeof(*nra_dnssl));
9768815eebdSflorian 			SIMPLEQ_INSERT_TAIL(&dst->ra_dnssl_list, nra_dnssl,
9778815eebdSflorian 			    entry);
9788815eebdSflorian 		}
9798815eebdSflorian 		dst->dnssl_len = src->dnssl_len;
9808815eebdSflorian 	}
9818815eebdSflorian }
9828815eebdSflorian 
9835207bb19Sflorian void
copy_pref64_options(const struct ra_options_conf * src,struct ra_options_conf * dst)9845207bb19Sflorian copy_pref64_options(const struct ra_options_conf *src, struct ra_options_conf
9855207bb19Sflorian     *dst)
9865207bb19Sflorian {
9875207bb19Sflorian 	struct ra_pref64_conf	*pref64, *npref64;
9885207bb19Sflorian 
9895207bb19Sflorian 	SIMPLEQ_FOREACH(pref64, &src->ra_pref64_list, entry) {
9905207bb19Sflorian 		if ((npref64 = calloc(1, sizeof(*npref64))) == NULL)
9915207bb19Sflorian 			err(1, "%s", __func__);
9925207bb19Sflorian 		memcpy(npref64, pref64, sizeof(*npref64));
9935207bb19Sflorian 		SIMPLEQ_INSERT_TAIL(&dst->ra_pref64_list, npref64, entry);
9945207bb19Sflorian 	}
9955207bb19Sflorian }
9965207bb19Sflorian 
99753293e44Sflorian int
symset(const char * nam,const char * val,int persist)99853293e44Sflorian symset(const char *nam, const char *val, int persist)
99953293e44Sflorian {
100053293e44Sflorian 	struct sym	*sym;
100153293e44Sflorian 
100253293e44Sflorian 	TAILQ_FOREACH(sym, &symhead, entry) {
100353293e44Sflorian 		if (strcmp(nam, sym->nam) == 0)
100453293e44Sflorian 			break;
100553293e44Sflorian 	}
100653293e44Sflorian 
100753293e44Sflorian 	if (sym != NULL) {
100853293e44Sflorian 		if (sym->persist == 1)
100953293e44Sflorian 			return (0);
101053293e44Sflorian 		else {
101153293e44Sflorian 			free(sym->nam);
101253293e44Sflorian 			free(sym->val);
101353293e44Sflorian 			TAILQ_REMOVE(&symhead, sym, entry);
101453293e44Sflorian 			free(sym);
101553293e44Sflorian 		}
101653293e44Sflorian 	}
101753293e44Sflorian 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
101853293e44Sflorian 		return (-1);
101953293e44Sflorian 
102053293e44Sflorian 	sym->nam = strdup(nam);
102153293e44Sflorian 	if (sym->nam == NULL) {
102253293e44Sflorian 		free(sym);
102353293e44Sflorian 		return (-1);
102453293e44Sflorian 	}
102553293e44Sflorian 	sym->val = strdup(val);
102653293e44Sflorian 	if (sym->val == NULL) {
102753293e44Sflorian 		free(sym->nam);
102853293e44Sflorian 		free(sym);
102953293e44Sflorian 		return (-1);
103053293e44Sflorian 	}
103153293e44Sflorian 	sym->used = 0;
103253293e44Sflorian 	sym->persist = persist;
103353293e44Sflorian 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
103453293e44Sflorian 	return (0);
103553293e44Sflorian }
103653293e44Sflorian 
103753293e44Sflorian int
cmdline_symset(char * s)103853293e44Sflorian cmdline_symset(char *s)
103953293e44Sflorian {
104053293e44Sflorian 	char	*sym, *val;
104153293e44Sflorian 	int	ret;
104253293e44Sflorian 
104353293e44Sflorian 	if ((val = strrchr(s, '=')) == NULL)
104453293e44Sflorian 		return (-1);
1045ed1b9eb8Smiko 	sym = strndup(s, val - s);
1046ed1b9eb8Smiko 	if (sym == NULL)
1047ed1b9eb8Smiko 		errx(1, "%s: strndup", __func__);
104853293e44Sflorian 	ret = symset(sym, val + 1, 1);
104953293e44Sflorian 	free(sym);
105053293e44Sflorian 
105153293e44Sflorian 	return (ret);
105253293e44Sflorian }
105353293e44Sflorian 
105453293e44Sflorian char *
symget(const char * nam)105553293e44Sflorian symget(const char *nam)
105653293e44Sflorian {
105753293e44Sflorian 	struct sym	*sym;
105853293e44Sflorian 
105953293e44Sflorian 	TAILQ_FOREACH(sym, &symhead, entry) {
106053293e44Sflorian 		if (strcmp(nam, sym->nam) == 0) {
106153293e44Sflorian 			sym->used = 1;
106253293e44Sflorian 			return (sym->val);
106353293e44Sflorian 		}
106453293e44Sflorian 	}
106553293e44Sflorian 	return (NULL);
106653293e44Sflorian }
106753293e44Sflorian 
106853293e44Sflorian struct ra_prefix_conf *
conf_get_ra_prefix(struct in6_addr * addr,int prefixlen)106953293e44Sflorian conf_get_ra_prefix(struct in6_addr *addr, int prefixlen)
107053293e44Sflorian {
107153293e44Sflorian 	struct ra_prefix_conf	*prefix;
107253293e44Sflorian 
107353293e44Sflorian 	if (addr == NULL) {
107453293e44Sflorian 		if (ra_iface_conf->autoprefix != NULL)
107553293e44Sflorian 			return (ra_iface_conf->autoprefix);
107653293e44Sflorian 	} else {
107753293e44Sflorian 		SIMPLEQ_FOREACH(prefix, &ra_iface_conf->ra_prefix_list, entry) {
107853293e44Sflorian 			if (prefix->prefixlen == prefixlen && memcmp(addr,
107953293e44Sflorian 			    &prefix->prefix, sizeof(*addr)) == 0)
108053293e44Sflorian 				return (prefix);
108153293e44Sflorian 		}
108253293e44Sflorian 	}
108353293e44Sflorian 
108453293e44Sflorian 	prefix = calloc(1, sizeof(*prefix));
108553293e44Sflorian 	if (prefix == NULL)
10869226b761Sflorian 		err(1, "%s", __func__);
108753293e44Sflorian 	prefix->prefixlen = prefixlen;
108803aa2005Sflorian 	prefix->vltime = ADV_VALID_LIFETIME;
108903aa2005Sflorian 	prefix->pltime = ADV_PREFERRED_LIFETIME;
109053293e44Sflorian 	prefix->lflag = 1;
109153293e44Sflorian 	prefix->aflag = 1;
109253293e44Sflorian 
109353293e44Sflorian 	if (addr == NULL)
109453293e44Sflorian 		ra_iface_conf->autoprefix = prefix;
109553293e44Sflorian 	else {
109653293e44Sflorian 		prefix->prefix = *addr;
109753293e44Sflorian 		SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list, prefix,
109853293e44Sflorian 		    entry);
109953293e44Sflorian 	}
110053293e44Sflorian 
110153293e44Sflorian 	return (prefix);
110253293e44Sflorian }
110353293e44Sflorian 
11045207bb19Sflorian struct ra_pref64_conf *
conf_get_ra_pref64(struct in6_addr * addr,int prefixlen)11055207bb19Sflorian conf_get_ra_pref64(struct in6_addr *addr, int prefixlen)
11065207bb19Sflorian {
11075207bb19Sflorian 	struct ra_pref64_conf	*pref64;
11085207bb19Sflorian 
11095207bb19Sflorian 	SIMPLEQ_FOREACH(pref64, &ra_options->ra_pref64_list, entry) {
11105207bb19Sflorian 		if (pref64->prefixlen == prefixlen && memcmp(addr,
11115207bb19Sflorian 		    &pref64->prefix, sizeof(*addr)) == 0)
11125207bb19Sflorian 			return (pref64);
11135207bb19Sflorian 	}
11145207bb19Sflorian 
11155207bb19Sflorian 	pref64 = calloc(1, sizeof(*pref64));
11165207bb19Sflorian 	if (pref64 == NULL)
11175207bb19Sflorian 		err(1, "%s", __func__);
11185207bb19Sflorian 	pref64->prefixlen = prefixlen;
11195207bb19Sflorian 	pref64->ltime = ADV_DEFAULT_LIFETIME;
11205207bb19Sflorian 	pref64->prefix = *addr;
11215207bb19Sflorian 	SIMPLEQ_INSERT_TAIL(&ra_options->ra_pref64_list, pref64, entry);
11225207bb19Sflorian 
11235207bb19Sflorian 	return (pref64);
11245207bb19Sflorian }
11255207bb19Sflorian 
112653293e44Sflorian struct ra_iface_conf *
conf_get_ra_iface(char * name)112753293e44Sflorian conf_get_ra_iface(char *name)
112853293e44Sflorian {
112953293e44Sflorian 	struct ra_iface_conf	*iface;
113053293e44Sflorian 	size_t			 n;
113153293e44Sflorian 
113253293e44Sflorian 	SIMPLEQ_FOREACH(iface, &conf->ra_iface_list, entry) {
113353293e44Sflorian 		if (strcmp(name, iface->name) == 0)
113453293e44Sflorian 			return (iface);
113553293e44Sflorian 	}
113653293e44Sflorian 
113753293e44Sflorian 	iface = calloc(1, sizeof(*iface));
113853293e44Sflorian 	if (iface == NULL)
113953293e44Sflorian 		errx(1, "%s: calloc", __func__);
114053293e44Sflorian 	n = strlcpy(iface->name, name, sizeof(iface->name));
114153293e44Sflorian 	if (n >= sizeof(iface->name))
114253293e44Sflorian 		errx(1, "%s: name too long", __func__);
114353293e44Sflorian 
114453293e44Sflorian 	/* Inherit attributes set in global section. */
114553293e44Sflorian 	iface->ra_options = conf->ra_options;
114653293e44Sflorian 
114753293e44Sflorian 	SIMPLEQ_INIT(&iface->ra_prefix_list);
11488815eebdSflorian 	SIMPLEQ_INIT(&iface->ra_options.ra_rdnss_list);
11498815eebdSflorian 	iface->ra_options.rdnss_count = 0;
11508815eebdSflorian 	SIMPLEQ_INIT(&iface->ra_options.ra_dnssl_list);
11518815eebdSflorian 	iface->ra_options.dnssl_len = 0;
11525207bb19Sflorian 	SIMPLEQ_INIT(&iface->ra_options.ra_pref64_list);
115353293e44Sflorian 
115453293e44Sflorian 	SIMPLEQ_INSERT_TAIL(&conf->ra_iface_list, iface, entry);
115553293e44Sflorian 
115653293e44Sflorian 	return (iface);
115753293e44Sflorian }
115853293e44Sflorian 
115953293e44Sflorian void
clear_config(struct rad_conf * xconf)116053293e44Sflorian clear_config(struct rad_conf *xconf)
116153293e44Sflorian {
116253293e44Sflorian 	struct ra_iface_conf	*iface;
116353293e44Sflorian 
11648815eebdSflorian 	free_dns_options(&xconf->ra_options);
11658815eebdSflorian 
116653293e44Sflorian 	while((iface = SIMPLEQ_FIRST(&xconf->ra_iface_list)) != NULL) {
116753293e44Sflorian 		SIMPLEQ_REMOVE_HEAD(&xconf->ra_iface_list, entry);
11682ef977c0Sflorian 		free_ra_iface_conf(iface);
116953293e44Sflorian 	}
117053293e44Sflorian 
117153293e44Sflorian 	free(xconf);
117253293e44Sflorian }
1173