1 /*	$OpenBSD: parse.y,v 1.479 2025/02/04 18:16:56 denis 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 EVPN
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);
TAILQ_FOREACH(m,netconf,entry)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 			if (get_id(curpeer)) {
1722 				yyerror("get_id failed");
1723 				YYERROR;
1724 			}
1725 		}
1726 		    peeropts_h {
1727 			uint8_t		aid;
1728 
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 			/*
1739 			 * Check if any MP capa is set, if none is set and
1740 			 * and the default AID was not disabled via none then
1741 			 * enable it. Finally fixup the disabled AID.
1742 			 */
1743 			for (aid = AID_MIN; aid < AID_MAX; aid++) {
1744 				if (curpeer->conf.capabilities.mp[aid] > 0)
1745 					break;
1746 			}
1747 			if (aid == AID_MAX &&
1748 			    curpeer->conf.capabilities.mp[
1749 			    curpeer->conf.remote_addr.aid] != -1)
1750 				curpeer->conf.capabilities.mp[
1751 				    curpeer->conf.remote_addr.aid] = 1;
1752 			for (aid = AID_MIN; aid < AID_MAX; aid++) {
1753 				if (curpeer->conf.capabilities.mp[aid] == -1)
1754 					curpeer->conf.capabilities.mp[aid] = 0;
1755 			}
1756 
1757 			if (neighbor_consistent(curpeer) == -1) {
1758 				free(curpeer);
1759 				YYERROR;
1760 			}
1761 			if (RB_INSERT(peer_head, new_peers, curpeer) != NULL)
1762 				fatalx("%s: peer tree is corrupt", __func__);
1763 			curpeer = curgroup;
1764 		}
1765 		;
1766 
1767 group		: GROUP string			{
1768 			curgroup = curpeer = new_group();
1769 			if (strlcpy(curgroup->conf.group, $2,
1770 			    sizeof(curgroup->conf.group)) >=
1771 			    sizeof(curgroup->conf.group)) {
1772 				yyerror("group name \"%s\" too long: max %zu",
1773 				    $2, sizeof(curgroup->conf.group) - 1);
1774 				free($2);
1775 				free(curgroup);
1776 				YYERROR;
1777 			}
1778 			free($2);
1779 			if (get_id(curgroup)) {
1780 				yyerror("get_id failed");
1781 				free(curgroup);
1782 				YYERROR;
1783 			}
1784 		} '{' groupopts_l '}'		{
1785 			if (curgroup_filter[0] != NULL)
1786 				TAILQ_INSERT_TAIL(groupfilter_l,
1787 				    curgroup_filter[0], entry);
1788 			if (curgroup_filter[1] != NULL)
1789 				TAILQ_INSERT_TAIL(groupfilter_l,
1790 				    curgroup_filter[1], entry);
1791 			curgroup_filter[0] = NULL;
1792 			curgroup_filter[1] = NULL;
1793 
1794 			free(curgroup);
1795 			curgroup = NULL;
1796 		}
1797 		;
1798 
1799 groupopts_l	: /* empty */
1800 		| groupopts_l '\n'
1801 		| groupopts_l peeropts '\n'
1802 		| groupopts_l neighbor '\n'
1803 		| groupopts_l error '\n'
1804 		;
1805 
1806 addpathextra	: /* empty */		{ $$ = 0; }
1807 		| PLUS NUMBER		{
1808 			if ($2 < 1 || $2 > USHRT_MAX) {
1809 				yyerror("additional paths must be between "
1810 				    "%u and %u", 1, USHRT_MAX);
1811 				YYERROR;
1812 			}
1813 			$$ = $2;
1814 		}
1815 		;
1816 
1817 addpathmax	: /* empty */		{ $$ = 0; }
1818 		| MAX NUMBER		{
1819 			if ($2 < 1 || $2 > USHRT_MAX) {
1820 				yyerror("maximum additional paths must be "
1821 				    "between %u and %u", 1, USHRT_MAX);
1822 				YYERROR;
1823 			}
1824 			$$ = $2;
1825 		}
1826 		;
1827 
1828 peeropts_h	: '{' '\n' peeropts_l '}'
1829 		| '{' peeropts '}'
1830 		| /* empty */
1831 		;
1832 
1833 peeropts_l	: /* empty */
1834 		| peeropts_l '\n'
1835 		| peeropts_l peeropts '\n'
1836 		| peeropts_l error '\n'
1837 		;
1838 
1839 peeropts	: REMOTEAS as4number	{
1840 			curpeer->conf.remote_as = $2;
1841 		}
1842 		| LOCALAS as4number	{
1843 			curpeer->conf.local_as = $2;
1844 			if ($2 > USHRT_MAX)
1845 				curpeer->conf.local_short_as = AS_TRANS;
1846 			else
1847 				curpeer->conf.local_short_as = $2;
1848 		}
1849 		| LOCALAS as4number asnumber {
1850 			curpeer->conf.local_as = $2;
1851 			curpeer->conf.local_short_as = $3;
1852 		}
1853 		| DESCR string		{
1854 			if (strlcpy(curpeer->conf.descr, $2,
1855 			    sizeof(curpeer->conf.descr)) >=
1856 			    sizeof(curpeer->conf.descr)) {
1857 				yyerror("descr \"%s\" too long: max %zu",
1858 				    $2, sizeof(curpeer->conf.descr) - 1);
1859 				free($2);
1860 				YYERROR;
1861 			}
1862 			free($2);
1863 		}
1864 		| LOCALADDR address	{
1865 			if ($2.aid == AID_INET)
1866 				memcpy(&curpeer->conf.local_addr_v4, &$2,
1867 				    sizeof(curpeer->conf.local_addr_v4));
1868 			else if ($2.aid == AID_INET6)
1869 				memcpy(&curpeer->conf.local_addr_v6, &$2,
1870 				    sizeof(curpeer->conf.local_addr_v6));
1871 			else {
1872 				yyerror("Unsupported address family %s for "
1873 				    "local-addr", aid2str($2.aid));
1874 				YYERROR;
1875 			}
1876 		}
1877 		| yesno LOCALADDR	{
1878 			if ($1) {
1879 				yyerror("bad local-address definition");
1880 				YYERROR;
1881 			}
1882 			memset(&curpeer->conf.local_addr_v4, 0,
1883 			    sizeof(curpeer->conf.local_addr_v4));
1884 			memset(&curpeer->conf.local_addr_v6, 0,
1885 			    sizeof(curpeer->conf.local_addr_v6));
1886 		}
1887 		| MULTIHOP NUMBER	{
1888 			if ($2 < 2 || $2 > 255) {
1889 				yyerror("invalid multihop distance %lld", $2);
1890 				YYERROR;
1891 			}
1892 			curpeer->conf.distance = $2;
1893 		}
1894 		| PASSIVE		{
1895 			curpeer->conf.passive = 1;
1896 		}
1897 		| DOWN			{
1898 			curpeer->conf.down = 1;
1899 		}
1900 		| DOWN STRING		{
1901 			curpeer->conf.down = 1;
1902 			if (strlcpy(curpeer->conf.reason, $2,
1903 				sizeof(curpeer->conf.reason)) >=
1904 				sizeof(curpeer->conf.reason)) {
1905 				    yyerror("shutdown reason too long");
1906 				    free($2);
1907 				    YYERROR;
1908 			}
1909 			free($2);
1910 		}
1911 		| RIB STRING	{
1912 			if (!find_rib($2)) {
1913 				yyerror("rib \"%s\" does not exist.", $2);
1914 				free($2);
1915 				YYERROR;
1916 			}
1917 			if (strlcpy(curpeer->conf.rib, $2,
1918 			    sizeof(curpeer->conf.rib)) >=
1919 			    sizeof(curpeer->conf.rib)) {
1920 				yyerror("rib name \"%s\" too long: max %zu",
1921 				    $2, sizeof(curpeer->conf.rib) - 1);
1922 				free($2);
1923 				YYERROR;
1924 			}
1925 			free($2);
1926 		}
1927 		| HOLDTIME NUMBER	{
1928 			if ($2 < MIN_HOLDTIME || $2 > USHRT_MAX) {
1929 				yyerror("holdtime must be between %u and %u",
1930 				    MIN_HOLDTIME, USHRT_MAX);
1931 				YYERROR;
1932 			}
1933 			curpeer->conf.holdtime = $2;
1934 		}
1935 		| HOLDTIME YMIN NUMBER	{
1936 			if ($3 < MIN_HOLDTIME || $3 > USHRT_MAX) {
1937 				yyerror("holdtime must be between %u and %u",
1938 				    MIN_HOLDTIME, USHRT_MAX);
1939 				YYERROR;
1940 			}
1941 			curpeer->conf.min_holdtime = $3;
1942 		}
1943 		| STALETIME NUMBER	{
1944 			if ($2 < MIN_HOLDTIME || $2 > USHRT_MAX) {
1945 				yyerror("staletime must be between %u and %u",
1946 				    MIN_HOLDTIME, USHRT_MAX);
1947 				YYERROR;
1948 			}
1949 			curpeer->conf.staletime = $2;
1950 		}
1951 		| ANNOUNCE af safi enforce {
1952 			uint8_t		aid, safi;
1953 			uint16_t	afi;
1954 
1955 			if ($3 == SAFI_NONE) {
1956 				for (aid = AID_MIN; aid < AID_MAX; aid++) {
1957 					if (aid2afi(aid, &afi, &safi) == -1 ||
1958 					    afi != $2)
1959 						continue;
1960 					curpeer->conf.capabilities.mp[aid] = -1;
1961 				}
1962 			} else {
1963 				if (afi2aid($2, $3, &aid) == -1) {
1964 					yyerror("unknown AFI/SAFI pair");
1965 					YYERROR;
1966 				}
1967 				if ($4)
1968 					curpeer->conf.capabilities.mp[aid] = 2;
1969 				else
1970 					curpeer->conf.capabilities.mp[aid] = 1;
1971 			}
1972 		}
1973 		| ANNOUNCE EVPN enforce {
1974 			if ($3)
1975 				curpeer->conf.capabilities.mp[AID_EVPN] = 2;
1976 			else
1977 				curpeer->conf.capabilities.mp[AID_EVPN] = 1;
1978 		}
1979 		| ANNOUNCE REFRESH yesnoenforce {
1980 			curpeer->conf.capabilities.refresh = $3;
1981 		}
1982 		| ANNOUNCE ENHANCED REFRESH yesnoenforce {
1983 			curpeer->conf.capabilities.enhanced_rr = $4;
1984 		}
1985 		| ANNOUNCE RESTART yesnoenforce {
1986 			curpeer->conf.capabilities.grestart.restart = $3;
1987 		}
1988 		| ANNOUNCE GRACEFUL NOTIFICATION yesno {
1989 			curpeer->conf.capabilities.grestart.grnotification = $4;
1990 		}
1991 		| ANNOUNCE AS4BYTE yesnoenforce {
1992 			curpeer->conf.capabilities.as4byte = $3;
1993 		}
1994 		| ANNOUNCE ADDPATH RECV yesnoenforce {
1995 			int8_t *ap = curpeer->conf.capabilities.add_path;
1996 			uint8_t i;
1997 
1998 			for (i = AID_MIN; i < AID_MAX; i++) {
1999 				if ($4) {
2000 					if ($4 == 2)
2001 						ap[i] |= CAPA_AP_RECV_ENFORCE;
2002 					ap[i] |= CAPA_AP_RECV;
2003 				} else
2004 					ap[i] &= ~CAPA_AP_RECV;
2005 			}
2006 		}
2007 		| ANNOUNCE ADDPATH SEND STRING addpathextra addpathmax enforce {
2008 			int8_t *ap = curpeer->conf.capabilities.add_path;
2009 			enum addpath_mode mode;
2010 			u_int8_t i;
2011 
2012 			if (!strcmp($4, "no")) {
2013 				free($4);
2014 				if ($5 != 0 || $6 != 0 || $7 != 0) {
2015 					yyerror("no additional option allowed "
2016 					    "for 'add-path send no'");
2017 					YYERROR;
2018 				}
2019 				mode = ADDPATH_EVAL_NONE;
2020 			} else if (!strcmp($4, "all")) {
2021 				free($4);
2022 				if ($5 != 0 || $6 != 0) {
2023 					yyerror("no additional option allowed "
2024 					    "for 'add-path send all'");
2025 					YYERROR;
2026 				}
2027 				mode = ADDPATH_EVAL_ALL;
2028 			} else if (!strcmp($4, "best")) {
2029 				free($4);
2030 				mode = ADDPATH_EVAL_BEST;
2031 			} else if (!strcmp($4, "ecmp")) {
2032 				free($4);
2033 				mode = ADDPATH_EVAL_ECMP;
2034 			} else if (!strcmp($4, "as-wide-best")) {
2035 				free($4);
2036 				mode = ADDPATH_EVAL_AS_WIDE;
2037 			} else {
2038 				yyerror("announce add-path send: "
2039 				    "unknown mode \"%s\"", $4);
2040 				free($4);
2041 				YYERROR;
2042 			}
2043 			for (i = AID_MIN; i < AID_MAX; i++) {
2044 				if (mode != ADDPATH_EVAL_NONE) {
2045 					if ($7)
2046 						ap[i] |= CAPA_AP_SEND_ENFORCE;
2047 					ap[i] |= CAPA_AP_SEND;
2048 				} else
2049 					ap[i] &= ~CAPA_AP_SEND;
2050 			}
2051 			curpeer->conf.eval.mode = mode;
2052 			curpeer->conf.eval.extrapaths = $5;
2053 			curpeer->conf.eval.maxpaths = $6;
2054 		}
2055 		| ANNOUNCE POLICY yesnoenforce {
2056 			curpeer->conf.capabilities.policy = $3;
2057 		}
2058 		| ANNOUNCE EXTENDED MESSAGE yesnoenforce {
2059 			curpeer->conf.capabilities.ext_msg = $4;
2060 		}
2061 		| ANNOUNCE EXTENDED NEXTHOP yesnoenforce {
2062 			curpeer->conf.capabilities.ext_nh[AID_VPN_IPv4] =
2063 			    curpeer->conf.capabilities.ext_nh[AID_INET] = $4;
2064 		}
2065 		| ROLE STRING {
2066 			if (strcmp($2, "provider") == 0) {
2067 				curpeer->conf.role = ROLE_PROVIDER;
2068 			} else if (strcmp($2, "rs") == 0) {
2069 				curpeer->conf.role = ROLE_RS;
2070 			} else if (strcmp($2, "rs-client") == 0) {
2071 				curpeer->conf.role = ROLE_RS_CLIENT;
2072 			} else if (strcmp($2, "customer") == 0) {
2073 				curpeer->conf.role = ROLE_CUSTOMER;
2074 			} else if (strcmp($2, "peer") == 0) {
2075 				curpeer->conf.role = ROLE_PEER;
2076 			} else {
2077 				yyerror("syntax error, one of none, provider, "
2078 				    "rs, rs-client, customer, peer expected");
2079 				free($2);
2080 				YYERROR;
2081 			}
2082 			free($2);
2083 		}
2084 		| ROLE NONE {
2085 			curpeer->conf.role = ROLE_NONE;
2086 		}
2087 		| EXPORT NONE {
2088 			curpeer->conf.export_type = EXPORT_NONE;
2089 		}
2090 		| EXPORT DEFAULTROUTE {
2091 			curpeer->conf.export_type = EXPORT_DEFAULT_ROUTE;
2092 		}
2093 		| ENFORCE NEIGHBORAS yesno {
2094 			if ($3)
2095 				curpeer->conf.enforce_as = ENFORCE_AS_ON;
2096 			else
2097 				curpeer->conf.enforce_as = ENFORCE_AS_OFF;
2098 		}
2099 		| ENFORCE LOCALAS yesno {
2100 			if ($3)
2101 				curpeer->conf.enforce_local_as = ENFORCE_AS_ON;
2102 			else
2103 				curpeer->conf.enforce_local_as = ENFORCE_AS_OFF;
2104 		}
2105 		| ASOVERRIDE yesno {
2106 			if ($2) {
2107 				struct filter_rule	*r;
2108 				struct filter_set	*s;
2109 
2110 				if ((s = calloc(1, sizeof(struct filter_set)))
2111 				    == NULL)
2112 					fatal(NULL);
2113 				s->type = ACTION_SET_AS_OVERRIDE;
2114 
2115 				r = get_rule(s->type);
2116 				if (merge_filterset(&r->set, s) == -1)
2117 					YYERROR;
2118 			}
2119 		}
2120 		| MAXPREFIX NUMBER restart {
2121 			if ($2 < 0 || $2 > UINT_MAX) {
2122 				yyerror("bad maximum number of prefixes");
2123 				YYERROR;
2124 			}
2125 			curpeer->conf.max_prefix = $2;
2126 			curpeer->conf.max_prefix_restart = $3;
2127 		}
2128 		| MAXPREFIX NUMBER OUT restart {
2129 			if ($2 < 0 || $2 > UINT_MAX) {
2130 				yyerror("bad maximum number of prefixes");
2131 				YYERROR;
2132 			}
2133 			curpeer->conf.max_out_prefix = $2;
2134 			curpeer->conf.max_out_prefix_restart = $4;
2135 		}
2136 		| authconf {
2137 			if (merge_auth_conf(&curpeer->auth_conf, &$1) == 0)
2138 				YYERROR;
2139 		}
2140 		| TTLSECURITY yesno	{
2141 			curpeer->conf.ttlsec = $2;
2142 		}
2143 		| SET filter_set_opt	{
2144 			struct filter_rule	*r;
2145 
2146 			r = get_rule($2->type);
2147 			if (merge_filterset(&r->set, $2) == -1)
2148 				YYERROR;
2149 		}
2150 		| SET '{' optnl filter_set_l optnl '}'	{
2151 			struct filter_rule	*r;
2152 			struct filter_set	*s;
2153 
2154 			while ((s = TAILQ_FIRST($4)) != NULL) {
2155 				TAILQ_REMOVE($4, s, entry);
2156 				r = get_rule(s->type);
2157 				if (merge_filterset(&r->set, s) == -1)
2158 					YYERROR;
2159 			}
2160 			free($4);
2161 		}
2162 		| mrtdump
2163 		| REFLECTOR		{
2164 			if ((conf->flags & BGPD_FLAG_REFLECTOR) &&
2165 			    conf->clusterid != 0) {
2166 				yyerror("only one route reflector "
2167 				    "cluster allowed");
2168 				YYERROR;
2169 			}
2170 			conf->flags |= BGPD_FLAG_REFLECTOR;
2171 			curpeer->conf.reflector_client = 1;
2172 		}
2173 		| REFLECTOR address	{
2174 			if ($2.aid != AID_INET) {
2175 				yyerror("route reflector cluster-id must be "
2176 				    "an IPv4 address");
2177 				YYERROR;
2178 			}
2179 			if ((conf->flags & BGPD_FLAG_REFLECTOR) &&
2180 			    conf->clusterid != ntohl($2.v4.s_addr)) {
2181 				yyerror("only one route reflector "
2182 				    "cluster allowed");
2183 				YYERROR;
2184 			}
2185 			conf->flags |= BGPD_FLAG_REFLECTOR;
2186 			curpeer->conf.reflector_client = 1;
2187 			conf->clusterid = ntohl($2.v4.s_addr);
2188 		}
2189 		| DEPEND ON STRING	{
2190 			if (strlcpy(curpeer->conf.if_depend, $3,
2191 			    sizeof(curpeer->conf.if_depend)) >=
2192 			    sizeof(curpeer->conf.if_depend)) {
2193 				yyerror("interface name \"%s\" too long: "
2194 				    "max %zu", $3,
2195 				    sizeof(curpeer->conf.if_depend) - 1);
2196 				free($3);
2197 				YYERROR;
2198 			}
2199 			free($3);
2200 		}
2201 		| DEMOTE STRING		{
2202 			if (strlcpy(curpeer->conf.demote_group, $2,
2203 			    sizeof(curpeer->conf.demote_group)) >=
2204 			    sizeof(curpeer->conf.demote_group)) {
2205 				yyerror("demote group name \"%s\" too long: "
2206 				    "max %zu", $2,
2207 				    sizeof(curpeer->conf.demote_group) - 1);
2208 				free($2);
2209 				YYERROR;
2210 			}
2211 			free($2);
2212 			if (carp_demote_init(curpeer->conf.demote_group,
2213 			    cmd_opts & BGPD_OPT_FORCE_DEMOTE) == -1) {
2214 				yyerror("error initializing group \"%s\"",
2215 				    curpeer->conf.demote_group);
2216 				YYERROR;
2217 			}
2218 		}
2219 		| TRANSPARENT yesno	{
2220 			if ($2 == 1)
2221 				curpeer->conf.flags |= PEERFLAG_TRANS_AS;
2222 			else
2223 				curpeer->conf.flags &= ~PEERFLAG_TRANS_AS;
2224 		}
2225 		| LOG STRING		{
2226 			if (!strcmp($2, "updates"))
2227 				curpeer->conf.flags |= PEERFLAG_LOG_UPDATES;
2228 			else if (!strcmp($2, "no"))
2229 				curpeer->conf.flags &= ~PEERFLAG_LOG_UPDATES;
2230 			else {
2231 				free($2);
2232 				YYERROR;
2233 			}
2234 			free($2);
2235 		}
2236 		| REJECT ASSET yesno	{
2237 			if ($3 == 1)
2238 				curpeer->conf.flags &= ~PEERFLAG_PERMIT_AS_SET;
2239 			else
2240 				curpeer->conf.flags |= PEERFLAG_PERMIT_AS_SET;
2241 		}
2242 		| PORT port {
2243 			curpeer->conf.remote_port = $2;
2244 		}
2245 		| RDE EVALUATE STRING {
2246 			if (!strcmp($3, "all"))
2247 				curpeer->conf.flags |= PEERFLAG_EVALUATE_ALL;
2248 			else if (!strcmp($3, "default"))
2249 				curpeer->conf.flags &= ~PEERFLAG_EVALUATE_ALL;
2250 			else {
2251 				yyerror("rde evaluate: "
2252 				    "unknown setting \"%s\"", $3);
2253 				free($3);
2254 				YYERROR;
2255 			}
2256 			free($3);
2257 		}
2258 		;
2259 
2260 restart		: /* nada */		{ $$ = 0; }
2261 		| RESTART NUMBER	{
2262 			if ($2 < 1 || $2 > USHRT_MAX) {
2263 				yyerror("restart out of range. 1 to %u minutes",
2264 				    USHRT_MAX);
2265 				YYERROR;
2266 			}
2267 			$$ = $2;
2268 		}
2269 		;
2270 
2271 af		: IPV4	{ $$ = AFI_IPv4; }
2272 		| IPV6	{ $$ = AFI_IPv6; }
2273 		;
2274 
2275 safi		: NONE		{ $$ = SAFI_NONE; }
2276 		| UNICAST	{ $$ = SAFI_UNICAST; }
2277 		| VPN		{ $$ = SAFI_MPLSVPN; }
2278 		| FLOWSPEC	{ $$ = SAFI_FLOWSPEC; }
2279 		;
2280 
2281 nettype		: STATIC	{ $$ = 1; }
2282 		| CONNECTED	{ $$ = 0; }
2283 		;
2284 
2285 authconf	: TCP MD5SIG PASSWORD string {
2286 			memset(&$$, 0, sizeof($$));
2287 			if (strlcpy($$.md5key, $4, sizeof($$.md5key)) >=
2288 			    sizeof($$.md5key)) {
2289 				yyerror("tcp md5sig password too long: max %zu",
2290 				    sizeof($$.md5key) - 1);
2291 				free($4);
2292 				YYERROR;
2293 			}
2294 			$$.method = AUTH_MD5SIG;
2295 			$$.md5key_len = strlen($4);
2296 			free($4);
2297 		}
2298 		| TCP MD5SIG KEY string {
2299 			memset(&$$, 0, sizeof($$));
2300 			if (str2key($4, $$.md5key, sizeof($$.md5key)) == -1) {
2301 				free($4);
2302 				YYERROR;
2303 			}
2304 			$$.method = AUTH_MD5SIG;
2305 			$$.md5key_len = strlen($4) / 2;
2306 			free($4);
2307 		}
2308 		| IPSEC espah IKE {
2309 			memset(&$$, 0, sizeof($$));
2310 			if ($2)
2311 				$$.method = AUTH_IPSEC_IKE_ESP;
2312 			else
2313 				$$.method = AUTH_IPSEC_IKE_AH;
2314 		}
2315 		| IPSEC espah inout SPI NUMBER STRING STRING encspec {
2316 			enum auth_alg	auth_alg;
2317 			uint8_t		keylen;
2318 
2319 			memset(&$$, 0, sizeof($$));
2320 			if (!strcmp($6, "sha1")) {
2321 				auth_alg = AUTH_AALG_SHA1HMAC;
2322 				keylen = 20;
2323 			} else if (!strcmp($6, "md5")) {
2324 				auth_alg = AUTH_AALG_MD5HMAC;
2325 				keylen = 16;
2326 			} else {
2327 				yyerror("unknown auth algorithm \"%s\"", $6);
2328 				free($6);
2329 				free($7);
2330 				YYERROR;
2331 			}
2332 			free($6);
2333 
2334 			if (strlen($7) / 2 != keylen) {
2335 				yyerror("auth key len: must be %u bytes, "
2336 				    "is %zu bytes", keylen, strlen($7) / 2);
2337 				free($7);
2338 				YYERROR;
2339 			}
2340 
2341 			if ($2)
2342 				$$.method = AUTH_IPSEC_MANUAL_ESP;
2343 			else {
2344 				if ($8.enc_alg) {
2345 					yyerror("\"ipsec ah\" doesn't take "
2346 					    "encryption keys");
2347 					free($7);
2348 					YYERROR;
2349 				}
2350 				$$.method = AUTH_IPSEC_MANUAL_AH;
2351 			}
2352 
2353 			if ($5 <= SPI_RESERVED_MAX || $5 > UINT_MAX) {
2354 				yyerror("bad spi number %lld", $5);
2355 				free($7);
2356 				YYERROR;
2357 			}
2358 
2359 			if ($3 == 1) {
2360 				if (str2key($7, $$.auth_key_in,
2361 				    sizeof($$.auth_key_in)) == -1) {
2362 					free($7);
2363 					YYERROR;
2364 				}
2365 				$$.spi_in = $5;
2366 				$$.auth_alg_in = auth_alg;
2367 				$$.enc_alg_in = $8.enc_alg;
2368 				memcpy(&$$.enc_key_in, &$8.enc_key,
2369 				    sizeof($$.enc_key_in));
2370 				$$.enc_keylen_in = $8.enc_key_len;
2371 				$$.auth_keylen_in = keylen;
2372 			} else {
2373 				if (str2key($7, $$.auth_key_out,
2374 				    sizeof($$.auth_key_out)) == -1) {
2375 					free($7);
2376 					YYERROR;
2377 				}
2378 				$$.spi_out = $5;
2379 				$$.auth_alg_out = auth_alg;
2380 				$$.enc_alg_out = $8.enc_alg;
2381 				memcpy(&$$.enc_key_out, &$8.enc_key,
2382 				    sizeof($$.enc_key_out));
2383 				$$.enc_keylen_out = $8.enc_key_len;
2384 				$$.auth_keylen_out = keylen;
2385 			}
2386 			free($7);
2387 		}
2388 		;
2389 
2390 espah		: ESP		{ $$ = 1; }
2391 		| AH		{ $$ = 0; }
2392 		;
2393 
2394 encspec		: /* nada */	{
2395 			memset(&$$, 0, sizeof($$));
2396 		}
2397 		| STRING STRING {
2398 			memset(&$$, 0, sizeof($$));
2399 			if (!strcmp($1, "3des") || !strcmp($1, "3des-cbc")) {
2400 				$$.enc_alg = AUTH_EALG_3DESCBC;
2401 				$$.enc_key_len = 21; /* XXX verify */
2402 			} else if (!strcmp($1, "aes") ||
2403 			    !strcmp($1, "aes-128-cbc")) {
2404 				$$.enc_alg = AUTH_EALG_AES;
2405 				$$.enc_key_len = 16;
2406 			} else {
2407 				yyerror("unknown enc algorithm \"%s\"", $1);
2408 				free($1);
2409 				free($2);
2410 				YYERROR;
2411 			}
2412 			free($1);
2413 
2414 			if (strlen($2) / 2 != $$.enc_key_len) {
2415 				yyerror("enc key length wrong: should be %u "
2416 				    "bytes, is %zu bytes",
2417 				    $$.enc_key_len * 2, strlen($2));
2418 				free($2);
2419 				YYERROR;
2420 			}
2421 
2422 			if (str2key($2, $$.enc_key, sizeof($$.enc_key)) == -1) {
2423 				free($2);
2424 				YYERROR;
2425 			}
2426 			free($2);
2427 		}
2428 		;
2429 
2430 filterrule	: action quick filter_rib_h direction filter_peer_h
2431 				filter_match_h filter_set
2432 		{
2433 			struct filter_rule	 r;
2434 			struct filter_rib_l	 *rb, *rbnext;
2435 
2436 			memset(&r, 0, sizeof(r));
2437 			r.action = $1;
2438 			r.quick = $2;
2439 			r.dir = $4;
2440 			if ($3) {
2441 				if (r.dir != DIR_IN) {
2442 					yyerror("rib only allowed on \"from\" "
2443 					    "rules.");
2444 
2445 					for (rb = $3; rb != NULL; rb = rbnext) {
2446 						rbnext = rb->next;
2447 						free(rb);
2448 					}
2449 					YYERROR;
2450 				}
2451 			}
2452 			if (expand_rule(&r, $3, $5, &$6, $7) == -1)
2453 				YYERROR;
2454 		}
2455 		;
2456 
2457 action		: ALLOW		{ $$ = ACTION_ALLOW; }
2458 		| DENY		{ $$ = ACTION_DENY; }
2459 		| MATCH		{ $$ = ACTION_NONE; }
2460 		;
2461 
2462 quick		: /* empty */	{ $$ = 0; }
2463 		| QUICK		{ $$ = 1; }
2464 		;
2465 
2466 direction	: FROM		{ $$ = DIR_IN; }
2467 		| TO		{ $$ = DIR_OUT; }
2468 		;
2469 
2470 filter_rib_h	: /* empty */			{ $$ = NULL; }
2471 		| RIB filter_rib		{ $$ = $2; }
2472 		| RIB '{' optnl filter_rib_l optnl '}'	{ $$ = $4; }
2473 
2474 filter_rib_l	: filter_rib			{ $$ = $1; }
2475 		| filter_rib_l comma filter_rib	{
2476 			$3->next = $1;
2477 			$$ = $3;
2478 		}
2479 		;
2480 
2481 filter_rib	: STRING	{
2482 			if (!find_rib($1)) {
2483 				yyerror("rib \"%s\" does not exist.", $1);
2484 				free($1);
2485 				YYERROR;
2486 			}
2487 			if (($$ = calloc(1, sizeof(struct filter_rib_l))) ==
2488 			    NULL)
2489 				fatal(NULL);
2490 			$$->next = NULL;
2491 			if (strlcpy($$->name, $1, sizeof($$->name)) >=
2492 			    sizeof($$->name)) {
2493 				yyerror("rib name \"%s\" too long: "
2494 				    "max %zu", $1, sizeof($$->name) - 1);
2495 				free($1);
2496 				free($$);
2497 				YYERROR;
2498 			}
2499 			free($1);
2500 		}
2501 		;
2502 
2503 filter_peer_h	: filter_peer
2504 		| '{' optnl filter_peer_l optnl '}'	{ $$ = $3; }
2505 		;
2506 
2507 filter_peer_l	: filter_peer				{ $$ = $1; }
2508 		| filter_peer_l comma filter_peer	{
2509 			$3->next = $1;
2510 			$$ = $3;
2511 		}
2512 		;
2513 
2514 filter_peer	: ANY		{
2515 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
2516 			    NULL)
2517 				fatal(NULL);
2518 			$$->p.peerid = $$->p.groupid = 0;
2519 			$$->next = NULL;
2520 		}
2521 		| address	{
2522 			struct peer *p;
2523 
2524 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
2525 			    NULL)
2526 				fatal(NULL);
2527 			$$->p.remote_as = $$->p.groupid = $$->p.peerid = 0;
2528 			$$->next = NULL;
2529 			RB_FOREACH(p, peer_head, new_peers)
2530 				if (!memcmp(&p->conf.remote_addr,
2531 				    &$1, sizeof(p->conf.remote_addr))) {
2532 					$$->p.peerid = p->conf.id;
2533 					break;
2534 				}
2535 			if ($$->p.peerid == 0) {
2536 				yyerror("no such peer: %s", log_addr(&$1));
2537 				free($$);
2538 				YYERROR;
2539 			}
2540 		}
2541 		| AS as4number	{
2542 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
2543 			    NULL)
2544 				fatal(NULL);
2545 			$$->p.groupid = $$->p.peerid = 0;
2546 			$$->p.remote_as = $2;
2547 		}
2548 		| GROUP STRING	{
2549 			struct peer *p;
2550 
2551 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
2552 			    NULL)
2553 				fatal(NULL);
2554 			$$->p.remote_as = $$->p.peerid = 0;
2555 			$$->next = NULL;
2556 			RB_FOREACH(p, peer_head, new_peers)
2557 				if (!strcmp(p->conf.group, $2)) {
2558 					$$->p.groupid = p->conf.groupid;
2559 					break;
2560 				}
2561 			if ($$->p.groupid == 0) {
2562 				yyerror("no such group: \"%s\"", $2);
2563 				free($2);
2564 				free($$);
2565 				YYERROR;
2566 			}
2567 			free($2);
2568 		}
2569 		| EBGP {
2570 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
2571 			    NULL)
2572 				fatal(NULL);
2573 			$$->p.ebgp = 1;
2574 		}
2575 		| IBGP {
2576 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
2577 			    NULL)
2578 				fatal(NULL);
2579 			$$->p.ibgp = 1;
2580 		}
2581 		;
2582 
2583 filter_prefix_h	: IPV4 prefixlenop			 {
2584 			if ($2.op == OP_NONE) {
2585 				$2.op = OP_RANGE;
2586 				$2.len_min = 0;
2587 				$2.len_max = -1;
2588 			}
2589 			if (($$ = calloc(1, sizeof(struct filter_prefix_l))) ==
2590 			    NULL)
2591 				fatal(NULL);
2592 			$$->p.addr.aid = AID_INET;
2593 			if (merge_prefixspec(&$$->p, &$2) == -1) {
2594 				free($$);
2595 				YYERROR;
2596 			}
2597 		}
2598 		| IPV6 prefixlenop			{
2599 			if ($2.op == OP_NONE) {
2600 				$2.op = OP_RANGE;
2601 				$2.len_min = 0;
2602 				$2.len_max = -1;
2603 			}
2604 			if (($$ = calloc(1, sizeof(struct filter_prefix_l))) ==
2605 			    NULL)
2606 				fatal(NULL);
2607 			$$->p.addr.aid = AID_INET6;
2608 			if (merge_prefixspec(&$$->p, &$2) == -1) {
2609 				free($$);
2610 				YYERROR;
2611 			}
2612 		}
2613 		| PREFIX filter_prefix			{ $$ = $2; }
2614 		| PREFIX '{' filter_prefix_m '}'	{ $$ = $3; }
2615 		;
2616 
2617 filter_prefix_m	: filter_prefix_l
2618 		| '{' filter_prefix_l '}'		{ $$ = $2; }
2619 		| '{' filter_prefix_l '}' filter_prefix_m
2620 		{
2621 			struct filter_prefix_l	*p;
2622 
2623 			/* merge, both can be lists */
2624 			for (p = $2; p != NULL && p->next != NULL; p = p->next)
2625 				;	/* nothing */
2626 			if (p != NULL)
2627 				p->next = $4;
2628 			$$ = $2;
2629 		}
2630 
2631 filter_prefix_l	: filter_prefix			{ $$ = $1; }
2632 		| filter_prefix_l comma filter_prefix	{
2633 			$3->next = $1;
2634 			$$ = $3;
2635 		}
2636 		;
2637 
2638 filter_prefix	: prefix prefixlenop			{
2639 			if (($$ = calloc(1, sizeof(struct filter_prefix_l))) ==
2640 			    NULL)
2641 				fatal(NULL);
2642 			memcpy(&$$->p.addr, &$1.prefix,
2643 			    sizeof($$->p.addr));
2644 			$$->p.len = $1.len;
2645 
2646 			if (merge_prefixspec(&$$->p, &$2) == -1) {
2647 				free($$);
2648 				YYERROR;
2649 			}
2650 		}
2651 		;
2652 
2653 filter_as_h	: filter_as_t
2654 		| '{' filter_as_t_l '}'		{ $$ = $2; }
2655 		;
2656 
2657 filter_as_t_l	: filter_as_t
2658 		| filter_as_t_l comma filter_as_t		{
2659 			struct filter_as_l	*a;
2660 
2661 			/* merge, both can be lists */
2662 			for (a = $1; a != NULL && a->next != NULL; a = a->next)
2663 				;	/* nothing */
2664 			if (a != NULL)
2665 				a->next = $3;
2666 			$$ = $1;
2667 		}
2668 		;
2669 
2670 filter_as_t	: filter_as_type filter_as			{
2671 			$$ = $2;
2672 			$$->a.type = $1;
2673 		}
2674 		| filter_as_type '{' filter_as_l_h '}'	{
2675 			struct filter_as_l	*a;
2676 
2677 			$$ = $3;
2678 			for (a = $$; a != NULL; a = a->next)
2679 				a->a.type = $1;
2680 		}
2681 		| filter_as_type ASSET STRING {
2682 			if (as_sets_lookup(&conf->as_sets, $3) == NULL) {
2683 				yyerror("as-set \"%s\" not defined", $3);
2684 				free($3);
2685 				YYERROR;
2686 			}
2687 			if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
2688 			    NULL)
2689 				fatal(NULL);
2690 			$$->a.type = $1;
2691 			$$->a.flags = AS_FLAG_AS_SET_NAME;
2692 			if (strlcpy($$->a.name, $3, sizeof($$->a.name)) >=
2693 			    sizeof($$->a.name)) {
2694 				yyerror("as-set name \"%s\" too long: "
2695 				    "max %zu", $3, sizeof($$->a.name) - 1);
2696 				free($3);
2697 				free($$);
2698 				YYERROR;
2699 			}
2700 			free($3);
2701 		}
2702 		;
2703 
2704 filter_as_l_h	: filter_as_l
2705 		| '{' filter_as_l '}'			{ $$ = $2; }
2706 		| '{' filter_as_l '}' filter_as_l_h
2707 		{
2708 			struct filter_as_l	*a;
2709 
2710 			/* merge, both can be lists */
2711 			for (a = $2; a != NULL && a->next != NULL; a = a->next)
2712 				;	/* nothing */
2713 			if (a != NULL)
2714 				a->next = $4;
2715 			$$ = $2;
2716 		}
2717 		;
2718 
2719 filter_as_l	: filter_as
2720 		| filter_as_l comma filter_as	{
2721 			$3->next = $1;
2722 			$$ = $3;
2723 		}
2724 		;
2725 
2726 filter_as	: as4number_any		{
2727 			if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
2728 			    NULL)
2729 				fatal(NULL);
2730 			$$->a.as_min = $1;
2731 			$$->a.as_max = $1;
2732 			$$->a.op = OP_EQ;
2733 		}
2734 		| NEIGHBORAS		{
2735 			if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
2736 			    NULL)
2737 				fatal(NULL);
2738 			$$->a.flags = AS_FLAG_NEIGHBORAS;
2739 		}
2740 		| equalityop as4number_any	{
2741 			if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
2742 			    NULL)
2743 				fatal(NULL);
2744 			$$->a.op = $1;
2745 			$$->a.as_min = $2;
2746 			$$->a.as_max = $2;
2747 		}
2748 		| as4number_any binaryop as4number_any {
2749 			if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
2750 			    NULL)
2751 				fatal(NULL);
2752 			if ($1 >= $3) {
2753 				yyerror("start AS is bigger than end");
2754 				YYERROR;
2755 			}
2756 			$$->a.op = $2;
2757 			$$->a.as_min = $1;
2758 			$$->a.as_max = $3;
2759 		}
2760 		;
2761 
2762 filter_match_h	: /* empty */			{
2763 			memset(&$$, 0, sizeof($$));
2764 		}
2765 		| {
2766 			memset(&fmopts, 0, sizeof(fmopts));
2767 		}
2768 		    filter_match		{
2769 			memcpy(&$$, &fmopts, sizeof($$));
2770 		}
2771 		;
2772 
2773 filter_match	: filter_elm
2774 		| filter_match filter_elm
2775 		;
2776 
2777 filter_elm	: filter_prefix_h	{
2778 			if (fmopts.prefix_l != NULL) {
2779 				yyerror("\"prefix\" already specified");
2780 				YYERROR;
2781 			}
2782 			if (fmopts.m.prefixset.name[0] != '\0') {
2783 				yyerror("\"prefix-set\" already specified, "
2784 				    "cannot be used with \"prefix\" in the "
2785 				    "same filter rule");
2786 				YYERROR;
2787 			}
2788 			fmopts.prefix_l = $1;
2789 		}
2790 		| filter_as_h		{
2791 			if (fmopts.as_l != NULL) {
2792 				yyerror("AS filters already specified");
2793 				YYERROR;
2794 			}
2795 			fmopts.as_l = $1;
2796 		}
2797 		| MAXASLEN NUMBER	{
2798 			if (fmopts.m.aslen.type != ASLEN_NONE) {
2799 				yyerror("AS length filters already specified");
2800 				YYERROR;
2801 			}
2802 			if ($2 < 0 || $2 > UINT_MAX) {
2803 				yyerror("bad max-as-len %lld", $2);
2804 				YYERROR;
2805 			}
2806 			fmopts.m.aslen.type = ASLEN_MAX;
2807 			fmopts.m.aslen.aslen = $2;
2808 		}
2809 		| MAXASSEQ NUMBER	{
2810 			if (fmopts.m.aslen.type != ASLEN_NONE) {
2811 				yyerror("AS length filters already specified");
2812 				YYERROR;
2813 			}
2814 			if ($2 < 0 || $2 > UINT_MAX) {
2815 				yyerror("bad max-as-seq %lld", $2);
2816 				YYERROR;
2817 			}
2818 			fmopts.m.aslen.type = ASLEN_SEQ;
2819 			fmopts.m.aslen.aslen = $2;
2820 		}
2821 		| community STRING	{
2822 			int i;
2823 			for (i = 0; i < MAX_COMM_MATCH; i++) {
2824 				if (fmopts.m.community[i].flags == 0)
2825 					break;
2826 			}
2827 			if (i >= MAX_COMM_MATCH) {
2828 				yyerror("too many \"community\" filters "
2829 				    "specified");
2830 				free($2);
2831 				YYERROR;
2832 			}
2833 			if (parsecommunity(&fmopts.m.community[i], $1, $2) == -1) {
2834 				free($2);
2835 				YYERROR;
2836 			}
2837 			free($2);
2838 		}
2839 		| EXTCOMMUNITY STRING STRING {
2840 			int i;
2841 			for (i = 0; i < MAX_COMM_MATCH; i++) {
2842 				if (fmopts.m.community[i].flags == 0)
2843 					break;
2844 			}
2845 			if (i >= MAX_COMM_MATCH) {
2846 				yyerror("too many \"community\" filters "
2847 				    "specified");
2848 				free($2);
2849 				free($3);
2850 				YYERROR;
2851 			}
2852 			if (parseextcommunity(&fmopts.m.community[i],
2853 			    $2, $3) == -1) {
2854 				free($2);
2855 				free($3);
2856 				YYERROR;
2857 			}
2858 			free($2);
2859 			free($3);
2860 		}
2861 		| EXTCOMMUNITY OVS STRING {
2862 			int i;
2863 			for (i = 0; i < MAX_COMM_MATCH; i++) {
2864 				if (fmopts.m.community[i].flags == 0)
2865 					break;
2866 			}
2867 			if (i >= MAX_COMM_MATCH) {
2868 				yyerror("too many \"community\" filters "
2869 				    "specified");
2870 				free($3);
2871 				YYERROR;
2872 			}
2873 			if (parseextcommunity(&fmopts.m.community[i],
2874 			    "ovs", $3) == -1) {
2875 				free($3);
2876 				YYERROR;
2877 			}
2878 			free($3);
2879 		}
2880 		| MAXCOMMUNITIES NUMBER {
2881 			if ($2 < 0 || $2 > INT16_MAX) {
2882 				yyerror("bad max-comunities %lld", $2);
2883 				YYERROR;
2884 			}
2885 			if (fmopts.m.maxcomm != 0) {
2886 				yyerror("%s already specified",
2887 				    "max-communities");
2888 				YYERROR;
2889 			}
2890 			/*
2891 			 * Offset by 1 since 0 means not used.
2892 			 * The match function then uses >= to compensate.
2893 			 */
2894 			fmopts.m.maxcomm = $2 + 1;
2895 		}
2896 		| MAXEXTCOMMUNITIES NUMBER {
2897 			if ($2 < 0 || $2 > INT16_MAX) {
2898 				yyerror("bad max-ext-communities %lld", $2);
2899 				YYERROR;
2900 			}
2901 			if (fmopts.m.maxextcomm != 0) {
2902 				yyerror("%s already specified",
2903 				    "max-ext-communities");
2904 				YYERROR;
2905 			}
2906 			fmopts.m.maxextcomm = $2 + 1;
2907 		}
2908 		| MAXLARGECOMMUNITIES NUMBER {
2909 			if ($2 < 0 || $2 > INT16_MAX) {
2910 				yyerror("bad max-large-communities %lld", $2);
2911 				YYERROR;
2912 			}
2913 			if (fmopts.m.maxlargecomm != 0) {
2914 				yyerror("%s already specified",
2915 				    "max-large-communities");
2916 				YYERROR;
2917 			}
2918 			fmopts.m.maxlargecomm = $2 + 1;
2919 		}
2920 		| NEXTHOP address	{
2921 			if (fmopts.m.nexthop.flags) {
2922 				yyerror("nexthop already specified");
2923 				YYERROR;
2924 			}
2925 			fmopts.m.nexthop.addr = $2;
2926 			fmopts.m.nexthop.flags = FILTER_NEXTHOP_ADDR;
2927 		}
2928 		| NEXTHOP NEIGHBOR	{
2929 			if (fmopts.m.nexthop.flags) {
2930 				yyerror("nexthop already specified");
2931 				YYERROR;
2932 			}
2933 			fmopts.m.nexthop.flags = FILTER_NEXTHOP_NEIGHBOR;
2934 		}
2935 		| PREFIXSET STRING prefixlenop {
2936 			struct prefixset *ps;
2937 			if (fmopts.prefix_l != NULL) {
2938 				yyerror("\"prefix\" already specified, cannot "
2939 				    "be used with \"prefix-set\" in the same "
2940 				    "filter rule");
2941 				free($2);
2942 				YYERROR;
2943 			}
2944 			if (fmopts.m.prefixset.name[0] != '\0') {
2945 				yyerror("prefix-set filter already specified");
2946 				free($2);
2947 				YYERROR;
2948 			}
2949 			if ((ps = find_prefixset($2, &conf->prefixsets))
2950 			    == NULL) {
2951 				yyerror("prefix-set '%s' not defined", $2);
2952 				free($2);
2953 				YYERROR;
2954 			}
2955 			if (strlcpy(fmopts.m.prefixset.name, $2,
2956 			    sizeof(fmopts.m.prefixset.name)) >=
2957 			    sizeof(fmopts.m.prefixset.name)) {
2958 				yyerror("prefix-set name too long");
2959 				free($2);
2960 				YYERROR;
2961 			}
2962 			if (!($3.op == OP_NONE ||
2963 			    ($3.op == OP_RANGE &&
2964 			     $3.len_min == -1 && $3.len_max == -1))) {
2965 				yyerror("prefix-sets can only use option "
2966 				    "or-longer");
2967 				free($2);
2968 				YYERROR;
2969 			}
2970 			if ($3.op == OP_RANGE && ps->sflags & PREFIXSET_FLAG_OPS) {
2971 				yyerror("prefix-set %s contains prefixlen "
2972 				    "operators and cannot be used with an "
2973 				    "or-longer filter", $2);
2974 				free($2);
2975 				YYERROR;
2976 			}
2977 			if ($3.op == OP_RANGE && $3.len_min == -1 &&
2978 			    $3.len_min == -1)
2979 				fmopts.m.prefixset.flags |=
2980 				    PREFIXSET_FLAG_LONGER;
2981 			fmopts.m.prefixset.flags |= PREFIXSET_FLAG_FILTER;
2982 			free($2);
2983 		}
2984 		| ORIGINSET STRING {
2985 			if (fmopts.m.originset.name[0] != '\0') {
2986 				yyerror("origin-set filter already specified");
2987 				free($2);
2988 				YYERROR;
2989 			}
2990 			if (find_prefixset($2, &conf->originsets) == NULL) {
2991 				yyerror("origin-set '%s' not defined", $2);
2992 				free($2);
2993 				YYERROR;
2994 			}
2995 			if (strlcpy(fmopts.m.originset.name, $2,
2996 			    sizeof(fmopts.m.originset.name)) >=
2997 			    sizeof(fmopts.m.originset.name)) {
2998 				yyerror("origin-set name too long");
2999 				free($2);
3000 				YYERROR;
3001 			}
3002 			free($2);
3003 		}
3004 		| OVS validity		{
3005 			if (fmopts.m.ovs.is_set) {
3006 				yyerror("ovs filter already specified");
3007 				YYERROR;
3008 			}
3009 			fmopts.m.ovs.validity = $2;
3010 			fmopts.m.ovs.is_set = 1;
3011 		}
3012 		| AVS aspa_validity		{
3013 			if (fmopts.m.avs.is_set) {
3014 				yyerror("avs filter already specified");
3015 				YYERROR;
3016 			}
3017 			fmopts.m.avs.validity = $2;
3018 			fmopts.m.avs.is_set = 1;
3019 		}
3020 		;
3021 
3022 prefixlenop	: /* empty */		{ memset(&$$, 0, sizeof($$)); }
3023 		| LONGER				{
3024 			memset(&$$, 0, sizeof($$));
3025 			$$.op = OP_RANGE;
3026 			$$.len_min = -1;
3027 			$$.len_max = -1;
3028 		}
3029 		| MAXLEN NUMBER				{
3030 			memset(&$$, 0, sizeof($$));
3031 			if ($2 < 0 || $2 > 128) {
3032 				yyerror("prefixlen must be >= 0 and <= 128");
3033 				YYERROR;
3034 			}
3035 
3036 			$$.op = OP_RANGE;
3037 			$$.len_min = -1;
3038 			$$.len_max = $2;
3039 		}
3040 		| PREFIXLEN unaryop NUMBER		{
3041 			int min, max;
3042 
3043 			memset(&$$, 0, sizeof($$));
3044 			if ($3 < 0 || $3 > 128) {
3045 				yyerror("prefixlen must be >= 0 and <= 128");
3046 				YYERROR;
3047 			}
3048 			/*
3049 			 * convert the unary operation into the equivalent
3050 			 * range check
3051 			 */
3052 			$$.op = OP_RANGE;
3053 
3054 			switch ($2) {
3055 			case OP_NE:
3056 				$$.op = $2;
3057 			case OP_EQ:
3058 				min = max = $3;
3059 				break;
3060 			case OP_LT:
3061 				if ($3 == 0) {
3062 					yyerror("prefixlen must be > 0");
3063 					YYERROR;
3064 				}
3065 				$3 -= 1;
3066 			case OP_LE:
3067 				min = -1;
3068 				max = $3;
3069 				break;
3070 			case OP_GT:
3071 				$3 += 1;
3072 			case OP_GE:
3073 				min = $3;
3074 				max = -1;
3075 				break;
3076 			default:
3077 				yyerror("unknown prefixlen operation");
3078 				YYERROR;
3079 			}
3080 			$$.len_min = min;
3081 			$$.len_max = max;
3082 		}
3083 		| PREFIXLEN NUMBER binaryop NUMBER	{
3084 			memset(&$$, 0, sizeof($$));
3085 			if ($2 < 0 || $2 > 128 || $4 < 0 || $4 > 128) {
3086 				yyerror("prefixlen must be < 128");
3087 				YYERROR;
3088 			}
3089 			if ($2 > $4) {
3090 				yyerror("start prefixlen is bigger than end");
3091 				YYERROR;
3092 			}
3093 			$$.op = $3;
3094 			$$.len_min = $2;
3095 			$$.len_max = $4;
3096 		}
3097 		;
3098 
3099 filter_as_type	: AS		{ $$ = AS_ALL; }
3100 		| SOURCEAS	{ $$ = AS_SOURCE; }
3101 		| TRANSITAS	{ $$ = AS_TRANSIT; }
3102 		| PEERAS	{ $$ = AS_PEER; }
3103 		;
3104 
3105 filter_set	: /* empty */	{ $$ = NULL; }
3106 		| SET filter_set_opt	{
3107 			if (($$ = calloc(1, sizeof(struct filter_set_head))) ==
3108 			    NULL)
3109 				fatal(NULL);
3110 			TAILQ_INIT($$);
3111 			TAILQ_INSERT_TAIL($$, $2, entry);
3112 		}
3113 		| SET '{' optnl filter_set_l optnl '}'	{ $$ = $4; }
3114 		;
3115 
3116 filter_set_l	: filter_set_l comma filter_set_opt	{
3117 			$$ = $1;
3118 			if (merge_filterset($$, $3) == 1)
3119 				YYERROR;
3120 		}
3121 		| filter_set_opt {
3122 			if (($$ = calloc(1, sizeof(struct filter_set_head))) ==
3123 			    NULL)
3124 				fatal(NULL);
3125 			TAILQ_INIT($$);
3126 			TAILQ_INSERT_TAIL($$, $1, entry);
3127 		}
3128 		;
3129 
3130 community	: COMMUNITY		{ $$ = COMMUNITY_TYPE_BASIC; }
3131 		| LARGECOMMUNITY	{ $$ = COMMUNITY_TYPE_LARGE; }
3132 		;
3133 
3134 delete		: /* empty */	{ $$ = 0; }
3135 		| DELETE	{ $$ = 1; }
3136 		;
3137 
3138 enforce		: /* empty */	{ $$ = 0; }
3139 		| ENFORCE	{ $$ = 2; }
3140 		;
3141 
3142 yesnoenforce	: yesno		{ $$ = $1; }
3143 		| ENFORCE	{ $$ = 2; }
3144 		;
3145 
3146 filter_set_opt	: LOCALPREF NUMBER		{
3147 			if ($2 < -INT_MAX || $2 > UINT_MAX) {
3148 				yyerror("bad localpref %lld", $2);
3149 				YYERROR;
3150 			}
3151 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3152 				fatal(NULL);
3153 			if ($2 >= 0) {
3154 				$$->type = ACTION_SET_LOCALPREF;
3155 				$$->action.metric = $2;
3156 			} else {
3157 				$$->type = ACTION_SET_RELATIVE_LOCALPREF;
3158 				$$->action.relative = $2;
3159 			}
3160 		}
3161 		| LOCALPREF '+' NUMBER		{
3162 			if ($3 < 0 || $3 > INT_MAX) {
3163 				yyerror("bad localpref +%lld", $3);
3164 				YYERROR;
3165 			}
3166 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3167 				fatal(NULL);
3168 			$$->type = ACTION_SET_RELATIVE_LOCALPREF;
3169 			$$->action.relative = $3;
3170 		}
3171 		| LOCALPREF '-' NUMBER		{
3172 			if ($3 < 0 || $3 > INT_MAX) {
3173 				yyerror("bad localpref -%lld", $3);
3174 				YYERROR;
3175 			}
3176 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3177 				fatal(NULL);
3178 			$$->type = ACTION_SET_RELATIVE_LOCALPREF;
3179 			$$->action.relative = -$3;
3180 		}
3181 		| MED NUMBER			{
3182 			if ($2 < -INT_MAX || $2 > UINT_MAX) {
3183 				yyerror("bad metric %lld", $2);
3184 				YYERROR;
3185 			}
3186 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3187 				fatal(NULL);
3188 			if ($2 >= 0) {
3189 				$$->type = ACTION_SET_MED;
3190 				$$->action.metric = $2;
3191 			} else {
3192 				$$->type = ACTION_SET_RELATIVE_MED;
3193 				$$->action.relative = $2;
3194 			}
3195 		}
3196 		| MED '+' NUMBER		{
3197 			if ($3 < 0 || $3 > INT_MAX) {
3198 				yyerror("bad metric +%lld", $3);
3199 				YYERROR;
3200 			}
3201 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3202 				fatal(NULL);
3203 			$$->type = ACTION_SET_RELATIVE_MED;
3204 			$$->action.relative = $3;
3205 		}
3206 		| MED '-' 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.relative = -$3;
3215 		}
3216 		| METRIC NUMBER			{	/* alias for MED */
3217 			if ($2 < -INT_MAX || $2 > UINT_MAX) {
3218 				yyerror("bad metric %lld", $2);
3219 				YYERROR;
3220 			}
3221 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3222 				fatal(NULL);
3223 			if ($2 >= 0) {
3224 				$$->type = ACTION_SET_MED;
3225 				$$->action.metric = $2;
3226 			} else {
3227 				$$->type = ACTION_SET_RELATIVE_MED;
3228 				$$->action.relative = $2;
3229 			}
3230 		}
3231 		| METRIC '+' NUMBER		{
3232 			if ($3 < 0 || $3 > INT_MAX) {
3233 				yyerror("bad metric +%lld", $3);
3234 				YYERROR;
3235 			}
3236 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3237 				fatal(NULL);
3238 			$$->type = ACTION_SET_RELATIVE_MED;
3239 			$$->action.metric = $3;
3240 		}
3241 		| METRIC '-' NUMBER		{
3242 			if ($3 < 0 || $3 > INT_MAX) {
3243 				yyerror("bad metric -%lld", $3);
3244 				YYERROR;
3245 			}
3246 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3247 				fatal(NULL);
3248 			$$->type = ACTION_SET_RELATIVE_MED;
3249 			$$->action.relative = -$3;
3250 		}
3251 		| WEIGHT NUMBER			{
3252 			if ($2 < -INT_MAX || $2 > UINT_MAX) {
3253 				yyerror("bad weight %lld", $2);
3254 				YYERROR;
3255 			}
3256 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3257 				fatal(NULL);
3258 			if ($2 > 0) {
3259 				$$->type = ACTION_SET_WEIGHT;
3260 				$$->action.metric = $2;
3261 			} else {
3262 				$$->type = ACTION_SET_RELATIVE_WEIGHT;
3263 				$$->action.relative = $2;
3264 			}
3265 		}
3266 		| WEIGHT '+' NUMBER		{
3267 			if ($3 < 0 || $3 > INT_MAX) {
3268 				yyerror("bad weight +%lld", $3);
3269 				YYERROR;
3270 			}
3271 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3272 				fatal(NULL);
3273 			$$->type = ACTION_SET_RELATIVE_WEIGHT;
3274 			$$->action.relative = $3;
3275 		}
3276 		| WEIGHT '-' NUMBER		{
3277 			if ($3 < 0 || $3 > INT_MAX) {
3278 				yyerror("bad weight -%lld", $3);
3279 				YYERROR;
3280 			}
3281 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3282 				fatal(NULL);
3283 			$$->type = ACTION_SET_RELATIVE_WEIGHT;
3284 			$$->action.relative = -$3;
3285 		}
3286 		| NEXTHOP address		{
3287 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3288 				fatal(NULL);
3289 			$$->type = ACTION_SET_NEXTHOP;
3290 			memcpy(&$$->action.nexthop, &$2,
3291 			    sizeof($$->action.nexthop));
3292 		}
3293 		| NEXTHOP BLACKHOLE		{
3294 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3295 				fatal(NULL);
3296 			$$->type = ACTION_SET_NEXTHOP_BLACKHOLE;
3297 		}
3298 		| NEXTHOP REJECT		{
3299 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3300 				fatal(NULL);
3301 			$$->type = ACTION_SET_NEXTHOP_REJECT;
3302 		}
3303 		| NEXTHOP NOMODIFY		{
3304 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3305 				fatal(NULL);
3306 			$$->type = ACTION_SET_NEXTHOP_NOMODIFY;
3307 		}
3308 		| NEXTHOP SELF		{
3309 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3310 				fatal(NULL);
3311 			$$->type = ACTION_SET_NEXTHOP_SELF;
3312 		}
3313 		| PREPEND_SELF NUMBER		{
3314 			if ($2 < 0 || $2 > 128) {
3315 				yyerror("bad number of prepends");
3316 				YYERROR;
3317 			}
3318 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3319 				fatal(NULL);
3320 			$$->type = ACTION_SET_PREPEND_SELF;
3321 			$$->action.prepend = $2;
3322 		}
3323 		| PREPEND_PEER NUMBER		{
3324 			if ($2 < 0 || $2 > 128) {
3325 				yyerror("bad number of prepends");
3326 				YYERROR;
3327 			}
3328 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3329 				fatal(NULL);
3330 			$$->type = ACTION_SET_PREPEND_PEER;
3331 			$$->action.prepend = $2;
3332 		}
3333 		| ASOVERRIDE			{
3334 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3335 				fatal(NULL);
3336 			$$->type = ACTION_SET_AS_OVERRIDE;
3337 		}
3338 		| PFTABLE STRING		{
3339 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3340 				fatal(NULL);
3341 			$$->type = ACTION_PFTABLE;
3342 			if (!(cmd_opts & BGPD_OPT_NOACTION) &&
3343 			    pftable_exists($2) != 0) {
3344 				yyerror("pftable name does not exist");
3345 				free($2);
3346 				free($$);
3347 				YYERROR;
3348 			}
3349 			if (strlcpy($$->action.pftable, $2,
3350 			    sizeof($$->action.pftable)) >=
3351 			    sizeof($$->action.pftable)) {
3352 				yyerror("pftable name too long");
3353 				free($2);
3354 				free($$);
3355 				YYERROR;
3356 			}
3357 			if (pftable_add($2) != 0) {
3358 				yyerror("Couldn't register table");
3359 				free($2);
3360 				free($$);
3361 				YYERROR;
3362 			}
3363 			free($2);
3364 		}
3365 		| RTLABEL STRING		{
3366 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3367 				fatal(NULL);
3368 			$$->type = ACTION_RTLABEL;
3369 			if (strlcpy($$->action.rtlabel, $2,
3370 			    sizeof($$->action.rtlabel)) >=
3371 			    sizeof($$->action.rtlabel)) {
3372 				yyerror("rtlabel name too long");
3373 				free($2);
3374 				free($$);
3375 				YYERROR;
3376 			}
3377 			free($2);
3378 		}
3379 		| community delete STRING	{
3380 			uint8_t f1, f2, f3;
3381 
3382 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3383 				fatal(NULL);
3384 			if ($2)
3385 				$$->type = ACTION_DEL_COMMUNITY;
3386 			else
3387 				$$->type = ACTION_SET_COMMUNITY;
3388 
3389 			if (parsecommunity(&$$->action.community, $1, $3) ==
3390 			    -1) {
3391 				free($3);
3392 				free($$);
3393 				YYERROR;
3394 			}
3395 			free($3);
3396 			/* Don't allow setting of any match */
3397 			f1 = $$->action.community.flags >> 8;
3398 			f2 = $$->action.community.flags >> 16;
3399 			f3 = $$->action.community.flags >> 24;
3400 			if (!$2 && (f1 == COMMUNITY_ANY ||
3401 			    f2 == COMMUNITY_ANY || f3 == COMMUNITY_ANY)) {
3402 				yyerror("'*' is not allowed in set community");
3403 				free($$);
3404 				YYERROR;
3405 			}
3406 		}
3407 		| EXTCOMMUNITY delete STRING STRING {
3408 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3409 				fatal(NULL);
3410 			if ($2)
3411 				$$->type = ACTION_DEL_COMMUNITY;
3412 			else
3413 				$$->type = ACTION_SET_COMMUNITY;
3414 
3415 			if (parseextcommunity(&$$->action.community,
3416 			    $3, $4) == -1) {
3417 				free($3);
3418 				free($4);
3419 				free($$);
3420 				YYERROR;
3421 			}
3422 			free($3);
3423 			free($4);
3424 		}
3425 		| EXTCOMMUNITY delete OVS STRING {
3426 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3427 				fatal(NULL);
3428 			if ($2)
3429 				$$->type = ACTION_DEL_COMMUNITY;
3430 			else
3431 				$$->type = ACTION_SET_COMMUNITY;
3432 
3433 			if (parseextcommunity(&$$->action.community,
3434 			    "ovs", $4) == -1) {
3435 				free($4);
3436 				free($$);
3437 				YYERROR;
3438 			}
3439 			free($4);
3440 		}
3441 		| ORIGIN origincode {
3442 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
3443 				fatal(NULL);
3444 			$$->type = ACTION_SET_ORIGIN;
3445 			$$->action.origin = $2;
3446 		}
3447 		;
3448 
3449 origincode	: STRING	{
3450 			if (!strcmp($1, "egp"))
3451 				$$ = ORIGIN_EGP;
3452 			else if (!strcmp($1, "igp"))
3453 				$$ = ORIGIN_IGP;
3454 			else if (!strcmp($1, "incomplete"))
3455 				$$ = ORIGIN_INCOMPLETE;
3456 			else {
3457 				yyerror("unknown origin \"%s\"", $1);
3458 				free($1);
3459 				YYERROR;
3460 			}
3461 			free($1);
3462 		};
3463 
3464 validity	: STRING	{
3465 			if (!strcmp($1, "not-found"))
3466 				$$ = ROA_NOTFOUND;
3467 			else if (!strcmp($1, "invalid"))
3468 				$$ = ROA_INVALID;
3469 			else if (!strcmp($1, "valid"))
3470 				$$ = ROA_VALID;
3471 			else {
3472 				yyerror("unknown roa validity \"%s\"", $1);
3473 				free($1);
3474 				YYERROR;
3475 			}
3476 			free($1);
3477 		};
3478 
3479 aspa_validity	: STRING	{
3480 			if (!strcmp($1, "unknown"))
3481 				$$ = ASPA_UNKNOWN;
3482 			else if (!strcmp($1, "invalid"))
3483 				$$ = ASPA_INVALID;
3484 			else if (!strcmp($1, "valid"))
3485 				$$ = ASPA_VALID;
3486 			else {
3487 				yyerror("unknown aspa validity \"%s\"", $1);
3488 				free($1);
3489 				YYERROR;
3490 			}
3491 			free($1);
3492 		};
3493 
3494 optnl		: /* empty */
3495 		| '\n' optnl
3496 		;
3497 
3498 comma		: /* empty */
3499 		| ','
3500 		| '\n' optnl
3501 		| ',' '\n' optnl
3502 		;
3503 
3504 unaryop		: '='		{ $$ = OP_EQ; }
3505 		| NE		{ $$ = OP_NE; }
3506 		| LE		{ $$ = OP_LE; }
3507 		| '<'		{ $$ = OP_LT; }
3508 		| GE		{ $$ = OP_GE; }
3509 		| '>'		{ $$ = OP_GT; }
3510 		;
3511 
3512 equalityop	: '='		{ $$ = OP_EQ; }
3513 		| NE		{ $$ = OP_NE; }
3514 		;
3515 
3516 binaryop	: '-'		{ $$ = OP_RANGE; }
3517 		| XRANGE	{ $$ = OP_XRANGE; }
3518 		;
3519 
3520 %%
3521 
3522 struct keywords {
3523 	const char	*k_name;
3524 	int		 k_val;
3525 };
3526 
3527 int
yyerror(const char * fmt,...)3528 yyerror(const char *fmt, ...)
3529 {
3530 	va_list		 ap;
3531 	char		*msg;
3532 
3533 	file->errors++;
3534 	va_start(ap, fmt);
3535 	if (vasprintf(&msg, fmt, ap) == -1)
3536 		fatalx("yyerror vasprintf");
3537 	va_end(ap);
3538 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
3539 	free(msg);
3540 	return (0);
3541 }
3542 
3543 int
kw_cmp(const void * k,const void * e)3544 kw_cmp(const void *k, const void *e)
3545 {
3546 	return (strcmp(k, ((const struct keywords *)e)->k_name));
3547 }
3548 
3549 int
lookup(char * s)3550 lookup(char *s)
3551 {
3552 	/* this has to be sorted always */
3553 	static const struct keywords keywords[] = {
3554 		{ "AS",			AS },
3555 		{ "EVPN",		EVPN },
3556 		{ "IPv4",		IPV4 },
3557 		{ "IPv6",		IPV6 },
3558 		{ "add-path",		ADDPATH },
3559 		{ "ah",			AH },
3560 		{ "allow",		ALLOW },
3561 		{ "announce",		ANNOUNCE },
3562 		{ "any",		ANY },
3563 		{ "as-4byte",		AS4BYTE },
3564 		{ "as-override",	ASOVERRIDE },
3565 		{ "as-set",		ASSET },
3566 		{ "aspa-set",		ASPASET },
3567 		{ "avs",		AVS },
3568 		{ "blackhole",		BLACKHOLE },
3569 		{ "community",		COMMUNITY },
3570 		{ "compare",		COMPARE },
3571 		{ "connect-retry",	CONNECTRETRY },
3572 		{ "connected",		CONNECTED },
3573 		{ "customer-as",	CUSTOMERAS },
3574 		{ "default-route",	DEFAULTROUTE },
3575 		{ "delete",		DELETE },
3576 		{ "demote",		DEMOTE },
3577 		{ "deny",		DENY },
3578 		{ "depend",		DEPEND },
3579 		{ "descr",		DESCR },
3580 		{ "down",		DOWN },
3581 		{ "dump",		DUMP },
3582 		{ "ebgp",		EBGP },
3583 		{ "enforce",		ENFORCE },
3584 		{ "enhanced",		ENHANCED },
3585 		{ "esp",		ESP },
3586 		{ "evaluate",		EVALUATE },
3587 		{ "expires",		EXPIRES },
3588 		{ "export",		EXPORT },
3589 		{ "export-target",	EXPORTTRGT },
3590 		{ "ext-community",	EXTCOMMUNITY },
3591 		{ "extended",		EXTENDED },
3592 		{ "fib-priority",	FIBPRIORITY },
3593 		{ "fib-update",		FIBUPDATE },
3594 		{ "filtered",		FILTERED },
3595 		{ "flags",		FLAGS },
3596 		{ "flowspec",		FLOWSPEC },
3597 		{ "fragment",		FRAGMENT },
3598 		{ "from",		FROM },
3599 		{ "graceful",		GRACEFUL },
3600 		{ "group",		GROUP },
3601 		{ "holdtime",		HOLDTIME },
3602 		{ "ibgp",		IBGP },
3603 		{ "ignore",		IGNORE },
3604 		{ "ike",		IKE },
3605 		{ "import-target",	IMPORTTRGT },
3606 		{ "in",			IN },
3607 		{ "include",		INCLUDE },
3608 		{ "inet",		IPV4 },
3609 		{ "inet6",		IPV6 },
3610 		{ "ipsec",		IPSEC },
3611 		{ "key",		KEY },
3612 		{ "large-community",	LARGECOMMUNITY },
3613 		{ "listen",		LISTEN },
3614 		{ "local-address",	LOCALADDR },
3615 		{ "local-as",		LOCALAS },
3616 		{ "localpref",		LOCALPREF },
3617 		{ "log",		LOG },
3618 		{ "match",		MATCH },
3619 		{ "max",		MAX },
3620 		{ "max-as-len",		MAXASLEN },
3621 		{ "max-as-seq",		MAXASSEQ },
3622 		{ "max-communities",	MAXCOMMUNITIES },
3623 		{ "max-ext-communities",	MAXEXTCOMMUNITIES },
3624 		{ "max-large-communities",	MAXLARGECOMMUNITIES },
3625 		{ "max-prefix",		MAXPREFIX },
3626 		{ "maxlen",		MAXLEN },
3627 		{ "md5sig",		MD5SIG },
3628 		{ "med",		MED },
3629 		{ "message",		MESSAGE },
3630 		{ "metric",		METRIC },
3631 		{ "min",		YMIN },
3632 		{ "min-version",	MINVERSION },
3633 		{ "multihop",		MULTIHOP },
3634 		{ "neighbor",		NEIGHBOR },
3635 		{ "neighbor-as",	NEIGHBORAS },
3636 		{ "network",		NETWORK },
3637 		{ "nexthop",		NEXTHOP },
3638 		{ "no-modify",		NOMODIFY },
3639 		{ "none",		NONE },
3640 		{ "notification",	NOTIFICATION },
3641 		{ "on",			ON },
3642 		{ "or-longer",		LONGER },
3643 		{ "origin",		ORIGIN },
3644 		{ "origin-set",		ORIGINSET },
3645 		{ "out",		OUT },
3646 		{ "ovs",		OVS },
3647 		{ "passive",		PASSIVE },
3648 		{ "password",		PASSWORD },
3649 		{ "peer-as",		PEERAS },
3650 		{ "pftable",		PFTABLE },
3651 		{ "plus",		PLUS },
3652 		{ "policy",		POLICY },
3653 		{ "port",		PORT },
3654 		{ "prefix",		PREFIX },
3655 		{ "prefix-set",		PREFIXSET },
3656 		{ "prefixlen",		PREFIXLEN },
3657 		{ "prepend-neighbor",	PREPEND_PEER },
3658 		{ "prepend-self",	PREPEND_SELF },
3659 		{ "priority",		PRIORITY },
3660 		{ "proto",		PROTO },
3661 		{ "provider-as",	PROVIDERAS },
3662 		{ "qualify",		QUALIFY },
3663 		{ "quick",		QUICK },
3664 		{ "rd",			RD },
3665 		{ "rde",		RDE },
3666 		{ "recv",		RECV },
3667 		{ "refresh",		REFRESH },
3668 		{ "reject",		REJECT },
3669 		{ "remote-as",		REMOTEAS },
3670 		{ "restart",		RESTART },
3671 		{ "restricted",		RESTRICTED },
3672 		{ "rib",		RIB },
3673 		{ "roa-set",		ROASET },
3674 		{ "role",		ROLE },
3675 		{ "route-reflector",	REFLECTOR },
3676 		{ "router-id",		ROUTERID },
3677 		{ "rtable",		RTABLE },
3678 		{ "rtlabel",		RTLABEL },
3679 		{ "rtr",		RTR },
3680 		{ "self",		SELF },
3681 		{ "send",		SEND },
3682 		{ "set",		SET },
3683 		{ "socket",		SOCKET },
3684 		{ "source-as",		SOURCEAS },
3685 		{ "spi",		SPI },
3686 		{ "staletime",		STALETIME },
3687 		{ "static",		STATIC },
3688 		{ "tcp",		TCP },
3689 		{ "to",			TO },
3690 		{ "tos",		TOS },
3691 		{ "transit-as",		TRANSITAS },
3692 		{ "transparent-as",	TRANSPARENT },
3693 		{ "ttl-security",	TTLSECURITY },
3694 		{ "unicast",		UNICAST },
3695 		{ "via",		VIA },
3696 		{ "vpn",		VPN },
3697 		{ "weight",		WEIGHT },
3698 	};
3699 	const struct keywords	*p;
3700 
3701 	p = bsearch(s, keywords, nitems(keywords), sizeof(keywords[0]), kw_cmp);
3702 
3703 	if (p)
3704 		return (p->k_val);
3705 	else
3706 		return (STRING);
3707 }
3708 
3709 #define START_EXPAND	1
3710 #define DONE_EXPAND	2
3711 
3712 static int	expanding;
3713 
3714 int
igetc(void)3715 igetc(void)
3716 {
3717 	int	c;
3718 
3719 	while (1) {
3720 		if (file->ungetpos > 0)
3721 			c = file->ungetbuf[--file->ungetpos];
3722 		else
3723 			c = getc(file->stream);
3724 
3725 		if (c == START_EXPAND)
3726 			expanding = 1;
3727 		else if (c == DONE_EXPAND)
3728 			expanding = 0;
3729 		else
3730 			break;
3731 	}
3732 	return (c);
3733 }
3734 
3735 int
lgetc(int quotec)3736 lgetc(int quotec)
3737 {
3738 	int		c, next;
3739 
3740 	if (quotec) {
3741 		if ((c = igetc()) == EOF) {
3742 			yyerror("reached end of file while parsing "
3743 			    "quoted string");
3744 			if (file == topfile || popfile() == EOF)
3745 				return (EOF);
3746 			return (quotec);
3747 		}
3748 		return (c);
3749 	}
3750 
3751 	while ((c = igetc()) == '\\') {
3752 		next = igetc();
3753 		if (next != '\n') {
3754 			c = next;
3755 			break;
3756 		}
3757 		yylval.lineno = file->lineno;
3758 		file->lineno++;
3759 	}
3760 
3761 	if (c == EOF) {
3762 		/*
3763 		 * Fake EOL when hit EOF for the first time. This gets line
3764 		 * count right if last line in included file is syntactically
3765 		 * invalid and has no newline.
3766 		 */
3767 		if (file->eof_reached == 0) {
3768 			file->eof_reached = 1;
3769 			return ('\n');
3770 		}
3771 		while (c == EOF) {
3772 			if (file == topfile || popfile() == EOF)
3773 				return (EOF);
3774 			c = igetc();
3775 		}
3776 	}
3777 	return (c);
3778 }
3779 
3780 void
lungetc(int c)3781 lungetc(int c)
3782 {
3783 	if (c == EOF)
3784 		return;
3785 
3786 	if (file->ungetpos >= file->ungetsize) {
3787 		void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
3788 		if (p == NULL)
3789 			err(1, "lungetc");
3790 		file->ungetbuf = p;
3791 		file->ungetsize *= 2;
3792 	}
3793 	file->ungetbuf[file->ungetpos++] = c;
3794 }
3795 
3796 int
findeol(void)3797 findeol(void)
3798 {
3799 	int	c;
3800 
3801 	/* skip to either EOF or the first real EOL */
3802 	while (1) {
3803 		c = lgetc(0);
3804 		if (c == '\n') {
3805 			file->lineno++;
3806 			break;
3807 		}
3808 		if (c == EOF)
3809 			break;
3810 	}
3811 	return (ERROR);
3812 }
3813 
3814 int
expand_macro(void)3815 expand_macro(void)
3816 {
3817 	char	 buf[MACRO_NAME_LEN];
3818 	char	*p, *val;
3819 	int	 c;
3820 
3821 	p = buf;
3822 	while (1) {
3823 		if ((c = lgetc('$')) == EOF)
3824 			return (ERROR);
3825 		if (p + 1 >= buf + sizeof(buf) - 1) {
3826 			yyerror("macro name too long");
3827 			return (ERROR);
3828 		}
3829 		if (isalnum(c) || c == '_') {
3830 			*p++ = c;
3831 			continue;
3832 		}
3833 		*p = '\0';
3834 		lungetc(c);
3835 		break;
3836 	}
3837 	val = symget(buf);
3838 	if (val == NULL) {
3839 		yyerror("macro '%s' not defined", buf);
3840 		return (ERROR);
3841 	}
3842 	p = val + strlen(val) - 1;
3843 	lungetc(DONE_EXPAND);
3844 	while (p >= val) {
3845 		lungetc((unsigned char)*p);
3846 		p--;
3847 	}
3848 	lungetc(START_EXPAND);
3849 	return (0);
3850 }
3851 
3852 int
yylex(void)3853 yylex(void)
3854 {
3855 	char	 buf[8096];
3856 	char	*p;
3857 	int	 quotec, next, c;
3858 	int	 token;
3859 
3860 top:
3861 	p = buf;
3862 	while ((c = lgetc(0)) == ' ' || c == '\t')
3863 		; /* nothing */
3864 
3865 	yylval.lineno = file->lineno;
3866 	if (c == '#')
3867 		while ((c = lgetc(0)) != '\n' && c != EOF)
3868 			; /* nothing */
3869 	if (c == '$' && !expanding) {
3870 		c = expand_macro();
3871 		if (c != 0)
3872 			return (c);
3873 		goto top;
3874 	}
3875 
3876 	switch (c) {
3877 	case '\'':
3878 	case '"':
3879 		quotec = c;
3880 		while (1) {
3881 			if ((c = lgetc(quotec)) == EOF)
3882 				return (0);
3883 			if (c == '\n') {
3884 				file->lineno++;
3885 				continue;
3886 			} else if (c == '\\') {
3887 				if ((next = lgetc(quotec)) == EOF)
3888 					return (0);
3889 				if (next == quotec || next == ' ' ||
3890 				    next == '\t')
3891 					c = next;
3892 				else if (next == '\n') {
3893 					file->lineno++;
3894 					continue;
3895 				} else
3896 					lungetc(next);
3897 			} else if (c == quotec) {
3898 				*p = '\0';
3899 				break;
3900 			} else if (c == '\0') {
3901 				yyerror("syntax error: unterminated quote");
3902 				return (findeol());
3903 			}
3904 			if (p + 1 >= buf + sizeof(buf) - 1) {
3905 				yyerror("string too long");
3906 				return (findeol());
3907 			}
3908 			*p++ = c;
3909 		}
3910 		yylval.v.string = strdup(buf);
3911 		if (yylval.v.string == NULL)
3912 			fatal("yylex: strdup");
3913 		return (STRING);
3914 	case '!':
3915 		next = lgetc(0);
3916 		if (next == '=')
3917 			return (NE);
3918 		lungetc(next);
3919 		break;
3920 	case '<':
3921 		next = lgetc(0);
3922 		if (next == '=')
3923 			return (LE);
3924 		lungetc(next);
3925 		break;
3926 	case '>':
3927 		next = lgetc(0);
3928 		if (next == '<')
3929 			return (XRANGE);
3930 		else if (next == '=')
3931 			return (GE);
3932 		lungetc(next);
3933 		break;
3934 	}
3935 
3936 #define allowed_to_end_number(x) \
3937 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
3938 
3939 	if (c == '-' || isdigit(c)) {
3940 		do {
3941 			*p++ = c;
3942 			if ((size_t)(p-buf) >= sizeof(buf)) {
3943 				yyerror("string too long");
3944 				return (findeol());
3945 			}
3946 		} while ((c = lgetc(0)) != EOF && isdigit(c));
3947 		lungetc(c);
3948 		if (p == buf + 1 && buf[0] == '-')
3949 			goto nodigits;
3950 		if (c == EOF || allowed_to_end_number(c)) {
3951 			const char *errstr = NULL;
3952 
3953 			*p = '\0';
3954 			yylval.v.number = strtonum(buf, LLONG_MIN,
3955 			    LLONG_MAX, &errstr);
3956 			if (errstr) {
3957 				yyerror("\"%s\" invalid number: %s",
3958 				    buf, errstr);
3959 				return (findeol());
3960 			}
3961 			return (NUMBER);
3962 		} else {
3963 nodigits:
3964 			while (p > buf + 1)
3965 				lungetc((unsigned char)*--p);
3966 			c = (unsigned char)*--p;
3967 			if (c == '-')
3968 				return (c);
3969 		}
3970 	}
3971 
3972 #define allowed_in_string(x) \
3973 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
3974 	x != '{' && x != '}' && x != '<' && x != '>' && \
3975 	x != '!' && x != '=' && x != '/' && x != '#' && \
3976 	x != ','))
3977 
3978 	if (isalnum(c) || c == ':' || c == '_' || c == '*') {
3979 		do {
3980 			if (c == '$' && !expanding) {
3981 				c = expand_macro();
3982 				if (c != 0)
3983 					return (c);
3984 			} else
3985 				*p++ = c;
3986 
3987 			if ((size_t)(p-buf) >= sizeof(buf)) {
3988 				yyerror("string too long");
3989 				return (findeol());
3990 			}
3991 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
3992 		lungetc(c);
3993 		*p = '\0';
3994 		if ((token = lookup(buf)) == STRING)
3995 			if ((yylval.v.string = strdup(buf)) == NULL)
3996 				fatal("yylex: strdup");
3997 		return (token);
3998 	}
3999 	if (c == '\n') {
4000 		yylval.lineno = file->lineno;
4001 		file->lineno++;
4002 	}
4003 	if (c == EOF)
4004 		return (0);
4005 	return (c);
4006 }
4007 
4008 int
check_file_secrecy(int fd,const char * fname)4009 check_file_secrecy(int fd, const char *fname)
4010 {
4011 	struct stat	st;
4012 
4013 	if (fstat(fd, &st)) {
4014 		log_warn("cannot stat %s", fname);
4015 		return (-1);
4016 	}
4017 	return (0);
4018 }
4019 
4020 struct file *
pushfile(const char * name,int secret)4021 pushfile(const char *name, int secret)
4022 {
4023 	struct file	*nfile;
4024 
4025 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
4026 		log_warn("%s", __func__);
4027 		return (NULL);
4028 	}
4029 	if ((nfile->name = strdup(name)) == NULL) {
4030 		log_warn("%s", __func__);
4031 		free(nfile);
4032 		return (NULL);
4033 	}
4034 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
4035 		log_warn("%s: %s", __func__, nfile->name);
4036 		free(nfile->name);
4037 		free(nfile);
4038 		return (NULL);
4039 	}
4040 	if (secret &&
4041 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
4042 		fclose(nfile->stream);
4043 		free(nfile->name);
4044 		free(nfile);
4045 		return (NULL);
4046 	}
4047 	nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
4048 	nfile->ungetsize = 16;
4049 	nfile->ungetbuf = malloc(nfile->ungetsize);
4050 	if (nfile->ungetbuf == NULL) {
4051 		log_warn("%s", __func__);
4052 		fclose(nfile->stream);
4053 		free(nfile->name);
4054 		free(nfile);
4055 		return (NULL);
4056 	}
4057 	TAILQ_INSERT_TAIL(&files, nfile, entry);
4058 	return (nfile);
4059 }
4060 
4061 int
popfile(void)4062 popfile(void)
4063 {
4064 	struct file	*prev;
4065 
4066 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
4067 		prev->errors += file->errors;
4068 
4069 	TAILQ_REMOVE(&files, file, entry);
4070 	fclose(file->stream);
4071 	free(file->name);
4072 	free(file->ungetbuf);
4073 	free(file);
4074 	file = prev;
4075 	return (file ? 0 : EOF);
4076 }
4077 
4078 static void
init_config(struct bgpd_config * c)4079 init_config(struct bgpd_config *c)
4080 {
4081 	u_int rdomid;
4082 
4083 	c->min_holdtime = MIN_HOLDTIME;
4084 	c->holdtime = INTERVAL_HOLD;
4085 	c->staletime = INTERVAL_STALE;
4086 	c->connectretry = INTERVAL_CONNECTRETRY;
4087 	c->bgpid = get_bgpid();
4088 	c->fib_priority = kr_default_prio();
4089 	c->default_tableid = getrtable();
4090 	if (!ktable_exists(c->default_tableid, &rdomid))
4091 		fatalx("current routing table %u does not exist",
4092 		    c->default_tableid);
4093 	if (rdomid != c->default_tableid)
4094 		fatalx("current routing table %u is not a routing domain",
4095 		    c->default_tableid);
4096 
4097 	if (asprintf(&c->csock, "%s.%d", SOCKET_NAME, c->default_tableid) == -1)
4098 		fatal(NULL);
4099 }
4100 
4101 struct bgpd_config *
parse_config(char * filename,struct peer_head * ph,struct rtr_config_head * rh)4102 parse_config(char *filename, struct peer_head *ph, struct rtr_config_head *rh)
4103 {
4104 	struct sym		*sym, *next;
4105 	struct rde_rib		*rr;
4106 	struct network		*n;
4107 	int			 errors = 0;
4108 
4109 	conf = new_config();
4110 	init_config(conf);
4111 
4112 	if ((filter_l = calloc(1, sizeof(struct filter_head))) == NULL)
4113 		fatal(NULL);
4114 	if ((peerfilter_l = calloc(1, sizeof(struct filter_head))) == NULL)
4115 		fatal(NULL);
4116 	if ((groupfilter_l = calloc(1, sizeof(struct filter_head))) == NULL)
4117 		fatal(NULL);
4118 	TAILQ_INIT(filter_l);
4119 	TAILQ_INIT(peerfilter_l);
4120 	TAILQ_INIT(groupfilter_l);
4121 
4122 	curpeer = NULL;
4123 	curgroup = NULL;
4124 
4125 	cur_peers = ph;
4126 	cur_rtrs = rh;
4127 	new_peers = &conf->peers;
4128 	netconf = &conf->networks;
4129 
4130 	if ((rr = add_rib("Adj-RIB-In")) == NULL)
4131 		fatal("add_rib failed");
4132 	rr->flags = F_RIB_NOFIB | F_RIB_NOEVALUATE;
4133 	if ((rr = add_rib("Loc-RIB")) == NULL)
4134 		fatal("add_rib failed");
4135 	rib_add_fib(rr, conf->default_tableid);
4136 	rr->flags = F_RIB_LOCAL;
4137 
4138 	if ((file = pushfile(filename, 1)) == NULL)
4139 		goto errors;
4140 	topfile = file;
4141 
4142 	yyparse();
4143 	errors = file->errors;
4144 	popfile();
4145 
4146 	/* check that we dont try to announce our own routes */
4147 	TAILQ_FOREACH(n, netconf, entry)
4148 	    if (n->net.priority == conf->fib_priority) {
4149 		    errors++;
4150 		    logit(LOG_CRIT, "network priority %d == fib-priority "
4151 			"%d is not allowed.",
4152 			n->net.priority, conf->fib_priority);
4153 	    }
4154 
4155 	/* Free macros and check which have not been used. */
4156 	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
4157 		if ((cmd_opts & BGPD_OPT_VERBOSE2) && !sym->used)
4158 			fprintf(stderr, "warning: macro \"%s\" not "
4159 			    "used\n", sym->nam);
4160 		if (!sym->persist) {
4161 			free(sym->nam);
4162 			free(sym->val);
4163 			TAILQ_REMOVE(&symhead, sym, entry);
4164 			free(sym);
4165 		}
4166 	}
4167 
4168 	if (!conf->as) {
4169 		log_warnx("configuration error: AS not given");
4170 		errors++;
4171 	}
4172 
4173 	/* clear the globals */
4174 	curpeer = NULL;
4175 	curgroup = NULL;
4176 	cur_peers = NULL;
4177 	new_peers = NULL;
4178 	netconf = NULL;
4179 	curflow = NULL;
4180 
4181 	if (errors) {
4182 errors:
4183 		while ((rr = SIMPLEQ_FIRST(&ribnames)) != NULL) {
4184 			SIMPLEQ_REMOVE_HEAD(&ribnames, entry);
4185 			free(rr);
4186 		}
4187 
4188 		filterlist_free(filter_l);
4189 		filterlist_free(peerfilter_l);
4190 		filterlist_free(groupfilter_l);
4191 
4192 		free_config(conf);
4193 		return (NULL);
4194 	}
4195 
4196 	/* Create default listeners if none where specified. */
4197 	if (TAILQ_EMPTY(conf->listen_addrs)) {
4198 		struct listen_addr *la;
4199 
4200 		if ((la = calloc(1, sizeof(struct listen_addr))) == NULL)
4201 			fatal("setup_listeners calloc");
4202 		la->fd = -1;
4203 		la->flags = DEFAULT_LISTENER;
4204 		la->reconf = RECONF_REINIT;
4205 		la->sa_len = sizeof(struct sockaddr_in);
4206 		((struct sockaddr_in *)&la->sa)->sin_family = AF_INET;
4207 		((struct sockaddr_in *)&la->sa)->sin_addr.s_addr =
4208 		    htonl(INADDR_ANY);
4209 		((struct sockaddr_in *)&la->sa)->sin_port = htons(BGP_PORT);
4210 		TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry);
4211 
4212 		if ((la = calloc(1, sizeof(struct listen_addr))) == NULL)
4213 			fatal("setup_listeners calloc");
4214 		la->fd = -1;
4215 		la->flags = DEFAULT_LISTENER;
4216 		la->reconf = RECONF_REINIT;
4217 		la->sa_len = sizeof(struct sockaddr_in6);
4218 		((struct sockaddr_in6 *)&la->sa)->sin6_family = AF_INET6;
4219 		((struct sockaddr_in6 *)&la->sa)->sin6_port = htons(BGP_PORT);
4220 		TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry);
4221 	}
4222 
4223 	/* update clusterid in case it was not set explicitly */
4224 	if ((conf->flags & BGPD_FLAG_REFLECTOR) && conf->clusterid == 0)
4225 		conf->clusterid = conf->bgpid;
4226 
4227 	/*
4228 	 * Concatenate filter list and static group and peer filtersets
4229 	 * together. Static group sets come first then peer sets
4230 	 * last normal filter rules.
4231 	 */
4232 	TAILQ_CONCAT(conf->filters, groupfilter_l, entry);
4233 	TAILQ_CONCAT(conf->filters, peerfilter_l, entry);
4234 	TAILQ_CONCAT(conf->filters, filter_l, entry);
4235 
4236 	optimize_filters(conf->filters);
4237 
4238 	free(filter_l);
4239 	free(peerfilter_l);
4240 	free(groupfilter_l);
4241 
4242 	return (conf);
4243 }
4244 
4245 int
symset(const char * nam,const char * val,int persist)4246 symset(const char *nam, const char *val, int persist)
4247 {
4248 	struct sym	*sym;
4249 
4250 	TAILQ_FOREACH(sym, &symhead, entry) {
4251 		if (strcmp(nam, sym->nam) == 0)
4252 			break;
4253 	}
4254 
4255 	if (sym != NULL) {
4256 		if (sym->persist == 1)
4257 			return (0);
4258 		else {
4259 			free(sym->nam);
4260 			free(sym->val);
4261 			TAILQ_REMOVE(&symhead, sym, entry);
4262 			free(sym);
4263 		}
4264 	}
4265 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
4266 		return (-1);
4267 
4268 	sym->nam = strdup(nam);
4269 	if (sym->nam == NULL) {
4270 		free(sym);
4271 		return (-1);
4272 	}
4273 	sym->val = strdup(val);
4274 	if (sym->val == NULL) {
4275 		free(sym->nam);
4276 		free(sym);
4277 		return (-1);
4278 	}
4279 	sym->used = 0;
4280 	sym->persist = persist;
4281 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
4282 	return (0);
4283 }
4284 
4285 int
cmdline_symset(char * s)4286 cmdline_symset(char *s)
4287 {
4288 	char	*sym, *val;
4289 	int	ret;
4290 
4291 	if ((val = strrchr(s, '=')) == NULL)
4292 		return (-1);
4293 	sym = strndup(s, val - s);
4294 	if (sym == NULL)
4295 		fatal("%s: strndup", __func__);
4296 	ret = symset(sym, val + 1, 1);
4297 	free(sym);
4298 
4299 	return (ret);
4300 }
4301 
4302 char *
symget(const char * nam)4303 symget(const char *nam)
4304 {
4305 	struct sym	*sym;
4306 
4307 	TAILQ_FOREACH(sym, &symhead, entry) {
4308 		if (strcmp(nam, sym->nam) == 0) {
4309 			sym->used = 1;
4310 			return (sym->val);
4311 		}
4312 	}
4313 	return (NULL);
4314 }
4315 
4316 static int
cmpcommunity(struct community * a,struct community * b)4317 cmpcommunity(struct community *a, struct community *b)
4318 {
4319 	if (a->flags > b->flags)
4320 		return 1;
4321 	if (a->flags < b->flags)
4322 		return -1;
4323 	if (a->data1 > b->data1)
4324 		return 1;
4325 	if (a->data1 < b->data1)
4326 		return -1;
4327 	if (a->data2 > b->data2)
4328 		return 1;
4329 	if (a->data2 < b->data2)
4330 		return -1;
4331 	if (a->data3 > b->data3)
4332 		return 1;
4333 	if (a->data3 < b->data3)
4334 		return -1;
4335 	return 0;
4336 }
4337 
4338 static int
getcommunity(char * s,int large,uint32_t * val,uint32_t * flag)4339 getcommunity(char *s, int large, uint32_t *val, uint32_t *flag)
4340 {
4341 	long long	 max = USHRT_MAX;
4342 	const char	*errstr;
4343 
4344 	*flag = 0;
4345 	*val = 0;
4346 	if (strcmp(s, "*") == 0) {
4347 		*flag = COMMUNITY_ANY;
4348 		return 0;
4349 	} else if (strcmp(s, "neighbor-as") == 0) {
4350 		*flag = COMMUNITY_NEIGHBOR_AS;
4351 		return 0;
4352 	} else if (strcmp(s, "local-as") == 0) {
4353 		*flag = COMMUNITY_LOCAL_AS;
4354 		return 0;
4355 	}
4356 	if (large)
4357 		max = UINT_MAX;
4358 	*val = strtonum(s, 0, max, &errstr);
4359 	if (errstr) {
4360 		yyerror("Community %s is %s (max: %lld)", s, errstr, max);
4361 		return -1;
4362 	}
4363 	return 0;
4364 }
4365 
4366 static void
setcommunity(struct community * c,uint32_t as,uint32_t data,uint32_t asflag,uint32_t dataflag)4367 setcommunity(struct community *c, uint32_t as, uint32_t data,
4368     uint32_t asflag, uint32_t dataflag)
4369 {
4370 	c->flags = COMMUNITY_TYPE_BASIC;
4371 	c->flags |= asflag << 8;
4372 	c->flags |= dataflag << 16;
4373 	c->data1 = as;
4374 	c->data2 = data;
4375 	c->data3 = 0;
4376 }
4377 
4378 static int
parselargecommunity(struct community * c,char * s)4379 parselargecommunity(struct community *c, char *s)
4380 {
4381 	char *p, *q;
4382 	uint32_t dflag1, dflag2, dflag3;
4383 
4384 	if ((p = strchr(s, ':')) == NULL) {
4385 		yyerror("Bad community syntax");
4386 		return (-1);
4387 	}
4388 	*p++ = 0;
4389 
4390 	if ((q = strchr(p, ':')) == NULL) {
4391 		yyerror("Bad community syntax");
4392 		return (-1);
4393 	}
4394 	*q++ = 0;
4395 
4396 	if (getcommunity(s, 1, &c->data1, &dflag1) == -1 ||
4397 	    getcommunity(p, 1, &c->data2, &dflag2) == -1 ||
4398 	    getcommunity(q, 1, &c->data3, &dflag3) == -1)
4399 		return (-1);
4400 	c->flags = COMMUNITY_TYPE_LARGE;
4401 	c->flags |= dflag1 << 8;
4402 	c->flags |= dflag2 << 16;
4403 	c->flags |= dflag3 << 24;
4404 	return (0);
4405 }
4406 
4407 int
parsecommunity(struct community * c,int type,char * s)4408 parsecommunity(struct community *c, int type, char *s)
4409 {
4410 	char *p;
4411 	uint32_t as, data, asflag, dataflag;
4412 
4413 	if (type == COMMUNITY_TYPE_LARGE)
4414 		return parselargecommunity(c, s);
4415 
4416 	/* Well-known communities */
4417 	if (strcasecmp(s, "GRACEFUL_SHUTDOWN") == 0) {
4418 		setcommunity(c, COMMUNITY_WELLKNOWN,
4419 		    COMMUNITY_GRACEFUL_SHUTDOWN, 0, 0);
4420 		return (0);
4421 	} else if (strcasecmp(s, "NO_EXPORT") == 0) {
4422 		setcommunity(c, COMMUNITY_WELLKNOWN,
4423 		    COMMUNITY_NO_EXPORT, 0, 0);
4424 		return (0);
4425 	} else if (strcasecmp(s, "NO_ADVERTISE") == 0) {
4426 		setcommunity(c, COMMUNITY_WELLKNOWN,
4427 		    COMMUNITY_NO_ADVERTISE, 0, 0);
4428 		return (0);
4429 	} else if (strcasecmp(s, "NO_EXPORT_SUBCONFED") == 0) {
4430 		setcommunity(c, COMMUNITY_WELLKNOWN,
4431 		    COMMUNITY_NO_EXPSUBCONFED, 0, 0);
4432 		return (0);
4433 	} else if (strcasecmp(s, "NO_PEER") == 0) {
4434 		setcommunity(c, COMMUNITY_WELLKNOWN,
4435 		    COMMUNITY_NO_PEER, 0, 0);
4436 		return (0);
4437 	} else if (strcasecmp(s, "BLACKHOLE") == 0) {
4438 		setcommunity(c, COMMUNITY_WELLKNOWN,
4439 		    COMMUNITY_BLACKHOLE, 0, 0);
4440 		return (0);
4441 	}
4442 
4443 	if ((p = strchr(s, ':')) == NULL) {
4444 		yyerror("Bad community syntax");
4445 		return (-1);
4446 	}
4447 	*p++ = 0;
4448 
4449 	if (getcommunity(s, 0, &as, &asflag) == -1 ||
4450 	    getcommunity(p, 0, &data, &dataflag) == -1)
4451 		return (-1);
4452 	setcommunity(c, as, data, asflag, dataflag);
4453 	return (0);
4454 }
4455 
4456 static int
parsesubtype(char * name,int * type,int * subtype)4457 parsesubtype(char *name, int *type, int *subtype)
4458 {
4459 	const struct ext_comm_pairs *cp;
4460 	int found = 0;
4461 
4462 	for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
4463 		if (strcmp(name, cp->subname) == 0) {
4464 			if (found == 0) {
4465 				*type = cp->type;
4466 				*subtype = cp->subtype;
4467 			}
4468 			found++;
4469 		}
4470 	}
4471 	if (found > 1)
4472 		*type = -1;
4473 	return (found);
4474 }
4475 
4476 static int
parseextvalue(int type,char * s,uint32_t * v,uint32_t * flag)4477 parseextvalue(int type, char *s, uint32_t *v, uint32_t *flag)
4478 {
4479 	const char	*errstr;
4480 	char		*p;
4481 	struct in_addr	 ip;
4482 	uint32_t	 uvalh, uval;
4483 
4484 	if (type != -1) {
4485 		/* nothing */
4486 	} else if (strcmp(s, "neighbor-as") == 0) {
4487 		*flag = COMMUNITY_NEIGHBOR_AS;
4488 		*v = 0;
4489 		return EXT_COMMUNITY_TRANS_TWO_AS;
4490 	} else if (strcmp(s, "local-as") == 0) {
4491 		*flag = COMMUNITY_LOCAL_AS;
4492 		*v = 0;
4493 		return EXT_COMMUNITY_TRANS_TWO_AS;
4494 	} else if ((p = strchr(s, '.')) == NULL) {
4495 		/* AS_PLAIN number (4 or 2 byte) */
4496 		strtonum(s, 0, USHRT_MAX, &errstr);
4497 		if (errstr == NULL)
4498 			type = EXT_COMMUNITY_TRANS_TWO_AS;
4499 		else
4500 			type = EXT_COMMUNITY_TRANS_FOUR_AS;
4501 	} else if (strchr(p + 1, '.') == NULL) {
4502 		/* AS_DOT number (4-byte) */
4503 		type = EXT_COMMUNITY_TRANS_FOUR_AS;
4504 	} else {
4505 		/* more than one dot -> IP address */
4506 		type = EXT_COMMUNITY_TRANS_IPV4;
4507 	}
4508 
4509 	switch (type & EXT_COMMUNITY_VALUE) {
4510 	case EXT_COMMUNITY_TRANS_TWO_AS:
4511 		uval = strtonum(s, 0, USHRT_MAX, &errstr);
4512 		if (errstr) {
4513 			yyerror("Bad ext-community %s is %s", s, errstr);
4514 			return (-1);
4515 		}
4516 		*v = uval;
4517 		break;
4518 	case EXT_COMMUNITY_TRANS_FOUR_AS:
4519 		if ((p = strchr(s, '.')) == NULL) {
4520 			uval = strtonum(s, 0, UINT_MAX, &errstr);
4521 			if (errstr) {
4522 				yyerror("Bad ext-community %s is %s", s,
4523 				    errstr);
4524 				return (-1);
4525 			}
4526 			*v = uval;
4527 			break;
4528 		}
4529 		*p++ = '\0';
4530 		uvalh = strtonum(s, 0, USHRT_MAX, &errstr);
4531 		if (errstr) {
4532 			yyerror("Bad ext-community %s is %s", s, errstr);
4533 			return (-1);
4534 		}
4535 		uval = strtonum(p, 0, USHRT_MAX, &errstr);
4536 		if (errstr) {
4537 			yyerror("Bad ext-community %s is %s", p, errstr);
4538 			return (-1);
4539 		}
4540 		*v = uval | (uvalh << 16);
4541 		break;
4542 	case EXT_COMMUNITY_TRANS_IPV4:
4543 		if (inet_pton(AF_INET, s, &ip) != 1) {
4544 			yyerror("Bad ext-community %s not parseable", s);
4545 			return (-1);
4546 		}
4547 		*v = ntohl(ip.s_addr);
4548 		break;
4549 	default:
4550 		fatalx("%s: unexpected type %d", __func__, type);
4551 	}
4552 	return (type);
4553 }
4554 
4555 int
parseextcommunity(struct community * c,char * t,char * s)4556 parseextcommunity(struct community *c, char *t, char *s)
4557 {
4558 	const struct ext_comm_pairs *cp;
4559 	char		*p, *ep;
4560 	uint64_t	 ullval;
4561 	uint32_t	 uval, uval2, dflag1 = 0, dflag2 = 0;
4562 	int		 type = 0, subtype = 0;
4563 
4564 	if (strcmp(t, "*") == 0 && strcmp(s, "*") == 0) {
4565 		c->flags = COMMUNITY_TYPE_EXT;
4566 		c->flags |= COMMUNITY_ANY << 24;
4567 		return (0);
4568 	}
4569 	if (parsesubtype(t, &type, &subtype) == 0) {
4570 		yyerror("Bad ext-community unknown type");
4571 		return (-1);
4572 	}
4573 
4574 	switch (type) {
4575 	case EXT_COMMUNITY_TRANS_TWO_AS:
4576 	case EXT_COMMUNITY_TRANS_FOUR_AS:
4577 	case EXT_COMMUNITY_TRANS_IPV4:
4578 	case EXT_COMMUNITY_GEN_TWO_AS:
4579 	case EXT_COMMUNITY_GEN_FOUR_AS:
4580 	case EXT_COMMUNITY_GEN_IPV4:
4581 	case -1:
4582 		if (strcmp(s, "*") == 0) {
4583 			dflag1 = COMMUNITY_ANY;
4584 			break;
4585 		}
4586 		if ((p = strchr(s, ':')) == NULL) {
4587 			yyerror("Bad ext-community %s", s);
4588 			return (-1);
4589 		}
4590 		*p++ = '\0';
4591 		if ((type = parseextvalue(type, s, &uval, &dflag1)) == -1)
4592 			return (-1);
4593 
4594 		switch (type) {
4595 		case EXT_COMMUNITY_TRANS_TWO_AS:
4596 		case EXT_COMMUNITY_GEN_TWO_AS:
4597 			if (getcommunity(p, 1, &uval2, &dflag2) == -1)
4598 				return (-1);
4599 			break;
4600 		case EXT_COMMUNITY_TRANS_IPV4:
4601 		case EXT_COMMUNITY_TRANS_FOUR_AS:
4602 		case EXT_COMMUNITY_GEN_IPV4:
4603 		case EXT_COMMUNITY_GEN_FOUR_AS:
4604 			if (getcommunity(p, 0, &uval2, &dflag2) == -1)
4605 				return (-1);
4606 			break;
4607 		default:
4608 			fatalx("parseextcommunity: unexpected result");
4609 		}
4610 
4611 		c->data1 = uval;
4612 		c->data2 = uval2;
4613 		break;
4614 	case EXT_COMMUNITY_TRANS_OPAQUE:
4615 	case EXT_COMMUNITY_TRANS_EVPN:
4616 		if (strcmp(s, "*") == 0) {
4617 			dflag1 = COMMUNITY_ANY;
4618 			break;
4619 		}
4620 		errno = 0;
4621 		ullval = strtoull(s, &ep, 0);
4622 		if (s[0] == '\0' || *ep != '\0') {
4623 			yyerror("Bad ext-community bad value");
4624 			return (-1);
4625 		}
4626 		if (errno == ERANGE && ullval > EXT_COMMUNITY_OPAQUE_MAX) {
4627 			yyerror("Bad ext-community value too big");
4628 			return (-1);
4629 		}
4630 		c->data1 = ullval >> 32;
4631 		c->data2 = ullval;
4632 		break;
4633 	case EXT_COMMUNITY_NON_TRANS_OPAQUE:
4634 		if (subtype == EXT_COMMUNITY_SUBTYPE_OVS) {
4635 			if (strcmp(s, "valid") == 0) {
4636 				c->data2 = EXT_COMMUNITY_OVS_VALID;
4637 				break;
4638 			} else if (strcmp(s, "invalid") == 0) {
4639 				c->data2 = EXT_COMMUNITY_OVS_INVALID;
4640 				break;
4641 			} else if (strcmp(s, "not-found") == 0) {
4642 				c->data2 = EXT_COMMUNITY_OVS_NOTFOUND;
4643 				break;
4644 			} else if (strcmp(s, "*") == 0) {
4645 				dflag1 = COMMUNITY_ANY;
4646 				break;
4647 			}
4648 		}
4649 		yyerror("Bad ext-community %s", s);
4650 		return (-1);
4651 	}
4652 
4653 	c->data3 = type << 8 | subtype;
4654 
4655 	/* special handling of ext-community rt * since type is not known */
4656 	if (dflag1 == COMMUNITY_ANY && type == -1) {
4657 		c->flags = COMMUNITY_TYPE_EXT;
4658 		c->flags |= dflag1 << 8;
4659 		return (0);
4660 	}
4661 
4662 	/* verify type/subtype combo */
4663 	for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
4664 		if (cp->type == type && cp->subtype == subtype) {
4665 			c->flags = COMMUNITY_TYPE_EXT;
4666 			c->flags |= dflag1 << 8;
4667 			c->flags |= dflag2 << 16;
4668 			return (0);
4669 		}
4670 	}
4671 
4672 	yyerror("Bad ext-community bad format for type");
4673 	return (-1);
4674 }
4675 
4676 struct peer *
alloc_peer(void)4677 alloc_peer(void)
4678 {
4679 	struct peer	*p;
4680 
4681 	if ((p = calloc(1, sizeof(struct peer))) == NULL)
4682 		fatal("new_peer");
4683 
4684 	/* some sane defaults */
4685 	p->state = STATE_NONE;
4686 	p->reconf_action = RECONF_REINIT;
4687 	p->conf.distance = 1;
4688 	p->conf.export_type = EXPORT_UNSET;
4689 	p->conf.capabilities.refresh = 1;
4690 	p->conf.capabilities.grestart.restart = 1;
4691 	p->conf.capabilities.as4byte = 1;
4692 	p->conf.capabilities.policy = 1;
4693 	p->conf.local_as = conf->as;
4694 	p->conf.local_short_as = conf->short_as;
4695 	p->conf.remote_port = BGP_PORT;
4696 
4697 	if (conf->flags & BGPD_FLAG_DECISION_TRANS_AS)
4698 		p->conf.flags |= PEERFLAG_TRANS_AS;
4699 	if (conf->flags & BGPD_FLAG_DECISION_ALL_PATHS)
4700 		p->conf.flags |= PEERFLAG_EVALUATE_ALL;
4701 	if (conf->flags & BGPD_FLAG_PERMIT_AS_SET)
4702 		p->conf.flags |= PEERFLAG_PERMIT_AS_SET;
4703 
4704 	return (p);
4705 }
4706 
4707 struct peer *
new_peer(void)4708 new_peer(void)
4709 {
4710 	struct peer		*p;
4711 
4712 	p = alloc_peer();
4713 
4714 	if (curgroup != NULL) {
4715 		p->conf = curgroup->conf;
4716 		p->auth_conf = curgroup->auth_conf;
4717 		p->conf.groupid = curgroup->conf.id;
4718 	}
4719 	return (p);
4720 }
4721 
4722 struct peer *
new_group(void)4723 new_group(void)
4724 {
4725 	return (alloc_peer());
4726 }
4727 
4728 int
add_mrtconfig(enum mrt_type type,char * name,int timeout,struct peer * p,char * rib)4729 add_mrtconfig(enum mrt_type type, char *name, int timeout, struct peer *p,
4730     char *rib)
4731 {
4732 	struct mrt	*m, *n;
4733 
4734 	LIST_FOREACH(m, conf->mrt, entry) {
4735 		if ((rib && strcmp(rib, m->rib)) ||
4736 		    (!rib && *m->rib))
4737 			continue;
4738 		if (p == NULL) {
4739 			if (m->peer_id != 0 || m->group_id != 0)
4740 				continue;
4741 		} else {
4742 			if (m->peer_id != p->conf.id ||
4743 			    m->group_id != p->conf.groupid)
4744 				continue;
4745 		}
4746 		if (m->type == type) {
4747 			yyerror("only one mrtdump per type allowed.");
4748 			return (-1);
4749 		}
4750 	}
4751 
4752 	if ((n = calloc(1, sizeof(struct mrt_config))) == NULL)
4753 		fatal("add_mrtconfig");
4754 
4755 	n->type = type;
4756 	n->state = MRT_STATE_OPEN;
4757 	if (strlcpy(MRT2MC(n)->name, name, sizeof(MRT2MC(n)->name)) >=
4758 	    sizeof(MRT2MC(n)->name)) {
4759 		yyerror("filename \"%s\" too long: max %zu",
4760 		    name, sizeof(MRT2MC(n)->name) - 1);
4761 		free(n);
4762 		return (-1);
4763 	}
4764 	MRT2MC(n)->ReopenTimerInterval = timeout;
4765 	if (p != NULL) {
4766 		if (curgroup == p) {
4767 			n->peer_id = 0;
4768 			n->group_id = p->conf.id;
4769 		} else {
4770 			n->peer_id = p->conf.id;
4771 			n->group_id = p->conf.groupid;
4772 		}
4773 	}
4774 	if (rib) {
4775 		if (!find_rib(rib)) {
4776 			yyerror("rib \"%s\" does not exist.", rib);
4777 			free(n);
4778 			return (-1);
4779 		}
4780 		if (strlcpy(n->rib, rib, sizeof(n->rib)) >=
4781 		    sizeof(n->rib)) {
4782 			yyerror("rib name \"%s\" too long: max %zu",
4783 			    name, sizeof(n->rib) - 1);
4784 			free(n);
4785 			return (-1);
4786 		}
4787 	}
4788 
4789 	LIST_INSERT_HEAD(conf->mrt, n, entry);
4790 
4791 	return (0);
4792 }
4793 
4794 struct rde_rib *
add_rib(char * name)4795 add_rib(char *name)
4796 {
4797 	struct rde_rib	*rr;
4798 
4799 	if ((rr = find_rib(name)) == NULL) {
4800 		if ((rr = calloc(1, sizeof(*rr))) == NULL) {
4801 			log_warn("add_rib");
4802 			return (NULL);
4803 		}
4804 		if (strlcpy(rr->name, name, sizeof(rr->name)) >=
4805 		    sizeof(rr->name)) {
4806 			yyerror("rib name \"%s\" too long: max %zu",
4807 			    name, sizeof(rr->name) - 1);
4808 			free(rr);
4809 			return (NULL);
4810 		}
4811 		rr->flags = F_RIB_NOFIB;
4812 		SIMPLEQ_INSERT_TAIL(&ribnames, rr, entry);
4813 	}
4814 	return (rr);
4815 }
4816 
4817 struct rde_rib *
find_rib(char * name)4818 find_rib(char *name)
4819 {
4820 	struct rde_rib	*rr;
4821 
4822 	SIMPLEQ_FOREACH(rr, &ribnames, entry) {
4823 		if (!strcmp(rr->name, name))
4824 			return (rr);
4825 	}
4826 	return (NULL);
4827 }
4828 
4829 int
rib_add_fib(struct rde_rib * rr,u_int rtableid)4830 rib_add_fib(struct rde_rib *rr, u_int rtableid)
4831 {
4832 	u_int	rdom;
4833 
4834 	if (!ktable_exists(rtableid, &rdom)) {
4835 		yyerror("rtable id %u does not exist", rtableid);
4836 		return (-1);
4837 	}
4838 	/*
4839 	 * conf->default_tableid is also a rdomain because that is checked
4840 	 * in init_config()
4841 	 */
4842 	if (rdom != conf->default_tableid) {
4843 		log_warnx("rtable %u does not belong to rdomain %u",
4844 		    rtableid, conf->default_tableid);
4845 		return (-1);
4846 	}
4847 	rr->rtableid = rtableid;
4848 	rr->flags &= ~F_RIB_NOFIB;
4849 	return (0);
4850 }
4851 
4852 struct prefixset *
find_prefixset(char * name,struct prefixset_head * p)4853 find_prefixset(char *name, struct prefixset_head *p)
4854 {
4855 	struct prefixset *ps;
4856 
4857 	SIMPLEQ_FOREACH(ps, p, entry) {
4858 		if (!strcmp(ps->name, name))
4859 			return (ps);
4860 	}
4861 	return (NULL);
4862 }
4863 
4864 int
get_id(struct peer * newpeer)4865 get_id(struct peer *newpeer)
4866 {
4867 	static uint32_t id = PEER_ID_STATIC_MIN;
4868 	struct peer	*p = NULL;
4869 
4870 	/* check if the peer already existed before */
4871 	if (newpeer->conf.remote_addr.aid) {
4872 		/* neighbor */
4873 		if (cur_peers)
4874 			RB_FOREACH(p, peer_head, cur_peers)
4875 				if (p->conf.remote_masklen ==
4876 				    newpeer->conf.remote_masklen &&
4877 				    memcmp(&p->conf.remote_addr,
4878 				    &newpeer->conf.remote_addr,
4879 				    sizeof(p->conf.remote_addr)) == 0)
4880 					break;
4881 		if (p) {
4882 			newpeer->conf.id = p->conf.id;
4883 			return (0);
4884 		}
4885 	} else {
4886 		/* group */
4887 		if (cur_peers)
4888 			RB_FOREACH(p, peer_head, cur_peers)
4889 				if (strcmp(p->conf.group,
4890 				    newpeer->conf.group) == 0)
4891 					break;
4892 		if (p) {
4893 			newpeer->conf.id = p->conf.groupid;
4894 			return (0);
4895 		}
4896 	}
4897 
4898 	/* else new one */
4899 	if (id < PEER_ID_STATIC_MAX) {
4900 		newpeer->conf.id = id++;
4901 		return (0);
4902 	}
4903 
4904 	return (-1);
4905 }
4906 
4907 int
merge_prefixspec(struct filter_prefix * p,struct filter_prefixlen * pl)4908 merge_prefixspec(struct filter_prefix *p, struct filter_prefixlen *pl)
4909 {
4910 	uint8_t max_len = 0;
4911 
4912 	switch (p->addr.aid) {
4913 	case AID_INET:
4914 	case AID_VPN_IPv4:
4915 		max_len = 32;
4916 		break;
4917 	case AID_INET6:
4918 	case AID_VPN_IPv6:
4919 		max_len = 128;
4920 		break;
4921 	}
4922 
4923 	if (pl->op == OP_NONE) {
4924 		p->len_min = p->len_max = p->len;
4925 		return (0);
4926 	}
4927 
4928 	if (pl->len_min == -1)
4929 		pl->len_min = p->len;
4930 	if (pl->len_max == -1)
4931 		pl->len_max = max_len;
4932 
4933 	if (pl->len_max > max_len) {
4934 		yyerror("prefixlen %d too big, limit %d",
4935 		    pl->len_max, max_len);
4936 		return (-1);
4937 	}
4938 	if (pl->len_min > pl->len_max) {
4939 		yyerror("prefixlen %d too big, limit %d",
4940 		    pl->len_min, pl->len_max);
4941 		return (-1);
4942 	}
4943 	if (pl->len_min < p->len) {
4944 		yyerror("prefixlen %d smaller than prefix, limit %d",
4945 		    pl->len_min, p->len);
4946 		return (-1);
4947 	}
4948 
4949 	p->op = pl->op;
4950 	p->len_min = pl->len_min;
4951 	p->len_max = pl->len_max;
4952 	return (0);
4953 }
4954 
4955 int
expand_rule(struct filter_rule * rule,struct filter_rib_l * rib,struct filter_peers_l * peer,struct filter_match_l * match,struct filter_set_head * set)4956 expand_rule(struct filter_rule *rule, struct filter_rib_l *rib,
4957     struct filter_peers_l *peer, struct filter_match_l *match,
4958     struct filter_set_head *set)
4959 {
4960 	struct filter_rule	*r;
4961 	struct filter_rib_l	*rb, *rbnext;
4962 	struct filter_peers_l	*p, *pnext;
4963 	struct filter_prefix_l	*prefix, *prefix_next;
4964 	struct filter_as_l	*a, *anext;
4965 	struct filter_set	*s;
4966 
4967 	rb = rib;
4968 	do {
4969 		p = peer;
4970 		do {
4971 			a = match->as_l;
4972 			do {
4973 				prefix = match->prefix_l;
4974 				do {
4975 					if ((r = calloc(1,
4976 					    sizeof(struct filter_rule))) ==
4977 						 NULL) {
4978 						log_warn("expand_rule");
4979 						return (-1);
4980 					}
4981 
4982 					memcpy(r, rule, sizeof(struct filter_rule));
4983 					memcpy(&r->match, match,
4984 					    sizeof(struct filter_match));
4985 					filterset_copy(set, &r->set);
4986 
4987 					if (rb != NULL)
4988 						strlcpy(r->rib, rb->name,
4989 						    sizeof(r->rib));
4990 
4991 					if (p != NULL)
4992 						memcpy(&r->peer, &p->p,
4993 						    sizeof(struct filter_peers));
4994 
4995 					if (prefix != NULL)
4996 						memcpy(&r->match.prefix, &prefix->p,
4997 						    sizeof(r->match.prefix));
4998 
4999 					if (a != NULL)
5000 						memcpy(&r->match.as, &a->a,
5001 						    sizeof(struct filter_as));
5002 
5003 					TAILQ_INSERT_TAIL(filter_l, r, entry);
5004 
5005 					if (prefix != NULL)
5006 						prefix = prefix->next;
5007 				} while (prefix != NULL);
5008 
5009 				if (a != NULL)
5010 					a = a->next;
5011 			} while (a != NULL);
5012 
5013 			if (p != NULL)
5014 				p = p->next;
5015 		} while (p != NULL);
5016 
5017 		if (rb != NULL)
5018 			rb = rb->next;
5019 	} while (rb != NULL);
5020 
5021 	for (rb = rib; rb != NULL; rb = rbnext) {
5022 		rbnext = rb->next;
5023 		free(rb);
5024 	}
5025 
5026 	for (p = peer; p != NULL; p = pnext) {
5027 		pnext = p->next;
5028 		free(p);
5029 	}
5030 
5031 	for (a = match->as_l; a != NULL; a = anext) {
5032 		anext = a->next;
5033 		free(a);
5034 	}
5035 
5036 	for (prefix = match->prefix_l; prefix != NULL; prefix = prefix_next) {
5037 		prefix_next = prefix->next;
5038 		free(prefix);
5039 	}
5040 
5041 	if (set != NULL) {
5042 		while ((s = TAILQ_FIRST(set)) != NULL) {
5043 			TAILQ_REMOVE(set, s, entry);
5044 			free(s);
5045 		}
5046 		free(set);
5047 	}
5048 
5049 	return (0);
5050 }
5051 
5052 static int
h2i(char c)5053 h2i(char c)
5054 {
5055 	if (c >= '0' && c <= '9')
5056 		return c - '0';
5057 	else if (c >= 'a' && c <= 'f')
5058 		return c - 'a' + 10;
5059 	else if (c >= 'A' && c <= 'F')
5060 		return c - 'A' + 10;
5061 	else
5062 		return -1;
5063 }
5064 
5065 int
str2key(char * s,char * dest,size_t max_len)5066 str2key(char *s, char *dest, size_t max_len)
5067 {
5068 	size_t	i;
5069 
5070 	if (strlen(s) / 2 > max_len) {
5071 		yyerror("key too long");
5072 		return (-1);
5073 	}
5074 
5075 	if (strlen(s) % 2) {
5076 		yyerror("key must be of even length");
5077 		return (-1);
5078 	}
5079 
5080 	for (i = 0; i < strlen(s) / 2; i++) {
5081 		int hi, lo;
5082 
5083 		hi = h2i(s[2 * i]);
5084 		lo = h2i(s[2 * i + 1]);
5085 		if (hi == -1 || lo == -1) {
5086 			yyerror("key must be specified in hex");
5087 			return (-1);
5088 		}
5089 		dest[i] = (hi << 4) | lo;
5090 	}
5091 
5092 	return (0);
5093 }
5094 
5095 int
neighbor_consistent(struct peer * p)5096 neighbor_consistent(struct peer *p)
5097 {
5098 	struct bgpd_addr *local_addr;
5099 	struct peer *xp;
5100 
5101 	switch (p->conf.remote_addr.aid) {
5102 	case AID_INET:
5103 		local_addr = &p->conf.local_addr_v4;
5104 		break;
5105 	case AID_INET6:
5106 		local_addr = &p->conf.local_addr_v6;
5107 		break;
5108 	default:
5109 		yyerror("Bad address family for remote-addr");
5110 		return (-1);
5111 	}
5112 
5113 	/* with any form of ipsec local-address is required */
5114 	if ((p->auth_conf.method == AUTH_IPSEC_IKE_ESP ||
5115 	    p->auth_conf.method == AUTH_IPSEC_IKE_AH ||
5116 	    p->auth_conf.method == AUTH_IPSEC_MANUAL_ESP ||
5117 	    p->auth_conf.method == AUTH_IPSEC_MANUAL_AH) &&
5118 	    local_addr->aid == AID_UNSPEC) {
5119 		yyerror("neighbors with any form of IPsec configured "
5120 		    "need local-address to be specified");
5121 		return (-1);
5122 	}
5123 
5124 	/* with static keying we need both directions */
5125 	if ((p->auth_conf.method == AUTH_IPSEC_MANUAL_ESP ||
5126 	    p->auth_conf.method == AUTH_IPSEC_MANUAL_AH) &&
5127 	    (!p->auth_conf.spi_in || !p->auth_conf.spi_out)) {
5128 		yyerror("with manual keyed IPsec, SPIs and keys "
5129 		    "for both directions are required");
5130 		return (-1);
5131 	}
5132 
5133 	if (!conf->as) {
5134 		yyerror("AS needs to be given before neighbor definitions");
5135 		return (-1);
5136 	}
5137 
5138 	/* set default values if they where undefined */
5139 	p->conf.ebgp = (p->conf.remote_as != conf->as);
5140 	if (p->conf.enforce_as == ENFORCE_AS_UNDEF)
5141 		p->conf.enforce_as = p->conf.ebgp ?
5142 		    ENFORCE_AS_ON : ENFORCE_AS_OFF;
5143 	if (p->conf.enforce_local_as == ENFORCE_AS_UNDEF)
5144 		p->conf.enforce_local_as = ENFORCE_AS_ON;
5145 
5146 	if (p->conf.remote_as == 0 && !p->conf.template) {
5147 		yyerror("peer AS may not be zero");
5148 		return (-1);
5149 	}
5150 
5151 	/* EBGP neighbors are not allowed in route reflector clusters */
5152 	if (p->conf.reflector_client && p->conf.ebgp) {
5153 		yyerror("EBGP neighbors are not allowed in route "
5154 		    "reflector clusters");
5155 		return (-1);
5156 	}
5157 
5158 	/* BGP role and RFC 9234 role are only valid for EBGP neighbors */
5159 	if (!p->conf.ebgp) {
5160 		p->conf.role = ROLE_NONE;
5161 		p->conf.capabilities.policy = 0;
5162 	} else if (p->conf.role == ROLE_NONE) {
5163 		/* no role, no policy capability */
5164 		p->conf.capabilities.policy = 0;
5165 	}
5166 
5167 	/* check for duplicate peer definitions */
5168 	RB_FOREACH(xp, peer_head, new_peers)
5169 		if (xp->conf.remote_masklen ==
5170 		    p->conf.remote_masklen &&
5171 		    memcmp(&xp->conf.remote_addr,
5172 		    &p->conf.remote_addr,
5173 		    sizeof(p->conf.remote_addr)) == 0)
5174 			break;
5175 	if (xp != NULL) {
5176 		char *descr = log_fmt_peer(&p->conf);
5177 		yyerror("duplicate %s", descr);
5178 		free(descr);
5179 		return (-1);
5180 	}
5181 
5182 	return (0);
5183 }
5184 
5185 static void
filterset_add(struct filter_set_head * sh,struct filter_set * s)5186 filterset_add(struct filter_set_head *sh, struct filter_set *s)
5187 {
5188 	struct filter_set	*t;
5189 
5190 	TAILQ_FOREACH(t, sh, entry) {
5191 		if (s->type < t->type) {
5192 			TAILQ_INSERT_BEFORE(t, s, entry);
5193 			return;
5194 		}
5195 		if (s->type == t->type) {
5196 			switch (s->type) {
5197 			case ACTION_SET_COMMUNITY:
5198 			case ACTION_DEL_COMMUNITY:
5199 				switch (cmpcommunity(&s->action.community,
5200 				    &t->action.community)) {
5201 				case -1:
5202 					TAILQ_INSERT_BEFORE(t, s, entry);
5203 					return;
5204 				case 0:
5205 					break;
5206 				case 1:
5207 					continue;
5208 				}
5209 				break;
5210 			case ACTION_SET_NEXTHOP:
5211 				/* only last nexthop per AF matters */
5212 				if (s->action.nexthop.aid <
5213 				    t->action.nexthop.aid) {
5214 					TAILQ_INSERT_BEFORE(t, s, entry);
5215 					return;
5216 				} else if (s->action.nexthop.aid ==
5217 				    t->action.nexthop.aid) {
5218 					t->action.nexthop = s->action.nexthop;
5219 					break;
5220 				}
5221 				continue;
5222 			case ACTION_SET_NEXTHOP_BLACKHOLE:
5223 			case ACTION_SET_NEXTHOP_REJECT:
5224 			case ACTION_SET_NEXTHOP_NOMODIFY:
5225 			case ACTION_SET_NEXTHOP_SELF:
5226 				/* set it only once */
5227 				break;
5228 			case ACTION_SET_LOCALPREF:
5229 			case ACTION_SET_MED:
5230 			case ACTION_SET_WEIGHT:
5231 				/* only last set matters */
5232 				t->action.metric = s->action.metric;
5233 				break;
5234 			case ACTION_SET_RELATIVE_LOCALPREF:
5235 			case ACTION_SET_RELATIVE_MED:
5236 			case ACTION_SET_RELATIVE_WEIGHT:
5237 				/* sum all relative numbers */
5238 				t->action.relative += s->action.relative;
5239 				break;
5240 			case ACTION_SET_ORIGIN:
5241 				/* only last set matters */
5242 				t->action.origin = s->action.origin;
5243 				break;
5244 			case ACTION_PFTABLE:
5245 				/* only last set matters */
5246 				strlcpy(t->action.pftable, s->action.pftable,
5247 				    sizeof(t->action.pftable));
5248 				break;
5249 			case ACTION_RTLABEL:
5250 				/* only last set matters */
5251 				strlcpy(t->action.rtlabel, s->action.rtlabel,
5252 				    sizeof(t->action.rtlabel));
5253 				break;
5254 			default:
5255 				break;
5256 			}
5257 			free(s);
5258 			return;
5259 		}
5260 	}
5261 
5262 	TAILQ_INSERT_TAIL(sh, s, entry);
5263 }
5264 
5265 int
merge_filterset(struct filter_set_head * sh,struct filter_set * s)5266 merge_filterset(struct filter_set_head *sh, struct filter_set *s)
5267 {
5268 	struct filter_set	*t;
5269 
5270 	TAILQ_FOREACH(t, sh, entry) {
5271 		/*
5272 		 * need to cycle across the full list because even
5273 		 * if types are not equal filterset_cmp() may return 0.
5274 		 */
5275 		if (filterset_cmp(s, t) == 0) {
5276 			if (s->type == ACTION_SET_COMMUNITY)
5277 				yyerror("community is already set");
5278 			else if (s->type == ACTION_DEL_COMMUNITY)
5279 				yyerror("community will already be deleted");
5280 			else
5281 				yyerror("redefining set parameter %s",
5282 				    filterset_name(s->type));
5283 			return (-1);
5284 		}
5285 	}
5286 
5287 	filterset_add(sh, s);
5288 	return (0);
5289 }
5290 
5291 static int
filter_equal(struct filter_rule * fa,struct filter_rule * fb)5292 filter_equal(struct filter_rule *fa, struct filter_rule *fb)
5293 {
5294 	if (fa == NULL || fb == NULL)
5295 		return 0;
5296 	if (fa->action != fb->action || fa->quick != fb->quick ||
5297 	    fa->dir != fb->dir)
5298 		return 0;
5299 	if (memcmp(&fa->peer, &fb->peer, sizeof(fa->peer)))
5300 		return 0;
5301 	if (memcmp(&fa->match, &fb->match, sizeof(fa->match)))
5302 		return 0;
5303 
5304 	return 1;
5305 }
5306 
5307 /* do a basic optimization by folding equal rules together */
5308 void
optimize_filters(struct filter_head * fh)5309 optimize_filters(struct filter_head *fh)
5310 {
5311 	struct filter_rule *r, *nr;
5312 
5313 	TAILQ_FOREACH_SAFE(r, fh, entry, nr) {
5314 		while (filter_equal(r, nr)) {
5315 			struct filter_set	*t;
5316 
5317 			while ((t = TAILQ_FIRST(&nr->set)) != NULL) {
5318 				TAILQ_REMOVE(&nr->set, t, entry);
5319 				filterset_add(&r->set, t);
5320 			}
5321 
5322 			TAILQ_REMOVE(fh, nr, entry);
5323 			free(nr);
5324 			nr = TAILQ_NEXT(r, entry);
5325 		}
5326 	}
5327 }
5328 
5329 struct filter_rule *
get_rule(enum action_types type)5330 get_rule(enum action_types type)
5331 {
5332 	struct filter_rule	*r;
5333 	int			 out;
5334 
5335 	switch (type) {
5336 	case ACTION_SET_PREPEND_SELF:
5337 	case ACTION_SET_NEXTHOP_NOMODIFY:
5338 	case ACTION_SET_NEXTHOP_SELF:
5339 		out = 1;
5340 		break;
5341 	default:
5342 		out = 0;
5343 		break;
5344 	}
5345 	r = (curpeer == curgroup) ? curgroup_filter[out] : curpeer_filter[out];
5346 	if (r == NULL) {
5347 		if ((r = calloc(1, sizeof(struct filter_rule))) == NULL)
5348 			fatal(NULL);
5349 		r->quick = 0;
5350 		r->dir = out ? DIR_OUT : DIR_IN;
5351 		r->action = ACTION_NONE;
5352 		TAILQ_INIT(&r->set);
5353 		if (curpeer == curgroup) {
5354 			/* group */
5355 			r->peer.groupid = curgroup->conf.id;
5356 			curgroup_filter[out] = r;
5357 		} else {
5358 			/* peer */
5359 			r->peer.peerid = curpeer->conf.id;
5360 			curpeer_filter[out] = r;
5361 		}
5362 	}
5363 	return (r);
5364 }
5365 
5366 struct set_table *curset;
5367 static int
new_as_set(char * name)5368 new_as_set(char *name)
5369 {
5370 	struct as_set *aset;
5371 
5372 	if (as_sets_lookup(&conf->as_sets, name) != NULL) {
5373 		yyerror("as-set \"%s\" already exists", name);
5374 		return -1;
5375 	}
5376 
5377 	aset = as_sets_new(&conf->as_sets, name, 0, sizeof(uint32_t));
5378 	if (aset == NULL)
5379 		fatal(NULL);
5380 
5381 	curset = aset->set;
5382 	return 0;
5383 }
5384 
5385 static void
add_as_set(uint32_t as)5386 add_as_set(uint32_t as)
5387 {
5388 	if (curset == NULL)
5389 		fatalx("%s: bad mojo jojo", __func__);
5390 
5391 	if (set_add(curset, &as, 1) != 0)
5392 		fatal(NULL);
5393 }
5394 
5395 static void
done_as_set(void)5396 done_as_set(void)
5397 {
5398 	curset = NULL;
5399 }
5400 
5401 static struct prefixset *
new_prefix_set(char * name,int is_roa)5402 new_prefix_set(char *name, int is_roa)
5403 {
5404 	const char *type = "prefix-set";
5405 	struct prefixset_head *sets = &conf->prefixsets;
5406 	struct prefixset *pset;
5407 
5408 	if (is_roa) {
5409 		type = "origin-set";
5410 		sets = &conf->originsets;
5411 	}
5412 
5413 	if (find_prefixset(name, sets) != NULL) {
5414 		yyerror("%s \"%s\" already exists", type, name);
5415 		return NULL;
5416 	}
5417 	if ((pset = calloc(1, sizeof(*pset))) == NULL)
5418 		fatal("prefixset");
5419 	if (strlcpy(pset->name, name, sizeof(pset->name)) >=
5420 	    sizeof(pset->name)) {
5421 		yyerror("%s \"%s\" too long: max %zu", type,
5422 		    name, sizeof(pset->name) - 1);
5423 		free(pset);
5424 		return NULL;
5425 	}
5426 	RB_INIT(&pset->psitems);
5427 	RB_INIT(&pset->roaitems);
5428 	return pset;
5429 }
5430 
5431 static void
add_roa_set(struct prefixset_item * npsi,uint32_t as,uint8_t max,time_t expires)5432 add_roa_set(struct prefixset_item *npsi, uint32_t as, uint8_t max,
5433     time_t expires)
5434 {
5435 	struct roa *roa, *r;
5436 
5437 	if ((roa = calloc(1, sizeof(*roa))) == NULL)
5438 		fatal("add_roa_set");
5439 
5440 	roa->aid = npsi->p.addr.aid;
5441 	roa->prefixlen = npsi->p.len;
5442 	roa->maxlen = max;
5443 	roa->asnum = as;
5444 	roa->expires = expires;
5445 	switch (roa->aid) {
5446 	case AID_INET:
5447 		roa->prefix.inet = npsi->p.addr.v4;
5448 		break;
5449 	case AID_INET6:
5450 		roa->prefix.inet6 = npsi->p.addr.v6;
5451 		break;
5452 	default:
5453 		fatalx("Bad address family for roa_set address");
5454 	}
5455 
5456 	r = RB_INSERT(roa_tree, curroatree, roa);
5457 	if (r != NULL) {
5458 		/* just ignore duplicates */
5459 		if (r->expires != 0 && expires != 0 && expires > r->expires)
5460 			r->expires = expires;
5461 		free(roa);
5462 	}
5463 }
5464 
5465 static struct rtr_config *
get_rtr(struct bgpd_addr * addr)5466 get_rtr(struct bgpd_addr *addr)
5467 {
5468 	struct rtr_config *n;
5469 
5470 	n = calloc(1, sizeof(*n));
5471 	if (n == NULL) {
5472 		yyerror("out of memory");
5473 		return NULL;
5474 	}
5475 
5476 	n->remote_addr = *addr;
5477 	strlcpy(n->descr, log_addr(addr), sizeof(currtr->descr));
5478 
5479 	return n;
5480 }
5481 
5482 static int
insert_rtr(struct rtr_config * new)5483 insert_rtr(struct rtr_config *new)
5484 {
5485 	static uint32_t id;
5486 	struct rtr_config *r;
5487 
5488 	if (id == UINT32_MAX) {
5489 		yyerror("out of rtr session IDs");
5490 		return -1;
5491 	}
5492 
5493 	SIMPLEQ_FOREACH(r, &conf->rtrs, entry)
5494 		if (memcmp(&r->remote_addr, &new->remote_addr,
5495 		    sizeof(r->remote_addr)) == 0 &&
5496 		    r->remote_port == new->remote_port) {
5497 			yyerror("duplicate rtr session to %s:%u",
5498 			    log_addr(&new->remote_addr), new->remote_port);
5499 			return -1;
5500 		}
5501 
5502 	if (cur_rtrs)
5503 		SIMPLEQ_FOREACH(r, cur_rtrs, entry)
5504 			if (memcmp(&r->remote_addr, &new->remote_addr,
5505 			    sizeof(r->remote_addr)) == 0 &&
5506 			    r->remote_port == new->remote_port) {
5507 				new->id = r->id;
5508 				break;
5509 			}
5510 
5511 	if (new->id == 0)
5512 		new->id = ++id;
5513 
5514 	SIMPLEQ_INSERT_TAIL(&conf->rtrs, currtr, entry);
5515 
5516 	return 0;
5517 }
5518 
5519 static int
merge_aspa_set(uint32_t as,struct aspa_tas_l * tas,time_t expires)5520 merge_aspa_set(uint32_t as, struct aspa_tas_l *tas, time_t expires)
5521 {
5522 	struct aspa_set	*aspa, needle = { .as = as };
5523 	uint32_t i, num, *newtas;
5524 
5525 	aspa = RB_FIND(aspa_tree, &conf->aspa, &needle);
5526 	if (aspa == NULL) {
5527 		if ((aspa = calloc(1, sizeof(*aspa))) == NULL) {
5528 			yyerror("out of memory");
5529 			return -1;
5530 		}
5531 		aspa->as = as;
5532 		aspa->expires = expires;
5533 		RB_INSERT(aspa_tree, &conf->aspa, aspa);
5534 	}
5535 
5536 	if (MAX_ASPA_SPAS_COUNT - aspa->num <= tas->num) {
5537 		yyerror("too many providers for customer-as %u", as);
5538 		return -1;
5539 	}
5540 	num = aspa->num + tas->num;
5541 	newtas = recallocarray(aspa->tas, aspa->num, num, sizeof(uint32_t));
5542 	if (newtas == NULL) {
5543 		yyerror("out of memory");
5544 		return -1;
5545 	}
5546 	/* fill starting at the end since the tas list is reversed */
5547 	if (num > 0) {
5548 		for (i = num - 1; tas; tas = tas->next, i--)
5549 			newtas[i] = tas->as;
5550 	}
5551 
5552 	aspa->num = num;
5553 	aspa->tas = newtas;
5554 
5555 	/* take the longest expiry time, same logic as for ROA entries */
5556 	if (aspa->expires != 0 && expires != 0 && expires > aspa->expires)
5557 		aspa->expires = expires;
5558 
5559 	return 0;
5560 }
5561 
5562 static int
kw_casecmp(const void * k,const void * e)5563 kw_casecmp(const void *k, const void *e)
5564 {
5565 	return (strcasecmp(k, ((const struct keywords *)e)->k_name));
5566 }
5567 
5568 static int
map_tos(char * s,int * val)5569 map_tos(char *s, int *val)
5570 {
5571 	/* DiffServ Codepoints and other TOS mappings */
5572 	const struct keywords	 toswords[] = {
5573 		{ "af11",		IPTOS_DSCP_AF11 },
5574 		{ "af12",		IPTOS_DSCP_AF12 },
5575 		{ "af13",		IPTOS_DSCP_AF13 },
5576 		{ "af21",		IPTOS_DSCP_AF21 },
5577 		{ "af22",		IPTOS_DSCP_AF22 },
5578 		{ "af23",		IPTOS_DSCP_AF23 },
5579 		{ "af31",		IPTOS_DSCP_AF31 },
5580 		{ "af32",		IPTOS_DSCP_AF32 },
5581 		{ "af33",		IPTOS_DSCP_AF33 },
5582 		{ "af41",		IPTOS_DSCP_AF41 },
5583 		{ "af42",		IPTOS_DSCP_AF42 },
5584 		{ "af43",		IPTOS_DSCP_AF43 },
5585 		{ "critical",		IPTOS_PREC_CRITIC_ECP },
5586 		{ "cs0",		IPTOS_DSCP_CS0 },
5587 		{ "cs1",		IPTOS_DSCP_CS1 },
5588 		{ "cs2",		IPTOS_DSCP_CS2 },
5589 		{ "cs3",		IPTOS_DSCP_CS3 },
5590 		{ "cs4",		IPTOS_DSCP_CS4 },
5591 		{ "cs5",		IPTOS_DSCP_CS5 },
5592 		{ "cs6",		IPTOS_DSCP_CS6 },
5593 		{ "cs7",		IPTOS_DSCP_CS7 },
5594 		{ "ef",			IPTOS_DSCP_EF },
5595 		{ "inetcontrol",	IPTOS_PREC_INTERNETCONTROL },
5596 		{ "lowdelay",		IPTOS_LOWDELAY },
5597 		{ "netcontrol",		IPTOS_PREC_NETCONTROL },
5598 		{ "reliability",	IPTOS_RELIABILITY },
5599 		{ "throughput",		IPTOS_THROUGHPUT },
5600 	};
5601 	const struct keywords	*p;
5602 
5603 	p = bsearch(s, toswords, nitems(toswords), sizeof(toswords[0]),
5604 	    kw_casecmp);
5605 
5606 	if (p) {
5607 		*val = p->k_val;
5608 		return (1);
5609 	}
5610 	return (0);
5611 }
5612 
5613 static int
getservice(char * n)5614 getservice(char *n)
5615 {
5616 	struct servent	*s;
5617 
5618 	s = getservbyname(n, "tcp");
5619 	if (s == NULL)
5620 		s = getservbyname(n, "udp");
5621 	if (s == NULL)
5622 		return -1;
5623 	return s->s_port;
5624 }
5625 
5626 static int
parse_flags(char * s)5627 parse_flags(char *s)
5628 {
5629 	const char *flags = FLOWSPEC_TCP_FLAG_STRING;
5630 	char *p, *q;
5631 	uint8_t f = 0;
5632 
5633 	if (curflow->type == FLOWSPEC_TYPE_FRAG) {
5634 		if (curflow->aid == AID_INET)
5635 			flags = FLOWSPEC_FRAG_STRING4;
5636 		else
5637 			flags = FLOWSPEC_FRAG_STRING6;
5638 	}
5639 
5640 	for (p = s; *p; p++) {
5641 		if ((q = strchr(flags, *p)) == NULL)
5642 			return -1;
5643 		f |= 1 << (q - flags);
5644 	}
5645 	return (f ? f : 0xff);
5646 }
5647 
5648 static void
component_finish(int type,uint8_t * data,int len)5649 component_finish(int type, uint8_t *data, int len)
5650 {
5651 	uint8_t *last;
5652 	int i;
5653 
5654 	switch (type) {
5655 	case FLOWSPEC_TYPE_DEST:
5656 	case FLOWSPEC_TYPE_SOURCE:
5657 		/* nothing to do */
5658 		return;
5659 	default:
5660 		break;
5661 	}
5662 
5663 	i = 0;
5664 	do {
5665 		last = data + i;
5666 		i += FLOWSPEC_OP_LEN(*last) + 1;
5667 	} while (i < len);
5668 	*last |= FLOWSPEC_OP_EOL;
5669 }
5670 
5671 static struct flowspec_config *
flow_to_flowspec(struct flowspec_context * ctx)5672 flow_to_flowspec(struct flowspec_context *ctx)
5673 {
5674 	struct flowspec_config *f;
5675 	int i, len = 0;
5676 	uint8_t aid;
5677 
5678 	switch (ctx->aid) {
5679 	case AID_INET:
5680 		aid = AID_FLOWSPECv4;
5681 		break;
5682 	case AID_INET6:
5683 		aid = AID_FLOWSPECv6;
5684 		break;
5685 	default:
5686 		return NULL;
5687 	}
5688 
5689 	for (i = FLOWSPEC_TYPE_MIN; i < FLOWSPEC_TYPE_MAX; i++)
5690 		if (ctx->components[i] != NULL)
5691 			len += ctx->complen[i] + 1;
5692 
5693 	f = flowspec_alloc(aid, len);
5694 	if (f == NULL)
5695 		return NULL;
5696 
5697 	len = 0;
5698 	for (i = FLOWSPEC_TYPE_MIN; i < FLOWSPEC_TYPE_MAX; i++)
5699 		if (ctx->components[i] != NULL) {
5700 			f->flow->data[len++] = i;
5701 			component_finish(i, ctx->components[i],
5702 			    ctx->complen[i]);
5703 			memcpy(f->flow->data + len, ctx->components[i],
5704 			    ctx->complen[i]);
5705 			len += ctx->complen[i];
5706 		}
5707 
5708 	return f;
5709 }
5710 
5711 static void
flow_free(struct flowspec_context * ctx)5712 flow_free(struct flowspec_context *ctx)
5713 {
5714 	int i;
5715 
5716 	for (i = 0; i < FLOWSPEC_TYPE_MAX; i++)
5717 		free(ctx->components[i]);
5718 	free(ctx);
5719 }
5720 
5721 static int
push_prefix(struct bgpd_addr * addr,uint8_t len)5722 push_prefix(struct bgpd_addr *addr, uint8_t len)
5723 {
5724 	void *data;
5725 	uint8_t *comp;
5726 	int complen, l;
5727 
5728 	if (curflow->components[curflow->addr_type] != NULL) {
5729 		yyerror("flowspec address already set");
5730 		return -1;
5731 	}
5732 
5733 	if (curflow->aid != addr->aid) {
5734 		yyerror("wrong address family for flowspec address");
5735 		return -1;
5736 	}
5737 
5738 	switch (curflow->aid) {
5739 	case AID_INET:
5740 		complen = PREFIX_SIZE(len);
5741 		data = &addr->v4;
5742 		break;
5743 	case AID_INET6:
5744 		/* IPv6 includes an offset byte */
5745 		complen = PREFIX_SIZE(len) + 1;
5746 		data = &addr->v6;
5747 		break;
5748 	default:
5749 		yyerror("unsupported address family for flowspec address");
5750 		return -1;
5751 	}
5752 	comp = malloc(complen);
5753 	if (comp == NULL) {
5754 		yyerror("out of memory");
5755 		return -1;
5756 	}
5757 
5758 	l = 0;
5759 	comp[l++] = len;
5760 	if (curflow->aid == AID_INET6)
5761 		comp[l++] = 0;
5762 	memcpy(comp + l, data, complen - l);
5763 
5764 	curflow->complen[curflow->addr_type] = complen;
5765 	curflow->components[curflow->addr_type] = comp;
5766 
5767 	return 0;
5768 }
5769 
5770 static int
push_binop(uint8_t binop,long long val)5771 push_binop(uint8_t binop, long long val)
5772 {
5773 	uint8_t *comp;
5774 	int complen;
5775 	uint8_t u8;
5776 
5777 	if (val < 0 || val > 0xff) {
5778 		yyerror("unsupported value for flowspec bin_op");
5779 		return -1;
5780 	}
5781 	u8 = val;
5782 
5783 	complen = curflow->complen[curflow->type];
5784 	comp = realloc(curflow->components[curflow->type],
5785 	    complen + 2);
5786 	if (comp == NULL) {
5787 		yyerror("out of memory");
5788 		return -1;
5789 	}
5790 
5791 	comp[complen++] = binop;
5792 	comp[complen++] = u8;
5793 	curflow->complen[curflow->type] = complen;
5794 	curflow->components[curflow->type] = comp;
5795 
5796 	return 0;
5797 }
5798 
5799 static uint8_t
component_numop(enum comp_ops op,int and,int len)5800 component_numop(enum comp_ops op, int and, int len)
5801 {
5802 	uint8_t flag = 0;
5803 
5804 	switch (op) {
5805 	case OP_EQ:
5806 		flag |= FLOWSPEC_OP_NUM_EQ;
5807 		break;
5808 	case OP_NE:
5809 		flag |= FLOWSPEC_OP_NUM_NOT;
5810 		break;
5811 	case OP_LE:
5812 		flag |= FLOWSPEC_OP_NUM_LE;
5813 		break;
5814 	case OP_LT:
5815 		flag |= FLOWSPEC_OP_NUM_LT;
5816 		break;
5817 	case OP_GE:
5818 		flag |= FLOWSPEC_OP_NUM_GE;
5819 		break;
5820 	case OP_GT:
5821 		flag |= FLOWSPEC_OP_NUM_GT;
5822 		break;
5823 	default:
5824 		fatalx("unsupported op");
5825 	}
5826 
5827 	switch (len) {
5828 	case 2:
5829 		flag |= 1 << FLOWSPEC_OP_LEN_SHIFT;
5830 		break;
5831 	case 4:
5832 		flag |= 2 << FLOWSPEC_OP_LEN_SHIFT;
5833 		break;
5834 	case 8:
5835 		flag |= 3 << FLOWSPEC_OP_LEN_SHIFT;
5836 		break;
5837 	}
5838 
5839 	if (and)
5840 		flag |= FLOWSPEC_OP_AND;
5841 
5842 	return flag;
5843 }
5844 
5845 static int
push_numop(enum comp_ops op,int and,long long val)5846 push_numop(enum comp_ops op, int and, long long val)
5847 {
5848 	uint8_t *comp;
5849 	void *data;
5850 	uint32_t u32;
5851 	uint16_t u16;
5852 	uint8_t u8;
5853 	int len, complen;
5854 
5855 	if (val < 0 || val > 0xffffffff) {
5856 		yyerror("unsupported value for flowspec num_op");
5857 		return -1;
5858 	} else if (val <= 255) {
5859 		len = 1;
5860 		u8 = val;
5861 		data = &u8;
5862 	} else if (val <= 0xffff) {
5863 		len = 2;
5864 		u16 = htons(val);
5865 		data = &u16;
5866 	} else {
5867 		len = 4;
5868 		u32 = htonl(val);
5869 		data = &u32;
5870 	}
5871 
5872 	complen = curflow->complen[curflow->type];
5873 	comp = realloc(curflow->components[curflow->type],
5874 	    complen + len + 1);
5875 	if (comp == NULL) {
5876 		yyerror("out of memory");
5877 		return -1;
5878 	}
5879 
5880 	comp[complen++] = component_numop(op, and, len);
5881 	memcpy(comp + complen, data, len);
5882 	complen += len;
5883 	curflow->complen[curflow->type] = complen;
5884 	curflow->components[curflow->type] = comp;
5885 
5886 	return 0;
5887 }
5888 
5889 static int
push_unary_numop(enum comp_ops op,long long val)5890 push_unary_numop(enum comp_ops op, long long val)
5891 {
5892 	return push_numop(op, 0, val);
5893 }
5894 
5895 static int
push_binary_numop(enum comp_ops op,long long min,long long max)5896 push_binary_numop(enum comp_ops op, long long min, long long max)
5897 {
5898 	switch (op) {
5899 	case OP_RANGE:
5900 		if (push_numop(OP_GE, 0, min) == -1)
5901 			return -1;
5902 		return push_numop(OP_LE, 1, max);
5903 	case OP_XRANGE:
5904 		if (push_numop(OP_LT, 0, min) == -1)
5905 			return -1;
5906 		return push_numop(OP_GT, 0, max);
5907 	default:
5908 		yyerror("unsupported binary flowspec num_op");
5909 		return -1;
5910 	}
5911 }
5912 
5913 struct icmptypeent {
5914 	const char *name;
5915 	u_int8_t type;
5916 };
5917 
5918 struct icmpcodeent {
5919 	const char *name;
5920 	u_int8_t type;
5921 	u_int8_t code;
5922 };
5923 
5924 static const struct icmptypeent icmp_type[] = {
5925 	{ "echoreq",	ICMP_ECHO },
5926 	{ "echorep",	ICMP_ECHOREPLY },
5927 	{ "unreach",	ICMP_UNREACH },
5928 	{ "squench",	ICMP_SOURCEQUENCH },
5929 	{ "redir",	ICMP_REDIRECT },
5930 	{ "althost",	ICMP_ALTHOSTADDR },
5931 	{ "routeradv",	ICMP_ROUTERADVERT },
5932 	{ "routersol",	ICMP_ROUTERSOLICIT },
5933 	{ "timex",	ICMP_TIMXCEED },
5934 	{ "paramprob",	ICMP_PARAMPROB },
5935 	{ "timereq",	ICMP_TSTAMP },
5936 	{ "timerep",	ICMP_TSTAMPREPLY },
5937 	{ "inforeq",	ICMP_IREQ },
5938 	{ "inforep",	ICMP_IREQREPLY },
5939 	{ "maskreq",	ICMP_MASKREQ },
5940 	{ "maskrep",	ICMP_MASKREPLY },
5941 	{ "trace",	ICMP_TRACEROUTE },
5942 	{ "dataconv",	ICMP_DATACONVERR },
5943 	{ "mobredir",	ICMP_MOBILE_REDIRECT },
5944 	{ "ipv6-where",	ICMP_IPV6_WHEREAREYOU },
5945 	{ "ipv6-here",	ICMP_IPV6_IAMHERE },
5946 	{ "mobregreq",	ICMP_MOBILE_REGREQUEST },
5947 	{ "mobregrep",	ICMP_MOBILE_REGREPLY },
5948 	{ "skip",	ICMP_SKIP },
5949 	{ "photuris",	ICMP_PHOTURIS },
5950 };
5951 
5952 static const struct icmptypeent icmp6_type[] = {
5953 	{ "unreach",	ICMP6_DST_UNREACH },
5954 	{ "toobig",	ICMP6_PACKET_TOO_BIG },
5955 	{ "timex",	ICMP6_TIME_EXCEEDED },
5956 	{ "paramprob",	ICMP6_PARAM_PROB },
5957 	{ "echoreq",	ICMP6_ECHO_REQUEST },
5958 	{ "echorep",	ICMP6_ECHO_REPLY },
5959 	{ "groupqry",	ICMP6_MEMBERSHIP_QUERY },
5960 	{ "listqry",	MLD_LISTENER_QUERY },
5961 	{ "grouprep",	ICMP6_MEMBERSHIP_REPORT },
5962 	{ "listenrep",	MLD_LISTENER_REPORT },
5963 	{ "groupterm",	ICMP6_MEMBERSHIP_REDUCTION },
5964 	{ "listendone", MLD_LISTENER_DONE },
5965 	{ "routersol",	ND_ROUTER_SOLICIT },
5966 	{ "routeradv",	ND_ROUTER_ADVERT },
5967 	{ "neighbrsol", ND_NEIGHBOR_SOLICIT },
5968 	{ "neighbradv", ND_NEIGHBOR_ADVERT },
5969 	{ "redir",	ND_REDIRECT },
5970 	{ "routrrenum", ICMP6_ROUTER_RENUMBERING },
5971 	{ "wrureq",	ICMP6_WRUREQUEST },
5972 	{ "wrurep",	ICMP6_WRUREPLY },
5973 	{ "fqdnreq",	ICMP6_FQDN_QUERY },
5974 	{ "fqdnrep",	ICMP6_FQDN_REPLY },
5975 	{ "niqry",	ICMP6_NI_QUERY },
5976 	{ "nirep",	ICMP6_NI_REPLY },
5977 	{ "mtraceresp",	MLD_MTRACE_RESP },
5978 	{ "mtrace",	MLD_MTRACE },
5979 	{ "listenrepv2", MLDV2_LISTENER_REPORT },
5980 };
5981 
5982 static const struct icmpcodeent icmp_code[] = {
5983 	{ "net-unr",		ICMP_UNREACH,	ICMP_UNREACH_NET },
5984 	{ "host-unr",		ICMP_UNREACH,	ICMP_UNREACH_HOST },
5985 	{ "proto-unr",		ICMP_UNREACH,	ICMP_UNREACH_PROTOCOL },
5986 	{ "port-unr",		ICMP_UNREACH,	ICMP_UNREACH_PORT },
5987 	{ "needfrag",		ICMP_UNREACH,	ICMP_UNREACH_NEEDFRAG },
5988 	{ "srcfail",		ICMP_UNREACH,	ICMP_UNREACH_SRCFAIL },
5989 	{ "net-unk",		ICMP_UNREACH,	ICMP_UNREACH_NET_UNKNOWN },
5990 	{ "host-unk",		ICMP_UNREACH,	ICMP_UNREACH_HOST_UNKNOWN },
5991 	{ "isolate",		ICMP_UNREACH,	ICMP_UNREACH_ISOLATED },
5992 	{ "net-prohib",		ICMP_UNREACH,	ICMP_UNREACH_NET_PROHIB },
5993 	{ "host-prohib",	ICMP_UNREACH,	ICMP_UNREACH_HOST_PROHIB },
5994 	{ "net-tos",		ICMP_UNREACH,	ICMP_UNREACH_TOSNET },
5995 	{ "host-tos",		ICMP_UNREACH,	ICMP_UNREACH_TOSHOST },
5996 	{ "filter-prohib",	ICMP_UNREACH,	ICMP_UNREACH_FILTER_PROHIB },
5997 	{ "host-preced",	ICMP_UNREACH,	ICMP_UNREACH_HOST_PRECEDENCE },
5998 	{ "cutoff-preced",	ICMP_UNREACH,	ICMP_UNREACH_PRECEDENCE_CUTOFF },
5999 	{ "redir-net",		ICMP_REDIRECT,	ICMP_REDIRECT_NET },
6000 	{ "redir-host",		ICMP_REDIRECT,	ICMP_REDIRECT_HOST },
6001 	{ "redir-tos-net",	ICMP_REDIRECT,	ICMP_REDIRECT_TOSNET },
6002 	{ "redir-tos-host",	ICMP_REDIRECT,	ICMP_REDIRECT_TOSHOST },
6003 	{ "normal-adv",		ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NORMAL },
6004 	{ "common-adv",		ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NOROUTE_COMMON },
6005 	{ "transit",		ICMP_TIMXCEED,	ICMP_TIMXCEED_INTRANS },
6006 	{ "reassemb",		ICMP_TIMXCEED,	ICMP_TIMXCEED_REASS },
6007 	{ "badhead",		ICMP_PARAMPROB,	ICMP_PARAMPROB_ERRATPTR },
6008 	{ "optmiss",		ICMP_PARAMPROB,	ICMP_PARAMPROB_OPTABSENT },
6009 	{ "badlen",		ICMP_PARAMPROB,	ICMP_PARAMPROB_LENGTH },
6010 	{ "unknown-ind",	ICMP_PHOTURIS,	ICMP_PHOTURIS_UNKNOWN_INDEX },
6011 	{ "auth-fail",		ICMP_PHOTURIS,	ICMP_PHOTURIS_AUTH_FAILED },
6012 	{ "decrypt-fail",	ICMP_PHOTURIS,	ICMP_PHOTURIS_DECRYPT_FAILED },
6013 };
6014 
6015 static const struct icmpcodeent icmp6_code[] = {
6016 	{ "admin-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN },
6017 	{ "noroute-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE },
6018 	{ "beyond-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE },
6019 	{ "addr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR },
6020 	{ "port-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT },
6021 	{ "transit", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT },
6022 	{ "reassemb", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_REASSEMBLY },
6023 	{ "badhead", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER },
6024 	{ "nxthdr", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXTHEADER },
6025 	{ "redironlink", ND_REDIRECT, ND_REDIRECT_ONLINK },
6026 	{ "redirrouter", ND_REDIRECT, ND_REDIRECT_ROUTER },
6027 };
6028 
6029 static int
geticmptypebyname(char * w,uint8_t aid)6030 geticmptypebyname(char *w, uint8_t aid)
6031 {
6032 	size_t	i;
6033 
6034 	switch (aid) {
6035 	case AID_INET:
6036 		for (i = 0; i < nitems(icmp_type); i++) {
6037 			if (!strcmp(w, icmp_type[i].name))
6038 				return (icmp_type[i].type);
6039 		}
6040 		break;
6041 	case AID_INET6:
6042 		for (i = 0; i < nitems(icmp6_type); i++) {
6043 			if (!strcmp(w, icmp6_type[i].name))
6044 				return (icmp6_type[i].type);
6045 		}
6046 		break;
6047 	}
6048 	return -1;
6049 }
6050 
6051 static int
geticmpcodebyname(u_long type,char * w,uint8_t aid)6052 geticmpcodebyname(u_long type, char *w, uint8_t aid)
6053 {
6054 	size_t	i;
6055 
6056 	switch (aid) {
6057 	case AID_INET:
6058 		for (i = 0; i < nitems(icmp_code); i++) {
6059 			if (type == icmp_code[i].type &&
6060 			    !strcmp(w, icmp_code[i].name))
6061 				return (icmp_code[i].code);
6062 		}
6063 		break;
6064 	case AID_INET6:
6065 		for (i = 0; i < nitems(icmp6_code); i++) {
6066 			if (type == icmp6_code[i].type &&
6067 			    !strcmp(w, icmp6_code[i].name))
6068 				return (icmp6_code[i].code);
6069 		}
6070 		break;
6071 	}
6072 	return -1;
6073 }
6074 
6075 static int
merge_auth_conf(struct auth_config * to,struct auth_config * from)6076 merge_auth_conf(struct auth_config *to, struct auth_config *from)
6077 {
6078 	if (to->method != 0) {
6079 		/* extra magic for manual ipsec rules */
6080 		if (to->method == from->method &&
6081 		    (to->method == AUTH_IPSEC_MANUAL_ESP ||
6082 		    to->method == AUTH_IPSEC_MANUAL_AH)) {
6083 			if (to->spi_in == 0 && from->spi_in != 0) {
6084 				to->spi_in = from->spi_in;
6085 				to->auth_alg_in = from->auth_alg_in;
6086 				to->enc_alg_in = from->enc_alg_in;
6087 				memcpy(to->enc_key_in, from->enc_key_in,
6088 				    sizeof(to->enc_key_in));
6089 				to->enc_keylen_in = from->enc_keylen_in;
6090 				to->auth_keylen_in = from->auth_keylen_in;
6091 				return 1;
6092 			} else if (to->spi_out == 0 && from->spi_out != 0) {
6093 				to->spi_out = from->spi_out;
6094 				to->auth_alg_out = from->auth_alg_out;
6095 				to->enc_alg_out = from->enc_alg_out;
6096 				memcpy(to->enc_key_out, from->enc_key_out,
6097 				    sizeof(to->enc_key_out));
6098 				to->enc_keylen_out = from->enc_keylen_out;
6099 				to->auth_keylen_out = from->auth_keylen_out;
6100 				return 1;
6101 			}
6102 		}
6103 		yyerror("auth method cannot be redefined");
6104 		return 0;
6105 	}
6106 	*to = *from;
6107 	return 1;
6108 }
6109 
6110