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