1 /*	$OpenBSD: parse.y,v 1.415 2021/04/15 13:42:33 bluhm 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_ipsp.h>
32 #include <arpa/inet.h>
33 
34 #include <ctype.h>
35 #include <endian.h>
36 #include <err.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <limits.h>
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <syslog.h>
45 
46 #include "bgpd.h"
47 #include "session.h"
48 #include "rde.h"
49 #include "log.h"
50 
51 TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
52 static struct file {
53 	TAILQ_ENTRY(file)	 entry;
54 	FILE			*stream;
55 	char			*name;
56 	size_t			 ungetpos;
57 	size_t			 ungetsize;
58 	u_char			*ungetbuf;
59 	int			 eof_reached;
60 	int			 lineno;
61 	int			 errors;
62 } *file, *topfile;
63 struct file	*pushfile(const char *, int);
64 int		 popfile(void);
65 int		 check_file_secrecy(int, const char *);
66 int		 yyparse(void);
67 int		 yylex(void);
68 int		 yyerror(const char *, ...)
69     __attribute__((__format__ (printf, 1, 2)))
70     __attribute__((__nonnull__ (1)));
71 int		 kw_cmp(const void *, const void *);
72 int		 lookup(char *);
73 int		 igetc(void);
74 int		 lgetc(int);
75 void		 lungetc(int);
76 int		 findeol(void);
77 
78 TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
79 struct sym {
80 	TAILQ_ENTRY(sym)	 entry;
81 	int			 used;
82 	int			 persist;
83 	char			*nam;
84 	char			*val;
85 };
86 int		 symset(const char *, const char *, int);
87 char		*symget(const char *);
88 
89 static struct bgpd_config	*conf;
90 static struct network_head	*netconf;
91 static struct peer_head		*new_peers, *cur_peers;
92 static struct rtr_config_head	*cur_rtrs;
93 static struct peer		*curpeer;
94 static struct peer		*curgroup;
95 static struct rde_rib		*currib;
96 static struct l3vpn		*curvpn;
97 static struct prefixset		*curpset, *curoset;
98 static struct roa_tree		*curroatree;
99 static struct rtr_config	*currtr;
100 static struct filter_head	*filter_l;
101 static struct filter_head	*peerfilter_l;
102 static struct filter_head	*groupfilter_l;
103 static struct filter_rule	*curpeer_filter[2];
104 static struct filter_rule	*curgroup_filter[2];
105 
106 struct filter_rib_l {
107 	struct filter_rib_l	*next;
108 	char			 name[PEER_DESCR_LEN];
109 };
110 
111 struct filter_peers_l {
112 	struct filter_peers_l	*next;
113 	struct filter_peers	 p;
114 };
115 
116 struct filter_prefix_l {
117 	struct filter_prefix_l	*next;
118 	struct filter_prefix	 p;
119 };
120 
121 struct filter_prefixlen {
122 	enum comp_ops		op;
123 	int			len_min;
124 	int			len_max;
125 };
126 
127 struct filter_as_l {
128 	struct filter_as_l	*next;
129 	struct filter_as	 a;
130 };
131 
132 struct filter_match_l {
133 	struct filter_match	 m;
134 	struct filter_prefix_l	*prefix_l;
135 	struct filter_as_l	*as_l;
136 	struct filter_prefixset	*prefixset;
137 } fmopts;
138 
139 struct peer	*alloc_peer(void);
140 struct peer	*new_peer(void);
141 struct peer	*new_group(void);
142 int		 add_mrtconfig(enum mrt_type, char *, int, struct peer *,
143 		    char *);
144 struct rde_rib	*add_rib(char *);
145 struct rde_rib	*find_rib(char *);
146 int		 rib_add_fib(struct rde_rib *, u_int);
147 int		 get_id(struct peer *);
148 int		 merge_prefixspec(struct filter_prefix *,
149 		    struct filter_prefixlen *);
150 int		 expand_rule(struct filter_rule *, struct filter_rib_l *,
151 		    struct filter_peers_l *, struct filter_match_l *,
152 		    struct filter_set_head *);
153 int		 str2key(char *, char *, size_t);
154 int		 neighbor_consistent(struct peer *);
155 int		 merge_filterset(struct filter_set_head *, struct filter_set *);
156 void		 optimize_filters(struct filter_head *);
157 struct filter_rule	*get_rule(enum action_types);
158 
159 int		 parsecommunity(struct community *, int, char *);
160 int		 parseextcommunity(struct community *, char *,
161 		    char *);
162 static int	 new_as_set(char *);
163 static void	 add_as_set(u_int32_t);
164 static void	 done_as_set(void);
165 static struct prefixset	*new_prefix_set(char *, int);
166 static void	 add_roa_set(struct prefixset_item *, u_int32_t, u_int8_t);
167 static struct rtr_config	*get_rtr(struct bgpd_addr *);
168 static int	 insert_rtr(struct rtr_config *);
169 
170 typedef struct {
171 	union {
172 		long long		 number;
173 		char			*string;
174 		struct bgpd_addr	 addr;
175 		u_int8_t		 u8;
176 		struct filter_rib_l	*filter_rib;
177 		struct filter_peers_l	*filter_peers;
178 		struct filter_match_l	 filter_match;
179 		struct filter_prefixset	*filter_prefixset;
180 		struct filter_prefix_l	*filter_prefix;
181 		struct filter_as_l	*filter_as;
182 		struct filter_set	*filter_set;
183 		struct filter_set_head	*filter_set_head;
184 		struct {
185 			struct bgpd_addr	prefix;
186 			u_int8_t		len;
187 		}			prefix;
188 		struct filter_prefixlen	prefixlen;
189 		struct prefixset_item	*prefixset_item;
190 		struct {
191 			u_int8_t		enc_alg;
192 			char			enc_key[IPSEC_ENC_KEY_LEN];
193 			u_int8_t		enc_key_len;
194 		}			encspec;
195 	} v;
196 	int lineno;
197 } YYSTYPE;
198 
199 %}
200 
201 %token	AS ROUTERID HOLDTIME YMIN LISTEN ON FIBUPDATE FIBPRIORITY RTABLE
202 %token	NONE UNICAST VPN RD EXPORT EXPORTTRGT IMPORTTRGT DEFAULTROUTE
203 %token	RDE RIB EVALUATE IGNORE COMPARE RTR PORT
204 %token	GROUP NEIGHBOR NETWORK
205 %token	EBGP IBGP
206 %token	LOCALAS REMOTEAS DESCR LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART
207 %token	ANNOUNCE CAPABILITIES REFRESH AS4BYTE CONNECTRETRY
208 %token	DEMOTE ENFORCE NEIGHBORAS ASOVERRIDE REFLECTOR DEPEND DOWN
209 %token	DUMP IN OUT SOCKET RESTRICTED
210 %token	LOG TRANSPARENT
211 %token	TCP MD5SIG PASSWORD KEY TTLSECURITY
212 %token	ALLOW DENY MATCH
213 %token	QUICK
214 %token	FROM TO ANY
215 %token	CONNECTED STATIC
216 %token	COMMUNITY EXTCOMMUNITY LARGECOMMUNITY DELETE
217 %token	PREFIX PREFIXLEN PREFIXSET
218 %token	ROASET ORIGINSET OVS
219 %token	ASSET SOURCEAS TRANSITAS PEERAS MAXASLEN MAXASSEQ
220 %token	SET LOCALPREF MED METRIC NEXTHOP REJECT BLACKHOLE NOMODIFY SELF
221 %token	PREPEND_SELF PREPEND_PEER PFTABLE WEIGHT RTLABEL ORIGIN PRIORITY
222 %token	ERROR INCLUDE
223 %token	IPSEC ESP AH SPI IKE
224 %token	IPV4 IPV6
225 %token	QUALIFY VIA
226 %token	NE LE GE XRANGE LONGER MAXLEN
227 %token	<v.string>		STRING
228 %token	<v.number>		NUMBER
229 %type	<v.number>		asnumber as4number as4number_any optnumber
230 %type	<v.number>		espah family safi restart origincode nettype
231 %type	<v.number>		yesno inout restricted validity
232 %type	<v.string>		string
233 %type	<v.addr>		address
234 %type	<v.prefix>		prefix addrspec
235 %type	<v.prefixset_item>	prefixset_item
236 %type	<v.u8>			action quick direction delete community
237 %type	<v.filter_rib>		filter_rib_h filter_rib_l filter_rib
238 %type	<v.filter_peers>	filter_peer filter_peer_l filter_peer_h
239 %type	<v.filter_match>	filter_match filter_elm filter_match_h
240 %type	<v.filter_as>		filter_as filter_as_l filter_as_h
241 %type	<v.filter_as>		filter_as_t filter_as_t_l filter_as_l_h
242 %type	<v.prefixlen>		prefixlenop
243 %type	<v.filter_set>		filter_set_opt
244 %type	<v.filter_set_head>	filter_set filter_set_l
245 %type	<v.filter_prefix>	filter_prefix filter_prefix_l filter_prefix_h
246 %type	<v.filter_prefix>	filter_prefix_m
247 %type	<v.u8>			unaryop equalityop binaryop filter_as_type
248 %type	<v.encspec>		encspec
249 %%
250 
251 grammar		: /* empty */
252 		| grammar '\n'
253 		| grammar varset '\n'
254 		| grammar include '\n'
255 		| grammar as_set '\n'
256 		| grammar prefixset '\n'
257 		| grammar roa_set '\n'
258 		| grammar origin_set '\n'
259 		| grammar rtr '\n'
260 		| grammar rib '\n'
261 		| grammar conf_main '\n'
262 		| grammar l3vpn '\n'
263 		| grammar neighbor '\n'
264 		| grammar group '\n'
265 		| grammar filterrule '\n'
266 		| grammar error '\n'		{ file->errors++; }
267 		;
268 
269 asnumber	: NUMBER			{
270 			/*
271 			 * According to iana 65535 and 4294967295 are reserved
272 			 * but enforcing this is not duty of the parser.
273 			 */
274 			if ($1 < 0 || $1 > UINT_MAX) {
275 				yyerror("AS too big: max %u", UINT_MAX);
276 				YYERROR;
277 			}
278 		}
279 
280 as4number	: STRING			{
281 			const char	*errstr;
282 			char		*dot;
283 			u_int32_t	 uvalh = 0, uval;
284 
285 			if ((dot = strchr($1,'.')) != NULL) {
286 				*dot++ = '\0';
287 				uvalh = strtonum($1, 0, USHRT_MAX, &errstr);
288 				if (errstr) {
289 					yyerror("number %s is %s", $1, errstr);
290 					free($1);
291 					YYERROR;
292 				}
293 				uval = strtonum(dot, 0, USHRT_MAX, &errstr);
294 				if (errstr) {
295 					yyerror("number %s is %s", dot, errstr);
296 					free($1);
297 					YYERROR;
298 				}
299 				free($1);
300 			} else {
301 				yyerror("AS %s is bad", $1);
302 				free($1);
303 				YYERROR;
304 			}
305 			if (uvalh == 0 && (uval == AS_TRANS || uval == 0)) {
306 				yyerror("AS %u is reserved and may not be used",
307 				    uval);
308 				YYERROR;
309 			}
310 			$$ = uval | (uvalh << 16);
311 		}
312 		| asnumber {
313 			if ($1 == AS_TRANS || $1 == 0) {
314 				yyerror("AS %u is reserved and may not be used",
315 				    (u_int32_t)$1);
316 				YYERROR;
317 			}
318 			$$ = $1;
319 		}
320 		;
321 
322 as4number_any	: STRING			{
323 			const char	*errstr;
324 			char		*dot;
325 			u_int32_t	 uvalh = 0, uval;
326 
327 			if ((dot = strchr($1,'.')) != NULL) {
328 				*dot++ = '\0';
329 				uvalh = strtonum($1, 0, USHRT_MAX, &errstr);
330 				if (errstr) {
331 					yyerror("number %s is %s", $1, errstr);
332 					free($1);
333 					YYERROR;
334 				}
335 				uval = strtonum(dot, 0, USHRT_MAX, &errstr);
336 				if (errstr) {
337 					yyerror("number %s is %s", dot, errstr);
338 					free($1);
339 					YYERROR;
340 				}
341 				free($1);
342 			} else {
343 				yyerror("AS %s is bad", $1);
344 				free($1);
345 				YYERROR;
346 			}
347 			$$ = uval | (uvalh << 16);
348 		}
349 		| asnumber {
350 			$$ = $1;
351 		}
352 		;
353 
354 string		: string STRING			{
355 			if (asprintf(&$$, "%s %s", $1, $2) == -1)
356 				fatal("string: asprintf");
357 			free($1);
358 			free($2);
359 		}
360 		| STRING
361 		;
362 
363 yesno		:  STRING			{
364 			if (!strcmp($1, "yes"))
365 				$$ = 1;
366 			else if (!strcmp($1, "no"))
367 				$$ = 0;
368 			else {
369 				yyerror("syntax error, "
370 				    "either yes or no expected");
371 				free($1);
372 				YYERROR;
373 			}
374 			free($1);
375 		}
376 		;
377 
378 varset		: STRING '=' string		{
379 			char *s = $1;
380 			if (cmd_opts & BGPD_OPT_VERBOSE)
381 				printf("%s = \"%s\"\n", $1, $3);
382 			while (*s++) {
383 				if (isspace((unsigned char)*s)) {
384 					yyerror("macro name cannot contain "
385 					    "whitespace");
386 					free($1);
387 					free($3);
388 					YYERROR;
389 				}
390 			}
391 			if (symset($1, $3, 0) == -1)
392 				fatal("cannot store variable");
393 			free($1);
394 			free($3);
395 		}
396 		;
397 
398 include		: INCLUDE STRING		{
399 			struct file	*nfile;
400 
401 			if ((nfile = pushfile($2, 1)) == NULL) {
402 				yyerror("failed to include file %s", $2);
403 				free($2);
404 				YYERROR;
405 			}
406 			free($2);
407 
408 			file = nfile;
409 			lungetc('\n');
410 		}
411 		;
412 
413 as_set		: ASSET STRING '{' optnl	{
414 			if (strlen($2) >= SET_NAME_LEN) {
415 				yyerror("as-set name %s too long", $2);
416 				free($2);
417 				YYERROR;
418 			}
419 			if (new_as_set($2) != 0) {
420 				free($2);
421 				YYERROR;
422 			}
423 			free($2);
424 		} as_set_l optnl '}' {
425 			done_as_set();
426 		}
427 		| ASSET STRING '{' optnl '}'	{
428 			if (new_as_set($2) != 0) {
429 				free($2);
430 				YYERROR;
431 			}
432 			free($2);
433 		}
434 
435 as_set_l	: as4number_any			{ add_as_set($1); }
436 		| as_set_l comma as4number_any	{ add_as_set($3); }
437 
438 prefixset	: PREFIXSET STRING '{' optnl		{
439 			if ((curpset = new_prefix_set($2, 0)) == NULL) {
440 				free($2);
441 				YYERROR;
442 			}
443 			free($2);
444 		} prefixset_l optnl '}'			{
445 			SIMPLEQ_INSERT_TAIL(&conf->prefixsets, curpset, entry);
446 			curpset = NULL;
447 		}
448 		| PREFIXSET STRING '{' optnl '}'	{
449 			if ((curpset = new_prefix_set($2, 0)) == NULL) {
450 				free($2);
451 				YYERROR;
452 			}
453 			free($2);
454 			SIMPLEQ_INSERT_TAIL(&conf->prefixsets, curpset, entry);
455 			curpset = NULL;
456 		}
457 
458 prefixset_l	: prefixset_item			{
459 			struct prefixset_item	*psi;
460 			if ($1->p.op != OP_NONE)
461 				curpset->sflags |= PREFIXSET_FLAG_OPS;
462 			psi = RB_INSERT(prefixset_tree, &curpset->psitems, $1);
463 			if (psi != NULL) {
464 				if (cmd_opts & BGPD_OPT_VERBOSE2)
465 					log_warnx("warning: duplicate entry in "
466 					    "prefixset \"%s\" for %s/%u",
467 					    curpset->name,
468 					    log_addr(&$1->p.addr), $1->p.len);
469 				free($1);
470 			}
471 		}
472 		| prefixset_l comma prefixset_item	{
473 			struct prefixset_item	*psi;
474 			if ($3->p.op != OP_NONE)
475 				curpset->sflags |= PREFIXSET_FLAG_OPS;
476 			psi = RB_INSERT(prefixset_tree, &curpset->psitems, $3);
477 			if (psi != NULL) {
478 				if (cmd_opts & BGPD_OPT_VERBOSE2)
479 					log_warnx("warning: duplicate entry in "
480 					    "prefixset \"%s\" for %s/%u",
481 					    curpset->name,
482 					    log_addr(&$3->p.addr), $3->p.len);
483 				free($3);
484 			}
485 		}
486 		;
487 
488 prefixset_item	: prefix prefixlenop			{
489 			if ($2.op != OP_NONE && $2.op != OP_RANGE) {
490 				yyerror("unsupported prefixlen operation in "
491 				    "prefix-set");
492 				YYERROR;
493 			}
494 			if (($$ = calloc(1, sizeof(*$$))) == NULL)
495 				fatal(NULL);
496 			memcpy(&$$->p.addr, &$1.prefix, sizeof($$->p.addr));
497 			$$->p.len = $1.len;
498 			if (merge_prefixspec(&$$->p, &$2) == -1) {
499 				free($$);
500 				YYERROR;
501 			}
502 		}
503 		;
504 
505 roa_set		: ROASET '{' optnl		{
506 			curroatree = &conf->roa;
507 		} roa_set_l optnl '}'			{
508 			curroatree = NULL;
509 		}
510 		| ROASET '{' optnl '}'		/* nothing */
511 		;
512 
513 origin_set	: ORIGINSET STRING '{' optnl		{
514 			if ((curoset = new_prefix_set($2, 1)) == NULL) {
515 				free($2);
516 				YYERROR;
517 			}
518 			curroatree = &curoset->roaitems;
519 			free($2);
520 		} roa_set_l optnl '}'			{
521 			SIMPLEQ_INSERT_TAIL(&conf->originsets, curoset, entry);
522 			curoset = NULL;
523 			curroatree = NULL;
524 		}
525 		| ORIGINSET STRING '{' optnl '}'		{
526 			if ((curoset = new_prefix_set($2, 1)) == NULL) {
527 				free($2);
528 				YYERROR;
529 			}
530 			free($2);
531 			SIMPLEQ_INSERT_TAIL(&conf->originsets, curoset, entry);
532 			curoset = NULL;
533 			curroatree = NULL;
534 		}
535 		;
536 
537 roa_set_l	: prefixset_item SOURCEAS as4number_any			{
538 			if ($1->p.len_min != $1->p.len) {
539 				yyerror("unsupported prefixlen operation in "
540 				    "roa-set");
541 				free($1);
542 				YYERROR;
543 			}
544 			add_roa_set($1, $3, $1->p.len_max);
545 			free($1);
546 		}
547 		| roa_set_l comma prefixset_item SOURCEAS as4number_any	{
548 			if ($3->p.len_min != $3->p.len) {
549 				yyerror("unsupported prefixlen operation in "
550 				    "roa-set");
551 				free($3);
552 				YYERROR;
553 			}
554 			add_roa_set($3, $5, $3->p.len_max);
555 			free($3);
556 		}
557 		;
558 
559 rtr		: RTR address	{
560 			currtr = get_rtr(&$2);
561 			currtr->remote_port = 323;
562 			if (insert_rtr(currtr) == -1) {
563 				free(currtr);
564 				YYERROR;
565 			}
566 			currtr = NULL;
567 		}
568 		| RTR address	{
569 			currtr = get_rtr(&$2);
570 			currtr->remote_port = 323;
571 		} '{' optnl rtropt_l optnl '}' {
572 			if (insert_rtr(currtr) == -1) {
573 				free(currtr);
574 				YYERROR;
575 			}
576 			currtr = NULL;
577 		}
578 		;
579 
580 rtropt_l	: rtropt
581 		| rtropt_l optnl rtropt
582 
583 rtropt		: DESCR STRING		{
584 			if (strlcpy(currtr->descr, $2,
585 			    sizeof(currtr->descr)) >=
586 			    sizeof(currtr->descr)) {
587 				yyerror("descr \"%s\" too long: max %zu",
588 				    $2, sizeof(currtr->descr) - 1);
589 				free($2);
590 				YYERROR;
591 			}
592 			free($2);
593 		}
594 		| LOCALADDR address	{
595 			if ($2.aid != currtr->remote_addr.aid) {
596 				yyerror("Bad address family %s for "
597 				    "local-addr", aid2str($2.aid));
598 				YYERROR;
599 			}
600 			currtr->local_addr = $2;
601 		}
602 		| PORT NUMBER {
603 			if ($2 < 1 || $2 > USHRT_MAX) {
604 				yyerror("local-port must be between %u and %u",
605 				    1, USHRT_MAX);
606 				YYERROR;
607 			}
608 			currtr->remote_port = $2;
609 		}
610 		;
611 
612 conf_main	: AS as4number		{
613 			conf->as = $2;
614 			if ($2 > USHRT_MAX)
615 				conf->short_as = AS_TRANS;
616 			else
617 				conf->short_as = $2;
618 		}
619 		| AS as4number asnumber {
620 			conf->as = $2;
621 			conf->short_as = $3;
622 		}
623 		| ROUTERID address		{
624 			if ($2.aid != AID_INET) {
625 				yyerror("router-id must be an IPv4 address");
626 				YYERROR;
627 			}
628 			conf->bgpid = $2.v4.s_addr;
629 		}
630 		| HOLDTIME NUMBER	{
631 			if ($2 < MIN_HOLDTIME || $2 > USHRT_MAX) {
632 				yyerror("holdtime must be between %u and %u",
633 				    MIN_HOLDTIME, USHRT_MAX);
634 				YYERROR;
635 			}
636 			conf->holdtime = $2;
637 		}
638 		| HOLDTIME YMIN NUMBER	{
639 			if ($3 < MIN_HOLDTIME || $3 > USHRT_MAX) {
640 				yyerror("holdtime must be between %u and %u",
641 				    MIN_HOLDTIME, USHRT_MAX);
642 				YYERROR;
643 			}
644 			conf->min_holdtime = $3;
645 		}
646 		| LISTEN ON address	{
647 			struct listen_addr	*la;
648 			struct sockaddr		*sa;
649 
650 			if ((la = calloc(1, sizeof(struct listen_addr))) ==
651 			    NULL)
652 				fatal("parse conf_main listen on calloc");
653 
654 			la->fd = -1;
655 			la->reconf = RECONF_REINIT;
656 			sa = addr2sa(&$3, BGP_PORT, &la->sa_len);
657 			memcpy(&la->sa, sa, la->sa_len);
658 			TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry);
659 		}
660 		| FIBPRIORITY NUMBER		{
661 			if ($2 <= RTP_NONE || $2 > RTP_MAX) {
662 				yyerror("invalid fib-priority");
663 				YYERROR;
664 			}
665 			conf->fib_priority = $2;
666 		}
667 		| FIBUPDATE yesno		{
668 			struct rde_rib *rr;
669 			rr = find_rib("Loc-RIB");
670 			if (rr == NULL)
671 				fatalx("RTABLE can not find the main RIB!");
672 
673 			if ($2 == 0)
674 				rr->flags |= F_RIB_NOFIBSYNC;
675 			else
676 				rr->flags &= ~F_RIB_NOFIBSYNC;
677 		}
678 		| TRANSPARENT yesno	{
679 			if ($2 == 1)
680 				conf->flags |= BGPD_FLAG_DECISION_TRANS_AS;
681 			else
682 				conf->flags &= ~BGPD_FLAG_DECISION_TRANS_AS;
683 		}
684 		| REJECT ASSET yesno	{
685 			if ($3 == 1)
686 				conf->flags |= BGPD_FLAG_NO_AS_SET;
687 			else
688 				conf->flags &= ~BGPD_FLAG_NO_AS_SET;
689 		}
690 		| LOG STRING		{
691 			if (!strcmp($2, "updates"))
692 				conf->log |= BGPD_LOG_UPDATES;
693 			else {
694 				free($2);
695 				YYERROR;
696 			}
697 			free($2);
698 		}
699 		| network
700 		| DUMP STRING STRING optnumber		{
701 			int action;
702 
703 			if ($4 < 0 || $4 > INT_MAX) {
704 				yyerror("bad timeout");
705 				free($2);
706 				free($3);
707 				YYERROR;
708 			}
709 			if (!strcmp($2, "table"))
710 				action = MRT_TABLE_DUMP;
711 			else if (!strcmp($2, "table-mp"))
712 				action = MRT_TABLE_DUMP_MP;
713 			else if (!strcmp($2, "table-v2"))
714 				action = MRT_TABLE_DUMP_V2;
715 			else {
716 				yyerror("unknown mrt dump type");
717 				free($2);
718 				free($3);
719 				YYERROR;
720 			}
721 			free($2);
722 			if (add_mrtconfig(action, $3, $4, NULL, NULL) == -1) {
723 				free($3);
724 				YYERROR;
725 			}
726 			free($3);
727 		}
728 		| DUMP RIB STRING STRING STRING optnumber		{
729 			int action;
730 
731 			if ($6 < 0 || $6 > INT_MAX) {
732 				yyerror("bad timeout");
733 				free($3);
734 				free($4);
735 				free($5);
736 				YYERROR;
737 			}
738 			if (!strcmp($4, "table"))
739 				action = MRT_TABLE_DUMP;
740 			else if (!strcmp($4, "table-mp"))
741 				action = MRT_TABLE_DUMP_MP;
742 			else if (!strcmp($4, "table-v2"))
743 				action = MRT_TABLE_DUMP_V2;
744 			else {
745 				yyerror("unknown mrt dump type");
746 				free($3);
747 				free($4);
748 				free($5);
749 				YYERROR;
750 			}
751 			free($4);
752 			if (add_mrtconfig(action, $5, $6, NULL, $3) == -1) {
753 				free($3);
754 				free($5);
755 				YYERROR;
756 			}
757 			free($3);
758 			free($5);
759 		}
760 		| mrtdump
761 		| RDE STRING EVALUATE		{
762 			if (!strcmp($2, "route-age"))
763 				conf->flags |= BGPD_FLAG_DECISION_ROUTEAGE;
764 			else {
765 				yyerror("unknown route decision type");
766 				free($2);
767 				YYERROR;
768 			}
769 			free($2);
770 		}
771 		| RDE STRING IGNORE		{
772 			if (!strcmp($2, "route-age"))
773 				conf->flags &= ~BGPD_FLAG_DECISION_ROUTEAGE;
774 			else {
775 				yyerror("unknown route decision type");
776 				free($2);
777 				YYERROR;
778 			}
779 			free($2);
780 		}
781 		| RDE MED COMPARE STRING	{
782 			if (!strcmp($4, "always"))
783 				conf->flags |= BGPD_FLAG_DECISION_MED_ALWAYS;
784 			else if (!strcmp($4, "strict"))
785 				conf->flags &= ~BGPD_FLAG_DECISION_MED_ALWAYS;
786 			else {
787 				yyerror("rde med compare: "
788 				    "unknown setting \"%s\"", $4);
789 				free($4);
790 				YYERROR;
791 			}
792 			free($4);
793 		}
794 		| RDE EVALUATE STRING {
795 			if (!strcmp($3, "all"))
796 				conf->flags |= BGPD_FLAG_DECISION_ALL_PATHS;
797 			else if (!strcmp($3, "default"))
798 				conf->flags &= ~BGPD_FLAG_DECISION_ALL_PATHS;
799 			else {
800 				yyerror("rde evaluate: "
801 				    "unknown setting \"%s\"", $3);
802 				free($3);
803 				YYERROR;
804 			}
805 			free($3);
806 		}
807 		| NEXTHOP QUALIFY VIA STRING	{
808 			if (!strcmp($4, "bgp"))
809 				conf->flags |= BGPD_FLAG_NEXTHOP_BGP;
810 			else if (!strcmp($4, "default"))
811 				conf->flags |= BGPD_FLAG_NEXTHOP_DEFAULT;
812 			else {
813 				yyerror("nexthop depend on: "
814 				    "unknown setting \"%s\"", $4);
815 				free($4);
816 				YYERROR;
817 			}
818 			free($4);
819 		}
820 		| RTABLE NUMBER {
821 			struct rde_rib *rr;
822 			if ($2 > RT_TABLEID_MAX) {
823 				yyerror("rtable %llu too big: max %u", $2,
824 				    RT_TABLEID_MAX);
825 				YYERROR;
826 			}
827 			if (ktable_exists($2, NULL) != 1) {
828 				yyerror("rtable id %lld does not exist", $2);
829 				YYERROR;
830 			}
831 			rr = find_rib("Loc-RIB");
832 			if (rr == NULL)
833 				fatalx("RTABLE can not find the main RIB!");
834 			rr->rtableid = $2;
835 		}
836 		| CONNECTRETRY NUMBER {
837 			if ($2 > USHRT_MAX || $2 < 1) {
838 				yyerror("invalid connect-retry");
839 				YYERROR;
840 			}
841 			conf->connectretry = $2;
842 		}
843 		| SOCKET STRING	restricted {
844 			if (strlen($2) >=
845 			    sizeof(((struct sockaddr_un *)0)->sun_path)) {
846 				yyerror("socket path too long");
847 				YYERROR;
848 			}
849 			if ($3) {
850 				free(conf->rcsock);
851 				conf->rcsock = $2;
852 			} else {
853 				free(conf->csock);
854 				conf->csock = $2;
855 			}
856 		}
857 		;
858 
859 rib		: RDE RIB STRING {
860 			if ((currib = add_rib($3)) == NULL) {
861 				free($3);
862 				YYERROR;
863 			}
864 			free($3);
865 		} ribopts {
866 			currib = NULL;
867 		}
868 
869 ribopts		: fibupdate
870 		| RTABLE NUMBER fibupdate {
871 			if ($2 > RT_TABLEID_MAX) {
872 				yyerror("rtable %llu too big: max %u", $2,
873 				    RT_TABLEID_MAX);
874 				YYERROR;
875 			}
876 			if (rib_add_fib(currib, $2) == -1)
877 				YYERROR;
878 		}
879 		| yesno EVALUATE {
880 			if ($1) {
881 				yyerror("bad rde rib definition");
882 				YYERROR;
883 			}
884 			currib->flags |= F_RIB_NOEVALUATE;
885 		}
886 		;
887 
888 fibupdate	: /* empty */
889 		| FIBUPDATE yesno {
890 			if ($2 == 0)
891 				currib->flags |= F_RIB_NOFIBSYNC;
892 			else
893 				currib->flags &= ~F_RIB_NOFIBSYNC;
894 		}
895 		;
896 
897 mrtdump		: DUMP STRING inout STRING optnumber	{
898 			int action;
899 
900 			if ($5 < 0 || $5 > INT_MAX) {
901 				yyerror("bad timeout");
902 				free($2);
903 				free($4);
904 				YYERROR;
905 			}
906 			if (!strcmp($2, "all"))
907 				action = $3 ? MRT_ALL_IN : MRT_ALL_OUT;
908 			else if (!strcmp($2, "updates"))
909 				action = $3 ? MRT_UPDATE_IN : MRT_UPDATE_OUT;
910 			else {
911 				yyerror("unknown mrt msg dump type");
912 				free($2);
913 				free($4);
914 				YYERROR;
915 			}
916 			if (add_mrtconfig(action, $4, $5, curpeer, NULL) ==
917 			    -1) {
918 				free($2);
919 				free($4);
920 				YYERROR;
921 			}
922 			free($2);
923 			free($4);
924 		}
925 		;
926 
927 network		: NETWORK prefix filter_set	{
928 			struct network	*n, *m;
929 
930 			if ((n = calloc(1, sizeof(struct network))) == NULL)
931 				fatal("new_network");
932 			memcpy(&n->net.prefix, &$2.prefix,
933 			    sizeof(n->net.prefix));
934 			n->net.prefixlen = $2.len;
935 			filterset_move($3, &n->net.attrset);
936 			free($3);
TAILQ_FOREACH(m,netconf,entry)937 			TAILQ_FOREACH(m, netconf, entry) {
938 				if (n->net.type == m->net.type &&
939 				    n->net.prefixlen == m->net.prefixlen &&
940 				    prefix_compare(&n->net.prefix,
941 				    &m->net.prefix, n->net.prefixlen) == 0)
942 					yyerror("duplicate prefix "
943 					    "in network statement");
944 			}
945 
946 			TAILQ_INSERT_TAIL(netconf, n, entry);
947 		}
948 		| NETWORK PREFIXSET STRING filter_set	{
949 			struct prefixset *ps;
950 			struct network	*n;
951 			if ((ps = find_prefixset($3, &conf->prefixsets))
952 			    == NULL) {
953 				yyerror("prefix-set '%s' not defined", $3);
954 				free($3);
955 				filterset_free($4);
956 				free($4);
957 				YYERROR;
958 			}
959 			if (ps->sflags & PREFIXSET_FLAG_OPS) {
960 				yyerror("prefix-set %s has prefixlen operators "
961 				    "and cannot be used in network statements.",
962 				    ps->name);
963 				free($3);
964 				filterset_free($4);
965 				free($4);
966 				YYERROR;
967 			}
968 			if ((n = calloc(1, sizeof(struct network))) == NULL)
969 				fatal("new_network");
970 			strlcpy(n->net.psname, ps->name, sizeof(n->net.psname));
971 			filterset_move($4, &n->net.attrset);
972 			n->net.type = NETWORK_PREFIXSET;
973 			TAILQ_INSERT_TAIL(netconf, n, entry);
974 			free($3);
975 			free($4);
976 		}
977 		| NETWORK family RTLABEL STRING filter_set	{
978 			struct network	*n;
979 
980 			if ((n = calloc(1, sizeof(struct network))) == NULL)
981 				fatal("new_network");
982 			if (afi2aid($2, SAFI_UNICAST, &n->net.prefix.aid) ==
983 			    -1) {
984 				yyerror("unknown family");
985 				filterset_free($5);
986 				free($5);
987 				YYERROR;
988 			}
989 			n->net.type = NETWORK_RTLABEL;
990 			n->net.rtlabel = rtlabel_name2id($4);
991 			filterset_move($5, &n->net.attrset);
992 			free($5);
993 
994 			TAILQ_INSERT_TAIL(netconf, n, entry);
995 		}
996 		| NETWORK family PRIORITY NUMBER filter_set	{
997 			struct network	*n;
998 			if ($4 < RTP_LOCAL && $4 > RTP_MAX) {
999 				yyerror("priority %lld > max %d or < min %d", $4,
1000 				    RTP_MAX, RTP_LOCAL);
1001 				YYERROR;
1002 			}
1003 
1004 			if ((n = calloc(1, sizeof(struct network))) == NULL)
1005 				fatal("new_network");
1006 			if (afi2aid($2, SAFI_UNICAST, &n->net.prefix.aid) ==
1007 			    -1) {
1008 				yyerror("unknown family");
1009 				filterset_free($5);
1010 				free($5);
1011 				YYERROR;
1012 			}
1013 			n->net.type = NETWORK_PRIORITY;
1014 			n->net.priority = $4;
1015 			filterset_move($5, &n->net.attrset);
1016 			free($5);
1017 
1018 			TAILQ_INSERT_TAIL(netconf, n, entry);
1019 		}
1020 		| NETWORK family nettype filter_set	{
1021 			struct network	*n;
1022 
1023 			if ((n = calloc(1, sizeof(struct network))) == NULL)
1024 				fatal("new_network");
1025 			if (afi2aid($2, SAFI_UNICAST, &n->net.prefix.aid) ==
1026 			    -1) {
1027 				yyerror("unknown family");
1028 				filterset_free($4);
1029 				free($4);
1030 				YYERROR;
1031 			}
1032 			n->net.type = $3 ? NETWORK_STATIC : NETWORK_CONNECTED;
1033 			filterset_move($4, &n->net.attrset);
1034 			free($4);
1035 
1036 			TAILQ_INSERT_TAIL(netconf, n, entry);
1037 		}
1038 		;
1039 
1040 inout		: IN		{ $$ = 1; }
1041 		| OUT		{ $$ = 0; }
1042 		;
1043 
1044 restricted	: RESTRICTED	{ $$ = 1; }
1045 		| /* nothing */	{ $$ = 0; }
1046 		;
1047 
1048 address		: STRING		{
1049 			u_int8_t	len;
1050 
1051 			if (!host($1, &$$, &len)) {
1052 				yyerror("could not parse address spec \"%s\"",
1053 				    $1);
1054 				free($1);
1055 				YYERROR;
1056 			}
1057 			free($1);
1058 
1059 			if (($$.aid == AID_INET && len != 32) ||
1060 			    ($$.aid == AID_INET6 && len != 128)) {
1061 				/* unreachable */
1062 				yyerror("got prefixlen %u, expected %u",
1063 				    len, $$.aid == AID_INET ? 32 : 128);
1064 				YYERROR;
1065 			}
1066 		}
1067 		;
1068 
1069 prefix		: STRING '/' NUMBER	{
1070 			char	*s;
1071 			if ($3 < 0 || $3 > 128) {
1072 				yyerror("bad prefixlen %lld", $3);
1073 				free($1);
1074 				YYERROR;
1075 			}
1076 			if (asprintf(&s, "%s/%lld", $1, $3) == -1)
1077 				fatal(NULL);
1078 			free($1);
1079 
1080 			if (!host(s, &$$.prefix, &$$.len)) {
1081 				yyerror("could not parse address \"%s\"", s);
1082 				free(s);
1083 				YYERROR;
1084 			}
1085 			free(s);
1086 		}
1087 		| NUMBER '/' NUMBER	{
1088 			char	*s;
1089 
1090 			/* does not match IPv6 */
1091 			if ($1 < 0 || $1 > 255 || $3 < 0 || $3 > 32) {
1092 				yyerror("bad prefix %lld/%lld", $1, $3);
1093 				YYERROR;
1094 			}
1095 			if (asprintf(&s, "%lld/%lld", $1, $3) == -1)
1096 				fatal(NULL);
1097 
1098 			if (!host(s, &$$.prefix, &$$.len)) {
1099 				yyerror("could not parse address \"%s\"", s);
1100 				free(s);
1101 				YYERROR;
1102 			}
1103 			free(s);
1104 		}
1105 		;
1106 
1107 addrspec	: address	{
1108 			memcpy(&$$.prefix, &$1, sizeof(struct bgpd_addr));
1109 			if ($$.prefix.aid == AID_INET)
1110 				$$.len = 32;
1111 			else
1112 				$$.len = 128;
1113 		}
1114 		| prefix
1115 		;
1116 
1117 optnumber	: /* empty */		{ $$ = 0; }
1118 		| NUMBER
1119 		;
1120 
1121 l3vpn		: VPN STRING ON STRING			{
1122 			u_int rdomain, label;
1123 
1124 			if (get_mpe_config($4, &rdomain, &label) == -1) {
1125 				if ((cmd_opts & BGPD_OPT_NOACTION) == 0) {
1126 					yyerror("troubles getting config of %s",
1127 					    $4);
1128 					free($4);
1129 					free($2);
1130 					YYERROR;
1131 				}
1132 			}
1133 
1134 			if (!(curvpn = calloc(1, sizeof(struct l3vpn))))
1135 				fatal(NULL);
1136 			strlcpy(curvpn->ifmpe, $4, IFNAMSIZ);
1137 
1138 			if (strlcpy(curvpn->descr, $2,
1139 			    sizeof(curvpn->descr)) >=
1140 			    sizeof(curvpn->descr)) {
1141 				yyerror("descr \"%s\" too long: max %zu",
1142 				    $2, sizeof(curvpn->descr) - 1);
1143 				free($2);
1144 				free($4);
1145 				free(curvpn);
1146 				curvpn = NULL;
1147 				YYERROR;
1148 			}
1149 			free($2);
1150 			free($4);
1151 
1152 			TAILQ_INIT(&curvpn->import);
1153 			TAILQ_INIT(&curvpn->export);
1154 			TAILQ_INIT(&curvpn->net_l);
1155 			curvpn->label = label;
1156 			curvpn->rtableid = rdomain;
1157 			netconf = &curvpn->net_l;
1158 		} '{' l3vpnopts_l '}'	{
1159 			/* insert into list */
1160 			SIMPLEQ_INSERT_TAIL(&conf->l3vpns, curvpn, entry);
1161 			curvpn = NULL;
1162 			netconf = &conf->networks;
1163 		}
1164 		;
1165 
1166 l3vpnopts_l	: /* empty */
1167 		| l3vpnopts_l '\n'
1168 		| l3vpnopts_l l3vpnopts '\n'
1169 		| l3vpnopts_l error '\n'
1170 		;
1171 
1172 l3vpnopts	: RD STRING {
1173 			struct community	ext;
1174 
1175 			memset(&ext, 0, sizeof(ext));
1176 			if (parseextcommunity(&ext, "rt", $2) == -1) {
1177 				free($2);
1178 				YYERROR;
1179 			}
1180 			free($2);
1181 			/*
1182 			 * RD is almost encoded like an ext-community,
1183 			 * but only almost so convert here.
1184 			 */
1185 			if (community_to_rd(&ext, &curvpn->rd) == -1) {
1186 				yyerror("bad encoding of rd");
1187 				YYERROR;
1188 			}
1189 		}
1190 		| EXPORTTRGT STRING STRING	{
1191 			struct filter_set	*set;
1192 
1193 			if ((set = calloc(1, sizeof(struct filter_set))) ==
1194 			    NULL)
1195 				fatal(NULL);
1196 			set->type = ACTION_SET_COMMUNITY;
1197 			if (parseextcommunity(&set->action.community,
1198 			    $2, $3) == -1) {
1199 				free($3);
1200 				free($2);
1201 				free(set);
1202 				YYERROR;
1203 			}
1204 			free($3);
1205 			free($2);
1206 			TAILQ_INSERT_TAIL(&curvpn->export, set, entry);
1207 		}
1208 		| IMPORTTRGT STRING STRING	{
1209 			struct filter_set	*set;
1210 
1211 			if ((set = calloc(1, sizeof(struct filter_set))) ==
1212 			    NULL)
1213 				fatal(NULL);
1214 			set->type = ACTION_SET_COMMUNITY;
1215 			if (parseextcommunity(&set->action.community,
1216 			    $2, $3) == -1) {
1217 				free($3);
1218 				free($2);
1219 				free(set);
1220 				YYERROR;
1221 			}
1222 			free($3);
1223 			free($2);
1224 			TAILQ_INSERT_TAIL(&curvpn->import, set, entry);
1225 		}
1226 		| FIBUPDATE yesno		{
1227 			if ($2 == 0)
1228 				curvpn->flags |= F_RIB_NOFIBSYNC;
1229 			else
1230 				curvpn->flags &= ~F_RIB_NOFIBSYNC;
1231 		}
1232 		| network
1233 		;
1234 
1235 neighbor	: {	curpeer = new_peer(); }
1236 		    NEIGHBOR addrspec {
1237 			memcpy(&curpeer->conf.remote_addr, &$3.prefix,
1238 			    sizeof(curpeer->conf.remote_addr));
1239 			curpeer->conf.remote_masklen = $3.len;
1240 			if (($3.prefix.aid == AID_INET && $3.len != 32) ||
1241 			    ($3.prefix.aid == AID_INET6 && $3.len != 128))
1242 				curpeer->conf.template = 1;
1243 			curpeer->conf.capabilities.mp[
1244 			    curpeer->conf.remote_addr.aid] = 1;
1245 			if (get_id(curpeer)) {
1246 				yyerror("get_id failed");
1247 				YYERROR;
1248 			}
1249 		}
1250 		    peeropts_h {
1251 			if (curpeer_filter[0] != NULL)
1252 				TAILQ_INSERT_TAIL(peerfilter_l,
1253 				    curpeer_filter[0], entry);
1254 			if (curpeer_filter[1] != NULL)
1255 				TAILQ_INSERT_TAIL(peerfilter_l,
1256 				    curpeer_filter[1], entry);
1257 			curpeer_filter[0] = NULL;
1258 			curpeer_filter[1] = NULL;
1259 
1260 			if (neighbor_consistent(curpeer) == -1) {
1261 				free(curpeer);
1262 				YYERROR;
1263 			}
1264 			if (RB_INSERT(peer_head, new_peers, curpeer) != NULL)
1265 				fatalx("%s: peer tree is corrupt", __func__);
1266 			curpeer = curgroup;
1267 		}
1268 		;
1269 
1270 group		: GROUP string			{
1271 			curgroup = curpeer = new_group();
1272 			if (strlcpy(curgroup->conf.group, $2,
1273 			    sizeof(curgroup->conf.group)) >=
1274 			    sizeof(curgroup->conf.group)) {
1275 				yyerror("group name \"%s\" too long: max %zu",
1276 				    $2, sizeof(curgroup->conf.group) - 1);
1277 				free($2);
1278 				free(curgroup);
1279 				YYERROR;
1280 			}
1281 			free($2);
1282 			if (get_id(curgroup)) {
1283 				yyerror("get_id failed");
1284 				free(curgroup);
1285 				YYERROR;
1286 			}
1287 		} '{' groupopts_l '}'		{
1288 			if (curgroup_filter[0] != NULL)
1289 				TAILQ_INSERT_TAIL(groupfilter_l,
1290 				    curgroup_filter[0], entry);
1291 			if (curgroup_filter[1] != NULL)
1292 				TAILQ_INSERT_TAIL(groupfilter_l,
1293 				    curgroup_filter[1], entry);
1294 			curgroup_filter[0] = NULL;
1295 			curgroup_filter[1] = NULL;
1296 
1297 			free(curgroup);
1298 			curgroup = NULL;
1299 		}
1300 		;
1301 
1302 groupopts_l	: /* empty */
1303 		| groupopts_l '\n'
1304 		| groupopts_l peeropts '\n'
1305 		| groupopts_l neighbor '\n'
1306 		| groupopts_l error '\n'
1307 		;
1308 
1309 peeropts_h	: '{' '\n' peeropts_l '}'
1310 		| '{' peeropts '}'
1311 		| /* empty */
1312 		;
1313 
1314 peeropts_l	: /* empty */
1315 		| peeropts_l '\n'
1316 		| peeropts_l peeropts '\n'
1317 		| peeropts_l error '\n'
1318 		;
1319 
1320 peeropts	: REMOTEAS as4number	{
1321 			curpeer->conf.remote_as = $2;
1322 		}
1323 		| LOCALAS as4number	{
1324 			curpeer->conf.local_as = $2;
1325 			if ($2 > USHRT_MAX)
1326 				curpeer->conf.local_short_as = AS_TRANS;
1327 			else
1328 				curpeer->conf.local_short_as = $2;
1329 		}
1330 		| LOCALAS as4number asnumber {
1331 			curpeer->conf.local_as = $2;
1332 			curpeer->conf.local_short_as = $3;
1333 		}
1334 		| DESCR string		{
1335 			if (strlcpy(curpeer->conf.descr, $2,
1336 			    sizeof(curpeer->conf.descr)) >=
1337 			    sizeof(curpeer->conf.descr)) {
1338 				yyerror("descr \"%s\" too long: max %zu",
1339 				    $2, sizeof(curpeer->conf.descr) - 1);
1340 				free($2);
1341 				YYERROR;
1342 			}
1343 			free($2);
1344 		}
1345 		| LOCALADDR address	{
1346 			if ($2.aid == AID_INET)
1347 				memcpy(&curpeer->conf.local_addr_v4, &$2,
1348 				    sizeof(curpeer->conf.local_addr_v4));
1349 			else if ($2.aid == AID_INET6)
1350 				memcpy(&curpeer->conf.local_addr_v6, &$2,
1351 				    sizeof(curpeer->conf.local_addr_v6));
1352 			else {
1353 				yyerror("Unsupported address family %s for "
1354 				    "local-addr", aid2str($2.aid));
1355 				YYERROR;
1356 			}
1357 		}
1358 		| yesno LOCALADDR	{
1359 			if ($1) {
1360 				yyerror("bad local-address definition");
1361 				YYERROR;
1362 			}
1363 			memset(&curpeer->conf.local_addr_v4, 0,
1364 			    sizeof(curpeer->conf.local_addr_v4));
1365 			memset(&curpeer->conf.local_addr_v6, 0,
1366 			    sizeof(curpeer->conf.local_addr_v6));
1367 		}
1368 		| MULTIHOP NUMBER	{
1369 			if ($2 < 2 || $2 > 255) {
1370 				yyerror("invalid multihop distance %lld", $2);
1371 				YYERROR;
1372 			}
1373 			curpeer->conf.distance = $2;
1374 		}
1375 		| PASSIVE		{
1376 			curpeer->conf.passive = 1;
1377 		}
1378 		| DOWN			{
1379 			curpeer->conf.down = 1;
1380 		}
1381 		| DOWN STRING		{
1382 			curpeer->conf.down = 1;
1383 			if (strlcpy(curpeer->conf.reason, $2,
1384 				sizeof(curpeer->conf.reason)) >=
1385 				sizeof(curpeer->conf.reason)) {
1386 				    yyerror("shutdown reason too long");
1387 				    free($2);
1388 				    YYERROR;
1389 			}
1390 			free($2);
1391 		}
1392 		| RIB STRING	{
1393 			if (!find_rib($2)) {
1394 				yyerror("rib \"%s\" does not exist.", $2);
1395 				free($2);
1396 				YYERROR;
1397 			}
1398 			if (strlcpy(curpeer->conf.rib, $2,
1399 			    sizeof(curpeer->conf.rib)) >=
1400 			    sizeof(curpeer->conf.rib)) {
1401 				yyerror("rib name \"%s\" too long: max %zu",
1402 				    $2, sizeof(curpeer->conf.rib) - 1);
1403 				free($2);
1404 				YYERROR;
1405 			}
1406 			free($2);
1407 		}
1408 		| HOLDTIME NUMBER	{
1409 			if ($2 < MIN_HOLDTIME || $2 > USHRT_MAX) {
1410 				yyerror("holdtime must be between %u and %u",
1411 				    MIN_HOLDTIME, USHRT_MAX);
1412 				YYERROR;
1413 			}
1414 			curpeer->conf.holdtime = $2;
1415 		}
1416 		| HOLDTIME YMIN NUMBER	{
1417 			if ($3 < MIN_HOLDTIME || $3 > USHRT_MAX) {
1418 				yyerror("holdtime must be between %u and %u",
1419 				    MIN_HOLDTIME, USHRT_MAX);
1420 				YYERROR;
1421 			}
1422 			curpeer->conf.min_holdtime = $3;
1423 		}
1424 		| ANNOUNCE family safi {
1425 			u_int8_t	aid, safi;
1426 			u_int16_t	afi;
1427 
1428 			if ($3 == SAFI_NONE) {
1429 				for (aid = 0; aid < AID_MAX; aid++) {
1430 					if (aid2afi(aid, &afi, &safi) == -1 ||
1431 					    afi != $2)
1432 						continue;
1433 					curpeer->conf.capabilities.mp[aid] = 0;
1434 				}
1435 			} else {
1436 				if (afi2aid($2, $3, &aid) == -1) {
1437 					yyerror("unknown AFI/SAFI pair");
1438 					YYERROR;
1439 				}
1440 				curpeer->conf.capabilities.mp[aid] = 1;
1441 			}
1442 		}
1443 		| ANNOUNCE CAPABILITIES yesno {
1444 			curpeer->conf.announce_capa = $3;
1445 		}
1446 		| ANNOUNCE REFRESH yesno {
1447 			curpeer->conf.capabilities.refresh = $3;
1448 		}
1449 		| ANNOUNCE RESTART yesno {
1450 			curpeer->conf.capabilities.grestart.restart = $3;
1451 		}
1452 		| ANNOUNCE AS4BYTE yesno {
1453 			curpeer->conf.capabilities.as4byte = $3;
1454 		}
1455 		| EXPORT NONE {
1456 			curpeer->conf.export_type = EXPORT_NONE;
1457 		}
1458 		| EXPORT DEFAULTROUTE {
1459 			curpeer->conf.export_type = EXPORT_DEFAULT_ROUTE;
1460 		}
1461 		| ENFORCE NEIGHBORAS yesno {
1462 			if ($3)
1463 				curpeer->conf.enforce_as = ENFORCE_AS_ON;
1464 			else
1465 				curpeer->conf.enforce_as = ENFORCE_AS_OFF;
1466 		}
1467 		| ENFORCE LOCALAS yesno {
1468 			if ($3)
1469 				curpeer->conf.enforce_local_as = ENFORCE_AS_ON;
1470 			else
1471 				curpeer->conf.enforce_local_as = ENFORCE_AS_OFF;
1472 		}
1473 		| ASOVERRIDE yesno {
1474 			if ($2) {
1475 				struct filter_rule	*r;
1476 				struct filter_set	*s;
1477 
1478 				if ((s = calloc(1, sizeof(struct filter_set)))
1479 				    == NULL)
1480 					fatal(NULL);
1481 				s->type = ACTION_SET_AS_OVERRIDE;
1482 
1483 				r = get_rule(s->type);
1484 				if (merge_filterset(&r->set, s) == -1)
1485 					YYERROR;
1486 			}
1487 		}
1488 		| MAXPREFIX NUMBER restart {
1489 			if ($2 < 0 || $2 > UINT_MAX) {
1490 				yyerror("bad maximum number of prefixes");
1491 				YYERROR;
1492 			}
1493 			curpeer->conf.max_prefix = $2;
1494 			curpeer->conf.max_prefix_restart = $3;
1495 		}
1496 		| MAXPREFIX NUMBER OUT restart {
1497 			if ($2 < 0 || $2 > UINT_MAX) {
1498 				yyerror("bad maximum number of prefixes");
1499 				YYERROR;
1500 			}
1501 			curpeer->conf.max_out_prefix = $2;
1502 			curpeer->conf.max_out_prefix_restart = $4;
1503 		}
1504 		| TCP MD5SIG PASSWORD string {
1505 			if (curpeer->conf.auth.method) {
1506 				yyerror("auth method cannot be redefined");
1507 				free($4);
1508 				YYERROR;
1509 			}
1510 			if (strlcpy(curpeer->conf.auth.md5key, $4,
1511 			    sizeof(curpeer->conf.auth.md5key)) >=
1512 			    sizeof(curpeer->conf.auth.md5key)) {
1513 				yyerror("tcp md5sig password too long: max %zu",
1514 				    sizeof(curpeer->conf.auth.md5key) - 1);
1515 				free($4);
1516 				YYERROR;
1517 			}
1518 			curpeer->conf.auth.method = AUTH_MD5SIG;
1519 			curpeer->conf.auth.md5key_len = strlen($4);
1520 			free($4);
1521 		}
1522 		| TCP MD5SIG KEY string {
1523 			if (curpeer->conf.auth.method) {
1524 				yyerror("auth method cannot be redefined");
1525 				free($4);
1526 				YYERROR;
1527 			}
1528 
1529 			if (str2key($4, curpeer->conf.auth.md5key,
1530 			    sizeof(curpeer->conf.auth.md5key)) == -1) {
1531 				free($4);
1532 				YYERROR;
1533 			}
1534 			curpeer->conf.auth.method = AUTH_MD5SIG;
1535 			curpeer->conf.auth.md5key_len = strlen($4) / 2;
1536 			free($4);
1537 		}
1538 		| IPSEC espah IKE {
1539 			if (curpeer->conf.auth.method) {
1540 				yyerror("auth method cannot be redefined");
1541 				YYERROR;
1542 			}
1543 			if ($2)
1544 				curpeer->conf.auth.method = AUTH_IPSEC_IKE_ESP;
1545 			else
1546 				curpeer->conf.auth.method = AUTH_IPSEC_IKE_AH;
1547 		}
1548 		| IPSEC espah inout SPI NUMBER STRING STRING encspec {
1549 			u_int32_t	auth_alg;
1550 			u_int8_t	keylen;
1551 
1552 			if (curpeer->conf.auth.method &&
1553 			    (((curpeer->conf.auth.spi_in && $3 == 1) ||
1554 			    (curpeer->conf.auth.spi_out && $3 == 0)) ||
1555 			    ($2 == 1 && curpeer->conf.auth.method !=
1556 			    AUTH_IPSEC_MANUAL_ESP) ||
1557 			    ($2 == 0 && curpeer->conf.auth.method !=
1558 			    AUTH_IPSEC_MANUAL_AH))) {
1559 				yyerror("auth method cannot be redefined");
1560 				free($6);
1561 				free($7);
1562 				YYERROR;
1563 			}
1564 
1565 			if (!strcmp($6, "sha1")) {
1566 				auth_alg = SADB_AALG_SHA1HMAC;
1567 				keylen = 20;
1568 			} else if (!strcmp($6, "md5")) {
1569 				auth_alg = SADB_AALG_MD5HMAC;
1570 				keylen = 16;
1571 			} else {
1572 				yyerror("unknown auth algorithm \"%s\"", $6);
1573 				free($6);
1574 				free($7);
1575 				YYERROR;
1576 			}
1577 			free($6);
1578 
1579 			if (strlen($7) / 2 != keylen) {
1580 				yyerror("auth key len: must be %u bytes, "
1581 				    "is %zu bytes", keylen, strlen($7) / 2);
1582 				free($7);
1583 				YYERROR;
1584 			}
1585 
1586 			if ($2)
1587 				curpeer->conf.auth.method =
1588 				    AUTH_IPSEC_MANUAL_ESP;
1589 			else {
1590 				if ($8.enc_alg) {
1591 					yyerror("\"ipsec ah\" doesn't take "
1592 					    "encryption keys");
1593 					free($7);
1594 					YYERROR;
1595 				}
1596 				curpeer->conf.auth.method =
1597 				    AUTH_IPSEC_MANUAL_AH;
1598 			}
1599 
1600 			if ($5 <= SPI_RESERVED_MAX || $5 > UINT_MAX) {
1601 				yyerror("bad spi number %lld", $5);
1602 				free($7);
1603 				YYERROR;
1604 			}
1605 
1606 			if ($3 == 1) {
1607 				if (str2key($7, curpeer->conf.auth.auth_key_in,
1608 				    sizeof(curpeer->conf.auth.auth_key_in)) ==
1609 				    -1) {
1610 					free($7);
1611 					YYERROR;
1612 				}
1613 				curpeer->conf.auth.spi_in = $5;
1614 				curpeer->conf.auth.auth_alg_in = auth_alg;
1615 				curpeer->conf.auth.enc_alg_in = $8.enc_alg;
1616 				memcpy(&curpeer->conf.auth.enc_key_in,
1617 				    &$8.enc_key,
1618 				    sizeof(curpeer->conf.auth.enc_key_in));
1619 				curpeer->conf.auth.enc_keylen_in =
1620 				    $8.enc_key_len;
1621 				curpeer->conf.auth.auth_keylen_in = keylen;
1622 			} else {
1623 				if (str2key($7, curpeer->conf.auth.auth_key_out,
1624 				    sizeof(curpeer->conf.auth.auth_key_out)) ==
1625 				    -1) {
1626 					free($7);
1627 					YYERROR;
1628 				}
1629 				curpeer->conf.auth.spi_out = $5;
1630 				curpeer->conf.auth.auth_alg_out = auth_alg;
1631 				curpeer->conf.auth.enc_alg_out = $8.enc_alg;
1632 				memcpy(&curpeer->conf.auth.enc_key_out,
1633 				    &$8.enc_key,
1634 				    sizeof(curpeer->conf.auth.enc_key_out));
1635 				curpeer->conf.auth.enc_keylen_out =
1636 				    $8.enc_key_len;
1637 				curpeer->conf.auth.auth_keylen_out = keylen;
1638 			}
1639 			free($7);
1640 		}
1641 		| TTLSECURITY yesno	{
1642 			curpeer->conf.ttlsec = $2;
1643 		}
1644 		| SET filter_set_opt	{
1645 			struct filter_rule	*r;
1646 
1647 			r = get_rule($2->type);
1648 			if (merge_filterset(&r->set, $2) == -1)
1649 				YYERROR;
1650 		}
1651 		| SET '{' optnl filter_set_l optnl '}'	{
1652 			struct filter_rule	*r;
1653 			struct filter_set	*s;
1654 
1655 			while ((s = TAILQ_FIRST($4)) != NULL) {
1656 				TAILQ_REMOVE($4, s, entry);
1657 				r = get_rule(s->type);
1658 				if (merge_filterset(&r->set, s) == -1)
1659 					YYERROR;
1660 			}
1661 			free($4);
1662 		}
1663 		| mrtdump
1664 		| REFLECTOR		{
1665 			if ((conf->flags & BGPD_FLAG_REFLECTOR) &&
1666 			    conf->clusterid != 0) {
1667 				yyerror("only one route reflector "
1668 				    "cluster allowed");
1669 				YYERROR;
1670 			}
1671 			conf->flags |= BGPD_FLAG_REFLECTOR;
1672 			curpeer->conf.reflector_client = 1;
1673 		}
1674 		| REFLECTOR address	{
1675 			if ($2.aid != AID_INET) {
1676 				yyerror("route reflector cluster-id must be "
1677 				    "an IPv4 address");
1678 				YYERROR;
1679 			}
1680 			if ((conf->flags & BGPD_FLAG_REFLECTOR) &&
1681 			    conf->clusterid != $2.v4.s_addr) {
1682 				yyerror("only one route reflector "
1683 				    "cluster allowed");
1684 				YYERROR;
1685 			}
1686 			conf->flags |= BGPD_FLAG_REFLECTOR;
1687 			curpeer->conf.reflector_client = 1;
1688 			conf->clusterid = $2.v4.s_addr;
1689 		}
1690 		| DEPEND ON STRING	{
1691 			if (strlcpy(curpeer->conf.if_depend, $3,
1692 			    sizeof(curpeer->conf.if_depend)) >=
1693 			    sizeof(curpeer->conf.if_depend)) {
1694 				yyerror("interface name \"%s\" too long: "
1695 				    "max %zu", $3,
1696 				    sizeof(curpeer->conf.if_depend) - 1);
1697 				free($3);
1698 				YYERROR;
1699 			}
1700 			free($3);
1701 		}
1702 		| DEMOTE STRING		{
1703 #ifdef HAVE_CARP
1704 			if (strlcpy(curpeer->conf.demote_group, $2,
1705 			    sizeof(curpeer->conf.demote_group)) >=
1706 			    sizeof(curpeer->conf.demote_group)) {
1707 				yyerror("demote group name \"%s\" too long: "
1708 				    "max %zu", $2,
1709 				    sizeof(curpeer->conf.demote_group) - 1);
1710 				free($2);
1711 				YYERROR;
1712 			}
1713 			free($2);
1714 			if (carp_demote_init(curpeer->conf.demote_group,
1715 			    cmd_opts & BGPD_OPT_FORCE_DEMOTE) == -1) {
1716 				yyerror("error initializing group \"%s\"",
1717 				    curpeer->conf.demote_group);
1718 				YYERROR;
1719 			}
1720 #else
1721 			yyerror("carp demote not supported");
1722 			free($2);
1723 			YYERROR;
1724 #endif
1725 		}
1726 		| TRANSPARENT yesno	{
1727 			if ($2 == 1)
1728 				curpeer->conf.flags |= PEERFLAG_TRANS_AS;
1729 			else
1730 				curpeer->conf.flags &= ~PEERFLAG_TRANS_AS;
1731 		}
1732 		| LOG STRING		{
1733 			if (!strcmp($2, "updates"))
1734 				curpeer->conf.flags |= PEERFLAG_LOG_UPDATES;
1735 			else if (!strcmp($2, "no"))
1736 				curpeer->conf.flags &= ~PEERFLAG_LOG_UPDATES;
1737 			else {
1738 				free($2);
1739 				YYERROR;
1740 			}
1741 			free($2);
1742 		}
1743 		| REJECT ASSET yesno	{
1744 			if ($3 == 1)
1745 				curpeer->conf.flags |= PEERFLAG_NO_AS_SET;
1746 			else
1747 				curpeer->conf.flags &= ~PEERFLAG_NO_AS_SET;
1748 		}
1749 		| RDE EVALUATE STRING {
1750 			if (!strcmp($3, "all"))
1751 				curpeer->conf.flags |= PEERFLAG_EVALUATE_ALL;
1752 			else if (!strcmp($3, "default"))
1753 				curpeer->conf.flags &= ~PEERFLAG_EVALUATE_ALL;
1754 			else {
1755 				yyerror("rde evaluate: "
1756 				    "unknown setting \"%s\"", $3);
1757 				free($3);
1758 				YYERROR;
1759 			}
1760 			free($3);
1761 		}
1762 		;
1763 
1764 restart		: /* nada */		{ $$ = 0; }
1765 		| RESTART NUMBER	{
1766 			if ($2 < 1 || $2 > USHRT_MAX) {
1767 				yyerror("restart out of range. 1 to %u minutes",
1768 				    USHRT_MAX);
1769 				YYERROR;
1770 			}
1771 			$$ = $2;
1772 		}
1773 		;
1774 
1775 family		: IPV4	{ $$ = AFI_IPv4; }
1776 		| IPV6	{ $$ = AFI_IPv6; }
1777 		;
1778 
1779 safi		: NONE		{ $$ = SAFI_NONE; }
1780 		| UNICAST	{ $$ = SAFI_UNICAST; }
1781 		| VPN		{ $$ = SAFI_MPLSVPN; }
1782 		;
1783 
1784 nettype		: STATIC { $$ = 1; }
1785 		| CONNECTED { $$ = 0; }
1786 		;
1787 
1788 espah		: ESP		{ $$ = 1; }
1789 		| AH		{ $$ = 0; }
1790 		;
1791 
1792 encspec		: /* nada */	{
1793 			bzero(&$$, sizeof($$));
1794 		}
1795 		| STRING STRING {
1796 			bzero(&$$, sizeof($$));
1797 			if (!strcmp($1, "3des") || !strcmp($1, "3des-cbc")) {
1798 				$$.enc_alg = SADB_EALG_3DESCBC;
1799 				$$.enc_key_len = 21; /* XXX verify */
1800 			} else if (!strcmp($1, "aes") ||
1801 			    !strcmp($1, "aes-128-cbc")) {
1802 				$$.enc_alg = SADB_X_EALG_AES;
1803 				$$.enc_key_len = 16;
1804 			} else {
1805 				yyerror("unknown enc algorithm \"%s\"", $1);
1806 				free($1);
1807 				free($2);
1808 				YYERROR;
1809 			}
1810 			free($1);
1811 
1812 			if (strlen($2) / 2 != $$.enc_key_len) {
1813 				yyerror("enc key length wrong: should be %u "
1814 				    "bytes, is %zu bytes",
1815 				    $$.enc_key_len * 2, strlen($2));
1816 				free($2);
1817 				YYERROR;
1818 			}
1819 
1820 			if (str2key($2, $$.enc_key, sizeof($$.enc_key)) == -1) {
1821 				free($2);
1822 				YYERROR;
1823 			}
1824 			free($2);
1825 		}
1826 		;
1827 
1828 filterrule	: action quick filter_rib_h direction filter_peer_h
1829 				filter_match_h filter_set
1830 		{
1831 			struct filter_rule	 r;
1832 			struct filter_rib_l	 *rb, *rbnext;
1833 
1834 			bzero(&r, sizeof(r));
1835 			r.action = $1;
1836 			r.quick = $2;
1837 			r.dir = $4;
1838 			if ($3) {
1839 				if (r.dir != DIR_IN) {
1840 					yyerror("rib only allowed on \"from\" "
1841 					    "rules.");
1842 
1843 					for (rb = $3; rb != NULL; rb = rbnext) {
1844 						rbnext = rb->next;
1845 						free(rb);
1846 					}
1847 					YYERROR;
1848 				}
1849 			}
1850 			if (expand_rule(&r, $3, $5, &$6, $7) == -1)
1851 				YYERROR;
1852 		}
1853 		;
1854 
1855 action		: ALLOW		{ $$ = ACTION_ALLOW; }
1856 		| DENY		{ $$ = ACTION_DENY; }
1857 		| MATCH		{ $$ = ACTION_NONE; }
1858 		;
1859 
1860 quick		: /* empty */	{ $$ = 0; }
1861 		| QUICK		{ $$ = 1; }
1862 		;
1863 
1864 direction	: FROM		{ $$ = DIR_IN; }
1865 		| TO		{ $$ = DIR_OUT; }
1866 		;
1867 
1868 filter_rib_h	: /* empty */			{ $$ = NULL; }
1869 		| RIB filter_rib		{ $$ = $2; }
1870 		| RIB '{' optnl filter_rib_l optnl '}'	{ $$ = $4; }
1871 
1872 filter_rib_l	: filter_rib			{ $$ = $1; }
1873 		| filter_rib_l comma filter_rib	{
1874 			$3->next = $1;
1875 			$$ = $3;
1876 		}
1877 		;
1878 
1879 filter_rib	: STRING	{
1880 			if (!find_rib($1)) {
1881 				yyerror("rib \"%s\" does not exist.", $1);
1882 				free($1);
1883 				YYERROR;
1884 			}
1885 			if (($$ = calloc(1, sizeof(struct filter_rib_l))) ==
1886 			    NULL)
1887 				fatal(NULL);
1888 			$$->next = NULL;
1889 			if (strlcpy($$->name, $1, sizeof($$->name)) >=
1890 			    sizeof($$->name)) {
1891 				yyerror("rib name \"%s\" too long: "
1892 				    "max %zu", $1, sizeof($$->name) - 1);
1893 				free($1);
1894 				free($$);
1895 				YYERROR;
1896 			}
1897 			free($1);
1898 		}
1899 		;
1900 
1901 filter_peer_h	: filter_peer
1902 		| '{' optnl filter_peer_l optnl '}'	{ $$ = $3; }
1903 		;
1904 
1905 filter_peer_l	: filter_peer				{ $$ = $1; }
1906 		| filter_peer_l comma filter_peer	{
1907 			$3->next = $1;
1908 			$$ = $3;
1909 		}
1910 		;
1911 
1912 filter_peer	: ANY		{
1913 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
1914 			    NULL)
1915 				fatal(NULL);
1916 			$$->p.peerid = $$->p.groupid = 0;
1917 			$$->next = NULL;
1918 		}
1919 		| address	{
1920 			struct peer *p;
1921 
1922 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
1923 			    NULL)
1924 				fatal(NULL);
1925 			$$->p.remote_as = $$->p.groupid = $$->p.peerid = 0;
1926 			$$->next = NULL;
1927 			RB_FOREACH(p, peer_head, new_peers)
1928 				if (!memcmp(&p->conf.remote_addr,
1929 				    &$1, sizeof(p->conf.remote_addr))) {
1930 					$$->p.peerid = p->conf.id;
1931 					break;
1932 				}
1933 			if ($$->p.peerid == 0) {
1934 				yyerror("no such peer: %s", log_addr(&$1));
1935 				free($$);
1936 				YYERROR;
1937 			}
1938 		}
1939 		| AS as4number	{
1940 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
1941 			    NULL)
1942 				fatal(NULL);
1943 			$$->p.groupid = $$->p.peerid = 0;
1944 			$$->p.remote_as = $2;
1945 		}
1946 		| GROUP STRING	{
1947 			struct peer *p;
1948 
1949 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
1950 			    NULL)
1951 				fatal(NULL);
1952 			$$->p.remote_as = $$->p.peerid = 0;
1953 			$$->next = NULL;
1954 			RB_FOREACH(p, peer_head, new_peers)
1955 				if (!strcmp(p->conf.group, $2)) {
1956 					$$->p.groupid = p->conf.groupid;
1957 					break;
1958 				}
1959 			if ($$->p.groupid == 0) {
1960 				yyerror("no such group: \"%s\"", $2);
1961 				free($2);
1962 				free($$);
1963 				YYERROR;
1964 			}
1965 			free($2);
1966 		}
1967 		| EBGP {
1968 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
1969 			    NULL)
1970 				fatal(NULL);
1971 			$$->p.ebgp = 1;
1972 		}
1973 		| IBGP {
1974 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
1975 			    NULL)
1976 				fatal(NULL);
1977 			$$->p.ibgp = 1;
1978 		}
1979 		;
1980 
1981 filter_prefix_h	: IPV4 prefixlenop			 {
1982 			if ($2.op == OP_NONE) {
1983 				$2.op = OP_RANGE;
1984 				$2.len_min = 0;
1985 				$2.len_max = -1;
1986 			}
1987 			if (($$ = calloc(1, sizeof(struct filter_prefix_l))) ==
1988 			    NULL)
1989 				fatal(NULL);
1990 			$$->p.addr.aid = AID_INET;
1991 			if (merge_prefixspec(&$$->p, &$2) == -1) {
1992 				free($$);
1993 				YYERROR;
1994 			}
1995 		}
1996 		| IPV6 prefixlenop			{
1997 			if ($2.op == OP_NONE) {
1998 				$2.op = OP_RANGE;
1999 				$2.len_min = 0;
2000 				$2.len_max = -1;
2001 			}
2002 			if (($$ = calloc(1, sizeof(struct filter_prefix_l))) ==
2003 			    NULL)
2004 				fatal(NULL);
2005 			$$->p.addr.aid = AID_INET6;
2006 			if (merge_prefixspec(&$$->p, &$2) == -1) {
2007 				free($$);
2008 				YYERROR;
2009 			}
2010 		}
2011 		| PREFIX filter_prefix			{ $$ = $2; }
2012 		| PREFIX '{' filter_prefix_m '}'	{ $$ = $3; }
2013 		;
2014 
2015 filter_prefix_m	: filter_prefix_l
2016 		| '{' filter_prefix_l '}'		{ $$ = $2; }
2017 		| '{' filter_prefix_l '}' filter_prefix_m
2018 		{
2019 			struct filter_prefix_l  *p;
2020 
2021 			/* merge, both can be lists */
2022 			for (p = $2; p != NULL && p->next != NULL; p = p->next)
2023 				;       /* nothing */
2024 			if (p != NULL)
2025 				p->next = $4;
2026 			$$ = $2;
2027 		}
2028 
2029 filter_prefix_l	: filter_prefix			{ $$ = $1; }
2030 		| filter_prefix_l comma filter_prefix	{
2031 			$3->next = $1;
2032 			$$ = $3;
2033 		}
2034 		;
2035 
2036 filter_prefix	: prefix prefixlenop			{
2037 			if (($$ = calloc(1, sizeof(struct filter_prefix_l))) ==
2038 			    NULL)
2039 				fatal(NULL);
2040 			memcpy(&$$->p.addr, &$1.prefix,
2041 			    sizeof($$->p.addr));
2042 			$$->p.len = $1.len;
2043 
2044 			if (merge_prefixspec(&$$->p, &$2) == -1) {
2045 				free($$);
2046 				YYERROR;
2047 			}
2048 		}
2049 		;
2050 
2051 filter_as_h	: filter_as_t
2052 		| '{' filter_as_t_l '}'		{ $$ = $2; }
2053 		;
2054 
2055 filter_as_t_l	: filter_as_t
2056 		| filter_as_t_l comma filter_as_t		{
2057 			struct filter_as_l	*a;
2058 
2059 			/* merge, both can be lists */
2060 			for (a = $1; a != NULL && a->next != NULL; a = a->next)
2061 				;	/* nothing */
2062 			if (a != NULL)
2063 				a->next = $3;
2064 			$$ = $1;
2065 		}
2066 		;
2067 
2068 filter_as_t	: filter_as_type filter_as			{
2069 			$$ = $2;
2070 			$$->a.type = $1;
2071 		}
2072 		| filter_as_type '{' filter_as_l_h '}'	{
2073 			struct filter_as_l	*a;
2074 
2075 			$$ = $3;
2076 			for (a = $$; a != NULL; a = a->next)
2077 				a->a.type = $1;
2078 		}
2079 		| filter_as_type ASSET STRING {
2080 			if (as_sets_lookup(&conf->as_sets, $3) == NULL) {
2081 				yyerror("as-set \"%s\" not defined", $3);
2082 				free($3);
2083 				YYERROR;
2084 			}
2085 			if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
2086 			    NULL)
2087 				fatal(NULL);
2088 			$$->a.type = $1;
2089 			$$->a.flags = AS_FLAG_AS_SET_NAME;
2090 			if (strlcpy($$->a.name, $3, sizeof($$->a.name)) >=
2091 			    sizeof($$->a.name)) {
2092 				yyerror("as-set name \"%s\" too long: "
2093 				    "max %zu", $3, sizeof($$->a.name) - 1);
2094 				free($3);
2095 				free($$);
2096 				YYERROR;
2097 			}
2098 			free($3);
2099 		}
2100 		;
2101 
2102 filter_as_l_h	: filter_as_l
2103 		| '{' filter_as_l '}'			{ $$ = $2; }
2104 		| '{' filter_as_l '}' filter_as_l_h
2105 		{
2106 			struct filter_as_l	*a;
2107 
2108 			/* merge, both can be lists */
2109 			for (a = $2; a != NULL && a->next != NULL; a = a->next)
2110 				;	/* nothing */
2111 			if (a != NULL)
2112 				a->next = $4;
2113 			$$ = $2;
2114 		}
2115 		;
2116 
2117 filter_as_l	: filter_as
2118 		| filter_as_l comma filter_as	{
2119 			$3->next = $1;
2120 			$$ = $3;
2121 		}
2122 		;
2123 
2124 filter_as	: as4number_any		{
2125 			if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
2126 			    NULL)
2127 				fatal(NULL);
2128 			$$->a.as_min = $1;
2129 			$$->a.as_max = $1;
2130 			$$->a.op = OP_EQ;
2131 		}
2132 		| NEIGHBORAS		{
2133 			if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
2134 			    NULL)
2135 				fatal(NULL);
2136 			$$->a.flags = AS_FLAG_NEIGHBORAS;
2137 		}
2138 		| equalityop as4number_any	{
2139 			if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
2140 			    NULL)
2141 				fatal(NULL);
2142 			$$->a.op = $1;
2143 			$$->a.as_min = $2;
2144 			$$->a.as_max = $2;
2145 		}
2146 		| as4number_any binaryop as4number_any {
2147 			if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
2148 			    NULL)
2149 				fatal(NULL);
2150 			if ($1 >= $3) {
2151 				yyerror("start AS is bigger than end");
2152 				YYERROR;
2153 			}
2154 			$$->a.op = $2;
2155 			$$->a.as_min = $1;
2156 			$$->a.as_max = $3;
2157 		}
2158 		;
2159 
2160 filter_match_h	: /* empty */			{
2161 			bzero(&$$, sizeof($$));
2162 		}
2163 		| {
2164 			bzero(&fmopts, sizeof(fmopts));
2165 		}
2166 		    filter_match		{
2167 			memcpy(&$$, &fmopts, sizeof($$));
2168 		}
2169 		;
2170 
2171 filter_match	: filter_elm
2172 		| filter_match filter_elm
2173 		;
2174 
2175 filter_elm	: filter_prefix_h	{
2176 			if (fmopts.prefix_l != NULL) {
2177 				yyerror("\"prefix\" already specified");
2178 				YYERROR;
2179 			}
2180 			if (fmopts.m.prefixset.name[0] != '\0') {
2181 				yyerror("\"prefix-set\" already specified, "
2182 				    "cannot be used with \"prefix\" in the "
2183 				    "same filter rule");
2184 				YYERROR;
2185 			}
2186 			fmopts.prefix_l = $1;
2187 		}
2188 		| filter_as_h		{
2189 			if (fmopts.as_l != NULL) {
2190 				yyerror("AS filters already specified");
2191 				YYERROR;
2192 			}
2193 			fmopts.as_l = $1;
2194 		}
2195 		| MAXASLEN NUMBER	{
2196 			if (fmopts.m.aslen.type != ASLEN_NONE) {
2197 				yyerror("AS length filters already specified");
2198 				YYERROR;
2199 			}
2200 			if ($2 < 0 || $2 > UINT_MAX) {
2201 				yyerror("bad max-as-len %lld", $2);
2202 				YYERROR;
2203 			}
2204 			fmopts.m.aslen.type = ASLEN_MAX;
2205 			fmopts.m.aslen.aslen = $2;
2206 		}
2207 		| MAXASSEQ NUMBER	{
2208 			if (fmopts.m.aslen.type != ASLEN_NONE) {
2209 				yyerror("AS length filters already specified");
2210 				YYERROR;
2211 			}
2212 			if ($2 < 0 || $2 > UINT_MAX) {
2213 				yyerror("bad max-as-seq %lld", $2);
2214 				YYERROR;
2215 			}
2216 			fmopts.m.aslen.type = ASLEN_SEQ;
2217 			fmopts.m.aslen.aslen = $2;
2218 		}
2219 		| community STRING	{
2220 			int i;
2221 			for (i = 0; i < MAX_COMM_MATCH; i++) {
2222 				if (fmopts.m.community[i].flags == 0)
2223 					break;
2224 			}
2225 			if (i >= MAX_COMM_MATCH) {
2226 				yyerror("too many \"community\" filters "
2227 				    "specified");
2228 				free($2);
2229 				YYERROR;
2230 			}
2231 			if (parsecommunity(&fmopts.m.community[i], $1, $2) == -1) {
2232 				free($2);
2233 				YYERROR;
2234 			}
2235 			free($2);
2236 		}
2237 		| EXTCOMMUNITY STRING STRING {
2238 			int i;
2239 			for (i = 0; i < MAX_COMM_MATCH; i++) {
2240 				if (fmopts.m.community[i].flags == 0)
2241 					break;
2242 			}
2243 			if (i >= MAX_COMM_MATCH) {
2244 				yyerror("too many \"community\" filters "
2245 				    "specified");
2246 				free($2);
2247 				free($3);
2248 				YYERROR;
2249 			}
2250 			if (parseextcommunity(&fmopts.m.community[i],
2251 			    $2, $3) == -1) {
2252 				free($2);
2253 				free($3);
2254 				YYERROR;
2255 			}
2256 			free($2);
2257 			free($3);
2258 		}
2259 		| EXTCOMMUNITY OVS STRING {
2260 			int i;
2261 			for (i = 0; i < MAX_COMM_MATCH; i++) {
2262 				if (fmopts.m.community[i].flags == 0)
2263 					break;
2264 			}
2265 			if (i >= MAX_COMM_MATCH) {
2266 				yyerror("too many \"community\" filters "
2267 				    "specified");
2268 				free($3);
2269 				YYERROR;
2270 			}
2271 			if (parseextcommunity(&fmopts.m.community[i],
2272 			    "ovs", $3) == -1) {
2273 				free($3);
2274 				YYERROR;
2275 			}
2276 			free($3);
2277 		}
2278 		| NEXTHOP address	{
2279 			if (fmopts.m.nexthop.flags) {
2280 				yyerror("nexthop already specified");
2281 				YYERROR;
2282 			}
2283 			fmopts.m.nexthop.addr = $2;
2284 			fmopts.m.nexthop.flags = FILTER_NEXTHOP_ADDR;
2285 		}
2286 		| NEXTHOP NEIGHBOR	{
2287 			if (fmopts.m.nexthop.flags) {
2288 				yyerror("nexthop already specified");
2289 				YYERROR;
2290 			}
2291 			fmopts.m.nexthop.flags = FILTER_NEXTHOP_NEIGHBOR;
2292 		}
2293 		| PREFIXSET STRING prefixlenop {
2294 			struct prefixset *ps;
2295 			if (fmopts.prefix_l != NULL) {
2296 				yyerror("\"prefix\" already specified, cannot "
2297 				    "be used with \"prefix-set\" in the same "
2298 				    "filter rule");
2299 				free($2);
2300 				YYERROR;
2301 			}
2302 			if (fmopts.m.prefixset.name[0] != '\0') {
2303 				yyerror("prefix-set filter already specified");
2304 				free($2);
2305 				YYERROR;
2306 			}
2307 			if ((ps = find_prefixset($2, &conf->prefixsets))
2308 			    == NULL) {
2309 				yyerror("prefix-set '%s' not defined", $2);
2310 				free($2);
2311 				YYERROR;
2312 			}
2313 			if (strlcpy(fmopts.m.prefixset.name, $2,
2314 			    sizeof(fmopts.m.prefixset.name)) >=
2315 			    sizeof(fmopts.m.prefixset.name)) {
2316 				yyerror("prefix-set name too long");
2317 				free($2);
2318 				YYERROR;
2319 			}
2320 			if (!($3.op == OP_NONE ||
2321 			    ($3.op == OP_RANGE &&
2322 			     $3.len_min == -1 && $3.len_max == -1))) {
2323 				yyerror("prefix-sets can only use option "
2324 				    "or-longer");
2325 				free($2);
2326 				YYERROR;
2327 			}
2328 			if ($3.op == OP_RANGE && ps->sflags & PREFIXSET_FLAG_OPS) {
2329 				yyerror("prefix-set %s contains prefixlen "
2330 				    "operators and cannot be used with an "
2331 				    "or-longer filter", $2);
2332 				free($2);
2333 				YYERROR;
2334 			}
2335 			if ($3.op == OP_RANGE && $3.len_min == -1 &&
2336 			    $3.len_min == -1)
2337 				fmopts.m.prefixset.flags |=
2338 				    PREFIXSET_FLAG_LONGER;
2339 			fmopts.m.prefixset.flags |= PREFIXSET_FLAG_FILTER;
2340 			free($2);
2341 		}
2342 		| ORIGINSET STRING {
2343 			if (fmopts.m.originset.name[0] != '\0') {
2344 				yyerror("origin-set filter already specified");
2345 				free($2);
2346 				YYERROR;
2347 			}
2348 			if (find_prefixset($2, &conf->originsets) == NULL) {
2349 				yyerror("origin-set '%s' not defined", $2);
2350 				free($2);
2351 				YYERROR;
2352 			}
2353 			if (strlcpy(fmopts.m.originset.name, $2,
2354 			    sizeof(fmopts.m.originset.name)) >=
2355 			    sizeof(fmopts.m.originset.name)) {
2356 				yyerror("origin-set name too long");
2357 				free($2);
2358 				YYERROR;
2359 			}
2360 			free($2);
2361 		}
2362 		| OVS validity		{
2363 			if (fmopts.m.ovs.is_set) {
2364 				yyerror("ovs filter already specified");
2365 				YYERROR;
2366 			}
2367 			fmopts.m.ovs.validity = $2;
2368 			fmopts.m.ovs.is_set = 1;
2369 		}
2370 		;
2371 
2372 prefixlenop	: /* empty */			{ bzero(&$$, sizeof($$)); }
2373 		| LONGER				{
2374 			bzero(&$$, sizeof($$));
2375 			$$.op = OP_RANGE;
2376 			$$.len_min = -1;
2377 			$$.len_max = -1;
2378 		}
2379 		| MAXLEN NUMBER				{
2380 			bzero(&$$, sizeof($$));
2381 			if ($2 < 0 || $2 > 128) {
2382 				yyerror("prefixlen must be >= 0 and <= 128");
2383 				YYERROR;
2384 			}
2385 
2386 			$$.op = OP_RANGE;
2387 			$$.len_min = -1;
2388 			$$.len_max = $2;
2389 		}
2390 		| PREFIXLEN unaryop NUMBER		{
2391 			int min, max;
2392 
2393 			bzero(&$$, sizeof($$));
2394 			if ($3 < 0 || $3 > 128) {
2395 				yyerror("prefixlen must be >= 0 and <= 128");
2396 				YYERROR;
2397 			}
2398 			/*
2399 			 * convert the unary operation into the equivalent
2400 			 * range check
2401 			 */
2402 			$$.op = OP_RANGE;
2403 
2404 			switch ($2) {
2405 			case OP_NE:
2406 				$$.op = $2;
2407 			case OP_EQ:
2408 				min = max = $3;
2409 				break;
2410 			case OP_LT:
2411 				if ($3 == 0) {
2412 					yyerror("prefixlen must be > 0");
2413 					YYERROR;
2414 				}
2415 				$3 -= 1;
2416 			case OP_LE:
2417 				min = -1;
2418 				max = $3;
2419 				break;
2420 			case OP_GT:
2421 				$3 += 1;
2422 			case OP_GE:
2423 				min = $3;
2424 				max = -1;
2425 				break;
2426 			default:
2427 				yyerror("unknown prefixlen operation");
2428 				YYERROR;
2429 			}
2430 			$$.len_min = min;
2431 			$$.len_max = max;
2432 		}
2433 		| PREFIXLEN NUMBER binaryop NUMBER	{
2434 			bzero(&$$, sizeof($$));
2435 			if ($2 < 0 || $2 > 128 || $4 < 0 || $4 > 128) {
2436 				yyerror("prefixlen must be < 128");
2437 				YYERROR;
2438 			}
2439 			if ($2 > $4) {
2440 				yyerror("start prefixlen is bigger than end");
2441 				YYERROR;
2442 			}
2443 			$$.op = $3;
2444 			$$.len_min = $2;
2445 			$$.len_max = $4;
2446 		}
2447 		;
2448 
2449 filter_as_type	: AS		{ $$ = AS_ALL; }
2450 		| SOURCEAS	{ $$ = AS_SOURCE; }
2451 		| TRANSITAS	{ $$ = AS_TRANSIT; }
2452 		| PEERAS	{ $$ = AS_PEER; }
2453 		;
2454 
2455 filter_set	: /* empty */					{ $$ = NULL; }
2456 		| SET filter_set_opt				{
2457 			if (($$ = calloc(1, sizeof(struct filter_set_head))) ==
2458 			    NULL)
2459 				fatal(NULL);
2460 			TAILQ_INIT($$);
2461 			TAILQ_INSERT_TAIL($$, $2, entry);
2462 		}
2463 		| SET '{' optnl filter_set_l optnl '}'	{ $$ = $4; }
2464 		;
2465 
2466 filter_set_l	: filter_set_l comma filter_set_opt	{
2467 			$$ = $1;
2468 			if (merge_filterset($$, $3) == 1)
2469 				YYERROR;
2470 		}
2471 		| filter_set_opt {
2472 			if (($$ = calloc(1, sizeof(struct filter_set_head))) ==
2473 			    NULL)
2474 				fatal(NULL);
2475 			TAILQ_INIT($$);
2476 			TAILQ_INSERT_TAIL($$, $1, entry);
2477 		}
2478 		;
2479 
2480 community	: COMMUNITY		{ $$ = COMMUNITY_TYPE_BASIC; }
2481 		| LARGECOMMUNITY	{ $$ = COMMUNITY_TYPE_LARGE; }
2482 		;
2483 
2484 delete		: /* empty */	{ $$ = 0; }
2485 		| DELETE	{ $$ = 1; }
2486 		;
2487 
2488 filter_set_opt	: LOCALPREF NUMBER		{
2489 			if ($2 < -INT_MAX || $2 > UINT_MAX) {
2490 				yyerror("bad localpref %lld", $2);
2491 				YYERROR;
2492 			}
2493 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2494 				fatal(NULL);
2495 			if ($2 >= 0) {
2496 				$$->type = ACTION_SET_LOCALPREF;
2497 				$$->action.metric = $2;
2498 			} else {
2499 				$$->type = ACTION_SET_RELATIVE_LOCALPREF;
2500 				$$->action.relative = $2;
2501 			}
2502 		}
2503 		| LOCALPREF '+' NUMBER		{
2504 			if ($3 < 0 || $3 > INT_MAX) {
2505 				yyerror("bad localpref +%lld", $3);
2506 				YYERROR;
2507 			}
2508 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2509 				fatal(NULL);
2510 			$$->type = ACTION_SET_RELATIVE_LOCALPREF;
2511 			$$->action.relative = $3;
2512 		}
2513 		| LOCALPREF '-' NUMBER		{
2514 			if ($3 < 0 || $3 > INT_MAX) {
2515 				yyerror("bad localpref -%lld", $3);
2516 				YYERROR;
2517 			}
2518 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2519 				fatal(NULL);
2520 			$$->type = ACTION_SET_RELATIVE_LOCALPREF;
2521 			$$->action.relative = -$3;
2522 		}
2523 		| MED NUMBER			{
2524 			if ($2 < -INT_MAX || $2 > UINT_MAX) {
2525 				yyerror("bad metric %lld", $2);
2526 				YYERROR;
2527 			}
2528 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2529 				fatal(NULL);
2530 			if ($2 >= 0) {
2531 				$$->type = ACTION_SET_MED;
2532 				$$->action.metric = $2;
2533 			} else {
2534 				$$->type = ACTION_SET_RELATIVE_MED;
2535 				$$->action.relative = $2;
2536 			}
2537 		}
2538 		| MED '+' NUMBER			{
2539 			if ($3 < 0 || $3 > INT_MAX) {
2540 				yyerror("bad metric +%lld", $3);
2541 				YYERROR;
2542 			}
2543 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2544 				fatal(NULL);
2545 			$$->type = ACTION_SET_RELATIVE_MED;
2546 			$$->action.relative = $3;
2547 		}
2548 		| MED '-' NUMBER			{
2549 			if ($3 < 0 || $3 > INT_MAX) {
2550 				yyerror("bad metric -%lld", $3);
2551 				YYERROR;
2552 			}
2553 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2554 				fatal(NULL);
2555 			$$->type = ACTION_SET_RELATIVE_MED;
2556 			$$->action.relative = -$3;
2557 		}
2558 		| METRIC NUMBER			{	/* alias for MED */
2559 			if ($2 < -INT_MAX || $2 > UINT_MAX) {
2560 				yyerror("bad metric %lld", $2);
2561 				YYERROR;
2562 			}
2563 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2564 				fatal(NULL);
2565 			if ($2 >= 0) {
2566 				$$->type = ACTION_SET_MED;
2567 				$$->action.metric = $2;
2568 			} else {
2569 				$$->type = ACTION_SET_RELATIVE_MED;
2570 				$$->action.relative = $2;
2571 			}
2572 		}
2573 		| METRIC '+' NUMBER			{
2574 			if ($3 < 0 || $3 > INT_MAX) {
2575 				yyerror("bad metric +%lld", $3);
2576 				YYERROR;
2577 			}
2578 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2579 				fatal(NULL);
2580 			$$->type = ACTION_SET_RELATIVE_MED;
2581 			$$->action.metric = $3;
2582 		}
2583 		| METRIC '-' NUMBER			{
2584 			if ($3 < 0 || $3 > INT_MAX) {
2585 				yyerror("bad metric -%lld", $3);
2586 				YYERROR;
2587 			}
2588 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2589 				fatal(NULL);
2590 			$$->type = ACTION_SET_RELATIVE_MED;
2591 			$$->action.relative = -$3;
2592 		}
2593 		| WEIGHT NUMBER				{
2594 			if ($2 < -INT_MAX || $2 > UINT_MAX) {
2595 				yyerror("bad weight %lld", $2);
2596 				YYERROR;
2597 			}
2598 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2599 				fatal(NULL);
2600 			if ($2 > 0) {
2601 				$$->type = ACTION_SET_WEIGHT;
2602 				$$->action.metric = $2;
2603 			} else {
2604 				$$->type = ACTION_SET_RELATIVE_WEIGHT;
2605 				$$->action.relative = $2;
2606 			}
2607 		}
2608 		| WEIGHT '+' NUMBER			{
2609 			if ($3 < 0 || $3 > INT_MAX) {
2610 				yyerror("bad weight +%lld", $3);
2611 				YYERROR;
2612 			}
2613 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2614 				fatal(NULL);
2615 			$$->type = ACTION_SET_RELATIVE_WEIGHT;
2616 			$$->action.relative = $3;
2617 		}
2618 		| WEIGHT '-' NUMBER			{
2619 			if ($3 < 0 || $3 > INT_MAX) {
2620 				yyerror("bad weight -%lld", $3);
2621 				YYERROR;
2622 			}
2623 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2624 				fatal(NULL);
2625 			$$->type = ACTION_SET_RELATIVE_WEIGHT;
2626 			$$->action.relative = -$3;
2627 		}
2628 		| NEXTHOP address		{
2629 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2630 				fatal(NULL);
2631 			$$->type = ACTION_SET_NEXTHOP;
2632 			memcpy(&$$->action.nexthop, &$2,
2633 			    sizeof($$->action.nexthop));
2634 		}
2635 		| NEXTHOP BLACKHOLE		{
2636 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2637 				fatal(NULL);
2638 			$$->type = ACTION_SET_NEXTHOP_BLACKHOLE;
2639 		}
2640 		| NEXTHOP REJECT		{
2641 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2642 				fatal(NULL);
2643 			$$->type = ACTION_SET_NEXTHOP_REJECT;
2644 		}
2645 		| NEXTHOP NOMODIFY		{
2646 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2647 				fatal(NULL);
2648 			$$->type = ACTION_SET_NEXTHOP_NOMODIFY;
2649 		}
2650 		| NEXTHOP SELF		{
2651 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2652 				fatal(NULL);
2653 			$$->type = ACTION_SET_NEXTHOP_SELF;
2654 		}
2655 		| PREPEND_SELF NUMBER		{
2656 			if ($2 < 0 || $2 > 128) {
2657 				yyerror("bad number of prepends");
2658 				YYERROR;
2659 			}
2660 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2661 				fatal(NULL);
2662 			$$->type = ACTION_SET_PREPEND_SELF;
2663 			$$->action.prepend = $2;
2664 		}
2665 		| PREPEND_PEER NUMBER		{
2666 			if ($2 < 0 || $2 > 128) {
2667 				yyerror("bad number of prepends");
2668 				YYERROR;
2669 			}
2670 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2671 				fatal(NULL);
2672 			$$->type = ACTION_SET_PREPEND_PEER;
2673 			$$->action.prepend = $2;
2674 		}
2675 		| ASOVERRIDE			{
2676 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2677 				fatal(NULL);
2678 			$$->type = ACTION_SET_AS_OVERRIDE;
2679 		}
2680 		| PFTABLE STRING		{
2681 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2682 				fatal(NULL);
2683 			$$->type = ACTION_PFTABLE;
2684 			if (!(cmd_opts & BGPD_OPT_NOACTION) &&
2685 			    pftable_exists($2) != 0) {
2686 				yyerror("pftable name does not exist");
2687 				free($2);
2688 				free($$);
2689 				YYERROR;
2690 			}
2691 			if (strlcpy($$->action.pftable, $2,
2692 			    sizeof($$->action.pftable)) >=
2693 			    sizeof($$->action.pftable)) {
2694 				yyerror("pftable name too long");
2695 				free($2);
2696 				free($$);
2697 				YYERROR;
2698 			}
2699 			if (pftable_add($2) != 0) {
2700 				yyerror("Couldn't register table");
2701 				free($2);
2702 				free($$);
2703 				YYERROR;
2704 			}
2705 			free($2);
2706 		}
2707 		| RTLABEL STRING		{
2708 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2709 				fatal(NULL);
2710 			$$->type = ACTION_RTLABEL;
2711 			if (strlcpy($$->action.rtlabel, $2,
2712 			    sizeof($$->action.rtlabel)) >=
2713 			    sizeof($$->action.rtlabel)) {
2714 				yyerror("rtlabel name too long");
2715 				free($2);
2716 				free($$);
2717 				YYERROR;
2718 			}
2719 			free($2);
2720 		}
2721 		| community delete STRING	{
2722 			u_int8_t f1, f2, f3;
2723 
2724 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2725 				fatal(NULL);
2726 			if ($2)
2727 				$$->type = ACTION_DEL_COMMUNITY;
2728 			else
2729 				$$->type = ACTION_SET_COMMUNITY;
2730 
2731 			if (parsecommunity(&$$->action.community, $1, $3) ==
2732 			    -1) {
2733 				free($3);
2734 				free($$);
2735 				YYERROR;
2736 			}
2737 			free($3);
2738 			/* Don't allow setting of any match */
2739 			f1 = $$->action.community.flags >> 8;
2740 			f2 = $$->action.community.flags >> 16;
2741 			f3 = $$->action.community.flags >> 24;
2742 			if (!$2 && (f1 == COMMUNITY_ANY ||
2743 			    f2 == COMMUNITY_ANY || f3 == COMMUNITY_ANY)) {
2744 				yyerror("'*' is not allowed in set community");
2745 				free($$);
2746 				YYERROR;
2747 			}
2748 		}
2749 		| EXTCOMMUNITY delete STRING STRING {
2750 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2751 				fatal(NULL);
2752 			if ($2)
2753 				$$->type = ACTION_DEL_COMMUNITY;
2754 			else
2755 				$$->type = ACTION_SET_COMMUNITY;
2756 
2757 			if (parseextcommunity(&$$->action.community,
2758 			    $3, $4) == -1) {
2759 				free($3);
2760 				free($4);
2761 				free($$);
2762 				YYERROR;
2763 			}
2764 			free($3);
2765 			free($4);
2766 		}
2767 		| EXTCOMMUNITY delete OVS STRING {
2768 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2769 				fatal(NULL);
2770 			if ($2)
2771 				$$->type = ACTION_DEL_COMMUNITY;
2772 			else
2773 				$$->type = ACTION_SET_COMMUNITY;
2774 
2775 			if (parseextcommunity(&$$->action.community,
2776 			    "ovs", $4) == -1) {
2777 				free($4);
2778 				free($$);
2779 				YYERROR;
2780 			}
2781 			free($4);
2782 		}
2783 		| ORIGIN origincode {
2784 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2785 				fatal(NULL);
2786 			$$->type = ACTION_SET_ORIGIN;
2787 			$$->action.origin = $2;
2788 		}
2789 		;
2790 
2791 origincode	: STRING	{
2792 			if (!strcmp($1, "egp"))
2793 				$$ = ORIGIN_EGP;
2794 			else if (!strcmp($1, "igp"))
2795 				$$ = ORIGIN_IGP;
2796 			else if (!strcmp($1, "incomplete"))
2797 				$$ = ORIGIN_INCOMPLETE;
2798 			else {
2799 				yyerror("unknown origin \"%s\"", $1);
2800 				free($1);
2801 				YYERROR;
2802 			}
2803 			free($1);
2804 		};
2805 
2806 validity	: STRING	{
2807 			if (!strcmp($1, "not-found"))
2808 				$$ = ROA_NOTFOUND;
2809 			else if (!strcmp($1, "invalid"))
2810 				$$ = ROA_INVALID;
2811 			else if (!strcmp($1, "valid"))
2812 				$$ = ROA_VALID;
2813 			else {
2814 				yyerror("unknown validity \"%s\"", $1);
2815 				free($1);
2816 				YYERROR;
2817 			}
2818 			free($1);
2819 		};
2820 
2821 optnl		: /* empty */
2822 		| '\n' optnl
2823 		;
2824 
2825 comma		: /* empty */
2826 		| ','
2827 		| '\n' optnl
2828 		| ',' '\n' optnl
2829 		;
2830 
2831 unaryop		: '='		{ $$ = OP_EQ; }
2832 		| NE		{ $$ = OP_NE; }
2833 		| LE		{ $$ = OP_LE; }
2834 		| '<'		{ $$ = OP_LT; }
2835 		| GE		{ $$ = OP_GE; }
2836 		| '>'		{ $$ = OP_GT; }
2837 		;
2838 
2839 equalityop	: '='		{ $$ = OP_EQ; }
2840 		| NE		{ $$ = OP_NE; }
2841 		;
2842 
2843 binaryop	: '-'		{ $$ = OP_RANGE; }
2844 		| XRANGE	{ $$ = OP_XRANGE; }
2845 		;
2846 
2847 %%
2848 
2849 struct keywords {
2850 	const char	*k_name;
2851 	int		 k_val;
2852 };
2853 
2854 int
yyerror(const char * fmt,...)2855 yyerror(const char *fmt, ...)
2856 {
2857 	va_list		 ap;
2858 	char		*msg;
2859 
2860 	file->errors++;
2861 	va_start(ap, fmt);
2862 	if (vasprintf(&msg, fmt, ap) == -1)
2863 		fatalx("yyerror vasprintf");
2864 	va_end(ap);
2865 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
2866 	free(msg);
2867 	return (0);
2868 }
2869 
2870 int
kw_cmp(const void * k,const void * e)2871 kw_cmp(const void *k, const void *e)
2872 {
2873 	return (strcmp(k, ((const struct keywords *)e)->k_name));
2874 }
2875 
2876 int
lookup(char * s)2877 lookup(char *s)
2878 {
2879 	/* this has to be sorted always */
2880 	static const struct keywords keywords[] = {
2881 		{ "AS",			AS},
2882 		{ "IPv4",		IPV4},
2883 		{ "IPv6",		IPV6},
2884 		{ "ah",			AH},
2885 		{ "allow",		ALLOW},
2886 		{ "announce",		ANNOUNCE},
2887 		{ "any",		ANY},
2888 		{ "as-4byte",		AS4BYTE },
2889 		{ "as-override",	ASOVERRIDE},
2890 		{ "as-set",		ASSET },
2891 		{ "blackhole",		BLACKHOLE},
2892 		{ "capabilities",	CAPABILITIES},
2893 		{ "community",		COMMUNITY},
2894 		{ "compare",		COMPARE},
2895 		{ "connect-retry",	CONNECTRETRY},
2896 		{ "connected",		CONNECTED},
2897 		{ "default-route",	DEFAULTROUTE},
2898 		{ "delete",		DELETE},
2899 		{ "demote",		DEMOTE},
2900 		{ "deny",		DENY},
2901 		{ "depend",		DEPEND},
2902 		{ "descr",		DESCR},
2903 		{ "down",		DOWN},
2904 		{ "dump",		DUMP},
2905 		{ "ebgp",		EBGP},
2906 		{ "enforce",		ENFORCE},
2907 		{ "esp",		ESP},
2908 		{ "evaluate",		EVALUATE},
2909 		{ "export",		EXPORT},
2910 		{ "export-target",	EXPORTTRGT},
2911 		{ "ext-community",	EXTCOMMUNITY},
2912 		{ "fib-priority",	FIBPRIORITY},
2913 		{ "fib-update",		FIBUPDATE},
2914 		{ "from",		FROM},
2915 		{ "group",		GROUP},
2916 		{ "holdtime",		HOLDTIME},
2917 		{ "ibgp",		IBGP},
2918 		{ "ignore",		IGNORE},
2919 		{ "ike",		IKE},
2920 		{ "import-target",	IMPORTTRGT},
2921 		{ "in",			IN},
2922 		{ "include",		INCLUDE},
2923 		{ "inet",		IPV4},
2924 		{ "inet6",		IPV6},
2925 		{ "ipsec",		IPSEC},
2926 		{ "key",		KEY},
2927 		{ "large-community",	LARGECOMMUNITY},
2928 		{ "listen",		LISTEN},
2929 		{ "local-address",	LOCALADDR},
2930 		{ "local-as",		LOCALAS},
2931 		{ "localpref",		LOCALPREF},
2932 		{ "log",		LOG},
2933 		{ "match",		MATCH},
2934 		{ "max-as-len",		MAXASLEN},
2935 		{ "max-as-seq",		MAXASSEQ},
2936 		{ "max-prefix",		MAXPREFIX},
2937 		{ "maxlen",		MAXLEN},
2938 		{ "md5sig",		MD5SIG},
2939 		{ "med",		MED},
2940 		{ "metric",		METRIC},
2941 		{ "min",		YMIN},
2942 		{ "multihop",		MULTIHOP},
2943 		{ "neighbor",		NEIGHBOR},
2944 		{ "neighbor-as",	NEIGHBORAS},
2945 		{ "network",		NETWORK},
2946 		{ "nexthop",		NEXTHOP},
2947 		{ "no-modify",		NOMODIFY},
2948 		{ "none",		NONE},
2949 		{ "on",			ON},
2950 		{ "or-longer",		LONGER},
2951 		{ "origin",		ORIGIN},
2952 		{ "origin-set",		ORIGINSET},
2953 		{ "out",		OUT},
2954 		{ "ovs",		OVS},
2955 		{ "passive",		PASSIVE},
2956 		{ "password",		PASSWORD},
2957 		{ "peer-as",		PEERAS},
2958 		{ "pftable",		PFTABLE},
2959 		{ "port",		PORT},
2960 		{ "prefix",		PREFIX},
2961 		{ "prefix-set",		PREFIXSET},
2962 		{ "prefixlen",		PREFIXLEN},
2963 		{ "prepend-neighbor",	PREPEND_PEER},
2964 		{ "prepend-self",	PREPEND_SELF},
2965 		{ "priority",		PRIORITY},
2966 		{ "qualify",		QUALIFY},
2967 		{ "quick",		QUICK},
2968 		{ "rd",			RD},
2969 		{ "rde",		RDE},
2970 		{ "refresh",		REFRESH },
2971 		{ "reject",		REJECT},
2972 		{ "remote-as",		REMOTEAS},
2973 		{ "restart",		RESTART},
2974 		{ "restricted",		RESTRICTED},
2975 		{ "rib",		RIB},
2976 		{ "roa-set",		ROASET },
2977 		{ "route-reflector",	REFLECTOR},
2978 		{ "router-id",		ROUTERID},
2979 		{ "rtable",		RTABLE},
2980 		{ "rtlabel",		RTLABEL},
2981 		{ "rtr",		RTR},
2982 		{ "self",		SELF},
2983 		{ "set",		SET},
2984 		{ "socket",		SOCKET },
2985 		{ "source-as",		SOURCEAS},
2986 		{ "spi",		SPI},
2987 		{ "static",		STATIC},
2988 		{ "tcp",		TCP},
2989 		{ "to",			TO},
2990 		{ "transit-as",		TRANSITAS},
2991 		{ "transparent-as",	TRANSPARENT},
2992 		{ "ttl-security",	TTLSECURITY},
2993 		{ "unicast",		UNICAST},
2994 		{ "via",		VIA},
2995 		{ "vpn",		VPN},
2996 		{ "weight",		WEIGHT}
2997 	};
2998 	const struct keywords	*p;
2999 
3000 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
3001 	    sizeof(keywords[0]), kw_cmp);
3002 
3003 	if (p)
3004 		return (p->k_val);
3005 	else
3006 		return (STRING);
3007 }
3008 
3009 #define START_EXPAND	1
3010 #define DONE_EXPAND	2
3011 
3012 static int	expanding;
3013 
3014 int
igetc(void)3015 igetc(void)
3016 {
3017 	int	c;
3018 
3019 	while (1) {
3020 		if (file->ungetpos > 0)
3021 			c = file->ungetbuf[--file->ungetpos];
3022 		else
3023 			c = getc(file->stream);
3024 
3025 		if (c == START_EXPAND)
3026 			expanding = 1;
3027 		else if (c == DONE_EXPAND)
3028 			expanding = 0;
3029 		else
3030 			break;
3031 	}
3032 	return (c);
3033 }
3034 
3035 int
lgetc(int quotec)3036 lgetc(int quotec)
3037 {
3038 	int		c, next;
3039 
3040 	if (quotec) {
3041 		if ((c = igetc()) == EOF) {
3042 			yyerror("reached end of file while parsing "
3043 			    "quoted string");
3044 			if (file == topfile || popfile() == EOF)
3045 				return (EOF);
3046 			return (quotec);
3047 		}
3048 		return (c);
3049 	}
3050 
3051 	while ((c = igetc()) == '\\') {
3052 		next = igetc();
3053 		if (next != '\n') {
3054 			c = next;
3055 			break;
3056 		}
3057 		yylval.lineno = file->lineno;
3058 		file->lineno++;
3059 	}
3060 
3061 	if (c == EOF) {
3062 		/*
3063 		 * Fake EOL when hit EOF for the first time. This gets line
3064 		 * count right if last line in included file is syntactically
3065 		 * invalid and has no newline.
3066 		 */
3067 		if (file->eof_reached == 0) {
3068 			file->eof_reached = 1;
3069 			return ('\n');
3070 		}
3071 		while (c == EOF) {
3072 			if (file == topfile || popfile() == EOF)
3073 				return (EOF);
3074 			c = igetc();
3075 		}
3076 	}
3077 	return (c);
3078 }
3079 
3080 void
lungetc(int c)3081 lungetc(int c)
3082 {
3083 	if (c == EOF)
3084 		return;
3085 
3086 	if (file->ungetpos >= file->ungetsize) {
3087 		void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
3088 		if (p == NULL)
3089 			err(1, "lungetc");
3090 		file->ungetbuf = p;
3091 		file->ungetsize *= 2;
3092 	}
3093 	file->ungetbuf[file->ungetpos++] = c;
3094 }
3095 
3096 int
findeol(void)3097 findeol(void)
3098 {
3099 	int	c;
3100 
3101 	/* skip to either EOF or the first real EOL */
3102 	while (1) {
3103 		c = lgetc(0);
3104 		if (c == '\n') {
3105 			file->lineno++;
3106 			break;
3107 		}
3108 		if (c == EOF)
3109 			break;
3110 	}
3111 	return (ERROR);
3112 }
3113 
3114 int
yylex(void)3115 yylex(void)
3116 {
3117 	u_char	 buf[8096];
3118 	u_char	*p, *val;
3119 	int	 quotec, next, c;
3120 	int	 token;
3121 
3122 top:
3123 	p = buf;
3124 	while ((c = lgetc(0)) == ' ' || c == '\t')
3125 		; /* nothing */
3126 
3127 	yylval.lineno = file->lineno;
3128 	if (c == '#')
3129 		while ((c = lgetc(0)) != '\n' && c != EOF)
3130 			; /* nothing */
3131 	if (c == '$' && !expanding) {
3132 		while (1) {
3133 			if ((c = lgetc(0)) == EOF)
3134 				return (0);
3135 
3136 			if (p + 1 >= buf + sizeof(buf) - 1) {
3137 				yyerror("string too long");
3138 				return (findeol());
3139 			}
3140 			if (isalnum(c) || c == '_') {
3141 				*p++ = c;
3142 				continue;
3143 			}
3144 			*p = '\0';
3145 			lungetc(c);
3146 			break;
3147 		}
3148 		val = symget(buf);
3149 		if (val == NULL) {
3150 			yyerror("macro '%s' not defined", buf);
3151 			return (findeol());
3152 		}
3153 		p = val + strlen(val) - 1;
3154 		lungetc(DONE_EXPAND);
3155 		while (p >= val) {
3156 			lungetc(*p);
3157 			p--;
3158 		}
3159 		lungetc(START_EXPAND);
3160 		goto top;
3161 	}
3162 
3163 	switch (c) {
3164 	case '\'':
3165 	case '"':
3166 		quotec = c;
3167 		while (1) {
3168 			if ((c = lgetc(quotec)) == EOF)
3169 				return (0);
3170 			if (c == '\n') {
3171 				file->lineno++;
3172 				continue;
3173 			} else if (c == '\\') {
3174 				if ((next = lgetc(quotec)) == EOF)
3175 					return (0);
3176 				if (next == quotec || next == ' ' ||
3177 				    next == '\t')
3178 					c = next;
3179 				else if (next == '\n') {
3180 					file->lineno++;
3181 					continue;
3182 				} else
3183 					lungetc(next);
3184 			} else if (c == quotec) {
3185 				*p = '\0';
3186 				break;
3187 			} else if (c == '\0') {
3188 				yyerror("syntax error: unterminated quote");
3189 				return (findeol());
3190 			}
3191 			if (p + 1 >= buf + sizeof(buf) - 1) {
3192 				yyerror("string too long");
3193 				return (findeol());
3194 			}
3195 			*p++ = c;
3196 		}
3197 		yylval.v.string = strdup(buf);
3198 		if (yylval.v.string == NULL)
3199 			fatal("yylex: strdup");
3200 		return (STRING);
3201 	case '!':
3202 		next = lgetc(0);
3203 		if (next == '=')
3204 			return (NE);
3205 		lungetc(next);
3206 		break;
3207 	case '<':
3208 		next = lgetc(0);
3209 		if (next == '=')
3210 			return (LE);
3211 		lungetc(next);
3212 		break;
3213 	case '>':
3214 		next = lgetc(0);
3215 		if (next == '<')
3216 			return (XRANGE);
3217 		else if (next == '=')
3218 			return (GE);
3219 		lungetc(next);
3220 		break;
3221 	}
3222 
3223 #define allowed_to_end_number(x) \
3224 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
3225 
3226 	if (c == '-' || isdigit(c)) {
3227 		do {
3228 			*p++ = c;
3229 			if ((size_t)(p-buf) >= sizeof(buf)) {
3230 				yyerror("string too long");
3231 				return (findeol());
3232 			}
3233 		} while ((c = lgetc(0)) != EOF && isdigit(c));
3234 		lungetc(c);
3235 		if (p == buf + 1 && buf[0] == '-')
3236 			goto nodigits;
3237 		if (c == EOF || allowed_to_end_number(c)) {
3238 			const char *errstr = NULL;
3239 
3240 			*p = '\0';
3241 			yylval.v.number = strtonum(buf, LLONG_MIN,
3242 			    LLONG_MAX, &errstr);
3243 			if (errstr) {
3244 				yyerror("\"%s\" invalid number: %s",
3245 				    buf, errstr);
3246 				return (findeol());
3247 			}
3248 			return (NUMBER);
3249 		} else {
3250 nodigits:
3251 			while (p > buf + 1)
3252 				lungetc(*--p);
3253 			c = *--p;
3254 			if (c == '-')
3255 				return (c);
3256 		}
3257 	}
3258 
3259 #define allowed_in_string(x) \
3260 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
3261 	x != '{' && x != '}' && x != '<' && x != '>' && \
3262 	x != '!' && x != '=' && x != '/' && x != '#' && \
3263 	x != ','))
3264 
3265 	if (isalnum(c) || c == ':' || c == '_' || c == '*') {
3266 		do {
3267 			*p++ = c;
3268 			if ((size_t)(p-buf) >= sizeof(buf)) {
3269 				yyerror("string too long");
3270 				return (findeol());
3271 			}
3272 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
3273 		lungetc(c);
3274 		*p = '\0';
3275 		if ((token = lookup(buf)) == STRING)
3276 			if ((yylval.v.string = strdup(buf)) == NULL)
3277 				fatal("yylex: strdup");
3278 		return (token);
3279 	}
3280 	if (c == '\n') {
3281 		yylval.lineno = file->lineno;
3282 		file->lineno++;
3283 	}
3284 	if (c == EOF)
3285 		return (0);
3286 	return (c);
3287 }
3288 
3289 int
check_file_secrecy(int fd,const char * fname)3290 check_file_secrecy(int fd, const char *fname)
3291 {
3292 	struct stat	st;
3293 
3294 	if (fstat(fd, &st)) {
3295 		log_warn("cannot stat %s", fname);
3296 		return (-1);
3297 	}
3298 	return (0);
3299 }
3300 
3301 struct file *
pushfile(const char * name,int secret)3302 pushfile(const char *name, int secret)
3303 {
3304 	struct file	*nfile;
3305 
3306 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
3307 		log_warn("%s", __func__);
3308 		return (NULL);
3309 	}
3310 	if ((nfile->name = strdup(name)) == NULL) {
3311 		log_warn("%s", __func__);
3312 		free(nfile);
3313 		return (NULL);
3314 	}
3315 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
3316 		log_warn("%s: %s", __func__, nfile->name);
3317 		free(nfile->name);
3318 		free(nfile);
3319 		return (NULL);
3320 	}
3321 	if (secret &&
3322 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
3323 		fclose(nfile->stream);
3324 		free(nfile->name);
3325 		free(nfile);
3326 		return (NULL);
3327 	}
3328 	nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
3329 	nfile->ungetsize = 16;
3330 	nfile->ungetbuf = malloc(nfile->ungetsize);
3331 	if (nfile->ungetbuf == NULL) {
3332 		log_warn("%s", __func__);
3333 		fclose(nfile->stream);
3334 		free(nfile->name);
3335 		free(nfile);
3336 		return (NULL);
3337 	}
3338 	TAILQ_INSERT_TAIL(&files, nfile, entry);
3339 	return (nfile);
3340 }
3341 
3342 int
popfile(void)3343 popfile(void)
3344 {
3345 	struct file	*prev;
3346 
3347 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
3348 		prev->errors += file->errors;
3349 
3350 	TAILQ_REMOVE(&files, file, entry);
3351 	fclose(file->stream);
3352 	free(file->name);
3353 	free(file->ungetbuf);
3354 	free(file);
3355 	file = prev;
3356 	return (file ? 0 : EOF);
3357 }
3358 
3359 static void
init_config(struct bgpd_config * c)3360 init_config(struct bgpd_config *c)
3361 {
3362 	u_int rdomid;
3363 
3364 	c->min_holdtime = MIN_HOLDTIME;
3365 	c->holdtime = INTERVAL_HOLD;
3366 	c->connectretry = INTERVAL_CONNECTRETRY;
3367 	c->bgpid = get_bgpid();
3368 	c->fib_priority = RTP_BGP;
3369 	c->default_tableid = getrtable();
3370 	ktable_exists(c->default_tableid, &rdomid);
3371 	if (rdomid != c->default_tableid)
3372 		fatalx("current routing table %u is not a routing domain",
3373 		    c->default_tableid);
3374 
3375 	if (asprintf(&c->csock, "%s.%d", SOCKET_NAME, c->default_tableid) == -1)
3376 		fatal(NULL);
3377 }
3378 
3379 struct bgpd_config *
parse_config(char * filename,struct peer_head * ph,struct rtr_config_head * rh)3380 parse_config(char *filename, struct peer_head *ph, struct rtr_config_head *rh)
3381 {
3382 	struct sym		*sym, *next;
3383 	struct rde_rib		*rr;
3384 	struct network		*n;
3385 	int			 errors = 0;
3386 
3387 	conf = new_config();
3388 	init_config(conf);
3389 
3390 	if ((filter_l = calloc(1, sizeof(struct filter_head))) == NULL)
3391 		fatal(NULL);
3392 	if ((peerfilter_l = calloc(1, sizeof(struct filter_head))) == NULL)
3393 		fatal(NULL);
3394 	if ((groupfilter_l = calloc(1, sizeof(struct filter_head))) == NULL)
3395 		fatal(NULL);
3396 	TAILQ_INIT(filter_l);
3397 	TAILQ_INIT(peerfilter_l);
3398 	TAILQ_INIT(groupfilter_l);
3399 
3400 	curpeer = NULL;
3401 	curgroup = NULL;
3402 
3403 	cur_peers = ph;
3404 	cur_rtrs = rh;
3405 	new_peers = &conf->peers;
3406 	netconf = &conf->networks;
3407 
3408 	if ((rr = add_rib("Adj-RIB-In")) == NULL)
3409 		fatal("add_rib failed");
3410 	rr->flags = F_RIB_NOFIB | F_RIB_NOEVALUATE;
3411 	if ((rr = add_rib("Loc-RIB")) == NULL)
3412 		fatal("add_rib failed");
3413 	rib_add_fib(rr, conf->default_tableid);
3414 	rr->flags = F_RIB_LOCAL;
3415 
3416 	if ((file = pushfile(filename, 1)) == NULL)
3417 		goto errors;
3418 	topfile = file;
3419 
3420 	yyparse();
3421 	errors = file->errors;
3422 	popfile();
3423 
3424 	/* check that we dont try to announce our own routes */
3425 	TAILQ_FOREACH(n, netconf, entry)
3426 	    if (n->net.priority == conf->fib_priority) {
3427 		    errors++;
3428 		    logit(LOG_CRIT, "network priority %d == fib-priority "
3429 			"%d is not allowed.",
3430 			n->net.priority, conf->fib_priority);
3431 	    }
3432 
3433 	/* Free macros and check which have not been used. */
3434 	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
3435 		if ((cmd_opts & BGPD_OPT_VERBOSE2) && !sym->used)
3436 			fprintf(stderr, "warning: macro \"%s\" not "
3437 			    "used\n", sym->nam);
3438 		if (!sym->persist) {
3439 			free(sym->nam);
3440 			free(sym->val);
3441 			TAILQ_REMOVE(&symhead, sym, entry);
3442 			free(sym);
3443 		}
3444 	}
3445 
3446 	if (!conf->as) {
3447 		log_warnx("configuration error: AS not given");
3448 		errors++;
3449 	}
3450 
3451 	/* clear the globals */
3452 	curpeer = NULL;
3453 	curgroup = NULL;
3454 	cur_peers = NULL;
3455 	new_peers = NULL;
3456 	netconf = NULL;
3457 
3458 	if (errors) {
3459 errors:
3460 		while ((rr = SIMPLEQ_FIRST(&ribnames)) != NULL) {
3461 			SIMPLEQ_REMOVE_HEAD(&ribnames, entry);
3462 			free(rr);
3463 		}
3464 
3465 		filterlist_free(filter_l);
3466 		filterlist_free(peerfilter_l);
3467 		filterlist_free(groupfilter_l);
3468 
3469 		free_config(conf);
3470 		return (NULL);
3471 	} else {
3472 		/* update clusterid in case it was not set explicitly */
3473 		if ((conf->flags & BGPD_FLAG_REFLECTOR) && conf->clusterid == 0)
3474 			conf->clusterid = conf->bgpid;
3475 
3476 		/*
3477 		 * Concatenate filter list and static group and peer filtersets
3478 		 * together. Static group sets come first then peer sets
3479 		 * last normal filter rules.
3480 		 */
3481 		TAILQ_CONCAT(conf->filters, groupfilter_l, entry);
3482 		TAILQ_CONCAT(conf->filters, peerfilter_l, entry);
3483 		TAILQ_CONCAT(conf->filters, filter_l, entry);
3484 
3485 		optimize_filters(conf->filters);
3486 
3487 		free(filter_l);
3488 		free(peerfilter_l);
3489 		free(groupfilter_l);
3490 
3491 		return (conf);
3492 	}
3493 }
3494 
3495 int
symset(const char * nam,const char * val,int persist)3496 symset(const char *nam, const char *val, int persist)
3497 {
3498 	struct sym	*sym;
3499 
3500 	TAILQ_FOREACH(sym, &symhead, entry) {
3501 		if (strcmp(nam, sym->nam) == 0)
3502 			break;
3503 	}
3504 
3505 	if (sym != NULL) {
3506 		if (sym->persist == 1)
3507 			return (0);
3508 		else {
3509 			free(sym->nam);
3510 			free(sym->val);
3511 			TAILQ_REMOVE(&symhead, sym, entry);
3512 			free(sym);
3513 		}
3514 	}
3515 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
3516 		return (-1);
3517 
3518 	sym->nam = strdup(nam);
3519 	if (sym->nam == NULL) {
3520 		free(sym);
3521 		return (-1);
3522 	}
3523 	sym->val = strdup(val);
3524 	if (sym->val == NULL) {
3525 		free(sym->nam);
3526 		free(sym);
3527 		return (-1);
3528 	}
3529 	sym->used = 0;
3530 	sym->persist = persist;
3531 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
3532 	return (0);
3533 }
3534 
3535 int
cmdline_symset(char * s)3536 cmdline_symset(char *s)
3537 {
3538 	char	*sym, *val;
3539 	int	ret;
3540 
3541 	if ((val = strrchr(s, '=')) == NULL)
3542 		return (-1);
3543 	sym = strndup(s, val - s);
3544 	if (sym == NULL)
3545 		fatal("%s: strndup", __func__);
3546 	ret = symset(sym, val + 1, 1);
3547 	free(sym);
3548 
3549 	return (ret);
3550 }
3551 
3552 char *
symget(const char * nam)3553 symget(const char *nam)
3554 {
3555 	struct sym	*sym;
3556 
3557 	TAILQ_FOREACH(sym, &symhead, entry) {
3558 		if (strcmp(nam, sym->nam) == 0) {
3559 			sym->used = 1;
3560 			return (sym->val);
3561 		}
3562 	}
3563 	return (NULL);
3564 }
3565 
3566 static int
cmpcommunity(struct community * a,struct community * b)3567 cmpcommunity(struct community *a, struct community *b)
3568 {
3569 	if (a->flags > b->flags)
3570 		return 1;
3571 	if (a->flags < b->flags)
3572 		return -1;
3573 	if (a->data1 > b->data1)
3574 		return 1;
3575 	if (a->data1 < b->data1)
3576 		return -1;
3577 	if (a->data2 > b->data2)
3578 		return 1;
3579 	if (a->data2 < b->data2)
3580 		return -1;
3581 	if (a->data3 > b->data3)
3582 		return 1;
3583 	if (a->data3 < b->data3)
3584 		return -1;
3585 	return 0;
3586 }
3587 
3588 static int
getcommunity(char * s,int large,u_int32_t * val,u_int32_t * flag)3589 getcommunity(char *s, int large, u_int32_t *val, u_int32_t *flag)
3590 {
3591 	long long	 max = USHRT_MAX;
3592 	const char	*errstr;
3593 
3594 	*flag = 0;
3595 	*val = 0;
3596 	if (strcmp(s, "*") == 0) {
3597 		*flag = COMMUNITY_ANY;
3598 		return 0;
3599 	} else if (strcmp(s, "neighbor-as") == 0) {
3600 		*flag = COMMUNITY_NEIGHBOR_AS;
3601 		return 0;
3602 	} else if (strcmp(s, "local-as") == 0) {
3603 		*flag =  COMMUNITY_LOCAL_AS;
3604 		return 0;
3605 	}
3606 	if (large)
3607 		max = UINT_MAX;
3608 	*val = strtonum(s, 0, max, &errstr);
3609 	if (errstr) {
3610 		yyerror("Community %s is %s (max: %lld)", s, errstr, max);
3611 		return -1;
3612 	}
3613 	return 0;
3614 }
3615 
3616 static void
setcommunity(struct community * c,u_int32_t as,u_int32_t data,u_int32_t asflag,u_int32_t dataflag)3617 setcommunity(struct community *c, u_int32_t as, u_int32_t data,
3618     u_int32_t asflag, u_int32_t dataflag)
3619 {
3620 	c->flags = COMMUNITY_TYPE_BASIC;
3621 	c->flags |= asflag << 8;
3622 	c->flags |= dataflag << 16;
3623 	c->data1 = as;
3624 	c->data2 = data;
3625 	c->data3 = 0;
3626 }
3627 
3628 static int
parselargecommunity(struct community * c,char * s)3629 parselargecommunity(struct community *c, char *s)
3630 {
3631 	char *p, *q;
3632 	u_int32_t dflag1, dflag2, dflag3;
3633 
3634 	if ((p = strchr(s, ':')) == NULL) {
3635 		yyerror("Bad community syntax");
3636 		return (-1);
3637 	}
3638 	*p++ = 0;
3639 
3640 	if ((q = strchr(p, ':')) == NULL) {
3641 		yyerror("Bad community syntax");
3642 		return (-1);
3643 	}
3644 	*q++ = 0;
3645 
3646 	if (getcommunity(s, 1, &c->data1, &dflag1) == -1 ||
3647 	    getcommunity(p, 1, &c->data2, &dflag2) == -1 ||
3648 	    getcommunity(q, 1, &c->data3, &dflag3) == -1)
3649 		return (-1);
3650 	c->flags = COMMUNITY_TYPE_LARGE;
3651 	c->flags |= dflag1 << 8;;
3652 	c->flags |= dflag2 << 16;;
3653 	c->flags |= dflag3 << 24;;
3654 	return (0);
3655 }
3656 
3657 int
parsecommunity(struct community * c,int type,char * s)3658 parsecommunity(struct community *c, int type, char *s)
3659 {
3660 	char *p;
3661 	u_int32_t as, data, asflag, dataflag;
3662 
3663 	if (type == COMMUNITY_TYPE_LARGE)
3664 		return parselargecommunity(c, s);
3665 
3666 	/* Well-known communities */
3667 	if (strcasecmp(s, "GRACEFUL_SHUTDOWN") == 0) {
3668 		setcommunity(c, COMMUNITY_WELLKNOWN,
3669 		    COMMUNITY_GRACEFUL_SHUTDOWN, 0, 0);
3670 		return (0);
3671 	} else if (strcasecmp(s, "NO_EXPORT") == 0) {
3672 		setcommunity(c, COMMUNITY_WELLKNOWN,
3673 		    COMMUNITY_NO_EXPORT, 0, 0);
3674 		return (0);
3675 	} else if (strcasecmp(s, "NO_ADVERTISE") == 0) {
3676 		setcommunity(c, COMMUNITY_WELLKNOWN,
3677 		    COMMUNITY_NO_ADVERTISE, 0, 0);
3678 		return (0);
3679 	} else if (strcasecmp(s, "NO_EXPORT_SUBCONFED") == 0) {
3680 		setcommunity(c, COMMUNITY_WELLKNOWN,
3681 		    COMMUNITY_NO_EXPSUBCONFED, 0, 0);
3682 		return (0);
3683 	} else if (strcasecmp(s, "NO_PEER") == 0) {
3684 		setcommunity(c, COMMUNITY_WELLKNOWN,
3685 		    COMMUNITY_NO_PEER, 0, 0);
3686 		return (0);
3687 	} else if (strcasecmp(s, "BLACKHOLE") == 0) {
3688 		setcommunity(c, COMMUNITY_WELLKNOWN,
3689 		    COMMUNITY_BLACKHOLE, 0, 0);
3690 		return (0);
3691 	}
3692 
3693 	if ((p = strchr(s, ':')) == NULL) {
3694 		yyerror("Bad community syntax");
3695 		return (-1);
3696 	}
3697 	*p++ = 0;
3698 
3699 	if (getcommunity(s, 0, &as, &asflag) == -1 ||
3700 	    getcommunity(p, 0, &data, &dataflag) == -1)
3701 		return (-1);
3702 	setcommunity(c, as, data, asflag, dataflag);
3703 	return (0);
3704 }
3705 
3706 static int
parsesubtype(char * name,int * type,int * subtype)3707 parsesubtype(char *name, int *type, int *subtype)
3708 {
3709 	const struct ext_comm_pairs *cp;
3710 	int found = 0;
3711 
3712 	for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
3713 		if (strcmp(name, cp->subname) == 0) {
3714 			if (found == 0) {
3715 				*type = cp->type;
3716 				*subtype = cp->subtype;
3717 			}
3718 			found++;
3719 		}
3720 	}
3721 	if (found > 1)
3722 		*type = -1;
3723 	return (found);
3724 }
3725 
3726 static int
parseextvalue(int type,char * s,u_int32_t * v,u_int32_t * flag)3727 parseextvalue(int type, char *s, u_int32_t *v, u_int32_t *flag)
3728 {
3729 	const char	*errstr;
3730 	char		*p;
3731 	struct in_addr	 ip;
3732 	u_int32_t	 uvalh, uval;
3733 
3734 	if (type != -1) {
3735 		/* nothing */
3736 	} else if (strcmp(s, "neighbor-as") == 0) {
3737 		*flag = COMMUNITY_NEIGHBOR_AS;
3738 		*v = 0;
3739 		return EXT_COMMUNITY_TRANS_FOUR_AS;
3740 	} else if (strcmp(s, "local-as") == 0) {
3741 		*flag = COMMUNITY_LOCAL_AS;
3742 		*v = 0;
3743 		return EXT_COMMUNITY_TRANS_FOUR_AS;
3744 	} else if ((p = strchr(s, '.')) == NULL) {
3745 		/* AS_PLAIN number (4 or 2 byte) */
3746 		strtonum(s, 0, USHRT_MAX, &errstr);
3747 		if (errstr == NULL)
3748 			type = EXT_COMMUNITY_TRANS_TWO_AS;
3749 		else
3750 			type = EXT_COMMUNITY_TRANS_FOUR_AS;
3751 	} else if (strchr(p + 1, '.') == NULL) {
3752 		/* AS_DOT number (4-byte) */
3753 		type = EXT_COMMUNITY_TRANS_FOUR_AS;
3754 	} else {
3755 		/* more than one dot -> IP address */
3756 		type = EXT_COMMUNITY_TRANS_IPV4;
3757 	}
3758 
3759 	switch (type) {
3760 	case EXT_COMMUNITY_TRANS_TWO_AS:
3761 		uval = strtonum(s, 0, USHRT_MAX, &errstr);
3762 		if (errstr) {
3763 			yyerror("Bad ext-community %s is %s", s, errstr);
3764 			return (-1);
3765 		}
3766 		*v = uval;
3767 		break;
3768 	case EXT_COMMUNITY_TRANS_FOUR_AS:
3769 		if ((p = strchr(s, '.')) == NULL) {
3770 			uval = strtonum(s, 0, UINT_MAX, &errstr);
3771 			if (errstr) {
3772 				yyerror("Bad ext-community %s is %s", s,
3773 				    errstr);
3774 				return (-1);
3775 			}
3776 			*v = uval;
3777 			break;
3778 		}
3779 		*p++ = '\0';
3780 		uvalh = strtonum(s, 0, USHRT_MAX, &errstr);
3781 		if (errstr) {
3782 			yyerror("Bad ext-community %s is %s", s, errstr);
3783 			return (-1);
3784 		}
3785 		uval = strtonum(p, 0, USHRT_MAX, &errstr);
3786 		if (errstr) {
3787 			yyerror("Bad ext-community %s is %s", p, errstr);
3788 			return (-1);
3789 		}
3790 		*v = uval | (uvalh << 16);
3791 		break;
3792 	case EXT_COMMUNITY_TRANS_IPV4:
3793 		if (inet_aton(s, &ip) == 0) {
3794 			yyerror("Bad ext-community %s not parseable", s);
3795 			return (-1);
3796 		}
3797 		*v = ntohl(ip.s_addr);
3798 		break;
3799 	default:
3800 		fatalx("%s: unexpected type %d", __func__, type);
3801 	}
3802 	return (type);
3803 }
3804 
3805 int
parseextcommunity(struct community * c,char * t,char * s)3806 parseextcommunity(struct community *c, char *t, char *s)
3807 {
3808 	const struct ext_comm_pairs *cp;
3809 	char		*p, *ep;
3810 	u_int64_t	 ullval;
3811 	u_int32_t	 uval, uval2, dflag1 = 0, dflag2 = 0;
3812 	int		 type = 0, subtype = 0;
3813 
3814 	if (strcmp(t, "*") == 0 && strcmp(s, "*") == 0) {
3815 		c->flags = COMMUNITY_TYPE_EXT;
3816 		c->flags |= COMMUNITY_ANY << 24;
3817 		return (0);
3818 	}
3819 	if (parsesubtype(t, &type, &subtype) == 0) {
3820 		yyerror("Bad ext-community unknown type");
3821 		return (-1);
3822 	}
3823 
3824 	switch (type) {
3825 	case EXT_COMMUNITY_TRANS_TWO_AS:
3826 	case EXT_COMMUNITY_TRANS_FOUR_AS:
3827 	case EXT_COMMUNITY_TRANS_IPV4:
3828 	case -1:
3829 		if (strcmp(s, "*") == 0) {
3830 			dflag1 = COMMUNITY_ANY;
3831 			break;
3832 		}
3833 		if ((p = strchr(s, ':')) == NULL) {
3834 			yyerror("Bad ext-community %s", s);
3835 			return (-1);
3836 		}
3837 		*p++ = '\0';
3838 		if ((type = parseextvalue(type, s, &uval, &dflag1)) == -1)
3839 			return (-1);
3840 
3841 		switch (type) {
3842 		case EXT_COMMUNITY_TRANS_TWO_AS:
3843 			if (getcommunity(p, 1, &uval2, &dflag2) == -1)
3844 				return (-1);
3845 			break;
3846 		case EXT_COMMUNITY_TRANS_IPV4:
3847 		case EXT_COMMUNITY_TRANS_FOUR_AS:
3848 			if (getcommunity(p, 0, &uval2, &dflag2) == -1)
3849 				return (-1);
3850 			break;
3851 		default:
3852 			fatalx("parseextcommunity: unexpected result");
3853 		}
3854 
3855 		c->data1 = uval;
3856 		c->data2 = uval2;
3857 		break;
3858 	case EXT_COMMUNITY_TRANS_OPAQUE:
3859 	case EXT_COMMUNITY_TRANS_EVPN:
3860 		if (strcmp(s, "*") == 0) {
3861 			dflag1 = COMMUNITY_ANY;
3862 			break;
3863 		}
3864 		errno = 0;
3865 		ullval = strtoull(s, &ep, 0);
3866 		if (s[0] == '\0' || *ep != '\0') {
3867 			yyerror("Bad ext-community bad value");
3868 			return (-1);
3869 		}
3870 		if (errno == ERANGE && ullval > EXT_COMMUNITY_OPAQUE_MAX) {
3871 			yyerror("Bad ext-community value too big");
3872 			return (-1);
3873 		}
3874 		c->data1 = ullval >> 32;
3875 		c->data2 = ullval;
3876 		break;
3877 	case EXT_COMMUNITY_NON_TRANS_OPAQUE:
3878 		if (subtype == EXT_COMMUNITY_SUBTYPE_OVS) {
3879 			if (strcmp(s, "valid") == 0) {
3880 				c->data2 = EXT_COMMUNITY_OVS_VALID;
3881 				break;
3882 			} else if (strcmp(s, "invalid") == 0) {
3883 				c->data2 = EXT_COMMUNITY_OVS_INVALID;
3884 				break;
3885 			} else if (strcmp(s, "not-found") == 0) {
3886 				c->data2 = EXT_COMMUNITY_OVS_NOTFOUND;
3887 				break;
3888 			} else if (strcmp(s, "*") == 0) {
3889 				dflag1 = COMMUNITY_ANY;
3890 				break;
3891 			}
3892 		}
3893 		yyerror("Bad ext-community %s", s);
3894 		return (-1);
3895 	}
3896 
3897 	c->data3 = type << 8 | subtype;
3898 
3899 	/* special handling of ext-community rt * since type is not known */
3900 	if (dflag1 == COMMUNITY_ANY && type == -1) {
3901 		c->flags = COMMUNITY_TYPE_EXT;
3902 		c->flags |= dflag1 << 8;
3903 		return (0);
3904 	}
3905 
3906 	/* verify type/subtype combo */
3907 	for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
3908 		if (cp->type == type && cp->subtype == subtype) {
3909 			c->flags = COMMUNITY_TYPE_EXT;
3910 			c->flags |= dflag1 << 8;
3911 			c->flags |= dflag2 << 16;
3912 			return (0);
3913 		}
3914 	}
3915 
3916 	yyerror("Bad ext-community bad format for type");
3917 	return (-1);
3918 }
3919 
3920 struct peer *
alloc_peer(void)3921 alloc_peer(void)
3922 {
3923 	struct peer	*p;
3924 	u_int8_t	 i;
3925 
3926 	if ((p = calloc(1, sizeof(struct peer))) == NULL)
3927 		fatal("new_peer");
3928 
3929 	/* some sane defaults */
3930 	p->state = STATE_NONE;
3931 	p->reconf_action = RECONF_REINIT;
3932 	p->conf.distance = 1;
3933 	p->conf.export_type = EXPORT_UNSET;
3934 	p->conf.announce_capa = 1;
3935 	for (i = 0; i < AID_MAX; i++)
3936 		p->conf.capabilities.mp[i] = 0;
3937 	p->conf.capabilities.refresh = 1;
3938 	p->conf.capabilities.grestart.restart = 1;
3939 	p->conf.capabilities.as4byte = 1;
3940 	p->conf.local_as = conf->as;
3941 	p->conf.local_short_as = conf->short_as;
3942 
3943 	if (conf->flags & BGPD_FLAG_DECISION_TRANS_AS)
3944 		p->conf.flags |= PEERFLAG_TRANS_AS;
3945 	if (conf->flags & BGPD_FLAG_DECISION_ALL_PATHS)
3946 		p->conf.flags |= PEERFLAG_EVALUATE_ALL;
3947 	if (conf->flags & BGPD_FLAG_NO_AS_SET)
3948 		p->conf.flags |= PEERFLAG_NO_AS_SET;
3949 
3950 	return (p);
3951 }
3952 
3953 struct peer *
new_peer(void)3954 new_peer(void)
3955 {
3956 	struct peer		*p;
3957 
3958 	p = alloc_peer();
3959 
3960 	if (curgroup != NULL) {
3961 		memcpy(p, curgroup, sizeof(struct peer));
3962 		if (strlcpy(p->conf.group, curgroup->conf.group,
3963 		    sizeof(p->conf.group)) >= sizeof(p->conf.group))
3964 			fatalx("new_peer group strlcpy");
3965 		if (strlcpy(p->conf.descr, curgroup->conf.descr,
3966 		    sizeof(p->conf.descr)) >= sizeof(p->conf.descr))
3967 			fatalx("new_peer descr strlcpy");
3968 		p->conf.groupid = curgroup->conf.id;
3969 	}
3970 	return (p);
3971 }
3972 
3973 struct peer *
new_group(void)3974 new_group(void)
3975 {
3976 	return (alloc_peer());
3977 }
3978 
3979 int
add_mrtconfig(enum mrt_type type,char * name,int timeout,struct peer * p,char * rib)3980 add_mrtconfig(enum mrt_type type, char *name, int timeout, struct peer *p,
3981     char *rib)
3982 {
3983 	struct mrt	*m, *n;
3984 
3985 	LIST_FOREACH(m, conf->mrt, entry) {
3986 		if ((rib && strcmp(rib, m->rib)) ||
3987 		    (!rib && *m->rib))
3988 			continue;
3989 		if (p == NULL) {
3990 			if (m->peer_id != 0 || m->group_id != 0)
3991 				continue;
3992 		} else {
3993 			if (m->peer_id != p->conf.id ||
3994 			    m->group_id != p->conf.groupid)
3995 				continue;
3996 		}
3997 		if (m->type == type) {
3998 			yyerror("only one mrtdump per type allowed.");
3999 			return (-1);
4000 		}
4001 	}
4002 
4003 	if ((n = calloc(1, sizeof(struct mrt_config))) == NULL)
4004 		fatal("add_mrtconfig");
4005 
4006 	n->type = type;
4007 	if (strlcpy(MRT2MC(n)->name, name, sizeof(MRT2MC(n)->name)) >=
4008 	    sizeof(MRT2MC(n)->name)) {
4009 		yyerror("filename \"%s\" too long: max %zu",
4010 		    name, sizeof(MRT2MC(n)->name) - 1);
4011 		free(n);
4012 		return (-1);
4013 	}
4014 	MRT2MC(n)->ReopenTimerInterval = timeout;
4015 	if (p != NULL) {
4016 		if (curgroup == p) {
4017 			n->peer_id = 0;
4018 			n->group_id = p->conf.id;
4019 		} else {
4020 			n->peer_id = p->conf.id;
4021 			n->group_id = 0;
4022 		}
4023 	}
4024 	if (rib) {
4025 		if (!find_rib(rib)) {
4026 			yyerror("rib \"%s\" does not exist.", rib);
4027 			free(n);
4028 			return (-1);
4029 		}
4030 		if (strlcpy(n->rib, rib, sizeof(n->rib)) >=
4031 		    sizeof(n->rib)) {
4032 			yyerror("rib name \"%s\" too long: max %zu",
4033 			    name, sizeof(n->rib) - 1);
4034 			free(n);
4035 			return (-1);
4036 		}
4037 	}
4038 
4039 	LIST_INSERT_HEAD(conf->mrt, n, entry);
4040 
4041 	return (0);
4042 }
4043 
4044 struct rde_rib *
add_rib(char * name)4045 add_rib(char *name)
4046 {
4047 	struct rde_rib	*rr;
4048 
4049 	if ((rr = find_rib(name)) == NULL) {
4050 		if ((rr = calloc(1, sizeof(*rr))) == NULL) {
4051 			log_warn("add_rib");
4052 			return (NULL);
4053 		}
4054 		if (strlcpy(rr->name, name, sizeof(rr->name)) >=
4055 		    sizeof(rr->name)) {
4056 			yyerror("rib name \"%s\" too long: max %zu",
4057 			    name, sizeof(rr->name) - 1);
4058 			free(rr);
4059 			return (NULL);
4060 		}
4061 		rr->flags = F_RIB_NOFIB;
4062 		SIMPLEQ_INSERT_TAIL(&ribnames, rr, entry);
4063 	}
4064 	return (rr);
4065 }
4066 
4067 struct rde_rib *
find_rib(char * name)4068 find_rib(char *name)
4069 {
4070 	struct rde_rib	*rr;
4071 
4072 	SIMPLEQ_FOREACH(rr, &ribnames, entry) {
4073 		if (!strcmp(rr->name, name))
4074 			return (rr);
4075 	}
4076 	return (NULL);
4077 }
4078 
4079 int
rib_add_fib(struct rde_rib * rr,u_int rtableid)4080 rib_add_fib(struct rde_rib *rr, u_int rtableid)
4081 {
4082 	u_int	rdom;
4083 
4084 	if (ktable_exists(rtableid, &rdom) != 1) {
4085 		yyerror("rtable id %u does not exist", rtableid);
4086 		return (-1);
4087 	}
4088 	/*
4089 	 * conf->default_tableid is also a rdomain because that is checked
4090 	 * in init_config()
4091 	 */
4092 	if (rdom != conf->default_tableid) {
4093 		log_warnx("rtable %u does not belong to rdomain %u",
4094 		    rtableid, conf->default_tableid);
4095 		return (-1);
4096 	}
4097 	rr->rtableid = rtableid;
4098 	rr->flags &= ~F_RIB_NOFIB;
4099 	return (0);
4100 }
4101 
4102 struct prefixset *
find_prefixset(char * name,struct prefixset_head * p)4103 find_prefixset(char *name, struct prefixset_head *p)
4104 {
4105 	struct prefixset *ps;
4106 
4107 	SIMPLEQ_FOREACH(ps, p, entry) {
4108 		if (!strcmp(ps->name, name))
4109 			return (ps);
4110 	}
4111 	return (NULL);
4112 }
4113 
4114 int
get_id(struct peer * newpeer)4115 get_id(struct peer *newpeer)
4116 {
4117 	static u_int32_t id = PEER_ID_STATIC_MIN;
4118 	struct peer	*p = NULL;
4119 
4120 	/* check if the peer already existed before */
4121 	if (newpeer->conf.remote_addr.aid) {
4122 		/* neighbor */
4123 		if (cur_peers)
4124 			RB_FOREACH(p, peer_head, cur_peers)
4125 				if (p->conf.remote_masklen ==
4126 				    newpeer->conf.remote_masklen &&
4127 				    memcmp(&p->conf.remote_addr,
4128 				    &newpeer->conf.remote_addr,
4129 				    sizeof(p->conf.remote_addr)) == 0)
4130 					break;
4131 		if (p) {
4132 			newpeer->conf.id = p->conf.id;
4133 			return (0);
4134 		}
4135 	} else {
4136 		/* group */
4137 		if (cur_peers)
4138 			RB_FOREACH(p, peer_head, cur_peers)
4139 				if (strcmp(p->conf.group,
4140 				    newpeer->conf.group) == 0)
4141 					break;
4142 		if (p) {
4143 			newpeer->conf.id = p->conf.groupid;
4144 			return (0);
4145 		}
4146 	}
4147 
4148 	/* else new one */
4149 	if (id < PEER_ID_STATIC_MAX) {
4150 		newpeer->conf.id = id++;
4151 		return (0);
4152 	}
4153 
4154 	return (-1);
4155 }
4156 
4157 int
merge_prefixspec(struct filter_prefix * p,struct filter_prefixlen * pl)4158 merge_prefixspec(struct filter_prefix *p, struct filter_prefixlen *pl)
4159 {
4160 	u_int8_t max_len = 0;
4161 
4162 	switch (p->addr.aid) {
4163 	case AID_INET:
4164 	case AID_VPN_IPv4:
4165 		max_len = 32;
4166 		break;
4167 	case AID_INET6:
4168 	case AID_VPN_IPv6:
4169 		max_len = 128;
4170 		break;
4171 	}
4172 
4173 	if (pl->op == OP_NONE) {
4174 		p->len_min = p->len_max = p->len;
4175 		return (0);
4176 	}
4177 
4178 	if (pl->len_min == -1)
4179 		pl->len_min = p->len;
4180 	if (pl->len_max == -1)
4181 		pl->len_max = max_len;
4182 
4183 	if (pl->len_max > max_len) {
4184 		yyerror("prefixlen %d too big, limit %d",
4185 		    pl->len_max, max_len);
4186 		return (-1);
4187 	}
4188 	if (pl->len_min > pl->len_max) {
4189 		yyerror("prefixlen %d too big, limit %d",
4190 		    pl->len_min, pl->len_max);
4191 		return (-1);
4192 	}
4193 	if (pl->len_min < p->len) {
4194 		yyerror("prefixlen %d smaller than prefix, limit %d",
4195 		    pl->len_min, p->len);
4196 		return (-1);
4197 	}
4198 
4199 	p->op = pl->op;
4200 	p->len_min = pl->len_min;
4201 	p->len_max = pl->len_max;
4202 	return (0);
4203 }
4204 
4205 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)4206 expand_rule(struct filter_rule *rule, struct filter_rib_l *rib,
4207     struct filter_peers_l *peer, struct filter_match_l *match,
4208     struct filter_set_head *set)
4209 {
4210 	struct filter_rule	*r;
4211 	struct filter_rib_l	*rb, *rbnext;
4212 	struct filter_peers_l	*p, *pnext;
4213 	struct filter_prefix_l	*prefix, *prefix_next;
4214 	struct filter_as_l	*a, *anext;
4215 	struct filter_set	*s;
4216 
4217 	rb = rib;
4218 	do {
4219 		p = peer;
4220 		do {
4221 			a = match->as_l;
4222 			do {
4223 				prefix = match->prefix_l;
4224 				do {
4225 					if ((r = calloc(1,
4226 					    sizeof(struct filter_rule))) ==
4227 						 NULL) {
4228 						log_warn("expand_rule");
4229 						return (-1);
4230 					}
4231 
4232 					memcpy(r, rule, sizeof(struct filter_rule));
4233 					memcpy(&r->match, match,
4234 					    sizeof(struct filter_match));
4235 					filterset_copy(set, &r->set);
4236 
4237 					if (rb != NULL)
4238 						strlcpy(r->rib, rb->name,
4239 						     sizeof(r->rib));
4240 
4241 					if (p != NULL)
4242 						memcpy(&r->peer, &p->p,
4243 						    sizeof(struct filter_peers));
4244 
4245 					if (prefix != NULL)
4246 						memcpy(&r->match.prefix, &prefix->p,
4247 						    sizeof(r->match.prefix));
4248 
4249 					if (a != NULL)
4250 						memcpy(&r->match.as, &a->a,
4251 						    sizeof(struct filter_as));
4252 
4253 					TAILQ_INSERT_TAIL(filter_l, r, entry);
4254 
4255 					if (prefix != NULL)
4256 						prefix = prefix->next;
4257 				} while (prefix != NULL);
4258 
4259 				if (a != NULL)
4260 					a = a->next;
4261 			} while (a != NULL);
4262 
4263 			if (p != NULL)
4264 				p = p->next;
4265 		} while (p != NULL);
4266 
4267 		if (rb != NULL)
4268 			rb = rb->next;
4269 	} while (rb != NULL);
4270 
4271 	for (rb = rib; rb != NULL; rb = rbnext) {
4272 		rbnext = rb->next;
4273 		free(rb);
4274 	}
4275 
4276 	for (p = peer; p != NULL; p = pnext) {
4277 		pnext = p->next;
4278 		free(p);
4279 	}
4280 
4281 	for (a = match->as_l; a != NULL; a = anext) {
4282 		anext = a->next;
4283 		free(a);
4284 	}
4285 
4286 	for (prefix = match->prefix_l; prefix != NULL; prefix = prefix_next) {
4287 		prefix_next = prefix->next;
4288 		free(prefix);
4289 	}
4290 
4291 	if (set != NULL) {
4292 		while ((s = TAILQ_FIRST(set)) != NULL) {
4293 			TAILQ_REMOVE(set, s, entry);
4294 			free(s);
4295 		}
4296 		free(set);
4297 	}
4298 
4299 	return (0);
4300 }
4301 
4302 int
str2key(char * s,char * dest,size_t max_len)4303 str2key(char *s, char *dest, size_t max_len)
4304 {
4305 	unsigned	i;
4306 	char		t[3];
4307 
4308 	if (strlen(s) / 2 > max_len) {
4309 		yyerror("key too long");
4310 		return (-1);
4311 	}
4312 
4313 	if (strlen(s) % 2) {
4314 		yyerror("key must be of even length");
4315 		return (-1);
4316 	}
4317 
4318 	for (i = 0; i < strlen(s) / 2; i++) {
4319 		t[0] = s[2*i];
4320 		t[1] = s[2*i + 1];
4321 		t[2] = 0;
4322 		if (!isxdigit(t[0]) || !isxdigit(t[1])) {
4323 			yyerror("key must be specified in hex");
4324 			return (-1);
4325 		}
4326 		dest[i] = strtoul(t, NULL, 16);
4327 	}
4328 
4329 	return (0);
4330 }
4331 
4332 int
neighbor_consistent(struct peer * p)4333 neighbor_consistent(struct peer *p)
4334 {
4335 	struct bgpd_addr *local_addr;
4336 	struct peer *xp;
4337 
4338 	switch (p->conf.remote_addr.aid) {
4339 	case AID_INET:
4340 		local_addr = &p->conf.local_addr_v4;
4341 		break;
4342 	case AID_INET6:
4343 		local_addr = &p->conf.local_addr_v6;
4344 		break;
4345 	default:
4346 		yyerror("Bad address family for remote-addr");
4347 		return (-1);
4348 	}
4349 
4350 	/* with any form of ipsec local-address is required */
4351 	if ((p->conf.auth.method == AUTH_IPSEC_IKE_ESP ||
4352 	    p->conf.auth.method == AUTH_IPSEC_IKE_AH ||
4353 	    p->conf.auth.method == AUTH_IPSEC_MANUAL_ESP ||
4354 	    p->conf.auth.method == AUTH_IPSEC_MANUAL_AH) &&
4355 	    local_addr->aid == AID_UNSPEC) {
4356 		yyerror("neighbors with any form of IPsec configured "
4357 		    "need local-address to be specified");
4358 		return (-1);
4359 	}
4360 
4361 	/* with static keying we need both directions */
4362 	if ((p->conf.auth.method == AUTH_IPSEC_MANUAL_ESP ||
4363 	    p->conf.auth.method == AUTH_IPSEC_MANUAL_AH) &&
4364 	    (!p->conf.auth.spi_in || !p->conf.auth.spi_out)) {
4365 		yyerror("with manual keyed IPsec, SPIs and keys "
4366 		    "for both directions are required");
4367 		return (-1);
4368 	}
4369 
4370 	if (!conf->as) {
4371 		yyerror("AS needs to be given before neighbor definitions");
4372 		return (-1);
4373 	}
4374 
4375 	/* set default values if they where undefined */
4376 	p->conf.ebgp = (p->conf.remote_as != conf->as);
4377 	if (p->conf.enforce_as == ENFORCE_AS_UNDEF)
4378 		p->conf.enforce_as = p->conf.ebgp ?
4379 		    ENFORCE_AS_ON : ENFORCE_AS_OFF;
4380 	if (p->conf.enforce_local_as == ENFORCE_AS_UNDEF)
4381 		p->conf.enforce_local_as = ENFORCE_AS_ON;
4382 
4383 	if (p->conf.remote_as == 0 && !p->conf.template) {
4384 		yyerror("peer AS may not be zero");
4385 		return (-1);
4386 	}
4387 
4388 	/* EBGP neighbors are not allowed in route reflector clusters */
4389 	if (p->conf.reflector_client && p->conf.ebgp) {
4390 		yyerror("EBGP neighbors are not allowed in route "
4391 		    "reflector clusters");
4392 		return (-1);
4393 	}
4394 
4395 	/* check for duplicate peer definitions */
4396 	RB_FOREACH(xp, peer_head, new_peers)
4397 		if (xp->conf.remote_masklen ==
4398 		    p->conf.remote_masklen &&
4399 		    memcmp(&xp->conf.remote_addr,
4400 		    &p->conf.remote_addr,
4401 		    sizeof(p->conf.remote_addr)) == 0)
4402 			break;
4403 	if (xp != NULL) {
4404 		char *descr = log_fmt_peer(&p->conf);
4405 		yyerror("duplicate %s", descr);
4406 		free(descr);
4407 		return (-1);
4408 	}
4409 
4410 	return (0);
4411 }
4412 
4413 static void
filterset_add(struct filter_set_head * sh,struct filter_set * s)4414 filterset_add(struct filter_set_head *sh, struct filter_set *s)
4415 {
4416 	struct filter_set	*t;
4417 
4418 	TAILQ_FOREACH(t, sh, entry) {
4419 		if (s->type < t->type) {
4420 			TAILQ_INSERT_BEFORE(t, s, entry);
4421 			return;
4422 		}
4423 		if (s->type == t->type) {
4424 			switch (s->type) {
4425 			case ACTION_SET_COMMUNITY:
4426 			case ACTION_DEL_COMMUNITY:
4427 				switch (cmpcommunity(&s->action.community,
4428 				    &t->action.community)) {
4429 				case -1:
4430 					TAILQ_INSERT_BEFORE(t, s, entry);
4431 					return;
4432 				case 0:
4433 					break;
4434 				case 1:
4435 					continue;
4436 				}
4437 				break;
4438 			case ACTION_SET_NEXTHOP:
4439 				/* only last nexthop per AF matters */
4440 				if (s->action.nexthop.aid <
4441 				    t->action.nexthop.aid) {
4442 					TAILQ_INSERT_BEFORE(t, s, entry);
4443 					return;
4444 				} else if (s->action.nexthop.aid ==
4445 				    t->action.nexthop.aid) {
4446 					t->action.nexthop = s->action.nexthop;
4447 					break;
4448 				}
4449 				continue;
4450 			case ACTION_SET_NEXTHOP_BLACKHOLE:
4451 			case ACTION_SET_NEXTHOP_REJECT:
4452 			case ACTION_SET_NEXTHOP_NOMODIFY:
4453 			case ACTION_SET_NEXTHOP_SELF:
4454 				/* set it only once */
4455 				break;
4456 			case ACTION_SET_LOCALPREF:
4457 			case ACTION_SET_MED:
4458 			case ACTION_SET_WEIGHT:
4459 				/* only last set matters */
4460 				t->action.metric = s->action.metric;
4461 				break;
4462 			case ACTION_SET_RELATIVE_LOCALPREF:
4463 			case ACTION_SET_RELATIVE_MED:
4464 			case ACTION_SET_RELATIVE_WEIGHT:
4465 				/* sum all relative numbers */
4466 				t->action.relative += s->action.relative;
4467 				break;
4468 			case ACTION_SET_ORIGIN:
4469 				/* only last set matters */
4470 				t->action.origin = s->action.origin;
4471 				break;
4472 			case ACTION_PFTABLE:
4473 				/* only last set matters */
4474 				strlcpy(t->action.pftable, s->action.pftable,
4475 				    sizeof(t->action.pftable));
4476 				break;
4477 			case ACTION_RTLABEL:
4478 				/* only last set matters */
4479 				strlcpy(t->action.rtlabel, s->action.rtlabel,
4480 				    sizeof(t->action.rtlabel));
4481 				break;
4482 			default:
4483 				break;
4484 			}
4485 			free(s);
4486 			return;
4487 		}
4488 	}
4489 
4490 	TAILQ_INSERT_TAIL(sh, s, entry);
4491 }
4492 
4493 int
merge_filterset(struct filter_set_head * sh,struct filter_set * s)4494 merge_filterset(struct filter_set_head *sh, struct filter_set *s)
4495 {
4496 	struct filter_set	*t;
4497 
4498 	TAILQ_FOREACH(t, sh, entry) {
4499 		/*
4500 		 * need to cycle across the full list because even
4501 		 * if types are not equal filterset_cmp() may return 0.
4502 		 */
4503 		if (filterset_cmp(s, t) == 0) {
4504 			if (s->type == ACTION_SET_COMMUNITY)
4505 				yyerror("community is already set");
4506 			else if (s->type == ACTION_DEL_COMMUNITY)
4507 				yyerror("community will already be deleted");
4508 			else
4509 				yyerror("redefining set parameter %s",
4510 				    filterset_name(s->type));
4511 			return (-1);
4512 		}
4513 	}
4514 
4515 	filterset_add(sh, s);
4516 	return (0);
4517 }
4518 
4519 static int
filter_equal(struct filter_rule * fa,struct filter_rule * fb)4520 filter_equal(struct filter_rule *fa, struct filter_rule *fb)
4521 {
4522 	if (fa == NULL || fb == NULL)
4523 		return 0;
4524 	if (fa->action != fb->action || fa->quick != fb->quick ||
4525 	    fa->dir != fb->dir)
4526 		return 0;
4527 	if (memcmp(&fa->peer, &fb->peer, sizeof(fa->peer)))
4528 		return 0;
4529 	if (memcmp(&fa->match, &fb->match, sizeof(fa->match)))
4530 		return 0;
4531 
4532 	return 1;
4533 }
4534 
4535 /* do a basic optimization by folding equal rules together */
4536 void
optimize_filters(struct filter_head * fh)4537 optimize_filters(struct filter_head *fh)
4538 {
4539 	struct filter_rule *r, *nr;
4540 
4541 	TAILQ_FOREACH_SAFE(r, fh, entry, nr) {
4542 		while (filter_equal(r, nr)) {
4543 			struct filter_set	*t;
4544 
4545 			while ((t = TAILQ_FIRST(&nr->set)) != NULL) {
4546 				TAILQ_REMOVE(&nr->set, t, entry);
4547 				filterset_add(&r->set, t);
4548 			}
4549 
4550 			TAILQ_REMOVE(fh, nr, entry);
4551 			free(nr);
4552 			nr = TAILQ_NEXT(r, entry);
4553 		}
4554 	}
4555 }
4556 
4557 struct filter_rule *
get_rule(enum action_types type)4558 get_rule(enum action_types type)
4559 {
4560 	struct filter_rule	*r;
4561 	int			 out;
4562 
4563 	switch (type) {
4564 	case ACTION_SET_PREPEND_SELF:
4565 	case ACTION_SET_NEXTHOP_NOMODIFY:
4566 	case ACTION_SET_NEXTHOP_SELF:
4567 		out = 1;
4568 		break;
4569 	default:
4570 		out = 0;
4571 		break;
4572 	}
4573 	r = (curpeer == curgroup) ? curgroup_filter[out] : curpeer_filter[out];
4574 	if (r == NULL) {
4575 		if ((r = calloc(1, sizeof(struct filter_rule))) == NULL)
4576 			fatal(NULL);
4577 		r->quick = 0;
4578 		r->dir = out ? DIR_OUT : DIR_IN;
4579 		r->action = ACTION_NONE;
4580 		TAILQ_INIT(&r->set);
4581 		if (curpeer == curgroup) {
4582 			/* group */
4583 			r->peer.groupid = curgroup->conf.id;
4584 			curgroup_filter[out] = r;
4585 		} else {
4586 			/* peer */
4587 			r->peer.peerid = curpeer->conf.id;
4588 			curpeer_filter[out] = r;
4589 		}
4590 	}
4591 	return (r);
4592 }
4593 
4594 struct set_table *curset;
4595 static int
new_as_set(char * name)4596 new_as_set(char *name)
4597 {
4598 	struct as_set *aset;
4599 
4600 	if (as_sets_lookup(&conf->as_sets, name) != NULL) {
4601 		yyerror("as-set \"%s\" already exists", name);
4602 		return -1;
4603 	}
4604 
4605 	aset = as_sets_new(&conf->as_sets, name, 0, sizeof(u_int32_t));
4606 	if (aset == NULL)
4607 		fatal(NULL);
4608 
4609 	curset = aset->set;
4610 	return 0;
4611 }
4612 
4613 static void
add_as_set(u_int32_t as)4614 add_as_set(u_int32_t as)
4615 {
4616 	if (curset == NULL)
4617 		fatalx("%s: bad mojo jojo", __func__);
4618 
4619 	if (set_add(curset, &as, 1) != 0)
4620 		fatal(NULL);
4621 }
4622 
4623 static void
done_as_set(void)4624 done_as_set(void)
4625 {
4626 	curset = NULL;
4627 }
4628 
4629 static struct prefixset *
new_prefix_set(char * name,int is_roa)4630 new_prefix_set(char *name, int is_roa)
4631 {
4632 	const char *type = "prefix-set";
4633 	struct prefixset_head *sets = &conf->prefixsets;
4634 	struct prefixset *pset;
4635 
4636 	if (is_roa) {
4637 		type = "origin-set";
4638 		sets = &conf->originsets;
4639 	}
4640 
4641 	if (find_prefixset(name, sets) != NULL)  {
4642 		yyerror("%s \"%s\" already exists", type, name);
4643 		return NULL;
4644 	}
4645 	if ((pset = calloc(1, sizeof(*pset))) == NULL)
4646 		fatal("prefixset");
4647 	if (strlcpy(pset->name, name, sizeof(pset->name)) >=
4648 	    sizeof(pset->name)) {
4649 		yyerror("%s \"%s\" too long: max %zu", type,
4650 		    name, sizeof(pset->name) - 1);
4651 		free(pset);
4652 		return NULL;
4653 	}
4654 	RB_INIT(&pset->psitems);
4655 	RB_INIT(&pset->roaitems);
4656 	return pset;
4657 }
4658 
4659 static void
add_roa_set(struct prefixset_item * npsi,u_int32_t as,u_int8_t max)4660 add_roa_set(struct prefixset_item *npsi, u_int32_t as, u_int8_t max)
4661 {
4662 	struct roa *roa, *r;
4663 
4664 	if ((roa = calloc(1, sizeof(*roa))) == NULL)
4665 		fatal("add_roa_set");
4666 
4667 	roa->aid = npsi->p.addr.aid;
4668 	roa->prefixlen = npsi->p.len;
4669 	roa->maxlen = max;
4670 	roa->asnum = as;
4671 	switch (roa->aid) {
4672 	case AID_INET:
4673 		roa->prefix.inet = npsi->p.addr.v4;
4674 		break;
4675 	case AID_INET6:
4676 		roa->prefix.inet6 = npsi->p.addr.v6;
4677 		break;
4678 	default:
4679 		fatalx("Bad address family for roa_set address");
4680 	}
4681 
4682 	r = RB_INSERT(roa_tree, curroatree, roa);
4683 	if (r != NULL)
4684 		/* just ignore duplicates */
4685 		free(roa);
4686 }
4687 
4688 static struct rtr_config *
get_rtr(struct bgpd_addr * addr)4689 get_rtr(struct bgpd_addr *addr)
4690 {
4691 	struct rtr_config *n;
4692 
4693 	n = calloc(1, sizeof(*n));
4694 	if (n == NULL) {
4695 		yyerror("out of memory");
4696 		return NULL;
4697 	}
4698 
4699 	n->remote_addr = *addr;
4700 	strlcpy(n->descr, log_addr(addr), sizeof(currtr->descr));
4701 
4702 	return n;
4703 }
4704 
4705 static int
insert_rtr(struct rtr_config * new)4706 insert_rtr(struct rtr_config *new)
4707 {
4708 	static uint32_t id;
4709 	struct rtr_config *r;
4710 
4711 	if (id == UINT32_MAX) {
4712 		yyerror("out of rtr session IDs");
4713 		return -1;
4714 	}
4715 
4716 	SIMPLEQ_FOREACH(r, &conf->rtrs, entry)
4717 		if (memcmp(&r->remote_addr, &new->remote_addr,
4718 		    sizeof(r->remote_addr)) == 0 &&
4719 		    r->remote_port == new->remote_port) {
4720 			yyerror("duplicate rtr session to %s:%u",
4721 			    log_addr(&new->remote_addr), new->remote_port);
4722 			return -1;
4723 		}
4724 
4725 	if (cur_rtrs)
4726 		SIMPLEQ_FOREACH(r, cur_rtrs, entry)
4727 			if (memcmp(&r->remote_addr, &new->remote_addr,
4728 			    sizeof(r->remote_addr)) == 0 &&
4729 			    r->remote_port == new->remote_port) {
4730 				new->id = r->id;
4731 				break;
4732 			}
4733 
4734 	if (new->id == 0)
4735 		new->id = ++id;
4736 
4737 	SIMPLEQ_INSERT_TAIL(&conf->rtrs, currtr, entry);
4738 
4739 	return 0;
4740 }
4741