1 /* $OpenBSD: parse.y,v 1.24 2009/03/31 21:03:49 tobias 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 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, "default")) 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 | FIBUPDATE yesno { 180 if ($2 == 0) 181 conf->flags |= RIPD_FLAG_NO_FIB_UPDATE; 182 else 183 conf->flags &= ~RIPD_FLAG_NO_FIB_UPDATE; 184 } 185 | no REDISTRIBUTE STRING { 186 struct redistribute *r; 187 188 if ((r = calloc(1, sizeof(*r))) == NULL) 189 fatal(NULL); 190 if (!strcmp($3, "static")) 191 r->type = REDIST_STATIC; 192 else if (!strcmp($3, "connected")) 193 r->type = REDIST_CONNECTED; 194 else if (!strcmp($3, "default")) 195 r->type = REDIST_DEFAULT; 196 else if (host($3, &r->addr, &r->mask)) 197 r->type = REDIST_ADDR; 198 else { 199 yyerror("unknown redistribute type"); 200 free($3); 201 free(r); 202 YYERROR; 203 } 204 205 if ($1) 206 r->type |= REDIST_NO; 207 208 SIMPLEQ_INSERT_TAIL(&conf->redist_list, r, 209 entry); 210 211 conf->redistribute |= REDISTRIBUTE_ON; 212 free($3); 213 } 214 | no REDISTRIBUTE RTLABEL STRING { 215 struct redistribute *r; 216 217 if ((r = calloc(1, sizeof(*r))) == NULL) 218 fatal(NULL); 219 r->type = REDIST_LABEL; 220 r->label = rtlabel_name2id($4); 221 if ($1) 222 r->type |= REDIST_NO; 223 free($4); 224 225 SIMPLEQ_INSERT_TAIL(&conf->redist_list, r, entry); 226 conf->redistribute |= REDISTRIBUTE_ON; 227 } 228 | defaults 229 ; 230 231 authmd : AUTHMD NUMBER STRING { 232 if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) { 233 yyerror("auth-md key-id out of range " 234 "(%d-%d)", MIN_MD_ID, MAX_MD_ID); 235 free($3); 236 YYERROR; 237 } 238 if (md_list_add(&defs->md_list, $2, $3) == -1) { 239 yyerror("auth-md key length out of range " 240 "(max length %d)", MD5_DIGEST_LENGTH); 241 free($3); 242 YYERROR; 243 } 244 free($3); 245 } 246 247 authmdkeyid : AUTHMDKEYID NUMBER { 248 if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) { 249 yyerror("auth-md-keyid out of range " 250 "(%d-%d)", MIN_MD_ID, MAX_MD_ID); 251 YYERROR; 252 } 253 defs->auth_keyid = $2; 254 } 255 256 authtype : AUTHTYPE STRING { 257 enum auth_type type; 258 259 if (!strcmp($2, "none")) 260 type = AUTH_NONE; 261 else if (!strcmp($2, "simple")) 262 type = AUTH_SIMPLE; 263 else if (!strcmp($2, "crypt")) 264 type = AUTH_CRYPT; 265 else { 266 yyerror("unknown auth-type"); 267 free($2); 268 YYERROR; 269 } 270 free($2); 271 defs->auth_type = type; 272 } 273 ; 274 275 authkey : AUTHKEY STRING { 276 if (strlen($2) > MAX_SIMPLE_AUTH_LEN) { 277 yyerror("auth-key too long (max length %d)", 278 MAX_SIMPLE_AUTH_LEN); 279 free($2); 280 YYERROR; 281 } 282 bzero(defs->auth_key, MAX_SIMPLE_AUTH_LEN); 283 memcpy(defs->auth_key, $2, strlen($2)); 284 free($2); 285 } 286 ; 287 288 defaults : COST NUMBER { 289 if ($2 < 1 || $2 > INFINITY) { 290 yyerror("cost out of range (%d-%d)", 1, 291 INFINITY); 292 YYERROR; 293 } 294 defs->cost = $2; 295 } 296 | authtype 297 | authkey 298 | authmdkeyid 299 | authmd 300 ; 301 302 optnl : '\n' optnl 303 | 304 ; 305 306 nl : '\n' optnl 307 ; 308 309 interface : INTERFACE STRING { 310 struct kif *kif; 311 312 if ((kif = kif_findname($2)) == NULL) { 313 yyerror("unknown interface %s", $2); 314 free($2); 315 YYERROR; 316 } 317 free($2); 318 iface = conf_get_if(kif); 319 if (iface == NULL) 320 YYERROR; 321 LIST_INSERT_HEAD(&conf->iface_list, iface, entry); 322 memcpy(&ifacedefs, defs, sizeof(ifacedefs)); 323 md_list_copy(&ifacedefs.md_list, &defs->md_list); 324 defs = &ifacedefs; 325 } interface_block { 326 iface->cost = defs->cost; 327 iface->auth_type = defs->auth_type; 328 iface->auth_keyid = defs->auth_keyid; 329 memcpy(iface->auth_key, defs->auth_key, 330 sizeof(iface->auth_key)); 331 md_list_copy(&iface->auth_md_list, &defs->md_list); 332 md_list_clr(&defs->md_list); 333 defs = &globaldefs; 334 } 335 ; 336 337 interface_block : '{' optnl interfaceopts_l '}' 338 | '{' optnl '}' 339 ; 340 341 interfaceopts_l : interfaceopts_l interfaceoptsl nl 342 | interfaceoptsl optnl 343 ; 344 345 interfaceoptsl : PASSIVE { iface->passive = 1; } 346 | DEMOTE STRING { 347 if (strlcpy(iface->demote_group, $2, 348 sizeof(iface->demote_group)) >= 349 sizeof(iface->demote_group)) { 350 yyerror("demote group name \"%s\" too long"); 351 free($2); 352 YYERROR; 353 } 354 free($2); 355 if (carp_demote_init(iface->demote_group, 356 conf->opts & RIPD_OPT_FORCE_DEMOTE) == -1) { 357 yyerror("error initializing group \"%s\"", 358 iface->demote_group); 359 YYERROR; 360 } 361 } 362 | defaults 363 ; 364 %% 365 366 struct keywords { 367 const char *k_name; 368 int k_val; 369 }; 370 371 int 372 yyerror(const char *fmt, ...) 373 { 374 va_list ap; 375 376 file->errors++; 377 va_start(ap, fmt); 378 fprintf(stderr, "%s:%d: ", file->name, yylval.lineno); 379 vfprintf(stderr, fmt, ap); 380 fprintf(stderr, "\n"); 381 va_end(ap); 382 return (0); 383 } 384 385 int 386 kw_cmp(const void *k, const void *e) 387 { 388 return (strcmp(k, ((const struct keywords *)e)->k_name)); 389 } 390 391 int 392 lookup(char *s) 393 { 394 /* this has to be sorted always */ 395 static const struct keywords keywords[] = { 396 {"auth-key", AUTHKEY}, 397 {"auth-md", AUTHMD}, 398 {"auth-md-keyid", AUTHMDKEYID}, 399 {"auth-type", AUTHTYPE}, 400 {"cost", COST}, 401 {"demote", DEMOTE}, 402 {"fib-update", FIBUPDATE}, 403 {"interface", INTERFACE}, 404 {"no", NO}, 405 {"passive", PASSIVE}, 406 {"redistribute", REDISTRIBUTE}, 407 {"rtlabel", RTLABEL}, 408 {"split-horizon", SPLIT_HORIZON}, 409 {"triggered-updates", TRIGGERED_UPDATES}, 410 {"yes", YES} 411 }; 412 const struct keywords *p; 413 414 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 415 sizeof(keywords[0]), kw_cmp); 416 417 if (p) 418 return (p->k_val); 419 else 420 return (STRING); 421 } 422 423 #define MAXPUSHBACK 128 424 425 char *parsebuf; 426 int parseindex; 427 char pushback_buffer[MAXPUSHBACK]; 428 int pushback_index = 0; 429 430 int 431 lgetc(int quotec) 432 { 433 int c, next; 434 435 if (parsebuf) { 436 /* Read character from the parsebuffer instead of input. */ 437 if (parseindex >= 0) { 438 c = parsebuf[parseindex++]; 439 if (c != '\0') 440 return (c); 441 parsebuf = NULL; 442 } else 443 parseindex++; 444 } 445 446 if (pushback_index) 447 return (pushback_buffer[--pushback_index]); 448 449 if (quotec) { 450 if ((c = getc(file->stream)) == EOF) { 451 yyerror("reached end of file while parsing " 452 "quoted string"); 453 if (file == topfile || popfile() == EOF) 454 return (EOF); 455 return (quotec); 456 } 457 return (c); 458 } 459 460 while ((c = getc(file->stream)) == '\\') { 461 next = getc(file->stream); 462 if (next != '\n') { 463 c = next; 464 break; 465 } 466 yylval.lineno = file->lineno; 467 file->lineno++; 468 } 469 470 while (c == EOF) { 471 if (file == topfile || popfile() == EOF) 472 return (EOF); 473 c = getc(file->stream); 474 } 475 return (c); 476 } 477 478 int 479 lungetc(int c) 480 { 481 if (c == EOF) 482 return (EOF); 483 if (parsebuf) { 484 parseindex--; 485 if (parseindex >= 0) 486 return (c); 487 } 488 if (pushback_index < MAXPUSHBACK-1) 489 return (pushback_buffer[pushback_index++] = c); 490 else 491 return (EOF); 492 } 493 494 int 495 findeol(void) 496 { 497 int c; 498 499 parsebuf = NULL; 500 501 /* skip to either EOF or the first real EOL */ 502 while (1) { 503 if (pushback_index) 504 c = pushback_buffer[--pushback_index]; 505 else 506 c = lgetc(0); 507 if (c == '\n') { 508 file->lineno++; 509 break; 510 } 511 if (c == EOF) 512 break; 513 } 514 return (ERROR); 515 } 516 517 int 518 yylex(void) 519 { 520 char buf[8096]; 521 char *p, *val; 522 int quotec, next, c; 523 int token; 524 525 top: 526 p = buf; 527 while ((c = lgetc(0)) == ' ' || c == '\t') 528 ; /* nothing */ 529 530 yylval.lineno = file->lineno; 531 if (c == '#') 532 while ((c = lgetc(0)) != '\n' && c != EOF) 533 ; /* nothing */ 534 if (c == '$' && parsebuf == NULL) { 535 while (1) { 536 if ((c = lgetc(0)) == EOF) 537 return (0); 538 539 if (p + 1 >= buf + sizeof(buf) - 1) { 540 yyerror("string too long"); 541 return (findeol()); 542 } 543 if (isalnum(c) || c == '_') { 544 *p++ = (char)c; 545 continue; 546 } 547 *p = '\0'; 548 lungetc(c); 549 break; 550 } 551 val = symget(buf); 552 if (val == NULL) { 553 yyerror("macro '%s' not defined", buf); 554 return (findeol()); 555 } 556 parsebuf = val; 557 parseindex = 0; 558 goto top; 559 } 560 561 switch (c) { 562 case '\'': 563 case '"': 564 quotec = c; 565 while (1) { 566 if ((c = lgetc(quotec)) == EOF) 567 return (0); 568 if (c == '\n') { 569 file->lineno++; 570 continue; 571 } else if (c == '\\') { 572 if ((next = lgetc(quotec)) == EOF) 573 return (0); 574 if (next == quotec || c == ' ' || c == '\t') 575 c = next; 576 else if (next == '\n') 577 continue; 578 else 579 lungetc(next); 580 } else if (c == quotec) { 581 *p = '\0'; 582 break; 583 } 584 if (p + 1 >= buf + sizeof(buf) - 1) { 585 yyerror("string too long"); 586 return (findeol()); 587 } 588 *p++ = (char)c; 589 } 590 yylval.v.string = strdup(buf); 591 if (yylval.v.string == NULL) 592 err(1, "yylex: strdup"); 593 return (STRING); 594 } 595 596 #define allowed_to_end_number(x) \ 597 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 598 599 if (c == '-' || isdigit(c)) { 600 do { 601 *p++ = c; 602 if ((unsigned)(p-buf) >= sizeof(buf)) { 603 yyerror("string too long"); 604 return (findeol()); 605 } 606 } while ((c = lgetc(0)) != EOF && isdigit(c)); 607 lungetc(c); 608 if (p == buf + 1 && buf[0] == '-') 609 goto nodigits; 610 if (c == EOF || allowed_to_end_number(c)) { 611 const char *errstr = NULL; 612 613 *p = '\0'; 614 yylval.v.number = strtonum(buf, LLONG_MIN, 615 LLONG_MAX, &errstr); 616 if (errstr) { 617 yyerror("\"%s\" invalid number: %s", 618 buf, errstr); 619 return (findeol()); 620 } 621 return (NUMBER); 622 } else { 623 nodigits: 624 while (p > buf + 1) 625 lungetc(*--p); 626 c = *--p; 627 if (c == '-') 628 return (c); 629 } 630 } 631 632 #define allowed_in_string(x) \ 633 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 634 x != '{' && x != '}' && \ 635 x != '!' && x != '=' && x != '#' && \ 636 x != ',')) 637 638 if (isalnum(c) || c == ':' || c == '_') { 639 do { 640 *p++ = c; 641 if ((unsigned)(p-buf) >= sizeof(buf)) { 642 yyerror("string too long"); 643 return (findeol()); 644 } 645 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 646 lungetc(c); 647 *p = '\0'; 648 if ((token = lookup(buf)) == STRING) 649 if ((yylval.v.string = strdup(buf)) == NULL) 650 err(1, "yylex: strdup"); 651 return (token); 652 } 653 if (c == '\n') { 654 yylval.lineno = file->lineno; 655 file->lineno++; 656 } 657 if (c == EOF) 658 return (0); 659 return (c); 660 } 661 662 int 663 check_file_secrecy(int fd, const char *fname) 664 { 665 struct stat st; 666 667 if (fstat(fd, &st)) { 668 log_warn("cannot stat %s", fname); 669 return (-1); 670 } 671 if (st.st_uid != 0 && st.st_uid != getuid()) { 672 log_warnx("%s: owner not root or current user", fname); 673 return (-1); 674 } 675 if (st.st_mode & (S_IRWXG | S_IRWXO)) { 676 log_warnx("%s: group/world readable/writeable", fname); 677 return (-1); 678 } 679 return (0); 680 } 681 682 struct file * 683 pushfile(const char *name, int secret) 684 { 685 struct file *nfile; 686 687 if ((nfile = calloc(1, sizeof(struct file))) == NULL) { 688 log_warn("malloc"); 689 return (NULL); 690 } 691 if ((nfile->name = strdup(name)) == NULL) { 692 log_warn("malloc"); 693 free(nfile); 694 return (NULL); 695 } 696 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 697 log_warn("%s", nfile->name); 698 free(nfile->name); 699 free(nfile); 700 return (NULL); 701 } else if (secret && 702 check_file_secrecy(fileno(nfile->stream), nfile->name)) { 703 fclose(nfile->stream); 704 free(nfile->name); 705 free(nfile); 706 return (NULL); 707 } 708 nfile->lineno = 1; 709 TAILQ_INSERT_TAIL(&files, nfile, entry); 710 return (nfile); 711 } 712 713 int 714 popfile(void) 715 { 716 struct file *prev; 717 718 if ((prev = TAILQ_PREV(file, files, entry)) != NULL) 719 prev->errors += file->errors; 720 721 TAILQ_REMOVE(&files, file, entry); 722 fclose(file->stream); 723 free(file->name); 724 free(file); 725 file = prev; 726 return (file ? 0 : EOF); 727 } 728 729 struct ripd_conf * 730 parse_config(char *filename, int opts) 731 { 732 struct sym *sym, *next; 733 734 if ((conf = calloc(1, sizeof(struct ripd_conf))) == NULL) 735 fatal("parse_config"); 736 737 bzero(&globaldefs, sizeof(globaldefs)); 738 defs = &globaldefs; 739 TAILQ_INIT(&defs->md_list); 740 defs->cost = DEFAULT_COST; 741 defs->auth_type = AUTH_NONE; 742 conf->opts = opts; 743 SIMPLEQ_INIT(&conf->redist_list); 744 745 if ((file = pushfile(filename, !(conf->opts & RIPD_OPT_NOACTION))) == NULL) { 746 free(conf); 747 return (NULL); 748 } 749 topfile = file; 750 751 yyparse(); 752 errors = file->errors; 753 popfile(); 754 755 /* Free macros and check which have not been used. */ 756 for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) { 757 next = TAILQ_NEXT(sym, entry); 758 if ((conf->opts & RIPD_OPT_VERBOSE2) && !sym->used) 759 fprintf(stderr, "warning: macro '%s' not " 760 "used\n", sym->nam); 761 if (!sym->persist) { 762 free(sym->nam); 763 free(sym->val); 764 TAILQ_REMOVE(&symhead, sym, entry); 765 free(sym); 766 } 767 } 768 769 /* free global config defaults */ 770 md_list_clr(&globaldefs.md_list); 771 772 if (errors) { 773 clear_config(conf); 774 return (NULL); 775 } 776 777 return (conf); 778 } 779 780 int 781 symset(const char *nam, const char *val, int persist) 782 { 783 struct sym *sym; 784 785 for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); 786 sym = TAILQ_NEXT(sym, entry)) 787 ; /* nothing */ 788 789 if (sym != NULL) { 790 if (sym->persist == 1) 791 return (0); 792 else { 793 free(sym->nam); 794 free(sym->val); 795 TAILQ_REMOVE(&symhead, sym, entry); 796 free(sym); 797 } 798 } 799 if ((sym = calloc(1, sizeof(*sym))) == NULL) 800 return (-1); 801 802 sym->nam = strdup(nam); 803 if (sym->nam == NULL) { 804 free(sym); 805 return (-1); 806 } 807 sym->val = strdup(val); 808 if (sym->val == NULL) { 809 free(sym->nam); 810 free(sym); 811 return (-1); 812 } 813 sym->used = 0; 814 sym->persist = persist; 815 TAILQ_INSERT_TAIL(&symhead, sym, entry); 816 return (0); 817 } 818 819 int 820 cmdline_symset(char *s) 821 { 822 char *sym, *val; 823 int ret; 824 size_t len; 825 826 if ((val = strrchr(s, '=')) == NULL) 827 return (-1); 828 829 len = strlen(s) - strlen(val) + 1; 830 if ((sym = malloc(len)) == NULL) 831 errx(1, "cmdline_symset: malloc"); 832 833 strlcpy(sym, s, len); 834 835 ret = symset(sym, val + 1, 1); 836 free(sym); 837 838 return (ret); 839 } 840 841 char * 842 symget(const char *nam) 843 { 844 struct sym *sym; 845 846 TAILQ_FOREACH(sym, &symhead, entry) 847 if (strcmp(nam, sym->nam) == 0) { 848 sym->used = 1; 849 return (sym->val); 850 } 851 return (NULL); 852 } 853 854 struct iface * 855 conf_get_if(struct kif *kif) 856 { 857 struct iface *i; 858 859 LIST_FOREACH(i, &conf->iface_list, entry) 860 if (i->ifindex == kif->ifindex) { 861 yyerror("interface %s already configured", 862 kif->ifname); 863 return (NULL); 864 } 865 866 i = if_new(kif); 867 i->auth_keyid = 1; 868 i->passive = 0; 869 870 return (i); 871 } 872 873 void 874 clear_config(struct ripd_conf *xconf) 875 { 876 struct iface *i; 877 878 while ((i = LIST_FIRST(&conf->iface_list)) != NULL) { 879 LIST_REMOVE(i, entry); 880 if_del(i); 881 } 882 883 free(xconf); 884 } 885 886 int 887 host(const char *s, struct in_addr *addr, struct in_addr *mask) 888 { 889 struct in_addr ina; 890 int bits = 32; 891 892 bzero(&ina, sizeof(struct in_addr)); 893 if (strrchr(s, '/') != NULL) { 894 if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1) 895 return (0); 896 } else { 897 if (inet_pton(AF_INET, s, &ina) != 1) 898 return (0); 899 } 900 901 addr->s_addr = ina.s_addr; 902 mask->s_addr = prefixlen2mask(bits); 903 904 return (1); 905 } 906