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