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