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