1 /* $OpenBSD: parse.y,v 1.20 2014/01/22 00:21:16 henning Exp $ */ 2 3 /* 4 * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org> 5 * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org> 6 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> 7 * Copyright (c) 2001 Markus Friedl. All rights reserved. 8 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. 9 * Copyright (c) 2001 Theo de Raadt. All rights reserved. 10 * 11 * Permission to use, copy, modify, and distribute this software for any 12 * purpose with or without fee is hereby granted, provided that the above 13 * copyright notice and this permission notice appear in all copies. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 21 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 */ 23 24 %{ 25 #include <sys/types.h> 26 #include <sys/socket.h> 27 #include <sys/stat.h> 28 #include <netinet/in.h> 29 #include <arpa/inet.h> 30 #include <ctype.h> 31 #include <err.h> 32 #include <errno.h> 33 #include <unistd.h> 34 #include <ifaddrs.h> 35 #include <net/if_types.h> 36 #include <limits.h> 37 #include <stdarg.h> 38 #include <stdio.h> 39 #include <string.h> 40 #include <syslog.h> 41 42 #include "ldp.h" 43 #include "ldpd.h" 44 #include "ldpe.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 76 int symset(const char *, const char *, int); 77 char *symget(const char *); 78 79 void clear_config(struct ldpd_conf *xconf); 80 u_int32_t get_rtr_id(void); 81 int host(const char *, struct in_addr *, struct in_addr *); 82 83 static struct ldpd_conf *conf; 84 static int errors = 0; 85 86 struct iface *iface = NULL; 87 struct tnbr *tnbr = NULL; 88 89 struct config_defaults { 90 u_int16_t lhello_holdtime; 91 u_int16_t lhello_interval; 92 u_int16_t thello_holdtime; 93 u_int16_t thello_interval; 94 }; 95 96 struct config_defaults globaldefs; 97 struct config_defaults ifacedefs; 98 struct config_defaults tnbrdefs; 99 struct config_defaults *defs; 100 101 struct iface *conf_get_if(struct kif *); 102 struct tnbr *conf_get_tnbr(struct in_addr); 103 104 typedef struct { 105 union { 106 int64_t number; 107 char *string; 108 } v; 109 int lineno; 110 } YYSTYPE; 111 112 %} 113 114 %token INTERFACE TNEIGHBOR ROUTERID FIBUPDATE 115 %token LHELLOHOLDTIME LHELLOINTERVAL 116 %token THELLOHOLDTIME THELLOINTERVAL 117 %token THELLOACCEPT 118 %token KEEPALIVE 119 %token DISTRIBUTION RETENTION ADVERTISEMENT 120 %token EXTTAG 121 %token YES NO 122 %token ERROR 123 %token <v.string> STRING 124 %token <v.number> NUMBER 125 %type <v.number> yesno 126 %type <v.string> string 127 128 %% 129 130 grammar : /* empty */ 131 | grammar '\n' 132 | grammar conf_main '\n' 133 | grammar varset '\n' 134 | grammar interface '\n' 135 | grammar tneighbor '\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 varset : STRING '=' string { 157 if (conf->opts & LDPD_OPT_VERBOSE) 158 printf("%s = \"%s\"\n", $1, $3); 159 if (symset($1, $3, 0) == -1) 160 fatal("cannot store variable"); 161 free($1); 162 free($3); 163 } 164 ; 165 166 conf_main : ROUTERID STRING { 167 if (!inet_aton($2, &conf->rtr_id)) { 168 yyerror("error parsing router-id"); 169 free($2); 170 YYERROR; 171 } 172 free($2); 173 } 174 | FIBUPDATE yesno { 175 if ($2 == 0) 176 conf->flags |= LDPD_FLAG_NO_FIB_UPDATE; 177 else 178 conf->flags &= ~LDPD_FLAG_NO_FIB_UPDATE; 179 } 180 | DISTRIBUTION STRING { 181 conf->mode &= ~(MODE_DIST_INDEPENDENT | 182 MODE_DIST_ORDERED); 183 184 if (!strcmp($2, "independent")) 185 conf->mode |= MODE_DIST_INDEPENDENT; 186 else if (!strcmp($2, "ordered")) 187 conf->mode |= MODE_DIST_ORDERED; 188 else { 189 yyerror("unknown distribution type"); 190 free($2); 191 YYERROR; 192 } 193 } 194 | RETENTION STRING { 195 conf->mode &= ~(MODE_RET_CONSERVATIVE | 196 MODE_RET_LIBERAL); 197 198 if (!strcmp($2, "conservative")) 199 conf->mode |= MODE_RET_CONSERVATIVE; 200 else if (!strcmp($2, "liberal")) 201 conf->mode |= MODE_RET_LIBERAL; 202 else { 203 yyerror("unknown retention type"); 204 free($2); 205 YYERROR; 206 } 207 } 208 | ADVERTISEMENT STRING { 209 conf->mode &= ~(MODE_ADV_ONDEMAND | 210 MODE_ADV_UNSOLICITED); 211 212 if (!strcmp($2, "ondemand")) 213 conf->mode |= MODE_ADV_ONDEMAND; 214 else if (!strcmp($2, "unsolicited")) 215 conf->mode |= MODE_ADV_UNSOLICITED; 216 else { 217 yyerror("unknown retention type"); 218 free($2); 219 YYERROR; 220 } 221 } 222 | THELLOACCEPT yesno { 223 if ($2 == 0) 224 conf->flags &= ~LDPD_FLAG_TH_ACCEPT; 225 else 226 conf->flags |= LDPD_FLAG_TH_ACCEPT; 227 } 228 | KEEPALIVE NUMBER { 229 if ($2 < MIN_KEEPALIVE || 230 $2 > MAX_KEEPALIVE) { 231 yyerror("keepalive out of range (%d-%d)", 232 MIN_KEEPALIVE, MAX_KEEPALIVE); 233 YYERROR; 234 } 235 conf->keepalive = $2; 236 } 237 | iface_defaults 238 | tnbr_defaults 239 ; 240 iface_defaults : LHELLOHOLDTIME NUMBER { 241 if ($2 < MIN_HOLDTIME || 242 $2 > MAX_HOLDTIME) { 243 yyerror("hello holdtime out of range (%d-%d)", 244 MIN_HOLDTIME, MAX_HOLDTIME); 245 YYERROR; 246 } 247 defs->lhello_holdtime = $2; 248 } 249 | LHELLOINTERVAL NUMBER { 250 if ($2 < MIN_HELLO_INTERVAL || 251 $2 > MAX_HELLO_INTERVAL) { 252 yyerror("hello-interval out of range (%d-%d)", 253 MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL); 254 YYERROR; 255 } 256 defs->lhello_interval = $2; 257 } 258 ; 259 260 tnbr_defaults : THELLOHOLDTIME NUMBER { 261 if ($2 < MIN_HOLDTIME || 262 $2 > MAX_HOLDTIME) { 263 yyerror("hello holdtime out of range (%d-%d)", 264 MIN_HOLDTIME, MAX_HOLDTIME); 265 YYERROR; 266 } 267 conf->thello_holdtime = $2; 268 defs->thello_holdtime = $2; 269 } 270 | THELLOINTERVAL NUMBER { 271 if ($2 < MIN_HELLO_INTERVAL || 272 $2 > MAX_HELLO_INTERVAL) { 273 yyerror("hello-interval out of range (%d-%d)", 274 MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL); 275 YYERROR; 276 } 277 conf->thello_interval = $2; 278 defs->thello_interval = $2; 279 } 280 ; 281 282 optnl : '\n' optnl 283 | 284 ; 285 286 nl : '\n' optnl /* one newline or more */ 287 ; 288 289 interface : INTERFACE STRING { 290 struct kif *kif; 291 292 if ((kif = kif_findname($2)) == NULL) { 293 yyerror("unknown interface %s", $2); 294 free($2); 295 YYERROR; 296 } 297 free($2); 298 iface = conf_get_if(kif); 299 if (iface == NULL) 300 YYERROR; 301 if (iface->media_type == IFT_LOOP || 302 iface->media_type == IFT_CARP) { 303 yyerror("unsupported interface type on " 304 "interface %s", iface->name); 305 YYERROR; 306 } 307 LIST_INSERT_HEAD(&conf->iface_list, iface, entry); 308 309 memcpy(&ifacedefs, defs, sizeof(ifacedefs)); 310 defs = &ifacedefs; 311 } interface_block { 312 iface->hello_holdtime = defs->lhello_holdtime; 313 iface->hello_interval = defs->lhello_interval; 314 iface = NULL; 315 316 defs = &globaldefs; 317 } 318 ; 319 320 interface_block : '{' optnl interfaceopts_l '}' 321 | '{' optnl '}' 322 | /* nothing */ 323 ; 324 325 interfaceopts_l : interfaceopts_l iface_defaults nl 326 | iface_defaults optnl 327 ; 328 329 tneighbor : TNEIGHBOR STRING { 330 struct in_addr addr; 331 332 if (inet_aton($2, &addr) == 0) { 333 yyerror( 334 "error parsing neighbor address"); 335 free($2); 336 YYERROR; 337 } 338 free($2); 339 340 tnbr = conf_get_tnbr(addr); 341 if (tnbr == NULL) 342 YYERROR; 343 LIST_INSERT_HEAD(&conf->tnbr_list, tnbr, entry); 344 345 memcpy(&tnbrdefs, defs, sizeof(tnbrdefs)); 346 defs = &tnbrdefs; 347 } tneighbor_block { 348 tnbr->hello_holdtime = defs->thello_holdtime; 349 tnbr->hello_interval = defs->thello_interval; 350 tnbr = NULL; 351 352 defs = &globaldefs; 353 } 354 ; 355 356 tneighbor_block : '{' optnl tneighboropts_l '}' 357 | '{' optnl '}' 358 | /* nothing */ 359 ; 360 361 tneighboropts_l : tneighboropts_l tnbr_defaults nl 362 | tnbr_defaults optnl 363 ; 364 365 %% 366 367 struct keywords { 368 const char *k_name; 369 int k_val; 370 }; 371 372 int 373 yyerror(const char *fmt, ...) 374 { 375 va_list ap; 376 char *nfmt; 377 378 file->errors++; 379 va_start(ap, fmt); 380 if (asprintf(&nfmt, "%s:%d: %s", file->name, yylval.lineno, fmt) == -1) 381 fatalx("yyerror asprintf"); 382 vlog(LOG_CRIT, nfmt, ap); 383 va_end(ap); 384 free(nfmt); 385 return (0); 386 } 387 388 int 389 kw_cmp(const void *k, const void *e) 390 { 391 return (strcmp(k, ((const struct keywords *)e)->k_name)); 392 } 393 394 int 395 lookup(char *s) 396 { 397 /* this has to be sorted always */ 398 static const struct keywords keywords[] = { 399 {"advertisement", ADVERTISEMENT}, 400 {"distribution", DISTRIBUTION}, 401 {"external-tag", EXTTAG}, 402 {"fib-update", FIBUPDATE}, 403 {"interface", INTERFACE}, 404 {"keepalive", KEEPALIVE}, 405 {"link-hello-holdtime", LHELLOHOLDTIME}, 406 {"link-hello-interval", LHELLOINTERVAL}, 407 {"no", NO}, 408 {"retention", RETENTION}, 409 {"router-id", ROUTERID}, 410 {"targeted-hello-accept", THELLOACCEPT}, 411 {"targeted-hello-holdtime", THELLOHOLDTIME}, 412 {"targeted-hello-interval", THELLOINTERVAL}, 413 {"targeted-neighbor", TNEIGHBOR}, 414 {"yes", YES} 415 }; 416 const struct keywords *p; 417 418 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 419 sizeof(keywords[0]), kw_cmp); 420 421 if (p) 422 return (p->k_val); 423 else 424 return (STRING); 425 } 426 427 #define MAXPUSHBACK 128 428 429 u_char *parsebuf; 430 int parseindex; 431 u_char pushback_buffer[MAXPUSHBACK]; 432 int pushback_index = 0; 433 434 int 435 lgetc(int quotec) 436 { 437 int c, next; 438 439 if (parsebuf) { 440 /* Read character from the parsebuffer instead of input. */ 441 if (parseindex >= 0) { 442 c = parsebuf[parseindex++]; 443 if (c != '\0') 444 return (c); 445 parsebuf = NULL; 446 } else 447 parseindex++; 448 } 449 450 if (pushback_index) 451 return (pushback_buffer[--pushback_index]); 452 453 if (quotec) { 454 if ((c = getc(file->stream)) == EOF) { 455 yyerror("reached end of file while parsing " 456 "quoted string"); 457 if (file == topfile || popfile() == EOF) 458 return (EOF); 459 return (quotec); 460 } 461 return (c); 462 } 463 464 while ((c = getc(file->stream)) == '\\') { 465 next = getc(file->stream); 466 if (next != '\n') { 467 c = next; 468 break; 469 } 470 yylval.lineno = file->lineno; 471 file->lineno++; 472 } 473 474 while (c == EOF) { 475 if (file == topfile || popfile() == EOF) 476 return (EOF); 477 c = getc(file->stream); 478 } 479 return (c); 480 } 481 482 int 483 lungetc(int c) 484 { 485 if (c == EOF) 486 return (EOF); 487 if (parsebuf) { 488 parseindex--; 489 if (parseindex >= 0) 490 return (c); 491 } 492 if (pushback_index < MAXPUSHBACK-1) 493 return (pushback_buffer[pushback_index++] = c); 494 else 495 return (EOF); 496 } 497 498 int 499 findeol(void) 500 { 501 int c; 502 503 parsebuf = NULL; 504 pushback_index = 0; 505 506 /* skip to either EOF or the first real EOL */ 507 while (1) { 508 c = lgetc(0); 509 if (c == '\n') { 510 file->lineno++; 511 break; 512 } 513 if (c == EOF) 514 break; 515 } 516 return (ERROR); 517 } 518 519 int 520 yylex(void) 521 { 522 u_char buf[8096]; 523 u_char *p, *val; 524 int quotec, next, c; 525 int token; 526 527 top: 528 p = buf; 529 while ((c = lgetc(0)) == ' ' || c == '\t') 530 ; /* nothing */ 531 532 yylval.lineno = file->lineno; 533 if (c == '#') 534 while ((c = lgetc(0)) != '\n' && c != EOF) 535 ; /* nothing */ 536 if (c == '$' && parsebuf == NULL) { 537 while (1) { 538 if ((c = lgetc(0)) == EOF) 539 return (0); 540 541 if (p + 1 >= buf + sizeof(buf) - 1) { 542 yyerror("string too long"); 543 return (findeol()); 544 } 545 if (isalnum(c) || c == '_') { 546 *p++ = c; 547 continue; 548 } 549 *p = '\0'; 550 lungetc(c); 551 break; 552 } 553 val = symget(buf); 554 if (val == NULL) { 555 yyerror("macro '%s' not defined", buf); 556 return (findeol()); 557 } 558 parsebuf = val; 559 parseindex = 0; 560 goto top; 561 } 562 563 switch (c) { 564 case '\'': 565 case '"': 566 quotec = c; 567 while (1) { 568 if ((c = lgetc(quotec)) == EOF) 569 return (0); 570 if (c == '\n') { 571 file->lineno++; 572 continue; 573 } else if (c == '\\') { 574 if ((next = lgetc(quotec)) == EOF) 575 return (0); 576 if (next == quotec || c == ' ' || c == '\t') 577 c = next; 578 else if (next == '\n') { 579 file->lineno++; 580 continue; 581 } else 582 lungetc(next); 583 } else if (c == quotec) { 584 *p = '\0'; 585 break; 586 } 587 if (p + 1 >= buf + sizeof(buf) - 1) { 588 yyerror("string too long"); 589 return (findeol()); 590 } 591 *p++ = c; 592 } 593 yylval.v.string = strdup(buf); 594 if (yylval.v.string == NULL) 595 err(1, "yylex: strdup"); 596 return (STRING); 597 } 598 599 #define allowed_to_end_number(x) \ 600 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 601 602 if (c == '-' || isdigit(c)) { 603 do { 604 *p++ = c; 605 if ((unsigned)(p-buf) >= sizeof(buf)) { 606 yyerror("string too long"); 607 return (findeol()); 608 } 609 } while ((c = lgetc(0)) != EOF && isdigit(c)); 610 lungetc(c); 611 if (p == buf + 1 && buf[0] == '-') 612 goto nodigits; 613 if (c == EOF || allowed_to_end_number(c)) { 614 const char *errstr = NULL; 615 616 *p = '\0'; 617 yylval.v.number = strtonum(buf, LLONG_MIN, 618 LLONG_MAX, &errstr); 619 if (errstr) { 620 yyerror("\"%s\" invalid number: %s", 621 buf, errstr); 622 return (findeol()); 623 } 624 return (NUMBER); 625 } else { 626 nodigits: 627 while (p > buf + 1) 628 lungetc(*--p); 629 c = *--p; 630 if (c == '-') 631 return (c); 632 } 633 } 634 635 #define allowed_in_string(x) \ 636 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 637 x != '{' && x != '}' && \ 638 x != '!' && x != '=' && x != '#' && \ 639 x != ',')) 640 641 if (isalnum(c) || c == ':' || c == '_') { 642 do { 643 *p++ = c; 644 if ((unsigned)(p-buf) >= sizeof(buf)) { 645 yyerror("string too long"); 646 return (findeol()); 647 } 648 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 649 lungetc(c); 650 *p = '\0'; 651 if ((token = lookup(buf)) == STRING) 652 if ((yylval.v.string = strdup(buf)) == NULL) 653 err(1, "yylex: strdup"); 654 return (token); 655 } 656 if (c == '\n') { 657 yylval.lineno = file->lineno; 658 file->lineno++; 659 } 660 if (c == EOF) 661 return (0); 662 return (c); 663 } 664 665 int 666 check_file_secrecy(int fd, const char *fname) 667 { 668 struct stat st; 669 670 if (fstat(fd, &st)) { 671 log_warn("cannot stat %s", fname); 672 return (-1); 673 } 674 if (st.st_uid != 0 && st.st_uid != getuid()) { 675 log_warnx("%s: owner not root or current user", fname); 676 return (-1); 677 } 678 if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { 679 log_warnx("%s: group writable or world read/writable", fname); 680 return (-1); 681 } 682 return (0); 683 } 684 685 struct file * 686 pushfile(const char *name, int secret) 687 { 688 struct file *nfile; 689 690 if ((nfile = calloc(1, sizeof(struct file))) == NULL) { 691 log_warn("malloc"); 692 return (NULL); 693 } 694 if ((nfile->name = strdup(name)) == NULL) { 695 log_warn("strdup"); 696 free(nfile); 697 return (NULL); 698 } 699 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 700 log_warn("%s", nfile->name); 701 free(nfile->name); 702 free(nfile); 703 return (NULL); 704 } else if (secret && 705 check_file_secrecy(fileno(nfile->stream), nfile->name)) { 706 fclose(nfile->stream); 707 free(nfile->name); 708 free(nfile); 709 return (NULL); 710 } 711 nfile->lineno = 1; 712 TAILQ_INSERT_TAIL(&files, nfile, entry); 713 return (nfile); 714 } 715 716 int 717 popfile(void) 718 { 719 struct file *prev; 720 721 if ((prev = TAILQ_PREV(file, files, entry)) != NULL) 722 prev->errors += file->errors; 723 724 TAILQ_REMOVE(&files, file, entry); 725 fclose(file->stream); 726 free(file->name); 727 free(file); 728 file = prev; 729 return (file ? 0 : EOF); 730 } 731 732 struct ldpd_conf * 733 parse_config(char *filename, int opts) 734 { 735 struct sym *sym, *next; 736 737 if ((conf = calloc(1, sizeof(struct ldpd_conf))) == NULL) 738 fatal("parse_config"); 739 conf->opts = opts; 740 conf->keepalive = DEFAULT_KEEPALIVE; 741 742 bzero(&globaldefs, sizeof(globaldefs)); 743 defs = &globaldefs; 744 defs->lhello_holdtime = LINK_DFLT_HOLDTIME; 745 defs->lhello_interval = DEFAULT_HELLO_INTERVAL; 746 defs->thello_holdtime = TARGETED_DFLT_HOLDTIME; 747 defs->thello_interval = DEFAULT_HELLO_INTERVAL; 748 conf->thello_holdtime = TARGETED_DFLT_HOLDTIME; 749 conf->thello_interval = DEFAULT_HELLO_INTERVAL; 750 751 conf->mode = (MODE_DIST_INDEPENDENT | MODE_RET_LIBERAL | 752 MODE_ADV_UNSOLICITED); 753 754 if ((file = pushfile(filename, !(conf->opts & LDPD_OPT_NOACTION))) == NULL) { 755 free(conf); 756 return (NULL); 757 } 758 topfile = file; 759 760 yyparse(); 761 errors = file->errors; 762 popfile(); 763 764 /* Free macros and check which have not been used. */ 765 for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) { 766 next = TAILQ_NEXT(sym, entry); 767 if ((conf->opts & LDPD_OPT_VERBOSE2) && !sym->used) 768 fprintf(stderr, "warning: macro '%s' not " 769 "used\n", sym->nam); 770 if (!sym->persist) { 771 free(sym->nam); 772 free(sym->val); 773 TAILQ_REMOVE(&symhead, sym, entry); 774 free(sym); 775 } 776 } 777 778 /* free global config defaults */ 779 if (errors) { 780 clear_config(conf); 781 return (NULL); 782 } 783 784 if (conf->rtr_id.s_addr == 0) 785 conf->rtr_id.s_addr = get_rtr_id(); 786 787 return (conf); 788 } 789 790 int 791 symset(const char *nam, const char *val, int persist) 792 { 793 struct sym *sym; 794 795 for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); 796 sym = TAILQ_NEXT(sym, entry)) 797 ; /* nothing */ 798 799 if (sym != NULL) { 800 if (sym->persist == 1) 801 return (0); 802 else { 803 free(sym->nam); 804 free(sym->val); 805 TAILQ_REMOVE(&symhead, sym, entry); 806 free(sym); 807 } 808 } 809 if ((sym = calloc(1, sizeof(*sym))) == NULL) 810 return (-1); 811 812 sym->nam = strdup(nam); 813 if (sym->nam == NULL) { 814 free(sym); 815 return (-1); 816 } 817 sym->val = strdup(val); 818 if (sym->val == NULL) { 819 free(sym->nam); 820 free(sym); 821 return (-1); 822 } 823 sym->used = 0; 824 sym->persist = persist; 825 TAILQ_INSERT_TAIL(&symhead, sym, entry); 826 return (0); 827 } 828 829 int 830 cmdline_symset(char *s) 831 { 832 char *sym, *val; 833 int ret; 834 size_t len; 835 836 if ((val = strrchr(s, '=')) == NULL) 837 return (-1); 838 839 len = strlen(s) - strlen(val) + 1; 840 if ((sym = malloc(len)) == NULL) 841 errx(1, "cmdline_symset: malloc"); 842 843 strlcpy(sym, s, len); 844 845 ret = symset(sym, val + 1, 1); 846 free(sym); 847 848 return (ret); 849 } 850 851 char * 852 symget(const char *nam) 853 { 854 struct sym *sym; 855 856 TAILQ_FOREACH(sym, &symhead, entry) 857 if (strcmp(nam, sym->nam) == 0) { 858 sym->used = 1; 859 return (sym->val); 860 } 861 return (NULL); 862 } 863 864 struct iface * 865 conf_get_if(struct kif *kif) 866 { 867 struct iface *i; 868 869 LIST_FOREACH(i, &conf->iface_list, entry) { 870 if (i->ifindex == kif->ifindex) { 871 yyerror("interface %s already configured", 872 kif->ifname); 873 return (NULL); 874 } 875 } 876 877 i = if_new(kif); 878 879 return (i); 880 } 881 882 struct tnbr * 883 conf_get_tnbr(struct in_addr addr) 884 { 885 struct tnbr *t; 886 887 LIST_FOREACH(t, &conf->tnbr_list, entry) { 888 if (t->addr.s_addr == addr.s_addr) { 889 yyerror("targeted neighbor %s already configured", 890 inet_ntoa(addr)); 891 return (NULL); 892 } 893 } 894 895 t = tnbr_new(conf, addr, 1); 896 897 return (t); 898 } 899 900 void 901 clear_config(struct ldpd_conf *xconf) 902 { 903 struct iface *i; 904 905 while ((i = LIST_FIRST(&conf->iface_list)) != NULL) { 906 LIST_REMOVE(i, entry); 907 if_del(i); 908 } 909 910 free(xconf); 911 } 912 913 u_int32_t 914 get_rtr_id(void) 915 { 916 struct ifaddrs *ifap, *ifa; 917 u_int32_t ip = 0, cur, localnet; 918 919 localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET); 920 921 if (getifaddrs(&ifap) == -1) 922 fatal("getifaddrs"); 923 924 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 925 if (strncmp(ifa->ifa_name, "carp", 4) == 0) 926 continue; 927 if (ifa->ifa_addr->sa_family != AF_INET) 928 continue; 929 cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; 930 if ((cur & localnet) == localnet) /* skip 127/8 */ 931 continue; 932 if (cur > ip || ip == 0) 933 ip = cur; 934 } 935 freeifaddrs(ifap); 936 937 if (ip == 0) 938 fatal("router-id is 0.0.0.0"); 939 940 return (ip); 941 } 942 943 int 944 host(const char *s, struct in_addr *addr, struct in_addr *mask) 945 { 946 struct in_addr ina; 947 int bits = 32; 948 949 bzero(&ina, sizeof(struct in_addr)); 950 if (strrchr(s, '/') != NULL) { 951 if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1) 952 return (0); 953 } else { 954 if (inet_pton(AF_INET, s, &ina) != 1) 955 return (0); 956 } 957 958 addr->s_addr = ina.s_addr; 959 mask->s_addr = prefixlen2mask(bits); 960 961 return (1); 962 } 963