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