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