xref: /openbsd-src/usr.sbin/bgpd/parse.y (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: parse.y,v 1.288 2016/06/21 21:35:24 benno 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  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 %{
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <sys/stat.h>
26 #include <sys/un.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <netmpls/mpls.h>
30 
31 #include <ctype.h>
32 #include <err.h>
33 #include <unistd.h>
34 #include <errno.h>
35 #include <limits.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <syslog.h>
40 
41 #include "bgpd.h"
42 #include "mrt.h"
43 #include "session.h"
44 #include "rde.h"
45 
46 TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
47 static struct file {
48 	TAILQ_ENTRY(file)	 entry;
49 	FILE			*stream;
50 	char			*name;
51 	int			 lineno;
52 	int			 errors;
53 } *file, *topfile;
54 struct file	*pushfile(const char *, int);
55 int		 popfile(void);
56 int		 check_file_secrecy(int, const char *);
57 int		 yyparse(void);
58 int		 yylex(void);
59 int		 yyerror(const char *, ...)
60     __attribute__((__format__ (printf, 1, 2)))
61     __attribute__((__nonnull__ (1)));
62 int		 kw_cmp(const void *, const void *);
63 int		 lookup(char *);
64 int		 lgetc(int);
65 int		 lungetc(int);
66 int		 findeol(void);
67 
68 TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
69 struct sym {
70 	TAILQ_ENTRY(sym)	 entry;
71 	int			 used;
72 	int			 persist;
73 	char			*nam;
74 	char			*val;
75 };
76 int		 symset(const char *, const char *, int);
77 char		*symget(const char *);
78 
79 static struct bgpd_config	*conf;
80 static struct network_head	*netconf;
81 static struct peer		*peer_l, *peer_l_old;
82 static struct peer		*curpeer;
83 static struct peer		*curgroup;
84 static struct rdomain		*currdom;
85 static struct filter_head	*filter_l;
86 static struct filter_head	*peerfilter_l;
87 static struct filter_head	*groupfilter_l;
88 static struct filter_rule	*curpeer_filter[2];
89 static struct filter_rule	*curgroup_filter[2];
90 static u_int32_t		 id;
91 
92 struct filter_peers_l {
93 	struct filter_peers_l	*next;
94 	struct filter_peers	 p;
95 };
96 
97 struct filter_prefix_l {
98 	struct filter_prefix_l	*next;
99 	struct filter_prefix	 p;
100 };
101 
102 struct filter_prefixlen {
103 	enum comp_ops		op;
104 	int			len_min;
105 	int			len_max;
106 };
107 
108 struct filter_as_l {
109 	struct filter_as_l	*next;
110 	struct filter_as	 a;
111 };
112 
113 struct filter_match_l {
114 	struct filter_match	 m;
115 	struct filter_prefix_l	*prefix_l;
116 	struct filter_as_l	*as_l;
117 } fmopts;
118 
119 struct peer	*alloc_peer(void);
120 struct peer	*new_peer(void);
121 struct peer	*new_group(void);
122 int		 add_mrtconfig(enum mrt_type, char *, int, struct peer *,
123 		    char *);
124 int		 add_rib(char *, u_int, u_int16_t);
125 struct rde_rib	*find_rib(char *);
126 int		 get_id(struct peer *);
127 int		 merge_prefixspec(struct filter_prefix_l *,
128 		    struct filter_prefixlen *);
129 int		 expand_rule(struct filter_rule *, struct filter_peers_l *,
130 		    struct filter_match_l *, struct filter_set_head *);
131 int		 str2key(char *, char *, size_t);
132 int		 neighbor_consistent(struct peer *);
133 int		 merge_filterset(struct filter_set_head *, struct filter_set *);
134 void		 copy_filterset(struct filter_set_head *,
135 		    struct filter_set_head *);
136 void		 merge_filter_lists(struct filter_head *, struct filter_head *);
137 struct filter_rule	*get_rule(enum action_types);
138 
139 int		 getcommunity(char *);
140 int		 parsecommunity(struct filter_community *, char *);
141 int		 parsesubtype(char *);
142 int		 parseextvalue(char *, u_int32_t *);
143 int		 parseextcommunity(struct filter_extcommunity *, char *,
144 		    char *);
145 
146 typedef struct {
147 	union {
148 		int64_t			 number;
149 		char			*string;
150 		struct bgpd_addr	 addr;
151 		u_int8_t		 u8;
152 		struct filter_peers_l	*filter_peers;
153 		struct filter_match_l	 filter_match;
154 		struct filter_prefix_l	*filter_prefix;
155 		struct filter_as_l	*filter_as;
156 		struct filter_set	*filter_set;
157 		struct filter_set_head	*filter_set_head;
158 		struct {
159 			struct bgpd_addr	prefix;
160 			u_int8_t		len;
161 		}			prefix;
162 		struct filter_prefixlen	prefixlen;
163 		struct {
164 			u_int8_t		enc_alg;
165 			char			enc_key[IPSEC_ENC_KEY_LEN];
166 			u_int8_t		enc_key_len;
167 		}			encspec;
168 	} v;
169 	int lineno;
170 } YYSTYPE;
171 
172 %}
173 
174 %token	AS ROUTERID HOLDTIME YMIN LISTEN ON FIBUPDATE FIBPRIORITY RTABLE
175 %token	RDOMAIN RD EXPORTTRGT IMPORTTRGT
176 %token	RDE RIB EVALUATE IGNORE COMPARE
177 %token	GROUP NEIGHBOR NETWORK
178 %token	REMOTEAS DESCR LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART
179 %token	ANNOUNCE CAPABILITIES REFRESH AS4BYTE CONNECTRETRY
180 %token	DEMOTE ENFORCE NEIGHBORAS REFLECTOR DEPEND DOWN SOFTRECONFIG
181 %token	DUMP IN OUT SOCKET RESTRICTED
182 %token	LOG ROUTECOLL TRANSPARENT
183 %token	TCP MD5SIG PASSWORD KEY TTLSECURITY
184 %token	ALLOW DENY MATCH
185 %token	QUICK
186 %token	FROM TO ANY
187 %token	CONNECTED STATIC
188 %token	COMMUNITY EXTCOMMUNITY
189 %token	PREFIX PREFIXLEN SOURCEAS TRANSITAS PEERAS DELETE MAXASLEN MAXASSEQ
190 %token	SET LOCALPREF MED METRIC NEXTHOP REJECT BLACKHOLE NOMODIFY SELF
191 %token	PREPEND_SELF PREPEND_PEER PFTABLE WEIGHT RTLABEL ORIGIN
192 %token	ERROR INCLUDE
193 %token	IPSEC ESP AH SPI IKE
194 %token	IPV4 IPV6
195 %token	QUALIFY VIA
196 %token	NE LE GE XRANGE LONGER
197 %token	<v.string>		STRING
198 %token	<v.number>		NUMBER
199 %type	<v.number>		asnumber as4number as4number_any optnumber
200 %type	<v.number>		espah family restart origincode nettype
201 %type	<v.number>		yesno inout restricted
202 %type	<v.string>		string filter_rib
203 %type	<v.addr>		address
204 %type	<v.prefix>		prefix addrspec
205 %type	<v.u8>			action quick direction delete
206 %type	<v.filter_peers>	filter_peer filter_peer_l filter_peer_h
207 %type	<v.filter_match>	filter_match filter_elm filter_match_h
208 %type	<v.filter_as>		filter_as filter_as_l filter_as_h
209 %type	<v.filter_as>		filter_as_t filter_as_t_l filter_as_l_h
210 %type	<v.prefixlen>		prefixlenop
211 %type	<v.filter_set>		filter_set_opt
212 %type	<v.filter_set_head>	filter_set filter_set_l
213 %type	<v.filter_prefix>	filter_prefix filter_prefix_l filter_prefix_h
214 %type	<v.u8>			unaryop equalityop binaryop filter_as_type
215 %type	<v.encspec>		encspec
216 %%
217 
218 grammar		: /* empty */
219 		| grammar '\n'
220 		| grammar include '\n'
221 		| grammar conf_main '\n'
222 		| grammar varset '\n'
223 		| grammar rdomain '\n'
224 		| grammar neighbor '\n'
225 		| grammar group '\n'
226 		| grammar filterrule '\n'
227 		| grammar error '\n'		{ file->errors++; }
228 		;
229 
230 asnumber	: NUMBER			{
231 			/*
232 			 * According to iana 65535 and 4294967295 are reserved
233 			 * but enforcing this is not duty of the parser.
234 			 */
235 			if ($1 < 0 || $1 > UINT_MAX) {
236 				yyerror("AS too big: max %u", UINT_MAX);
237 				YYERROR;
238 			}
239 		}
240 
241 as4number	: STRING			{
242 			const char	*errstr;
243 			char		*dot;
244 			u_int32_t	 uvalh = 0, uval;
245 
246 			if ((dot = strchr($1,'.')) != NULL) {
247 				*dot++ = '\0';
248 				uvalh = strtonum($1, 0, USHRT_MAX, &errstr);
249 				if (errstr) {
250 					yyerror("number %s is %s", $1, errstr);
251 					free($1);
252 					YYERROR;
253 				}
254 				uval = strtonum(dot, 0, USHRT_MAX, &errstr);
255 				if (errstr) {
256 					yyerror("number %s is %s", dot, errstr);
257 					free($1);
258 					YYERROR;
259 				}
260 				free($1);
261 			} else {
262 				yyerror("AS %s is bad", $1);
263 				free($1);
264 				YYERROR;
265 			}
266 			if (uvalh == 0 && uval == AS_TRANS) {
267 				yyerror("AS %u is reserved and may not be used",
268 				    AS_TRANS);
269 				YYERROR;
270 			}
271 			$$ = uval | (uvalh << 16);
272 		}
273 		| asnumber {
274 			if ($1 == AS_TRANS) {
275 				yyerror("AS %u is reserved and may not be used",
276 				    AS_TRANS);
277 				YYERROR;
278 			}
279 			$$ = $1;
280 		}
281 		;
282 
283 as4number_any	: STRING			{
284 			const char	*errstr;
285 			char		*dot;
286 			u_int32_t	 uvalh = 0, uval;
287 
288 			if ((dot = strchr($1,'.')) != NULL) {
289 				*dot++ = '\0';
290 				uvalh = strtonum($1, 0, USHRT_MAX, &errstr);
291 				if (errstr) {
292 					yyerror("number %s is %s", $1, errstr);
293 					free($1);
294 					YYERROR;
295 				}
296 				uval = strtonum(dot, 0, USHRT_MAX, &errstr);
297 				if (errstr) {
298 					yyerror("number %s is %s", dot, errstr);
299 					free($1);
300 					YYERROR;
301 				}
302 				free($1);
303 			} else {
304 				yyerror("AS %s is bad", $1);
305 				free($1);
306 				YYERROR;
307 			}
308 			$$ = uval | (uvalh << 16);
309 		}
310 		| asnumber {
311 			$$ = $1;
312 		}
313 		;
314 
315 string		: string STRING			{
316 			if (asprintf(&$$, "%s %s", $1, $2) == -1)
317 				fatal("string: asprintf");
318 			free($1);
319 			free($2);
320 		}
321 		| STRING
322 		;
323 
324 yesno		:  STRING			{
325 			if (!strcmp($1, "yes"))
326 				$$ = 1;
327 			else if (!strcmp($1, "no"))
328 				$$ = 0;
329 			else {
330 				yyerror("syntax error, "
331 				    "either yes or no expected");
332 				free($1);
333 				YYERROR;
334 			}
335 			free($1);
336 		}
337 		;
338 
339 varset		: STRING '=' string		{
340 			char *s = $1;
341 			if (cmd_opts & BGPD_OPT_VERBOSE)
342 				printf("%s = \"%s\"\n", $1, $3);
343 			while (*s++) {
344 				if (isspace((unsigned char)*s)) {
345 					yyerror("macro name cannot contain "
346 					    "whitespace");
347 					YYERROR;
348 				}
349 			}
350 			if (symset($1, $3, 0) == -1)
351 				fatal("cannot store variable");
352 			free($1);
353 			free($3);
354 		}
355 		;
356 
357 include		: INCLUDE STRING		{
358 			struct file	*nfile;
359 
360 			if ((nfile = pushfile($2, 1)) == NULL) {
361 				yyerror("failed to include file %s", $2);
362 				free($2);
363 				YYERROR;
364 			}
365 			free($2);
366 
367 			file = nfile;
368 			lungetc('\n');
369 		}
370 		;
371 
372 conf_main	: AS as4number		{
373 			conf->as = $2;
374 			if ($2 > USHRT_MAX)
375 				conf->short_as = AS_TRANS;
376 			else
377 				conf->short_as = $2;
378 		}
379 		| AS as4number asnumber {
380 			conf->as = $2;
381 			conf->short_as = $3;
382 		}
383 		| ROUTERID address		{
384 			if ($2.aid != AID_INET) {
385 				yyerror("router-id must be an IPv4 address");
386 				YYERROR;
387 			}
388 			conf->bgpid = $2.v4.s_addr;
389 		}
390 		| HOLDTIME NUMBER	{
391 			if ($2 < MIN_HOLDTIME || $2 > USHRT_MAX) {
392 				yyerror("holdtime must be between %u and %u",
393 				    MIN_HOLDTIME, USHRT_MAX);
394 				YYERROR;
395 			}
396 			conf->holdtime = $2;
397 		}
398 		| HOLDTIME YMIN NUMBER	{
399 			if ($3 < MIN_HOLDTIME || $3 > USHRT_MAX) {
400 				yyerror("holdtime must be between %u and %u",
401 				    MIN_HOLDTIME, USHRT_MAX);
402 				YYERROR;
403 			}
404 			conf->min_holdtime = $3;
405 		}
406 		| LISTEN ON address	{
407 			struct listen_addr	*la;
408 
409 			if ((la = calloc(1, sizeof(struct listen_addr))) ==
410 			    NULL)
411 				fatal("parse conf_main listen on calloc");
412 
413 			la->fd = -1;
414 			memcpy(&la->sa, addr2sa(&$3, BGP_PORT), sizeof(la->sa));
415 			TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry);
416 		}
417 		| FIBPRIORITY NUMBER		{
418 			if ($2 <= RTP_NONE || $2 > RTP_MAX) {
419 				yyerror("invalid fib-priority");
420 				YYERROR;
421 			}
422 			conf->fib_priority = $2;
423 		}
424 		| FIBUPDATE yesno		{
425 			struct rde_rib *rr;
426 			rr = find_rib("Loc-RIB");
427 			if (rr == NULL)
428 				fatalx("RTABLE can not find the main RIB!");
429 
430 			if ($2 == 0)
431 				rr->flags |= F_RIB_NOFIBSYNC;
432 			else
433 				rr->flags &= ~F_RIB_NOFIBSYNC;
434 		}
435 		| ROUTECOLL yesno	{
436 			if ($2 == 1)
437 				conf->flags |= BGPD_FLAG_NO_EVALUATE;
438 			else
439 				conf->flags &= ~BGPD_FLAG_NO_EVALUATE;
440 		}
441 		| RDE RIB STRING {
442 			if (add_rib($3, 0, F_RIB_NOFIB)) {
443 				free($3);
444 				YYERROR;
445 			}
446 			free($3);
447 		}
448 		| RDE RIB STRING yesno EVALUATE {
449 			if ($4) {
450 				free($3);
451 				yyerror("bad rde rib definition");
452 				YYERROR;
453 			}
454 			if (add_rib($3, 0, F_RIB_NOFIB | F_RIB_NOEVALUATE)) {
455 				free($3);
456 				YYERROR;
457 			}
458 			free($3);
459 		}
460 		| RDE RIB STRING RTABLE NUMBER {
461 			if (add_rib($3, $5, 0)) {
462 				free($3);
463 				YYERROR;
464 			}
465 			free($3);
466 		}
467 		| RDE RIB STRING RTABLE NUMBER FIBUPDATE yesno {
468 			int	flags = 0;
469 			if ($7 == 0)
470 				flags = F_RIB_NOFIBSYNC;
471 			if (add_rib($3, $5, flags)) {
472 				free($3);
473 				YYERROR;
474 			}
475 			free($3);
476 		}
477 		| TRANSPARENT yesno	{
478 			if ($2 == 1)
479 				conf->flags |= BGPD_FLAG_DECISION_TRANS_AS;
480 			else
481 				conf->flags &= ~BGPD_FLAG_DECISION_TRANS_AS;
482 		}
483 		| LOG STRING		{
484 			if (!strcmp($2, "updates"))
485 				conf->log |= BGPD_LOG_UPDATES;
486 			else {
487 				free($2);
488 				YYERROR;
489 			}
490 			free($2);
491 		}
492 		| network
493 		| DUMP STRING STRING optnumber		{
494 			int action;
495 
496 			if ($4 < 0 || $4 > INT_MAX) {
497 				yyerror("bad timeout");
498 				free($2);
499 				free($3);
500 				YYERROR;
501 			}
502 			if (!strcmp($2, "table"))
503 				action = MRT_TABLE_DUMP;
504 			else if (!strcmp($2, "table-mp"))
505 				action = MRT_TABLE_DUMP_MP;
506 			else if (!strcmp($2, "table-v2"))
507 				action = MRT_TABLE_DUMP_V2;
508 			else {
509 				yyerror("unknown mrt dump type");
510 				free($2);
511 				free($3);
512 				YYERROR;
513 			}
514 			free($2);
515 			if (add_mrtconfig(action, $3, $4, NULL, NULL) == -1) {
516 				free($3);
517 				YYERROR;
518 			}
519 			free($3);
520 		}
521 		| DUMP RIB STRING STRING STRING optnumber		{
522 			int action;
523 
524 			if ($6 < 0 || $6 > INT_MAX) {
525 				yyerror("bad timeout");
526 				free($3);
527 				free($4);
528 				free($5);
529 				YYERROR;
530 			}
531 			if (!strcmp($4, "table"))
532 				action = MRT_TABLE_DUMP;
533 			else if (!strcmp($4, "table-mp"))
534 				action = MRT_TABLE_DUMP_MP;
535 			else if (!strcmp($4, "table-v2"))
536 				action = MRT_TABLE_DUMP_V2;
537 			else {
538 				yyerror("unknown mrt dump type");
539 				free($3);
540 				free($4);
541 				free($5);
542 				YYERROR;
543 			}
544 			free($4);
545 			if (add_mrtconfig(action, $5, $6, NULL, $3) == -1) {
546 				free($3);
547 				free($5);
548 				YYERROR;
549 			}
550 			free($3);
551 			free($5);
552 		}
553 		| mrtdump
554 		| RDE STRING EVALUATE		{
555 			if (!strcmp($2, "route-age"))
556 				conf->flags |= BGPD_FLAG_DECISION_ROUTEAGE;
557 			else {
558 				yyerror("unknown route decision type");
559 				free($2);
560 				YYERROR;
561 			}
562 			free($2);
563 		}
564 		| RDE STRING IGNORE		{
565 			if (!strcmp($2, "route-age"))
566 				conf->flags &= ~BGPD_FLAG_DECISION_ROUTEAGE;
567 			else {
568 				yyerror("unknown route decision type");
569 				free($2);
570 				YYERROR;
571 			}
572 			free($2);
573 		}
574 		| RDE MED COMPARE STRING	{
575 			if (!strcmp($4, "always"))
576 				conf->flags |= BGPD_FLAG_DECISION_MED_ALWAYS;
577 			else if (!strcmp($4, "strict"))
578 				conf->flags &= ~BGPD_FLAG_DECISION_MED_ALWAYS;
579 			else {
580 				yyerror("rde med compare: "
581 				    "unknown setting \"%s\"", $4);
582 				free($4);
583 				YYERROR;
584 			}
585 			free($4);
586 		}
587 		| NEXTHOP QUALIFY VIA STRING	{
588 			if (!strcmp($4, "bgp"))
589 				conf->flags |= BGPD_FLAG_NEXTHOP_BGP;
590 			else if (!strcmp($4, "default"))
591 				conf->flags |= BGPD_FLAG_NEXTHOP_DEFAULT;
592 			else {
593 				yyerror("nexthop depend on: "
594 				    "unknown setting \"%s\"", $4);
595 				free($4);
596 				YYERROR;
597 			}
598 			free($4);
599 		}
600 		| RTABLE NUMBER {
601 			struct rde_rib *rr;
602 			if (ktable_exists($2, NULL) != 1) {
603 				yyerror("rtable id %lld does not exist", $2);
604 				YYERROR;
605 			}
606 			rr = find_rib("Loc-RIB");
607 			if (rr == NULL)
608 				fatalx("RTABLE can not find the main RIB!");
609 			rr->rtableid = $2;
610 		}
611 		| CONNECTRETRY NUMBER {
612 			if ($2 > USHRT_MAX || $2 < 1) {
613 				yyerror("invalid connect-retry");
614 				YYERROR;
615 			}
616 			conf->connectretry = $2;
617 		}
618 		| SOCKET STRING	restricted {
619 			if (strlen($2) >=
620 			    sizeof(((struct sockaddr_un *)0)->sun_path)) {
621 				yyerror("socket path too long");
622 				YYERROR;
623 			}
624 			if ($3) {
625 				free(conf->rcsock);
626 				conf->rcsock = $2;
627 			} else {
628 				free(conf->csock);
629 				conf->csock = $2;
630 			}
631 		}
632 		;
633 
634 mrtdump		: DUMP STRING inout STRING optnumber	{
635 			int action;
636 
637 			if ($5 < 0 || $5 > INT_MAX) {
638 				yyerror("bad timeout");
639 				free($2);
640 				free($4);
641 				YYERROR;
642 			}
643 			if (!strcmp($2, "all"))
644 				action = $3 ? MRT_ALL_IN : MRT_ALL_OUT;
645 			else if (!strcmp($2, "updates"))
646 				action = $3 ? MRT_UPDATE_IN : MRT_UPDATE_OUT;
647 			else {
648 				yyerror("unknown mrt msg dump type");
649 				free($2);
650 				free($4);
651 				YYERROR;
652 			}
653 			if (add_mrtconfig(action, $4, $5, curpeer, NULL) ==
654 			    -1) {
655 				free($2);
656 				free($4);
657 				YYERROR;
658 			}
659 			free($2);
660 			free($4);
661 		}
662 		;
663 
664 network		: NETWORK prefix filter_set	{
665 			struct network	*n;
666 
667 			if ((n = calloc(1, sizeof(struct network))) == NULL)
668 				fatal("new_network");
669 			memcpy(&n->net.prefix, &$2.prefix,
670 			    sizeof(n->net.prefix));
671 			n->net.prefixlen = $2.len;
672 			filterset_move($3, &n->net.attrset);
673 			free($3);
674 
675 			TAILQ_INSERT_TAIL(netconf, n, entry);
676 		}
677 		| NETWORK family nettype filter_set	{
678 			struct network	*n;
679 
680 			if ((n = calloc(1, sizeof(struct network))) == NULL)
681 				fatal("new_network");
682 			if (afi2aid($2, SAFI_UNICAST, &n->net.prefix.aid) ==
683 			    -1) {
684 				yyerror("unknown family");
685 				filterset_free($4);
686 				free($4);
687 				YYERROR;
688 			}
689 			n->net.type = $3 ? NETWORK_STATIC : NETWORK_CONNECTED;
690 			filterset_move($4, &n->net.attrset);
691 			free($4);
692 
693 			TAILQ_INSERT_TAIL(netconf, n, entry);
694 		}
695 		;
696 
697 inout		: IN		{ $$ = 1; }
698 		| OUT		{ $$ = 0; }
699 		;
700 
701 restricted	: RESTRICTED	{ $$ = 1; }
702 		| /* nothing */	{ $$ = 0; }
703 		;
704 
705 address		: STRING		{
706 			u_int8_t	len;
707 
708 			if (!host($1, &$$, &len)) {
709 				yyerror("could not parse address spec \"%s\"",
710 				    $1);
711 				free($1);
712 				YYERROR;
713 			}
714 			free($1);
715 
716 			if (($$.aid == AID_INET && len != 32) ||
717 			    ($$.aid == AID_INET6 && len != 128)) {
718 				/* unreachable */
719 				yyerror("got prefixlen %u, expected %u",
720 				    len, $$.aid == AID_INET ? 32 : 128);
721 				YYERROR;
722 			}
723 		}
724 		;
725 
726 prefix		: STRING '/' NUMBER	{
727 			char	*s;
728 
729 			if ($3 < 0 || $3 > 128) {
730 				yyerror("bad prefixlen %lld", $3);
731 				free($1);
732 				YYERROR;
733 			}
734 			if (asprintf(&s, "%s/%lld", $1, $3) == -1)
735 				fatal(NULL);
736 			free($1);
737 
738 			if (!host(s, &$$.prefix, &$$.len)) {
739 				yyerror("could not parse address \"%s\"", s);
740 				free(s);
741 				YYERROR;
742 			}
743 			free(s);
744 		}
745 		| NUMBER '/' NUMBER	{
746 			char	*s;
747 
748 			/* does not match IPv6 */
749 			if ($1 < 0 || $1 > 255 || $3 < 0 || $3 > 32) {
750 				yyerror("bad prefix %lld/%lld", $1, $3);
751 				YYERROR;
752 			}
753 			if (asprintf(&s, "%lld/%lld", $1, $3) == -1)
754 				fatal(NULL);
755 
756 			if (!host(s, &$$.prefix, &$$.len)) {
757 				yyerror("could not parse address \"%s\"", s);
758 				free(s);
759 				YYERROR;
760 			}
761 			free(s);
762 		}
763 		;
764 
765 addrspec	: address	{
766 			memcpy(&$$.prefix, &$1, sizeof(struct bgpd_addr));
767 			if ($$.prefix.aid == AID_INET)
768 				$$.len = 32;
769 			else
770 				$$.len = 128;
771 		}
772 		| prefix
773 		;
774 
775 optnl		: '\n' optnl
776 		|
777 		;
778 
779 nl		: '\n' optnl		/* one newline or more */
780 		;
781 
782 optnumber	: /* empty */		{ $$ = 0; }
783 		| NUMBER
784 		;
785 
786 rdomain		: RDOMAIN NUMBER optnl '{' optnl	{
787 			if (ktable_exists($2, NULL) != 1) {
788 				yyerror("rdomain %lld does not exist", $2);
789 				YYERROR;
790 			}
791 			if (!(currdom = calloc(1, sizeof(struct rdomain))))
792 				fatal(NULL);
793 			currdom->rtableid = $2;
794 			TAILQ_INIT(&currdom->import);
795 			TAILQ_INIT(&currdom->export);
796 			TAILQ_INIT(&currdom->net_l);
797 			netconf = &currdom->net_l;
798 		}
799 		    rdomainopts_l '}' {
800 			/* insert into list */
801 			SIMPLEQ_INSERT_TAIL(&conf->rdomains, currdom, entry);
802 			currdom = NULL;
803 			netconf = &conf->networks;
804 		}
805 
806 rdomainopts_l	: rdomainopts_l rdomainoptsl
807 		| rdomainoptsl
808 		;
809 
810 rdomainoptsl	: rdomainopts nl
811 		;
812 
813 rdomainopts	: RD STRING {
814 			struct filter_extcommunity	ext;
815 			u_int64_t			rd;
816 
817 			if (parseextcommunity(&ext, "rt", $2) == -1) {
818 				free($2);
819 				YYERROR;
820 			}
821 			free($2);
822 			/*
823 			 * RD is almost encode like an ext-community,
824 			 * but only almost so convert here.
825 			 */
826 			if (community_ext_conv(&ext, 0, &rd)) {
827 				yyerror("bad encoding of rd");
828 				YYERROR;
829 			}
830 			rd = betoh64(rd) & 0xffffffffffffULL;
831 			switch (ext.type) {
832 			case EXT_COMMUNITY_TWO_AS:
833 				rd |= (0ULL << 48);
834 				break;
835 			case EXT_COMMUNITY_IPV4:
836 				rd |= (1ULL << 48);
837 				break;
838 			case EXT_COMMUNITY_FOUR_AS:
839 				rd |= (2ULL << 48);
840 				break;
841 			default:
842 				yyerror("bad encoding of rd");
843 				YYERROR;
844 			}
845 			currdom->rd = htobe64(rd);
846 		}
847 		| EXPORTTRGT STRING STRING	{
848 			struct filter_set	*set;
849 
850 			if ((set = calloc(1, sizeof(struct filter_set))) ==
851 			    NULL)
852 				fatal(NULL);
853 			set->type = ACTION_SET_EXT_COMMUNITY;
854 			if (parseextcommunity(&set->action.ext_community,
855 			    $2, $3) == -1) {
856 				free($3);
857 				free($2);
858 				free(set);
859 				YYERROR;
860 			}
861 			free($3);
862 			free($2);
863 			TAILQ_INSERT_TAIL(&currdom->export, set, entry);
864 		}
865 		| IMPORTTRGT STRING STRING	{
866 			struct filter_set	*set;
867 
868 			if ((set = calloc(1, sizeof(struct filter_set))) ==
869 			    NULL)
870 				fatal(NULL);
871 			set->type = ACTION_SET_EXT_COMMUNITY;
872 			if (parseextcommunity(&set->action.ext_community,
873 			    $2, $3) == -1) {
874 				free($3);
875 				free($2);
876 				free(set);
877 				YYERROR;
878 			}
879 			free($3);
880 			free($2);
881 			TAILQ_INSERT_TAIL(&currdom->import, set, entry);
882 		}
883 		| DESCR string		{
884 			if (strlcpy(currdom->descr, $2,
885 			    sizeof(currdom->descr)) >=
886 			    sizeof(currdom->descr)) {
887 				yyerror("descr \"%s\" too long: max %zu",
888 				    $2, sizeof(currdom->descr) - 1);
889 				free($2);
890 				YYERROR;
891 			}
892 			free($2);
893 		}
894 		| FIBUPDATE yesno		{
895 			if ($2 == 0)
896 				currdom->flags |= F_RIB_NOFIBSYNC;
897 			else
898 				currdom->flags &= ~F_RIB_NOFIBSYNC;
899 		}
900 		| network
901 		| DEPEND ON STRING	{
902 			/* XXX this is a hack */
903 			if (if_nametoindex($3) == 0) {
904 				yyerror("interface %s does not exist", $3);
905 				free($3);
906 				YYERROR;
907 			}
908 			strlcpy(currdom->ifmpe, $3, IFNAMSIZ);
909 			free($3);
910 			if (get_mpe_label(currdom)) {
911 				yyerror("failed to get mpls label from %s",
912 				    currdom->ifmpe);
913 				YYERROR;
914 			}
915 		}
916 		;
917 
918 neighbor	: {	curpeer = new_peer(); }
919 		    NEIGHBOR addrspec {
920 			memcpy(&curpeer->conf.remote_addr, &$3.prefix,
921 			    sizeof(curpeer->conf.remote_addr));
922 			curpeer->conf.remote_masklen = $3.len;
923 			if (($3.prefix.aid == AID_INET && $3.len != 32) ||
924 			    ($3.prefix.aid == AID_INET6 && $3.len != 128))
925 				curpeer->conf.template = 1;
926 			if (curpeer->conf.capabilities.mp[
927 			    curpeer->conf.remote_addr.aid] == -1)
928 				curpeer->conf.capabilities.mp[
929 				    curpeer->conf.remote_addr.aid] = 1;
930 			if (get_id(curpeer)) {
931 				yyerror("get_id failed");
932 				YYERROR;
933 			}
934 		}
935 		    peeropts_h {
936 			if (curpeer_filter[0] != NULL)
937 				TAILQ_INSERT_TAIL(peerfilter_l,
938 				    curpeer_filter[0], entry);
939 			if (curpeer_filter[1] != NULL)
940 				TAILQ_INSERT_TAIL(peerfilter_l,
941 				    curpeer_filter[1], entry);
942 			curpeer_filter[0] = NULL;
943 			curpeer_filter[1] = NULL;
944 
945 			if (neighbor_consistent(curpeer) == -1)
946 				YYERROR;
947 			curpeer->next = peer_l;
948 			peer_l = curpeer;
949 			curpeer = curgroup;
950 		}
951 		;
952 
953 group		: GROUP string optnl '{' optnl {
954 			curgroup = curpeer = new_group();
955 			if (strlcpy(curgroup->conf.group, $2,
956 			    sizeof(curgroup->conf.group)) >=
957 			    sizeof(curgroup->conf.group)) {
958 				yyerror("group name \"%s\" too long: max %zu",
959 				    $2, sizeof(curgroup->conf.group) - 1);
960 				free($2);
961 				YYERROR;
962 			}
963 			free($2);
964 			if (get_id(curgroup)) {
965 				yyerror("get_id failed");
966 				YYERROR;
967 			}
968 		}
969 		    groupopts_l '}' {
970 			if (curgroup_filter[0] != NULL)
971 				TAILQ_INSERT_TAIL(groupfilter_l,
972 				    curgroup_filter[0], entry);
973 			if (curgroup_filter[1] != NULL)
974 				TAILQ_INSERT_TAIL(groupfilter_l,
975 				    curgroup_filter[1], entry);
976 			curgroup_filter[0] = NULL;
977 			curgroup_filter[1] = NULL;
978 
979 			free(curgroup);
980 			curgroup = NULL;
981 		}
982 		;
983 
984 groupopts_l	: groupopts_l groupoptsl
985 		| groupoptsl
986 		;
987 
988 groupoptsl	: peeropts nl
989 		| neighbor nl
990 		| error nl
991 		;
992 
993 peeropts_h	: '{' optnl peeropts_l '}'
994 		| /* empty */
995 		;
996 
997 peeropts_l	: peeropts_l peeroptsl
998 		| peeroptsl
999 		;
1000 
1001 peeroptsl	: peeropts nl
1002 		;
1003 
1004 peeropts	: REMOTEAS as4number	{
1005 			curpeer->conf.remote_as = $2;
1006 		}
1007 		| DESCR string		{
1008 			if (strlcpy(curpeer->conf.descr, $2,
1009 			    sizeof(curpeer->conf.descr)) >=
1010 			    sizeof(curpeer->conf.descr)) {
1011 				yyerror("descr \"%s\" too long: max %zu",
1012 				    $2, sizeof(curpeer->conf.descr) - 1);
1013 				free($2);
1014 				YYERROR;
1015 			}
1016 			free($2);
1017 		}
1018 		| LOCALADDR address	{
1019 			memcpy(&curpeer->conf.local_addr, &$2,
1020 			    sizeof(curpeer->conf.local_addr));
1021 		}
1022 		| MULTIHOP NUMBER	{
1023 			if ($2 < 2 || $2 > 255) {
1024 				yyerror("invalid multihop distance %lld", $2);
1025 				YYERROR;
1026 			}
1027 			curpeer->conf.distance = $2;
1028 		}
1029 		| PASSIVE		{
1030 			curpeer->conf.passive = 1;
1031 		}
1032 		| DOWN		{
1033 			curpeer->conf.down = 1;
1034 		}
1035 		| RIB STRING	{
1036 			if (!find_rib($2)) {
1037 				yyerror("rib \"%s\" does not exist.", $2);
1038 				free($2);
1039 				YYERROR;
1040 			}
1041 			if (strlcpy(curpeer->conf.rib, $2,
1042 			    sizeof(curpeer->conf.rib)) >=
1043 			    sizeof(curpeer->conf.rib)) {
1044 				yyerror("rib name \"%s\" too long: max %zu",
1045 				   $2, sizeof(curpeer->conf.rib) - 1);
1046 				free($2);
1047 				YYERROR;
1048 			}
1049 			free($2);
1050 		}
1051 		| HOLDTIME NUMBER	{
1052 			if ($2 < MIN_HOLDTIME || $2 > USHRT_MAX) {
1053 				yyerror("holdtime must be between %u and %u",
1054 				    MIN_HOLDTIME, USHRT_MAX);
1055 				YYERROR;
1056 			}
1057 			curpeer->conf.holdtime = $2;
1058 		}
1059 		| HOLDTIME YMIN NUMBER	{
1060 			if ($3 < MIN_HOLDTIME || $3 > USHRT_MAX) {
1061 				yyerror("holdtime must be between %u and %u",
1062 				    MIN_HOLDTIME, USHRT_MAX);
1063 				YYERROR;
1064 			}
1065 			curpeer->conf.min_holdtime = $3;
1066 		}
1067 		| ANNOUNCE family STRING {
1068 			u_int8_t	aid, safi;
1069 			int8_t		val = 1;
1070 
1071 			if (!strcmp($3, "none")) {
1072 				safi = SAFI_UNICAST;
1073 				val = 0;
1074 			} else if (!strcmp($3, "unicast")) {
1075 				safi = SAFI_UNICAST;
1076 			} else if (!strcmp($3, "vpn")) {
1077 				safi = SAFI_MPLSVPN;
1078 			} else {
1079 				yyerror("unknown/unsupported SAFI \"%s\"",
1080 				    $3);
1081 				free($3);
1082 				YYERROR;
1083 			}
1084 			free($3);
1085 
1086 			if (afi2aid($2, safi, &aid) == -1) {
1087 				yyerror("unknown AFI/SAFI pair");
1088 				YYERROR;
1089 			}
1090 			curpeer->conf.capabilities.mp[aid] = val;
1091 		}
1092 		| ANNOUNCE CAPABILITIES yesno {
1093 			curpeer->conf.announce_capa = $3;
1094 		}
1095 		| ANNOUNCE REFRESH yesno {
1096 			curpeer->conf.capabilities.refresh = $3;
1097 		}
1098 		| ANNOUNCE RESTART yesno {
1099 			curpeer->conf.capabilities.grestart.restart = $3;
1100 		}
1101 		| ANNOUNCE AS4BYTE yesno {
1102 			curpeer->conf.capabilities.as4byte = $3;
1103 		}
1104 		| ANNOUNCE SELF {
1105 			curpeer->conf.announce_type = ANNOUNCE_SELF;
1106 		}
1107 		| ANNOUNCE STRING {
1108 			if (!strcmp($2, "self"))
1109 				curpeer->conf.announce_type = ANNOUNCE_SELF;
1110 			else if (!strcmp($2, "none"))
1111 				curpeer->conf.announce_type = ANNOUNCE_NONE;
1112 			else if (!strcmp($2, "all"))
1113 				curpeer->conf.announce_type = ANNOUNCE_ALL;
1114 			else if (!strcmp($2, "default-route"))
1115 				curpeer->conf.announce_type =
1116 				    ANNOUNCE_DEFAULT_ROUTE;
1117 			else {
1118 				yyerror("invalid announce type");
1119 				free($2);
1120 				YYERROR;
1121 			}
1122 			free($2);
1123 		}
1124 		| ENFORCE NEIGHBORAS yesno {
1125 			if ($3)
1126 				curpeer->conf.enforce_as = ENFORCE_AS_ON;
1127 			else
1128 				curpeer->conf.enforce_as = ENFORCE_AS_OFF;
1129 		}
1130 		| MAXPREFIX NUMBER restart {
1131 			if ($2 < 0 || $2 > UINT_MAX) {
1132 				yyerror("bad maximum number of prefixes");
1133 				YYERROR;
1134 			}
1135 			curpeer->conf.max_prefix = $2;
1136 			curpeer->conf.max_prefix_restart = $3;
1137 		}
1138 		| TCP MD5SIG PASSWORD string {
1139 			if (curpeer->conf.auth.method) {
1140 				yyerror("auth method cannot be redefined");
1141 				free($4);
1142 				YYERROR;
1143 			}
1144 			if (strlcpy(curpeer->conf.auth.md5key, $4,
1145 			    sizeof(curpeer->conf.auth.md5key)) >=
1146 			    sizeof(curpeer->conf.auth.md5key)) {
1147 				yyerror("tcp md5sig password too long: max %zu",
1148 				    sizeof(curpeer->conf.auth.md5key) - 1);
1149 				free($4);
1150 				YYERROR;
1151 			}
1152 			curpeer->conf.auth.method = AUTH_MD5SIG;
1153 			curpeer->conf.auth.md5key_len = strlen($4);
1154 			free($4);
1155 		}
1156 		| TCP MD5SIG KEY string {
1157 			if (curpeer->conf.auth.method) {
1158 				yyerror("auth method cannot be redefined");
1159 				free($4);
1160 				YYERROR;
1161 			}
1162 
1163 			if (str2key($4, curpeer->conf.auth.md5key,
1164 			    sizeof(curpeer->conf.auth.md5key)) == -1) {
1165 				free($4);
1166 				YYERROR;
1167 			}
1168 			curpeer->conf.auth.method = AUTH_MD5SIG;
1169 			curpeer->conf.auth.md5key_len = strlen($4) / 2;
1170 			free($4);
1171 		}
1172 		| IPSEC espah IKE {
1173 			if (curpeer->conf.auth.method) {
1174 				yyerror("auth method cannot be redefined");
1175 				YYERROR;
1176 			}
1177 			if ($2)
1178 				curpeer->conf.auth.method = AUTH_IPSEC_IKE_ESP;
1179 			else
1180 				curpeer->conf.auth.method = AUTH_IPSEC_IKE_AH;
1181 		}
1182 		| IPSEC espah inout SPI NUMBER STRING STRING encspec {
1183 			u_int32_t	auth_alg;
1184 			u_int8_t	keylen;
1185 
1186 			if (curpeer->conf.auth.method &&
1187 			    (((curpeer->conf.auth.spi_in && $3 == 1) ||
1188 			    (curpeer->conf.auth.spi_out && $3 == 0)) ||
1189 			    ($2 == 1 && curpeer->conf.auth.method !=
1190 			    AUTH_IPSEC_MANUAL_ESP) ||
1191 			    ($2 == 0 && curpeer->conf.auth.method !=
1192 			    AUTH_IPSEC_MANUAL_AH))) {
1193 				yyerror("auth method cannot be redefined");
1194 				free($6);
1195 				free($7);
1196 				YYERROR;
1197 			}
1198 
1199 			if (!strcmp($6, "sha1")) {
1200 				auth_alg = SADB_AALG_SHA1HMAC;
1201 				keylen = 20;
1202 			} else if (!strcmp($6, "md5")) {
1203 				auth_alg = SADB_AALG_MD5HMAC;
1204 				keylen = 16;
1205 			} else {
1206 				yyerror("unknown auth algorithm \"%s\"", $6);
1207 				free($6);
1208 				free($7);
1209 				YYERROR;
1210 			}
1211 			free($6);
1212 
1213 			if (strlen($7) / 2 != keylen) {
1214 				yyerror("auth key len: must be %u bytes, "
1215 				    "is %zu bytes", keylen, strlen($7) / 2);
1216 				free($7);
1217 				YYERROR;
1218 			}
1219 
1220 			if ($2)
1221 				curpeer->conf.auth.method =
1222 				    AUTH_IPSEC_MANUAL_ESP;
1223 			else {
1224 				if ($8.enc_alg) {
1225 					yyerror("\"ipsec ah\" doesn't take "
1226 					    "encryption keys");
1227 					free($7);
1228 					YYERROR;
1229 				}
1230 				curpeer->conf.auth.method =
1231 				    AUTH_IPSEC_MANUAL_AH;
1232 			}
1233 
1234 			if ($5 < 0 || $5 > UINT_MAX) {
1235 				yyerror("bad spi number %lld", $5);
1236 				free($7);
1237 				YYERROR;
1238 			}
1239 
1240 			if ($3 == 1) {
1241 				if (str2key($7, curpeer->conf.auth.auth_key_in,
1242 				    sizeof(curpeer->conf.auth.auth_key_in)) ==
1243 				    -1) {
1244 					free($7);
1245 					YYERROR;
1246 				}
1247 				curpeer->conf.auth.spi_in = $5;
1248 				curpeer->conf.auth.auth_alg_in = auth_alg;
1249 				curpeer->conf.auth.enc_alg_in = $8.enc_alg;
1250 				memcpy(&curpeer->conf.auth.enc_key_in,
1251 				    &$8.enc_key,
1252 				    sizeof(curpeer->conf.auth.enc_key_in));
1253 				curpeer->conf.auth.enc_keylen_in =
1254 				    $8.enc_key_len;
1255 				curpeer->conf.auth.auth_keylen_in = keylen;
1256 			} else {
1257 				if (str2key($7, curpeer->conf.auth.auth_key_out,
1258 				    sizeof(curpeer->conf.auth.auth_key_out)) ==
1259 				    -1) {
1260 					free($7);
1261 					YYERROR;
1262 				}
1263 				curpeer->conf.auth.spi_out = $5;
1264 				curpeer->conf.auth.auth_alg_out = auth_alg;
1265 				curpeer->conf.auth.enc_alg_out = $8.enc_alg;
1266 				memcpy(&curpeer->conf.auth.enc_key_out,
1267 				    &$8.enc_key,
1268 				    sizeof(curpeer->conf.auth.enc_key_out));
1269 				curpeer->conf.auth.enc_keylen_out =
1270 				    $8.enc_key_len;
1271 				curpeer->conf.auth.auth_keylen_out = keylen;
1272 			}
1273 			free($7);
1274 		}
1275 		| TTLSECURITY yesno	{
1276 			curpeer->conf.ttlsec = $2;
1277 		}
1278 		| SET filter_set_opt	{
1279 			struct filter_rule	*r;
1280 
1281 			r = get_rule($2->type);
1282 			if (merge_filterset(&r->set, $2) == -1)
1283 				YYERROR;
1284 		}
1285 		| SET optnl "{" optnl filter_set_l optnl "}"	{
1286 			struct filter_rule	*r;
1287 			struct filter_set	*s;
1288 
1289 			while ((s = TAILQ_FIRST($5)) != NULL) {
1290 				TAILQ_REMOVE($5, s, entry);
1291 				r = get_rule(s->type);
1292 				if (merge_filterset(&r->set, s) == -1)
1293 					YYERROR;
1294 			}
1295 			free($5);
1296 		}
1297 		| mrtdump
1298 		| REFLECTOR		{
1299 			if ((conf->flags & BGPD_FLAG_REFLECTOR) &&
1300 			    conf->clusterid != 0) {
1301 				yyerror("only one route reflector "
1302 				    "cluster allowed");
1303 				YYERROR;
1304 			}
1305 			conf->flags |= BGPD_FLAG_REFLECTOR;
1306 			curpeer->conf.reflector_client = 1;
1307 		}
1308 		| REFLECTOR address	{
1309 			if ($2.aid != AID_INET) {
1310 				yyerror("route reflector cluster-id must be "
1311 				    "an IPv4 address");
1312 				YYERROR;
1313 			}
1314 			if ((conf->flags & BGPD_FLAG_REFLECTOR) &&
1315 			    conf->clusterid != $2.v4.s_addr) {
1316 				yyerror("only one route reflector "
1317 				    "cluster allowed");
1318 				YYERROR;
1319 			}
1320 			conf->flags |= BGPD_FLAG_REFLECTOR;
1321 			curpeer->conf.reflector_client = 1;
1322 			conf->clusterid = $2.v4.s_addr;
1323 		}
1324 		| DEPEND ON STRING	{
1325 			if (strlcpy(curpeer->conf.if_depend, $3,
1326 			    sizeof(curpeer->conf.if_depend)) >=
1327 			    sizeof(curpeer->conf.if_depend)) {
1328 				yyerror("interface name \"%s\" too long: "
1329 				    "max %zu", $3,
1330 				    sizeof(curpeer->conf.if_depend) - 1);
1331 				free($3);
1332 				YYERROR;
1333 			}
1334 			free($3);
1335 		}
1336 		| DEMOTE STRING		{
1337 			if (strlcpy(curpeer->conf.demote_group, $2,
1338 			    sizeof(curpeer->conf.demote_group)) >=
1339 			    sizeof(curpeer->conf.demote_group)) {
1340 				yyerror("demote group name \"%s\" too long: "
1341 				    "max %zu", $2,
1342 				    sizeof(curpeer->conf.demote_group) - 1);
1343 				free($2);
1344 				YYERROR;
1345 			}
1346 			free($2);
1347 			if (carp_demote_init(curpeer->conf.demote_group,
1348 			    cmd_opts & BGPD_OPT_FORCE_DEMOTE) == -1) {
1349 				yyerror("error initializing group \"%s\"",
1350 				    curpeer->conf.demote_group);
1351 				YYERROR;
1352 			}
1353 		}
1354 		| SOFTRECONFIG inout yesno {
1355 			if ($2)
1356 				curpeer->conf.softreconfig_in = $3;
1357 			else
1358 				curpeer->conf.softreconfig_out = $3;
1359 		}
1360 		| TRANSPARENT yesno	{
1361 			if ($2 == 1)
1362 				curpeer->conf.flags |= PEERFLAG_TRANS_AS;
1363 			else
1364 				curpeer->conf.flags &= ~PEERFLAG_TRANS_AS;
1365 		}
1366 		| LOG STRING		{
1367 			if (!strcmp($2, "updates"))
1368 				curpeer->conf.flags |= PEERFLAG_LOG_UPDATES;
1369 			else if (!strcmp($2, "no"))
1370 				curpeer->conf.flags &= ~PEERFLAG_LOG_UPDATES;
1371 			else {
1372 				free($2);
1373 				YYERROR;
1374 			}
1375 			free($2);
1376 		}
1377 		;
1378 
1379 restart		: /* nada */		{ $$ = 0; }
1380 		| RESTART NUMBER	{
1381 			if ($2 < 1 || $2 > USHRT_MAX) {
1382 				yyerror("restart out of range. 1 to %u minutes",
1383 				    USHRT_MAX);
1384 				YYERROR;
1385 			}
1386 			$$ = $2;
1387 		}
1388 		;
1389 
1390 family		: IPV4	{ $$ = AFI_IPv4; }
1391 		| IPV6	{ $$ = AFI_IPv6; }
1392 		;
1393 
1394 nettype		: STATIC { $$ = 1; },
1395 		| CONNECTED { $$ = 0; }
1396 		;
1397 
1398 espah		: ESP		{ $$ = 1; }
1399 		| AH		{ $$ = 0; }
1400 		;
1401 
1402 encspec		: /* nada */	{
1403 			bzero(&$$, sizeof($$));
1404 		}
1405 		| STRING STRING {
1406 			bzero(&$$, sizeof($$));
1407 			if (!strcmp($1, "3des") || !strcmp($1, "3des-cbc")) {
1408 				$$.enc_alg = SADB_EALG_3DESCBC;
1409 				$$.enc_key_len = 21; /* XXX verify */
1410 			} else if (!strcmp($1, "aes") ||
1411 			    !strcmp($1, "aes-128-cbc")) {
1412 				$$.enc_alg = SADB_X_EALG_AES;
1413 				$$.enc_key_len = 16;
1414 			} else {
1415 				yyerror("unknown enc algorithm \"%s\"", $1);
1416 				free($1);
1417 				free($2);
1418 				YYERROR;
1419 			}
1420 			free($1);
1421 
1422 			if (strlen($2) / 2 != $$.enc_key_len) {
1423 				yyerror("enc key length wrong: should be %u "
1424 				    "bytes, is %zu bytes",
1425 				    $$.enc_key_len * 2, strlen($2));
1426 				free($2);
1427 				YYERROR;
1428 			}
1429 
1430 			if (str2key($2, $$.enc_key, sizeof($$.enc_key)) == -1) {
1431 				free($2);
1432 				YYERROR;
1433 			}
1434 			free($2);
1435 		}
1436 		;
1437 
1438 filterrule	: action quick filter_rib direction filter_peer_h filter_match_h filter_set
1439 		{
1440 			struct filter_rule	 r;
1441 
1442 			bzero(&r, sizeof(r));
1443 			r.action = $1;
1444 			r.quick = $2;
1445 			r.dir = $4;
1446 			if ($3) {
1447 				if (r.dir != DIR_IN) {
1448 					yyerror("rib only allowed on \"from\" "
1449 					    "rules.");
1450 					free($3);
1451 					YYERROR;
1452 				}
1453 				if (!find_rib($3)) {
1454 					yyerror("rib \"%s\" does not exist.",
1455 					    $3);
1456 					free($3);
1457 					YYERROR;
1458 				}
1459 				if (strlcpy(r.rib, $3, sizeof(r.rib)) >=
1460 				    sizeof(r.rib)) {
1461 					yyerror("rib name \"%s\" too long: "
1462 					    "max %zu", $3, sizeof(r.rib) - 1);
1463 					free($3);
1464 					YYERROR;
1465 				}
1466 				free($3);
1467 			}
1468 			if (expand_rule(&r, $5, &$6, $7) == -1)
1469 				YYERROR;
1470 		}
1471 		;
1472 
1473 action		: ALLOW		{ $$ = ACTION_ALLOW; }
1474 		| DENY		{ $$ = ACTION_DENY; }
1475 		| MATCH		{ $$ = ACTION_NONE; }
1476 		;
1477 
1478 quick		: /* empty */	{ $$ = 0; }
1479 		| QUICK		{ $$ = 1; }
1480 		;
1481 
1482 direction	: FROM		{ $$ = DIR_IN; }
1483 		| TO		{ $$ = DIR_OUT; }
1484 		;
1485 
1486 filter_rib	: /* empty */	{ $$ = NULL; }
1487 		| RIB STRING	{ $$ = $2; }
1488 
1489 filter_peer_h	: filter_peer
1490 		| '{' filter_peer_l '}'		{ $$ = $2; }
1491 		;
1492 
1493 filter_peer_l	: filter_peer				{ $$ = $1; }
1494 		| filter_peer_l comma filter_peer	{
1495 			$3->next = $1;
1496 			$$ = $3;
1497 		}
1498 		;
1499 
1500 filter_peer	: ANY		{
1501 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
1502 			    NULL)
1503 				fatal(NULL);
1504 			$$->p.peerid = $$->p.groupid = 0;
1505 			$$->next = NULL;
1506 		}
1507 		| address	{
1508 			struct peer *p;
1509 
1510 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
1511 			    NULL)
1512 				fatal(NULL);
1513 			$$->p.remote_as = $$->p.groupid = $$->p.peerid = 0;
1514 			$$->next = NULL;
1515 			for (p = peer_l; p != NULL; p = p->next)
1516 				if (!memcmp(&p->conf.remote_addr,
1517 				    &$1, sizeof(p->conf.remote_addr))) {
1518 					$$->p.peerid = p->conf.id;
1519 					break;
1520 				}
1521 			if ($$->p.peerid == 0) {
1522 				yyerror("no such peer: %s", log_addr(&$1));
1523 				free($$);
1524 				YYERROR;
1525 			}
1526 		}
1527  		| AS as4number	{
1528 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
1529 			    NULL)
1530 				fatal(NULL);
1531 			$$->p.groupid = $$->p.peerid = 0;
1532 			$$->p.remote_as = $2;
1533 		}
1534 		| GROUP STRING	{
1535 			struct peer *p;
1536 
1537 			if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
1538 			    NULL)
1539 				fatal(NULL);
1540 			$$->p.remote_as = $$->p.peerid = 0;
1541 			$$->next = NULL;
1542 			for (p = peer_l; p != NULL; p = p->next)
1543 				if (!strcmp(p->conf.group, $2)) {
1544 					$$->p.groupid = p->conf.groupid;
1545 					break;
1546 				}
1547 			if ($$->p.groupid == 0) {
1548 				yyerror("no such group: \"%s\"", $2);
1549 				free($2);
1550 				free($$);
1551 				YYERROR;
1552 			}
1553 			free($2);
1554 		}
1555 		;
1556 
1557 filter_prefix_h	: IPV4 prefixlenop			 {
1558 			if ($2.op == OP_NONE)
1559 				$2.op = OP_GE;
1560 			if (($$ = calloc(1, sizeof(struct filter_prefix_l))) ==
1561 			    NULL)
1562 				fatal(NULL);
1563 			$$->p.addr.aid = AID_INET;
1564 			if (merge_prefixspec($$, &$2) == -1) {
1565 				free($$);
1566 				YYERROR;
1567 			}
1568 		}
1569 		| IPV6 prefixlenop			{
1570 			if ($2.op == OP_NONE)
1571 				$2.op = OP_GE;
1572 			if (($$ = calloc(1, sizeof(struct filter_prefix_l))) ==
1573 			    NULL)
1574 				fatal(NULL);
1575 			$$->p.addr.aid = AID_INET6;
1576 			if (merge_prefixspec($$, &$2) == -1) {
1577 				free($$);
1578 				YYERROR;
1579 			}
1580 		}
1581 		| PREFIX filter_prefix			{ $$ = $2; }
1582 		| PREFIX '{' filter_prefix_l '}'	{ $$ = $3; }
1583 		;
1584 
1585 filter_prefix_l	: filter_prefix				{ $$ = $1; }
1586 		| filter_prefix_l comma filter_prefix	{
1587 			$3->next = $1;
1588 			$$ = $3;
1589 		}
1590 		;
1591 
1592 filter_prefix	: prefix prefixlenop			{
1593 			if (($$ = calloc(1, sizeof(struct filter_prefix_l))) ==
1594 			    NULL)
1595 				fatal(NULL);
1596 			memcpy(&$$->p.addr, &$1.prefix,
1597 			    sizeof($$->p.addr));
1598 			$$->p.len = $1.len;
1599 
1600 			if (merge_prefixspec($$, &$2) == -1) {
1601 				free($$);
1602 				YYERROR;
1603 			}
1604 		}
1605 		;
1606 
1607 filter_as_h	: filter_as_t
1608 		| '{' filter_as_t_l '}'		{ $$ = $2; }
1609 		;
1610 
1611 filter_as_t_l	: filter_as_t
1612 		| filter_as_t_l comma filter_as_t		{
1613 			struct filter_as_l	*a;
1614 
1615 			/* merge, both can be lists */
1616 			for (a = $1; a != NULL && a->next != NULL; a = a->next)
1617 				;	/* nothing */
1618 			if (a != NULL)
1619 				a->next = $3;
1620 			$$ = $1;
1621 		}
1622 		;
1623 
1624 filter_as_t	: filter_as_type filter_as			{
1625 			$$ = $2;
1626 			$$->a.type = $1;
1627 		}
1628 		| filter_as_type '{' filter_as_l_h '}'	{
1629 			struct filter_as_l	*a;
1630 
1631 			$$ = $3;
1632 			for (a = $$; a != NULL; a = a->next)
1633 				a->a.type = $1;
1634 		}
1635 		;
1636 
1637 filter_as_l_h	: filter_as_l
1638 		| '{' filter_as_l '}'			{ $$ = $2; }
1639 		| '{' filter_as_l '}' filter_as_l_h
1640 		{
1641 			struct filter_as_l	*a;
1642 
1643 			/* merge, both can be lists */
1644 			for (a = $2; a != NULL && a->next != NULL; a = a->next)
1645 				;	/* nothing */
1646 			if (a != NULL)
1647 				a->next = $4;
1648 			$$ = $2;
1649 		}
1650 		;
1651 
1652 filter_as_l	: filter_as
1653 		| filter_as_l comma filter_as	{
1654 			$3->next = $1;
1655 			$$ = $3;
1656 		}
1657 		;
1658 
1659 filter_as	: as4number_any		{
1660 			if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
1661 			    NULL)
1662 				fatal(NULL);
1663 			$$->a.as = $1;
1664 			$$->a.op = OP_EQ;
1665 		}
1666 		| NEIGHBORAS		{
1667 			if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
1668 			    NULL)
1669 				fatal(NULL);
1670 			$$->a.flags = AS_FLAG_NEIGHBORAS;
1671 		}
1672 		| equalityop as4number_any	{
1673 			if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
1674 			    NULL)
1675 				fatal(NULL);
1676 			$$->a.op = $1;
1677 			$$->a.as = $2;
1678 		}
1679 		| as4number_any binaryop as4number_any {
1680 			if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
1681 			    NULL)
1682 				fatal(NULL);
1683 			if ($1 >= $3) {
1684 				yyerror("start AS is bigger than end");
1685 				YYERROR;
1686 			}
1687 			$$->a.op = $2;
1688 			$$->a.as_min = $1;
1689 			$$->a.as_max = $3;
1690 		}
1691 		;
1692 
1693 filter_match_h	: /* empty */			{
1694 			bzero(&$$, sizeof($$));
1695 			$$.m.community.as = COMMUNITY_UNSET;
1696 		}
1697 		| {
1698 			bzero(&fmopts, sizeof(fmopts));
1699 			fmopts.m.community.as = COMMUNITY_UNSET;
1700 		}
1701 		    filter_match		{
1702 			memcpy(&$$, &fmopts, sizeof($$));
1703 		}
1704 		;
1705 
1706 filter_match	: filter_elm
1707 		| filter_match filter_elm
1708 		;
1709 
1710 filter_elm	: filter_prefix_h	{
1711 			if (fmopts.prefix_l != NULL) {
1712 				yyerror("\"prefix\" already specified");
1713 				YYERROR;
1714 			}
1715 			fmopts.prefix_l = $1;
1716 		}
1717 		| filter_as_h		{
1718 			if (fmopts.as_l != NULL) {
1719 				yyerror("AS filters already specified");
1720 				YYERROR;
1721 			}
1722 			fmopts.as_l = $1;
1723 		}
1724 		| MAXASLEN NUMBER	{
1725 			if (fmopts.m.aslen.type != ASLEN_NONE) {
1726 				yyerror("AS length filters already specified");
1727 				YYERROR;
1728 			}
1729 			if ($2 < 0 || $2 > UINT_MAX) {
1730 				yyerror("bad max-as-len %lld", $2);
1731 				YYERROR;
1732 			}
1733 			fmopts.m.aslen.type = ASLEN_MAX;
1734 			fmopts.m.aslen.aslen = $2;
1735 		}
1736 		| MAXASSEQ NUMBER	{
1737 			if (fmopts.m.aslen.type != ASLEN_NONE) {
1738 				yyerror("AS length filters already specified");
1739 				YYERROR;
1740 			}
1741 			if ($2 < 0 || $2 > UINT_MAX) {
1742 				yyerror("bad max-as-seq %lld", $2);
1743 				YYERROR;
1744 			}
1745 			fmopts.m.aslen.type = ASLEN_SEQ;
1746 			fmopts.m.aslen.aslen = $2;
1747 		}
1748 		| COMMUNITY STRING	{
1749 			if (fmopts.m.community.as != COMMUNITY_UNSET) {
1750 				yyerror("\"community\" already specified");
1751 				free($2);
1752 				YYERROR;
1753 			}
1754 			if (parsecommunity(&fmopts.m.community, $2) == -1) {
1755 				free($2);
1756 				YYERROR;
1757 			}
1758 			free($2);
1759 		}
1760 		| EXTCOMMUNITY STRING STRING {
1761 			if (fmopts.m.ext_community.flags &
1762 			    EXT_COMMUNITY_FLAG_VALID) {
1763 				yyerror("\"ext-community\" already specified");
1764 				free($2);
1765 				free($3);
1766 				YYERROR;
1767 			}
1768 
1769 			if (parseextcommunity(&fmopts.m.ext_community,
1770 			    $2, $3) == -1) {
1771 				free($2);
1772 				free($3);
1773 				YYERROR;
1774 			}
1775 			free($2);
1776 			free($3);
1777 		}
1778 		| NEXTHOP address 	{
1779 			if (fmopts.m.nexthop.flags) {
1780 				yyerror("nexthop already specified");
1781 				YYERROR;
1782 			}
1783 			fmopts.m.nexthop.addr = $2;
1784 			fmopts.m.nexthop.flags = FILTER_NEXTHOP_ADDR;
1785 		}
1786 		| NEXTHOP NEIGHBOR 	{
1787 			if (fmopts.m.nexthop.flags) {
1788 				yyerror("nexthop already specified");
1789 				YYERROR;
1790 			}
1791 			fmopts.m.nexthop.flags = FILTER_NEXTHOP_NEIGHBOR;
1792 		}
1793 		;
1794 
1795 prefixlenop	: /* empty */			{ bzero(&$$, sizeof($$)); }
1796 		| LONGER				{
1797 			bzero(&$$, sizeof($$));
1798 			$$.op = OP_GE;
1799 			$$.len_min = -1;
1800 		}
1801 		| PREFIXLEN unaryop NUMBER		{
1802 			bzero(&$$, sizeof($$));
1803 			if ($3 < 0 || $3 > 128) {
1804 				yyerror("prefixlen must be >= 0 and <= 128");
1805 				YYERROR;
1806 			}
1807 			if ($2 == OP_GT && $3 == 0) {
1808 				yyerror("prefixlen must be > 0");
1809 				YYERROR;
1810 			}
1811 			$$.op = $2;
1812 			$$.len_min = $3;
1813 		}
1814 		| PREFIXLEN NUMBER binaryop NUMBER	{
1815 			bzero(&$$, sizeof($$));
1816 			if ($2 < 0 || $2 > 128 || $4 < 0 || $4 > 128) {
1817 				yyerror("prefixlen must be < 128");
1818 				YYERROR;
1819 			}
1820 			if ($2 >= $4) {
1821 				yyerror("start prefixlen is bigger than end");
1822 				YYERROR;
1823 			}
1824 			$$.op = $3;
1825 			$$.len_min = $2;
1826 			$$.len_max = $4;
1827 		}
1828 		;
1829 
1830 filter_as_type	: AS		{ $$ = AS_ALL; }
1831 		| SOURCEAS	{ $$ = AS_SOURCE; }
1832 		| TRANSITAS	{ $$ = AS_TRANSIT; }
1833 		| PEERAS	{ $$ = AS_PEER; }
1834 		;
1835 
1836 filter_set	: /* empty */					{ $$ = NULL; }
1837 		| SET filter_set_opt				{
1838 			if (($$ = calloc(1, sizeof(struct filter_set_head))) ==
1839 			    NULL)
1840 				fatal(NULL);
1841 			TAILQ_INIT($$);
1842 			TAILQ_INSERT_TAIL($$, $2, entry);
1843 		}
1844 		| SET optnl "{" optnl filter_set_l optnl "}"	{ $$ = $5; }
1845 		;
1846 
1847 filter_set_l	: filter_set_l comma filter_set_opt	{
1848 			$$ = $1;
1849 			if (merge_filterset($$, $3) == 1)
1850 				YYERROR;
1851 		}
1852 		| filter_set_opt {
1853 			if (($$ = calloc(1, sizeof(struct filter_set_head))) ==
1854 			    NULL)
1855 				fatal(NULL);
1856 			TAILQ_INIT($$);
1857 			TAILQ_INSERT_TAIL($$, $1, entry);
1858 		}
1859 		;
1860 
1861 delete		: /* empty */	{ $$ = 0; }
1862 		| DELETE	{ $$ = 1; }
1863 		;
1864 
1865 filter_set_opt	: LOCALPREF NUMBER		{
1866 			if ($2 < -INT_MAX || $2 > UINT_MAX) {
1867 				yyerror("bad localpref %lld", $2);
1868 				YYERROR;
1869 			}
1870 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
1871 				fatal(NULL);
1872 			if ($2 > 0) {
1873 				$$->type = ACTION_SET_LOCALPREF;
1874 				$$->action.metric = $2;
1875 			} else {
1876 				$$->type = ACTION_SET_RELATIVE_LOCALPREF;
1877 				$$->action.relative = $2;
1878 			}
1879 		}
1880 		| LOCALPREF '+' NUMBER		{
1881 			if ($3 < 0 || $3 > INT_MAX) {
1882 				yyerror("bad localpref +%lld", $3);
1883 				YYERROR;
1884 			}
1885 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
1886 				fatal(NULL);
1887 			$$->type = ACTION_SET_RELATIVE_LOCALPREF;
1888 			$$->action.relative = $3;
1889 		}
1890 		| LOCALPREF '-' NUMBER		{
1891 			if ($3 < 0 || $3 > INT_MAX) {
1892 				yyerror("bad localpref -%lld", $3);
1893 				YYERROR;
1894 			}
1895 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
1896 				fatal(NULL);
1897 			$$->type = ACTION_SET_RELATIVE_LOCALPREF;
1898 			$$->action.relative = -$3;
1899 		}
1900 		| MED NUMBER			{
1901 			if ($2 < -INT_MAX || $2 > UINT_MAX) {
1902 				yyerror("bad metric %lld", $2);
1903 				YYERROR;
1904 			}
1905 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
1906 				fatal(NULL);
1907 			if ($2 >= 0) {
1908 				$$->type = ACTION_SET_MED;
1909 				$$->action.metric = $2;
1910 			} else {
1911 				$$->type = ACTION_SET_RELATIVE_MED;
1912 				$$->action.relative = $2;
1913 			}
1914 		}
1915 		| MED '+' NUMBER			{
1916 			if ($3 < 0 || $3 > INT_MAX) {
1917 				yyerror("bad metric +%lld", $3);
1918 				YYERROR;
1919 			}
1920 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
1921 				fatal(NULL);
1922 			$$->type = ACTION_SET_RELATIVE_MED;
1923 			$$->action.relative = $3;
1924 		}
1925 		| MED '-' NUMBER			{
1926 			if ($3 < 0 || $3 > INT_MAX) {
1927 				yyerror("bad metric -%lld", $3);
1928 				YYERROR;
1929 			}
1930 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
1931 				fatal(NULL);
1932 			$$->type = ACTION_SET_RELATIVE_MED;
1933 			$$->action.relative = -$3;
1934 		}
1935 		| METRIC NUMBER			{	/* alias for MED */
1936 			if ($2 < -INT_MAX || $2 > UINT_MAX) {
1937 				yyerror("bad metric %lld", $2);
1938 				YYERROR;
1939 			}
1940 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
1941 				fatal(NULL);
1942 			if ($2 >= 0) {
1943 				$$->type = ACTION_SET_MED;
1944 				$$->action.metric = $2;
1945 			} else {
1946 				$$->type = ACTION_SET_RELATIVE_MED;
1947 				$$->action.relative = $2;
1948 			}
1949 		}
1950 		| METRIC '+' NUMBER			{
1951 			if ($3 < 0 || $3 > INT_MAX) {
1952 				yyerror("bad metric +%lld", $3);
1953 				YYERROR;
1954 			}
1955 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
1956 				fatal(NULL);
1957 			$$->type = ACTION_SET_RELATIVE_MED;
1958 			$$->action.metric = $3;
1959 		}
1960 		| METRIC '-' NUMBER			{
1961 			if ($3 < 0 || $3 > INT_MAX) {
1962 				yyerror("bad metric -%lld", $3);
1963 				YYERROR;
1964 			}
1965 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
1966 				fatal(NULL);
1967 			$$->type = ACTION_SET_RELATIVE_MED;
1968 			$$->action.relative = -$3;
1969 		}
1970 		| WEIGHT NUMBER				{
1971 			if ($2 < -INT_MAX || $2 > UINT_MAX) {
1972 				yyerror("bad weight %lld", $2);
1973 				YYERROR;
1974 			}
1975 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
1976 				fatal(NULL);
1977 			if ($2 > 0) {
1978 				$$->type = ACTION_SET_WEIGHT;
1979 				$$->action.metric = $2;
1980 			} else {
1981 				$$->type = ACTION_SET_RELATIVE_WEIGHT;
1982 				$$->action.relative = $2;
1983 			}
1984 		}
1985 		| WEIGHT '+' NUMBER			{
1986 			if ($3 < 0 || $3 > INT_MAX) {
1987 				yyerror("bad weight +%lld", $3);
1988 				YYERROR;
1989 			}
1990 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
1991 				fatal(NULL);
1992 			$$->type = ACTION_SET_RELATIVE_WEIGHT;
1993 			$$->action.relative = $3;
1994 		}
1995 		| WEIGHT '-' NUMBER			{
1996 			if ($3 < 0 || $3 > INT_MAX) {
1997 				yyerror("bad weight -%lld", $3);
1998 				YYERROR;
1999 			}
2000 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2001 				fatal(NULL);
2002 			$$->type = ACTION_SET_RELATIVE_WEIGHT;
2003 			$$->action.relative = -$3;
2004 		}
2005 		| NEXTHOP address		{
2006 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2007 				fatal(NULL);
2008 			$$->type = ACTION_SET_NEXTHOP;
2009 			memcpy(&$$->action.nexthop, &$2,
2010 			    sizeof($$->action.nexthop));
2011 		}
2012 		| NEXTHOP BLACKHOLE		{
2013 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2014 				fatal(NULL);
2015 			$$->type = ACTION_SET_NEXTHOP_BLACKHOLE;
2016 		}
2017 		| NEXTHOP REJECT		{
2018 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2019 				fatal(NULL);
2020 			$$->type = ACTION_SET_NEXTHOP_REJECT;
2021 		}
2022 		| NEXTHOP NOMODIFY		{
2023 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2024 				fatal(NULL);
2025 			$$->type = ACTION_SET_NEXTHOP_NOMODIFY;
2026 		}
2027 		| NEXTHOP SELF		{
2028 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2029 				fatal(NULL);
2030 			$$->type = ACTION_SET_NEXTHOP_SELF;
2031 		}
2032 		| PREPEND_SELF NUMBER		{
2033 			if ($2 < 0 || $2 > 128) {
2034 				yyerror("bad number of prepends");
2035 				YYERROR;
2036 			}
2037 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2038 				fatal(NULL);
2039 			$$->type = ACTION_SET_PREPEND_SELF;
2040 			$$->action.prepend = $2;
2041 		}
2042 		| PREPEND_PEER NUMBER		{
2043 			if ($2 < 0 || $2 > 128) {
2044 				yyerror("bad number of prepends");
2045 				YYERROR;
2046 			}
2047 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2048 				fatal(NULL);
2049 			$$->type = ACTION_SET_PREPEND_PEER;
2050 			$$->action.prepend = $2;
2051 		}
2052 		| PFTABLE STRING		{
2053 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2054 				fatal(NULL);
2055 			$$->type = ACTION_PFTABLE;
2056 			if (!(cmd_opts & BGPD_OPT_NOACTION) &&
2057 			    pftable_exists($2) != 0) {
2058 				yyerror("pftable name does not exist");
2059 				free($2);
2060 				free($$);
2061 				YYERROR;
2062 			}
2063 			if (strlcpy($$->action.pftable, $2,
2064 			    sizeof($$->action.pftable)) >=
2065 			    sizeof($$->action.pftable)) {
2066 				yyerror("pftable name too long");
2067 				free($2);
2068 				free($$);
2069 				YYERROR;
2070 			}
2071 			if (pftable_add($2) != 0) {
2072 				yyerror("Couldn't register table");
2073 				free($2);
2074 				free($$);
2075 				YYERROR;
2076 			}
2077 			free($2);
2078 		}
2079 		| RTLABEL STRING		{
2080 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2081 				fatal(NULL);
2082 			$$->type = ACTION_RTLABEL;
2083 			if (strlcpy($$->action.rtlabel, $2,
2084 			    sizeof($$->action.rtlabel)) >=
2085 			    sizeof($$->action.rtlabel)) {
2086 				yyerror("rtlabel name too long");
2087 				free($2);
2088 				free($$);
2089 				YYERROR;
2090 			}
2091 			free($2);
2092 		}
2093 		| COMMUNITY delete STRING	{
2094 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2095 				fatal(NULL);
2096 			if ($2)
2097 				$$->type = ACTION_DEL_COMMUNITY;
2098 			else
2099 				$$->type = ACTION_SET_COMMUNITY;
2100 
2101 			if (parsecommunity(&$$->action.community, $3) == -1) {
2102 				free($3);
2103 				free($$);
2104 				YYERROR;
2105 			}
2106 			free($3);
2107 			/* Don't allow setting of any match */
2108 			if (!$2 && ($$->action.community.as == COMMUNITY_ANY ||
2109 			    $$->action.community.type == COMMUNITY_ANY)) {
2110 				yyerror("'*' is not allowed in set community");
2111 				free($$);
2112 				YYERROR;
2113 			}
2114 		}
2115 		| EXTCOMMUNITY delete STRING STRING {
2116 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2117 				fatal(NULL);
2118 			if ($2)
2119 				$$->type = ACTION_DEL_EXT_COMMUNITY;
2120 			else
2121 				$$->type = ACTION_SET_EXT_COMMUNITY;
2122 
2123 			if (parseextcommunity(&$$->action.ext_community,
2124 			    $3, $4) == -1) {
2125 				free($3);
2126 				free($4);
2127 				free($$);
2128 				YYERROR;
2129 			}
2130 			free($3);
2131 			free($4);
2132 		}
2133 		| ORIGIN origincode {
2134 			if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
2135 				fatal(NULL);
2136 			$$->type = ACTION_SET_ORIGIN;
2137 			$$->action.origin = $2;
2138 		}
2139 		;
2140 
2141 origincode	: string {
2142 			if (!strcmp($1, "egp"))
2143 				$$ = ORIGIN_EGP;
2144 			else if (!strcmp($1, "igp"))
2145 				$$ = ORIGIN_IGP;
2146 			else if (!strcmp($1, "incomplete"))
2147 				$$ = ORIGIN_INCOMPLETE;
2148 			else {
2149 				yyerror("unknown origin \"%s\"", $1);
2150 				free($1);
2151 				YYERROR;
2152 			}
2153 			free($1);
2154 		};
2155 
2156 comma		: ","
2157 		| /* empty */
2158 		;
2159 
2160 unaryop		: '='		{ $$ = OP_EQ; }
2161 		| NE		{ $$ = OP_NE; }
2162 		| LE		{ $$ = OP_LE; }
2163 		| '<'		{ $$ = OP_LT; }
2164 		| GE		{ $$ = OP_GE; }
2165 		| '>'		{ $$ = OP_GT; }
2166 		;
2167 
2168 equalityop	: '='		{ $$ = OP_EQ; }
2169 		| NE		{ $$ = OP_NE; }
2170 		;
2171 
2172 binaryop	: '-'		{ $$ = OP_RANGE; }
2173 		| XRANGE	{ $$ = OP_XRANGE; }
2174 		;
2175 
2176 %%
2177 
2178 struct keywords {
2179 	const char	*k_name;
2180 	int		 k_val;
2181 };
2182 
2183 int
2184 yyerror(const char *fmt, ...)
2185 {
2186 	va_list		 ap;
2187 	char		*msg;
2188 
2189 	file->errors++;
2190 	va_start(ap, fmt);
2191 	if (vasprintf(&msg, fmt, ap) == -1)
2192 		fatalx("yyerror vasprintf");
2193 	va_end(ap);
2194 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
2195 	free(msg);
2196 	return (0);
2197 }
2198 
2199 int
2200 kw_cmp(const void *k, const void *e)
2201 {
2202 	return (strcmp(k, ((const struct keywords *)e)->k_name));
2203 }
2204 
2205 int
2206 lookup(char *s)
2207 {
2208 	/* this has to be sorted always */
2209 	static const struct keywords keywords[] = {
2210 		{ "AS",			AS},
2211 		{ "IPv4",		IPV4},
2212 		{ "IPv6",		IPV6},
2213 		{ "ah",			AH},
2214 		{ "allow",		ALLOW},
2215 		{ "announce",		ANNOUNCE},
2216 		{ "any",		ANY},
2217 		{ "as-4byte",		AS4BYTE },
2218 		{ "blackhole",		BLACKHOLE},
2219 		{ "capabilities",	CAPABILITIES},
2220 		{ "community",		COMMUNITY},
2221 		{ "compare",		COMPARE},
2222 		{ "connect-retry",	CONNECTRETRY},
2223 		{ "connected",		CONNECTED},
2224 		{ "delete",		DELETE},
2225 		{ "demote",		DEMOTE},
2226 		{ "deny",		DENY},
2227 		{ "depend",		DEPEND},
2228 		{ "descr",		DESCR},
2229 		{ "down",		DOWN},
2230 		{ "dump",		DUMP},
2231 		{ "enforce",		ENFORCE},
2232 		{ "esp",		ESP},
2233 		{ "evaluate",		EVALUATE},
2234 		{ "export-target",	EXPORTTRGT},
2235 		{ "ext-community",	EXTCOMMUNITY},
2236 		{ "fib-priority",	FIBPRIORITY},
2237 		{ "fib-update",		FIBUPDATE},
2238 		{ "from",		FROM},
2239 		{ "group",		GROUP},
2240 		{ "holdtime",		HOLDTIME},
2241 		{ "ignore",		IGNORE},
2242 		{ "ike",		IKE},
2243 		{ "import-target",	IMPORTTRGT},
2244 		{ "in",			IN},
2245 		{ "include",		INCLUDE},
2246 		{ "inet",		IPV4},
2247 		{ "inet6",		IPV6},
2248 		{ "ipsec",		IPSEC},
2249 		{ "key",		KEY},
2250 		{ "listen",		LISTEN},
2251 		{ "local-address",	LOCALADDR},
2252 		{ "localpref",		LOCALPREF},
2253 		{ "log",		LOG},
2254 		{ "match",		MATCH},
2255 		{ "max-as-len",		MAXASLEN},
2256 		{ "max-as-seq",		MAXASSEQ},
2257 		{ "max-prefix",		MAXPREFIX},
2258 		{ "md5sig",		MD5SIG},
2259 		{ "med",		MED},
2260 		{ "metric",		METRIC},
2261 		{ "min",		YMIN},
2262 		{ "multihop",		MULTIHOP},
2263 		{ "neighbor",		NEIGHBOR},
2264 		{ "neighbor-as",	NEIGHBORAS},
2265 		{ "network",		NETWORK},
2266 		{ "nexthop",		NEXTHOP},
2267 		{ "no-modify",		NOMODIFY},
2268 		{ "on",			ON},
2269 		{ "or-longer",		LONGER},
2270 		{ "origin",		ORIGIN},
2271 		{ "out",		OUT},
2272 		{ "passive",		PASSIVE},
2273 		{ "password",		PASSWORD},
2274 		{ "peer-as",		PEERAS},
2275 		{ "pftable",		PFTABLE},
2276 		{ "prefix",		PREFIX},
2277 		{ "prefixlen",		PREFIXLEN},
2278 		{ "prepend-neighbor",	PREPEND_PEER},
2279 		{ "prepend-self",	PREPEND_SELF},
2280 		{ "qualify",		QUALIFY},
2281 		{ "quick",		QUICK},
2282 		{ "rd",			RD},
2283 		{ "rde",		RDE},
2284 		{ "rdomain",		RDOMAIN},
2285 		{ "refresh",		REFRESH },
2286 		{ "reject",		REJECT},
2287 		{ "remote-as",		REMOTEAS},
2288 		{ "restart",		RESTART},
2289 		{ "restricted",		RESTRICTED},
2290 		{ "rib",		RIB},
2291 		{ "route-collector",	ROUTECOLL},
2292 		{ "route-reflector",	REFLECTOR},
2293 		{ "router-id",		ROUTERID},
2294 		{ "rtable",		RTABLE},
2295 		{ "rtlabel",		RTLABEL},
2296 		{ "self",		SELF},
2297 		{ "set",		SET},
2298 		{ "socket",		SOCKET },
2299 		{ "softreconfig",	SOFTRECONFIG},
2300 		{ "source-as",		SOURCEAS},
2301 		{ "spi",		SPI},
2302 		{ "static",		STATIC},
2303 		{ "tcp",		TCP},
2304 		{ "to",			TO},
2305 		{ "transit-as",		TRANSITAS},
2306 		{ "transparent-as",	TRANSPARENT},
2307 		{ "ttl-security",	TTLSECURITY},
2308 		{ "via",		VIA},
2309 		{ "weight",		WEIGHT}
2310 	};
2311 	const struct keywords	*p;
2312 
2313 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
2314 	    sizeof(keywords[0]), kw_cmp);
2315 
2316 	if (p)
2317 		return (p->k_val);
2318 	else
2319 		return (STRING);
2320 }
2321 
2322 #define MAXPUSHBACK	128
2323 
2324 u_char	*parsebuf;
2325 int	 parseindex;
2326 u_char	 pushback_buffer[MAXPUSHBACK];
2327 int	 pushback_index = 0;
2328 
2329 int
2330 lgetc(int quotec)
2331 {
2332 	int		c, next;
2333 
2334 	if (parsebuf) {
2335 		/* Read character from the parsebuffer instead of input. */
2336 		if (parseindex >= 0) {
2337 			c = parsebuf[parseindex++];
2338 			if (c != '\0')
2339 				return (c);
2340 			parsebuf = NULL;
2341 		} else
2342 			parseindex++;
2343 	}
2344 
2345 	if (pushback_index)
2346 		return (pushback_buffer[--pushback_index]);
2347 
2348 	if (quotec) {
2349 		if ((c = getc(file->stream)) == EOF) {
2350 			yyerror("reached end of file while parsing "
2351 			    "quoted string");
2352 			if (file == topfile || popfile() == EOF)
2353 				return (EOF);
2354 			return (quotec);
2355 		}
2356 		return (c);
2357 	}
2358 
2359 	while ((c = getc(file->stream)) == '\\') {
2360 		next = getc(file->stream);
2361 		if (next != '\n') {
2362 			c = next;
2363 			break;
2364 		}
2365 		yylval.lineno = file->lineno;
2366 		file->lineno++;
2367 	}
2368 
2369 	while (c == EOF) {
2370 		if (file == topfile || popfile() == EOF)
2371 			return (EOF);
2372 		c = getc(file->stream);
2373 	}
2374 	return (c);
2375 }
2376 
2377 int
2378 lungetc(int c)
2379 {
2380 	if (c == EOF)
2381 		return (EOF);
2382 	if (parsebuf) {
2383 		parseindex--;
2384 		if (parseindex >= 0)
2385 			return (c);
2386 	}
2387 	if (pushback_index < MAXPUSHBACK-1)
2388 		return (pushback_buffer[pushback_index++] = c);
2389 	else
2390 		return (EOF);
2391 }
2392 
2393 int
2394 findeol(void)
2395 {
2396 	int	c;
2397 
2398 	parsebuf = NULL;
2399 
2400 	/* skip to either EOF or the first real EOL */
2401 	while (1) {
2402 		if (pushback_index)
2403 			c = pushback_buffer[--pushback_index];
2404 		else
2405 			c = lgetc(0);
2406 		if (c == '\n') {
2407 			file->lineno++;
2408 			break;
2409 		}
2410 		if (c == EOF)
2411 			break;
2412 	}
2413 	return (ERROR);
2414 }
2415 
2416 int
2417 yylex(void)
2418 {
2419 	u_char	 buf[8096];
2420 	u_char	*p, *val;
2421 	int	 quotec, next, c;
2422 	int	 token;
2423 
2424 top:
2425 	p = buf;
2426 	while ((c = lgetc(0)) == ' ' || c == '\t')
2427 		; /* nothing */
2428 
2429 	yylval.lineno = file->lineno;
2430 	if (c == '#')
2431 		while ((c = lgetc(0)) != '\n' && c != EOF)
2432 			; /* nothing */
2433 	if (c == '$' && parsebuf == NULL) {
2434 		while (1) {
2435 			if ((c = lgetc(0)) == EOF)
2436 				return (0);
2437 
2438 			if (p + 1 >= buf + sizeof(buf) - 1) {
2439 				yyerror("string too long");
2440 				return (findeol());
2441 			}
2442 			if (isalnum(c) || c == '_') {
2443 				*p++ = c;
2444 				continue;
2445 			}
2446 			*p = '\0';
2447 			lungetc(c);
2448 			break;
2449 		}
2450 		val = symget(buf);
2451 		if (val == NULL) {
2452 			yyerror("macro '%s' not defined", buf);
2453 			return (findeol());
2454 		}
2455 		parsebuf = val;
2456 		parseindex = 0;
2457 		goto top;
2458 	}
2459 
2460 	switch (c) {
2461 	case '\'':
2462 	case '"':
2463 		quotec = c;
2464 		while (1) {
2465 			if ((c = lgetc(quotec)) == EOF)
2466 				return (0);
2467 			if (c == '\n') {
2468 				file->lineno++;
2469 				continue;
2470 			} else if (c == '\\') {
2471 				if ((next = lgetc(quotec)) == EOF)
2472 					return (0);
2473 				if (next == quotec || c == ' ' || c == '\t')
2474 					c = next;
2475 				else if (next == '\n') {
2476 					file->lineno++;
2477 					continue;
2478 				} else
2479 					lungetc(next);
2480 			} else if (c == quotec) {
2481 				*p = '\0';
2482 				break;
2483 			} else if (c == '\0') {
2484 				yyerror("syntax error");
2485 				return (findeol());
2486 			}
2487 			if (p + 1 >= buf + sizeof(buf) - 1) {
2488 				yyerror("string too long");
2489 				return (findeol());
2490 			}
2491 			*p++ = c;
2492 		}
2493 		yylval.v.string = strdup(buf);
2494 		if (yylval.v.string == NULL)
2495 			fatal("yylex: strdup");
2496 		return (STRING);
2497 	case '!':
2498 		next = lgetc(0);
2499 		if (next == '=')
2500 			return (NE);
2501 		lungetc(next);
2502 		break;
2503 	case '<':
2504 		next = lgetc(0);
2505 		if (next == '=')
2506 			return (LE);
2507 		lungetc(next);
2508 		break;
2509 	case '>':
2510 		next = lgetc(0);
2511 		if (next == '<')
2512 			return (XRANGE);
2513 		else if (next == '=')
2514 			return (GE);
2515 		lungetc(next);
2516 		break;
2517 	}
2518 
2519 #define allowed_to_end_number(x) \
2520 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
2521 
2522 	if (c == '-' || isdigit(c)) {
2523 		do {
2524 			*p++ = c;
2525 			if ((unsigned)(p-buf) >= sizeof(buf)) {
2526 				yyerror("string too long");
2527 				return (findeol());
2528 			}
2529 		} while ((c = lgetc(0)) != EOF && isdigit(c));
2530 		lungetc(c);
2531 		if (p == buf + 1 && buf[0] == '-')
2532 			goto nodigits;
2533 		if (c == EOF || allowed_to_end_number(c)) {
2534 			const char *errstr = NULL;
2535 
2536 			*p = '\0';
2537 			yylval.v.number = strtonum(buf, LLONG_MIN,
2538 			    LLONG_MAX, &errstr);
2539 			if (errstr) {
2540 				yyerror("\"%s\" invalid number: %s",
2541 				    buf, errstr);
2542 				return (findeol());
2543 			}
2544 			return (NUMBER);
2545 		} else {
2546 nodigits:
2547 			while (p > buf + 1)
2548 				lungetc(*--p);
2549 			c = *--p;
2550 			if (c == '-')
2551 				return (c);
2552 		}
2553 	}
2554 
2555 #define allowed_in_string(x) \
2556 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
2557 	x != '{' && x != '}' && x != '<' && x != '>' && \
2558 	x != '!' && x != '=' && x != '/' && x != '#' && \
2559 	x != ','))
2560 
2561 	if (isalnum(c) || c == ':' || c == '_' || c == '*') {
2562 		do {
2563 			*p++ = c;
2564 			if ((unsigned)(p-buf) >= sizeof(buf)) {
2565 				yyerror("string too long");
2566 				return (findeol());
2567 			}
2568 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
2569 		lungetc(c);
2570 		*p = '\0';
2571 		if ((token = lookup(buf)) == STRING)
2572 			if ((yylval.v.string = strdup(buf)) == NULL)
2573 				fatal("yylex: strdup");
2574 		return (token);
2575 	}
2576 	if (c == '\n') {
2577 		yylval.lineno = file->lineno;
2578 		file->lineno++;
2579 	}
2580 	if (c == EOF)
2581 		return (0);
2582 	return (c);
2583 }
2584 
2585 int
2586 check_file_secrecy(int fd, const char *fname)
2587 {
2588 	struct stat	st;
2589 
2590 	if (fstat(fd, &st)) {
2591 		log_warn("cannot stat %s", fname);
2592 		return (-1);
2593 	}
2594 	if (st.st_uid != 0 && st.st_uid != getuid()) {
2595 		log_warnx("%s: owner not root or current user", fname);
2596 		return (-1);
2597 	}
2598 	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
2599 		log_warnx("%s: group writable or world read/writeable", fname);
2600 		return (-1);
2601 	}
2602 	return (0);
2603 }
2604 
2605 struct file *
2606 pushfile(const char *name, int secret)
2607 {
2608 	struct file	*nfile;
2609 
2610 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
2611 		log_warn("malloc");
2612 		return (NULL);
2613 	}
2614 	if ((nfile->name = strdup(name)) == NULL) {
2615 		log_warn("malloc");
2616 		free(nfile);
2617 		return (NULL);
2618 	}
2619 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
2620 		log_warn("%s", nfile->name);
2621 		free(nfile->name);
2622 		free(nfile);
2623 		return (NULL);
2624 	}
2625 	if (secret &&
2626 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
2627 		fclose(nfile->stream);
2628 		free(nfile->name);
2629 		free(nfile);
2630 		return (NULL);
2631 	}
2632 	nfile->lineno = 1;
2633 	TAILQ_INSERT_TAIL(&files, nfile, entry);
2634 	return (nfile);
2635 }
2636 
2637 int
2638 popfile(void)
2639 {
2640 	struct file	*prev;
2641 
2642 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
2643 		prev->errors += file->errors;
2644 
2645 	TAILQ_REMOVE(&files, file, entry);
2646 	fclose(file->stream);
2647 	free(file->name);
2648 	free(file);
2649 	file = prev;
2650 	return (file ? 0 : EOF);
2651 }
2652 
2653 int
2654 parse_config(char *filename, struct bgpd_config *xconf, struct peer **xpeers)
2655 {
2656 	struct sym		*sym, *next;
2657 	struct peer		*p, *pnext;
2658 	struct rde_rib		*rr;
2659 	int			 errors = 0;
2660 
2661 	conf = new_config();
2662 
2663 	if ((filter_l = calloc(1, sizeof(struct filter_head))) == NULL)
2664 		fatal(NULL);
2665 	if ((peerfilter_l = calloc(1, sizeof(struct filter_head))) == NULL)
2666 		fatal(NULL);
2667 	if ((groupfilter_l = calloc(1, sizeof(struct filter_head))) == NULL)
2668 		fatal(NULL);
2669 	TAILQ_INIT(filter_l);
2670 	TAILQ_INIT(peerfilter_l);
2671 	TAILQ_INIT(groupfilter_l);
2672 
2673 	peer_l = NULL;
2674 	peer_l_old = *xpeers;
2675 	curpeer = NULL;
2676 	curgroup = NULL;
2677 	id = 1;
2678 
2679 	netconf = &conf->networks;
2680 
2681 	add_rib("Adj-RIB-In", 0, F_RIB_NOFIB | F_RIB_NOEVALUATE);
2682 	add_rib("Loc-RIB", 0, 0);
2683 
2684 	if ((file = pushfile(filename, 1)) == NULL) {
2685 		free(conf);
2686 		return (-1);
2687 	}
2688 	topfile = file;
2689 
2690 	yyparse();
2691 	errors = file->errors;
2692 	popfile();
2693 
2694 	/* Free macros and check which have not been used. */
2695 	for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
2696 		next = TAILQ_NEXT(sym, entry);
2697 		if ((cmd_opts & BGPD_OPT_VERBOSE2) && !sym->used)
2698 			fprintf(stderr, "warning: macro \"%s\" not "
2699 			    "used\n", sym->nam);
2700 		if (!sym->persist) {
2701 			free(sym->nam);
2702 			free(sym->val);
2703 			TAILQ_REMOVE(&symhead, sym, entry);
2704 			free(sym);
2705 		}
2706 	}
2707 
2708 	if (errors) {
2709 		for (p = peer_l; p != NULL; p = pnext) {
2710 			pnext = p->next;
2711 			free(p);
2712 		}
2713 
2714 		while ((rr = SIMPLEQ_FIRST(&ribnames)) != NULL) {
2715 			SIMPLEQ_REMOVE_HEAD(&ribnames, entry);
2716 			free(rr);
2717 		}
2718 
2719 		filterlist_free(filter_l);
2720 		filterlist_free(peerfilter_l);
2721 		filterlist_free(groupfilter_l);
2722 
2723 		free_config(conf);
2724 	} else {
2725 		/*
2726 		 * Move filter list and static group and peer filtersets
2727 		 * together. Static group sets come first then peer sets
2728 		 * last normal filter rules.
2729 		 */
2730 		merge_filter_lists(conf->filters, groupfilter_l);
2731 		merge_filter_lists(conf->filters, peerfilter_l);
2732 		merge_filter_lists(conf->filters, filter_l);
2733 
2734 		errors += mrt_mergeconfig(xconf->mrt, conf->mrt);
2735 		errors += merge_config(xconf, conf, peer_l);
2736 		*xpeers = peer_l;
2737 
2738 		for (p = peer_l_old; p != NULL; p = pnext) {
2739 			pnext = p->next;
2740 			free(p);
2741 		}
2742 
2743 		free(filter_l);
2744 		free(peerfilter_l);
2745 		free(groupfilter_l);
2746 	}
2747 
2748 	return (errors ? -1 : 0);
2749 }
2750 
2751 int
2752 symset(const char *nam, const char *val, int persist)
2753 {
2754 	struct sym	*sym;
2755 
2756 	for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
2757 	    sym = TAILQ_NEXT(sym, entry))
2758 		;	/* nothing */
2759 
2760 	if (sym != NULL) {
2761 		if (sym->persist == 1)
2762 			return (0);
2763 		else {
2764 			free(sym->nam);
2765 			free(sym->val);
2766 			TAILQ_REMOVE(&symhead, sym, entry);
2767 			free(sym);
2768 		}
2769 	}
2770 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
2771 		return (-1);
2772 
2773 	sym->nam = strdup(nam);
2774 	if (sym->nam == NULL) {
2775 		free(sym);
2776 		return (-1);
2777 	}
2778 	sym->val = strdup(val);
2779 	if (sym->val == NULL) {
2780 		free(sym->nam);
2781 		free(sym);
2782 		return (-1);
2783 	}
2784 	sym->used = 0;
2785 	sym->persist = persist;
2786 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
2787 	return (0);
2788 }
2789 
2790 int
2791 cmdline_symset(char *s)
2792 {
2793 	char	*sym, *val;
2794 	int	ret;
2795 	size_t	len;
2796 
2797 	if ((val = strrchr(s, '=')) == NULL)
2798 		return (-1);
2799 
2800 	len = strlen(s) - strlen(val) + 1;
2801 	if ((sym = malloc(len)) == NULL)
2802 		fatal("cmdline_symset: malloc");
2803 
2804 	strlcpy(sym, s, len);
2805 
2806 	ret = symset(sym, val + 1, 1);
2807 	free(sym);
2808 
2809 	return (ret);
2810 }
2811 
2812 char *
2813 symget(const char *nam)
2814 {
2815 	struct sym	*sym;
2816 
2817 	TAILQ_FOREACH(sym, &symhead, entry)
2818 		if (strcmp(nam, sym->nam) == 0) {
2819 			sym->used = 1;
2820 			return (sym->val);
2821 		}
2822 	return (NULL);
2823 }
2824 
2825 int
2826 getcommunity(char *s)
2827 {
2828 	int		 val;
2829 	const char	*errstr;
2830 
2831 	if (strcmp(s, "*") == 0)
2832 		return (COMMUNITY_ANY);
2833 	if (strcmp(s, "neighbor-as") == 0)
2834 		return (COMMUNITY_NEIGHBOR_AS);
2835 	val = strtonum(s, 0, USHRT_MAX, &errstr);
2836 	if (errstr) {
2837 		yyerror("Community %s is %s (max: %u)", s, errstr, USHRT_MAX);
2838 		return (COMMUNITY_ERROR);
2839 	}
2840 	return (val);
2841 }
2842 
2843 int
2844 parsecommunity(struct filter_community *c, char *s)
2845 {
2846 	char *p;
2847 	int i, as;
2848 
2849 	/* Well-known communities */
2850 	if (strcasecmp(s, "NO_EXPORT") == 0) {
2851 		c->as = COMMUNITY_WELLKNOWN;
2852 		c->type = COMMUNITY_NO_EXPORT;
2853 		return (0);
2854 	} else if (strcasecmp(s, "NO_ADVERTISE") == 0) {
2855 		c->as = COMMUNITY_WELLKNOWN;
2856 		c->type = COMMUNITY_NO_ADVERTISE;
2857 		return (0);
2858 	} else if (strcasecmp(s, "NO_EXPORT_SUBCONFED") == 0) {
2859 		c->as = COMMUNITY_WELLKNOWN;
2860 		c->type = COMMUNITY_NO_EXPSUBCONFED;
2861 		return (0);
2862 	} else if (strcasecmp(s, "NO_PEER") == 0) {
2863 		c->as = COMMUNITY_WELLKNOWN;
2864 		c->type = COMMUNITY_NO_PEER;
2865 		return (0);
2866 	} else if (strcasecmp(s, "BLACKHOLE") == 0) {
2867 		c->as = COMMUNITY_WELLKNOWN;
2868 		c->type = COMMUNITY_BLACKHOLE;
2869 		return (0);
2870 	}
2871 
2872 	if ((p = strchr(s, ':')) == NULL) {
2873 		yyerror("Bad community syntax");
2874 		return (-1);
2875 	}
2876 	*p++ = 0;
2877 
2878 	if ((i = getcommunity(s)) == COMMUNITY_ERROR)
2879 		return (-1);
2880 	if (i == COMMUNITY_WELLKNOWN) {
2881 		yyerror("Bad community AS number");
2882 		return (-1);
2883 	}
2884 	as = i;
2885 
2886 	if ((i = getcommunity(p)) == COMMUNITY_ERROR)
2887 		return (-1);
2888 	c->as = as;
2889 	c->type = i;
2890 
2891 	return (0);
2892 }
2893 
2894 int
2895 parsesubtype(char *type)
2896 {
2897 	/* this has to be sorted always */
2898 	static const struct keywords keywords[] = {
2899 		{ "bdc",	EXT_COMMUNITY_BGP_COLLECT },
2900 		{ "odi",	EXT_COMMUNITY_OSPF_DOM_ID },
2901 		{ "ori",	EXT_COMMUNITY_OSPF_RTR_ID },
2902 		{ "ort",	EXT_COMMUNITY_OSPF_RTR_TYPE },
2903 		{ "rt",		EXT_COMMUNITY_ROUTE_TGT },
2904 		{ "soo",	EXT_COMMUNITY_ROUTE_ORIG }
2905 	};
2906 	const struct keywords	*p;
2907 
2908 	p = bsearch(type, keywords, sizeof(keywords)/sizeof(keywords[0]),
2909 	    sizeof(keywords[0]), kw_cmp);
2910 
2911 	if (p)
2912 		return (p->k_val);
2913 	else
2914 		return (-1);
2915 }
2916 
2917 int
2918 parseextvalue(char *s, u_int32_t *v)
2919 {
2920 	const char 	*errstr;
2921 	char		*p;
2922 	struct in_addr	 ip;
2923 	u_int32_t	 uvalh = 0, uval;
2924 
2925 	if ((p = strchr(s, '.')) == NULL) {
2926 		/* AS_PLAIN number (4 or 2 byte) */
2927 		uval = strtonum(s, 0, UINT_MAX, &errstr);
2928 		if (errstr) {
2929 			yyerror("Bad ext-community %s is %s", s, errstr);
2930 			return (-1);
2931 		}
2932 		*v = uval;
2933 		if (uval > USHRT_MAX)
2934 			return (EXT_COMMUNITY_FOUR_AS);
2935 		else
2936 			return (EXT_COMMUNITY_TWO_AS);
2937 	} else if (strchr(p + 1, '.') == NULL) {
2938 		/* AS_DOT number (4-byte) */
2939 		*p++ = '\0';
2940 		uvalh = strtonum(s, 0, USHRT_MAX, &errstr);
2941 		if (errstr) {
2942 			yyerror("Bad ext-community %s is %s", s, errstr);
2943 			return (-1);
2944 		}
2945 		uval = strtonum(p, 0, USHRT_MAX, &errstr);
2946 		if (errstr) {
2947 			yyerror("Bad ext-community %s is %s", p, errstr);
2948 			return (-1);
2949 		}
2950 		*v = uval | (uvalh << 16);
2951 		return (EXT_COMMUNITY_FOUR_AS);
2952 	} else {
2953 		/* more then one dot -> IP address */
2954 		if (inet_aton(s, &ip) == 0) {
2955 			yyerror("Bad ext-community %s not parseable", s);
2956 			return (-1);
2957 		}
2958 		*v = ip.s_addr;
2959 		return (EXT_COMMUNITY_IPV4);
2960 	}
2961 	return (-1);
2962 }
2963 
2964 int
2965 parseextcommunity(struct filter_extcommunity *c, char *t, char *s)
2966 {
2967 	const struct ext_comm_pairs	 iana[] = IANA_EXT_COMMUNITIES;
2968 	const char 	*errstr;
2969 	u_int64_t	 ullval;
2970 	u_int32_t	 uval;
2971 	char		*p, *ep;
2972 	unsigned int	 i;
2973 	int		 type, subtype;
2974 
2975 	if ((subtype = parsesubtype(t)) == -1) {
2976 		yyerror("Bad ext-community unknown type");
2977 		return (-1);
2978 	}
2979 
2980 	if ((p = strchr(s, ':')) == NULL) {
2981 		type = EXT_COMMUNITY_OPAQUE,
2982 		errno = 0;
2983 		ullval = strtoull(s, &ep, 0);
2984 		if (s[0] == '\0' || *ep != '\0') {
2985 			yyerror("Bad ext-community bad value");
2986 			return (-1);
2987 		}
2988 		if (errno == ERANGE && ullval > EXT_COMMUNITY_OPAQUE_MAX) {
2989 			yyerror("Bad ext-community value to big");
2990 			return (-1);
2991 		}
2992 		c->data.ext_opaq = ullval;
2993 	} else {
2994 		*p++ = '\0';
2995 		if ((type = parseextvalue(s, &uval)) == -1)
2996 			return (-1);
2997 		switch (type) {
2998 		case EXT_COMMUNITY_TWO_AS:
2999 			ullval = strtonum(p, 0, UINT_MAX, &errstr);
3000 			break;
3001 		case EXT_COMMUNITY_IPV4:
3002 		case EXT_COMMUNITY_FOUR_AS:
3003 			ullval = strtonum(p, 0, USHRT_MAX, &errstr);
3004 			break;
3005 		default:
3006 			fatalx("parseextcommunity: unexpected result");
3007 		}
3008 		if (errstr) {
3009 			yyerror("Bad ext-community %s is %s", p,
3010 			    errstr);
3011 			return (-1);
3012 		}
3013 		switch (type) {
3014 		case EXT_COMMUNITY_TWO_AS:
3015 			c->data.ext_as.as = uval;
3016 			c->data.ext_as.val = ullval;
3017 			break;
3018 		case EXT_COMMUNITY_IPV4:
3019 			c->data.ext_ip.addr.s_addr = uval;
3020 			c->data.ext_ip.val = ullval;
3021 			break;
3022 		case EXT_COMMUNITY_FOUR_AS:
3023 			c->data.ext_as4.as4 = uval;
3024 			c->data.ext_as4.val = ullval;
3025 			break;
3026 		}
3027 	}
3028 	c->type = type;
3029 	c->subtype = subtype;
3030 
3031 	/* verify type/subtype combo */
3032 	for (i = 0; i < sizeof(iana)/sizeof(iana[0]); i++) {
3033 		if (iana[i].type == type && iana[i].subtype == subtype) {
3034 			if (iana[i].transitive)
3035 				c->type |= EXT_COMMUNITY_TRANSITIVE;
3036 			c->flags |= EXT_COMMUNITY_FLAG_VALID;
3037 			return (0);
3038 		}
3039 	}
3040 
3041 	yyerror("Bad ext-community bad format for type");
3042 	return (-1);
3043 }
3044 
3045 struct peer *
3046 alloc_peer(void)
3047 {
3048 	struct peer	*p;
3049 	u_int8_t	 i;
3050 
3051 	if ((p = calloc(1, sizeof(struct peer))) == NULL)
3052 		fatal("new_peer");
3053 
3054 	/* some sane defaults */
3055 	p->state = STATE_NONE;
3056 	p->next = NULL;
3057 	p->conf.distance = 1;
3058 	p->conf.announce_type = ANNOUNCE_UNDEF;
3059 	p->conf.announce_capa = 1;
3060 	for (i = 0; i < AID_MAX; i++)
3061 		p->conf.capabilities.mp[i] = -1;
3062 	p->conf.capabilities.refresh = 1;
3063 	p->conf.capabilities.grestart.restart = 1;
3064 	p->conf.capabilities.as4byte = 1;
3065 	p->conf.local_as = conf->as;
3066 	p->conf.local_short_as = conf->short_as;
3067 	p->conf.softreconfig_in = 1;
3068 	p->conf.softreconfig_out = 1;
3069 
3070 	return (p);
3071 }
3072 
3073 struct peer *
3074 new_peer(void)
3075 {
3076 	struct peer		*p;
3077 
3078 	p = alloc_peer();
3079 
3080 	if (curgroup != NULL) {
3081 		memcpy(p, curgroup, sizeof(struct peer));
3082 		if (strlcpy(p->conf.group, curgroup->conf.group,
3083 		    sizeof(p->conf.group)) >= sizeof(p->conf.group))
3084 			fatalx("new_peer group strlcpy");
3085 		if (strlcpy(p->conf.descr, curgroup->conf.descr,
3086 		    sizeof(p->conf.descr)) >= sizeof(p->conf.descr))
3087 			fatalx("new_peer descr strlcpy");
3088 		p->conf.groupid = curgroup->conf.id;
3089 		p->conf.local_as = curgroup->conf.local_as;
3090 		p->conf.local_short_as = curgroup->conf.local_short_as;
3091 	}
3092 	p->next = NULL;
3093 	if (conf->flags & BGPD_FLAG_DECISION_TRANS_AS)
3094 		p->conf.flags |= PEERFLAG_TRANS_AS;
3095 	return (p);
3096 }
3097 
3098 struct peer *
3099 new_group(void)
3100 {
3101 	return (alloc_peer());
3102 }
3103 
3104 int
3105 add_mrtconfig(enum mrt_type type, char *name, int timeout, struct peer *p,
3106     char *rib)
3107 {
3108 	struct mrt	*m, *n;
3109 
3110 	LIST_FOREACH(m, conf->mrt, entry) {
3111 		if ((rib && strcmp(rib, m->rib)) ||
3112 		    (!rib && *m->rib))
3113 			continue;
3114 		if (p == NULL) {
3115 			if (m->peer_id != 0 || m->group_id != 0)
3116 				continue;
3117 		} else {
3118 			if (m->peer_id != p->conf.id ||
3119 			    m->group_id != p->conf.groupid)
3120 				continue;
3121 		}
3122 		if (m->type == type) {
3123 			yyerror("only one mrtdump per type allowed.");
3124 			return (-1);
3125 		}
3126 	}
3127 
3128 	if ((n = calloc(1, sizeof(struct mrt_config))) == NULL)
3129 		fatal("add_mrtconfig");
3130 
3131 	n->type = type;
3132 	if (strlcpy(MRT2MC(n)->name, name, sizeof(MRT2MC(n)->name)) >=
3133 	    sizeof(MRT2MC(n)->name)) {
3134 		yyerror("filename \"%s\" too long: max %zu",
3135 		    name, sizeof(MRT2MC(n)->name) - 1);
3136 		free(n);
3137 		return (-1);
3138 	}
3139 	MRT2MC(n)->ReopenTimerInterval = timeout;
3140 	if (p != NULL) {
3141 		if (curgroup == p) {
3142 			n->peer_id = 0;
3143 			n->group_id = p->conf.id;
3144 		} else {
3145 			n->peer_id = p->conf.id;
3146 			n->group_id = 0;
3147 		}
3148 	}
3149 	if (rib) {
3150 		if (!find_rib(rib)) {
3151 			yyerror("rib \"%s\" does not exist.", rib);
3152 			free(n);
3153 			return (-1);
3154 		}
3155 		if (strlcpy(n->rib, rib, sizeof(n->rib)) >=
3156 		    sizeof(n->rib)) {
3157 			yyerror("rib name \"%s\" too long: max %zu",
3158 			    name, sizeof(n->rib) - 1);
3159 			free(n);
3160 			return (-1);
3161 		}
3162 	}
3163 
3164 	LIST_INSERT_HEAD(conf->mrt, n, entry);
3165 
3166 	return (0);
3167 }
3168 
3169 int
3170 add_rib(char *name, u_int rtableid, u_int16_t flags)
3171 {
3172 	struct rde_rib	*rr;
3173 	u_int		 rdom;
3174 
3175 	if ((rr = find_rib(name)) == NULL) {
3176 		if ((rr = calloc(1, sizeof(*rr))) == NULL) {
3177 			log_warn("add_rib");
3178 			return (-1);
3179 		}
3180 	}
3181 	if (strlcpy(rr->name, name, sizeof(rr->name)) >= sizeof(rr->name)) {
3182 		yyerror("rib name \"%s\" too long: max %zu",
3183 		   name, sizeof(rr->name) - 1);
3184 		free(rr);
3185 		return (-1);
3186 	}
3187 	rr->flags |= flags;
3188 	if ((rr->flags & F_RIB_HASNOFIB) == 0) {
3189 		if (ktable_exists(rtableid, &rdom) != 1) {
3190 			yyerror("rtable id %u does not exist", rtableid);
3191 			free(rr);
3192 			return (-1);
3193 		}
3194 		if (rdom != 0) {
3195 			yyerror("rtable %u does not belong to rdomain 0",
3196 			    rtableid);
3197 			free(rr);
3198 			return (-1);
3199 		}
3200 		rr->rtableid = rtableid;
3201 	}
3202 	SIMPLEQ_INSERT_TAIL(&ribnames, rr, entry);
3203 	return (0);
3204 }
3205 
3206 struct rde_rib *
3207 find_rib(char *name)
3208 {
3209 	struct rde_rib	*rr;
3210 
3211 	SIMPLEQ_FOREACH(rr, &ribnames, entry) {
3212 		if (!strcmp(rr->name, name))
3213 			return (rr);
3214 	}
3215 	return (NULL);
3216 }
3217 
3218 int
3219 get_id(struct peer *newpeer)
3220 {
3221 	struct peer	*p;
3222 
3223 	for (p = peer_l_old; p != NULL; p = p->next)
3224 		if (newpeer->conf.remote_addr.aid) {
3225 			if (!memcmp(&p->conf.remote_addr,
3226 			    &newpeer->conf.remote_addr,
3227 			    sizeof(p->conf.remote_addr))) {
3228 				newpeer->conf.id = p->conf.id;
3229 				return (0);
3230 			}
3231 		} else {	/* newpeer is a group */
3232 			if (strcmp(newpeer->conf.group, p->conf.group) == 0) {
3233 				newpeer->conf.id = p->conf.groupid;
3234 				return (0);
3235 			}
3236 		}
3237 
3238 	/* new one */
3239 	for (; id < UINT_MAX / 2; id++) {
3240 		for (p = peer_l_old; p != NULL &&
3241 		    p->conf.id != id && p->conf.groupid != id; p = p->next)
3242 			;	/* nothing */
3243 		if (p == NULL) {	/* we found a free id */
3244 			newpeer->conf.id = id++;
3245 			return (0);
3246 		}
3247 	}
3248 
3249 	return (-1);
3250 }
3251 
3252 int
3253 merge_prefixspec(struct filter_prefix_l *p, struct filter_prefixlen *pl)
3254 {
3255 	u_int8_t max_len = 0;
3256 
3257 	switch (p->p.addr.aid) {
3258 	case AID_INET:
3259 	case AID_VPN_IPv4:
3260 		max_len = 32;
3261 		break;
3262 	case AID_INET6:
3263 		max_len = 128;
3264 		break;
3265 	}
3266 
3267 	switch (pl->op) {
3268 	case OP_NONE:
3269 		return (0);
3270 	case OP_RANGE:
3271 	case OP_XRANGE:
3272 		if (pl->len_min > max_len || pl->len_max > max_len) {
3273 			yyerror("prefixlen %d too big for AF, limit %d",
3274 			    pl->len_min > max_len ? pl->len_min : pl->len_max,
3275 			    max_len);
3276 			return (-1);
3277 		}
3278 		if (pl->len_min < p->p.len) {
3279 			yyerror("prefixlen %d smaller than prefix, limit %d",
3280 			    pl->len_min, p->p.len);
3281 			return (-1);
3282 		}
3283 		p->p.len_max = pl->len_max;
3284 		break;
3285 	case OP_GE:
3286 		/* fix up the "or-longer" case */
3287 		if (pl->len_min == -1)
3288 			pl->len_min = p->p.len;
3289 		/* FALLTHROUGH */
3290 	case OP_EQ:
3291 	case OP_NE:
3292 	case OP_LE:
3293 	case OP_GT:
3294 		if (pl->len_min > max_len) {
3295 			yyerror("prefixlen %d to big for AF, limit %d",
3296 			    pl->len_min, max_len);
3297 			return (-1);
3298 		}
3299 		if (pl->len_min < p->p.len) {
3300 			yyerror("prefixlen %d smaller than prefix, limit %d",
3301 			    pl->len_min, p->p.len);
3302 			return (-1);
3303 		}
3304 		break;
3305 	case OP_LT:
3306 		if (pl->len_min > max_len - 1) {
3307 			yyerror("prefixlen %d to big for AF, limit %d",
3308 			    pl->len_min, max_len - 1);
3309 			return (-1);
3310 		}
3311 		if (pl->len_min < p->p.len + 1) {
3312 			yyerror("prefixlen %d too small for prefix, limit %d",
3313 			    pl->len_min, p->p.len + 1);
3314 			return (-1);
3315 		}
3316 		break;
3317 	}
3318 
3319 	p->p.op = pl->op;
3320 	p->p.len_min = pl->len_min;
3321 	return (0);
3322 }
3323 
3324 int
3325 expand_rule(struct filter_rule *rule, struct filter_peers_l *peer,
3326     struct filter_match_l *match, struct filter_set_head *set)
3327 {
3328 	struct filter_rule	*r;
3329 	struct filter_peers_l	*p, *pnext;
3330 	struct filter_prefix_l	*prefix, *prefix_next;
3331 	struct filter_as_l	*a, *anext;
3332 	struct filter_set	*s;
3333 
3334 	p = peer;
3335 	do {
3336 		a = match->as_l;
3337 		do {
3338 			prefix = match->prefix_l;
3339 			do {
3340 				if ((r = calloc(1,
3341 				    sizeof(struct filter_rule))) == NULL) {
3342 					log_warn("expand_rule");
3343 					return (-1);
3344 				}
3345 
3346 				memcpy(r, rule, sizeof(struct filter_rule));
3347 				memcpy(&r->match, match,
3348 				    sizeof(struct filter_match));
3349 				TAILQ_INIT(&r->set);
3350 				copy_filterset(set, &r->set);
3351 
3352 				if (p != NULL)
3353 					memcpy(&r->peer, &p->p,
3354 					    sizeof(struct filter_peers));
3355 
3356 				if (prefix != NULL)
3357 					memcpy(&r->match.prefix, &prefix->p,
3358 					    sizeof(r->match.prefix));
3359 
3360 				if (a != NULL)
3361 					memcpy(&r->match.as, &a->a,
3362 					    sizeof(struct filter_as));
3363 
3364 				TAILQ_INSERT_TAIL(filter_l, r, entry);
3365 
3366 				if (prefix != NULL)
3367 					prefix = prefix->next;
3368 			} while (prefix != NULL);
3369 
3370 			if (a != NULL)
3371 				a = a->next;
3372 		} while (a != NULL);
3373 
3374 		if (p != NULL)
3375 			p = p->next;
3376 	} while (p != NULL);
3377 
3378 	for (p = peer; p != NULL; p = pnext) {
3379 		pnext = p->next;
3380 		free(p);
3381 	}
3382 
3383 	for (a = match->as_l; a != NULL; a = anext) {
3384 		anext = a->next;
3385 		free(a);
3386 	}
3387 
3388 	for (prefix = match->prefix_l; prefix != NULL; prefix = prefix_next) {
3389 		prefix_next = prefix->next;
3390 		free(prefix);
3391 	}
3392 
3393 	if (set != NULL) {
3394 		while ((s = TAILQ_FIRST(set)) != NULL) {
3395 			TAILQ_REMOVE(set, s, entry);
3396 			free(s);
3397 		}
3398 		free(set);
3399 	}
3400 
3401 	return (0);
3402 }
3403 
3404 int
3405 str2key(char *s, char *dest, size_t max_len)
3406 {
3407 	unsigned	i;
3408 	char		t[3];
3409 
3410 	if (strlen(s) / 2 > max_len) {
3411 		yyerror("key too long");
3412 		return (-1);
3413 	}
3414 
3415 	if (strlen(s) % 2) {
3416 		yyerror("key must be of even length");
3417 		return (-1);
3418 	}
3419 
3420 	for (i = 0; i < strlen(s) / 2; i++) {
3421 		t[0] = s[2*i];
3422 		t[1] = s[2*i + 1];
3423 		t[2] = 0;
3424 		if (!isxdigit(t[0]) || !isxdigit(t[1])) {
3425 			yyerror("key must be specified in hex");
3426 			return (-1);
3427 		}
3428 		dest[i] = strtoul(t, NULL, 16);
3429 	}
3430 
3431 	return (0);
3432 }
3433 
3434 int
3435 neighbor_consistent(struct peer *p)
3436 {
3437 	u_int8_t	i;
3438 
3439 	/* local-address and peer's address: same address family */
3440 	if (p->conf.local_addr.aid &&
3441 	    p->conf.local_addr.aid != p->conf.remote_addr.aid) {
3442 		yyerror("local-address and neighbor address "
3443 		    "must be of the same address family");
3444 		return (-1);
3445 	}
3446 
3447 	/* with any form of ipsec local-address is required */
3448 	if ((p->conf.auth.method == AUTH_IPSEC_IKE_ESP ||
3449 	    p->conf.auth.method == AUTH_IPSEC_IKE_AH ||
3450 	    p->conf.auth.method == AUTH_IPSEC_MANUAL_ESP ||
3451 	    p->conf.auth.method == AUTH_IPSEC_MANUAL_AH) &&
3452 	    !p->conf.local_addr.aid) {
3453 		yyerror("neighbors with any form of IPsec configured "
3454 		    "need local-address to be specified");
3455 		return (-1);
3456 	}
3457 
3458 	/* with static keying we need both directions */
3459 	if ((p->conf.auth.method == AUTH_IPSEC_MANUAL_ESP ||
3460 	    p->conf.auth.method == AUTH_IPSEC_MANUAL_AH) &&
3461 	    (!p->conf.auth.spi_in || !p->conf.auth.spi_out)) {
3462 		yyerror("with manual keyed IPsec, SPIs and keys "
3463 		    "for both directions are required");
3464 		return (-1);
3465 	}
3466 
3467 	if (!conf->as) {
3468 		yyerror("AS needs to be given before neighbor definitions");
3469 		return (-1);
3470 	}
3471 
3472 	/* set default values if they where undefined */
3473 	p->conf.ebgp = (p->conf.remote_as != conf->as);
3474 	if (p->conf.announce_type == ANNOUNCE_UNDEF)
3475 		p->conf.announce_type = p->conf.ebgp ?
3476 		    ANNOUNCE_SELF : ANNOUNCE_ALL;
3477 	if (p->conf.enforce_as == ENFORCE_AS_UNDEF)
3478 		p->conf.enforce_as = p->conf.ebgp ?
3479 		    ENFORCE_AS_ON : ENFORCE_AS_OFF;
3480 
3481 	/* EBGP neighbors are not allowed in route reflector clusters */
3482 	if (p->conf.reflector_client && p->conf.ebgp) {
3483 		yyerror("EBGP neighbors are not allowed in route "
3484 		    "reflector clusters");
3485 		return (-1);
3486 	}
3487 
3488 	/* the default MP capability is NONE */
3489 	for (i = 0; i < AID_MAX; i++)
3490 		if (p->conf.capabilities.mp[i] == -1)
3491 			p->conf.capabilities.mp[i] = 0;
3492 
3493 	return (0);
3494 }
3495 
3496 int
3497 merge_filterset(struct filter_set_head *sh, struct filter_set *s)
3498 {
3499 	struct filter_set	*t;
3500 
3501 	TAILQ_FOREACH(t, sh, entry) {
3502 		/*
3503 		 * need to cycle across the full list because even
3504 		 * if types are not equal filterset_cmp() may return 0.
3505 		 */
3506 		if (filterset_cmp(s, t) == 0) {
3507 			if (s->type == ACTION_SET_COMMUNITY)
3508 				yyerror("community is already set");
3509 			else if (s->type == ACTION_DEL_COMMUNITY)
3510 				yyerror("community will already be deleted");
3511 			else if (s->type == ACTION_SET_EXT_COMMUNITY)
3512 				yyerror("ext-community is already set");
3513 			else if (s->type == ACTION_DEL_EXT_COMMUNITY)
3514 				yyerror(
3515 				    "ext-community will already be deleted");
3516 			else
3517 				yyerror("redefining set parameter %s",
3518 				    filterset_name(s->type));
3519 			return (-1);
3520 		}
3521 	}
3522 
3523 	TAILQ_FOREACH(t, sh, entry) {
3524 		if (s->type < t->type) {
3525 			TAILQ_INSERT_BEFORE(t, s, entry);
3526 			return (0);
3527 		}
3528 		if (s->type == t->type)
3529 			switch (s->type) {
3530 			case ACTION_SET_COMMUNITY:
3531 			case ACTION_DEL_COMMUNITY:
3532 				if (s->action.community.as <
3533 				    t->action.community.as ||
3534 				    (s->action.community.as ==
3535 				    t->action.community.as &&
3536 				    s->action.community.type <
3537 				    t->action.community.type)) {
3538 					TAILQ_INSERT_BEFORE(t, s, entry);
3539 					return (0);
3540 				}
3541 				break;
3542 			case ACTION_SET_EXT_COMMUNITY:
3543 			case ACTION_DEL_EXT_COMMUNITY:
3544 				if (memcmp(&s->action.ext_community,
3545 				    &t->action.ext_community,
3546 				    sizeof(s->action.ext_community)) < 0) {
3547 					TAILQ_INSERT_BEFORE(t, s, entry);
3548 					return (0);
3549 				}
3550 				break;
3551 			case ACTION_SET_NEXTHOP:
3552 				if (s->action.nexthop.aid <
3553 				    t->action.nexthop.aid) {
3554 					TAILQ_INSERT_BEFORE(t, s, entry);
3555 					return (0);
3556 				}
3557 				break;
3558 			default:
3559 				break;
3560 			}
3561 	}
3562 
3563 	TAILQ_INSERT_TAIL(sh, s, entry);
3564 	return (0);
3565 }
3566 
3567 void
3568 copy_filterset(struct filter_set_head *source, struct filter_set_head *dest)
3569 {
3570 	struct filter_set	*s, *t;
3571 
3572 	if (source == NULL)
3573 		return;
3574 
3575 	TAILQ_FOREACH(s, source, entry) {
3576 		if ((t = malloc(sizeof(struct filter_set))) == NULL)
3577 			fatal(NULL);
3578 		memcpy(t, s, sizeof(struct filter_set));
3579 		TAILQ_INSERT_TAIL(dest, t, entry);
3580 	}
3581 }
3582 
3583 void
3584 merge_filter_lists(struct filter_head *dst, struct filter_head *src)
3585 {
3586 	struct filter_rule *r;
3587 
3588 	while ((r = TAILQ_FIRST(src)) != NULL) {
3589 		TAILQ_REMOVE(src, r, entry);
3590 		TAILQ_INSERT_TAIL(dst, r, entry);
3591 	}
3592 }
3593 
3594 struct filter_rule *
3595 get_rule(enum action_types type)
3596 {
3597 	struct filter_rule	*r;
3598 	int			 out;
3599 
3600 	switch (type) {
3601 	case ACTION_SET_PREPEND_SELF:
3602 	case ACTION_SET_NEXTHOP_NOMODIFY:
3603 	case ACTION_SET_NEXTHOP_SELF:
3604 		out = 1;
3605 		break;
3606 	default:
3607 		out = 0;
3608 		break;
3609 	}
3610 	r = (curpeer == curgroup) ? curgroup_filter[out] : curpeer_filter[out];
3611 	if (r == NULL) {
3612 		if ((r = calloc(1, sizeof(struct filter_rule))) == NULL)
3613 			fatal(NULL);
3614 		r->quick = 0;
3615 		r->dir = out ? DIR_OUT : DIR_IN;
3616 		r->action = ACTION_NONE;
3617 		r->match.community.as = COMMUNITY_UNSET;
3618 		TAILQ_INIT(&r->set);
3619 		if (curpeer == curgroup) {
3620 			/* group */
3621 			r->peer.groupid = curgroup->conf.id;
3622 			curgroup_filter[out] = r;
3623 		} else {
3624 			/* peer */
3625 			r->peer.peerid = curpeer->conf.id;
3626 			curpeer_filter[out] = r;
3627 		}
3628 	}
3629 	return (r);
3630 }
3631