xref: /openbsd-src/usr.sbin/bgpd/parse.y (revision e3db1f63b9983ca4cf18b686be12853eccdfd031)
1 /*	$OpenBSD: parse.y,v 1.477 2025/01/27 15:22:11 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
5  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
6  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
7  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
8  * Copyright (c) 2016, 2017 Job Snijders <job@openbsd.org>
9  * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org>
10  * Copyright (c) 2017, 2018 Sebastian Benoit <benno@openbsd.org>
11  *
12  * Permission to use, copy, modify, and distribute this software for any
13  * purpose with or without fee is hereby granted, provided that the above
14  * copyright notice and this permission notice appear in all copies.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
17  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
19  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
21  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
22  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23  */
24 
25 %{
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <sys/stat.h>
29 #include <sys/un.h>
30 #include <netinet/in.h>
31 #include <netinet/ip.h>
32 #include <netinet/ip_icmp.h>
33 #include <netinet/ip_ipsp.h>
34 #include <netinet/icmp6.h>
35 #include <arpa/inet.h>
36 
37 #include <ctype.h>
38 #include <endian.h>
39 #include <err.h>
40 #include <unistd.h>
41 #include <errno.h>
42 #include <limits.h>
43 #include <netdb.h>
44 #include <stdarg.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <syslog.h>
49 
50 #include "bgpd.h"
51 #include "session.h"
52 #include "rde.h"
53 #include "log.h"
54 
55 #ifndef nitems
56 #define nitems(_a)	(sizeof((_a)) / sizeof((_a)[0]))
57 #endif
58 
59 #define MACRO_NAME_LEN		128
60 
61 TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
62 static struct file {
63 	TAILQ_ENTRY(file)	 entry;
64 	FILE			*stream;
65 	char			*name;
66 	size_t			 ungetpos;
67 	size_t			 ungetsize;
68 	u_char			*ungetbuf;
69 	int			 eof_reached;
70 	int			 lineno;
71 	int			 errors;
72 } *file, *topfile;
73 struct file	*pushfile(const char *, int);
74 int		 popfile(void);
75 int		 check_file_secrecy(int, const char *);
76 int		 yyparse(void);
77 int		 yylex(void);
78 int		 yyerror(const char *, ...)
79     __attribute__((__format__ (printf, 1, 2)))
80     __attribute__((__nonnull__ (1)));
81 int		 kw_cmp(const void *, const void *);
82 int		 lookup(char *);
83 int		 igetc(void);
84 int		 lgetc(int);
85 void		 lungetc(int);
86 int		 findeol(void);
87 int		 expand_macro(void);
88 
89 TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
90 struct sym {
91 	TAILQ_ENTRY(sym)	 entry;
92 	int			 used;
93 	int			 persist;
94 	char			*nam;
95 	char			*val;
96 };
97 int		 symset(const char *, const char *, int);
98 char		*symget(const char *);
99 
100 struct filter_rib_l {
101 	struct filter_rib_l	*next;
102 	char			 name[PEER_DESCR_LEN];
103 };
104 
105 struct filter_peers_l {
106 	struct filter_peers_l	*next;
107 	struct filter_peers	 p;
108 };
109 
110 struct filter_prefix_l {
111 	struct filter_prefix_l	*next;
112 	struct filter_prefix	 p;
113 };
114 
115 struct filter_prefixlen {
116 	enum comp_ops		op;
117 	int			len_min;
118 	int			len_max;
119 };
120 
121 struct filter_as_l {
122 	struct filter_as_l	*next;
123 	struct filter_as	 a;
124 };
125 
126 struct filter_match_l {
127 	struct filter_match	 m;
128 	struct filter_prefix_l	*prefix_l;
129 	struct filter_as_l	*as_l;
130 	struct filter_prefixset	*prefixset;
131 } fmopts;
132 
133 struct aspa_tas_l {
134 	struct aspa_tas_l	*next;
135 	uint32_t		 as;
136 	uint32_t		 num;
137 };
138 
139 struct flowspec_context {
140 	uint8_t			*components[FLOWSPEC_TYPE_MAX];
141 	uint16_t		 complen[FLOWSPEC_TYPE_MAX];
142 	uint8_t			 aid;
143 	uint8_t			 type;
144 	uint8_t			 addr_type;
145 };
146 
147 struct peer	*alloc_peer(void);
148 struct peer	*new_peer(void);
149 struct peer	*new_group(void);
150 int		 add_mrtconfig(enum mrt_type, char *, int, struct peer *,
151 		    char *);
152 struct rde_rib	*add_rib(char *);
153 struct rde_rib	*find_rib(char *);
154 int		 rib_add_fib(struct rde_rib *, u_int);
155 int		 get_id(struct peer *);
156 int		 merge_prefixspec(struct filter_prefix *,
157 		    struct filter_prefixlen *);
158 int		 expand_rule(struct filter_rule *, struct filter_rib_l *,
159 		    struct filter_peers_l *, struct filter_match_l *,
160 		    struct filter_set_head *);
161 int		 str2key(char *, char *, size_t);
162 int		 neighbor_consistent(struct peer *);
163 int		 merge_filterset(struct filter_set_head *, struct filter_set *);
164 void		 optimize_filters(struct filter_head *);
165 struct filter_rule	*get_rule(enum action_types);
166 
167 int		 parsecommunity(struct community *, int, char *);
168 int		 parseextcommunity(struct community *, char *,
169 		    char *);
170 static int	 new_as_set(char *);
171 static void	 add_as_set(uint32_t);
172 static void	 done_as_set(void);
173 static struct prefixset	*new_prefix_set(char *, int);
174 static void	 add_roa_set(struct prefixset_item *, uint32_t, uint8_t,
175 		    time_t);
176 static struct rtr_config	*get_rtr(struct bgpd_addr *);
177 static int	 insert_rtr(struct rtr_config *);
178 static int	 merge_aspa_set(uint32_t, struct aspa_tas_l *, time_t);
179 static int	 map_tos(char *, int *);
180 static int	 getservice(char *);
181 static int	 parse_flags(char *);
182 static struct flowspec_config	*flow_to_flowspec(struct flowspec_context *);
183 static void	 flow_free(struct flowspec_context *);
184 static int	 push_prefix(struct bgpd_addr *, uint8_t);
185 static int	 push_binop(uint8_t, long long);
186 static int	 push_unary_numop(enum comp_ops, long long);
187 static int	 push_binary_numop(enum comp_ops, long long, long long);
188 static int	 geticmptypebyname(char *, uint8_t);
189 static int	 geticmpcodebyname(u_long, char *, uint8_t);
190 static int	 merge_auth_conf(struct auth_config *, struct auth_config *);
191 
192 static struct bgpd_config	*conf;
193 static struct network_head	*netconf;
194 static struct peer_head		*new_peers, *cur_peers;
195 static struct rtr_config_head	*cur_rtrs;
196 static struct peer		*curpeer;
197 static struct peer		*curgroup;
198 static struct rde_rib		*currib;
199 static struct l3vpn		*curvpn;
200 static struct prefixset		*curpset, *curoset;
201 static struct roa_tree		*curroatree;
202 static struct rtr_config	*currtr;
203 static struct filter_head	*filter_l;
204 static struct filter_head	*peerfilter_l;
205 static struct filter_head	*groupfilter_l;
206 static struct filter_rule	*curpeer_filter[2];
207 static struct filter_rule	*curgroup_filter[2];
208 static struct flowspec_context	*curflow;
209 static int			 noexpires;
210 
211 typedef struct {
212 	union {
213 		long long		 number;
214 		char			*string;
215 		struct bgpd_addr	 addr;
216 		uint8_t			 u8;
217 		struct filter_rib_l	*filter_rib;
218 		struct filter_peers_l	*filter_peers;
219 		struct filter_match_l	 filter_match;
220 		struct filter_prefixset	*filter_prefixset;
221 		struct filter_prefix_l	*filter_prefix;
222 		struct filter_as_l	*filter_as;
223 		struct filter_set	*filter_set;
224 		struct filter_set_head	*filter_set_head;
225 		struct aspa_tas_l	*aspa_elm;
226 		struct {
227 			struct bgpd_addr	prefix;
228 			uint8_t			len;
229 		}			prefix;
230 		struct filter_prefixlen	prefixlen;
231 		struct prefixset_item	*prefixset_item;
232 		struct auth_config	authconf;
233 		struct {
234 			enum auth_enc_alg	enc_alg;
235 			uint8_t			enc_key_len;
236 			char			enc_key[IPSEC_ENC_KEY_LEN];
237 		}			encspec;
238 	} v;
239 	int lineno;
240 } YYSTYPE;
241 
242 %}
243 
244 %token	AS ROUTERID HOLDTIME YMIN LISTEN ON FIBUPDATE FIBPRIORITY RTABLE
245 %token	NONE UNICAST VPN RD EXPORT EXPORTTRGT IMPORTTRGT DEFAULTROUTE
246 %token	RDE RIB EVALUATE IGNORE COMPARE RTR PORT MINVERSION STALETIME
247 %token	GROUP NEIGHBOR NETWORK
248 %token	EBGP IBGP
249 %token	FLOWSPEC PROTO FLAGS FRAGMENT TOS LENGTH ICMPTYPE CODE
250 %token	LOCALAS REMOTEAS DESCR LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART
251 %token	ANNOUNCE REFRESH AS4BYTE CONNECTRETRY ENHANCED ADDPATH EXTENDED
252 %token	SEND RECV PLUS POLICY ROLE GRACEFUL NOTIFICATION MESSAGE
253 %token	DEMOTE ENFORCE NEIGHBORAS ASOVERRIDE REFLECTOR DEPEND DOWN
254 %token	DUMP IN OUT SOCKET RESTRICTED
255 %token	LOG TRANSPARENT FILTERED
256 %token	TCP MD5SIG PASSWORD KEY TTLSECURITY
257 %token	ALLOW DENY MATCH
258 %token	QUICK
259 %token	FROM TO ANY
260 %token	CONNECTED STATIC
261 %token	COMMUNITY EXTCOMMUNITY LARGECOMMUNITY DELETE
262 %token	MAXCOMMUNITIES MAXEXTCOMMUNITIES MAXLARGECOMMUNITIES
263 %token	PREFIX PREFIXLEN PREFIXSET
264 %token	ASPASET ROASET ORIGINSET OVS AVS EXPIRES
265 %token	ASSET SOURCEAS TRANSITAS PEERAS PROVIDERAS CUSTOMERAS MAXASLEN MAXASSEQ
266 %token	SET LOCALPREF MED METRIC NEXTHOP REJECT BLACKHOLE NOMODIFY SELF
267 %token	PREPEND_SELF PREPEND_PEER PFTABLE WEIGHT RTLABEL ORIGIN PRIORITY
268 %token	ERROR INCLUDE
269 %token	IPSEC ESP AH SPI IKE
270 %token	IPV4 IPV6
271 %token	QUALIFY VIA
272 %token	NE LE GE XRANGE LONGER MAXLEN MAX
273 %token	<v.string>		STRING
274 %token	<v.number>		NUMBER
275 %type	<v.number>		asnumber as4number as4number_any optnumber
276 %type	<v.number>		espah af safi restart origincode nettype
277 %type	<v.number>		yesno inout restricted expires
278 %type	<v.number>		yesnoenforce enforce
279 %type	<v.number>		validity aspa_validity
280 %type	<v.number>		addpathextra addpathmax
281 %type	<v.number>		port proto_item tos length flag icmptype
282 %type	<v.string>		string
283 %type	<v.addr>		address
284 %type	<v.prefix>		prefix addrspec
285 %type	<v.prefixset_item>	prefixset_item
286 %type	<v.u8>			action quick direction delete community
287 %type	<v.filter_rib>		filter_rib_h filter_rib_l filter_rib
288 %type	<v.filter_peers>	filter_peer filter_peer_l filter_peer_h
289 %type	<v.filter_match>	filter_match filter_elm filter_match_h
290 %type	<v.filter_as>		filter_as filter_as_l filter_as_h
291 %type	<v.filter_as>		filter_as_t filter_as_t_l filter_as_l_h
292 %type	<v.prefixlen>		prefixlenop
293 %type	<v.filter_set>		filter_set_opt
294 %type	<v.filter_set_head>	filter_set filter_set_l
295 %type	<v.filter_prefix>	filter_prefix filter_prefix_l filter_prefix_h
296 %type	<v.filter_prefix>	filter_prefix_m
297 %type	<v.u8>			unaryop equalityop binaryop filter_as_type
298 %type	<v.authconf>		authconf
299 %type	<v.encspec>		encspec
300 %type	<v.aspa_elm>		aspa_tas aspa_tas_l
301 %%
302 
303 grammar		: /* empty */
304 		| grammar '\n'
305 		| grammar varset '\n'
306 		| grammar include '\n'
307 		| grammar as_set '\n'
308 		| grammar prefixset '\n'
309 		| grammar roa_set '\n'
310 		| grammar aspa_set '\n'
311 		| grammar origin_set '\n'
312 		| grammar rtr '\n'
313 		| grammar rib '\n'
314 		| grammar network '\n'
315 		| grammar flowspec '\n'
316 		| grammar mrtdump '\n'
317 		| grammar conf_main '\n'
318 		| grammar l3vpn '\n'
319 		| grammar neighbor '\n'
320 		| grammar group '\n'
321 		| grammar filterrule '\n'
322 		| grammar error '\n'		{ file->errors++; }
323 		;
324 
325 asnumber	: NUMBER			{
326 			/*
327 			 * According to iana 65535 and 4294967295 are reserved
328 			 * but enforcing this is not duty of the parser.
329 			 */
330 			if ($1 < 0 || $1 > UINT_MAX) {
331 				yyerror("AS too big: max %u", UINT_MAX);
332 				YYERROR;
333 			}
334 		}
335 
336 as4number	: STRING			{
337 			const char	*errstr;
338 			char		*dot;
339 			uint32_t	 uvalh = 0, uval;
340 
341 			if ((dot = strchr($1,'.')) != NULL) {
342 				*dot++ = '\0';
343 				uvalh = strtonum($1, 0, USHRT_MAX, &errstr);
344 				if (errstr) {
345 					yyerror("number %s is %s", $1, errstr);
346 					free($1);
347 					YYERROR;
348 				}
349 				uval = strtonum(dot, 0, USHRT_MAX, &errstr);
350 				if (errstr) {
351 					yyerror("number %s is %s", dot, errstr);
352 					free($1);
353 					YYERROR;
354 				}
355 				free($1);
356 			} else {
357 				yyerror("AS %s is bad", $1);
358 				free($1);
359 				YYERROR;
360 			}
361 			if (uvalh == 0 && (uval == AS_TRANS || uval == 0)) {
362 				yyerror("AS %u is reserved and may not be used",
363 				    uval);
364 				YYERROR;
365 			}
366 			$$ = uval | (uvalh << 16);
367 		}
368 		| asnumber {
369 			if ($1 == AS_TRANS || $1 == 0) {
370 				yyerror("AS %u is reserved and may not be used",
371 				    (uint32_t)$1);
372 				YYERROR;
373 			}
374 			$$ = $1;
375 		}
376 		;
377 
378 as4number_any	: STRING			{
379 			const char	*errstr;
380 			char		*dot;
381 			uint32_t	 uvalh = 0, uval;
382 
383 			if ((dot = strchr($1,'.')) != NULL) {
384 				*dot++ = '\0';
385 				uvalh = strtonum($1, 0, USHRT_MAX, &errstr);
386 				if (errstr) {
387 					yyerror("number %s is %s", $1, errstr);
388 					free($1);
389 					YYERROR;
390 				}
391 				uval = strtonum(dot, 0, USHRT_MAX, &errstr);
392 				if (errstr) {
393 					yyerror("number %s is %s", dot, errstr);
394 					free($1);
395 					YYERROR;
396 				}
397 				free($1);
398 			} else {
399 				yyerror("AS %s is bad", $1);
400 				free($1);
401 				YYERROR;
402 			}
403 			$$ = uval | (uvalh << 16);
404 		}
405 		| asnumber {
406 			$$ = $1;
407 		}
408 		;
409 
410 string		: string STRING			{
411 			if (asprintf(&$$, "%s %s", $1, $2) == -1)
412 				fatal("string: asprintf");
413 			free($1);
414 			free($2);
415 		}
416 		| STRING
417 		;
418 
419 yesno		: STRING			{
420 			if (!strcmp($1, "yes"))
421 				$$ = 1;
422 			else if (!strcmp($1, "no"))
423 				$$ = 0;
424 			else {
425 				yyerror("syntax error, "
426 				    "either yes or no expected");
427 				free($1);
428 				YYERROR;
429 			}
430 			free($1);
431 		}
432 		;
433 
434 varset		: STRING '=' string		{
435 			char *s = $1;
436 			if (strlen($1) >= MACRO_NAME_LEN) {
437 				yyerror("macro name to long, max %d characters",
438 				    MACRO_NAME_LEN - 1);
439 				free($1);
440 				free($3);
441 				YYERROR;
442 			}
443 			do {
444 				if (isalnum((unsigned char)*s) || *s == '_')
445 					continue;
446 				yyerror("macro name can only contain "
447 					    "alphanumerics and '_'");
448 				free($1);
449 				free($3);
450 				YYERROR;
451 			} while (*++s);
452 
453 			if (cmd_opts & BGPD_OPT_VERBOSE)
454 				printf("%s = \"%s\"\n", $1, $3);
455 			if (symset($1, $3, 0) == -1)
456 				fatal("cannot store variable");
457 			free($1);
458 			free($3);
459 		}
460 		;
461 
462 include		: INCLUDE STRING		{
463 			struct file	*nfile;
464 
465 			if ((nfile = pushfile($2, 1)) == NULL) {
466 				yyerror("failed to include file %s", $2);
467 				free($2);
468 				YYERROR;
469 			}
470 			free($2);
471 
472 			file = nfile;
473 			lungetc('\n');
474 		}
475 		;
476 
477 as_set		: ASSET STRING '{' optnl	{
478 			if (strlen($2) >= SET_NAME_LEN) {
479 				yyerror("as-set name %s too long", $2);
480 				free($2);
481 				YYERROR;
482 			}
483 			if (new_as_set($2) != 0) {
484 				free($2);
485 				YYERROR;
486 			}
487 			free($2);
488 		} as_set_l optnl '}' {
489 			done_as_set();
490 		}
491 		| ASSET STRING '{' optnl '}'	{
492 			if (new_as_set($2) != 0) {
493 				free($2);
494 				YYERROR;
495 			}
496 			free($2);
497 		}
498 
499 as_set_l	: as4number_any			{ add_as_set($1); }
500 		| as_set_l comma as4number_any	{ add_as_set($3); }
501 
502 prefixset	: PREFIXSET STRING '{' optnl		{
503 			if ((curpset = new_prefix_set($2, 0)) == NULL) {
504 				free($2);
505 				YYERROR;
506 			}
507 			free($2);
508 		} prefixset_l optnl '}'			{
509 			SIMPLEQ_INSERT_TAIL(&conf->prefixsets, curpset, entry);
510 			curpset = NULL;
511 		}
512 		| PREFIXSET STRING '{' optnl '}'	{
513 			if ((curpset = new_prefix_set($2, 0)) == NULL) {
514 				free($2);
515 				YYERROR;
516 			}
517 			free($2);
518 			SIMPLEQ_INSERT_TAIL(&conf->prefixsets, curpset, entry);
519 			curpset = NULL;
520 		}
521 
522 prefixset_l	: prefixset_item			{
523 			struct prefixset_item	*psi;
524 			if ($1->p.op != OP_NONE)
525 				curpset->sflags |= PREFIXSET_FLAG_OPS;
526 			psi = RB_INSERT(prefixset_tree, &curpset->psitems, $1);
527 			if (psi != NULL) {
528 				if (cmd_opts & BGPD_OPT_VERBOSE2)
529 					log_warnx("warning: duplicate entry in "
530 					    "prefixset \"%s\" for %s/%u",
531 					    curpset->name,
532 					    log_addr(&$1->p.addr), $1->p.len);
533 				free($1);
534 			}
535 		}
536 		| prefixset_l comma prefixset_item	{
537 			struct prefixset_item	*psi;
538 			if ($3->p.op != OP_NONE)
539 				curpset->sflags |= PREFIXSET_FLAG_OPS;
540 			psi = RB_INSERT(prefixset_tree, &curpset->psitems, $3);
541 			if (psi != NULL) {
542 				if (cmd_opts & BGPD_OPT_VERBOSE2)
543 					log_warnx("warning: duplicate entry in "
544 					    "prefixset \"%s\" for %s/%u",
545 					    curpset->name,
546 					    log_addr(&$3->p.addr), $3->p.len);
547 				free($3);
548 			}
549 		}
550 		;
551 
552 prefixset_item	: prefix prefixlenop			{
553 			if ($2.op != OP_NONE && $2.op != OP_RANGE) {
554 				yyerror("unsupported prefixlen operation in "
555 				    "prefix-set");
556 				YYERROR;
557 			}
558 			if (($$ = calloc(1, sizeof(*$$))) == NULL)
559 				fatal(NULL);
560 			memcpy(&$$->p.addr, &$1.prefix, sizeof($$->p.addr));
561 			$$->p.len = $1.len;
562 			if (merge_prefixspec(&$$->p, &$2) == -1) {
563 				free($$);
564 				YYERROR;
565 			}
566 		}
567 		;
568 
569 roa_set		: ROASET '{' optnl		{
570 			curroatree = &conf->roa;
571 		} roa_set_l optnl '}'			{
572 			curroatree = NULL;
573 		}
574 		| ROASET '{' optnl '}'		/* nothing */
575 		;
576 
577 origin_set	: ORIGINSET STRING '{' optnl		{
578 			if ((curoset = new_prefix_set($2, 1)) == NULL) {
579 				free($2);
580 				YYERROR;
581 			}
582 			curroatree = &curoset->roaitems;
583 			noexpires = 1;
584 			free($2);
585 		} roa_set_l optnl '}'			{
586 			SIMPLEQ_INSERT_TAIL(&conf->originsets, curoset, entry);
587 			curoset = NULL;
588 			curroatree = NULL;
589 			noexpires = 0;
590 		}
591 		| ORIGINSET STRING '{' optnl '}'		{
592 			if ((curoset = new_prefix_set($2, 1)) == NULL) {
593 				free($2);
594 				YYERROR;
595 			}
596 			free($2);
597 			SIMPLEQ_INSERT_TAIL(&conf->originsets, curoset, entry);
598 			curoset = NULL;
599 			curroatree = NULL;
600 		}
601 		;
602 
603 expires		: /* empty */	{
604 			$$ = 0;
605 		}
606 		| EXPIRES NUMBER	{
607 			if (noexpires) {
608 				yyerror("syntax error, expires not allowed");
609 				YYERROR;
610 			}
611 			$$ = $2;
612 		}
613 
614 roa_set_l	: prefixset_item SOURCEAS as4number_any	expires		{
615 			if ($1->p.len_min != $1->p.len) {
616 				yyerror("unsupported prefixlen operation in "
617 				    "roa-set");
618 				free($1);
619 				YYERROR;
620 			}
621 			add_roa_set($1, $3, $1->p.len_max, $4);
622 			free($1);
623 		}
624 		| roa_set_l comma prefixset_item SOURCEAS as4number_any	expires {
625 			if ($3->p.len_min != $3->p.len) {
626 				yyerror("unsupported prefixlen operation in "
627 				    "roa-set");
628 				free($3);
629 				YYERROR;
630 			}
631 			add_roa_set($3, $5, $3->p.len_max, $6);
632 			free($3);
633 		}
634 		;
635 
636 aspa_set	: ASPASET '{' optnl aspa_set_l optnl '}'
637 		| ASPASET '{' optnl '}'
638 		;
639 
640 aspa_set_l	: aspa_elm
641 		| aspa_set_l comma aspa_elm
642 		;
643 
644 aspa_elm	: CUSTOMERAS as4number expires PROVIDERAS '{' optnl
645 		    aspa_tas_l optnl '}' {
646 			int rv;
647 			struct aspa_tas_l *a, *n;
648 
649 			rv = merge_aspa_set($2, $7, $3);
650 
651 			for (a = $7; a != NULL; a = n) {
652 				n = a->next;
653 				free(a);
654 			}
655 
656 			if (rv == -1)
657 				YYERROR;
658 		}
659 		;
660 
661 aspa_tas_l	: aspa_tas			{ $$ = $1; }
662 		| aspa_tas_l comma aspa_tas	{
663 			$3->next = $1;
664 			$3->num = $1->num + 1;
665 			$$ = $3;
666 		}
667 		;
668 
669 aspa_tas	: as4number_any {
670 			if (($$ = calloc(1, sizeof(*$$))) == NULL)
671 				fatal(NULL);
672 			$$->as = $1;
673 			$$->num = 1;
674 		}
675 		| as4number_any af {
676 			if (($$ = calloc(1, sizeof(*$$))) == NULL)
677 				fatal(NULL);
678 			$$->as = $1;
679 			$$->num = 1;
680 		}
681 		;
682 
683 rtr		: RTR address	{
684 			currtr = get_rtr(&$2);
685 			currtr->remote_port = RTR_PORT;
686 			if (insert_rtr(currtr) == -1) {
687 				free(currtr);
688 				YYERROR;
689 			}
690 			currtr = NULL;
691 		}
692 		| RTR address	{
693 			currtr = get_rtr(&$2);
694 			currtr->remote_port = RTR_PORT;
695 		} '{' optnl rtropt_l optnl '}' {
696 			if (insert_rtr(currtr) == -1) {
697 				free(currtr);
698 				YYERROR;
699 			}
700 			currtr = NULL;
701 		}
702 		;
703 
704 rtropt_l	: rtropt
705 		| rtropt_l optnl rtropt
706 		;
707 
708 rtropt		: DESCR STRING		{
709 			if (strlcpy(currtr->descr, $2,
710 			    sizeof(currtr->descr)) >=
711 			    sizeof(currtr->descr)) {
712 				yyerror("descr \"%s\" too long: max %zu",
713 				    $2, sizeof(currtr->descr) - 1);
714 				free($2);
715 				YYERROR;
716 			}
717 			free($2);
718 		}
719 		| LOCALADDR address	{
720 			if ($2.aid != currtr->remote_addr.aid) {
721 				yyerror("Bad address family %s for "
722 				    "local-addr", aid2str($2.aid));
723 				YYERROR;
724 			}
725 			currtr->local_addr = $2;
726 		}
727 		| PORT port {
728 			currtr->remote_port = $2;
729 		}
730 		| MINVERSION NUMBER {
731 			if ($2 < 0 || $2 > RTR_MAX_VERSION) {
732 				yyerror("min-version must be between %u and %u",
733 				    0, RTR_MAX_VERSION);
734 				YYERROR;
735 			}
736 			currtr->min_version = $2;
737 		}
738 		| authconf {
739 			if (merge_auth_conf(&currtr->auth, &$1) == 0)
740 				YYERROR;
741 		}
742 		;
743 
744 conf_main	: AS as4number		{
745 			conf->as = $2;
746 			if ($2 > USHRT_MAX)
747 				conf->short_as = AS_TRANS;
748 			else
749 				conf->short_as = $2;
750 		}
751 		| AS as4number asnumber {
752 			conf->as = $2;
753 			conf->short_as = $3;
754 		}
755 		| ROUTERID address		{
756 			if ($2.aid != AID_INET) {
757 				yyerror("router-id must be an IPv4 address");
758 				YYERROR;
759 			}
760 			conf->bgpid = ntohl($2.v4.s_addr);
761 		}
762 		| HOLDTIME NUMBER	{
763 			if ($2 < MIN_HOLDTIME || $2 > USHRT_MAX) {
764 				yyerror("holdtime must be between %u and %u",
765 				    MIN_HOLDTIME, USHRT_MAX);
766 				YYERROR;
767 			}
768 			conf->holdtime = $2;
769 		}
770 		| HOLDTIME YMIN NUMBER	{
771 			if ($3 < MIN_HOLDTIME || $3 > USHRT_MAX) {
772 				yyerror("holdtime must be between %u and %u",
773 				    MIN_HOLDTIME, USHRT_MAX);
774 				YYERROR;
775 			}
776 			conf->min_holdtime = $3;
777 		}
778 		| STALETIME NUMBER	{
779 			if ($2 < MIN_HOLDTIME || $2 > USHRT_MAX) {
780 				yyerror("staletime must be between %u and %u",
781 				    MIN_HOLDTIME, USHRT_MAX);
782 				YYERROR;
783 			}
784 			conf->staletime = $2;
785 		}
786 		| LISTEN ON address	{
787 			struct listen_addr	*la;
788 			struct sockaddr		*sa;
789 
790 			if ((la = calloc(1, sizeof(struct listen_addr))) ==
791 			    NULL)
792 				fatal("parse conf_main listen on calloc");
793 
794 			la->fd = -1;
795 			la->reconf = RECONF_REINIT;
796 			sa = addr2sa(&$3, BGP_PORT, &la->sa_len);
797 			memcpy(&la->sa, sa, la->sa_len);
798 			TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry);
799 		}
800 		| LISTEN ON address PORT port	{
801 			struct listen_addr	*la;
802 			struct sockaddr		*sa;
803 
804 			if ((la = calloc(1, sizeof(struct listen_addr))) ==
805 			    NULL)
806 				fatal("parse conf_main listen on calloc");
807 
808 			la->fd = -1;
809 			la->reconf = RECONF_REINIT;
810 			sa = addr2sa(&$3, $5, &la->sa_len);
811 			memcpy(&la->sa, sa, la->sa_len);
812 			TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry);
813 		}
814 		| FIBPRIORITY NUMBER		{
815 			if (!kr_check_prio($2)) {
816 				yyerror("fib-priority %lld out of range", $2);
817 				YYERROR;
818 			}
819 			conf->fib_priority = $2;
820 		}
821 		| FIBUPDATE yesno		{
822 			struct rde_rib *rr;
823 			rr = find_rib("Loc-RIB");
824 			if (rr == NULL)
825 				fatalx("RTABLE cannot find the main RIB!");
826 
827 			if ($2 == 0)
828 				rr->flags |= F_RIB_NOFIBSYNC;
829 			else
830 				rr->flags &= ~F_RIB_NOFIBSYNC;
831 		}
832 		| TRANSPARENT yesno	{
833 			if ($2 == 1)
834 				conf->flags |= BGPD_FLAG_DECISION_TRANS_AS;
835 			else
836 				conf->flags &= ~BGPD_FLAG_DECISION_TRANS_AS;
837 		}
838 		| REJECT ASSET yesno	{
839 			if ($3 == 1)
840 				conf->flags &= ~BGPD_FLAG_PERMIT_AS_SET;
841 			else
842 				conf->flags |= BGPD_FLAG_PERMIT_AS_SET;
843 		}
844 		| LOG STRING		{
845 			if (!strcmp($2, "updates"))
846 				conf->log |= BGPD_LOG_UPDATES;
847 			else {
848 				free($2);
849 				YYERROR;
850 			}
851 			free($2);
852 		}
853 		| DUMP STRING STRING optnumber		{
854 			int action;
855 
856 			if ($4 < 0 || $4 > INT_MAX) {
857 				yyerror("bad timeout");
858 				free($2);
859 				free($3);
860 				YYERROR;
861 			}
862 			if (!strcmp($2, "table"))
863 				action = MRT_TABLE_DUMP;
864 			else if (!strcmp($2, "table-mp"))
865 				action = MRT_TABLE_DUMP_MP;
866 			else if (!strcmp($2, "table-v2"))
867 				action = MRT_TABLE_DUMP_V2;
868 			else {
869 				yyerror("unknown mrt dump type");
870 				free($2);
871 				free($3);
872 				YYERROR;
873 			}
874 			free($2);
875 			if (add_mrtconfig(action, $3, $4, NULL, NULL) == -1) {
876 				free($3);
877 				YYERROR;
878 			}
879 			free($3);
880 		}
881 		| DUMP RIB STRING STRING STRING optnumber		{
882 			int action;
883 
884 			if ($6 < 0 || $6 > INT_MAX) {
885 				yyerror("bad timeout");
886 				free($3);
887 				free($4);
888 				free($5);
889 				YYERROR;
890 			}
891 			if (!strcmp($4, "table"))
892 				action = MRT_TABLE_DUMP;
893 			else if (!strcmp($4, "table-mp"))
894 				action = MRT_TABLE_DUMP_MP;
895 			else if (!strcmp($4, "table-v2"))
896 				action = MRT_TABLE_DUMP_V2;
897 			else {
898 				yyerror("unknown mrt dump type");
899 				free($3);
900 				free($4);
901 				free($5);
902 				YYERROR;
903 			}
904 			free($4);
905 			if (add_mrtconfig(action, $5, $6, NULL, $3) == -1) {
906 				free($3);
907 				free($5);
908 				YYERROR;
909 			}
910 			free($3);
911 			free($5);
912 		}
913 		| RDE STRING EVALUATE		{
914 			if (!strcmp($2, "route-age"))
915 				conf->flags |= BGPD_FLAG_DECISION_ROUTEAGE;
916 			else {
917 				yyerror("unknown route decision type");
918 				free($2);
919 				YYERROR;
920 			}
921 			free($2);
922 		}
923 		| RDE STRING IGNORE		{
924 			if (!strcmp($2, "route-age"))
925 				conf->flags &= ~BGPD_FLAG_DECISION_ROUTEAGE;
926 			else {
927 				yyerror("unknown route decision type");
928 				free($2);
929 				YYERROR;
930 			}
931 			free($2);
932 		}
933 		| RDE MED COMPARE STRING	{
934 			if (!strcmp($4, "always"))
935 				conf->flags |= BGPD_FLAG_DECISION_MED_ALWAYS;
936 			else if (!strcmp($4, "strict"))
937 				conf->flags &= ~BGPD_FLAG_DECISION_MED_ALWAYS;
938 			else {
939 				yyerror("rde med compare: "
940 				    "unknown setting \"%s\"", $4);
941 				free($4);
942 				YYERROR;
943 			}
944 			free($4);
945 		}
946 		| RDE EVALUATE STRING {
947 			if (!strcmp($3, "all"))
948 				conf->flags |= BGPD_FLAG_DECISION_ALL_PATHS;
949 			else if (!strcmp($3, "default"))
950 				conf->flags &= ~BGPD_FLAG_DECISION_ALL_PATHS;
951 			else {
952 				yyerror("rde evaluate: "
953 				    "unknown setting \"%s\"", $3);
954 				free($3);
955 				YYERROR;
956 			}
957 			free($3);
958 		}
959 		| RDE RIB STRING INCLUDE FILTERED {
960 			if (strcmp($3, "Loc-RIB") != 0) {
961 				yyerror("include filtered only supported in "
962 				    "Loc-RIB");
963 				YYERROR;
964 			}
965 			conf->filtered_in_locrib = 1;
966 		}
967 		| NEXTHOP QUALIFY VIA STRING	{
968 			if (!strcmp($4, "bgp"))
969 				conf->flags |= BGPD_FLAG_NEXTHOP_BGP;
970 			else if (!strcmp($4, "default"))
971 				conf->flags |= BGPD_FLAG_NEXTHOP_DEFAULT;
972 			else {
973 				yyerror("nexthop depend on: "
974 				    "unknown setting \"%s\"", $4);
975 				free($4);
976 				YYERROR;
977 			}
978 			free($4);
979 		}
980 		| RTABLE NUMBER {
981 			struct rde_rib *rr;
982 			if ($2 > RT_TABLEID_MAX) {
983 				yyerror("rtable %llu too big: max %u", $2,
984 				    RT_TABLEID_MAX);
985 				YYERROR;
986 			}
987 			if (!ktable_exists($2, NULL)) {
988 				yyerror("rtable id %lld does not exist", $2);
989 				YYERROR;
990 			}
991 			rr = find_rib("Loc-RIB");
992 			if (rr == NULL)
993 				fatalx("RTABLE cannot find the main RIB!");
994 			rr->rtableid = $2;
995 		}
996 		| CONNECTRETRY NUMBER {
997 			if ($2 > USHRT_MAX || $2 < 1) {
998 				yyerror("invalid connect-retry");
999 				YYERROR;
1000 			}
1001 			conf->connectretry = $2;
1002 		}
1003 		| SOCKET STRING	restricted {
1004 			if (strlen($2) >=
1005 			    sizeof(((struct sockaddr_un *)0)->sun_path)) {
1006 				yyerror("socket path too long");
1007 				YYERROR;
1008 			}
1009 			if ($3) {
1010 				free(conf->rcsock);
1011 				conf->rcsock = $2;
1012 			} else {
1013 				free(conf->csock);
1014 				conf->csock = $2;
1015 			}
1016 		}
1017 		;
1018 
1019 rib		: RDE RIB STRING {
1020 			if ((currib = add_rib($3)) == NULL) {
1021 				free($3);
1022 				YYERROR;
1023 			}
1024 			free($3);
1025 		} ribopts {
1026 			currib = NULL;
1027 		}
1028 
1029 ribopts		: fibupdate
1030 		| RTABLE NUMBER fibupdate {
1031 			if ($2 > RT_TABLEID_MAX) {
1032 				yyerror("rtable %llu too big: max %u", $2,
1033 				    RT_TABLEID_MAX);
1034 				YYERROR;
1035 			}
1036 			if (rib_add_fib(currib, $2) == -1)
1037 				YYERROR;
1038 		}
1039 		| yesno EVALUATE {
1040 			if ($1) {
1041 				yyerror("bad rde rib definition");
1042 				YYERROR;
1043 			}
1044 			currib->flags |= F_RIB_NOEVALUATE;
1045 		}
1046 		;
1047 
1048 fibupdate	: /* empty */
1049 		| FIBUPDATE yesno {
1050 			if ($2 == 0)
1051 				currib->flags |= F_RIB_NOFIBSYNC;
1052 			else
1053 				currib->flags &= ~F_RIB_NOFIBSYNC;
1054 		}
1055 		;
1056 
1057 mrtdump		: DUMP STRING inout STRING optnumber	{
1058 			int action;
1059 
1060 			if ($5 < 0 || $5 > INT_MAX) {
1061 				yyerror("bad timeout");
1062 				free($2);
1063 				free($4);
1064 				YYERROR;
1065 			}
1066 			if (!strcmp($2, "all"))
1067 				action = $3 ? MRT_ALL_IN : MRT_ALL_OUT;
1068 			else if (!strcmp($2, "updates"))
1069 				action = $3 ? MRT_UPDATE_IN : MRT_UPDATE_OUT;
1070 			else {
1071 				yyerror("unknown mrt msg dump type");
1072 				free($2);
1073 				free($4);
1074 				YYERROR;
1075 			}
1076 			if (add_mrtconfig(action, $4, $5, curpeer, NULL) ==
1077 			    -1) {
1078 				free($2);
1079 				free($4);
1080 				YYERROR;
1081 			}
1082 			free($2);
1083 			free($4);
1084 		}
1085 		;
1086 
1087 network		: NETWORK prefix filter_set	{
1088 			struct network	*n, *m;
1089 
1090 			if ((n = calloc(1, sizeof(struct network))) == NULL)
1091 				fatal("new_network");
1092 			memcpy(&n->net.prefix, &$2.prefix,
1093 			    sizeof(n->net.prefix));
1094 			n->net.prefixlen = $2.len;
1095 			filterset_move($3, &n->net.attrset);
1096 			free($3);
1097 			TAILQ_FOREACH(m, netconf, entry) {
1098 				if (n->net.type == m->net.type &&
1099 				    n->net.prefixlen == m->net.prefixlen &&
1100 				    prefix_compare(&n->net.prefix,
1101 				    &m->net.prefix, n->net.prefixlen) == 0)
1102 					yyerror("duplicate prefix "
1103 					    "in network statement");
1104 			}
1105 
1106 			TAILQ_INSERT_TAIL(netconf, n, entry);
1107 		}
1108 		| NETWORK PREFIXSET STRING filter_set	{
1109 			struct prefixset *ps;
1110 			struct network	*n;
1111 			if ((ps = find_prefixset($3, &conf->prefixsets))
1112 			    == NULL) {
1113 				yyerror("prefix-set '%s' not defined", $3);
1114 				free($3);
1115 				filterset_free($4);
1116 				free($4);
1117 				YYERROR;
1118 			}
1119 			if (ps->sflags & PREFIXSET_FLAG_OPS) {
1120 				yyerror("prefix-set %s has prefixlen operators "
1121 				    "and cannot be used in network statements.",
1122 				    ps->name);
1123 				free($3);
1124 				filterset_free($4);
1125 				free($4);
1126 				YYERROR;
1127 			}
1128 			if ((n = calloc(1, sizeof(struct network))) == NULL)
1129 				fatal("new_network");
1130 			strlcpy(n->net.psname, ps->name, sizeof(n->net.psname));
1131 			filterset_move($4, &n->net.attrset);
1132 			n->net.type = NETWORK_PREFIXSET;
1133 			TAILQ_INSERT_TAIL(netconf, n, entry);
1134 			free($3);
1135 			free($4);
1136 		}
1137 		| NETWORK af RTLABEL STRING filter_set	{
1138 			struct network	*n;
1139 
1140 			if ((n = calloc(1, sizeof(struct network))) == NULL)
1141 				fatal("new_network");
1142 			if (afi2aid($2, SAFI_UNICAST, &n->net.prefix.aid) ==
1143 			    -1) {
1144 				yyerror("unknown address family");
1145 				filterset_free($5);
1146 				free($5);
1147 				YYERROR;
1148 			}
1149 			n->net.type = NETWORK_RTLABEL;
1150 			n->net.rtlabel = rtlabel_name2id($4);
1151 			filterset_move($5, &n->net.attrset);
1152 			free($5);
1153 
1154 			TAILQ_INSERT_TAIL(netconf, n, entry);
1155 		}
1156 		| NETWORK af PRIORITY NUMBER filter_set	{
1157 			struct network	*n;
1158 			if (!kr_check_prio($4)) {
1159 				yyerror("priority %lld out of range", $4);
1160 				YYERROR;
1161 			}
1162 
1163 			if ((n = calloc(1, sizeof(struct network))) == NULL)
1164 				fatal("new_network");
1165 			if (afi2aid($2, SAFI_UNICAST, &n->net.prefix.aid) ==
1166 			    -1) {
1167 				yyerror("unknown address family");
1168 				filterset_free($5);
1169 				free($5);
1170 				YYERROR;
1171 			}
1172 			n->net.type = NETWORK_PRIORITY;
1173 			n->net.priority = $4;
1174 			filterset_move($5, &n->net.attrset);
1175 			free($5);
1176 
1177 			TAILQ_INSERT_TAIL(netconf, n, entry);
1178 		}
1179 		| NETWORK af nettype filter_set	{
1180 			struct network	*n;
1181 
1182 			if ((n = calloc(1, sizeof(struct network))) == NULL)
1183 				fatal("new_network");
1184 			if (afi2aid($2, SAFI_UNICAST, &n->net.prefix.aid) ==
1185 			    -1) {
1186 				yyerror("unknown address family");
1187 				filterset_free($4);
1188 				free($4);
1189 				YYERROR;
1190 			}
1191 			n->net.type = $3 ? NETWORK_STATIC : NETWORK_CONNECTED;
1192 			filterset_move($4, &n->net.attrset);
1193 			free($4);
1194 
1195 			TAILQ_INSERT_TAIL(netconf, n, entry);
1196 		}
1197 		;
1198 
1199 flowspec	: FLOWSPEC af {
1200 			if ((curflow = calloc(1, sizeof(*curflow))) == NULL)
1201 				fatal("new_flowspec");
1202 			curflow->aid = $2;
1203 		} flow_rules filter_set {
1204 			struct flowspec_config *f;
1205 
1206 			f = flow_to_flowspec(curflow);
1207 			if (f == NULL) {
1208 				yyerror("out of memory");
1209 				free($5);
1210 				flow_free(curflow);
1211 				curflow = NULL;
1212 				YYERROR;
1213 			}
1214 			filterset_move($5, &f->attrset);
1215 			free($5);
1216 			flow_free(curflow);
1217 			curflow = NULL;
1218 
1219 			if (RB_INSERT(flowspec_tree, &conf->flowspecs, f) !=
1220 			    NULL) {
1221 				yyerror("duplicate flowspec definition");
1222 				flowspec_free(f);
1223 				YYERROR;
1224 			}
1225 		}
1226 		;
1227 
1228 proto		: PROTO proto_item
1229 		| PROTO '{' optnl proto_list optnl '}'
1230 		;
1231 
1232 proto_list	: proto_item				{
1233 			curflow->type = FLOWSPEC_TYPE_PROTO;
1234 			if (push_unary_numop(OP_EQ, $1) == -1)
1235 				YYERROR;
1236 		}
1237 		| proto_list comma proto_item		{
1238 			curflow->type = FLOWSPEC_TYPE_PROTO;
1239 			if (push_unary_numop(OP_EQ, $3) == -1)
1240 				YYERROR;
1241 		}
1242 		;
1243 
1244 proto_item	: STRING				{
1245 			struct protoent *p;
1246 
1247 			p = getprotobyname($1);
1248 			if (p == NULL) {
1249 				yyerror("unknown protocol %s", $1);
1250 				free($1);
1251 				YYERROR;
1252 			}
1253 			$$ = p->p_proto;
1254 			free($1);
1255 		}
1256 		| NUMBER				{
1257 			if ($1 < 0 || $1 > 255) {
1258 				yyerror("protocol outside range");
1259 				YYERROR;
1260 			}
1261 			$$ = $1;
1262 		}
1263 		;
1264 
1265 from		: FROM {
1266 			curflow->type = FLOWSPEC_TYPE_SRC_PORT;
1267 			curflow->addr_type = FLOWSPEC_TYPE_SOURCE;
1268 		} ipportspec
1269 		;
1270 
1271 to		: TO {
1272 			curflow->type = FLOWSPEC_TYPE_DST_PORT;
1273 			curflow->addr_type = FLOWSPEC_TYPE_DEST;
1274 		} ipportspec
1275 		;
1276 
1277 ipportspec	: ipspec
1278 		| ipspec PORT portspec
1279 		| PORT portspec
1280 		;
1281 
1282 ipspec		: ANY
1283 		| prefix			{
1284 			if (push_prefix(&$1.prefix, $1.len) == -1)
1285 				YYERROR;
1286 		}
1287 		;
1288 
1289 portspec	: port_item
1290 		| '{' optnl port_list optnl '}'
1291 		;
1292 
1293 port_list	: port_item
1294 		| port_list comma port_item
1295 		;
1296 
1297 port_item	: port				{
1298 			if (push_unary_numop(OP_EQ, $1) == -1)
1299 				YYERROR;
1300 		}
1301 		| unaryop port			{
1302 			if (push_unary_numop($1, $2) == -1)
1303 				YYERROR;
1304 		}
1305 		| port binaryop port		{
1306 			if (push_binary_numop($2, $1, $3))
1307 				YYERROR;
1308 		}
1309 		;
1310 
1311 port		: NUMBER			{
1312 			if ($1 < 1 || $1 > USHRT_MAX) {
1313 				yyerror("port must be between %u and %u",
1314 				    1, USHRT_MAX);
1315 				YYERROR;
1316 			}
1317 			$$ = $1;
1318 		}
1319 		| STRING			{
1320 			if (($$ = getservice($1)) == -1) {
1321 				yyerror("unknown port '%s'", $1);
1322 				free($1);
1323 				YYERROR;
1324 			}
1325 			free($1);
1326 		}
1327 		;
1328 
1329 flow_rules	: /* empty */
1330 		| flow_rules_l
1331 		;
1332 
1333 flow_rules_l	: flowrule
1334 		| flow_rules_l flowrule
1335 		;
1336 
1337 flowrule	: from
1338 		| to
1339 		| FLAGS {
1340 			curflow->type = FLOWSPEC_TYPE_TCP_FLAGS;
1341 		} flags
1342 		| FRAGMENT {
1343 			curflow->type = FLOWSPEC_TYPE_FRAG;
1344 		} flags;
1345 		| icmpspec
1346 		| LENGTH lengthspec {
1347 			curflow->type = FLOWSPEC_TYPE_PKT_LEN;
1348 		}
1349 		| proto
1350 		| TOS tos {
1351 			curflow->type = FLOWSPEC_TYPE_DSCP;
1352 			if (push_unary_numop(OP_EQ, $2 >> 2) == -1)
1353 				YYERROR;
1354 		}
1355 		;
1356 
1357 flags		: flag '/' flag			{
1358 			if (($1 & $3) != $1) {
1359 				yyerror("bad flag combination, "
1360 				    "check bit not in mask");
1361 				YYERROR;
1362 			}
1363 			if (push_binop(FLOWSPEC_OP_BIT_MATCH, $1) == -1)
1364 				YYERROR;
1365 			/* check if extra mask op is needed */
1366 			if ($3 & ~$1) {
1367 				if (push_binop(FLOWSPEC_OP_BIT_NOT |
1368 				    FLOWSPEC_OP_AND, $3 & ~$1) == -1)
1369 					YYERROR;
1370 			}
1371 		}
1372 		| '/' flag			{
1373 			if (push_binop(FLOWSPEC_OP_BIT_NOT, $2) == -1)
1374 				YYERROR;
1375 		}
1376 		| flag				{
1377 			if (push_binop(0, $1) == -1)
1378 				YYERROR;
1379 		}
1380 		| ANY		/* nothing */
1381 		;
1382 
1383 flag		: STRING {
1384 			if (($$ = parse_flags($1)) < 0) {
1385 				yyerror("bad flags %s", $1);
1386 				free($1);
1387 				YYERROR;
1388 			}
1389 			free($1);
1390 		}
1391 		;
1392 
1393 icmpspec	: ICMPTYPE icmp_item
1394 		| ICMPTYPE '{' optnl icmp_list optnl '}'
1395 		;
1396 
1397 icmp_list	: icmp_item
1398 		| icmp_list comma icmp_item
1399 		;
1400 
1401 icmp_item	: icmptype			{
1402 			curflow->type = FLOWSPEC_TYPE_ICMP_TYPE;
1403 			if (push_unary_numop(OP_EQ, $1) == -1)
1404 				YYERROR;
1405 		}
1406 		| icmptype CODE STRING {
1407 			int code;
1408 
1409 			if ((code = geticmpcodebyname($1, $3, curflow->aid)) ==
1410 			    -1) {
1411 				yyerror("unknown icmp-code %s", $3);
1412 				free($3);
1413 				YYERROR;
1414 			}
1415 			free($3);
1416 
1417 			curflow->type = FLOWSPEC_TYPE_ICMP_TYPE;
1418 			if (push_unary_numop(OP_EQ, $1) == -1)
1419 				YYERROR;
1420 			curflow->type = FLOWSPEC_TYPE_ICMP_CODE;
1421 			if (push_unary_numop(OP_EQ, code) == -1)
1422 				YYERROR;
1423 		}
1424 		| icmptype CODE NUMBER {
1425 			if ($3 < 0 || $3 > 255) {
1426 				yyerror("illegal icmp-code %lld", $3);
1427 				YYERROR;
1428 			}
1429 			curflow->type = FLOWSPEC_TYPE_ICMP_TYPE;
1430 			if (push_unary_numop(OP_EQ, $1) == -1)
1431 				YYERROR;
1432 			curflow->type = FLOWSPEC_TYPE_ICMP_CODE;
1433 			if (push_unary_numop(OP_EQ, $3) == -1)
1434 				YYERROR;
1435 		}
1436 		;
1437 
1438 icmptype        : STRING {
1439 			int type;
1440 
1441 			if ((type = geticmptypebyname($1, curflow->aid)) ==
1442 			    -1) {
1443 				yyerror("unknown icmp-type %s", $1);
1444 				free($1);
1445 				YYERROR;
1446 			}
1447 			$$ = type;
1448 			free($1);
1449 		}
1450 		| NUMBER {
1451 			if ($1 < 0 || $1 > 255) {
1452 				yyerror("illegal icmp-type %lld", $1);
1453 				YYERROR;
1454 			}
1455 			$$ = $1;
1456 		}
1457 		;
1458 
1459 tos		: STRING		{
1460 			int val;
1461 			char *end;
1462 
1463 			if (map_tos($1, &val))
1464 				$$ = val;
1465 			else if ($1[0] == '0' && $1[1] == 'x') {
1466 				errno = 0;
1467 				$$ = strtoul($1, &end, 16);
1468 				if (errno || *end != '\0')
1469 					$$ = 256;
1470 			} else
1471 				$$ = 256;
1472 			if ($$ < 0 || $$ > 255) {
1473 				yyerror("illegal tos value %s", $1);
1474 				free($1);
1475 				YYERROR;
1476 			}
1477 			free($1);
1478 		}
1479 		| NUMBER		{
1480 			if ($$ < 0 || $$ > 255) {
1481 				yyerror("illegal tos value %lld", $1);
1482 				YYERROR;
1483 			}
1484 			$$ = $1;
1485 		}
1486 		;
1487 
1488 lengthspec	: length_item
1489 		| '{' optnl length_list optnl '}'
1490 		;
1491 
1492 length_list	: length_item
1493 		| length_list comma length_item
1494 		;
1495 
1496 length_item	: length			{
1497 			if (push_unary_numop(OP_EQ, $1) == -1)
1498 				YYERROR;
1499 		}
1500 		| unaryop length		{
1501 			if (push_unary_numop($1, $2) == -1)
1502 				YYERROR;
1503 		}
1504 		| length binaryop length	{
1505 			if (push_binary_numop($2, $1, $3) == -1)
1506 				YYERROR;
1507 		}
1508 		;
1509 
1510 length		: NUMBER			{
1511 			if ($$ < 0 || $$ > USHRT_MAX) {
1512 				yyerror("illegal ptk length value %lld", $1);
1513 				YYERROR;
1514 			}
1515 			$$ = $1;
1516 		}
1517 
1518 inout		: IN		{ $$ = 1; }
1519 		| OUT		{ $$ = 0; }
1520 		;
1521 
1522 restricted	: /* empty */	{ $$ = 0; }
1523 		| RESTRICTED	{ $$ = 1; }
1524 		;
1525 
1526 address		: STRING		{
1527 			uint8_t	len;
1528 
1529 			if (!host($1, &$$, &len)) {
1530 				yyerror("could not parse address spec \"%s\"",
1531 				    $1);
1532 				free($1);
1533 				YYERROR;
1534 			}
1535 			free($1);
1536 
1537 			if (($$.aid == AID_INET && len != 32) ||
1538 			    ($$.aid == AID_INET6 && len != 128)) {
1539 				/* unreachable */
1540 				yyerror("got prefixlen %u, expected %u",
1541 				    len, $$.aid == AID_INET ? 32 : 128);
1542 				YYERROR;
1543 			}
1544 		}
1545 		;
1546 
1547 prefix		: STRING '/' NUMBER	{
1548 			char	*s;
1549 			if ($3 < 0 || $3 > 128) {
1550 				yyerror("bad prefixlen %lld", $3);
1551 				free($1);
1552 				YYERROR;
1553 			}
1554 			if (asprintf(&s, "%s/%lld", $1, $3) == -1)
1555 				fatal(NULL);
1556 			free($1);
1557 
1558 			if (!host(s, &$$.prefix, &$$.len)) {
1559 				yyerror("could not parse address \"%s\"", s);
1560 				free(s);
1561 				YYERROR;
1562 			}
1563 			free(s);
1564 		}
1565 		| NUMBER '/' NUMBER	{
1566 			char	*s;
1567 
1568 			/* does not match IPv6 */
1569 			if ($1 < 0 || $1 > 255 || $3 < 0 || $3 > 32) {
1570 				yyerror("bad prefix %lld/%lld", $1, $3);
1571 				YYERROR;
1572 			}
1573 			if (asprintf(&s, "%lld/%lld", $1, $3) == -1)
1574 				fatal(NULL);
1575 
1576 			if (!host(s, &$$.prefix, &$$.len)) {
1577 				yyerror("could not parse address \"%s\"", s);
1578 				free(s);
1579 				YYERROR;
1580 			}
1581 			free(s);
1582 		}
1583 		;
1584 
1585 addrspec	: address	{
1586 			memcpy(&$$.prefix, &$1, sizeof(struct bgpd_addr));
1587 			if ($$.prefix.aid == AID_INET)
1588 				$$.len = 32;
1589 			else
1590 				$$.len = 128;
1591 		}
1592 		| prefix
1593 		;
1594 
1595 optnumber	: /* empty */		{ $$ = 0; }
1596 		| NUMBER
1597 		;
1598 
1599 l3vpn		: VPN STRING ON STRING			{
1600 			u_int rdomain, label;
1601 
1602 			if (get_mpe_config($4, &rdomain, &label) == -1) {
1603 				if ((cmd_opts & BGPD_OPT_NOACTION) == 0) {
1604 					yyerror("troubles getting config of %s",
1605 					    $4);
1606 					free($4);
1607 					free($2);
1608 					YYERROR;
1609 				}
1610 			}
1611 
1612 			if (!(curvpn = calloc(1, sizeof(struct l3vpn))))
1613 				fatal(NULL);
1614 			strlcpy(curvpn->ifmpe, $4, IFNAMSIZ);
1615 
1616 			if (strlcpy(curvpn->descr, $2,
1617 			    sizeof(curvpn->descr)) >=
1618 			    sizeof(curvpn->descr)) {
1619 				yyerror("descr \"%s\" too long: max %zu",
1620 				    $2, sizeof(curvpn->descr) - 1);
1621 				free($2);
1622 				free($4);
1623 				free(curvpn);
1624 				curvpn = NULL;
1625 				YYERROR;
1626 			}
1627 			free($2);
1628 			free($4);
1629 
1630 			TAILQ_INIT(&curvpn->import);
1631 			TAILQ_INIT(&curvpn->export);
1632 			TAILQ_INIT(&curvpn->net_l);
1633 			curvpn->label = label;
1634 			curvpn->rtableid = rdomain;
1635 			netconf = &curvpn->net_l;
1636 		} '{' l3vpnopts_l '}'	{
1637 			/* insert into list */
1638 			SIMPLEQ_INSERT_TAIL(&conf->l3vpns, curvpn, entry);
1639 			curvpn = NULL;
1640 			netconf = &conf->networks;
1641 		}
1642 		;
1643 
1644 l3vpnopts_l	: /* empty */
1645 		| l3vpnopts_l '\n'
1646 		| l3vpnopts_l l3vpnopts '\n'
1647 		| l3vpnopts_l error '\n'
1648 		;
1649 
1650 l3vpnopts	: RD STRING {
1651 			struct community	ext;
1652 
1653 			memset(&ext, 0, sizeof(ext));
1654 			if (parseextcommunity(&ext, "rt", $2) == -1) {
1655 				free($2);
1656 				YYERROR;
1657 			}
1658 			free($2);
1659 			/*
1660 			 * RD is almost encoded like an ext-community,
1661 			 * but only almost so convert here.
1662 			 */
1663 			if (community_to_rd(&ext, &curvpn->rd) == -1) {
1664 				yyerror("bad encoding of rd");
1665 				YYERROR;
1666 			}
1667 		}
1668 		| EXPORTTRGT STRING STRING	{
1669 			struct filter_set	*set;
1670 
1671 			if ((set = calloc(1, sizeof(struct filter_set))) ==
1672 			    NULL)
1673 				fatal(NULL);
1674 			set->type = ACTION_SET_COMMUNITY;
1675 			if (parseextcommunity(&set->action.community,
1676 			    $2, $3) == -1) {
1677 				free($3);
1678 				free($2);
1679 				free(set);
1680 				YYERROR;
1681 			}
1682 			free($3);
1683 			free($2);
1684 			TAILQ_INSERT_TAIL(&curvpn->export, set, entry);
1685 		}
1686 		| IMPORTTRGT STRING STRING	{
1687 			struct filter_set	*set;
1688 
1689 			if ((set = calloc(1, sizeof(struct filter_set))) ==
1690 			    NULL)
1691 				fatal(NULL);
1692 			set->type = ACTION_SET_COMMUNITY;
1693 			if (parseextcommunity(&set->action.community,
1694 			    $2, $3) == -1) {
1695 				free($3);
1696 				free($2);
1697 				free(set);
1698 				YYERROR;
1699 			}
1700 			free($3);
1701 			free($2);
1702 			TAILQ_INSERT_TAIL(&curvpn->import, set, entry);
1703 		}
1704 		| FIBUPDATE yesno		{
1705 			if ($2 == 0)
1706 				curvpn->flags |= F_RIB_NOFIBSYNC;
1707 			else
1708 				curvpn->flags &= ~F_RIB_NOFIBSYNC;
1709 		}
1710 		| network
1711 		;
1712 
1713 neighbor	: { curpeer = new_peer(); }
1714 		    NEIGHBOR addrspec {
1715 			memcpy(&curpeer->conf.remote_addr, &$3.prefix,
1716 			    sizeof(curpeer->conf.remote_addr));
1717 			curpeer->conf.remote_masklen = $3.len;
1718 			if (($3.prefix.aid == AID_INET && $3.len != 32) ||
1719 			    ($3.prefix.aid == AID_INET6 && $3.len != 128))
1720 				curpeer->conf.template = 1;
1721 			curpeer->conf.capabilities.mp[
1722 			    curpeer->conf.remote_addr.aid] = 1;
1723 			if (get_id(curpeer)) {
1724 				yyerror("get_id failed");
1725 				YYERROR;
1726 			}
1727 		}
1728 		    peeropts_h {
1729 			if (curpeer_filter[0] != NULL)
1730 				TAILQ_INSERT_TAIL(peerfilter_l,
1731 				    curpeer_filter[0], entry);
1732 			if (curpeer_filter[1] != NULL)
1733 				TAILQ_INSERT_TAIL(peerfilter_l,
1734 				    curpeer_filter[1], entry);
1735 			curpeer_filter[0] = NULL;
1736 			curpeer_filter[1] = NULL;
1737 
1738 			if (neighbor_consistent(curpeer) == -1) {
1739 				free(curpeer);
1740 				YYERROR;
1741 			}
1742 			if (RB_INSERT(peer_head, new_peers, curpeer) != NULL)
1743 				fatalx("%s: peer tree is corrupt", __func__);
1744 			curpeer = curgroup;
1745 		}
1746 		;
1747 
1748 group		: GROUP string			{
1749 			curgroup = curpeer = new_group();
1750 			if (strlcpy(curgroup->conf.group, $2,
1751 			    sizeof(curgroup->conf.group)) >=
1752 			    sizeof(curgroup->conf.group)) {
1753 				yyerror("group name \"%s\" too long: max %zu",
1754 				    $2, sizeof(curgroup->conf.group) - 1);
1755 				free($2);
1756 				free(curgroup);
1757 				YYERROR;
1758 			}
1759 			free($2);
1760 			if (get_id(curgroup)) {
1761 				yyerror("get_id failed");
1762 				free(curgroup);
1763 				YYERROR;
1764 			}
1765 		} '{' groupopts_l '}'		{
1766 			if (curgroup_filter[0] != NULL)
1767 				TAILQ_INSERT_TAIL(groupfilter_l,
1768 				    curgroup_filter[0], entry);
1769 			if (curgroup_filter[1] != NULL)
1770 				TAILQ_INSERT_TAIL(groupfilter_l,
1771 				    curgroup_filter[1], entry);
1772 			curgroup_filter[0] = NULL;
1773 			curgroup_filter[1] = NULL;
1774 
1775 			free(curgroup);
1776 			curgroup = NULL;
1777 		}
1778 		;
1779 
1780 groupopts_l	: /* empty */
1781 		| groupopts_l '\n'
1782 		| groupopts_l peeropts '\n'
1783 		| groupopts_l neighbor '\n'
1784 		| groupopts_l error '\n'
1785 		;
1786 
1787 addpathextra	: /* empty */		{ $$ = 0; }
1788 		| PLUS NUMBER		{
1789 			if ($2 < 1 || $2 > USHRT_MAX) {
1790 				yyerror("additional paths must be between "
1791 				    "%u and %u", 1, USHRT_MAX);
1792 				YYERROR;
1793 			}
1794 			$$ = $2;
1795 		}
1796 		;
1797 
1798 addpathmax	: /* empty */		{ $$ = 0; }
1799 		| MAX NUMBER		{
1800 			if ($2 < 1 || $2 > USHRT_MAX) {
1801 				yyerror("maximum additional paths must be "
1802 				    "between %u and %u", 1, USHRT_MAX);
1803 				YYERROR;
1804 			}
1805 			$$ = $2;
1806 		}
1807 		;
1808 
1809 peeropts_h	: '{' '\n' peeropts_l '}'
1810 		| '{' peeropts '}'
1811 		| /* empty */
1812 		;
1813 
1814 peeropts_l	: /* empty */
1815 		| peeropts_l '\n'
1816 		| peeropts_l peeropts '\n'
1817 		| peeropts_l error '\n'
1818 		;
1819 
1820 peeropts	: REMOTEAS as4number	{
1821 			curpeer->conf.remote_as = $2;
1822 		}
1823 		| LOCALAS as4number	{
1824 			curpeer->conf.local_as = $2;
1825 			if ($2 > USHRT_MAX)
1826 				curpeer->conf.local_short_as = AS_TRANS;
1827 			else
1828 				curpeer->conf.local_short_as = $2;
1829 		}
1830 		| LOCALAS as4number asnumber {
1831 			curpeer->conf.local_as = $2;
1832 			curpeer->conf.local_short_as = $3;
1833 		}
1834 		| DESCR string		{
1835 			if (strlcpy(curpeer->conf.descr, $2,
1836 			    sizeof(curpeer->conf.descr)) >=
1837 			    sizeof(curpeer->conf.descr)) {
1838 				yyerror("descr \"%s\" too long: max %zu",
1839 				    $2, sizeof(curpeer->conf.descr) - 1);
1840 				free($2);
1841 				YYERROR;
1842 			}
1843 			free($2);
1844 		}
1845 		| LOCALADDR address	{
1846 			if ($2.aid == AID_INET)
1847 				memcpy(&curpeer->conf.local_addr_v4, &$2,
1848 				    sizeof(curpeer->conf.local_addr_v4));
1849 			else if ($2.aid == AID_INET6)
1850 				memcpy(&curpeer->conf.local_addr_v6, &$2,
1851 				    sizeof(curpeer->conf.local_addr_v6));
1852 			else {
1853 				yyerror("Unsupported address family %s for "
1854 				    "local-addr", aid2str($2.aid));
1855 				YYERROR;
1856 			}
1857 		}
1858 		| yesno LOCALADDR	{
1859 			if ($1) {
1860 				yyerror("bad local-address definition");
1861 				YYERROR;
1862 			}
1863 			memset(&curpeer->conf.local_addr_v4, 0,
1864 			    sizeof(curpeer->conf.local_addr_v4));
1865 			memset(&curpeer->conf.local_addr_v6, 0,
1866 			    sizeof(curpeer->conf.local_addr_v6));
1867 		}
1868 		| MULTIHOP NUMBER	{
1869 			if ($2 < 2 || $2 > 255) {
1870 				yyerror("invalid multihop distance %lld", $2);
1871 				YYERROR;
1872 			}
1873 			curpeer->conf.distance = $2;
1874 		}
1875 		| PASSIVE		{
1876 			curpeer->conf.passive = 1;
1877 		}
1878 		| DOWN			{
1879 			curpeer->conf.down = 1;
1880 		}
1881 		| DOWN STRING		{
1882 			curpeer->conf.down = 1;
1883 			if (strlcpy(curpeer->conf.reason, $2,
1884 				sizeof(curpeer->conf.reason)) >=
1885 				sizeof(curpeer->conf.reason)) {
1886 				    yyerror("shutdown reason too long");
1887 				    free($2);
1888 				    YYERROR;
1889 			}
1890 			free($2);
1891 		}
1892 		| RIB STRING	{
1893 			if (!find_rib($2)) {
1894 				yyerror("rib \"%s\" does not exist.", $2);
1895 				free($2);
1896 				YYERROR;
1897 			}
1898 			if (strlcpy(curpeer->conf.rib, $2,
1899 			    sizeof(curpeer->conf.rib)) >=
1900 			    sizeof(curpeer->conf.rib)) {
1901 				yyerror("rib name \"%s\" too long: max %zu",
1902 				    $2, sizeof(curpeer->conf.rib) - 1);
1903 				free($2);
1904 				YYERROR;
1905 			}
1906 			free($2);
1907 		}
1908 		| HOLDTIME NUMBER	{
1909 			if ($2 < MIN_HOLDTIME || $2 > USHRT_MAX) {
1910 				yyerror("holdtime must be between %u and %u",
1911 				    MIN_HOLDTIME, USHRT_MAX);
1912 				YYERROR;
1913 			}
1914 			curpeer->conf.holdtime = $2;
1915 		}
1916 		| HOLDTIME YMIN NUMBER	{
1917 			if ($3 < MIN_HOLDTIME || $3 > USHRT_MAX) {
1918 				yyerror("holdtime must be between %u and %u",
1919 				    MIN_HOLDTIME, USHRT_MAX);
1920 				YYERROR;
1921 			}
1922 			curpeer->conf.min_holdtime = $3;
1923 		}
1924 		| STALETIME NUMBER	{
1925 			if ($2 < MIN_HOLDTIME || $2 > USHRT_MAX) {
1926 				yyerror("staletime must be between %u and %u",
1927 				    MIN_HOLDTIME, USHRT_MAX);
1928 				YYERROR;
1929 			}
1930 			curpeer->conf.staletime = $2;
1931 		}
1932 		| ANNOUNCE af safi enforce {
1933 			uint8_t		aid, safi;
1934 			uint16_t	afi;
1935 
1936 			if ($3 == SAFI_NONE) {
1937 				for (aid = AID_MIN; aid < AID_MAX; aid++) {
1938 					if (aid2afi(aid, &afi, &safi) == -1 ||
1939 					    afi != $2)
1940 						continue;
1941 					curpeer->conf.capabilities.mp[aid] = 0;
1942 				}
1943 			} else {
1944 				if (afi2aid($2, $3, &aid) == -1) {
1945 					yyerror("unknown AFI/SAFI pair");
1946 					YYERROR;
1947 				}
1948 				if ($4)
1949 					curpeer->conf.capabilities.mp[aid] = 2;
1950 				else
1951 					curpeer->conf.capabilities.mp[aid] = 1;
1952 			}
1953 		}
1954 		| ANNOUNCE REFRESH yesnoenforce {
1955 			curpeer->conf.capabilities.refresh = $3;
1956 		}
1957 		| ANNOUNCE ENHANCED REFRESH yesnoenforce {
1958 			curpeer->conf.capabilities.enhanced_rr = $4;
1959 		}
1960 		| ANNOUNCE RESTART yesnoenforce {
1961 			curpeer->conf.capabilities.grestart.restart = $3;
1962 		}
1963 		| ANNOUNCE GRACEFUL NOTIFICATION yesno {
1964 			curpeer->conf.capabilities.grestart.grnotification = $4;
1965 		}
1966 		| ANNOUNCE AS4BYTE yesnoenforce {
1967 			curpeer->conf.capabilities.as4byte = $3;
1968 		}
1969 		| ANNOUNCE ADDPATH RECV yesnoenforce {
1970 			int8_t *ap = curpeer->conf.capabilities.add_path;
1971 			uint8_t i;
1972 
1973 			for (i = AID_MIN; i < AID_MAX; i++) {
1974 				if ($4) {
1975 					if ($4 == 2)
1976 						ap[i] |= CAPA_AP_RECV_ENFORCE;
1977 					ap[i] |= CAPA_AP_RECV;
1978 				} else
1979 					ap[i] &= ~CAPA_AP_RECV;
1980 			}
1981 		}
1982 		| ANNOUNCE ADDPATH SEND STRING addpathextra addpathmax enforce {
1983 			int8_t *ap = curpeer->conf.capabilities.add_path;
1984 			enum addpath_mode mode;
1985 			u_int8_t i;
1986 
1987 			if (!strcmp($4, "no")) {
1988 				free($4);
1989 				if ($5 != 0 || $6 != 0 || $7 != 0) {
1990 					yyerror("no additional option allowed "
1991 					    "for 'add-path send no'");
1992 					YYERROR;
1993 				}
1994 				mode = ADDPATH_EVAL_NONE;
1995 			} else if (!strcmp($4, "all")) {
1996 				free($4);
1997 				if ($5 != 0 || $6 != 0) {
1998 					yyerror("no additional option allowed "
1999 					    "for 'add-path send all'");
2000 					YYERROR;
2001 				}
2002 				mode = ADDPATH_EVAL_ALL;
2003 			} else if (!strcmp($4, "best")) {
2004 				free($4);
2005 				mode = ADDPATH_EVAL_BEST;
2006 			} else if (!strcmp($4, "ecmp")) {
2007 				free($4);
2008 				mode = ADDPATH_EVAL_ECMP;
2009 			} else if (!strcmp($4, "as-wide-best")) {
2010 				free($4);
2011 				mode = ADDPATH_EVAL_AS_WIDE;
2012 			} else {
2013 				yyerror("announce add-path send: "
2014 				    "unknown mode \"%s\"", $4);
2015 				free($4);
2016 				YYERROR;
2017 			}
2018 			for (i = AID_MIN; i < AID_MAX; i++) {
2019 				if (mode != ADDPATH_EVAL_NONE) {
2020 					if ($7)
2021 						ap[i] |= CAPA_AP_SEND_ENFORCE;
2022 					ap[i] |= CAPA_AP_SEND;
2023 				} else
2024 					ap[i] &= ~CAPA_AP_SEND;
2025 			}
2026 			curpeer->conf.eval.mode = mode;
2027 			curpeer->conf.eval.extrapaths = $5;
2028 			curpeer->conf.eval.maxpaths = $6;
2029 		}
2030 		| ANNOUNCE POLICY yesnoenforce {
2031 			curpeer->conf.capabilities.policy = $3;
2032 		}
2033 		| ANNOUNCE EXTENDED MESSAGE yesnoenforce {
2034 			curpeer->conf.capabilities.ext_msg = $4;
2035 		}
2036 		| ANNOUNCE EXTENDED NEXTHOP yesnoenforce {
2037 			curpeer->conf.capabilities.ext_nh[AID_VPN_IPv4] =
2038 			    curpeer->conf.capabilities.ext_nh[AID_INET] = $4;
2039 		}
2040 		| ROLE STRING {
2041 			if (strcmp($2, "provider") == 0) {
2042 				curpeer->conf.role = ROLE_PROVIDER;
2043 			} else if (strcmp($2, "rs") == 0) {
2044 				curpeer->conf.role = ROLE_RS;
2045 			} else if (strcmp($2, "rs-client") == 0) {
2046 				curpeer->conf.role = ROLE_RS_CLIENT;
2047 			} else if (strcmp($2, "customer") == 0) {
2048 				curpeer->conf.role = ROLE_CUSTOMER;
2049 			} else if (strcmp($2, "peer") == 0) {
2050 				curpeer->conf.role = ROLE_PEER;
2051 			} else {
2052 				yyerror("syntax error, one of none, provider, "
2053 				    "rs, rs-client, customer, peer expected");
2054 				free($2);
2055 				YYERROR;
2056 			}
2057 			free($2);
2058 		}
2059 		| ROLE NONE {
2060 			curpeer->conf.role = ROLE_NONE;
2061 		}
2062 		| EXPORT NONE {
2063 			curpeer->conf.export_type = EXPORT_NONE;
2064 		}
2065 		| EXPORT DEFAULTROUTE {
2066 			curpeer->conf.export_type = EXPORT_DEFAULT_ROUTE;
2067 		}
2068 		| ENFORCE NEIGHBORAS yesno {
2069 			if ($3)
2070 				curpeer->conf.enforce_as = ENFORCE_AS_ON;
2071 			else
2072 				curpeer->conf.enforce_as = ENFORCE_AS_OFF;
2073 		}
2074 		| ENFORCE LOCALAS yesno {
2075 			if ($3)
2076 				curpeer->conf.enforce_local_as = ENFORCE_AS_ON;
2077 			else
2078 				curpeer->conf.enforce_local_as = ENFORCE_AS_OFF;
2079 		}
2080 		| ASOVERRIDE yesno {
2081 			if ($2) {
2082 				struct filter_rule	*r;
2083 				struct filter_set	*s;
2084 
2085 				if ((s = calloc(1, sizeof(struct filter_set)))
2086 				    == NULL)
2087 					fatal(NULL);
2088 				s->type = ACTION_SET_AS_OVERRIDE;
2089 
2090 				r = get_rule(s->type);
2091 				if (merge_filterset(&r->set, s) == -1)
2092 					YYERROR;
2093 			}
2094 		}
2095 		| MAXPREFIX NUMBER restart {
2096 			if ($2 < 0 || $2 > UINT_MAX) {
2097 				yyerror("bad maximum number of prefixes");
2098 				YYERROR;
2099 			}
2100 			curpeer->conf.max_prefix = $2;
2101 			curpeer->conf.max_prefix_restart = $3;
2102 		}
2103 		| MAXPREFIX NUMBER OUT restart {
2104 			if ($2 < 0 || $2 > UINT_MAX) {
2105 				yyerror("bad maximum number of prefixes");
2106 				YYERROR;
2107 			}
2108 			curpeer->conf.max_out_prefix = $2;
2109 			curpeer->conf.max_out_prefix_restart = $4;
2110 		}
2111 		| authconf {
2112 			if (merge_auth_conf(&curpeer->auth_conf, &$1) == 0)
2113 				YYERROR;
2114 		}
2115 		| TTLSECURITY yesno	{
2116 			curpeer->conf.ttlsec = $2;
2117 		}
2118 		| SET filter_set_opt	{
2119 			struct filter_rule	*r;
2120 
2121 			r = get_rule($2->type);
2122 			if (merge_filterset(&r->set, $2) == -1)
2123 				YYERROR;
2124 		}
2125 		| SET '{' optnl filter_set_l optnl '}'	{
2126 			struct filter_rule	*r;
2127 			struct filter_set	*s;
2128 
2129 			while ((s = TAILQ_FIRST($4)) != NULL) {
2130 				TAILQ_REMOVE($4, s, entry);
2131 				r = get_rule(s->type);
2132 				if (merge_filterset(&r->set, s) == -1)
2133 					YYERROR;
2134 			}
2135 			free($4);
2136 		}
2137 		| mrtdump
2138 		| REFLECTOR		{
2139 			if ((conf->flags & BGPD_FLAG_REFLECTOR) &&
2140 			    conf->clusterid != 0) {
2141 				yyerror("only one route reflector "
2142 				    "cluster allowed");
2143 				YYERROR;
2144 			}
2145 			conf->flags |= BGPD_FLAG_REFLECTOR;
2146 			curpeer->conf.reflector_client = 1;
2147 		}
2148 		| REFLECTOR address	{
2149 			if ($2.aid != AID_INET) {
2150 				yyerror("route reflector cluster-id must be "
2151 				    "an IPv4 address");
2152 				YYERROR;
2153 			}
2154 			if ((conf->flags & BGPD_FLAG_REFLECTOR) &&
2155 			    conf->clusterid != ntohl($2.v4.s_addr)) {
2156 				yyerror("only one route reflector "
2157 				    "cluster allowed");
2158 				YYERROR;
2159 			}
2160 			conf->flags |= BGPD_FLAG_REFLECTOR;
2161 			curpeer->conf.reflector_client = 1;
2162 			conf->clusterid = ntohl($2.v4.s_addr);
2163 		}
2164 		| DEPEND ON STRING	{
2165 			if (strlcpy(curpeer->conf.if_depend, $3,
2166 			    sizeof(curpeer->conf.if_depend)) >=
2167 			    sizeof(curpeer->conf.if_depend)) {
2168 				yyerror("interface name \"%s\" too long: "
2169 				    "max %zu", $3,
2170 				    sizeof(curpeer->conf.if_depend) - 1);
2171 				free($3);
2172 				YYERROR;
2173 			}
2174 			free($3);
2175 		}
2176 		| DEMOTE STRING		{
2177 			if (strlcpy(curpeer->conf.demote_group, $2,
2178 			    sizeof(curpeer->conf.demote_group)) >=
2179 			    sizeof(curpeer->conf.demote_group)) {
2180 				yyerror("demote group name \"%s\" too long: "
2181 				    "max %zu", $2,
2182 				    sizeof(curpeer->conf.demote_group) - 1);
2183 				free($2);
2184 				YYERROR;
2185 			}
2186 			free($2);
2187 			if (carp_demote_init(curpeer->conf.demote_group,
2188 			    cmd_opts & BGPD_OPT_FORCE_DEMOTE) == -1) {
2189 				yyerror("error initializing group \"%s\"",
2190 				    curpeer->conf.demote_group);
2191 				YYERROR;
2192 			}
2193 		}
2194 		| TRANSPARENT yesno	{
2195 			if ($2 == 1)
2196 				curpeer->conf.flags |= PEERFLAG_TRANS_AS;
2197 			else
2198 				curpeer->conf.flags &= ~PEERFLAG_TRANS_AS;
2199 		}
2200 		| LOG STRING		{
2201 			if (!strcmp($2, "updates"))
2202 				curpeer->conf.flags |= PEERFLAG_LOG_UPDATES;
2203 			else if (!strcmp($2, "no"))
2204 				curpeer->conf.flags &= ~PEERFLAG_LOG_UPDATES;
2205 			else {
2206 				free($2);
2207 				YYERROR;
2208 			}
2209 			free($2);
2210 		}
2211 		| REJECT ASSET yesno	{
2212 			if ($3 == 1)
2213 				curpeer->conf.flags &= ~PEERFLAG_PERMIT_AS_SET;
2214 			else
2215 				curpeer->conf.flags |= PEERFLAG_PERMIT_AS_SET;
2216 		}
2217 		| PORT port {
2218 			curpeer->conf.remote_port = $2;
2219 		}
2220 		| RDE EVALUATE STRING {
2221 			if (!strcmp($3, "all"))
2222 				curpeer->conf.flags |= PEERFLAG_EVALUATE_ALL;
2223 			else if (!strcmp($3, "default"))
2224 				curpeer->conf.flags &= ~PEERFLAG_EVALUATE_ALL;
2225 			else {
2226 				yyerror("rde evaluate: "
2227 				    "unknown setting \"%s\"", $3);
2228 				free($3);
2229 				YYERROR;
2230 			}
2231 			free($3);
2232 		}
2233 		;
2234 
2235 restart		: /* nada */		{ $$ = 0; }
2236 		| RESTART NUMBER	{
2237 			if ($2 < 1 || $2 > USHRT_MAX) {
2238 				yyerror("restart out of range. 1 to %u minutes",
2239 				    USHRT_MAX);
2240 				YYERROR;
2241 			}
2242 			$$ = $2;
2243 		}
2244 		;
2245 
2246 af		: IPV4	{ $$ = AFI_IPv4; }
2247 		| IPV6	{ $$ = AFI_IPv6; }
2248 		;
2249 
2250 safi		: NONE		{ $$ = SAFI_NONE; }
2251 		| UNICAST	{ $$ = SAFI_UNICAST; }
2252 		| VPN		{ $$ = SAFI_MPLSVPN; }
2253 		| FLOWSPEC	{ $$ = SAFI_FLOWSPEC; }
2254 		;
2255 
2256 nettype		: STATIC	{ $$ = 1; }
2257 		| CONNECTED	{ $$ = 0; }
2258 		;
2259 
2260 authconf	: TCP MD5SIG PASSWORD string {
2261 			memset(&$$, 0, sizeof($$));
2262 			if (strlcpy($$.md5key, $4, sizeof($$.md5key)) >=
2263 			    sizeof($$.md5key)) {
2264 				yyerror("tcp md5sig password too long: max %zu",
2265 				    sizeof($$.md5key) - 1);
2266 				free($4);
2267 				YYERROR;
2268 			}
2269 			$$.method = AUTH_MD5SIG;
2270 			$$.md5key_len = strlen($4);
2271 			free($4);
2272 		}
2273 		| TCP MD5SIG KEY string {
2274 			memset(&$$, 0, sizeof($$));
2275 			if (str2key($4, $$.md5key, sizeof($$.md5key)) == -1) {
2276 				free($4);
2277 				YYERROR;
2278 			}
2279 			$$.method = AUTH_MD5SIG;
2280 			$$.md5key_len = strlen($4) / 2;
2281 			free($4);
2282 		}
2283 		| IPSEC espah IKE {
2284 			memset(&$$, 0, sizeof($$));
2285 			if ($2)
2286 				$$.method = AUTH_IPSEC_IKE_ESP;
2287 			else
2288 				$$.method = AUTH_IPSEC_IKE_AH;
2289 		}
2290 		| IPSEC espah inout SPI NUMBER STRING STRING encspec {
2291 			enum auth_alg	auth_alg;
2292 			uint8_t		keylen;
2293 
2294 			memset(&$$, 0, sizeof($$));
2295 			if (!strcmp($6, "sha1")) {
2296 				auth_alg = AUTH_AALG_SHA1HMAC;
2297 				keylen = 20;
2298 			} else if (!strcmp($6, "md5")) {
2299 				auth_alg = AUTH_AALG_MD5HMAC;
2300 				keylen = 16;
2301 			} else {
2302 				yyerror("unknown auth algorithm \"%s\"", $6);
2303 				free($6);
2304 				free($7);
2305 				YYERROR;
2306 			}
2307 			free($6);
2308 
2309 			if (strlen($7) / 2 != keylen) {
2310 				yyerror("auth key len: must be %u bytes, "
2311 				    "is %zu bytes", keylen, strlen($7) / 2);
2312 				free($7);
2313 				YYERROR;
2314 			}
2315 
2316 			if ($2)
2317 				$$.method = AUTH_IPSEC_MANUAL_ESP;
2318 			else {
2319 				if ($8.enc_alg) {
2320 					yyerror("\"ipsec ah\" doesn't take "
2321 					    "encryption keys");
2322 					free($7);
2323 					YYERROR;
2324 				}
2325 				$$.method = AUTH_IPSEC_MANUAL_AH;
2326 			}
2327 
2328 			if ($5 <= SPI_RESERVED_MAX || $5 > UINT_MAX) {
2329 				yyerror("bad spi number %lld", $5);
2330 				free($7);
2331 				YYERROR;
2332 			}
2333 
2334 			if ($3 == 1) {
2335 				if (str2key($7, $$.auth_key_in,
2336 				    sizeof($$.auth_key_in)) == -1) {
2337 					free($7);
2338 					YYERROR;
2339 				}
2340 				$$.spi_in = $5;
2341 				$$.auth_alg_in = auth_alg;
2342 				$$.enc_alg_in = $8.enc_alg;
2343 				memcpy(&$$.enc_key_in, &$8.enc_key,
2344 				    sizeof($$.enc_key_in));
2345 				$$.enc_keylen_in = $8.enc_key_len;
2346 				$$.auth_keylen_in = keylen;
2347 			} else {
2348 				if (str2key($7, $$.auth_key_out,
2349 				    sizeof($$.auth_key_out)) == -1) {
2350 					free($7);
2351 					YYERROR;
2352 				}
2353 				$$.spi_out = $5;
2354 				$$.auth_alg_out = auth_alg;
2355 				$$.enc_alg_out = $8.enc_alg;
2356 				memcpy(&$$.enc_key_out, &$8.enc_key,
2357 				    sizeof($$.enc_key_out));
2358 				$$.enc_keylen_out = $8.enc_key_len;
2359 				$$.auth_keylen_out = keylen;
2360 			}
2361 			free($7);
2362 		}
2363 		;
2364 
2365 espah		: ESP		{ $$ = 1; }
2366 		| AH		{ $$ = 0; }
2367 		;
2368 
2369 encspec		: /* nada */	{
2370 			memset(&$$, 0, sizeof($$));
2371 		}
2372 		| STRING STRING {
2373 			memset(&$$, 0, sizeof($$));
2374 			if (!strcmp($1, "3des") || !strcmp($1, "3des-cbc")) {
2375 				$$.enc_alg = AUTH_EALG_3DESCBC;
2376 				$$.enc_key_len = 21; /* XXX verify */
2377 			} else if (!strcmp($1, "aes") ||
2378 			    !strcmp($1, "aes-128-cbc")) {
2379 				$$.enc_alg = AUTH_EALG_AES;
2380 				$$.enc_key_len = 16;
2381 			} else {
2382 				yyerror("unknown enc algorithm \"%s\"", $1);
2383 				free($1);
2384 				free($2);
2385 				YYERROR;
2386 			}
2387 			free($1);
2388 
2389 			if (strlen($2) / 2 != $$.enc_key_len) {
2390 				yyerror("enc key length wrong: should be %u "
2391 				    "bytes, is %zu bytes",
2392 				    $$.enc_key_len * 2, strlen($2));
2393 				free($2);
2394 				YYERROR;
2395 			}
2396 
2397 			if (str2key($2, $$.enc_key, sizeof($$.enc_key)) == -1) {
2398 				free($2);
2399 				YYERROR;
2400 			}
2401 			free($2);
2402 		}
2403 		;
2404 
2405 filterrule	: action quick filter_rib_h direction filter_peer_h
2406 				filter_match_h filter_set
2407 		{
2408 			struct filter_rule	 r;
2409 			struct filter_rib_l	 *rb, *rbnext;
2410 
2411 			memset(&r, 0, sizeof(r));
2412 			r.action = $1;
2413 			r.quick = $2;
2414 			r.dir = $4;
2415 			if ($3) {
2416 				if (r.dir != DIR_IN) {
2417 					yyerror("rib only allowed on \"from\" "
2418 					    "rules.");
2419 
2420 					for (rb = $3; rb != NULL; rb = rbnext) {
2421 						rbnext = rb->next;
2422 						free(rb);
2423 					}
2424 					YYERROR;
2425 				}
2426 			}
2427 			if (expand_rule(&r, $3, $5, &$6, $7) == -1)
2428 				YYERROR;
2429 		}
2430 		;
2431 
2432 action		: ALLOW		{ $$ = ACTION_ALLOW; }
2433 		| DENY		{ $$ = ACTION_DENY; }
2434 		| MATCH		{ $$ = ACTION_NONE; }
2435 		;
2436 
2437 quick		: /* empty */	{ $$ = 0; }
2438 		| QUICK		{ $$ = 1; }
2439 		;
2440 
2441 direction	: FROM		{ $$ = DIR_IN; }
2442 		| TO		{ $$ = DIR_OUT; }
2443 		;
2444 
2445 filter_rib_h	: /* empty */			{ $$ = NULL; }
2446 		| RIB filter_rib		{ $$ = $2; }
2447 		| RIB '{' optnl filter_rib_l optnl '}'	{ $$ = $4; }
2448 
2449 filter_rib_l	: filter_rib			{ $$ = $1; }
2450 		| filter_rib_l comma filter_rib	{
2451 			$3->next = $1;
2452 			$$ = $3;
2453 		}
2454 		;
2455 
2456 filter_rib	: STRING	{
2457 			if (!find_rib($1)) {
2458 				yyerror("rib \"%s\" does not exist.", $1);
2459 				free($1);
2460 				YYERROR;
2461 			}
2462 			if (($$ = calloc(1, sizeof(struct filter_rib_l))) ==
2463 			    NULL)
2464 				fatal(NULL);
2465 			$$->next = NULL;
2466 			if (strlcpy($$->name, $1, sizeof($$->name)) >=
2467 			    sizeof($$->name)) {
2468 				yyerror("rib name \"%s\" too long: "
2469 				    "max %zu", $1, sizeof($$->name) - 1);
2470 				free($1);
2471 				free($$);
2472 				YYERROR;
2473 			}
2474 			free($1);
2475 		}
2476 		;
2477 
2478 filter_peer_h	: filter_peer
2479 		| '{' optnl filter_peer_l optnl '}'	{ $$ = $3; }
2480 		;
2481 
2482 filter_peer_l	: filter_peer				{ $$ = $1; }
2483 		| filter_peer_l comma filter_peer	{
2484 			$3->next = $1;
2485 			$$ = $3;
2486 		}
2487 		;
2488 
2489 filter_peer	: ANY		{
2490 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
2491 			    NULL)
2492 				fatal(NULL);
2493 			$$->p.peerid = $$->p.groupid = 0;
2494 			$$->next = NULL;
2495 		}
2496 		| address	{
2497 			struct peer *p;
2498 
2499 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
2500 			    NULL)
2501 				fatal(NULL);
2502 			$$->p.remote_as = $$->p.groupid = $$->p.peerid = 0;
2503 			$$->next = NULL;
2504 			RB_FOREACH(p, peer_head, new_peers)
2505 				if (!memcmp(&p->conf.remote_addr,
2506 				    &$1, sizeof(p->conf.remote_addr))) {
2507 					$$->p.peerid = p->conf.id;
2508 					break;
2509 				}
2510 			if ($$->p.peerid == 0) {
2511 				yyerror("no such peer: %s", log_addr(&$1));
2512 				free($$);
2513 				YYERROR;
2514 			}
2515 		}
2516 		| AS as4number	{
2517 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
2518 			    NULL)
2519 				fatal(NULL);
2520 			$$->p.groupid = $$->p.peerid = 0;
2521 			$$->p.remote_as = $2;
2522 		}
2523 		| GROUP STRING	{
2524 			struct peer *p;
2525 
2526 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
2527 			    NULL)
2528 				fatal(NULL);
2529 			$$->p.remote_as = $$->p.peerid = 0;
2530 			$$->next = NULL;
2531 			RB_FOREACH(p, peer_head, new_peers)
2532 				if (!strcmp(p->conf.group, $2)) {
2533 					$$->p.groupid = p->conf.groupid;
2534 					break;
2535 				}
2536 			if ($$->p.groupid == 0) {
2537 				yyerror("no such group: \"%s\"", $2);
2538 				free($2);
2539 				free($$);
2540 				YYERROR;
2541 			}
2542 			free($2);
2543 		}
2544 		| EBGP {
2545 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
2546 			    NULL)
2547 				fatal(NULL);
2548 			$$->p.ebgp = 1;
2549 		}
2550 		| IBGP {
2551 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
2552 			    NULL)
2553 				fatal(NULL);
2554 			$$->p.ibgp = 1;
2555 		}
2556 		;
2557 
2558 filter_prefix_h	: IPV4 prefixlenop			 {
2559 			if ($2.op == OP_NONE) {
2560 				$2.op = OP_RANGE;
2561 				$2.len_min = 0;
2562 				$2.len_max = -1;
2563 			}
2564 			if (($$ = calloc(1, sizeof(struct filter_prefix_l))) ==
2565 			    NULL)
2566 				fatal(NULL);
2567 			$$->p.addr.aid = AID_INET;
2568 			if (merge_prefixspec(&$$->p, &$2) == -1) {
2569 				free($$);
2570 				YYERROR;
2571 			}
2572 		}
2573 		| IPV6 prefixlenop			{
2574 			if ($2.op == OP_NONE) {
2575 				$2.op = OP_RANGE;
2576 				$2.len_min = 0;
2577 				$2.len_max = -1;
2578 			}
2579 			if (($$ = calloc(1, sizeof(struct filter_prefix_l))) ==
2580 			    NULL)
2581 				fatal(NULL);
2582 			$$->p.addr.aid = AID_INET6;
2583 			if (merge_prefixspec(&$$->p, &$2) == -1) {
2584 				free($$);
2585 				YYERROR;
2586 			}
2587 		}
2588 		| PREFIX filter_prefix			{ $$ = $2; }
2589 		| PREFIX '{' filter_prefix_m '}'	{ $$ = $3; }
2590 		;
2591 
2592 filter_prefix_m	: filter_prefix_l
2593 		| '{' filter_prefix_l '}'		{ $$ = $2; }
2594 		| '{' filter_prefix_l '}' filter_prefix_m
2595 		{
2596 			struct filter_prefix_l	*p;
2597 
2598 			/* merge, both can be lists */
2599 			for (p = $2; p != NULL && p->next != NULL; p = p->next)
2600 				;	/* nothing */
2601 			if (p != NULL)
2602 				p->next = $4;
2603 			$$ = $2;
2604 		}
2605 
2606 filter_prefix_l	: filter_prefix			{ $$ = $1; }
2607 		| filter_prefix_l comma filter_prefix	{
2608 			$3->next = $1;
2609 			$$ = $3;
2610 		}
2611 		;
2612 
2613 filter_prefix	: prefix prefixlenop			{
2614 			if (($$ = calloc(1, sizeof(struct filter_prefix_l))) ==
2615 			    NULL)
2616 				fatal(NULL);
2617 			memcpy(&$$->p.addr, &$1.prefix,
2618 			    sizeof($$->p.addr));
2619 			$$->p.len = $1.len;
2620 
2621 			if (merge_prefixspec(&$$->p, &$2) == -1) {
2622 				free($$);
2623 				YYERROR;
2624 			}
2625 		}
2626 		;
2627 
2628 filter_as_h	: filter_as_t
2629 		| '{' filter_as_t_l '}'		{ $$ = $2; }
2630 		;
2631 
2632 filter_as_t_l	: filter_as_t
2633 		| filter_as_t_l comma filter_as_t		{
2634 			struct filter_as_l	*a;
2635 
2636 			/* merge, both can be lists */
2637 			for (a = $1; a != NULL && a->next != NULL; a = a->next)
2638 				;	/* nothing */
2639 			if (a != NULL)
2640 				a->next = $3;
2641 			$$ = $1;
2642 		}
2643 		;
2644 
2645 filter_as_t	: filter_as_type filter_as			{
2646 			$$ = $2;
2647 			$$->a.type = $1;
2648 		}
2649 		| filter_as_type '{' filter_as_l_h '}'	{
2650 			struct filter_as_l	*a;
2651 
2652 			$$ = $3;
2653 			for (a = $$; a != NULL; a = a->next)
2654 				a->a.type = $1;
2655 		}
2656 		| filter_as_type ASSET STRING {
2657 			if (as_sets_lookup(&conf->as_sets, $3) == NULL) {
2658 				yyerror("as-set \"%s\" not defined", $3);
2659 				free($3);
2660 				YYERROR;
2661 			}
2662 			if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
2663 			    NULL)
2664 				fatal(NULL);
2665 			$$->a.type = $1;
2666 			$$->a.flags = AS_FLAG_AS_SET_NAME;
2667 			if (strlcpy($$->a.name, $3, sizeof($$->a.name)) >=
2668 			    sizeof($$->a.name)) {
2669 				yyerror("as-set name \"%s\" too long: "
2670 				    "max %zu", $3, sizeof($$->a.name) - 1);
2671 				free($3);
2672 				free($$);
2673 				YYERROR;
2674 			}
2675 			free($3);
2676 		}
2677 		;
2678 
2679 filter_as_l_h	: filter_as_l
2680 		| '{' filter_as_l '}'			{ $$ = $2; }
2681 		| '{' filter_as_l '}' filter_as_l_h
2682 		{
2683 			struct filter_as_l	*a;
2684 
2685 			/* merge, both can be lists */
2686 			for (a = $2; a != NULL && a->next != NULL; a = a->next)
2687 				;	/* nothing */
2688 			if (a != NULL)
2689 				a->next = $4;
2690 			$$ = $2;
2691 		}
2692 		;
2693 
2694 filter_as_l	: filter_as
2695 		| filter_as_l comma filter_as	{
2696 			$3->next = $1;
2697 			$$ = $3;
2698 		}
2699 		;
2700 
2701 filter_as	: as4number_any		{
2702 			if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
2703 			    NULL)
2704 				fatal(NULL);
2705 			$$->a.as_min = $1;
2706 			$$->a.as_max = $1;
2707 			$$->a.op = OP_EQ;
2708 		}
2709 		| NEIGHBORAS		{
2710 			if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
2711 			    NULL)
2712 				fatal(NULL);
2713 			$$->a.flags = AS_FLAG_NEIGHBORAS;
2714 		}
2715 		| equalityop as4number_any	{
2716 			if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
2717 			    NULL)
2718 				fatal(NULL);
2719 			$$->a.op = $1;
2720 			$$->a.as_min = $2;
2721 			$$->a.as_max = $2;
2722 		}
2723 		| as4number_any binaryop as4number_any {
2724 			if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
2725 			    NULL)
2726 				fatal(NULL);
2727 			if ($1 >= $3) {
2728 				yyerror("start AS is bigger than end");
2729 				YYERROR;
2730 			}
2731 			$$->a.op = $2;
2732 			$$->a.as_min = $1;
2733 			$$->a.as_max = $3;
2734 		}
2735 		;
2736 
2737 filter_match_h	: /* empty */			{
2738 			memset(&$$, 0, sizeof($$));
2739 		}
2740 		| {
2741 			memset(&fmopts, 0, sizeof(fmopts));
2742 		}
2743 		    filter_match		{
2744 			memcpy(&$$, &fmopts, sizeof($$));
2745 		}
2746 		;
2747 
2748 filter_match	: filter_elm
2749 		| filter_match filter_elm
2750 		;
2751 
2752 filter_elm	: filter_prefix_h	{
2753 			if (fmopts.prefix_l != NULL) {
2754 				yyerror("\"prefix\" already specified");
2755 				YYERROR;
2756 			}
2757 			if (fmopts.m.prefixset.name[0] != '\0') {
2758 				yyerror("\"prefix-set\" already specified, "
2759 				    "cannot be used with \"prefix\" in the "
2760 				    "same filter rule");
2761 				YYERROR;
2762 			}
2763 			fmopts.prefix_l = $1;
2764 		}
2765 		| filter_as_h		{
2766 			if (fmopts.as_l != NULL) {
2767 				yyerror("AS filters already specified");
2768 				YYERROR;
2769 			}
2770 			fmopts.as_l = $1;
2771 		}
2772 		| MAXASLEN NUMBER	{
2773 			if (fmopts.m.aslen.type != ASLEN_NONE) {
2774 				yyerror("AS length filters already specified");
2775 				YYERROR;
2776 			}
2777 			if ($2 < 0 || $2 > UINT_MAX) {
2778 				yyerror("bad max-as-len %lld", $2);
2779 				YYERROR;
2780 			}
2781 			fmopts.m.aslen.type = ASLEN_MAX;
2782 			fmopts.m.aslen.aslen = $2;
2783 		}
2784 		| MAXASSEQ NUMBER	{
2785 			if (fmopts.m.aslen.type != ASLEN_NONE) {
2786 				yyerror("AS length filters already specified");
2787 				YYERROR;
2788 			}
2789 			if ($2 < 0 || $2 > UINT_MAX) {
2790 				yyerror("bad max-as-seq %lld", $2);
2791 				YYERROR;
2792 			}
2793 			fmopts.m.aslen.type = ASLEN_SEQ;
2794 			fmopts.m.aslen.aslen = $2;
2795 		}
2796 		| community STRING	{
2797 			int i;
2798 			for (i = 0; i < MAX_COMM_MATCH; i++) {
2799 				if (fmopts.m.community[i].flags == 0)
2800 					break;
2801 			}
2802 			if (i >= MAX_COMM_MATCH) {
2803 				yyerror("too many \"community\" filters "
2804 				    "specified");
2805 				free($2);
2806 				YYERROR;
2807 			}
2808 			if (parsecommunity(&fmopts.m.community[i], $1, $2) == -1) {
2809 				free($2);
2810 				YYERROR;
2811 			}
2812 			free($2);
2813 		}
2814 		| EXTCOMMUNITY STRING STRING {
2815 			int i;
2816 			for (i = 0; i < MAX_COMM_MATCH; i++) {
2817 				if (fmopts.m.community[i].flags == 0)
2818 					break;
2819 			}
2820 			if (i >= MAX_COMM_MATCH) {
2821 				yyerror("too many \"community\" filters "
2822 				    "specified");
2823 				free($2);
2824 				free($3);
2825 				YYERROR;
2826 			}
2827 			if (parseextcommunity(&fmopts.m.community[i],
2828 			    $2, $3) == -1) {
2829 				free($2);
2830 				free($3);
2831 				YYERROR;
2832 			}
2833 			free($2);
2834 			free($3);
2835 		}
2836 		| EXTCOMMUNITY OVS STRING {
2837 			int i;
2838 			for (i = 0; i < MAX_COMM_MATCH; i++) {
2839 				if (fmopts.m.community[i].flags == 0)
2840 					break;
2841 			}
2842 			if (i >= MAX_COMM_MATCH) {
2843 				yyerror("too many \"community\" filters "
2844 				    "specified");
2845 				free($3);
2846 				YYERROR;
2847 			}
2848 			if (parseextcommunity(&fmopts.m.community[i],
2849 			    "ovs", $3) == -1) {
2850 				free($3);
2851 				YYERROR;
2852 			}
2853 			free($3);
2854 		}
2855 		| MAXCOMMUNITIES NUMBER {
2856 			if ($2 < 0 || $2 > INT16_MAX) {
2857 				yyerror("bad max-comunities %lld", $2);
2858 				YYERROR;
2859 			}
2860 			if (fmopts.m.maxcomm != 0) {
2861 				yyerror("%s already specified",
2862 				    "max-communities");
2863 				YYERROR;
2864 			}
2865 			/*
2866 			 * Offset by 1 since 0 means not used.
2867 			 * The match function then uses >= to compensate.
2868 			 */
2869 			fmopts.m.maxcomm = $2 + 1;
2870 		}
2871 		| MAXEXTCOMMUNITIES NUMBER {
2872 			if ($2 < 0 || $2 > INT16_MAX) {
2873 				yyerror("bad max-ext-communities %lld", $2);
2874 				YYERROR;
2875 			}
2876 			if (fmopts.m.maxextcomm != 0) {
2877 				yyerror("%s already specified",
2878 				    "max-ext-communities");
2879 				YYERROR;
2880 			}
2881 			fmopts.m.maxextcomm = $2 + 1;
2882 		}
2883 		| MAXLARGECOMMUNITIES NUMBER {
2884 			if ($2 < 0 || $2 > INT16_MAX) {
2885 				yyerror("bad max-large-communities %lld", $2);
2886 				YYERROR;
2887 			}
2888 			if (fmopts.m.maxlargecomm != 0) {
2889 				yyerror("%s already specified",
2890 				    "max-large-communities");
2891 				YYERROR;
2892 			}
2893 			fmopts.m.maxlargecomm = $2 + 1;
2894 		}
2895 		| NEXTHOP address	{
2896 			if (fmopts.m.nexthop.flags) {
2897 				yyerror("nexthop already specified");
2898 				YYERROR;
2899 			}
2900 			fmopts.m.nexthop.addr = $2;
2901 			fmopts.m.nexthop.flags = FILTER_NEXTHOP_ADDR;
2902 		}
2903 		| NEXTHOP NEIGHBOR	{
2904 			if (fmopts.m.nexthop.flags) {
2905 				yyerror("nexthop already specified");
2906 				YYERROR;
2907 			}
2908 			fmopts.m.nexthop.flags = FILTER_NEXTHOP_NEIGHBOR;
2909 		}
2910 		| PREFIXSET STRING prefixlenop {
2911 			struct prefixset *ps;
2912 			if (fmopts.prefix_l != NULL) {
2913 				yyerror("\"prefix\" already specified, cannot "
2914 				    "be used with \"prefix-set\" in the same "
2915 				    "filter rule");
2916 				free($2);
2917 				YYERROR;
2918 			}
2919 			if (fmopts.m.prefixset.name[0] != '\0') {
2920 				yyerror("prefix-set filter already specified");
2921 				free($2);
2922 				YYERROR;
2923 			}
2924 			if ((ps = find_prefixset($2, &conf->prefixsets))
2925 			    == NULL) {
2926 				yyerror("prefix-set '%s' not defined", $2);
2927 				free($2);
2928 				YYERROR;
2929 			}
2930 			if (strlcpy(fmopts.m.prefixset.name, $2,
2931 			    sizeof(fmopts.m.prefixset.name)) >=
2932 			    sizeof(fmopts.m.prefixset.name)) {
2933 				yyerror("prefix-set name too long");
2934 				free($2);
2935 				YYERROR;
2936 			}
2937 			if (!($3.op == OP_NONE ||
2938 			    ($3.op == OP_RANGE &&
2939 			     $3.len_min == -1 && $3.len_max == -1))) {
2940 				yyerror("prefix-sets can only use option "
2941 				    "or-longer");
2942 				free($2);
2943 				YYERROR;
2944 			}
2945 			if ($3.op == OP_RANGE && ps->sflags & PREFIXSET_FLAG_OPS) {
2946 				yyerror("prefix-set %s contains prefixlen "
2947 				    "operators and cannot be used with an "
2948 				    "or-longer filter", $2);
2949 				free($2);
2950 				YYERROR;
2951 			}
2952 			if ($3.op == OP_RANGE && $3.len_min == -1 &&
2953 			    $3.len_min == -1)
2954 				fmopts.m.prefixset.flags |=
2955 				    PREFIXSET_FLAG_LONGER;
2956 			fmopts.m.prefixset.flags |= PREFIXSET_FLAG_FILTER;
2957 			free($2);
2958 		}
2959 		| ORIGINSET STRING {
2960 			if (fmopts.m.originset.name[0] != '\0') {
2961 				yyerror("origin-set filter already specified");
2962 				free($2);
2963 				YYERROR;
2964 			}
2965 			if (find_prefixset($2, &conf->originsets) == NULL) {
2966 				yyerror("origin-set '%s' not defined", $2);
2967 				free($2);
2968 				YYERROR;
2969 			}
2970 			if (strlcpy(fmopts.m.originset.name, $2,
2971 			    sizeof(fmopts.m.originset.name)) >=
2972 			    sizeof(fmopts.m.originset.name)) {
2973 				yyerror("origin-set name too long");
2974 				free($2);
2975 				YYERROR;
2976 			}
2977 			free($2);
2978 		}
2979 		| OVS validity		{
2980 			if (fmopts.m.ovs.is_set) {
2981 				yyerror("ovs filter already specified");
2982 				YYERROR;
2983 			}
2984 			fmopts.m.ovs.validity = $2;
2985 			fmopts.m.ovs.is_set = 1;
2986 		}
2987 		| AVS aspa_validity		{
2988 			if (fmopts.m.avs.is_set) {
2989 				yyerror("avs filter already specified");
2990 				YYERROR;
2991 			}
2992 			fmopts.m.avs.validity = $2;
2993 			fmopts.m.avs.is_set = 1;
2994 		}
2995 		;
2996 
2997 prefixlenop	: /* empty */		{ memset(&$$, 0, sizeof($$)); }
2998 		| LONGER				{
2999 			memset(&$$, 0, sizeof($$));
3000 			$$.op = OP_RANGE;
3001 			$$.len_min = -1;
3002 			$$.len_max = -1;
3003 		}
3004 		| MAXLEN NUMBER				{
3005 			memset(&$$, 0, sizeof($$));
3006 			if ($2 < 0 || $2 > 128) {
3007 				yyerror("prefixlen must be >= 0 and <= 128");
3008 				YYERROR;
3009 			}
3010 
3011 			$$.op = OP_RANGE;
3012 			$$.len_min = -1;
3013 			$$.len_max = $2;
3014 		}
3015 		| PREFIXLEN unaryop NUMBER		{
3016 			int min, max;
3017 
3018 			memset(&$$, 0, sizeof($$));
3019 			if ($3 < 0 || $3 > 128) {
3020 				yyerror("prefixlen must be >= 0 and <= 128");
3021 				YYERROR;
3022 			}
3023 			/*
3024 			 * convert the unary operation into the equivalent
3025 			 * range check
3026 			 */
3027 			$$.op = OP_RANGE;
3028 
3029 			switch ($2) {
3030 			case OP_NE:
3031 				$$.op = $2;
3032 			case OP_EQ:
3033 				min = max = $3;
3034 				break;
3035 			case OP_LT:
3036 				if ($3 == 0) {
3037 					yyerror("prefixlen must be > 0");
3038 					YYERROR;
3039 				}
3040 				$3 -= 1;
3041 			case OP_LE:
3042 				min = -1;
3043 				max = $3;
3044 				break;
3045 			case OP_GT:
3046 				$3 += 1;
3047 			case OP_GE:
3048 				min = $3;
3049 				max = -1;
3050 				break;
3051 			default:
3052 				yyerror("unknown prefixlen operation");
3053 				YYERROR;
3054 			}
3055 			$$.len_min = min;
3056 			$$.len_max = max;
3057 		}
3058 		| PREFIXLEN NUMBER binaryop NUMBER	{
3059 			memset(&$$, 0, sizeof($$));
3060 			if ($2 < 0 || $2 > 128 || $4 < 0 || $4 > 128) {
3061 				yyerror("prefixlen must be < 128");
3062 				YYERROR;
3063 			}
3064 			if ($2 > $4) {
3065 				yyerror("start prefixlen is bigger than end");
3066 				YYERROR;
3067 			}
3068 			$$.op = $3;
3069 			$$.len_min = $2;
3070 			$$.len_max = $4;
3071 		}
3072 		;
3073 
3074 filter_as_type	: AS		{ $$ = AS_ALL; }
3075 		| SOURCEAS	{ $$ = AS_SOURCE; }
3076 		| TRANSITAS	{ $$ = AS_TRANSIT; }
3077 		| PEERAS	{ $$ = AS_PEER; }
3078 		;
3079 
3080 filter_set	: /* empty */	{ $$ = NULL; }
3081 		| SET filter_set_opt	{
3082 			if (($$ = calloc(1, sizeof(struct filter_set_head))) ==
3083 			    NULL)
3084 				fatal(NULL);
3085 			TAILQ_INIT($$);
3086 			TAILQ_INSERT_TAIL($$, $2, entry);
3087 		}
3088 		| SET '{' optnl filter_set_l optnl '}'	{ $$ = $4; }
3089 		;
3090 
3091 filter_set_l	: filter_set_l comma filter_set_opt	{
3092 			$$ = $1;
3093 			if (merge_filterset($$, $3) == 1)
3094 				YYERROR;
3095 		}
3096 		| filter_set_opt {
3097 			if (($$ = calloc(1, sizeof(struct filter_set_head))) ==
3098 			    NULL)
3099 				fatal(NULL);
3100 			TAILQ_INIT($$);
3101 			TAILQ_INSERT_TAIL($$, $1, entry);
3102 		}
3103 		;
3104 
3105 community	: COMMUNITY		{ $$ = COMMUNITY_TYPE_BASIC; }
3106 		| LARGECOMMUNITY	{ $$ = COMMUNITY_TYPE_LARGE; }
3107 		;
3108 
3109 delete		: /* empty */	{ $$ = 0; }
3110 		| DELETE	{ $$ = 1; }
3111 		;
3112 
3113 enforce		: /* empty */	{ $$ = 0; }
3114 		| ENFORCE	{ $$ = 2; }
3115 		;
3116 
3117 yesnoenforce	: yesno		{ $$ = $1; }
3118 		| ENFORCE	{ $$ = 2; }
3119 		;
3120 
3121 filter_set_opt	: LOCALPREF NUMBER		{
3122 			if ($2 < -INT_MAX || $2 > UINT_MAX) {
3123 				yyerror("bad localpref %lld", $2);
3124 				YYERROR;
3125 			}
3126 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3127 				fatal(NULL);
3128 			if ($2 >= 0) {
3129 				$$->type = ACTION_SET_LOCALPREF;
3130 				$$->action.metric = $2;
3131 			} else {
3132 				$$->type = ACTION_SET_RELATIVE_LOCALPREF;
3133 				$$->action.relative = $2;
3134 			}
3135 		}
3136 		| LOCALPREF '+' NUMBER		{
3137 			if ($3 < 0 || $3 > INT_MAX) {
3138 				yyerror("bad localpref +%lld", $3);
3139 				YYERROR;
3140 			}
3141 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3142 				fatal(NULL);
3143 			$$->type = ACTION_SET_RELATIVE_LOCALPREF;
3144 			$$->action.relative = $3;
3145 		}
3146 		| LOCALPREF '-' NUMBER		{
3147 			if ($3 < 0 || $3 > INT_MAX) {
3148 				yyerror("bad localpref -%lld", $3);
3149 				YYERROR;
3150 			}
3151 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3152 				fatal(NULL);
3153 			$$->type = ACTION_SET_RELATIVE_LOCALPREF;
3154 			$$->action.relative = -$3;
3155 		}
3156 		| MED NUMBER			{
3157 			if ($2 < -INT_MAX || $2 > UINT_MAX) {
3158 				yyerror("bad metric %lld", $2);
3159 				YYERROR;
3160 			}
3161 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3162 				fatal(NULL);
3163 			if ($2 >= 0) {
3164 				$$->type = ACTION_SET_MED;
3165 				$$->action.metric = $2;
3166 			} else {
3167 				$$->type = ACTION_SET_RELATIVE_MED;
3168 				$$->action.relative = $2;
3169 			}
3170 		}
3171 		| MED '+' NUMBER		{
3172 			if ($3 < 0 || $3 > INT_MAX) {
3173 				yyerror("bad metric +%lld", $3);
3174 				YYERROR;
3175 			}
3176 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3177 				fatal(NULL);
3178 			$$->type = ACTION_SET_RELATIVE_MED;
3179 			$$->action.relative = $3;
3180 		}
3181 		| MED '-' NUMBER		{
3182 			if ($3 < 0 || $3 > INT_MAX) {
3183 				yyerror("bad metric -%lld", $3);
3184 				YYERROR;
3185 			}
3186 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3187 				fatal(NULL);
3188 			$$->type = ACTION_SET_RELATIVE_MED;
3189 			$$->action.relative = -$3;
3190 		}
3191 		| METRIC NUMBER			{	/* alias for MED */
3192 			if ($2 < -INT_MAX || $2 > UINT_MAX) {
3193 				yyerror("bad metric %lld", $2);
3194 				YYERROR;
3195 			}
3196 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3197 				fatal(NULL);
3198 			if ($2 >= 0) {
3199 				$$->type = ACTION_SET_MED;
3200 				$$->action.metric = $2;
3201 			} else {
3202 				$$->type = ACTION_SET_RELATIVE_MED;
3203 				$$->action.relative = $2;
3204 			}
3205 		}
3206 		| METRIC '+' NUMBER		{
3207 			if ($3 < 0 || $3 > INT_MAX) {
3208 				yyerror("bad metric +%lld", $3);
3209 				YYERROR;
3210 			}
3211 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3212 				fatal(NULL);
3213 			$$->type = ACTION_SET_RELATIVE_MED;
3214 			$$->action.metric = $3;
3215 		}
3216 		| METRIC '-' NUMBER		{
3217 			if ($3 < 0 || $3 > INT_MAX) {
3218 				yyerror("bad metric -%lld", $3);
3219 				YYERROR;
3220 			}
3221 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3222 				fatal(NULL);
3223 			$$->type = ACTION_SET_RELATIVE_MED;
3224 			$$->action.relative = -$3;
3225 		}
3226 		| WEIGHT NUMBER			{
3227 			if ($2 < -INT_MAX || $2 > UINT_MAX) {
3228 				yyerror("bad weight %lld", $2);
3229 				YYERROR;
3230 			}
3231 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3232 				fatal(NULL);
3233 			if ($2 > 0) {
3234 				$$->type = ACTION_SET_WEIGHT;
3235 				$$->action.metric = $2;
3236 			} else {
3237 				$$->type = ACTION_SET_RELATIVE_WEIGHT;
3238 				$$->action.relative = $2;
3239 			}
3240 		}
3241 		| WEIGHT '+' NUMBER		{
3242 			if ($3 < 0 || $3 > INT_MAX) {
3243 				yyerror("bad weight +%lld", $3);
3244 				YYERROR;
3245 			}
3246 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3247 				fatal(NULL);
3248 			$$->type = ACTION_SET_RELATIVE_WEIGHT;
3249 			$$->action.relative = $3;
3250 		}
3251 		| WEIGHT '-' NUMBER		{
3252 			if ($3 < 0 || $3 > INT_MAX) {
3253 				yyerror("bad weight -%lld", $3);
3254 				YYERROR;
3255 			}
3256 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3257 				fatal(NULL);
3258 			$$->type = ACTION_SET_RELATIVE_WEIGHT;
3259 			$$->action.relative = -$3;
3260 		}
3261 		| NEXTHOP address		{
3262 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3263 				fatal(NULL);
3264 			$$->type = ACTION_SET_NEXTHOP;
3265 			memcpy(&$$->action.nexthop, &$2,
3266 			    sizeof($$->action.nexthop));
3267 		}
3268 		| NEXTHOP BLACKHOLE		{
3269 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3270 				fatal(NULL);
3271 			$$->type = ACTION_SET_NEXTHOP_BLACKHOLE;
3272 		}
3273 		| NEXTHOP REJECT		{
3274 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3275 				fatal(NULL);
3276 			$$->type = ACTION_SET_NEXTHOP_REJECT;
3277 		}
3278 		| NEXTHOP NOMODIFY		{
3279 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3280 				fatal(NULL);
3281 			$$->type = ACTION_SET_NEXTHOP_NOMODIFY;
3282 		}
3283 		| NEXTHOP SELF		{
3284 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3285 				fatal(NULL);
3286 			$$->type = ACTION_SET_NEXTHOP_SELF;
3287 		}
3288 		| PREPEND_SELF NUMBER		{
3289 			if ($2 < 0 || $2 > 128) {
3290 				yyerror("bad number of prepends");
3291 				YYERROR;
3292 			}
3293 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3294 				fatal(NULL);
3295 			$$->type = ACTION_SET_PREPEND_SELF;
3296 			$$->action.prepend = $2;
3297 		}
3298 		| PREPEND_PEER NUMBER		{
3299 			if ($2 < 0 || $2 > 128) {
3300 				yyerror("bad number of prepends");
3301 				YYERROR;
3302 			}
3303 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3304 				fatal(NULL);
3305 			$$->type = ACTION_SET_PREPEND_PEER;
3306 			$$->action.prepend = $2;
3307 		}
3308 		| ASOVERRIDE			{
3309 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3310 				fatal(NULL);
3311 			$$->type = ACTION_SET_AS_OVERRIDE;
3312 		}
3313 		| PFTABLE STRING		{
3314 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3315 				fatal(NULL);
3316 			$$->type = ACTION_PFTABLE;
3317 			if (!(cmd_opts & BGPD_OPT_NOACTION) &&
3318 			    pftable_exists($2) != 0) {
3319 				yyerror("pftable name does not exist");
3320 				free($2);
3321 				free($$);
3322 				YYERROR;
3323 			}
3324 			if (strlcpy($$->action.pftable, $2,
3325 			    sizeof($$->action.pftable)) >=
3326 			    sizeof($$->action.pftable)) {
3327 				yyerror("pftable name too long");
3328 				free($2);
3329 				free($$);
3330 				YYERROR;
3331 			}
3332 			if (pftable_add($2) != 0) {
3333 				yyerror("Couldn't register table");
3334 				free($2);
3335 				free($$);
3336 				YYERROR;
3337 			}
3338 			free($2);
3339 		}
3340 		| RTLABEL STRING		{
3341 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3342 				fatal(NULL);
3343 			$$->type = ACTION_RTLABEL;
3344 			if (strlcpy($$->action.rtlabel, $2,
3345 			    sizeof($$->action.rtlabel)) >=
3346 			    sizeof($$->action.rtlabel)) {
3347 				yyerror("rtlabel name too long");
3348 				free($2);
3349 				free($$);
3350 				YYERROR;
3351 			}
3352 			free($2);
3353 		}
3354 		| community delete STRING	{
3355 			uint8_t f1, f2, f3;
3356 
3357 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3358 				fatal(NULL);
3359 			if ($2)
3360 				$$->type = ACTION_DEL_COMMUNITY;
3361 			else
3362 				$$->type = ACTION_SET_COMMUNITY;
3363 
3364 			if (parsecommunity(&$$->action.community, $1, $3) ==
3365 			    -1) {
3366 				free($3);
3367 				free($$);
3368 				YYERROR;
3369 			}
3370 			free($3);
3371 			/* Don't allow setting of any match */
3372 			f1 = $$->action.community.flags >> 8;
3373 			f2 = $$->action.community.flags >> 16;
3374 			f3 = $$->action.community.flags >> 24;
3375 			if (!$2 && (f1 == COMMUNITY_ANY ||
3376 			    f2 == COMMUNITY_ANY || f3 == COMMUNITY_ANY)) {
3377 				yyerror("'*' is not allowed in set community");
3378 				free($$);
3379 				YYERROR;
3380 			}
3381 		}
3382 		| EXTCOMMUNITY delete STRING STRING {
3383 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3384 				fatal(NULL);
3385 			if ($2)
3386 				$$->type = ACTION_DEL_COMMUNITY;
3387 			else
3388 				$$->type = ACTION_SET_COMMUNITY;
3389 
3390 			if (parseextcommunity(&$$->action.community,
3391 			    $3, $4) == -1) {
3392 				free($3);
3393 				free($4);
3394 				free($$);
3395 				YYERROR;
3396 			}
3397 			free($3);
3398 			free($4);
3399 		}
3400 		| EXTCOMMUNITY delete OVS STRING {
3401 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3402 				fatal(NULL);
3403 			if ($2)
3404 				$$->type = ACTION_DEL_COMMUNITY;
3405 			else
3406 				$$->type = ACTION_SET_COMMUNITY;
3407 
3408 			if (parseextcommunity(&$$->action.community,
3409 			    "ovs", $4) == -1) {
3410 				free($4);
3411 				free($$);
3412 				YYERROR;
3413 			}
3414 			free($4);
3415 		}
3416 		| ORIGIN origincode {
3417 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3418 				fatal(NULL);
3419 			$$->type = ACTION_SET_ORIGIN;
3420 			$$->action.origin = $2;
3421 		}
3422 		;
3423 
3424 origincode	: STRING	{
3425 			if (!strcmp($1, "egp"))
3426 				$$ = ORIGIN_EGP;
3427 			else if (!strcmp($1, "igp"))
3428 				$$ = ORIGIN_IGP;
3429 			else if (!strcmp($1, "incomplete"))
3430 				$$ = ORIGIN_INCOMPLETE;
3431 			else {
3432 				yyerror("unknown origin \"%s\"", $1);
3433 				free($1);
3434 				YYERROR;
3435 			}
3436 			free($1);
3437 		};
3438 
3439 validity	: STRING	{
3440 			if (!strcmp($1, "not-found"))
3441 				$$ = ROA_NOTFOUND;
3442 			else if (!strcmp($1, "invalid"))
3443 				$$ = ROA_INVALID;
3444 			else if (!strcmp($1, "valid"))
3445 				$$ = ROA_VALID;
3446 			else {
3447 				yyerror("unknown roa validity \"%s\"", $1);
3448 				free($1);
3449 				YYERROR;
3450 			}
3451 			free($1);
3452 		};
3453 
3454 aspa_validity	: STRING	{
3455 			if (!strcmp($1, "unknown"))
3456 				$$ = ASPA_UNKNOWN;
3457 			else if (!strcmp($1, "invalid"))
3458 				$$ = ASPA_INVALID;
3459 			else if (!strcmp($1, "valid"))
3460 				$$ = ASPA_VALID;
3461 			else {
3462 				yyerror("unknown aspa validity \"%s\"", $1);
3463 				free($1);
3464 				YYERROR;
3465 			}
3466 			free($1);
3467 		};
3468 
3469 optnl		: /* empty */
3470 		| '\n' optnl
3471 		;
3472 
3473 comma		: /* empty */
3474 		| ','
3475 		| '\n' optnl
3476 		| ',' '\n' optnl
3477 		;
3478 
3479 unaryop		: '='		{ $$ = OP_EQ; }
3480 		| NE		{ $$ = OP_NE; }
3481 		| LE		{ $$ = OP_LE; }
3482 		| '<'		{ $$ = OP_LT; }
3483 		| GE		{ $$ = OP_GE; }
3484 		| '>'		{ $$ = OP_GT; }
3485 		;
3486 
3487 equalityop	: '='		{ $$ = OP_EQ; }
3488 		| NE		{ $$ = OP_NE; }
3489 		;
3490 
3491 binaryop	: '-'		{ $$ = OP_RANGE; }
3492 		| XRANGE	{ $$ = OP_XRANGE; }
3493 		;
3494 
3495 %%
3496 
3497 struct keywords {
3498 	const char	*k_name;
3499 	int		 k_val;
3500 };
3501 
3502 int
3503 yyerror(const char *fmt, ...)
3504 {
3505 	va_list		 ap;
3506 	char		*msg;
3507 
3508 	file->errors++;
3509 	va_start(ap, fmt);
3510 	if (vasprintf(&msg, fmt, ap) == -1)
3511 		fatalx("yyerror vasprintf");
3512 	va_end(ap);
3513 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
3514 	free(msg);
3515 	return (0);
3516 }
3517 
3518 int
3519 kw_cmp(const void *k, const void *e)
3520 {
3521 	return (strcmp(k, ((const struct keywords *)e)->k_name));
3522 }
3523 
3524 int
3525 lookup(char *s)
3526 {
3527 	/* this has to be sorted always */
3528 	static const struct keywords keywords[] = {
3529 		{ "AS",			AS },
3530 		{ "IPv4",		IPV4 },
3531 		{ "IPv6",		IPV6 },
3532 		{ "add-path",		ADDPATH },
3533 		{ "ah",			AH },
3534 		{ "allow",		ALLOW },
3535 		{ "announce",		ANNOUNCE },
3536 		{ "any",		ANY },
3537 		{ "as-4byte",		AS4BYTE },
3538 		{ "as-override",	ASOVERRIDE },
3539 		{ "as-set",		ASSET },
3540 		{ "aspa-set",		ASPASET },
3541 		{ "avs",		AVS },
3542 		{ "blackhole",		BLACKHOLE },
3543 		{ "community",		COMMUNITY },
3544 		{ "compare",		COMPARE },
3545 		{ "connect-retry",	CONNECTRETRY },
3546 		{ "connected",		CONNECTED },
3547 		{ "customer-as",	CUSTOMERAS },
3548 		{ "default-route",	DEFAULTROUTE },
3549 		{ "delete",		DELETE },
3550 		{ "demote",		DEMOTE },
3551 		{ "deny",		DENY },
3552 		{ "depend",		DEPEND },
3553 		{ "descr",		DESCR },
3554 		{ "down",		DOWN },
3555 		{ "dump",		DUMP },
3556 		{ "ebgp",		EBGP },
3557 		{ "enforce",		ENFORCE },
3558 		{ "enhanced",		ENHANCED },
3559 		{ "esp",		ESP },
3560 		{ "evaluate",		EVALUATE },
3561 		{ "expires",		EXPIRES },
3562 		{ "export",		EXPORT },
3563 		{ "export-target",	EXPORTTRGT },
3564 		{ "ext-community",	EXTCOMMUNITY },
3565 		{ "extended",		EXTENDED },
3566 		{ "fib-priority",	FIBPRIORITY },
3567 		{ "fib-update",		FIBUPDATE },
3568 		{ "filtered",		FILTERED },
3569 		{ "flags",		FLAGS },
3570 		{ "flowspec",		FLOWSPEC },
3571 		{ "fragment",		FRAGMENT },
3572 		{ "from",		FROM },
3573 		{ "graceful",		GRACEFUL },
3574 		{ "group",		GROUP },
3575 		{ "holdtime",		HOLDTIME },
3576 		{ "ibgp",		IBGP },
3577 		{ "ignore",		IGNORE },
3578 		{ "ike",		IKE },
3579 		{ "import-target",	IMPORTTRGT },
3580 		{ "in",			IN },
3581 		{ "include",		INCLUDE },
3582 		{ "inet",		IPV4 },
3583 		{ "inet6",		IPV6 },
3584 		{ "ipsec",		IPSEC },
3585 		{ "key",		KEY },
3586 		{ "large-community",	LARGECOMMUNITY },
3587 		{ "listen",		LISTEN },
3588 		{ "local-address",	LOCALADDR },
3589 		{ "local-as",		LOCALAS },
3590 		{ "localpref",		LOCALPREF },
3591 		{ "log",		LOG },
3592 		{ "match",		MATCH },
3593 		{ "max",		MAX },
3594 		{ "max-as-len",		MAXASLEN },
3595 		{ "max-as-seq",		MAXASSEQ },
3596 		{ "max-communities",	MAXCOMMUNITIES },
3597 		{ "max-ext-communities",	MAXEXTCOMMUNITIES },
3598 		{ "max-large-communities",	MAXLARGECOMMUNITIES },
3599 		{ "max-prefix",		MAXPREFIX },
3600 		{ "maxlen",		MAXLEN },
3601 		{ "md5sig",		MD5SIG },
3602 		{ "med",		MED },
3603 		{ "message",		MESSAGE },
3604 		{ "metric",		METRIC },
3605 		{ "min",		YMIN },
3606 		{ "min-version",	MINVERSION },
3607 		{ "multihop",		MULTIHOP },
3608 		{ "neighbor",		NEIGHBOR },
3609 		{ "neighbor-as",	NEIGHBORAS },
3610 		{ "network",		NETWORK },
3611 		{ "nexthop",		NEXTHOP },
3612 		{ "no-modify",		NOMODIFY },
3613 		{ "none",		NONE },
3614 		{ "notification",	NOTIFICATION },
3615 		{ "on",			ON },
3616 		{ "or-longer",		LONGER },
3617 		{ "origin",		ORIGIN },
3618 		{ "origin-set",		ORIGINSET },
3619 		{ "out",		OUT },
3620 		{ "ovs",		OVS },
3621 		{ "passive",		PASSIVE },
3622 		{ "password",		PASSWORD },
3623 		{ "peer-as",		PEERAS },
3624 		{ "pftable",		PFTABLE },
3625 		{ "plus",		PLUS },
3626 		{ "policy",		POLICY },
3627 		{ "port",		PORT },
3628 		{ "prefix",		PREFIX },
3629 		{ "prefix-set",		PREFIXSET },
3630 		{ "prefixlen",		PREFIXLEN },
3631 		{ "prepend-neighbor",	PREPEND_PEER },
3632 		{ "prepend-self",	PREPEND_SELF },
3633 		{ "priority",		PRIORITY },
3634 		{ "proto",		PROTO },
3635 		{ "provider-as",	PROVIDERAS },
3636 		{ "qualify",		QUALIFY },
3637 		{ "quick",		QUICK },
3638 		{ "rd",			RD },
3639 		{ "rde",		RDE },
3640 		{ "recv",		RECV },
3641 		{ "refresh",		REFRESH },
3642 		{ "reject",		REJECT },
3643 		{ "remote-as",		REMOTEAS },
3644 		{ "restart",		RESTART },
3645 		{ "restricted",		RESTRICTED },
3646 		{ "rib",		RIB },
3647 		{ "roa-set",		ROASET },
3648 		{ "role",		ROLE },
3649 		{ "route-reflector",	REFLECTOR },
3650 		{ "router-id",		ROUTERID },
3651 		{ "rtable",		RTABLE },
3652 		{ "rtlabel",		RTLABEL },
3653 		{ "rtr",		RTR },
3654 		{ "self",		SELF },
3655 		{ "send",		SEND },
3656 		{ "set",		SET },
3657 		{ "socket",		SOCKET },
3658 		{ "source-as",		SOURCEAS },
3659 		{ "spi",		SPI },
3660 		{ "staletime",		STALETIME },
3661 		{ "static",		STATIC },
3662 		{ "tcp",		TCP },
3663 		{ "to",			TO },
3664 		{ "tos",		TOS },
3665 		{ "transit-as",		TRANSITAS },
3666 		{ "transparent-as",	TRANSPARENT },
3667 		{ "ttl-security",	TTLSECURITY },
3668 		{ "unicast",		UNICAST },
3669 		{ "via",		VIA },
3670 		{ "vpn",		VPN },
3671 		{ "weight",		WEIGHT },
3672 	};
3673 	const struct keywords	*p;
3674 
3675 	p = bsearch(s, keywords, nitems(keywords), sizeof(keywords[0]), kw_cmp);
3676 
3677 	if (p)
3678 		return (p->k_val);
3679 	else
3680 		return (STRING);
3681 }
3682 
3683 #define START_EXPAND	1
3684 #define DONE_EXPAND	2
3685 
3686 static int	expanding;
3687 
3688 int
3689 igetc(void)
3690 {
3691 	int	c;
3692 
3693 	while (1) {
3694 		if (file->ungetpos > 0)
3695 			c = file->ungetbuf[--file->ungetpos];
3696 		else
3697 			c = getc(file->stream);
3698 
3699 		if (c == START_EXPAND)
3700 			expanding = 1;
3701 		else if (c == DONE_EXPAND)
3702 			expanding = 0;
3703 		else
3704 			break;
3705 	}
3706 	return (c);
3707 }
3708 
3709 int
3710 lgetc(int quotec)
3711 {
3712 	int		c, next;
3713 
3714 	if (quotec) {
3715 		if ((c = igetc()) == EOF) {
3716 			yyerror("reached end of file while parsing "
3717 			    "quoted string");
3718 			if (file == topfile || popfile() == EOF)
3719 				return (EOF);
3720 			return (quotec);
3721 		}
3722 		return (c);
3723 	}
3724 
3725 	while ((c = igetc()) == '\\') {
3726 		next = igetc();
3727 		if (next != '\n') {
3728 			c = next;
3729 			break;
3730 		}
3731 		yylval.lineno = file->lineno;
3732 		file->lineno++;
3733 	}
3734 
3735 	if (c == EOF) {
3736 		/*
3737 		 * Fake EOL when hit EOF for the first time. This gets line
3738 		 * count right if last line in included file is syntactically
3739 		 * invalid and has no newline.
3740 		 */
3741 		if (file->eof_reached == 0) {
3742 			file->eof_reached = 1;
3743 			return ('\n');
3744 		}
3745 		while (c == EOF) {
3746 			if (file == topfile || popfile() == EOF)
3747 				return (EOF);
3748 			c = igetc();
3749 		}
3750 	}
3751 	return (c);
3752 }
3753 
3754 void
3755 lungetc(int c)
3756 {
3757 	if (c == EOF)
3758 		return;
3759 
3760 	if (file->ungetpos >= file->ungetsize) {
3761 		void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
3762 		if (p == NULL)
3763 			err(1, "lungetc");
3764 		file->ungetbuf = p;
3765 		file->ungetsize *= 2;
3766 	}
3767 	file->ungetbuf[file->ungetpos++] = c;
3768 }
3769 
3770 int
3771 findeol(void)
3772 {
3773 	int	c;
3774 
3775 	/* skip to either EOF or the first real EOL */
3776 	while (1) {
3777 		c = lgetc(0);
3778 		if (c == '\n') {
3779 			file->lineno++;
3780 			break;
3781 		}
3782 		if (c == EOF)
3783 			break;
3784 	}
3785 	return (ERROR);
3786 }
3787 
3788 int
3789 expand_macro(void)
3790 {
3791 	char	 buf[MACRO_NAME_LEN];
3792 	char	*p, *val;
3793 	int	 c;
3794 
3795 	p = buf;
3796 	while (1) {
3797 		if ((c = lgetc('$')) == EOF)
3798 			return (ERROR);
3799 		if (p + 1 >= buf + sizeof(buf) - 1) {
3800 			yyerror("macro name too long");
3801 			return (ERROR);
3802 		}
3803 		if (isalnum(c) || c == '_') {
3804 			*p++ = c;
3805 			continue;
3806 		}
3807 		*p = '\0';
3808 		lungetc(c);
3809 		break;
3810 	}
3811 	val = symget(buf);
3812 	if (val == NULL) {
3813 		yyerror("macro '%s' not defined", buf);
3814 		return (ERROR);
3815 	}
3816 	p = val + strlen(val) - 1;
3817 	lungetc(DONE_EXPAND);
3818 	while (p >= val) {
3819 		lungetc((unsigned char)*p);
3820 		p--;
3821 	}
3822 	lungetc(START_EXPAND);
3823 	return (0);
3824 }
3825 
3826 int
3827 yylex(void)
3828 {
3829 	char	 buf[8096];
3830 	char	*p;
3831 	int	 quotec, next, c;
3832 	int	 token;
3833 
3834 top:
3835 	p = buf;
3836 	while ((c = lgetc(0)) == ' ' || c == '\t')
3837 		; /* nothing */
3838 
3839 	yylval.lineno = file->lineno;
3840 	if (c == '#')
3841 		while ((c = lgetc(0)) != '\n' && c != EOF)
3842 			; /* nothing */
3843 	if (c == '$' && !expanding) {
3844 		c = expand_macro();
3845 		if (c != 0)
3846 			return (c);
3847 		goto top;
3848 	}
3849 
3850 	switch (c) {
3851 	case '\'':
3852 	case '"':
3853 		quotec = c;
3854 		while (1) {
3855 			if ((c = lgetc(quotec)) == EOF)
3856 				return (0);
3857 			if (c == '\n') {
3858 				file->lineno++;
3859 				continue;
3860 			} else if (c == '\\') {
3861 				if ((next = lgetc(quotec)) == EOF)
3862 					return (0);
3863 				if (next == quotec || next == ' ' ||
3864 				    next == '\t')
3865 					c = next;
3866 				else if (next == '\n') {
3867 					file->lineno++;
3868 					continue;
3869 				} else
3870 					lungetc(next);
3871 			} else if (c == quotec) {
3872 				*p = '\0';
3873 				break;
3874 			} else if (c == '\0') {
3875 				yyerror("syntax error: unterminated quote");
3876 				return (findeol());
3877 			}
3878 			if (p + 1 >= buf + sizeof(buf) - 1) {
3879 				yyerror("string too long");
3880 				return (findeol());
3881 			}
3882 			*p++ = c;
3883 		}
3884 		yylval.v.string = strdup(buf);
3885 		if (yylval.v.string == NULL)
3886 			fatal("yylex: strdup");
3887 		return (STRING);
3888 	case '!':
3889 		next = lgetc(0);
3890 		if (next == '=')
3891 			return (NE);
3892 		lungetc(next);
3893 		break;
3894 	case '<':
3895 		next = lgetc(0);
3896 		if (next == '=')
3897 			return (LE);
3898 		lungetc(next);
3899 		break;
3900 	case '>':
3901 		next = lgetc(0);
3902 		if (next == '<')
3903 			return (XRANGE);
3904 		else if (next == '=')
3905 			return (GE);
3906 		lungetc(next);
3907 		break;
3908 	}
3909 
3910 #define allowed_to_end_number(x) \
3911 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
3912 
3913 	if (c == '-' || isdigit(c)) {
3914 		do {
3915 			*p++ = c;
3916 			if ((size_t)(p-buf) >= sizeof(buf)) {
3917 				yyerror("string too long");
3918 				return (findeol());
3919 			}
3920 		} while ((c = lgetc(0)) != EOF && isdigit(c));
3921 		lungetc(c);
3922 		if (p == buf + 1 && buf[0] == '-')
3923 			goto nodigits;
3924 		if (c == EOF || allowed_to_end_number(c)) {
3925 			const char *errstr = NULL;
3926 
3927 			*p = '\0';
3928 			yylval.v.number = strtonum(buf, LLONG_MIN,
3929 			    LLONG_MAX, &errstr);
3930 			if (errstr) {
3931 				yyerror("\"%s\" invalid number: %s",
3932 				    buf, errstr);
3933 				return (findeol());
3934 			}
3935 			return (NUMBER);
3936 		} else {
3937 nodigits:
3938 			while (p > buf + 1)
3939 				lungetc((unsigned char)*--p);
3940 			c = (unsigned char)*--p;
3941 			if (c == '-')
3942 				return (c);
3943 		}
3944 	}
3945 
3946 #define allowed_in_string(x) \
3947 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
3948 	x != '{' && x != '}' && x != '<' && x != '>' && \
3949 	x != '!' && x != '=' && x != '/' && x != '#' && \
3950 	x != ','))
3951 
3952 	if (isalnum(c) || c == ':' || c == '_' || c == '*') {
3953 		do {
3954 			if (c == '$' && !expanding) {
3955 				c = expand_macro();
3956 				if (c != 0)
3957 					return (c);
3958 			} else
3959 				*p++ = c;
3960 
3961 			if ((size_t)(p-buf) >= sizeof(buf)) {
3962 				yyerror("string too long");
3963 				return (findeol());
3964 			}
3965 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
3966 		lungetc(c);
3967 		*p = '\0';
3968 		if ((token = lookup(buf)) == STRING)
3969 			if ((yylval.v.string = strdup(buf)) == NULL)
3970 				fatal("yylex: strdup");
3971 		return (token);
3972 	}
3973 	if (c == '\n') {
3974 		yylval.lineno = file->lineno;
3975 		file->lineno++;
3976 	}
3977 	if (c == EOF)
3978 		return (0);
3979 	return (c);
3980 }
3981 
3982 int
3983 check_file_secrecy(int fd, const char *fname)
3984 {
3985 	struct stat	st;
3986 
3987 	if (fstat(fd, &st)) {
3988 		log_warn("cannot stat %s", fname);
3989 		return (-1);
3990 	}
3991 	return (0);
3992 }
3993 
3994 struct file *
3995 pushfile(const char *name, int secret)
3996 {
3997 	struct file	*nfile;
3998 
3999 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
4000 		log_warn("%s", __func__);
4001 		return (NULL);
4002 	}
4003 	if ((nfile->name = strdup(name)) == NULL) {
4004 		log_warn("%s", __func__);
4005 		free(nfile);
4006 		return (NULL);
4007 	}
4008 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
4009 		log_warn("%s: %s", __func__, nfile->name);
4010 		free(nfile->name);
4011 		free(nfile);
4012 		return (NULL);
4013 	}
4014 	if (secret &&
4015 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
4016 		fclose(nfile->stream);
4017 		free(nfile->name);
4018 		free(nfile);
4019 		return (NULL);
4020 	}
4021 	nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
4022 	nfile->ungetsize = 16;
4023 	nfile->ungetbuf = malloc(nfile->ungetsize);
4024 	if (nfile->ungetbuf == NULL) {
4025 		log_warn("%s", __func__);
4026 		fclose(nfile->stream);
4027 		free(nfile->name);
4028 		free(nfile);
4029 		return (NULL);
4030 	}
4031 	TAILQ_INSERT_TAIL(&files, nfile, entry);
4032 	return (nfile);
4033 }
4034 
4035 int
4036 popfile(void)
4037 {
4038 	struct file	*prev;
4039 
4040 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
4041 		prev->errors += file->errors;
4042 
4043 	TAILQ_REMOVE(&files, file, entry);
4044 	fclose(file->stream);
4045 	free(file->name);
4046 	free(file->ungetbuf);
4047 	free(file);
4048 	file = prev;
4049 	return (file ? 0 : EOF);
4050 }
4051 
4052 static void
4053 init_config(struct bgpd_config *c)
4054 {
4055 	u_int rdomid;
4056 
4057 	c->min_holdtime = MIN_HOLDTIME;
4058 	c->holdtime = INTERVAL_HOLD;
4059 	c->staletime = INTERVAL_STALE;
4060 	c->connectretry = INTERVAL_CONNECTRETRY;
4061 	c->bgpid = get_bgpid();
4062 	c->fib_priority = kr_default_prio();
4063 	c->default_tableid = getrtable();
4064 	if (!ktable_exists(c->default_tableid, &rdomid))
4065 		fatalx("current routing table %u does not exist",
4066 		    c->default_tableid);
4067 	if (rdomid != c->default_tableid)
4068 		fatalx("current routing table %u is not a routing domain",
4069 		    c->default_tableid);
4070 
4071 	if (asprintf(&c->csock, "%s.%d", SOCKET_NAME, c->default_tableid) == -1)
4072 		fatal(NULL);
4073 }
4074 
4075 struct bgpd_config *
4076 parse_config(char *filename, struct peer_head *ph, struct rtr_config_head *rh)
4077 {
4078 	struct sym		*sym, *next;
4079 	struct rde_rib		*rr;
4080 	struct network		*n;
4081 	int			 errors = 0;
4082 
4083 	conf = new_config();
4084 	init_config(conf);
4085 
4086 	if ((filter_l = calloc(1, sizeof(struct filter_head))) == NULL)
4087 		fatal(NULL);
4088 	if ((peerfilter_l = calloc(1, sizeof(struct filter_head))) == NULL)
4089 		fatal(NULL);
4090 	if ((groupfilter_l = calloc(1, sizeof(struct filter_head))) == NULL)
4091 		fatal(NULL);
4092 	TAILQ_INIT(filter_l);
4093 	TAILQ_INIT(peerfilter_l);
4094 	TAILQ_INIT(groupfilter_l);
4095 
4096 	curpeer = NULL;
4097 	curgroup = NULL;
4098 
4099 	cur_peers = ph;
4100 	cur_rtrs = rh;
4101 	new_peers = &conf->peers;
4102 	netconf = &conf->networks;
4103 
4104 	if ((rr = add_rib("Adj-RIB-In")) == NULL)
4105 		fatal("add_rib failed");
4106 	rr->flags = F_RIB_NOFIB | F_RIB_NOEVALUATE;
4107 	if ((rr = add_rib("Loc-RIB")) == NULL)
4108 		fatal("add_rib failed");
4109 	rib_add_fib(rr, conf->default_tableid);
4110 	rr->flags = F_RIB_LOCAL;
4111 
4112 	if ((file = pushfile(filename, 1)) == NULL)
4113 		goto errors;
4114 	topfile = file;
4115 
4116 	yyparse();
4117 	errors = file->errors;
4118 	popfile();
4119 
4120 	/* check that we dont try to announce our own routes */
4121 	TAILQ_FOREACH(n, netconf, entry)
4122 	    if (n->net.priority == conf->fib_priority) {
4123 		    errors++;
4124 		    logit(LOG_CRIT, "network priority %d == fib-priority "
4125 			"%d is not allowed.",
4126 			n->net.priority, conf->fib_priority);
4127 	    }
4128 
4129 	/* Free macros and check which have not been used. */
4130 	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
4131 		if ((cmd_opts & BGPD_OPT_VERBOSE2) && !sym->used)
4132 			fprintf(stderr, "warning: macro \"%s\" not "
4133 			    "used\n", sym->nam);
4134 		if (!sym->persist) {
4135 			free(sym->nam);
4136 			free(sym->val);
4137 			TAILQ_REMOVE(&symhead, sym, entry);
4138 			free(sym);
4139 		}
4140 	}
4141 
4142 	if (!conf->as) {
4143 		log_warnx("configuration error: AS not given");
4144 		errors++;
4145 	}
4146 
4147 	/* clear the globals */
4148 	curpeer = NULL;
4149 	curgroup = NULL;
4150 	cur_peers = NULL;
4151 	new_peers = NULL;
4152 	netconf = NULL;
4153 	curflow = NULL;
4154 
4155 	if (errors) {
4156 errors:
4157 		while ((rr = SIMPLEQ_FIRST(&ribnames)) != NULL) {
4158 			SIMPLEQ_REMOVE_HEAD(&ribnames, entry);
4159 			free(rr);
4160 		}
4161 
4162 		filterlist_free(filter_l);
4163 		filterlist_free(peerfilter_l);
4164 		filterlist_free(groupfilter_l);
4165 
4166 		free_config(conf);
4167 		return (NULL);
4168 	}
4169 
4170 	/* Create default listeners if none where specified. */
4171 	if (TAILQ_EMPTY(conf->listen_addrs)) {
4172 		struct listen_addr *la;
4173 
4174 		if ((la = calloc(1, sizeof(struct listen_addr))) == NULL)
4175 			fatal("setup_listeners calloc");
4176 		la->fd = -1;
4177 		la->flags = DEFAULT_LISTENER;
4178 		la->reconf = RECONF_REINIT;
4179 		la->sa_len = sizeof(struct sockaddr_in);
4180 		((struct sockaddr_in *)&la->sa)->sin_family = AF_INET;
4181 		((struct sockaddr_in *)&la->sa)->sin_addr.s_addr =
4182 		    htonl(INADDR_ANY);
4183 		((struct sockaddr_in *)&la->sa)->sin_port = htons(BGP_PORT);
4184 		TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry);
4185 
4186 		if ((la = calloc(1, sizeof(struct listen_addr))) == NULL)
4187 			fatal("setup_listeners calloc");
4188 		la->fd = -1;
4189 		la->flags = DEFAULT_LISTENER;
4190 		la->reconf = RECONF_REINIT;
4191 		la->sa_len = sizeof(struct sockaddr_in6);
4192 		((struct sockaddr_in6 *)&la->sa)->sin6_family = AF_INET6;
4193 		((struct sockaddr_in6 *)&la->sa)->sin6_port = htons(BGP_PORT);
4194 		TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry);
4195 	}
4196 
4197 	/* update clusterid in case it was not set explicitly */
4198 	if ((conf->flags & BGPD_FLAG_REFLECTOR) && conf->clusterid == 0)
4199 		conf->clusterid = conf->bgpid;
4200 
4201 	/*
4202 	 * Concatenate filter list and static group and peer filtersets
4203 	 * together. Static group sets come first then peer sets
4204 	 * last normal filter rules.
4205 	 */
4206 	TAILQ_CONCAT(conf->filters, groupfilter_l, entry);
4207 	TAILQ_CONCAT(conf->filters, peerfilter_l, entry);
4208 	TAILQ_CONCAT(conf->filters, filter_l, entry);
4209 
4210 	optimize_filters(conf->filters);
4211 
4212 	free(filter_l);
4213 	free(peerfilter_l);
4214 	free(groupfilter_l);
4215 
4216 	return (conf);
4217 }
4218 
4219 int
4220 symset(const char *nam, const char *val, int persist)
4221 {
4222 	struct sym	*sym;
4223 
4224 	TAILQ_FOREACH(sym, &symhead, entry) {
4225 		if (strcmp(nam, sym->nam) == 0)
4226 			break;
4227 	}
4228 
4229 	if (sym != NULL) {
4230 		if (sym->persist == 1)
4231 			return (0);
4232 		else {
4233 			free(sym->nam);
4234 			free(sym->val);
4235 			TAILQ_REMOVE(&symhead, sym, entry);
4236 			free(sym);
4237 		}
4238 	}
4239 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
4240 		return (-1);
4241 
4242 	sym->nam = strdup(nam);
4243 	if (sym->nam == NULL) {
4244 		free(sym);
4245 		return (-1);
4246 	}
4247 	sym->val = strdup(val);
4248 	if (sym->val == NULL) {
4249 		free(sym->nam);
4250 		free(sym);
4251 		return (-1);
4252 	}
4253 	sym->used = 0;
4254 	sym->persist = persist;
4255 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
4256 	return (0);
4257 }
4258 
4259 int
4260 cmdline_symset(char *s)
4261 {
4262 	char	*sym, *val;
4263 	int	ret;
4264 
4265 	if ((val = strrchr(s, '=')) == NULL)
4266 		return (-1);
4267 	sym = strndup(s, val - s);
4268 	if (sym == NULL)
4269 		fatal("%s: strndup", __func__);
4270 	ret = symset(sym, val + 1, 1);
4271 	free(sym);
4272 
4273 	return (ret);
4274 }
4275 
4276 char *
4277 symget(const char *nam)
4278 {
4279 	struct sym	*sym;
4280 
4281 	TAILQ_FOREACH(sym, &symhead, entry) {
4282 		if (strcmp(nam, sym->nam) == 0) {
4283 			sym->used = 1;
4284 			return (sym->val);
4285 		}
4286 	}
4287 	return (NULL);
4288 }
4289 
4290 static int
4291 cmpcommunity(struct community *a, struct community *b)
4292 {
4293 	if (a->flags > b->flags)
4294 		return 1;
4295 	if (a->flags < b->flags)
4296 		return -1;
4297 	if (a->data1 > b->data1)
4298 		return 1;
4299 	if (a->data1 < b->data1)
4300 		return -1;
4301 	if (a->data2 > b->data2)
4302 		return 1;
4303 	if (a->data2 < b->data2)
4304 		return -1;
4305 	if (a->data3 > b->data3)
4306 		return 1;
4307 	if (a->data3 < b->data3)
4308 		return -1;
4309 	return 0;
4310 }
4311 
4312 static int
4313 getcommunity(char *s, int large, uint32_t *val, uint32_t *flag)
4314 {
4315 	long long	 max = USHRT_MAX;
4316 	const char	*errstr;
4317 
4318 	*flag = 0;
4319 	*val = 0;
4320 	if (strcmp(s, "*") == 0) {
4321 		*flag = COMMUNITY_ANY;
4322 		return 0;
4323 	} else if (strcmp(s, "neighbor-as") == 0) {
4324 		*flag = COMMUNITY_NEIGHBOR_AS;
4325 		return 0;
4326 	} else if (strcmp(s, "local-as") == 0) {
4327 		*flag = COMMUNITY_LOCAL_AS;
4328 		return 0;
4329 	}
4330 	if (large)
4331 		max = UINT_MAX;
4332 	*val = strtonum(s, 0, max, &errstr);
4333 	if (errstr) {
4334 		yyerror("Community %s is %s (max: %lld)", s, errstr, max);
4335 		return -1;
4336 	}
4337 	return 0;
4338 }
4339 
4340 static void
4341 setcommunity(struct community *c, uint32_t as, uint32_t data,
4342     uint32_t asflag, uint32_t dataflag)
4343 {
4344 	c->flags = COMMUNITY_TYPE_BASIC;
4345 	c->flags |= asflag << 8;
4346 	c->flags |= dataflag << 16;
4347 	c->data1 = as;
4348 	c->data2 = data;
4349 	c->data3 = 0;
4350 }
4351 
4352 static int
4353 parselargecommunity(struct community *c, char *s)
4354 {
4355 	char *p, *q;
4356 	uint32_t dflag1, dflag2, dflag3;
4357 
4358 	if ((p = strchr(s, ':')) == NULL) {
4359 		yyerror("Bad community syntax");
4360 		return (-1);
4361 	}
4362 	*p++ = 0;
4363 
4364 	if ((q = strchr(p, ':')) == NULL) {
4365 		yyerror("Bad community syntax");
4366 		return (-1);
4367 	}
4368 	*q++ = 0;
4369 
4370 	if (getcommunity(s, 1, &c->data1, &dflag1) == -1 ||
4371 	    getcommunity(p, 1, &c->data2, &dflag2) == -1 ||
4372 	    getcommunity(q, 1, &c->data3, &dflag3) == -1)
4373 		return (-1);
4374 	c->flags = COMMUNITY_TYPE_LARGE;
4375 	c->flags |= dflag1 << 8;
4376 	c->flags |= dflag2 << 16;
4377 	c->flags |= dflag3 << 24;
4378 	return (0);
4379 }
4380 
4381 int
4382 parsecommunity(struct community *c, int type, char *s)
4383 {
4384 	char *p;
4385 	uint32_t as, data, asflag, dataflag;
4386 
4387 	if (type == COMMUNITY_TYPE_LARGE)
4388 		return parselargecommunity(c, s);
4389 
4390 	/* Well-known communities */
4391 	if (strcasecmp(s, "GRACEFUL_SHUTDOWN") == 0) {
4392 		setcommunity(c, COMMUNITY_WELLKNOWN,
4393 		    COMMUNITY_GRACEFUL_SHUTDOWN, 0, 0);
4394 		return (0);
4395 	} else if (strcasecmp(s, "NO_EXPORT") == 0) {
4396 		setcommunity(c, COMMUNITY_WELLKNOWN,
4397 		    COMMUNITY_NO_EXPORT, 0, 0);
4398 		return (0);
4399 	} else if (strcasecmp(s, "NO_ADVERTISE") == 0) {
4400 		setcommunity(c, COMMUNITY_WELLKNOWN,
4401 		    COMMUNITY_NO_ADVERTISE, 0, 0);
4402 		return (0);
4403 	} else if (strcasecmp(s, "NO_EXPORT_SUBCONFED") == 0) {
4404 		setcommunity(c, COMMUNITY_WELLKNOWN,
4405 		    COMMUNITY_NO_EXPSUBCONFED, 0, 0);
4406 		return (0);
4407 	} else if (strcasecmp(s, "NO_PEER") == 0) {
4408 		setcommunity(c, COMMUNITY_WELLKNOWN,
4409 		    COMMUNITY_NO_PEER, 0, 0);
4410 		return (0);
4411 	} else if (strcasecmp(s, "BLACKHOLE") == 0) {
4412 		setcommunity(c, COMMUNITY_WELLKNOWN,
4413 		    COMMUNITY_BLACKHOLE, 0, 0);
4414 		return (0);
4415 	}
4416 
4417 	if ((p = strchr(s, ':')) == NULL) {
4418 		yyerror("Bad community syntax");
4419 		return (-1);
4420 	}
4421 	*p++ = 0;
4422 
4423 	if (getcommunity(s, 0, &as, &asflag) == -1 ||
4424 	    getcommunity(p, 0, &data, &dataflag) == -1)
4425 		return (-1);
4426 	setcommunity(c, as, data, asflag, dataflag);
4427 	return (0);
4428 }
4429 
4430 static int
4431 parsesubtype(char *name, int *type, int *subtype)
4432 {
4433 	const struct ext_comm_pairs *cp;
4434 	int found = 0;
4435 
4436 	for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
4437 		if (strcmp(name, cp->subname) == 0) {
4438 			if (found == 0) {
4439 				*type = cp->type;
4440 				*subtype = cp->subtype;
4441 			}
4442 			found++;
4443 		}
4444 	}
4445 	if (found > 1)
4446 		*type = -1;
4447 	return (found);
4448 }
4449 
4450 static int
4451 parseextvalue(int type, char *s, uint32_t *v, uint32_t *flag)
4452 {
4453 	const char	*errstr;
4454 	char		*p;
4455 	struct in_addr	 ip;
4456 	uint32_t	 uvalh, uval;
4457 
4458 	if (type != -1) {
4459 		/* nothing */
4460 	} else if (strcmp(s, "neighbor-as") == 0) {
4461 		*flag = COMMUNITY_NEIGHBOR_AS;
4462 		*v = 0;
4463 		return EXT_COMMUNITY_TRANS_TWO_AS;
4464 	} else if (strcmp(s, "local-as") == 0) {
4465 		*flag = COMMUNITY_LOCAL_AS;
4466 		*v = 0;
4467 		return EXT_COMMUNITY_TRANS_TWO_AS;
4468 	} else if ((p = strchr(s, '.')) == NULL) {
4469 		/* AS_PLAIN number (4 or 2 byte) */
4470 		strtonum(s, 0, USHRT_MAX, &errstr);
4471 		if (errstr == NULL)
4472 			type = EXT_COMMUNITY_TRANS_TWO_AS;
4473 		else
4474 			type = EXT_COMMUNITY_TRANS_FOUR_AS;
4475 	} else if (strchr(p + 1, '.') == NULL) {
4476 		/* AS_DOT number (4-byte) */
4477 		type = EXT_COMMUNITY_TRANS_FOUR_AS;
4478 	} else {
4479 		/* more than one dot -> IP address */
4480 		type = EXT_COMMUNITY_TRANS_IPV4;
4481 	}
4482 
4483 	switch (type & EXT_COMMUNITY_VALUE) {
4484 	case EXT_COMMUNITY_TRANS_TWO_AS:
4485 		uval = strtonum(s, 0, USHRT_MAX, &errstr);
4486 		if (errstr) {
4487 			yyerror("Bad ext-community %s is %s", s, errstr);
4488 			return (-1);
4489 		}
4490 		*v = uval;
4491 		break;
4492 	case EXT_COMMUNITY_TRANS_FOUR_AS:
4493 		if ((p = strchr(s, '.')) == NULL) {
4494 			uval = strtonum(s, 0, UINT_MAX, &errstr);
4495 			if (errstr) {
4496 				yyerror("Bad ext-community %s is %s", s,
4497 				    errstr);
4498 				return (-1);
4499 			}
4500 			*v = uval;
4501 			break;
4502 		}
4503 		*p++ = '\0';
4504 		uvalh = strtonum(s, 0, USHRT_MAX, &errstr);
4505 		if (errstr) {
4506 			yyerror("Bad ext-community %s is %s", s, errstr);
4507 			return (-1);
4508 		}
4509 		uval = strtonum(p, 0, USHRT_MAX, &errstr);
4510 		if (errstr) {
4511 			yyerror("Bad ext-community %s is %s", p, errstr);
4512 			return (-1);
4513 		}
4514 		*v = uval | (uvalh << 16);
4515 		break;
4516 	case EXT_COMMUNITY_TRANS_IPV4:
4517 		if (inet_pton(AF_INET, s, &ip) != 1) {
4518 			yyerror("Bad ext-community %s not parseable", s);
4519 			return (-1);
4520 		}
4521 		*v = ntohl(ip.s_addr);
4522 		break;
4523 	default:
4524 		fatalx("%s: unexpected type %d", __func__, type);
4525 	}
4526 	return (type);
4527 }
4528 
4529 int
4530 parseextcommunity(struct community *c, char *t, char *s)
4531 {
4532 	const struct ext_comm_pairs *cp;
4533 	char		*p, *ep;
4534 	uint64_t	 ullval;
4535 	uint32_t	 uval, uval2, dflag1 = 0, dflag2 = 0;
4536 	int		 type = 0, subtype = 0;
4537 
4538 	if (strcmp(t, "*") == 0 && strcmp(s, "*") == 0) {
4539 		c->flags = COMMUNITY_TYPE_EXT;
4540 		c->flags |= COMMUNITY_ANY << 24;
4541 		return (0);
4542 	}
4543 	if (parsesubtype(t, &type, &subtype) == 0) {
4544 		yyerror("Bad ext-community unknown type");
4545 		return (-1);
4546 	}
4547 
4548 	switch (type) {
4549 	case EXT_COMMUNITY_TRANS_TWO_AS:
4550 	case EXT_COMMUNITY_TRANS_FOUR_AS:
4551 	case EXT_COMMUNITY_TRANS_IPV4:
4552 	case EXT_COMMUNITY_GEN_TWO_AS:
4553 	case EXT_COMMUNITY_GEN_FOUR_AS:
4554 	case EXT_COMMUNITY_GEN_IPV4:
4555 	case -1:
4556 		if (strcmp(s, "*") == 0) {
4557 			dflag1 = COMMUNITY_ANY;
4558 			break;
4559 		}
4560 		if ((p = strchr(s, ':')) == NULL) {
4561 			yyerror("Bad ext-community %s", s);
4562 			return (-1);
4563 		}
4564 		*p++ = '\0';
4565 		if ((type = parseextvalue(type, s, &uval, &dflag1)) == -1)
4566 			return (-1);
4567 
4568 		switch (type) {
4569 		case EXT_COMMUNITY_TRANS_TWO_AS:
4570 		case EXT_COMMUNITY_GEN_TWO_AS:
4571 			if (getcommunity(p, 1, &uval2, &dflag2) == -1)
4572 				return (-1);
4573 			break;
4574 		case EXT_COMMUNITY_TRANS_IPV4:
4575 		case EXT_COMMUNITY_TRANS_FOUR_AS:
4576 		case EXT_COMMUNITY_GEN_IPV4:
4577 		case EXT_COMMUNITY_GEN_FOUR_AS:
4578 			if (getcommunity(p, 0, &uval2, &dflag2) == -1)
4579 				return (-1);
4580 			break;
4581 		default:
4582 			fatalx("parseextcommunity: unexpected result");
4583 		}
4584 
4585 		c->data1 = uval;
4586 		c->data2 = uval2;
4587 		break;
4588 	case EXT_COMMUNITY_TRANS_OPAQUE:
4589 	case EXT_COMMUNITY_TRANS_EVPN:
4590 		if (strcmp(s, "*") == 0) {
4591 			dflag1 = COMMUNITY_ANY;
4592 			break;
4593 		}
4594 		errno = 0;
4595 		ullval = strtoull(s, &ep, 0);
4596 		if (s[0] == '\0' || *ep != '\0') {
4597 			yyerror("Bad ext-community bad value");
4598 			return (-1);
4599 		}
4600 		if (errno == ERANGE && ullval > EXT_COMMUNITY_OPAQUE_MAX) {
4601 			yyerror("Bad ext-community value too big");
4602 			return (-1);
4603 		}
4604 		c->data1 = ullval >> 32;
4605 		c->data2 = ullval;
4606 		break;
4607 	case EXT_COMMUNITY_NON_TRANS_OPAQUE:
4608 		if (subtype == EXT_COMMUNITY_SUBTYPE_OVS) {
4609 			if (strcmp(s, "valid") == 0) {
4610 				c->data2 = EXT_COMMUNITY_OVS_VALID;
4611 				break;
4612 			} else if (strcmp(s, "invalid") == 0) {
4613 				c->data2 = EXT_COMMUNITY_OVS_INVALID;
4614 				break;
4615 			} else if (strcmp(s, "not-found") == 0) {
4616 				c->data2 = EXT_COMMUNITY_OVS_NOTFOUND;
4617 				break;
4618 			} else if (strcmp(s, "*") == 0) {
4619 				dflag1 = COMMUNITY_ANY;
4620 				break;
4621 			}
4622 		}
4623 		yyerror("Bad ext-community %s", s);
4624 		return (-1);
4625 	}
4626 
4627 	c->data3 = type << 8 | subtype;
4628 
4629 	/* special handling of ext-community rt * since type is not known */
4630 	if (dflag1 == COMMUNITY_ANY && type == -1) {
4631 		c->flags = COMMUNITY_TYPE_EXT;
4632 		c->flags |= dflag1 << 8;
4633 		return (0);
4634 	}
4635 
4636 	/* verify type/subtype combo */
4637 	for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
4638 		if (cp->type == type && cp->subtype == subtype) {
4639 			c->flags = COMMUNITY_TYPE_EXT;
4640 			c->flags |= dflag1 << 8;
4641 			c->flags |= dflag2 << 16;
4642 			return (0);
4643 		}
4644 	}
4645 
4646 	yyerror("Bad ext-community bad format for type");
4647 	return (-1);
4648 }
4649 
4650 struct peer *
4651 alloc_peer(void)
4652 {
4653 	struct peer	*p;
4654 
4655 	if ((p = calloc(1, sizeof(struct peer))) == NULL)
4656 		fatal("new_peer");
4657 
4658 	/* some sane defaults */
4659 	p->state = STATE_NONE;
4660 	p->reconf_action = RECONF_REINIT;
4661 	p->conf.distance = 1;
4662 	p->conf.export_type = EXPORT_UNSET;
4663 	p->conf.capabilities.refresh = 1;
4664 	p->conf.capabilities.grestart.restart = 1;
4665 	p->conf.capabilities.as4byte = 1;
4666 	p->conf.capabilities.policy = 1;
4667 	p->conf.local_as = conf->as;
4668 	p->conf.local_short_as = conf->short_as;
4669 	p->conf.remote_port = BGP_PORT;
4670 
4671 	if (conf->flags & BGPD_FLAG_DECISION_TRANS_AS)
4672 		p->conf.flags |= PEERFLAG_TRANS_AS;
4673 	if (conf->flags & BGPD_FLAG_DECISION_ALL_PATHS)
4674 		p->conf.flags |= PEERFLAG_EVALUATE_ALL;
4675 	if (conf->flags & BGPD_FLAG_PERMIT_AS_SET)
4676 		p->conf.flags |= PEERFLAG_PERMIT_AS_SET;
4677 
4678 	return (p);
4679 }
4680 
4681 struct peer *
4682 new_peer(void)
4683 {
4684 	struct peer		*p;
4685 
4686 	p = alloc_peer();
4687 
4688 	if (curgroup != NULL) {
4689 		memcpy(p, curgroup, sizeof(struct peer));
4690 		p->conf.groupid = curgroup->conf.id;
4691 	}
4692 	return (p);
4693 }
4694 
4695 struct peer *
4696 new_group(void)
4697 {
4698 	return (alloc_peer());
4699 }
4700 
4701 int
4702 add_mrtconfig(enum mrt_type type, char *name, int timeout, struct peer *p,
4703     char *rib)
4704 {
4705 	struct mrt	*m, *n;
4706 
4707 	LIST_FOREACH(m, conf->mrt, entry) {
4708 		if ((rib && strcmp(rib, m->rib)) ||
4709 		    (!rib && *m->rib))
4710 			continue;
4711 		if (p == NULL) {
4712 			if (m->peer_id != 0 || m->group_id != 0)
4713 				continue;
4714 		} else {
4715 			if (m->peer_id != p->conf.id ||
4716 			    m->group_id != p->conf.groupid)
4717 				continue;
4718 		}
4719 		if (m->type == type) {
4720 			yyerror("only one mrtdump per type allowed.");
4721 			return (-1);
4722 		}
4723 	}
4724 
4725 	if ((n = calloc(1, sizeof(struct mrt_config))) == NULL)
4726 		fatal("add_mrtconfig");
4727 
4728 	n->type = type;
4729 	n->state = MRT_STATE_OPEN;
4730 	if (strlcpy(MRT2MC(n)->name, name, sizeof(MRT2MC(n)->name)) >=
4731 	    sizeof(MRT2MC(n)->name)) {
4732 		yyerror("filename \"%s\" too long: max %zu",
4733 		    name, sizeof(MRT2MC(n)->name) - 1);
4734 		free(n);
4735 		return (-1);
4736 	}
4737 	MRT2MC(n)->ReopenTimerInterval = timeout;
4738 	if (p != NULL) {
4739 		if (curgroup == p) {
4740 			n->peer_id = 0;
4741 			n->group_id = p->conf.id;
4742 		} else {
4743 			n->peer_id = p->conf.id;
4744 			n->group_id = p->conf.groupid;
4745 		}
4746 	}
4747 	if (rib) {
4748 		if (!find_rib(rib)) {
4749 			yyerror("rib \"%s\" does not exist.", rib);
4750 			free(n);
4751 			return (-1);
4752 		}
4753 		if (strlcpy(n->rib, rib, sizeof(n->rib)) >=
4754 		    sizeof(n->rib)) {
4755 			yyerror("rib name \"%s\" too long: max %zu",
4756 			    name, sizeof(n->rib) - 1);
4757 			free(n);
4758 			return (-1);
4759 		}
4760 	}
4761 
4762 	LIST_INSERT_HEAD(conf->mrt, n, entry);
4763 
4764 	return (0);
4765 }
4766 
4767 struct rde_rib *
4768 add_rib(char *name)
4769 {
4770 	struct rde_rib	*rr;
4771 
4772 	if ((rr = find_rib(name)) == NULL) {
4773 		if ((rr = calloc(1, sizeof(*rr))) == NULL) {
4774 			log_warn("add_rib");
4775 			return (NULL);
4776 		}
4777 		if (strlcpy(rr->name, name, sizeof(rr->name)) >=
4778 		    sizeof(rr->name)) {
4779 			yyerror("rib name \"%s\" too long: max %zu",
4780 			    name, sizeof(rr->name) - 1);
4781 			free(rr);
4782 			return (NULL);
4783 		}
4784 		rr->flags = F_RIB_NOFIB;
4785 		SIMPLEQ_INSERT_TAIL(&ribnames, rr, entry);
4786 	}
4787 	return (rr);
4788 }
4789 
4790 struct rde_rib *
4791 find_rib(char *name)
4792 {
4793 	struct rde_rib	*rr;
4794 
4795 	SIMPLEQ_FOREACH(rr, &ribnames, entry) {
4796 		if (!strcmp(rr->name, name))
4797 			return (rr);
4798 	}
4799 	return (NULL);
4800 }
4801 
4802 int
4803 rib_add_fib(struct rde_rib *rr, u_int rtableid)
4804 {
4805 	u_int	rdom;
4806 
4807 	if (!ktable_exists(rtableid, &rdom)) {
4808 		yyerror("rtable id %u does not exist", rtableid);
4809 		return (-1);
4810 	}
4811 	/*
4812 	 * conf->default_tableid is also a rdomain because that is checked
4813 	 * in init_config()
4814 	 */
4815 	if (rdom != conf->default_tableid) {
4816 		log_warnx("rtable %u does not belong to rdomain %u",
4817 		    rtableid, conf->default_tableid);
4818 		return (-1);
4819 	}
4820 	rr->rtableid = rtableid;
4821 	rr->flags &= ~F_RIB_NOFIB;
4822 	return (0);
4823 }
4824 
4825 struct prefixset *
4826 find_prefixset(char *name, struct prefixset_head *p)
4827 {
4828 	struct prefixset *ps;
4829 
4830 	SIMPLEQ_FOREACH(ps, p, entry) {
4831 		if (!strcmp(ps->name, name))
4832 			return (ps);
4833 	}
4834 	return (NULL);
4835 }
4836 
4837 int
4838 get_id(struct peer *newpeer)
4839 {
4840 	static uint32_t id = PEER_ID_STATIC_MIN;
4841 	struct peer	*p = NULL;
4842 
4843 	/* check if the peer already existed before */
4844 	if (newpeer->conf.remote_addr.aid) {
4845 		/* neighbor */
4846 		if (cur_peers)
4847 			RB_FOREACH(p, peer_head, cur_peers)
4848 				if (p->conf.remote_masklen ==
4849 				    newpeer->conf.remote_masklen &&
4850 				    memcmp(&p->conf.remote_addr,
4851 				    &newpeer->conf.remote_addr,
4852 				    sizeof(p->conf.remote_addr)) == 0)
4853 					break;
4854 		if (p) {
4855 			newpeer->conf.id = p->conf.id;
4856 			return (0);
4857 		}
4858 	} else {
4859 		/* group */
4860 		if (cur_peers)
4861 			RB_FOREACH(p, peer_head, cur_peers)
4862 				if (strcmp(p->conf.group,
4863 				    newpeer->conf.group) == 0)
4864 					break;
4865 		if (p) {
4866 			newpeer->conf.id = p->conf.groupid;
4867 			return (0);
4868 		}
4869 	}
4870 
4871 	/* else new one */
4872 	if (id < PEER_ID_STATIC_MAX) {
4873 		newpeer->conf.id = id++;
4874 		return (0);
4875 	}
4876 
4877 	return (-1);
4878 }
4879 
4880 int
4881 merge_prefixspec(struct filter_prefix *p, struct filter_prefixlen *pl)
4882 {
4883 	uint8_t max_len = 0;
4884 
4885 	switch (p->addr.aid) {
4886 	case AID_INET:
4887 	case AID_VPN_IPv4:
4888 		max_len = 32;
4889 		break;
4890 	case AID_INET6:
4891 	case AID_VPN_IPv6:
4892 		max_len = 128;
4893 		break;
4894 	}
4895 
4896 	if (pl->op == OP_NONE) {
4897 		p->len_min = p->len_max = p->len;
4898 		return (0);
4899 	}
4900 
4901 	if (pl->len_min == -1)
4902 		pl->len_min = p->len;
4903 	if (pl->len_max == -1)
4904 		pl->len_max = max_len;
4905 
4906 	if (pl->len_max > max_len) {
4907 		yyerror("prefixlen %d too big, limit %d",
4908 		    pl->len_max, max_len);
4909 		return (-1);
4910 	}
4911 	if (pl->len_min > pl->len_max) {
4912 		yyerror("prefixlen %d too big, limit %d",
4913 		    pl->len_min, pl->len_max);
4914 		return (-1);
4915 	}
4916 	if (pl->len_min < p->len) {
4917 		yyerror("prefixlen %d smaller than prefix, limit %d",
4918 		    pl->len_min, p->len);
4919 		return (-1);
4920 	}
4921 
4922 	p->op = pl->op;
4923 	p->len_min = pl->len_min;
4924 	p->len_max = pl->len_max;
4925 	return (0);
4926 }
4927 
4928 int
4929 expand_rule(struct filter_rule *rule, struct filter_rib_l *rib,
4930     struct filter_peers_l *peer, struct filter_match_l *match,
4931     struct filter_set_head *set)
4932 {
4933 	struct filter_rule	*r;
4934 	struct filter_rib_l	*rb, *rbnext;
4935 	struct filter_peers_l	*p, *pnext;
4936 	struct filter_prefix_l	*prefix, *prefix_next;
4937 	struct filter_as_l	*a, *anext;
4938 	struct filter_set	*s;
4939 
4940 	rb = rib;
4941 	do {
4942 		p = peer;
4943 		do {
4944 			a = match->as_l;
4945 			do {
4946 				prefix = match->prefix_l;
4947 				do {
4948 					if ((r = calloc(1,
4949 					    sizeof(struct filter_rule))) ==
4950 						 NULL) {
4951 						log_warn("expand_rule");
4952 						return (-1);
4953 					}
4954 
4955 					memcpy(r, rule, sizeof(struct filter_rule));
4956 					memcpy(&r->match, match,
4957 					    sizeof(struct filter_match));
4958 					filterset_copy(set, &r->set);
4959 
4960 					if (rb != NULL)
4961 						strlcpy(r->rib, rb->name,
4962 						    sizeof(r->rib));
4963 
4964 					if (p != NULL)
4965 						memcpy(&r->peer, &p->p,
4966 						    sizeof(struct filter_peers));
4967 
4968 					if (prefix != NULL)
4969 						memcpy(&r->match.prefix, &prefix->p,
4970 						    sizeof(r->match.prefix));
4971 
4972 					if (a != NULL)
4973 						memcpy(&r->match.as, &a->a,
4974 						    sizeof(struct filter_as));
4975 
4976 					TAILQ_INSERT_TAIL(filter_l, r, entry);
4977 
4978 					if (prefix != NULL)
4979 						prefix = prefix->next;
4980 				} while (prefix != NULL);
4981 
4982 				if (a != NULL)
4983 					a = a->next;
4984 			} while (a != NULL);
4985 
4986 			if (p != NULL)
4987 				p = p->next;
4988 		} while (p != NULL);
4989 
4990 		if (rb != NULL)
4991 			rb = rb->next;
4992 	} while (rb != NULL);
4993 
4994 	for (rb = rib; rb != NULL; rb = rbnext) {
4995 		rbnext = rb->next;
4996 		free(rb);
4997 	}
4998 
4999 	for (p = peer; p != NULL; p = pnext) {
5000 		pnext = p->next;
5001 		free(p);
5002 	}
5003 
5004 	for (a = match->as_l; a != NULL; a = anext) {
5005 		anext = a->next;
5006 		free(a);
5007 	}
5008 
5009 	for (prefix = match->prefix_l; prefix != NULL; prefix = prefix_next) {
5010 		prefix_next = prefix->next;
5011 		free(prefix);
5012 	}
5013 
5014 	if (set != NULL) {
5015 		while ((s = TAILQ_FIRST(set)) != NULL) {
5016 			TAILQ_REMOVE(set, s, entry);
5017 			free(s);
5018 		}
5019 		free(set);
5020 	}
5021 
5022 	return (0);
5023 }
5024 
5025 static int
5026 h2i(char c)
5027 {
5028 	if (c >= '0' && c <= '9')
5029 		return c - '0';
5030 	else if (c >= 'a' && c <= 'f')
5031 		return c - 'a' + 10;
5032 	else if (c >= 'A' && c <= 'F')
5033 		return c - 'A' + 10;
5034 	else
5035 		return -1;
5036 }
5037 
5038 int
5039 str2key(char *s, char *dest, size_t max_len)
5040 {
5041 	size_t	i;
5042 
5043 	if (strlen(s) / 2 > max_len) {
5044 		yyerror("key too long");
5045 		return (-1);
5046 	}
5047 
5048 	if (strlen(s) % 2) {
5049 		yyerror("key must be of even length");
5050 		return (-1);
5051 	}
5052 
5053 	for (i = 0; i < strlen(s) / 2; i++) {
5054 		int hi, lo;
5055 
5056 		hi = h2i(s[2 * i]);
5057 		lo = h2i(s[2 * i + 1]);
5058 		if (hi == -1 || lo == -1) {
5059 			yyerror("key must be specified in hex");
5060 			return (-1);
5061 		}
5062 		dest[i] = (hi << 4) | lo;
5063 	}
5064 
5065 	return (0);
5066 }
5067 
5068 int
5069 neighbor_consistent(struct peer *p)
5070 {
5071 	struct bgpd_addr *local_addr;
5072 	struct peer *xp;
5073 
5074 	switch (p->conf.remote_addr.aid) {
5075 	case AID_INET:
5076 		local_addr = &p->conf.local_addr_v4;
5077 		break;
5078 	case AID_INET6:
5079 		local_addr = &p->conf.local_addr_v6;
5080 		break;
5081 	default:
5082 		yyerror("Bad address family for remote-addr");
5083 		return (-1);
5084 	}
5085 
5086 	/* with any form of ipsec local-address is required */
5087 	if ((p->auth_conf.method == AUTH_IPSEC_IKE_ESP ||
5088 	    p->auth_conf.method == AUTH_IPSEC_IKE_AH ||
5089 	    p->auth_conf.method == AUTH_IPSEC_MANUAL_ESP ||
5090 	    p->auth_conf.method == AUTH_IPSEC_MANUAL_AH) &&
5091 	    local_addr->aid == AID_UNSPEC) {
5092 		yyerror("neighbors with any form of IPsec configured "
5093 		    "need local-address to be specified");
5094 		return (-1);
5095 	}
5096 
5097 	/* with static keying we need both directions */
5098 	if ((p->auth_conf.method == AUTH_IPSEC_MANUAL_ESP ||
5099 	    p->auth_conf.method == AUTH_IPSEC_MANUAL_AH) &&
5100 	    (!p->auth_conf.spi_in || !p->auth_conf.spi_out)) {
5101 		yyerror("with manual keyed IPsec, SPIs and keys "
5102 		    "for both directions are required");
5103 		return (-1);
5104 	}
5105 
5106 	if (!conf->as) {
5107 		yyerror("AS needs to be given before neighbor definitions");
5108 		return (-1);
5109 	}
5110 
5111 	/* set default values if they where undefined */
5112 	p->conf.ebgp = (p->conf.remote_as != conf->as);
5113 	if (p->conf.enforce_as == ENFORCE_AS_UNDEF)
5114 		p->conf.enforce_as = p->conf.ebgp ?
5115 		    ENFORCE_AS_ON : ENFORCE_AS_OFF;
5116 	if (p->conf.enforce_local_as == ENFORCE_AS_UNDEF)
5117 		p->conf.enforce_local_as = ENFORCE_AS_ON;
5118 
5119 	if (p->conf.remote_as == 0 && !p->conf.template) {
5120 		yyerror("peer AS may not be zero");
5121 		return (-1);
5122 	}
5123 
5124 	/* EBGP neighbors are not allowed in route reflector clusters */
5125 	if (p->conf.reflector_client && p->conf.ebgp) {
5126 		yyerror("EBGP neighbors are not allowed in route "
5127 		    "reflector clusters");
5128 		return (-1);
5129 	}
5130 
5131 	/* BGP role and RFC 9234 role are only valid for EBGP neighbors */
5132 	if (!p->conf.ebgp) {
5133 		p->conf.role = ROLE_NONE;
5134 		p->conf.capabilities.policy = 0;
5135 	} else if (p->conf.role == ROLE_NONE) {
5136 		/* no role, no policy capability */
5137 		p->conf.capabilities.policy = 0;
5138 	}
5139 
5140 	/* check for duplicate peer definitions */
5141 	RB_FOREACH(xp, peer_head, new_peers)
5142 		if (xp->conf.remote_masklen ==
5143 		    p->conf.remote_masklen &&
5144 		    memcmp(&xp->conf.remote_addr,
5145 		    &p->conf.remote_addr,
5146 		    sizeof(p->conf.remote_addr)) == 0)
5147 			break;
5148 	if (xp != NULL) {
5149 		char *descr = log_fmt_peer(&p->conf);
5150 		yyerror("duplicate %s", descr);
5151 		free(descr);
5152 		return (-1);
5153 	}
5154 
5155 	return (0);
5156 }
5157 
5158 static void
5159 filterset_add(struct filter_set_head *sh, struct filter_set *s)
5160 {
5161 	struct filter_set	*t;
5162 
5163 	TAILQ_FOREACH(t, sh, entry) {
5164 		if (s->type < t->type) {
5165 			TAILQ_INSERT_BEFORE(t, s, entry);
5166 			return;
5167 		}
5168 		if (s->type == t->type) {
5169 			switch (s->type) {
5170 			case ACTION_SET_COMMUNITY:
5171 			case ACTION_DEL_COMMUNITY:
5172 				switch (cmpcommunity(&s->action.community,
5173 				    &t->action.community)) {
5174 				case -1:
5175 					TAILQ_INSERT_BEFORE(t, s, entry);
5176 					return;
5177 				case 0:
5178 					break;
5179 				case 1:
5180 					continue;
5181 				}
5182 				break;
5183 			case ACTION_SET_NEXTHOP:
5184 				/* only last nexthop per AF matters */
5185 				if (s->action.nexthop.aid <
5186 				    t->action.nexthop.aid) {
5187 					TAILQ_INSERT_BEFORE(t, s, entry);
5188 					return;
5189 				} else if (s->action.nexthop.aid ==
5190 				    t->action.nexthop.aid) {
5191 					t->action.nexthop = s->action.nexthop;
5192 					break;
5193 				}
5194 				continue;
5195 			case ACTION_SET_NEXTHOP_BLACKHOLE:
5196 			case ACTION_SET_NEXTHOP_REJECT:
5197 			case ACTION_SET_NEXTHOP_NOMODIFY:
5198 			case ACTION_SET_NEXTHOP_SELF:
5199 				/* set it only once */
5200 				break;
5201 			case ACTION_SET_LOCALPREF:
5202 			case ACTION_SET_MED:
5203 			case ACTION_SET_WEIGHT:
5204 				/* only last set matters */
5205 				t->action.metric = s->action.metric;
5206 				break;
5207 			case ACTION_SET_RELATIVE_LOCALPREF:
5208 			case ACTION_SET_RELATIVE_MED:
5209 			case ACTION_SET_RELATIVE_WEIGHT:
5210 				/* sum all relative numbers */
5211 				t->action.relative += s->action.relative;
5212 				break;
5213 			case ACTION_SET_ORIGIN:
5214 				/* only last set matters */
5215 				t->action.origin = s->action.origin;
5216 				break;
5217 			case ACTION_PFTABLE:
5218 				/* only last set matters */
5219 				strlcpy(t->action.pftable, s->action.pftable,
5220 				    sizeof(t->action.pftable));
5221 				break;
5222 			case ACTION_RTLABEL:
5223 				/* only last set matters */
5224 				strlcpy(t->action.rtlabel, s->action.rtlabel,
5225 				    sizeof(t->action.rtlabel));
5226 				break;
5227 			default:
5228 				break;
5229 			}
5230 			free(s);
5231 			return;
5232 		}
5233 	}
5234 
5235 	TAILQ_INSERT_TAIL(sh, s, entry);
5236 }
5237 
5238 int
5239 merge_filterset(struct filter_set_head *sh, struct filter_set *s)
5240 {
5241 	struct filter_set	*t;
5242 
5243 	TAILQ_FOREACH(t, sh, entry) {
5244 		/*
5245 		 * need to cycle across the full list because even
5246 		 * if types are not equal filterset_cmp() may return 0.
5247 		 */
5248 		if (filterset_cmp(s, t) == 0) {
5249 			if (s->type == ACTION_SET_COMMUNITY)
5250 				yyerror("community is already set");
5251 			else if (s->type == ACTION_DEL_COMMUNITY)
5252 				yyerror("community will already be deleted");
5253 			else
5254 				yyerror("redefining set parameter %s",
5255 				    filterset_name(s->type));
5256 			return (-1);
5257 		}
5258 	}
5259 
5260 	filterset_add(sh, s);
5261 	return (0);
5262 }
5263 
5264 static int
5265 filter_equal(struct filter_rule *fa, struct filter_rule *fb)
5266 {
5267 	if (fa == NULL || fb == NULL)
5268 		return 0;
5269 	if (fa->action != fb->action || fa->quick != fb->quick ||
5270 	    fa->dir != fb->dir)
5271 		return 0;
5272 	if (memcmp(&fa->peer, &fb->peer, sizeof(fa->peer)))
5273 		return 0;
5274 	if (memcmp(&fa->match, &fb->match, sizeof(fa->match)))
5275 		return 0;
5276 
5277 	return 1;
5278 }
5279 
5280 /* do a basic optimization by folding equal rules together */
5281 void
5282 optimize_filters(struct filter_head *fh)
5283 {
5284 	struct filter_rule *r, *nr;
5285 
5286 	TAILQ_FOREACH_SAFE(r, fh, entry, nr) {
5287 		while (filter_equal(r, nr)) {
5288 			struct filter_set	*t;
5289 
5290 			while ((t = TAILQ_FIRST(&nr->set)) != NULL) {
5291 				TAILQ_REMOVE(&nr->set, t, entry);
5292 				filterset_add(&r->set, t);
5293 			}
5294 
5295 			TAILQ_REMOVE(fh, nr, entry);
5296 			free(nr);
5297 			nr = TAILQ_NEXT(r, entry);
5298 		}
5299 	}
5300 }
5301 
5302 struct filter_rule *
5303 get_rule(enum action_types type)
5304 {
5305 	struct filter_rule	*r;
5306 	int			 out;
5307 
5308 	switch (type) {
5309 	case ACTION_SET_PREPEND_SELF:
5310 	case ACTION_SET_NEXTHOP_NOMODIFY:
5311 	case ACTION_SET_NEXTHOP_SELF:
5312 		out = 1;
5313 		break;
5314 	default:
5315 		out = 0;
5316 		break;
5317 	}
5318 	r = (curpeer == curgroup) ? curgroup_filter[out] : curpeer_filter[out];
5319 	if (r == NULL) {
5320 		if ((r = calloc(1, sizeof(struct filter_rule))) == NULL)
5321 			fatal(NULL);
5322 		r->quick = 0;
5323 		r->dir = out ? DIR_OUT : DIR_IN;
5324 		r->action = ACTION_NONE;
5325 		TAILQ_INIT(&r->set);
5326 		if (curpeer == curgroup) {
5327 			/* group */
5328 			r->peer.groupid = curgroup->conf.id;
5329 			curgroup_filter[out] = r;
5330 		} else {
5331 			/* peer */
5332 			r->peer.peerid = curpeer->conf.id;
5333 			curpeer_filter[out] = r;
5334 		}
5335 	}
5336 	return (r);
5337 }
5338 
5339 struct set_table *curset;
5340 static int
5341 new_as_set(char *name)
5342 {
5343 	struct as_set *aset;
5344 
5345 	if (as_sets_lookup(&conf->as_sets, name) != NULL) {
5346 		yyerror("as-set \"%s\" already exists", name);
5347 		return -1;
5348 	}
5349 
5350 	aset = as_sets_new(&conf->as_sets, name, 0, sizeof(uint32_t));
5351 	if (aset == NULL)
5352 		fatal(NULL);
5353 
5354 	curset = aset->set;
5355 	return 0;
5356 }
5357 
5358 static void
5359 add_as_set(uint32_t as)
5360 {
5361 	if (curset == NULL)
5362 		fatalx("%s: bad mojo jojo", __func__);
5363 
5364 	if (set_add(curset, &as, 1) != 0)
5365 		fatal(NULL);
5366 }
5367 
5368 static void
5369 done_as_set(void)
5370 {
5371 	curset = NULL;
5372 }
5373 
5374 static struct prefixset *
5375 new_prefix_set(char *name, int is_roa)
5376 {
5377 	const char *type = "prefix-set";
5378 	struct prefixset_head *sets = &conf->prefixsets;
5379 	struct prefixset *pset;
5380 
5381 	if (is_roa) {
5382 		type = "origin-set";
5383 		sets = &conf->originsets;
5384 	}
5385 
5386 	if (find_prefixset(name, sets) != NULL) {
5387 		yyerror("%s \"%s\" already exists", type, name);
5388 		return NULL;
5389 	}
5390 	if ((pset = calloc(1, sizeof(*pset))) == NULL)
5391 		fatal("prefixset");
5392 	if (strlcpy(pset->name, name, sizeof(pset->name)) >=
5393 	    sizeof(pset->name)) {
5394 		yyerror("%s \"%s\" too long: max %zu", type,
5395 		    name, sizeof(pset->name) - 1);
5396 		free(pset);
5397 		return NULL;
5398 	}
5399 	RB_INIT(&pset->psitems);
5400 	RB_INIT(&pset->roaitems);
5401 	return pset;
5402 }
5403 
5404 static void
5405 add_roa_set(struct prefixset_item *npsi, uint32_t as, uint8_t max,
5406     time_t expires)
5407 {
5408 	struct roa *roa, *r;
5409 
5410 	if ((roa = calloc(1, sizeof(*roa))) == NULL)
5411 		fatal("add_roa_set");
5412 
5413 	roa->aid = npsi->p.addr.aid;
5414 	roa->prefixlen = npsi->p.len;
5415 	roa->maxlen = max;
5416 	roa->asnum = as;
5417 	roa->expires = expires;
5418 	switch (roa->aid) {
5419 	case AID_INET:
5420 		roa->prefix.inet = npsi->p.addr.v4;
5421 		break;
5422 	case AID_INET6:
5423 		roa->prefix.inet6 = npsi->p.addr.v6;
5424 		break;
5425 	default:
5426 		fatalx("Bad address family for roa_set address");
5427 	}
5428 
5429 	r = RB_INSERT(roa_tree, curroatree, roa);
5430 	if (r != NULL) {
5431 		/* just ignore duplicates */
5432 		if (r->expires != 0 && expires != 0 && expires > r->expires)
5433 			r->expires = expires;
5434 		free(roa);
5435 	}
5436 }
5437 
5438 static struct rtr_config *
5439 get_rtr(struct bgpd_addr *addr)
5440 {
5441 	struct rtr_config *n;
5442 
5443 	n = calloc(1, sizeof(*n));
5444 	if (n == NULL) {
5445 		yyerror("out of memory");
5446 		return NULL;
5447 	}
5448 
5449 	n->remote_addr = *addr;
5450 	strlcpy(n->descr, log_addr(addr), sizeof(currtr->descr));
5451 
5452 	return n;
5453 }
5454 
5455 static int
5456 insert_rtr(struct rtr_config *new)
5457 {
5458 	static uint32_t id;
5459 	struct rtr_config *r;
5460 
5461 	if (id == UINT32_MAX) {
5462 		yyerror("out of rtr session IDs");
5463 		return -1;
5464 	}
5465 
5466 	SIMPLEQ_FOREACH(r, &conf->rtrs, entry)
5467 		if (memcmp(&r->remote_addr, &new->remote_addr,
5468 		    sizeof(r->remote_addr)) == 0 &&
5469 		    r->remote_port == new->remote_port) {
5470 			yyerror("duplicate rtr session to %s:%u",
5471 			    log_addr(&new->remote_addr), new->remote_port);
5472 			return -1;
5473 		}
5474 
5475 	if (cur_rtrs)
5476 		SIMPLEQ_FOREACH(r, cur_rtrs, entry)
5477 			if (memcmp(&r->remote_addr, &new->remote_addr,
5478 			    sizeof(r->remote_addr)) == 0 &&
5479 			    r->remote_port == new->remote_port) {
5480 				new->id = r->id;
5481 				break;
5482 			}
5483 
5484 	if (new->id == 0)
5485 		new->id = ++id;
5486 
5487 	SIMPLEQ_INSERT_TAIL(&conf->rtrs, currtr, entry);
5488 
5489 	return 0;
5490 }
5491 
5492 static int
5493 merge_aspa_set(uint32_t as, struct aspa_tas_l *tas, time_t expires)
5494 {
5495 	struct aspa_set	*aspa, needle = { .as = as };
5496 	uint32_t i, num, *newtas;
5497 
5498 	aspa = RB_FIND(aspa_tree, &conf->aspa, &needle);
5499 	if (aspa == NULL) {
5500 		if ((aspa = calloc(1, sizeof(*aspa))) == NULL) {
5501 			yyerror("out of memory");
5502 			return -1;
5503 		}
5504 		aspa->as = as;
5505 		aspa->expires = expires;
5506 		RB_INSERT(aspa_tree, &conf->aspa, aspa);
5507 	}
5508 
5509 	if (MAX_ASPA_SPAS_COUNT - aspa->num <= tas->num) {
5510 		yyerror("too many providers for customer-as %u", as);
5511 		return -1;
5512 	}
5513 	num = aspa->num + tas->num;
5514 	newtas = recallocarray(aspa->tas, aspa->num, num, sizeof(uint32_t));
5515 	if (newtas == NULL) {
5516 		yyerror("out of memory");
5517 		return -1;
5518 	}
5519 	/* fill starting at the end since the tas list is reversed */
5520 	if (num > 0) {
5521 		for (i = num - 1; tas; tas = tas->next, i--)
5522 			newtas[i] = tas->as;
5523 	}
5524 
5525 	aspa->num = num;
5526 	aspa->tas = newtas;
5527 
5528 	/* take the longest expiry time, same logic as for ROA entries */
5529 	if (aspa->expires != 0 && expires != 0 && expires > aspa->expires)
5530 		aspa->expires = expires;
5531 
5532 	return 0;
5533 }
5534 
5535 static int
5536 kw_casecmp(const void *k, const void *e)
5537 {
5538 	return (strcasecmp(k, ((const struct keywords *)e)->k_name));
5539 }
5540 
5541 static int
5542 map_tos(char *s, int *val)
5543 {
5544 	/* DiffServ Codepoints and other TOS mappings */
5545 	const struct keywords	 toswords[] = {
5546 		{ "af11",		IPTOS_DSCP_AF11 },
5547 		{ "af12",		IPTOS_DSCP_AF12 },
5548 		{ "af13",		IPTOS_DSCP_AF13 },
5549 		{ "af21",		IPTOS_DSCP_AF21 },
5550 		{ "af22",		IPTOS_DSCP_AF22 },
5551 		{ "af23",		IPTOS_DSCP_AF23 },
5552 		{ "af31",		IPTOS_DSCP_AF31 },
5553 		{ "af32",		IPTOS_DSCP_AF32 },
5554 		{ "af33",		IPTOS_DSCP_AF33 },
5555 		{ "af41",		IPTOS_DSCP_AF41 },
5556 		{ "af42",		IPTOS_DSCP_AF42 },
5557 		{ "af43",		IPTOS_DSCP_AF43 },
5558 		{ "critical",		IPTOS_PREC_CRITIC_ECP },
5559 		{ "cs0",		IPTOS_DSCP_CS0 },
5560 		{ "cs1",		IPTOS_DSCP_CS1 },
5561 		{ "cs2",		IPTOS_DSCP_CS2 },
5562 		{ "cs3",		IPTOS_DSCP_CS3 },
5563 		{ "cs4",		IPTOS_DSCP_CS4 },
5564 		{ "cs5",		IPTOS_DSCP_CS5 },
5565 		{ "cs6",		IPTOS_DSCP_CS6 },
5566 		{ "cs7",		IPTOS_DSCP_CS7 },
5567 		{ "ef",			IPTOS_DSCP_EF },
5568 		{ "inetcontrol",	IPTOS_PREC_INTERNETCONTROL },
5569 		{ "lowdelay",		IPTOS_LOWDELAY },
5570 		{ "netcontrol",		IPTOS_PREC_NETCONTROL },
5571 		{ "reliability",	IPTOS_RELIABILITY },
5572 		{ "throughput",		IPTOS_THROUGHPUT },
5573 	};
5574 	const struct keywords	*p;
5575 
5576 	p = bsearch(s, toswords, nitems(toswords), sizeof(toswords[0]),
5577 	    kw_casecmp);
5578 
5579 	if (p) {
5580 		*val = p->k_val;
5581 		return (1);
5582 	}
5583 	return (0);
5584 }
5585 
5586 static int
5587 getservice(char *n)
5588 {
5589 	struct servent	*s;
5590 
5591 	s = getservbyname(n, "tcp");
5592 	if (s == NULL)
5593 		s = getservbyname(n, "udp");
5594 	if (s == NULL)
5595 		return -1;
5596 	return s->s_port;
5597 }
5598 
5599 static int
5600 parse_flags(char *s)
5601 {
5602 	const char *flags = FLOWSPEC_TCP_FLAG_STRING;
5603 	char *p, *q;
5604 	uint8_t f = 0;
5605 
5606 	if (curflow->type == FLOWSPEC_TYPE_FRAG) {
5607 		if (curflow->aid == AID_INET)
5608 			flags = FLOWSPEC_FRAG_STRING4;
5609 		else
5610 			flags = FLOWSPEC_FRAG_STRING6;
5611 	}
5612 
5613 	for (p = s; *p; p++) {
5614 		if ((q = strchr(flags, *p)) == NULL)
5615 			return -1;
5616 		f |= 1 << (q - flags);
5617 	}
5618 	return (f ? f : 0xff);
5619 }
5620 
5621 static void
5622 component_finish(int type, uint8_t *data, int len)
5623 {
5624 	uint8_t *last;
5625 	int i;
5626 
5627 	switch (type) {
5628 	case FLOWSPEC_TYPE_DEST:
5629 	case FLOWSPEC_TYPE_SOURCE:
5630 		/* nothing to do */
5631 		return;
5632 	default:
5633 		break;
5634 	}
5635 
5636 	i = 0;
5637 	do {
5638 		last = data + i;
5639 		i += FLOWSPEC_OP_LEN(*last) + 1;
5640 	} while (i < len);
5641 	*last |= FLOWSPEC_OP_EOL;
5642 }
5643 
5644 static struct flowspec_config *
5645 flow_to_flowspec(struct flowspec_context *ctx)
5646 {
5647 	struct flowspec_config *f;
5648 	int i, len = 0;
5649 	uint8_t aid;
5650 
5651 	switch (ctx->aid) {
5652 	case AID_INET:
5653 		aid = AID_FLOWSPECv4;
5654 		break;
5655 	case AID_INET6:
5656 		aid = AID_FLOWSPECv6;
5657 		break;
5658 	default:
5659 		return NULL;
5660 	}
5661 
5662 	for (i = FLOWSPEC_TYPE_MIN; i < FLOWSPEC_TYPE_MAX; i++)
5663 		if (ctx->components[i] != NULL)
5664 			len += ctx->complen[i] + 1;
5665 
5666 	f = flowspec_alloc(aid, len);
5667 	if (f == NULL)
5668 		return NULL;
5669 
5670 	len = 0;
5671 	for (i = FLOWSPEC_TYPE_MIN; i < FLOWSPEC_TYPE_MAX; i++)
5672 		if (ctx->components[i] != NULL) {
5673 			f->flow->data[len++] = i;
5674 			component_finish(i, ctx->components[i],
5675 			    ctx->complen[i]);
5676 			memcpy(f->flow->data + len, ctx->components[i],
5677 			    ctx->complen[i]);
5678 			len += ctx->complen[i];
5679 		}
5680 
5681 	return f;
5682 }
5683 
5684 static void
5685 flow_free(struct flowspec_context *ctx)
5686 {
5687 	int i;
5688 
5689 	for (i = 0; i < FLOWSPEC_TYPE_MAX; i++)
5690 		free(ctx->components[i]);
5691 	free(ctx);
5692 }
5693 
5694 static int
5695 push_prefix(struct bgpd_addr *addr, uint8_t len)
5696 {
5697 	void *data;
5698 	uint8_t *comp;
5699 	int complen, l;
5700 
5701 	if (curflow->components[curflow->addr_type] != NULL) {
5702 		yyerror("flowspec address already set");
5703 		return -1;
5704 	}
5705 
5706 	if (curflow->aid != addr->aid) {
5707 		yyerror("wrong address family for flowspec address");
5708 		return -1;
5709 	}
5710 
5711 	switch (curflow->aid) {
5712 	case AID_INET:
5713 		complen = PREFIX_SIZE(len);
5714 		data = &addr->v4;
5715 		break;
5716 	case AID_INET6:
5717 		/* IPv6 includes an offset byte */
5718 		complen = PREFIX_SIZE(len) + 1;
5719 		data = &addr->v6;
5720 		break;
5721 	default:
5722 		yyerror("unsupported address family for flowspec address");
5723 		return -1;
5724 	}
5725 	comp = malloc(complen);
5726 	if (comp == NULL) {
5727 		yyerror("out of memory");
5728 		return -1;
5729 	}
5730 
5731 	l = 0;
5732 	comp[l++] = len;
5733 	if (curflow->aid == AID_INET6)
5734 		comp[l++] = 0;
5735 	memcpy(comp + l, data, complen - l);
5736 
5737 	curflow->complen[curflow->addr_type] = complen;
5738 	curflow->components[curflow->addr_type] = comp;
5739 
5740 	return 0;
5741 }
5742 
5743 static int
5744 push_binop(uint8_t binop, long long val)
5745 {
5746 	uint8_t *comp;
5747 	int complen;
5748 	uint8_t u8;
5749 
5750 	if (val < 0 || val > 0xff) {
5751 		yyerror("unsupported value for flowspec bin_op");
5752 		return -1;
5753 	}
5754 	u8 = val;
5755 
5756 	complen = curflow->complen[curflow->type];
5757 	comp = realloc(curflow->components[curflow->type],
5758 	    complen + 2);
5759 	if (comp == NULL) {
5760 		yyerror("out of memory");
5761 		return -1;
5762 	}
5763 
5764 	comp[complen++] = binop;
5765 	comp[complen++] = u8;
5766 	curflow->complen[curflow->type] = complen;
5767 	curflow->components[curflow->type] = comp;
5768 
5769 	return 0;
5770 }
5771 
5772 static uint8_t
5773 component_numop(enum comp_ops op, int and, int len)
5774 {
5775 	uint8_t flag = 0;
5776 
5777 	switch (op) {
5778 	case OP_EQ:
5779 		flag |= FLOWSPEC_OP_NUM_EQ;
5780 		break;
5781 	case OP_NE:
5782 		flag |= FLOWSPEC_OP_NUM_NOT;
5783 		break;
5784 	case OP_LE:
5785 		flag |= FLOWSPEC_OP_NUM_LE;
5786 		break;
5787 	case OP_LT:
5788 		flag |= FLOWSPEC_OP_NUM_LT;
5789 		break;
5790 	case OP_GE:
5791 		flag |= FLOWSPEC_OP_NUM_GE;
5792 		break;
5793 	case OP_GT:
5794 		flag |= FLOWSPEC_OP_NUM_GT;
5795 		break;
5796 	default:
5797 		fatalx("unsupported op");
5798 	}
5799 
5800 	switch (len) {
5801 	case 2:
5802 		flag |= 1 << FLOWSPEC_OP_LEN_SHIFT;
5803 		break;
5804 	case 4:
5805 		flag |= 2 << FLOWSPEC_OP_LEN_SHIFT;
5806 		break;
5807 	case 8:
5808 		flag |= 3 << FLOWSPEC_OP_LEN_SHIFT;
5809 		break;
5810 	}
5811 
5812 	if (and)
5813 		flag |= FLOWSPEC_OP_AND;
5814 
5815 	return flag;
5816 }
5817 
5818 static int
5819 push_numop(enum comp_ops op, int and, long long val)
5820 {
5821 	uint8_t *comp;
5822 	void *data;
5823 	uint32_t u32;
5824 	uint16_t u16;
5825 	uint8_t u8;
5826 	int len, complen;
5827 
5828 	if (val < 0 || val > 0xffffffff) {
5829 		yyerror("unsupported value for flowspec num_op");
5830 		return -1;
5831 	} else if (val <= 255) {
5832 		len = 1;
5833 		u8 = val;
5834 		data = &u8;
5835 	} else if (val <= 0xffff) {
5836 		len = 2;
5837 		u16 = htons(val);
5838 		data = &u16;
5839 	} else {
5840 		len = 4;
5841 		u32 = htonl(val);
5842 		data = &u32;
5843 	}
5844 
5845 	complen = curflow->complen[curflow->type];
5846 	comp = realloc(curflow->components[curflow->type],
5847 	    complen + len + 1);
5848 	if (comp == NULL) {
5849 		yyerror("out of memory");
5850 		return -1;
5851 	}
5852 
5853 	comp[complen++] = component_numop(op, and, len);
5854 	memcpy(comp + complen, data, len);
5855 	complen += len;
5856 	curflow->complen[curflow->type] = complen;
5857 	curflow->components[curflow->type] = comp;
5858 
5859 	return 0;
5860 }
5861 
5862 static int
5863 push_unary_numop(enum comp_ops op, long long val)
5864 {
5865 	return push_numop(op, 0, val);
5866 }
5867 
5868 static int
5869 push_binary_numop(enum comp_ops op, long long min, long long max)
5870 {
5871 	switch (op) {
5872 	case OP_RANGE:
5873 		if (push_numop(OP_GE, 0, min) == -1)
5874 			return -1;
5875 		return push_numop(OP_LE, 1, max);
5876 	case OP_XRANGE:
5877 		if (push_numop(OP_LT, 0, min) == -1)
5878 			return -1;
5879 		return push_numop(OP_GT, 0, max);
5880 	default:
5881 		yyerror("unsupported binary flowspec num_op");
5882 		return -1;
5883 	}
5884 }
5885 
5886 struct icmptypeent {
5887 	const char *name;
5888 	u_int8_t type;
5889 };
5890 
5891 struct icmpcodeent {
5892 	const char *name;
5893 	u_int8_t type;
5894 	u_int8_t code;
5895 };
5896 
5897 static const struct icmptypeent icmp_type[] = {
5898 	{ "echoreq",	ICMP_ECHO },
5899 	{ "echorep",	ICMP_ECHOREPLY },
5900 	{ "unreach",	ICMP_UNREACH },
5901 	{ "squench",	ICMP_SOURCEQUENCH },
5902 	{ "redir",	ICMP_REDIRECT },
5903 	{ "althost",	ICMP_ALTHOSTADDR },
5904 	{ "routeradv",	ICMP_ROUTERADVERT },
5905 	{ "routersol",	ICMP_ROUTERSOLICIT },
5906 	{ "timex",	ICMP_TIMXCEED },
5907 	{ "paramprob",	ICMP_PARAMPROB },
5908 	{ "timereq",	ICMP_TSTAMP },
5909 	{ "timerep",	ICMP_TSTAMPREPLY },
5910 	{ "inforeq",	ICMP_IREQ },
5911 	{ "inforep",	ICMP_IREQREPLY },
5912 	{ "maskreq",	ICMP_MASKREQ },
5913 	{ "maskrep",	ICMP_MASKREPLY },
5914 	{ "trace",	ICMP_TRACEROUTE },
5915 	{ "dataconv",	ICMP_DATACONVERR },
5916 	{ "mobredir",	ICMP_MOBILE_REDIRECT },
5917 	{ "ipv6-where",	ICMP_IPV6_WHEREAREYOU },
5918 	{ "ipv6-here",	ICMP_IPV6_IAMHERE },
5919 	{ "mobregreq",	ICMP_MOBILE_REGREQUEST },
5920 	{ "mobregrep",	ICMP_MOBILE_REGREPLY },
5921 	{ "skip",	ICMP_SKIP },
5922 	{ "photuris",	ICMP_PHOTURIS },
5923 };
5924 
5925 static const struct icmptypeent icmp6_type[] = {
5926 	{ "unreach",	ICMP6_DST_UNREACH },
5927 	{ "toobig",	ICMP6_PACKET_TOO_BIG },
5928 	{ "timex",	ICMP6_TIME_EXCEEDED },
5929 	{ "paramprob",	ICMP6_PARAM_PROB },
5930 	{ "echoreq",	ICMP6_ECHO_REQUEST },
5931 	{ "echorep",	ICMP6_ECHO_REPLY },
5932 	{ "groupqry",	ICMP6_MEMBERSHIP_QUERY },
5933 	{ "listqry",	MLD_LISTENER_QUERY },
5934 	{ "grouprep",	ICMP6_MEMBERSHIP_REPORT },
5935 	{ "listenrep",	MLD_LISTENER_REPORT },
5936 	{ "groupterm",	ICMP6_MEMBERSHIP_REDUCTION },
5937 	{ "listendone", MLD_LISTENER_DONE },
5938 	{ "routersol",	ND_ROUTER_SOLICIT },
5939 	{ "routeradv",	ND_ROUTER_ADVERT },
5940 	{ "neighbrsol", ND_NEIGHBOR_SOLICIT },
5941 	{ "neighbradv", ND_NEIGHBOR_ADVERT },
5942 	{ "redir",	ND_REDIRECT },
5943 	{ "routrrenum", ICMP6_ROUTER_RENUMBERING },
5944 	{ "wrureq",	ICMP6_WRUREQUEST },
5945 	{ "wrurep",	ICMP6_WRUREPLY },
5946 	{ "fqdnreq",	ICMP6_FQDN_QUERY },
5947 	{ "fqdnrep",	ICMP6_FQDN_REPLY },
5948 	{ "niqry",	ICMP6_NI_QUERY },
5949 	{ "nirep",	ICMP6_NI_REPLY },
5950 	{ "mtraceresp",	MLD_MTRACE_RESP },
5951 	{ "mtrace",	MLD_MTRACE },
5952 	{ "listenrepv2", MLDV2_LISTENER_REPORT },
5953 };
5954 
5955 static const struct icmpcodeent icmp_code[] = {
5956 	{ "net-unr",		ICMP_UNREACH,	ICMP_UNREACH_NET },
5957 	{ "host-unr",		ICMP_UNREACH,	ICMP_UNREACH_HOST },
5958 	{ "proto-unr",		ICMP_UNREACH,	ICMP_UNREACH_PROTOCOL },
5959 	{ "port-unr",		ICMP_UNREACH,	ICMP_UNREACH_PORT },
5960 	{ "needfrag",		ICMP_UNREACH,	ICMP_UNREACH_NEEDFRAG },
5961 	{ "srcfail",		ICMP_UNREACH,	ICMP_UNREACH_SRCFAIL },
5962 	{ "net-unk",		ICMP_UNREACH,	ICMP_UNREACH_NET_UNKNOWN },
5963 	{ "host-unk",		ICMP_UNREACH,	ICMP_UNREACH_HOST_UNKNOWN },
5964 	{ "isolate",		ICMP_UNREACH,	ICMP_UNREACH_ISOLATED },
5965 	{ "net-prohib",		ICMP_UNREACH,	ICMP_UNREACH_NET_PROHIB },
5966 	{ "host-prohib",	ICMP_UNREACH,	ICMP_UNREACH_HOST_PROHIB },
5967 	{ "net-tos",		ICMP_UNREACH,	ICMP_UNREACH_TOSNET },
5968 	{ "host-tos",		ICMP_UNREACH,	ICMP_UNREACH_TOSHOST },
5969 	{ "filter-prohib",	ICMP_UNREACH,	ICMP_UNREACH_FILTER_PROHIB },
5970 	{ "host-preced",	ICMP_UNREACH,	ICMP_UNREACH_HOST_PRECEDENCE },
5971 	{ "cutoff-preced",	ICMP_UNREACH,	ICMP_UNREACH_PRECEDENCE_CUTOFF },
5972 	{ "redir-net",		ICMP_REDIRECT,	ICMP_REDIRECT_NET },
5973 	{ "redir-host",		ICMP_REDIRECT,	ICMP_REDIRECT_HOST },
5974 	{ "redir-tos-net",	ICMP_REDIRECT,	ICMP_REDIRECT_TOSNET },
5975 	{ "redir-tos-host",	ICMP_REDIRECT,	ICMP_REDIRECT_TOSHOST },
5976 	{ "normal-adv",		ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NORMAL },
5977 	{ "common-adv",		ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NOROUTE_COMMON },
5978 	{ "transit",		ICMP_TIMXCEED,	ICMP_TIMXCEED_INTRANS },
5979 	{ "reassemb",		ICMP_TIMXCEED,	ICMP_TIMXCEED_REASS },
5980 	{ "badhead",		ICMP_PARAMPROB,	ICMP_PARAMPROB_ERRATPTR },
5981 	{ "optmiss",		ICMP_PARAMPROB,	ICMP_PARAMPROB_OPTABSENT },
5982 	{ "badlen",		ICMP_PARAMPROB,	ICMP_PARAMPROB_LENGTH },
5983 	{ "unknown-ind",	ICMP_PHOTURIS,	ICMP_PHOTURIS_UNKNOWN_INDEX },
5984 	{ "auth-fail",		ICMP_PHOTURIS,	ICMP_PHOTURIS_AUTH_FAILED },
5985 	{ "decrypt-fail",	ICMP_PHOTURIS,	ICMP_PHOTURIS_DECRYPT_FAILED },
5986 };
5987 
5988 static const struct icmpcodeent icmp6_code[] = {
5989 	{ "admin-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN },
5990 	{ "noroute-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE },
5991 	{ "beyond-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE },
5992 	{ "addr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR },
5993 	{ "port-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT },
5994 	{ "transit", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT },
5995 	{ "reassemb", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_REASSEMBLY },
5996 	{ "badhead", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER },
5997 	{ "nxthdr", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXTHEADER },
5998 	{ "redironlink", ND_REDIRECT, ND_REDIRECT_ONLINK },
5999 	{ "redirrouter", ND_REDIRECT, ND_REDIRECT_ROUTER },
6000 };
6001 
6002 static int
6003 geticmptypebyname(char *w, uint8_t aid)
6004 {
6005 	size_t	i;
6006 
6007 	switch (aid) {
6008 	case AID_INET:
6009 		for (i = 0; i < nitems(icmp_type); i++) {
6010 			if (!strcmp(w, icmp_type[i].name))
6011 				return (icmp_type[i].type);
6012 		}
6013 		break;
6014 	case AID_INET6:
6015 		for (i = 0; i < nitems(icmp6_type); i++) {
6016 			if (!strcmp(w, icmp6_type[i].name))
6017 				return (icmp6_type[i].type);
6018 		}
6019 		break;
6020 	}
6021 	return -1;
6022 }
6023 
6024 static int
6025 geticmpcodebyname(u_long type, char *w, uint8_t aid)
6026 {
6027 	size_t	i;
6028 
6029 	switch (aid) {
6030 	case AID_INET:
6031 		for (i = 0; i < nitems(icmp_code); i++) {
6032 			if (type == icmp_code[i].type &&
6033 			    !strcmp(w, icmp_code[i].name))
6034 				return (icmp_code[i].code);
6035 		}
6036 		break;
6037 	case AID_INET6:
6038 		for (i = 0; i < nitems(icmp6_code); i++) {
6039 			if (type == icmp6_code[i].type &&
6040 			    !strcmp(w, icmp6_code[i].name))
6041 				return (icmp6_code[i].code);
6042 		}
6043 		break;
6044 	}
6045 	return -1;
6046 }
6047 
6048 static int
6049 merge_auth_conf(struct auth_config *to, struct auth_config *from)
6050 {
6051 	if (to->method != 0) {
6052 		/* extra magic for manual ipsec rules */
6053 		if (to->method == from->method &&
6054 		    (to->method == AUTH_IPSEC_MANUAL_ESP ||
6055 		    to->method == AUTH_IPSEC_MANUAL_AH)) {
6056 			if (to->spi_in == 0 && from->spi_in != 0) {
6057 				to->spi_in = from->spi_in;
6058 				to->auth_alg_in = from->auth_alg_in;
6059 				to->enc_alg_in = from->enc_alg_in;
6060 				memcpy(to->enc_key_in, from->enc_key_in,
6061 				    sizeof(to->enc_key_in));
6062 				to->enc_keylen_in = from->enc_keylen_in;
6063 				to->auth_keylen_in = from->auth_keylen_in;
6064 				return 1;
6065 			} else if (to->spi_out == 0 && from->spi_out != 0) {
6066 				to->spi_out = from->spi_out;
6067 				to->auth_alg_out = from->auth_alg_out;
6068 				to->enc_alg_out = from->enc_alg_out;
6069 				memcpy(to->enc_key_out, from->enc_key_out,
6070 				    sizeof(to->enc_key_out));
6071 				to->enc_keylen_out = from->enc_keylen_out;
6072 				to->auth_keylen_out = from->auth_keylen_out;
6073 				return 1;
6074 			}
6075 		}
6076 		yyerror("auth method cannot be redefined");
6077 		return 0;
6078 	}
6079 	*to = *from;
6080 	return 1;
6081 }
6082 
6083