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