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