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