GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/bgpd/parse.y Lines: 0 802 0.0 %
Date: 2017-11-07 Branches: 0 601 0.0 %

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