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