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