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