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