1 /* $OpenBSD: parse.y,v 1.28 2010/08/03 18:42:41 henning Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it> 5 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 6 * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org> 7 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> 8 * Copyright (c) 2001 Markus Friedl. All rights reserved. 9 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. 10 * Copyright (c) 2001 Theo de Raadt. All rights reserved. 11 * 12 * Permission to use, copy, modify, and distribute this software for any 13 * purpose with or without fee is hereby granted, provided that the above 14 * copyright notice and this permission notice appear in all copies. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 17 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 19 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 21 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 22 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 23 */ 24 25 %{ 26 #include <sys/types.h> 27 #include <sys/socket.h> 28 #include <sys/stat.h> 29 #include <netinet/in.h> 30 #include <arpa/inet.h> 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 <stdarg.h> 38 #include <stdio.h> 39 #include <string.h> 40 41 #include "ripd.h" 42 #include "rip.h" 43 #include "ripe.h" 44 #include "log.h" 45 46 TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); 47 static struct file { 48 TAILQ_ENTRY(file) entry; 49 FILE *stream; 50 char *name; 51 int lineno; 52 int errors; 53 } *file, *topfile; 54 struct file *pushfile(const char *, int); 55 int popfile(void); 56 int yyparse(void); 57 int yylex(void); 58 int yyerror(const char *, ...); 59 int kw_cmp(const void *, const void *); 60 int lookup(char *); 61 int lgetc(int); 62 int lungetc(int); 63 int findeol(void); 64 65 TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); 66 struct sym { 67 TAILQ_ENTRY(sym) entry; 68 int used; 69 int persist; 70 char *nam; 71 char *val; 72 }; 73 int symset(const char *, const char *, int); 74 char *symget(const char *); 75 76 static struct { 77 u_int8_t auth_key[MAX_SIMPLE_AUTH_LEN]; 78 struct auth_md_head md_list; 79 enum auth_type auth_type; 80 u_int8_t auth_keyid; 81 u_int8_t cost; 82 } *defs, globaldefs, ifacedefs; 83 84 struct iface *iface = NULL; 85 static struct ripd_conf *conf; 86 static int errors = 0; 87 88 struct iface *conf_get_if(struct kif *); 89 void clear_config(struct ripd_conf *); 90 int check_file_secrecy(int, const char *); 91 u_int32_t get_rtr_id(void); 92 int host(const char *, struct in_addr *, struct in_addr *); 93 94 typedef struct { 95 union { 96 int64_t number; 97 char *string; 98 } v; 99 int lineno; 100 } YYSTYPE; 101 102 %} 103 104 %token SPLIT_HORIZON TRIGGERED_UPDATES FIBUPDATE REDISTRIBUTE RDOMAIN 105 %token AUTHKEY AUTHTYPE AUTHMD AUTHMDKEYID 106 %token INTERFACE RTLABEL 107 %token COST PASSIVE 108 %token YES NO 109 %token DEMOTE 110 %token ERROR 111 %token <v.string> STRING 112 %token <v.number> NUMBER 113 %type <v.number> yesno no 114 %type <v.string> string 115 116 %% 117 118 grammar : /* empty */ 119 | grammar '\n' 120 | grammar conf_main '\n' 121 | grammar varset '\n' 122 | grammar interface '\n' 123 | grammar error '\n' { file->errors++; } 124 ; 125 126 string : string STRING { 127 if (asprintf(&$$, "%s %s", $1, $2) == -1) { 128 free($1); 129 free($2); 130 yyerror("string: asprintf"); 131 YYERROR; 132 } 133 free($1); 134 free($2); 135 } 136 | STRING 137 ; 138 139 yesno : YES { $$ = 1; } 140 | NO { $$ = 0; } 141 ; 142 143 no : /* empty */ { $$ = 0; } 144 | NO { $$ = 1; } 145 146 varset : STRING '=' string { 147 if (conf->opts & RIPD_OPT_VERBOSE) 148 printf("%s = \"%s\"\n", $1, $3); 149 if (symset($1, $3, 0) == -1) 150 fatal("cannot store variable"); 151 free($1); 152 free($3); 153 } 154 ; 155 156 conf_main : SPLIT_HORIZON STRING { 157 /* clean flags first */ 158 conf->options &= ~(OPT_SPLIT_HORIZON | 159 OPT_SPLIT_POISONED); 160 if (!strcmp($2, "none")) 161 /* nothing */ ; 162 else if (!strcmp($2, "simple")) 163 conf->options |= OPT_SPLIT_HORIZON; 164 else if (!strcmp($2, "poisoned")) 165 conf->options |= OPT_SPLIT_POISONED; 166 else { 167 yyerror("unknown split horizon type"); 168 free($2); 169 YYERROR; 170 } 171 free($2); 172 } 173 | TRIGGERED_UPDATES yesno { 174 if ($2 == 1) 175 conf->options |= OPT_TRIGGERED_UPDATES; 176 else 177 conf->options &= ~OPT_TRIGGERED_UPDATES; 178 } 179 | RDOMAIN NUMBER { 180 if ($2 < 0 || $2 > RT_TABLEID_MAX) { 181 yyerror("invalid rdomain"); 182 YYERROR; 183 } 184 conf->rdomain = $2; 185 } 186 | FIBUPDATE yesno { 187 if ($2 == 0) 188 conf->flags |= RIPD_FLAG_NO_FIB_UPDATE; 189 else 190 conf->flags &= ~RIPD_FLAG_NO_FIB_UPDATE; 191 } 192 | no REDISTRIBUTE STRING { 193 struct redistribute *r; 194 195 if ((r = calloc(1, sizeof(*r))) == NULL) 196 fatal(NULL); 197 if (!strcmp($3, "static")) 198 r->type = REDIST_STATIC; 199 else if (!strcmp($3, "connected")) 200 r->type = REDIST_CONNECTED; 201 else if (!strcmp($3, "default")) 202 r->type = REDIST_DEFAULT; 203 else if (host($3, &r->addr, &r->mask)) 204 r->type = REDIST_ADDR; 205 else { 206 yyerror("unknown redistribute type"); 207 free($3); 208 free(r); 209 YYERROR; 210 } 211 212 if ($1) 213 r->type |= REDIST_NO; 214 215 SIMPLEQ_INSERT_TAIL(&conf->redist_list, r, 216 entry); 217 218 conf->redistribute |= REDISTRIBUTE_ON; 219 free($3); 220 } 221 | no REDISTRIBUTE RTLABEL STRING { 222 struct redistribute *r; 223 224 if ((r = calloc(1, sizeof(*r))) == NULL) 225 fatal(NULL); 226 r->type = REDIST_LABEL; 227 r->label = rtlabel_name2id($4); 228 if ($1) 229 r->type |= REDIST_NO; 230 free($4); 231 232 SIMPLEQ_INSERT_TAIL(&conf->redist_list, r, entry); 233 conf->redistribute |= REDISTRIBUTE_ON; 234 } 235 | defaults 236 ; 237 238 authmd : AUTHMD NUMBER STRING { 239 if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) { 240 yyerror("auth-md key-id out of range " 241 "(%d-%d)", MIN_MD_ID, MAX_MD_ID); 242 free($3); 243 YYERROR; 244 } 245 if (md_list_add(&defs->md_list, $2, $3) == -1) { 246 yyerror("auth-md key length out of range " 247 "(max length %d)", MD5_DIGEST_LENGTH); 248 free($3); 249 YYERROR; 250 } 251 free($3); 252 } 253 254 authmdkeyid : AUTHMDKEYID NUMBER { 255 if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) { 256 yyerror("auth-md-keyid out of range " 257 "(%d-%d)", MIN_MD_ID, MAX_MD_ID); 258 YYERROR; 259 } 260 defs->auth_keyid = $2; 261 } 262 263 authtype : AUTHTYPE STRING { 264 enum auth_type type; 265 266 if (!strcmp($2, "none")) 267 type = AUTH_NONE; 268 else if (!strcmp($2, "simple")) 269 type = AUTH_SIMPLE; 270 else if (!strcmp($2, "crypt")) 271 type = AUTH_CRYPT; 272 else { 273 yyerror("unknown auth-type"); 274 free($2); 275 YYERROR; 276 } 277 free($2); 278 defs->auth_type = type; 279 } 280 ; 281 282 authkey : AUTHKEY STRING { 283 if (strlen($2) > MAX_SIMPLE_AUTH_LEN) { 284 yyerror("auth-key too long (max length %d)", 285 MAX_SIMPLE_AUTH_LEN); 286 free($2); 287 YYERROR; 288 } 289 bzero(defs->auth_key, MAX_SIMPLE_AUTH_LEN); 290 memcpy(defs->auth_key, $2, strlen($2)); 291 free($2); 292 } 293 ; 294 295 defaults : COST NUMBER { 296 if ($2 < 1 || $2 > INFINITY) { 297 yyerror("cost out of range (%d-%d)", 1, 298 INFINITY); 299 YYERROR; 300 } 301 defs->cost = $2; 302 } 303 | authtype 304 | authkey 305 | authmdkeyid 306 | authmd 307 ; 308 309 optnl : '\n' optnl 310 | 311 ; 312 313 nl : '\n' optnl 314 ; 315 316 interface : INTERFACE STRING { 317 struct kif *kif; 318 319 if ((kif = kif_findname($2)) == NULL) { 320 yyerror("unknown interface %s", $2); 321 free($2); 322 YYERROR; 323 } 324 free($2); 325 iface = conf_get_if(kif); 326 if (iface == NULL) 327 YYERROR; 328 LIST_INSERT_HEAD(&conf->iface_list, iface, entry); 329 memcpy(&ifacedefs, defs, sizeof(ifacedefs)); 330 md_list_copy(&ifacedefs.md_list, &defs->md_list); 331 defs = &ifacedefs; 332 } interface_block { 333 iface->cost = defs->cost; 334 iface->auth_type = defs->auth_type; 335 iface->auth_keyid = defs->auth_keyid; 336 memcpy(iface->auth_key, defs->auth_key, 337 sizeof(iface->auth_key)); 338 md_list_copy(&iface->auth_md_list, &defs->md_list); 339 md_list_clr(&defs->md_list); 340 defs = &globaldefs; 341 } 342 ; 343 344 interface_block : '{' optnl interfaceopts_l '}' 345 | '{' optnl '}' 346 ; 347 348 interfaceopts_l : interfaceopts_l interfaceoptsl nl 349 | interfaceoptsl optnl 350 ; 351 352 interfaceoptsl : PASSIVE { iface->passive = 1; } 353 | DEMOTE STRING { 354 if (strlcpy(iface->demote_group, $2, 355 sizeof(iface->demote_group)) >= 356 sizeof(iface->demote_group)) { 357 yyerror("demote group name \"%s\" too long"); 358 free($2); 359 YYERROR; 360 } 361 free($2); 362 if (carp_demote_init(iface->demote_group, 363 conf->opts & RIPD_OPT_FORCE_DEMOTE) == -1) { 364 yyerror("error initializing group \"%s\"", 365 iface->demote_group); 366 YYERROR; 367 } 368 } 369 | defaults 370 ; 371 %% 372 373 struct keywords { 374 const char *k_name; 375 int k_val; 376 }; 377 378 int 379 yyerror(const char *fmt, ...) 380 { 381 va_list ap; 382 383 file->errors++; 384 va_start(ap, fmt); 385 fprintf(stderr, "%s:%d: ", file->name, yylval.lineno); 386 vfprintf(stderr, fmt, ap); 387 fprintf(stderr, "\n"); 388 va_end(ap); 389 return (0); 390 } 391 392 int 393 kw_cmp(const void *k, const void *e) 394 { 395 return (strcmp(k, ((const struct keywords *)e)->k_name)); 396 } 397 398 int 399 lookup(char *s) 400 { 401 /* this has to be sorted always */ 402 static const struct keywords keywords[] = { 403 {"auth-key", AUTHKEY}, 404 {"auth-md", AUTHMD}, 405 {"auth-md-keyid", AUTHMDKEYID}, 406 {"auth-type", AUTHTYPE}, 407 {"cost", COST}, 408 {"demote", DEMOTE}, 409 {"fib-update", FIBUPDATE}, 410 {"interface", INTERFACE}, 411 {"no", NO}, 412 {"passive", PASSIVE}, 413 {"rdomain", RDOMAIN}, 414 {"redistribute", REDISTRIBUTE}, 415 {"rtlabel", RTLABEL}, 416 {"split-horizon", SPLIT_HORIZON}, 417 {"triggered-updates", TRIGGERED_UPDATES}, 418 {"yes", YES} 419 }; 420 const struct keywords *p; 421 422 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 423 sizeof(keywords[0]), kw_cmp); 424 425 if (p) 426 return (p->k_val); 427 else 428 return (STRING); 429 } 430 431 #define MAXPUSHBACK 128 432 433 char *parsebuf; 434 int parseindex; 435 char pushback_buffer[MAXPUSHBACK]; 436 int pushback_index = 0; 437 438 int 439 lgetc(int quotec) 440 { 441 int c, next; 442 443 if (parsebuf) { 444 /* Read character from the parsebuffer instead of input. */ 445 if (parseindex >= 0) { 446 c = parsebuf[parseindex++]; 447 if (c != '\0') 448 return (c); 449 parsebuf = NULL; 450 } else 451 parseindex++; 452 } 453 454 if (pushback_index) 455 return (pushback_buffer[--pushback_index]); 456 457 if (quotec) { 458 if ((c = getc(file->stream)) == EOF) { 459 yyerror("reached end of file while parsing " 460 "quoted string"); 461 if (file == topfile || popfile() == EOF) 462 return (EOF); 463 return (quotec); 464 } 465 return (c); 466 } 467 468 while ((c = getc(file->stream)) == '\\') { 469 next = getc(file->stream); 470 if (next != '\n') { 471 c = next; 472 break; 473 } 474 yylval.lineno = file->lineno; 475 file->lineno++; 476 } 477 478 while (c == EOF) { 479 if (file == topfile || popfile() == EOF) 480 return (EOF); 481 c = getc(file->stream); 482 } 483 return (c); 484 } 485 486 int 487 lungetc(int c) 488 { 489 if (c == EOF) 490 return (EOF); 491 if (parsebuf) { 492 parseindex--; 493 if (parseindex >= 0) 494 return (c); 495 } 496 if (pushback_index < MAXPUSHBACK-1) 497 return (pushback_buffer[pushback_index++] = c); 498 else 499 return (EOF); 500 } 501 502 int 503 findeol(void) 504 { 505 int c; 506 507 parsebuf = NULL; 508 509 /* skip to either EOF or the first real EOL */ 510 while (1) { 511 if (pushback_index) 512 c = pushback_buffer[--pushback_index]; 513 else 514 c = lgetc(0); 515 if (c == '\n') { 516 file->lineno++; 517 break; 518 } 519 if (c == EOF) 520 break; 521 } 522 return (ERROR); 523 } 524 525 int 526 yylex(void) 527 { 528 char buf[8096]; 529 char *p, *val; 530 int quotec, next, c; 531 int token; 532 533 top: 534 p = buf; 535 while ((c = lgetc(0)) == ' ' || c == '\t') 536 ; /* nothing */ 537 538 yylval.lineno = file->lineno; 539 if (c == '#') 540 while ((c = lgetc(0)) != '\n' && c != EOF) 541 ; /* nothing */ 542 if (c == '$' && parsebuf == NULL) { 543 while (1) { 544 if ((c = lgetc(0)) == EOF) 545 return (0); 546 547 if (p + 1 >= buf + sizeof(buf) - 1) { 548 yyerror("string too long"); 549 return (findeol()); 550 } 551 if (isalnum(c) || c == '_') { 552 *p++ = (char)c; 553 continue; 554 } 555 *p = '\0'; 556 lungetc(c); 557 break; 558 } 559 val = symget(buf); 560 if (val == NULL) { 561 yyerror("macro '%s' not defined", buf); 562 return (findeol()); 563 } 564 parsebuf = val; 565 parseindex = 0; 566 goto top; 567 } 568 569 switch (c) { 570 case '\'': 571 case '"': 572 quotec = c; 573 while (1) { 574 if ((c = lgetc(quotec)) == EOF) 575 return (0); 576 if (c == '\n') { 577 file->lineno++; 578 continue; 579 } else if (c == '\\') { 580 if ((next = lgetc(quotec)) == EOF) 581 return (0); 582 if (next == quotec || c == ' ' || c == '\t') 583 c = next; 584 else if (next == '\n') { 585 file->lineno++; 586 continue; 587 } else 588 lungetc(next); 589 } else if (c == quotec) { 590 *p = '\0'; 591 break; 592 } 593 if (p + 1 >= buf + sizeof(buf) - 1) { 594 yyerror("string too long"); 595 return (findeol()); 596 } 597 *p++ = (char)c; 598 } 599 yylval.v.string = strdup(buf); 600 if (yylval.v.string == NULL) 601 err(1, "yylex: strdup"); 602 return (STRING); 603 } 604 605 #define allowed_to_end_number(x) \ 606 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 607 608 if (c == '-' || isdigit(c)) { 609 do { 610 *p++ = c; 611 if ((unsigned)(p-buf) >= sizeof(buf)) { 612 yyerror("string too long"); 613 return (findeol()); 614 } 615 } while ((c = lgetc(0)) != EOF && isdigit(c)); 616 lungetc(c); 617 if (p == buf + 1 && buf[0] == '-') 618 goto nodigits; 619 if (c == EOF || allowed_to_end_number(c)) { 620 const char *errstr = NULL; 621 622 *p = '\0'; 623 yylval.v.number = strtonum(buf, LLONG_MIN, 624 LLONG_MAX, &errstr); 625 if (errstr) { 626 yyerror("\"%s\" invalid number: %s", 627 buf, errstr); 628 return (findeol()); 629 } 630 return (NUMBER); 631 } else { 632 nodigits: 633 while (p > buf + 1) 634 lungetc(*--p); 635 c = *--p; 636 if (c == '-') 637 return (c); 638 } 639 } 640 641 #define allowed_in_string(x) \ 642 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 643 x != '{' && x != '}' && \ 644 x != '!' && x != '=' && x != '#' && \ 645 x != ',')) 646 647 if (isalnum(c) || c == ':' || c == '_') { 648 do { 649 *p++ = c; 650 if ((unsigned)(p-buf) >= sizeof(buf)) { 651 yyerror("string too long"); 652 return (findeol()); 653 } 654 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 655 lungetc(c); 656 *p = '\0'; 657 if ((token = lookup(buf)) == STRING) 658 if ((yylval.v.string = strdup(buf)) == NULL) 659 err(1, "yylex: strdup"); 660 return (token); 661 } 662 if (c == '\n') { 663 yylval.lineno = file->lineno; 664 file->lineno++; 665 } 666 if (c == EOF) 667 return (0); 668 return (c); 669 } 670 671 int 672 check_file_secrecy(int fd, const char *fname) 673 { 674 struct stat st; 675 676 if (fstat(fd, &st)) { 677 log_warn("cannot stat %s", fname); 678 return (-1); 679 } 680 if (st.st_uid != 0 && st.st_uid != getuid()) { 681 log_warnx("%s: owner not root or current user", fname); 682 return (-1); 683 } 684 if (st.st_mode & (S_IRWXG | S_IRWXO)) { 685 log_warnx("%s: group/world readable/writeable", fname); 686 return (-1); 687 } 688 return (0); 689 } 690 691 struct file * 692 pushfile(const char *name, int secret) 693 { 694 struct file *nfile; 695 696 if ((nfile = calloc(1, sizeof(struct file))) == NULL) { 697 log_warn("malloc"); 698 return (NULL); 699 } 700 if ((nfile->name = strdup(name)) == NULL) { 701 log_warn("malloc"); 702 free(nfile); 703 return (NULL); 704 } 705 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 706 log_warn("%s", nfile->name); 707 free(nfile->name); 708 free(nfile); 709 return (NULL); 710 } else if (secret && 711 check_file_secrecy(fileno(nfile->stream), nfile->name)) { 712 fclose(nfile->stream); 713 free(nfile->name); 714 free(nfile); 715 return (NULL); 716 } 717 nfile->lineno = 1; 718 TAILQ_INSERT_TAIL(&files, nfile, entry); 719 return (nfile); 720 } 721 722 int 723 popfile(void) 724 { 725 struct file *prev; 726 727 if ((prev = TAILQ_PREV(file, files, entry)) != NULL) 728 prev->errors += file->errors; 729 730 TAILQ_REMOVE(&files, file, entry); 731 fclose(file->stream); 732 free(file->name); 733 free(file); 734 file = prev; 735 return (file ? 0 : EOF); 736 } 737 738 struct ripd_conf * 739 parse_config(char *filename, int opts) 740 { 741 struct sym *sym, *next; 742 743 if ((conf = calloc(1, sizeof(struct ripd_conf))) == NULL) 744 fatal("parse_config"); 745 746 bzero(&globaldefs, sizeof(globaldefs)); 747 defs = &globaldefs; 748 TAILQ_INIT(&defs->md_list); 749 defs->cost = DEFAULT_COST; 750 defs->auth_type = AUTH_NONE; 751 conf->opts = opts; 752 conf->options = OPT_SPLIT_POISONED; 753 SIMPLEQ_INIT(&conf->redist_list); 754 755 if ((file = pushfile(filename, !(conf->opts & RIPD_OPT_NOACTION))) == NULL) { 756 free(conf); 757 return (NULL); 758 } 759 topfile = file; 760 761 yyparse(); 762 errors = file->errors; 763 popfile(); 764 765 /* Free macros and check which have not been used. */ 766 for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) { 767 next = TAILQ_NEXT(sym, entry); 768 if ((conf->opts & RIPD_OPT_VERBOSE2) && !sym->used) 769 fprintf(stderr, "warning: macro '%s' not " 770 "used\n", sym->nam); 771 if (!sym->persist) { 772 free(sym->nam); 773 free(sym->val); 774 TAILQ_REMOVE(&symhead, sym, entry); 775 free(sym); 776 } 777 } 778 779 /* free global config defaults */ 780 md_list_clr(&globaldefs.md_list); 781 782 if (errors) { 783 clear_config(conf); 784 return (NULL); 785 } 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 i = if_new(kif); 877 i->auth_keyid = 1; 878 i->passive = 0; 879 880 return (i); 881 } 882 883 void 884 clear_config(struct ripd_conf *xconf) 885 { 886 struct iface *i; 887 888 while ((i = LIST_FIRST(&conf->iface_list)) != NULL) { 889 LIST_REMOVE(i, entry); 890 if_del(i); 891 } 892 893 free(xconf); 894 } 895 896 int 897 host(const char *s, struct in_addr *addr, struct in_addr *mask) 898 { 899 struct in_addr ina; 900 int bits = 32; 901 902 bzero(&ina, sizeof(struct in_addr)); 903 if (strrchr(s, '/') != NULL) { 904 if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1) 905 return (0); 906 } else { 907 if (inet_pton(AF_INET, s, &ina) != 1) 908 return (0); 909 } 910 911 addr->s_addr = ina.s_addr; 912 mask->s_addr = prefixlen2mask(bits); 913 914 return (1); 915 } 916