1 /* $OpenBSD: parse.y,v 1.104 2021/10/15 15:01:28 naddy Exp $ */ 2 3 /* 4 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 5 * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org> 6 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> 7 * Copyright (c) 2001 Markus Friedl. All rights reserved. 8 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. 9 * Copyright (c) 2001 Theo de Raadt. All rights reserved. 10 * 11 * Permission to use, copy, modify, and distribute this software for any 12 * purpose with or without fee is hereby granted, provided that the above 13 * copyright notice and this permission notice appear in all copies. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 21 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 */ 23 24 %{ 25 #include <sys/types.h> 26 #include <sys/socket.h> 27 #include <sys/stat.h> 28 #include <net/route.h> 29 #include <netinet/in.h> 30 #include <arpa/inet.h> 31 #include <ctype.h> 32 #include <err.h> 33 #include <errno.h> 34 #include <unistd.h> 35 #include <ifaddrs.h> 36 #include <limits.h> 37 #include <stdarg.h> 38 #include <stdio.h> 39 #include <string.h> 40 #include <syslog.h> 41 42 #include "ospf.h" 43 #include "ospfd.h" 44 #include "ospfe.h" 45 #include "log.h" 46 47 TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); 48 static struct file { 49 TAILQ_ENTRY(file) entry; 50 FILE *stream; 51 char *name; 52 size_t ungetpos; 53 size_t ungetsize; 54 u_char *ungetbuf; 55 int eof_reached; 56 int lineno; 57 int errors; 58 } *file, *topfile; 59 struct file *pushfile(const char *, int); 60 int popfile(void); 61 int check_file_secrecy(int, const char *); 62 int yyparse(void); 63 int yylex(void); 64 int yyerror(const char *, ...) 65 __attribute__((__format__ (printf, 1, 2))) 66 __attribute__((__nonnull__ (1))); 67 int kw_cmp(const void *, const void *); 68 int lookup(char *); 69 int igetc(void); 70 int lgetc(int); 71 void lungetc(int); 72 int findeol(void); 73 74 TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); 75 struct sym { 76 TAILQ_ENTRY(sym) entry; 77 int used; 78 int persist; 79 char *nam; 80 char *val; 81 }; 82 int symset(const char *, const char *, int); 83 char *symget(const char *); 84 85 void clear_config(struct ospfd_conf *xconf); 86 int host(const char *, struct in_addr *, struct in_addr *); 87 88 static struct ospfd_conf *conf; 89 static int errors = 0; 90 91 struct area *area = NULL; 92 struct iface *iface = NULL; 93 94 struct config_defaults { 95 char auth_key[MAX_SIMPLE_AUTH_LEN]; 96 struct auth_md_head md_list; 97 u_int32_t dead_interval; 98 u_int32_t fast_hello_interval; 99 u_int16_t transmit_delay; 100 u_int16_t hello_interval; 101 u_int16_t rxmt_interval; 102 u_int16_t metric; 103 enum auth_type auth_type; 104 u_int8_t auth_keyid; 105 u_int8_t priority; 106 u_int8_t p2p; 107 }; 108 109 struct config_defaults globaldefs; 110 struct config_defaults areadefs; 111 struct config_defaults ifacedefs; 112 struct config_defaults *defs; 113 114 struct area *conf_get_area(struct in_addr); 115 struct iface *conf_get_if(struct kif *, struct kif_addr *); 116 int conf_check_rdomain(unsigned int); 117 118 typedef struct { 119 union { 120 int64_t number; 121 char *string; 122 struct redistribute *redist; 123 struct in_addr id; 124 } v; 125 int lineno; 126 } YYSTYPE; 127 128 %} 129 130 %token AREA INTERFACE ROUTERID FIBPRIORITY FIBUPDATE REDISTRIBUTE RTLABEL 131 %token RDOMAIN RFC1583COMPAT STUB ROUTER SPFDELAY SPFHOLDTIME EXTTAG 132 %token AUTHKEY AUTHTYPE AUTHMD AUTHMDKEYID 133 %token METRIC P2P PASSIVE 134 %token HELLOINTERVAL FASTHELLOINTERVAL TRANSMITDELAY 135 %token RETRANSMITINTERVAL ROUTERDEADTIME ROUTERPRIORITY 136 %token SET TYPE 137 %token YES NO 138 %token MSEC MINIMAL 139 %token DEMOTE 140 %token INCLUDE 141 %token ERROR 142 %token DEPEND ON 143 %token <v.string> STRING 144 %token <v.number> NUMBER 145 %type <v.number> yesno no optlist optlist_l option demotecount msec 146 %type <v.number> deadtime 147 %type <v.string> string dependon dependonopt 148 %type <v.redist> redistribute 149 %type <v.id> areaid 150 151 %% 152 153 grammar : /* empty */ 154 | grammar include '\n' 155 | grammar '\n' 156 | grammar conf_main '\n' 157 | grammar varset '\n' 158 | grammar area '\n' 159 | grammar error '\n' { file->errors++; } 160 ; 161 162 include : INCLUDE STRING { 163 struct file *nfile; 164 165 if ((nfile = pushfile($2, 166 !(conf->opts & OSPFD_OPT_NOACTION))) == NULL) { 167 yyerror("failed to include file %s", $2); 168 free($2); 169 YYERROR; 170 } 171 free($2); 172 173 file = nfile; 174 lungetc('\n'); 175 } 176 ; 177 178 string : string STRING { 179 if (asprintf(&$$, "%s %s", $1, $2) == -1) { 180 free($1); 181 free($2); 182 yyerror("string: asprintf"); 183 YYERROR; 184 } 185 free($1); 186 free($2); 187 } 188 | STRING 189 ; 190 191 yesno : YES { $$ = 1; } 192 | NO { $$ = 0; } 193 ; 194 195 no : /* empty */ { $$ = 0; } 196 | NO { $$ = 1; } 197 ; 198 199 msec : MSEC NUMBER { 200 $$ = $2; 201 } 202 | NUMBER { 203 $$ = $1 * 1000; 204 } 205 ; 206 207 varset : STRING '=' string { 208 char *s = $1; 209 if (conf->opts & OSPFD_OPT_VERBOSE) 210 printf("%s = \"%s\"\n", $1, $3); 211 while (*s++) { 212 if (isspace((unsigned char)*s)) { 213 yyerror("macro name cannot contain " 214 "whitespace"); 215 free($1); 216 free($3); 217 YYERROR; 218 } 219 } 220 if (symset($1, $3, 0) == -1) 221 fatal("cannot store variable"); 222 free($1); 223 free($3); 224 } 225 ; 226 227 conf_main : ROUTERID STRING { 228 if (!inet_aton($2, &conf->rtr_id)) { 229 yyerror("error parsing router-id"); 230 free($2); 231 YYERROR; 232 } 233 free($2); 234 } 235 | FIBPRIORITY NUMBER { 236 if ($2 <= RTP_NONE || $2 > RTP_MAX) { 237 yyerror("invalid fib-priority"); 238 YYERROR; 239 } 240 conf->fib_priority = $2; 241 } 242 | FIBUPDATE yesno { 243 if ($2 == 0) 244 conf->flags |= OSPFD_FLAG_NO_FIB_UPDATE; 245 else 246 conf->flags &= ~OSPFD_FLAG_NO_FIB_UPDATE; 247 } 248 | redistribute { 249 SIMPLEQ_INSERT_TAIL(&conf->redist_list, $1, entry); 250 conf->redistribute = 1; 251 } 252 | RTLABEL STRING EXTTAG NUMBER { 253 if ($4 < 0 || $4 > UINT_MAX) { 254 yyerror("invalid external route tag"); 255 free($2); 256 YYERROR; 257 } 258 rtlabel_tag(rtlabel_name2id($2), $4); 259 free($2); 260 } 261 | RDOMAIN NUMBER { 262 if ($2 < 0 || $2 > RT_TABLEID_MAX) { 263 yyerror("invalid rdomain"); 264 YYERROR; 265 } 266 conf->rdomain = $2; 267 } 268 | RFC1583COMPAT yesno { 269 conf->rfc1583compat = $2; 270 } 271 | SPFDELAY msec { 272 if ($2 < MIN_SPF_DELAY || $2 > MAX_SPF_DELAY) { 273 yyerror("spf-delay out of range " 274 "(%d-%d)", MIN_SPF_DELAY, 275 MAX_SPF_DELAY); 276 YYERROR; 277 } 278 conf->spf_delay = $2; 279 } 280 | SPFHOLDTIME msec { 281 if ($2 < MIN_SPF_HOLDTIME || $2 > MAX_SPF_HOLDTIME) { 282 yyerror("spf-holdtime out of range " 283 "(%d-%d)", MIN_SPF_HOLDTIME, 284 MAX_SPF_HOLDTIME); 285 YYERROR; 286 } 287 conf->spf_hold_time = $2; 288 } 289 | STUB ROUTER yesno { 290 if ($3) 291 conf->flags |= OSPFD_FLAG_STUB_ROUTER; 292 else 293 /* allow to force non stub mode */ 294 conf->flags &= ~OSPFD_FLAG_STUB_ROUTER; 295 } 296 | defaults 297 ; 298 299 300 redistribute : no REDISTRIBUTE NUMBER '/' NUMBER optlist dependonopt { 301 struct redistribute *r; 302 303 if ((r = calloc(1, sizeof(*r))) == NULL) 304 fatal(NULL); 305 r->type = REDIST_ADDR; 306 if ($3 < 0 || $3 > 255 || $5 < 1 || $5 > 32) { 307 yyerror("bad network: %llu/%llu", $3, $5); 308 free(r); 309 YYERROR; 310 } 311 r->addr.s_addr = htonl($3 << IN_CLASSA_NSHIFT); 312 r->mask.s_addr = prefixlen2mask($5); 313 314 if ($1) 315 r->type |= REDIST_NO; 316 else 317 conf->redist_label_or_prefix = 1; 318 r->metric = $6; 319 if ($7) 320 strlcpy(r->dependon, $7, sizeof(r->dependon)); 321 else 322 r->dependon[0] = '\0'; 323 free($7); 324 $$ = r; 325 } 326 | no REDISTRIBUTE STRING optlist dependonopt { 327 struct redistribute *r; 328 329 if ((r = calloc(1, sizeof(*r))) == NULL) 330 fatal(NULL); 331 if (!strcmp($3, "default")) 332 r->type = REDIST_DEFAULT; 333 else if (!strcmp($3, "static")) 334 r->type = REDIST_STATIC; 335 else if (!strcmp($3, "connected")) 336 r->type = REDIST_CONNECTED; 337 else if (host($3, &r->addr, &r->mask)) { 338 r->type = REDIST_ADDR; 339 conf->redist_label_or_prefix = !$1; 340 } else { 341 yyerror("unknown redistribute type"); 342 free($3); 343 free(r); 344 YYERROR; 345 } 346 347 if ($1) 348 r->type |= REDIST_NO; 349 r->metric = $4; 350 if ($5) 351 strlcpy(r->dependon, $5, sizeof(r->dependon)); 352 else 353 r->dependon[0] = '\0'; 354 free($3); 355 free($5); 356 $$ = r; 357 } 358 | no REDISTRIBUTE RTLABEL STRING optlist dependonopt { 359 struct redistribute *r; 360 361 if ((r = calloc(1, sizeof(*r))) == NULL) 362 fatal(NULL); 363 r->type = REDIST_LABEL; 364 r->label = rtlabel_name2id($4); 365 if ($1) 366 r->type |= REDIST_NO; 367 else 368 conf->redist_label_or_prefix = 1; 369 r->metric = $5; 370 if ($6) 371 strlcpy(r->dependon, $6, sizeof(r->dependon)); 372 else 373 r->dependon[0] = '\0'; 374 free($4); 375 free($6); 376 $$ = r; 377 } 378 ; 379 380 optlist : /* empty */ { $$ = DEFAULT_REDIST_METRIC; } 381 | SET option { 382 $$ = $2; 383 if (($$ & LSA_METRIC_MASK) == 0) 384 $$ |= DEFAULT_REDIST_METRIC; 385 } 386 | SET optnl '{' optnl optlist_l optnl '}' { 387 $$ = $5; 388 if (($$ & LSA_METRIC_MASK) == 0) 389 $$ |= DEFAULT_REDIST_METRIC; 390 } 391 ; 392 393 optlist_l : optlist_l comma option { 394 if ($1 & LSA_ASEXT_E_FLAG && $3 & LSA_ASEXT_E_FLAG) { 395 yyerror("redistribute type already defined"); 396 YYERROR; 397 } 398 if ($1 & LSA_METRIC_MASK && $3 & LSA_METRIC_MASK) { 399 yyerror("redistribute metric already defined"); 400 YYERROR; 401 } 402 $$ = $1 | $3; 403 } 404 | option { $$ = $1; } 405 ; 406 407 option : METRIC NUMBER { 408 if ($2 == 0 || $2 > MAX_METRIC) { 409 yyerror("invalid redistribute metric"); 410 YYERROR; 411 } 412 $$ = $2; 413 } 414 | TYPE NUMBER { 415 switch ($2) { 416 case 1: 417 $$ = 0; 418 break; 419 case 2: 420 $$ = LSA_ASEXT_E_FLAG; 421 break; 422 default: 423 yyerror("only external type 1 and 2 allowed"); 424 YYERROR; 425 } 426 } 427 ; 428 429 dependonopt : /* empty */ { $$ = NULL; } 430 | dependon 431 432 dependon : DEPEND ON STRING { 433 struct in_addr addr; 434 struct kif *kif; 435 436 if (strlen($3) >= IFNAMSIZ) { 437 yyerror("interface name %s too long", $3); 438 free($3); 439 YYERROR; 440 } 441 bzero(&addr, sizeof(addr)); 442 if ((kif = kif_findname($3, addr, NULL)) == NULL) { 443 yyerror("unknown interface %s", $3); 444 free($3); 445 YYERROR; 446 } 447 $$ = $3; 448 } 449 ; 450 451 authmd : AUTHMD NUMBER STRING { 452 if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) { 453 yyerror("auth-md key-id out of range " 454 "(%d-%d)", MIN_MD_ID, MAX_MD_ID); 455 free($3); 456 YYERROR; 457 } 458 if (strlen($3) > MD5_DIGEST_LENGTH) { 459 yyerror("auth-md key length out of range " 460 "(max length %d)", 461 MD5_DIGEST_LENGTH); 462 free($3); 463 YYERROR; 464 } 465 md_list_add(&defs->md_list, $2, $3); 466 free($3); 467 } 468 469 authmdkeyid : AUTHMDKEYID NUMBER { 470 if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) { 471 yyerror("auth-md-keyid out of range " 472 "(%d-%d)", MIN_MD_ID, MAX_MD_ID); 473 YYERROR; 474 } 475 defs->auth_keyid = $2; 476 } 477 478 authtype : AUTHTYPE STRING { 479 enum auth_type type; 480 481 if (!strcmp($2, "none")) 482 type = AUTH_NONE; 483 else if (!strcmp($2, "simple")) 484 type = AUTH_SIMPLE; 485 else if (!strcmp($2, "crypt")) 486 type = AUTH_CRYPT; 487 else { 488 yyerror("unknown auth-type"); 489 free($2); 490 YYERROR; 491 } 492 free($2); 493 defs->auth_type = type; 494 } 495 ; 496 497 authkey : AUTHKEY STRING { 498 if (strlen($2) > MAX_SIMPLE_AUTH_LEN) { 499 yyerror("auth-key too long (max length %d)", 500 MAX_SIMPLE_AUTH_LEN); 501 free($2); 502 YYERROR; 503 } 504 strncpy(defs->auth_key, $2, 505 sizeof(defs->auth_key)); 506 free($2); 507 } 508 ; 509 510 defaults : METRIC NUMBER { 511 if ($2 < MIN_METRIC || $2 > MAX_METRIC) { 512 yyerror("metric out of range (%d-%d)", 513 MIN_METRIC, MAX_METRIC); 514 YYERROR; 515 } 516 defs->metric = $2; 517 } 518 | ROUTERPRIORITY NUMBER { 519 if ($2 < MIN_PRIORITY || $2 > MAX_PRIORITY) { 520 yyerror("router-priority out of range (%d-%d)", 521 MIN_PRIORITY, MAX_PRIORITY); 522 YYERROR; 523 } 524 defs->priority = $2; 525 } 526 | ROUTERDEADTIME deadtime { 527 defs->dead_interval = $2; 528 } 529 | TRANSMITDELAY NUMBER { 530 if ($2 < MIN_TRANSMIT_DELAY || 531 $2 > MAX_TRANSMIT_DELAY) { 532 yyerror("transmit-delay out of range (%d-%d)", 533 MIN_TRANSMIT_DELAY, MAX_TRANSMIT_DELAY); 534 YYERROR; 535 } 536 defs->transmit_delay = $2; 537 } 538 | HELLOINTERVAL NUMBER { 539 if ($2 < MIN_HELLO_INTERVAL || 540 $2 > MAX_HELLO_INTERVAL) { 541 yyerror("hello-interval out of range (%d-%d)", 542 MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL); 543 YYERROR; 544 } 545 defs->hello_interval = $2; 546 } 547 | FASTHELLOINTERVAL MSEC NUMBER { 548 if ($3 < MIN_FAST_INTERVAL || 549 $3 > MAX_FAST_INTERVAL) { 550 yyerror("fast-hello-interval msec out of " 551 "range (%d-%d)", MIN_FAST_INTERVAL, 552 MAX_FAST_INTERVAL); 553 YYERROR; 554 } 555 defs->fast_hello_interval = $3; 556 } 557 | RETRANSMITINTERVAL NUMBER { 558 if ($2 < MIN_RXMT_INTERVAL || $2 > MAX_RXMT_INTERVAL) { 559 yyerror("retransmit-interval out of range " 560 "(%d-%d)", MIN_RXMT_INTERVAL, 561 MAX_RXMT_INTERVAL); 562 YYERROR; 563 } 564 defs->rxmt_interval = $2; 565 } 566 | TYPE P2P { 567 defs->p2p = 1; 568 } 569 | authtype 570 | authkey 571 | authmdkeyid 572 | authmd 573 ; 574 575 deadtime : NUMBER { 576 if ($1 < MIN_RTR_DEAD_TIME || $1 > MAX_RTR_DEAD_TIME) { 577 yyerror("router-dead-time out of range (%d-%d)", 578 MIN_RTR_DEAD_TIME, MAX_RTR_DEAD_TIME); 579 YYERROR; 580 } 581 $$ = $1; 582 } 583 | MINIMAL { 584 $$ = FAST_RTR_DEAD_TIME; 585 } 586 587 optnl : '\n' optnl 588 | 589 ; 590 591 nl : '\n' optnl /* one newline or more */ 592 ; 593 594 comma : ',' 595 | /*empty*/ 596 ; 597 598 area : AREA areaid { 599 area = conf_get_area($2); 600 601 memcpy(&areadefs, defs, sizeof(areadefs)); 602 md_list_copy(&areadefs.md_list, &defs->md_list); 603 defs = &areadefs; 604 } '{' optnl areaopts_l optnl '}' { 605 area = NULL; 606 md_list_clr(&defs->md_list); 607 defs = &globaldefs; 608 } 609 ; 610 611 demotecount : NUMBER { $$ = $1; } 612 | /*empty*/ { $$ = 1; } 613 ; 614 615 areaid : NUMBER { 616 if ($1 < 0 || $1 > 0xffffffff) { 617 yyerror("invalid area id"); 618 YYERROR; 619 } 620 $$.s_addr = htonl($1); 621 } 622 | STRING { 623 if (inet_aton($1, &$$) == 0) { 624 yyerror("error parsing area"); 625 free($1); 626 YYERROR; 627 } 628 free($1); 629 } 630 ; 631 632 areaopts_l : areaopts_l nl areaoptsl 633 | areaoptsl 634 ; 635 636 areaoptsl : interface 637 | DEMOTE STRING demotecount { 638 if ($3 < 1 || $3 > 255) { 639 yyerror("demote count out of range (1-255)"); 640 free($2); 641 YYERROR; 642 } 643 area->demote_level = $3; 644 if (strlcpy(area->demote_group, $2, 645 sizeof(area->demote_group)) >= 646 sizeof(area->demote_group)) { 647 yyerror("demote group name \"%s\" too long", 648 $2); 649 free($2); 650 YYERROR; 651 } 652 free($2); 653 if (carp_demote_init(area->demote_group, 654 conf->opts & OSPFD_OPT_FORCE_DEMOTE) == -1) { 655 yyerror("error initializing group \"%s\"", 656 area->demote_group); 657 YYERROR; 658 } 659 } 660 | defaults 661 | STUB { area->stub = 1; } 662 | STUB redistribute { 663 area->stub = 1; 664 if ($2->type != REDIST_DEFAULT) { 665 yyerror("bad redistribute option"); 666 YYERROR; 667 } 668 if (!SIMPLEQ_EMPTY(&area->redist_list)) { 669 yyerror("area redistribute option only " 670 "allowed once"); 671 YYERROR; 672 } 673 SIMPLEQ_INSERT_TAIL(&area->redist_list, $2, entry); 674 } 675 ; 676 677 interface : INTERFACE STRING { 678 struct kif *kif; 679 struct kif_addr *ka = NULL; 680 char *s; 681 struct in_addr addr; 682 683 s = strchr($2, ':'); 684 if (s) { 685 *s++ = '\0'; 686 if (inet_aton(s, &addr) == 0) { 687 yyerror( 688 "error parsing interface address"); 689 free($2); 690 YYERROR; 691 } 692 } else 693 addr.s_addr = 0; 694 695 if ((kif = kif_findname($2, addr, &ka)) == NULL) { 696 yyerror("unknown interface %s", $2); 697 free($2); 698 YYERROR; 699 } 700 if (ka == NULL) { 701 if (s) 702 yyerror("address %s not configured on " 703 "interface %s", s, $2); 704 else 705 yyerror("unnumbered interface %s", $2); 706 free($2); 707 YYERROR; 708 } 709 free($2); 710 iface = conf_get_if(kif, ka); 711 if (iface == NULL) 712 YYERROR; 713 iface->area = area; 714 LIST_INSERT_HEAD(&area->iface_list, iface, entry); 715 716 memcpy(&ifacedefs, defs, sizeof(ifacedefs)); 717 md_list_copy(&ifacedefs.md_list, &defs->md_list); 718 defs = &ifacedefs; 719 } interface_block { 720 iface->dead_interval = defs->dead_interval; 721 iface->fast_hello_interval = defs->fast_hello_interval; 722 iface->transmit_delay = defs->transmit_delay; 723 if (iface->dead_interval == FAST_RTR_DEAD_TIME) 724 iface->hello_interval = 0; 725 else 726 iface->hello_interval = defs->hello_interval; 727 iface->rxmt_interval = defs->rxmt_interval; 728 iface->metric = defs->metric; 729 iface->priority = defs->priority; 730 iface->auth_type = defs->auth_type; 731 iface->auth_keyid = defs->auth_keyid; 732 if (defs->p2p == 1) 733 iface->type = IF_TYPE_POINTOPOINT; 734 memcpy(iface->auth_key, defs->auth_key, 735 sizeof(iface->auth_key)); 736 md_list_copy(&iface->auth_md_list, &defs->md_list); 737 md_list_clr(&defs->md_list); 738 iface = NULL; 739 /* interface is always part of an area */ 740 defs = &areadefs; 741 } 742 ; 743 744 interface_block : '{' optnl interfaceopts_l optnl '}' 745 | '{' optnl '}' 746 | /* empty */ 747 ; 748 749 interfaceopts_l : interfaceopts_l nl interfaceoptsl 750 | interfaceoptsl 751 ; 752 753 interfaceoptsl : PASSIVE { iface->passive = 1; } 754 | DEMOTE STRING { 755 if (strlcpy(iface->demote_group, $2, 756 sizeof(iface->demote_group)) >= 757 sizeof(iface->demote_group)) { 758 yyerror("demote group name \"%s\" too long", 759 $2); 760 free($2); 761 YYERROR; 762 } 763 free($2); 764 if (carp_demote_init(iface->demote_group, 765 conf->opts & OSPFD_OPT_FORCE_DEMOTE) == -1) { 766 yyerror("error initializing group \"%s\"", 767 iface->demote_group); 768 YYERROR; 769 } 770 } 771 | dependon { 772 struct in_addr addr; 773 struct kif *kif; 774 775 if ($1) { 776 strlcpy(iface->dependon, $1, 777 sizeof(iface->dependon)); 778 bzero(&addr, sizeof(addr)); 779 kif = kif_findname($1, addr, NULL); 780 iface->depend_ok = ifstate_is_up(kif); 781 } else { 782 iface->dependon[0] = '\0'; 783 iface->depend_ok = 1; 784 } 785 786 free($1); 787 } 788 | defaults 789 ; 790 791 %% 792 793 struct keywords { 794 const char *k_name; 795 int k_val; 796 }; 797 798 int 799 yyerror(const char *fmt, ...) 800 { 801 va_list ap; 802 char *msg; 803 804 file->errors++; 805 va_start(ap, fmt); 806 if (vasprintf(&msg, fmt, ap) == -1) 807 fatalx("yyerror vasprintf"); 808 va_end(ap); 809 logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); 810 free(msg); 811 return (0); 812 } 813 814 int 815 kw_cmp(const void *k, const void *e) 816 { 817 return (strcmp(k, ((const struct keywords *)e)->k_name)); 818 } 819 820 int 821 lookup(char *s) 822 { 823 /* this has to be sorted always */ 824 static const struct keywords keywords[] = { 825 {"area", AREA}, 826 {"auth-key", AUTHKEY}, 827 {"auth-md", AUTHMD}, 828 {"auth-md-keyid", AUTHMDKEYID}, 829 {"auth-type", AUTHTYPE}, 830 {"demote", DEMOTE}, 831 {"depend", DEPEND}, 832 {"external-tag", EXTTAG}, 833 {"fast-hello-interval", FASTHELLOINTERVAL}, 834 {"fib-priority", FIBPRIORITY}, 835 {"fib-update", FIBUPDATE}, 836 {"hello-interval", HELLOINTERVAL}, 837 {"include", INCLUDE}, 838 {"interface", INTERFACE}, 839 {"metric", METRIC}, 840 {"minimal", MINIMAL}, 841 {"msec", MSEC}, 842 {"no", NO}, 843 {"on", ON}, 844 {"p2p", P2P}, 845 {"passive", PASSIVE}, 846 {"rdomain", RDOMAIN}, 847 {"redistribute", REDISTRIBUTE}, 848 {"retransmit-interval", RETRANSMITINTERVAL}, 849 {"rfc1583compat", RFC1583COMPAT}, 850 {"router", ROUTER}, 851 {"router-dead-time", ROUTERDEADTIME}, 852 {"router-id", ROUTERID}, 853 {"router-priority", ROUTERPRIORITY}, 854 {"rtlabel", RTLABEL}, 855 {"set", SET}, 856 {"spf-delay", SPFDELAY}, 857 {"spf-holdtime", SPFHOLDTIME}, 858 {"stub", STUB}, 859 {"transmit-delay", TRANSMITDELAY}, 860 {"type", TYPE}, 861 {"yes", YES} 862 }; 863 const struct keywords *p; 864 865 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 866 sizeof(keywords[0]), kw_cmp); 867 868 if (p) 869 return (p->k_val); 870 else 871 return (STRING); 872 } 873 874 #define START_EXPAND 1 875 #define DONE_EXPAND 2 876 877 static int expanding; 878 879 int 880 igetc(void) 881 { 882 int c; 883 884 while (1) { 885 if (file->ungetpos > 0) 886 c = file->ungetbuf[--file->ungetpos]; 887 else 888 c = getc(file->stream); 889 890 if (c == START_EXPAND) 891 expanding = 1; 892 else if (c == DONE_EXPAND) 893 expanding = 0; 894 else 895 break; 896 } 897 return (c); 898 } 899 900 int 901 lgetc(int quotec) 902 { 903 int c, next; 904 905 if (quotec) { 906 if ((c = igetc()) == EOF) { 907 yyerror("reached end of file while parsing " 908 "quoted string"); 909 if (file == topfile || popfile() == EOF) 910 return (EOF); 911 return (quotec); 912 } 913 return (c); 914 } 915 916 while ((c = igetc()) == '\\') { 917 next = igetc(); 918 if (next != '\n') { 919 c = next; 920 break; 921 } 922 yylval.lineno = file->lineno; 923 file->lineno++; 924 } 925 926 if (c == EOF) { 927 /* 928 * Fake EOL when hit EOF for the first time. This gets line 929 * count right if last line in included file is syntactically 930 * invalid and has no newline. 931 */ 932 if (file->eof_reached == 0) { 933 file->eof_reached = 1; 934 return ('\n'); 935 } 936 while (c == EOF) { 937 if (file == topfile || popfile() == EOF) 938 return (EOF); 939 c = igetc(); 940 } 941 } 942 return (c); 943 } 944 945 void 946 lungetc(int c) 947 { 948 if (c == EOF) 949 return; 950 951 if (file->ungetpos >= file->ungetsize) { 952 void *p = reallocarray(file->ungetbuf, file->ungetsize, 2); 953 if (p == NULL) 954 err(1, "%s", __func__); 955 file->ungetbuf = p; 956 file->ungetsize *= 2; 957 } 958 file->ungetbuf[file->ungetpos++] = c; 959 } 960 961 int 962 findeol(void) 963 { 964 int c; 965 966 /* skip to either EOF or the first real EOL */ 967 while (1) { 968 c = lgetc(0); 969 if (c == '\n') { 970 file->lineno++; 971 break; 972 } 973 if (c == EOF) 974 break; 975 } 976 return (ERROR); 977 } 978 979 int 980 yylex(void) 981 { 982 char buf[8096]; 983 char *p, *val; 984 int quotec, next, c; 985 int token; 986 987 top: 988 p = buf; 989 while ((c = lgetc(0)) == ' ' || c == '\t') 990 ; /* nothing */ 991 992 yylval.lineno = file->lineno; 993 if (c == '#') 994 while ((c = lgetc(0)) != '\n' && c != EOF) 995 ; /* nothing */ 996 if (c == '$' && !expanding) { 997 while (1) { 998 if ((c = lgetc(0)) == EOF) 999 return (0); 1000 1001 if (p + 1 >= buf + sizeof(buf) - 1) { 1002 yyerror("string too long"); 1003 return (findeol()); 1004 } 1005 if (isalnum(c) || c == '_') { 1006 *p++ = c; 1007 continue; 1008 } 1009 *p = '\0'; 1010 lungetc(c); 1011 break; 1012 } 1013 val = symget(buf); 1014 if (val == NULL) { 1015 yyerror("macro '%s' not defined", buf); 1016 return (findeol()); 1017 } 1018 p = val + strlen(val) - 1; 1019 lungetc(DONE_EXPAND); 1020 while (p >= val) { 1021 lungetc((unsigned char)*p); 1022 p--; 1023 } 1024 lungetc(START_EXPAND); 1025 goto top; 1026 } 1027 1028 switch (c) { 1029 case '\'': 1030 case '"': 1031 quotec = c; 1032 while (1) { 1033 if ((c = lgetc(quotec)) == EOF) 1034 return (0); 1035 if (c == '\n') { 1036 file->lineno++; 1037 continue; 1038 } else if (c == '\\') { 1039 if ((next = lgetc(quotec)) == EOF) 1040 return (0); 1041 if (next == quotec || next == ' ' || 1042 next == '\t') 1043 c = next; 1044 else if (next == '\n') { 1045 file->lineno++; 1046 continue; 1047 } else 1048 lungetc(next); 1049 } else if (c == quotec) { 1050 *p = '\0'; 1051 break; 1052 } else if (c == '\0') { 1053 yyerror("syntax error"); 1054 return (findeol()); 1055 } 1056 if (p + 1 >= buf + sizeof(buf) - 1) { 1057 yyerror("string too long"); 1058 return (findeol()); 1059 } 1060 *p++ = c; 1061 } 1062 yylval.v.string = strdup(buf); 1063 if (yylval.v.string == NULL) 1064 err(1, "%s", __func__); 1065 return (STRING); 1066 } 1067 1068 #define allowed_to_end_number(x) \ 1069 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 1070 1071 if (c == '-' || isdigit(c)) { 1072 do { 1073 *p++ = c; 1074 if ((size_t)(p-buf) >= sizeof(buf)) { 1075 yyerror("string too long"); 1076 return (findeol()); 1077 } 1078 } while ((c = lgetc(0)) != EOF && isdigit(c)); 1079 lungetc(c); 1080 if (p == buf + 1 && buf[0] == '-') 1081 goto nodigits; 1082 if (c == EOF || allowed_to_end_number(c)) { 1083 const char *errstr = NULL; 1084 1085 *p = '\0'; 1086 yylval.v.number = strtonum(buf, LLONG_MIN, 1087 LLONG_MAX, &errstr); 1088 if (errstr) { 1089 yyerror("\"%s\" invalid number: %s", 1090 buf, errstr); 1091 return (findeol()); 1092 } 1093 return (NUMBER); 1094 } else { 1095 nodigits: 1096 while (p > buf + 1) 1097 lungetc((unsigned char)*--p); 1098 c = (unsigned char)*--p; 1099 if (c == '-') 1100 return (c); 1101 } 1102 } 1103 1104 #define allowed_in_string(x) \ 1105 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 1106 x != '{' && x != '}' && \ 1107 x != '!' && x != '=' && x != '#' && \ 1108 x != ',')) 1109 1110 if (isalnum(c) || c == ':' || c == '_') { 1111 do { 1112 *p++ = c; 1113 if ((size_t)(p-buf) >= sizeof(buf)) { 1114 yyerror("string too long"); 1115 return (findeol()); 1116 } 1117 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 1118 lungetc(c); 1119 *p = '\0'; 1120 if ((token = lookup(buf)) == STRING) 1121 if ((yylval.v.string = strdup(buf)) == NULL) 1122 err(1, "%s", __func__); 1123 return (token); 1124 } 1125 if (c == '\n') { 1126 yylval.lineno = file->lineno; 1127 file->lineno++; 1128 } 1129 if (c == EOF) 1130 return (0); 1131 return (c); 1132 } 1133 1134 int 1135 check_file_secrecy(int fd, const char *fname) 1136 { 1137 struct stat st; 1138 1139 if (fstat(fd, &st)) { 1140 log_warn("cannot stat %s", fname); 1141 return (-1); 1142 } 1143 if (st.st_uid != 0 && st.st_uid != getuid()) { 1144 log_warnx("%s: owner not root or current user", fname); 1145 return (-1); 1146 } 1147 if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { 1148 log_warnx("%s: group writable or world read/writable", fname); 1149 return (-1); 1150 } 1151 return (0); 1152 } 1153 1154 struct file * 1155 pushfile(const char *name, int secret) 1156 { 1157 struct file *nfile; 1158 1159 if ((nfile = calloc(1, sizeof(struct file))) == NULL) { 1160 log_warn("%s", __func__); 1161 return (NULL); 1162 } 1163 if ((nfile->name = strdup(name)) == NULL) { 1164 log_warn("%s", __func__); 1165 free(nfile); 1166 return (NULL); 1167 } 1168 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 1169 log_warn("%s: %s", __func__, nfile->name); 1170 free(nfile->name); 1171 free(nfile); 1172 return (NULL); 1173 } else if (secret && 1174 check_file_secrecy(fileno(nfile->stream), nfile->name)) { 1175 fclose(nfile->stream); 1176 free(nfile->name); 1177 free(nfile); 1178 return (NULL); 1179 } 1180 nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0; 1181 nfile->ungetsize = 16; 1182 nfile->ungetbuf = malloc(nfile->ungetsize); 1183 if (nfile->ungetbuf == NULL) { 1184 log_warn("%s", __func__); 1185 fclose(nfile->stream); 1186 free(nfile->name); 1187 free(nfile); 1188 return (NULL); 1189 } 1190 TAILQ_INSERT_TAIL(&files, nfile, entry); 1191 return (nfile); 1192 } 1193 1194 int 1195 popfile(void) 1196 { 1197 struct file *prev; 1198 1199 if ((prev = TAILQ_PREV(file, files, entry)) != NULL) 1200 prev->errors += file->errors; 1201 1202 TAILQ_REMOVE(&files, file, entry); 1203 fclose(file->stream); 1204 free(file->name); 1205 free(file->ungetbuf); 1206 free(file); 1207 file = prev; 1208 return (file ? 0 : EOF); 1209 } 1210 1211 struct ospfd_conf * 1212 parse_config(char *filename, int opts) 1213 { 1214 struct sym *sym, *next; 1215 1216 if ((conf = calloc(1, sizeof(struct ospfd_conf))) == NULL) 1217 fatal("parse_config"); 1218 conf->opts = opts; 1219 if (conf->opts & OSPFD_OPT_STUB_ROUTER) 1220 conf->flags |= OSPFD_FLAG_STUB_ROUTER; 1221 1222 bzero(&globaldefs, sizeof(globaldefs)); 1223 defs = &globaldefs; 1224 TAILQ_INIT(&defs->md_list); 1225 defs->dead_interval = DEFAULT_RTR_DEAD_TIME; 1226 defs->fast_hello_interval = DEFAULT_FAST_INTERVAL; 1227 defs->transmit_delay = DEFAULT_TRANSMIT_DELAY; 1228 defs->hello_interval = DEFAULT_HELLO_INTERVAL; 1229 defs->rxmt_interval = DEFAULT_RXMT_INTERVAL; 1230 defs->metric = DEFAULT_METRIC; 1231 defs->priority = DEFAULT_PRIORITY; 1232 defs->p2p = 0; 1233 1234 conf->spf_delay = DEFAULT_SPF_DELAY; 1235 conf->spf_hold_time = DEFAULT_SPF_HOLDTIME; 1236 conf->spf_state = SPF_IDLE; 1237 conf->fib_priority = RTP_OSPF; 1238 1239 if ((file = pushfile(filename, 1240 !(conf->opts & OSPFD_OPT_NOACTION))) == NULL) { 1241 free(conf); 1242 return (NULL); 1243 } 1244 topfile = file; 1245 1246 LIST_INIT(&conf->area_list); 1247 LIST_INIT(&conf->cand_list); 1248 SIMPLEQ_INIT(&conf->redist_list); 1249 1250 yyparse(); 1251 errors = file->errors; 1252 popfile(); 1253 1254 /* Free macros and check which have not been used. */ 1255 TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { 1256 if ((conf->opts & OSPFD_OPT_VERBOSE2) && !sym->used) 1257 fprintf(stderr, "warning: macro '%s' not " 1258 "used\n", sym->nam); 1259 if (!sym->persist) { 1260 free(sym->nam); 1261 free(sym->val); 1262 TAILQ_REMOVE(&symhead, sym, entry); 1263 free(sym); 1264 } 1265 } 1266 1267 /* free global config defaults */ 1268 md_list_clr(&globaldefs.md_list); 1269 1270 /* check that all interfaces belong to the configured rdomain */ 1271 errors += conf_check_rdomain(conf->rdomain); 1272 1273 if (errors) { 1274 clear_config(conf); 1275 return (NULL); 1276 } 1277 1278 return (conf); 1279 } 1280 1281 int 1282 symset(const char *nam, const char *val, int persist) 1283 { 1284 struct sym *sym; 1285 1286 TAILQ_FOREACH(sym, &symhead, entry) { 1287 if (strcmp(nam, sym->nam) == 0) 1288 break; 1289 } 1290 1291 if (sym != NULL) { 1292 if (sym->persist == 1) 1293 return (0); 1294 else { 1295 free(sym->nam); 1296 free(sym->val); 1297 TAILQ_REMOVE(&symhead, sym, entry); 1298 free(sym); 1299 } 1300 } 1301 if ((sym = calloc(1, sizeof(*sym))) == NULL) 1302 return (-1); 1303 1304 sym->nam = strdup(nam); 1305 if (sym->nam == NULL) { 1306 free(sym); 1307 return (-1); 1308 } 1309 sym->val = strdup(val); 1310 if (sym->val == NULL) { 1311 free(sym->nam); 1312 free(sym); 1313 return (-1); 1314 } 1315 sym->used = 0; 1316 sym->persist = persist; 1317 TAILQ_INSERT_TAIL(&symhead, sym, entry); 1318 return (0); 1319 } 1320 1321 int 1322 cmdline_symset(char *s) 1323 { 1324 char *sym, *val; 1325 int ret; 1326 1327 if ((val = strrchr(s, '=')) == NULL) 1328 return (-1); 1329 sym = strndup(s, val - s); 1330 if (sym == NULL) 1331 errx(1, "%s: strndup", __func__); 1332 ret = symset(sym, val + 1, 1); 1333 free(sym); 1334 1335 return (ret); 1336 } 1337 1338 char * 1339 symget(const char *nam) 1340 { 1341 struct sym *sym; 1342 1343 TAILQ_FOREACH(sym, &symhead, entry) { 1344 if (strcmp(nam, sym->nam) == 0) { 1345 sym->used = 1; 1346 return (sym->val); 1347 } 1348 } 1349 return (NULL); 1350 } 1351 1352 struct area * 1353 conf_get_area(struct in_addr id) 1354 { 1355 struct area *a; 1356 1357 a = area_find(conf, id); 1358 if (a) 1359 return (a); 1360 a = area_new(); 1361 LIST_INSERT_HEAD(&conf->area_list, a, entry); 1362 1363 a->id.s_addr = id.s_addr; 1364 1365 return (a); 1366 } 1367 1368 struct iface * 1369 conf_get_if(struct kif *kif, struct kif_addr *ka) 1370 { 1371 struct area *a; 1372 struct iface *i; 1373 1374 LIST_FOREACH(a, &conf->area_list, entry) 1375 LIST_FOREACH(i, &a->iface_list, entry) 1376 if (i->ifindex == kif->ifindex && 1377 i->addr.s_addr == ka->addr.s_addr) { 1378 yyerror("interface %s already configured", 1379 kif->ifname); 1380 return (NULL); 1381 } 1382 1383 i = if_new(kif, ka); 1384 i->auth_keyid = 1; 1385 1386 return (i); 1387 } 1388 1389 int 1390 conf_check_rdomain(unsigned int rdomain) 1391 { 1392 struct area *a; 1393 struct iface *i; 1394 struct in_addr addr; 1395 struct kif *kif; 1396 struct redistribute *r; 1397 int errs = 0; 1398 1399 SIMPLEQ_FOREACH(r, &conf->redist_list, entry) 1400 if (r->dependon[0] != '\0') { 1401 bzero(&addr, sizeof(addr)); 1402 kif = kif_findname(r->dependon, addr, NULL); 1403 if (kif->rdomain != rdomain) { 1404 logit(LOG_CRIT, 1405 "depend on %s: interface not in rdomain %u", 1406 kif->ifname, rdomain); 1407 errs++; 1408 } 1409 } 1410 1411 LIST_FOREACH(a, &conf->area_list, entry) 1412 LIST_FOREACH(i, &a->iface_list, entry) { 1413 if (i->rdomain != rdomain) { 1414 logit(LOG_CRIT, 1415 "interface %s not in rdomain %u", 1416 i->name, rdomain); 1417 errs++; 1418 } 1419 if (i->dependon[0] != '\0') { 1420 bzero(&addr, sizeof(addr)); 1421 kif = kif_findname(i->dependon, addr, NULL); 1422 if (kif->rdomain != rdomain) { 1423 logit(LOG_CRIT, 1424 "depend on %s: interface not in " 1425 "rdomain %u", 1426 kif->ifname, rdomain); 1427 errs++; 1428 } 1429 } 1430 } 1431 1432 return (errs); 1433 } 1434 1435 void 1436 conf_clear_redist_list(struct redist_list *rl) 1437 { 1438 struct redistribute *r; 1439 while ((r = SIMPLEQ_FIRST(rl)) != NULL) { 1440 SIMPLEQ_REMOVE_HEAD(rl, entry); 1441 free(r); 1442 } 1443 } 1444 1445 void 1446 clear_config(struct ospfd_conf *xconf) 1447 { 1448 struct area *a; 1449 1450 while ((a = LIST_FIRST(&xconf->area_list)) != NULL) { 1451 LIST_REMOVE(a, entry); 1452 area_del(a); 1453 } 1454 1455 conf_clear_redist_list(&xconf->redist_list); 1456 1457 free(xconf); 1458 } 1459 1460 u_int32_t 1461 get_rtr_id(void) 1462 { 1463 struct ifaddrs *ifap, *ifa; 1464 u_int32_t ip = 0, cur, localnet; 1465 1466 localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET); 1467 1468 if (getifaddrs(&ifap) == -1) 1469 fatal("getifaddrs"); 1470 1471 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 1472 if (strncmp(ifa->ifa_name, "carp", 4) == 0) 1473 continue; 1474 if (ifa->ifa_addr == NULL || 1475 ifa->ifa_addr->sa_family != AF_INET) 1476 continue; 1477 cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; 1478 if ((cur & localnet) == localnet) /* skip 127/8 */ 1479 continue; 1480 if (ntohl(cur) < ntohl(ip) || ip == 0) 1481 ip = cur; 1482 } 1483 freeifaddrs(ifap); 1484 1485 if (ip == 0) 1486 fatal("router-id is 0.0.0.0"); 1487 1488 return (ip); 1489 } 1490 1491 int 1492 host(const char *s, struct in_addr *addr, struct in_addr *mask) 1493 { 1494 struct in_addr ina; 1495 int bits = 32; 1496 1497 bzero(&ina, sizeof(struct in_addr)); 1498 if (strrchr(s, '/') != NULL) { 1499 if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1) 1500 return (0); 1501 } else { 1502 if (inet_pton(AF_INET, s, &ina) != 1) 1503 return (0); 1504 } 1505 1506 addr->s_addr = ina.s_addr; 1507 mask->s_addr = prefixlen2mask(bits); 1508 1509 return (1); 1510 } 1511