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