parse.y revision 1.11
1/* $OpenBSD: parse.y,v 1.11 2013/06/01 18:30:32 claudio 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 47TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); 48static struct file { 49 TAILQ_ENTRY(file) entry; 50 FILE *stream; 51 char *name; 52 int lineno; 53 int errors; 54} *file, *topfile; 55struct file *pushfile(const char *, int); 56int popfile(void); 57int check_file_secrecy(int, const char *); 58int yyparse(void); 59int yylex(void); 60int yyerror(const char *, ...); 61int kw_cmp(const void *, const void *); 62int lookup(char *); 63int lgetc(int); 64int lungetc(int); 65int findeol(void); 66 67TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); 68struct sym { 69 TAILQ_ENTRY(sym) entry; 70 int used; 71 int persist; 72 char *nam; 73 char *val; 74}; 75 76int symset(const char *, const char *, int); 77char *symget(const char *); 78 79void clear_config(struct ldpd_conf *xconf); 80u_int32_t get_rtr_id(void); 81int host(const char *, struct in_addr *, struct in_addr *); 82 83static struct ldpd_conf *conf; 84static int errors = 0; 85 86struct iface *iface = NULL; 87 88struct config_defaults { 89 u_int16_t holdtime; 90 u_int16_t keepalive; 91 u_int16_t hello_interval; 92 u_int8_t mode; 93}; 94 95struct config_defaults globaldefs; 96struct config_defaults lspacedefs; 97struct config_defaults ifacedefs; 98struct config_defaults *defs; 99 100struct iface *conf_get_if(struct kif *, struct kif_addr *); 101 102typedef struct { 103 union { 104 int64_t number; 105 char *string; 106 } v; 107 int lineno; 108} YYSTYPE; 109 110%} 111 112%token LSPACE INTERFACE ROUTERID FIBUPDATE 113%token HOLDTIME HELLOINTERVAL KEEPALIVE 114%token DISTRIBUTION RETENTION ADVERTISEMENT 115%token EXTTAG PASSIVE 116%token HELLOINTERVAL 117%token YES NO 118%token ERROR 119%token <v.string> STRING 120%token <v.number> NUMBER 121%type <v.number> yesno 122%type <v.string> string 123 124%% 125 126grammar : /* empty */ 127 | grammar '\n' 128 | grammar conf_main '\n' 129 | grammar varset '\n' 130 | grammar interface '\n' 131 | grammar error '\n' { file->errors++; } 132 ; 133 134string : string STRING { 135 if (asprintf(&$$, "%s %s", $1, $2) == -1) { 136 free($1); 137 free($2); 138 yyerror("string: asprintf"); 139 YYERROR; 140 } 141 free($1); 142 free($2); 143 } 144 | STRING 145 ; 146 147yesno : YES { $$ = 1; } 148 | NO { $$ = 0; } 149 ; 150 151varset : STRING '=' string { 152 if (conf->opts & LDPD_OPT_VERBOSE) 153 printf("%s = \"%s\"\n", $1, $3); 154 if (symset($1, $3, 0) == -1) 155 fatal("cannot store variable"); 156 free($1); 157 free($3); 158 } 159 ; 160 161conf_main : ROUTERID STRING { 162 if (!inet_aton($2, &conf->rtr_id)) { 163 yyerror("error parsing router-id"); 164 free($2); 165 YYERROR; 166 } 167 free($2); 168 } 169 | FIBUPDATE yesno { 170 if ($2 == 0) 171 conf->flags |= LDPD_FLAG_NO_FIB_UPDATE; 172 else 173 conf->flags &= ~LDPD_FLAG_NO_FIB_UPDATE; 174 } 175 | DISTRIBUTION STRING { 176 conf->mode &= ~(MODE_DIST_INDEPENDENT | 177 MODE_DIST_ORDERED); 178 179 if (!strcmp($2, "independent")) 180 conf->mode |= MODE_DIST_INDEPENDENT; 181 else if (!strcmp($2, "ordered")) 182 conf->mode |= MODE_DIST_ORDERED; 183 else { 184 yyerror("unknown distribution type"); 185 free($2); 186 YYERROR; 187 } 188 } 189 | RETENTION STRING { 190 conf->mode &= ~(MODE_RET_CONSERVATIVE | 191 MODE_RET_LIBERAL); 192 193 if (!strcmp($2, "conservative")) 194 conf->mode |= MODE_RET_CONSERVATIVE; 195 else if (!strcmp($2, "liberal")) 196 conf->mode |= MODE_RET_LIBERAL; 197 else { 198 yyerror("unknown retention type"); 199 free($2); 200 YYERROR; 201 } 202 } 203 | ADVERTISEMENT STRING { 204 conf->mode &= ~(MODE_ADV_ONDEMAND | 205 MODE_ADV_UNSOLICITED); 206 207 if (!strcmp($2, "ondemand")) 208 conf->mode |= MODE_ADV_ONDEMAND; 209 else if (!strcmp($2, "unsolicited")) 210 conf->mode |= MODE_ADV_UNSOLICITED; 211 else { 212 yyerror("unknown retention type"); 213 free($2); 214 YYERROR; 215 } 216 } 217 | defaults 218 ; 219defaults : HOLDTIME NUMBER { 220 if ($2 < MIN_HOLDTIME || 221 $2 > MAX_HOLDTIME) { 222 yyerror("holdtime out of range (%d-%d)", 223 MIN_HOLDTIME, MAX_HOLDTIME); 224 YYERROR; 225 } 226 defs->holdtime = $2; 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 defs->keepalive = $2; 236 } 237 | HELLOINTERVAL NUMBER { 238 if ($2 < MIN_HELLO_INTERVAL || 239 $2 > MAX_HELLO_INTERVAL) { 240 yyerror("hello-interval out of range (%d-%d)", 241 MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL); 242 YYERROR; 243 } 244 defs->hello_interval = $2; 245 } 246 ; 247 248optnl : '\n' optnl 249 | 250 ; 251 252nl : '\n' optnl /* one newline or more */ 253 ; 254 255interface : INTERFACE STRING { 256 struct kif *kif; 257 struct kif_addr *ka = NULL; 258 char *s; 259 struct in_addr addr; 260 261 s = strchr($2, ':'); 262 if (s) { 263 *s++ = '\0'; 264 if (inet_aton(s, &addr) == 0) { 265 yyerror( 266 "error parsing interface address"); 267 free($2); 268 YYERROR; 269 } 270 } else 271 addr.s_addr = 0; 272 273 if ((kif = kif_findname($2, addr, &ka)) == NULL) { 274 yyerror("unknown interface %s", $2); 275 free($2); 276 YYERROR; 277 } 278 if (ka == NULL) { 279 if (s) 280 yyerror("address %s not configured on " 281 "interface %s", s, $2); 282 else 283 yyerror("unnumbered interface %s", $2); 284 free($2); 285 YYERROR; 286 } 287 free($2); 288 iface = conf_get_if(kif, ka); 289 if (iface == NULL) 290 YYERROR; 291 if (iface->media_type == IFT_LOOP || 292 iface->media_type == IFT_CARP) { 293 yyerror("unsupported interface type on " 294 "interface %s", iface->name); 295 YYERROR; 296 } 297 LIST_INSERT_HEAD(&conf->iface_list, iface, entry); 298 299 memcpy(&ifacedefs, defs, sizeof(ifacedefs)); 300 defs = &ifacedefs; 301 } interface_block { 302 iface->holdtime = defs->holdtime; 303 iface->keepalive = defs->keepalive; 304 iface->hello_interval = defs->hello_interval; 305 iface = NULL; 306 307 defs = &globaldefs; 308 } 309 ; 310 311interface_block : '{' optnl interfaceopts_l '}' 312 | '{' optnl '}' 313 | /* nothing */ 314 ; 315 316interfaceopts_l : interfaceopts_l interfaceoptsl nl 317 | interfaceoptsl optnl 318 ; 319 320interfaceoptsl : PASSIVE { iface->passive = 1; } 321 | defaults 322 ; 323 324%% 325 326struct keywords { 327 const char *k_name; 328 int k_val; 329}; 330 331int 332yyerror(const char *fmt, ...) 333{ 334 va_list ap; 335 char *nfmt; 336 337 file->errors++; 338 va_start(ap, fmt); 339 if (asprintf(&nfmt, "%s:%d: %s", file->name, yylval.lineno, fmt) == -1) 340 fatalx("yyerror asprintf"); 341 vlog(LOG_CRIT, nfmt, ap); 342 va_end(ap); 343 free(nfmt); 344 return (0); 345} 346 347int 348kw_cmp(const void *k, const void *e) 349{ 350 return (strcmp(k, ((const struct keywords *)e)->k_name)); 351} 352 353int 354lookup(char *s) 355{ 356 /* this has to be sorted always */ 357 static const struct keywords keywords[] = { 358 {"advertisement", ADVERTISEMENT}, 359 {"distribution", DISTRIBUTION}, 360 {"external-tag", EXTTAG}, 361 {"fib-update", FIBUPDATE}, 362 {"hello-interval", HELLOINTERVAL}, 363 {"holdtime", HOLDTIME}, 364 {"interface", INTERFACE}, 365 {"keepalive", KEEPALIVE}, 366 {"labelspace", LSPACE}, 367 {"passive", PASSIVE}, 368 {"retention", RETENTION}, 369 {"router-id", ROUTERID}, 370 {"yes", YES} 371 }; 372 const struct keywords *p; 373 374 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 375 sizeof(keywords[0]), kw_cmp); 376 377 if (p) 378 return (p->k_val); 379 else 380 return (STRING); 381} 382 383#define MAXPUSHBACK 128 384 385char *parsebuf; 386int parseindex; 387char pushback_buffer[MAXPUSHBACK]; 388int pushback_index = 0; 389 390int 391lgetc(int quotec) 392{ 393 int c, next; 394 395 if (parsebuf) { 396 /* Read character from the parsebuffer instead of input. */ 397 if (parseindex >= 0) { 398 c = parsebuf[parseindex++]; 399 if (c != '\0') 400 return (c); 401 parsebuf = NULL; 402 } else 403 parseindex++; 404 } 405 406 if (pushback_index) 407 return (pushback_buffer[--pushback_index]); 408 409 if (quotec) { 410 if ((c = getc(file->stream)) == EOF) { 411 yyerror("reached end of file while parsing " 412 "quoted string"); 413 if (file == topfile || popfile() == EOF) 414 return (EOF); 415 return (quotec); 416 } 417 return (c); 418 } 419 420 while ((c = getc(file->stream)) == '\\') { 421 next = getc(file->stream); 422 if (next != '\n') { 423 c = next; 424 break; 425 } 426 yylval.lineno = file->lineno; 427 file->lineno++; 428 } 429 430 while (c == EOF) { 431 if (file == topfile || popfile() == EOF) 432 return (EOF); 433 c = getc(file->stream); 434 } 435 return (c); 436} 437 438int 439lungetc(int c) 440{ 441 if (c == EOF) 442 return (EOF); 443 if (parsebuf) { 444 parseindex--; 445 if (parseindex >= 0) 446 return (c); 447 } 448 if (pushback_index < MAXPUSHBACK-1) 449 return (pushback_buffer[pushback_index++] = c); 450 else 451 return (EOF); 452} 453 454int 455findeol(void) 456{ 457 int c; 458 459 parsebuf = NULL; 460 pushback_index = 0; 461 462 /* skip to either EOF or the first real EOL */ 463 while (1) { 464 c = lgetc(0); 465 if (c == '\n') { 466 file->lineno++; 467 break; 468 } 469 if (c == EOF) 470 break; 471 } 472 return (ERROR); 473} 474 475int 476yylex(void) 477{ 478 char buf[8096]; 479 char *p, *val; 480 int quotec, next, c; 481 int token; 482 483top: 484 p = buf; 485 while ((c = lgetc(0)) == ' ' || c == '\t') 486 ; /* nothing */ 487 488 yylval.lineno = file->lineno; 489 if (c == '#') 490 while ((c = lgetc(0)) != '\n' && c != EOF) 491 ; /* nothing */ 492 if (c == '$' && parsebuf == NULL) { 493 while (1) { 494 if ((c = lgetc(0)) == EOF) 495 return (0); 496 497 if (p + 1 >= buf + sizeof(buf) - 1) { 498 yyerror("string too long"); 499 return (findeol()); 500 } 501 if (isalnum(c) || c == '_') { 502 *p++ = (char)c; 503 continue; 504 } 505 *p = '\0'; 506 lungetc(c); 507 break; 508 } 509 val = symget(buf); 510 if (val == NULL) { 511 yyerror("macro '%s' not defined", buf); 512 return (findeol()); 513 } 514 parsebuf = val; 515 parseindex = 0; 516 goto top; 517 } 518 519 switch (c) { 520 case '\'': 521 case '"': 522 quotec = c; 523 while (1) { 524 if ((c = lgetc(quotec)) == EOF) 525 return (0); 526 if (c == '\n') { 527 file->lineno++; 528 continue; 529 } else if (c == '\\') { 530 if ((next = lgetc(quotec)) == EOF) 531 return (0); 532 if (next == quotec || c == ' ' || c == '\t') 533 c = next; 534 else if (next == '\n') { 535 file->lineno++; 536 continue; 537 } else 538 lungetc(next); 539 } else if (c == quotec) { 540 *p = '\0'; 541 break; 542 } 543 if (p + 1 >= buf + sizeof(buf) - 1) { 544 yyerror("string too long"); 545 return (findeol()); 546 } 547 *p++ = (char)c; 548 } 549 yylval.v.string = strdup(buf); 550 if (yylval.v.string == NULL) 551 err(1, "yylex: strdup"); 552 return (STRING); 553 } 554 555#define allowed_to_end_number(x) \ 556 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 557 558 if (c == '-' || isdigit(c)) { 559 do { 560 *p++ = c; 561 if ((unsigned)(p-buf) >= sizeof(buf)) { 562 yyerror("string too long"); 563 return (findeol()); 564 } 565 } while ((c = lgetc(0)) != EOF && isdigit(c)); 566 lungetc(c); 567 if (p == buf + 1 && buf[0] == '-') 568 goto nodigits; 569 if (c == EOF || allowed_to_end_number(c)) { 570 const char *errstr = NULL; 571 572 *p = '\0'; 573 yylval.v.number = strtonum(buf, LLONG_MIN, 574 LLONG_MAX, &errstr); 575 if (errstr) { 576 yyerror("\"%s\" invalid number: %s", 577 buf, errstr); 578 return (findeol()); 579 } 580 return (NUMBER); 581 } else { 582nodigits: 583 while (p > buf + 1) 584 lungetc(*--p); 585 c = *--p; 586 if (c == '-') 587 return (c); 588 } 589 } 590 591#define allowed_in_string(x) \ 592 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 593 x != '{' && x != '}' && \ 594 x != '!' && x != '=' && x != '#' && \ 595 x != ',')) 596 597 if (isalnum(c) || c == ':' || c == '_') { 598 do { 599 *p++ = c; 600 if ((unsigned)(p-buf) >= sizeof(buf)) { 601 yyerror("string too long"); 602 return (findeol()); 603 } 604 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 605 lungetc(c); 606 *p = '\0'; 607 if ((token = lookup(buf)) == STRING) 608 if ((yylval.v.string = strdup(buf)) == NULL) 609 err(1, "yylex: strdup"); 610 return (token); 611 } 612 if (c == '\n') { 613 yylval.lineno = file->lineno; 614 file->lineno++; 615 } 616 if (c == EOF) 617 return (0); 618 return (c); 619} 620 621int 622check_file_secrecy(int fd, const char *fname) 623{ 624 struct stat st; 625 626 if (fstat(fd, &st)) { 627 log_warn("cannot stat %s", fname); 628 return (-1); 629 } 630 if (st.st_uid != 0 && st.st_uid != getuid()) { 631 log_warnx("%s: owner not root or current user", fname); 632 return (-1); 633 } 634 if (st.st_mode & (S_IRWXG | S_IRWXO)) { 635 log_warnx("%s: group/world readable/writeable", fname); 636 return (-1); 637 } 638 return (0); 639} 640 641struct file * 642pushfile(const char *name, int secret) 643{ 644 struct file *nfile; 645 646 if ((nfile = calloc(1, sizeof(struct file))) == NULL) { 647 log_warn("malloc"); 648 return (NULL); 649 } 650 if ((nfile->name = strdup(name)) == NULL) { 651 log_warn("strdup"); 652 free(nfile); 653 return (NULL); 654 } 655 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 656 log_warn("%s", nfile->name); 657 free(nfile->name); 658 free(nfile); 659 return (NULL); 660 } else if (secret && 661 check_file_secrecy(fileno(nfile->stream), nfile->name)) { 662 fclose(nfile->stream); 663 free(nfile->name); 664 free(nfile); 665 return (NULL); 666 } 667 nfile->lineno = 1; 668 TAILQ_INSERT_TAIL(&files, nfile, entry); 669 return (nfile); 670} 671 672int 673popfile(void) 674{ 675 struct file *prev; 676 677 if ((prev = TAILQ_PREV(file, files, entry)) != NULL) 678 prev->errors += file->errors; 679 680 TAILQ_REMOVE(&files, file, entry); 681 fclose(file->stream); 682 free(file->name); 683 free(file); 684 file = prev; 685 return (file ? 0 : EOF); 686} 687 688struct ldpd_conf * 689parse_config(char *filename, int opts) 690{ 691 struct sym *sym, *next; 692 693 if ((conf = calloc(1, sizeof(struct ldpd_conf))) == NULL) 694 fatal("parse_config"); 695 conf->opts = opts; 696 697 bzero(&globaldefs, sizeof(globaldefs)); 698 defs = &globaldefs; 699 defs->holdtime = DEFAULT_HOLDTIME; 700 defs->keepalive = DEFAULT_KEEPALIVE; 701 defs->hello_interval = DEFAULT_HELLO_INTERVAL; 702 703 conf->mode = (MODE_DIST_INDEPENDENT | MODE_RET_LIBERAL | 704 MODE_ADV_UNSOLICITED); 705 706 if ((file = pushfile(filename, !(conf->opts & LDPD_OPT_NOACTION))) == NULL) { 707 free(conf); 708 return (NULL); 709 } 710 topfile = file; 711 712 yyparse(); 713 errors = file->errors; 714 popfile(); 715 716 /* Free macros and check which have not been used. */ 717 for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) { 718 next = TAILQ_NEXT(sym, entry); 719 if ((conf->opts & LDPD_OPT_VERBOSE2) && !sym->used) 720 fprintf(stderr, "warning: macro '%s' not " 721 "used\n", sym->nam); 722 if (!sym->persist) { 723 free(sym->nam); 724 free(sym->val); 725 TAILQ_REMOVE(&symhead, sym, entry); 726 free(sym); 727 } 728 } 729 730 /* free global config defaults */ 731 if (errors) { 732 clear_config(conf); 733 return (NULL); 734 } 735 736 if (conf->rtr_id.s_addr == 0) 737 conf->rtr_id.s_addr = get_rtr_id(); 738 739 return (conf); 740} 741 742int 743symset(const char *nam, const char *val, int persist) 744{ 745 struct sym *sym; 746 747 for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); 748 sym = TAILQ_NEXT(sym, entry)) 749 ; /* nothing */ 750 751 if (sym != NULL) { 752 if (sym->persist == 1) 753 return (0); 754 else { 755 free(sym->nam); 756 free(sym->val); 757 TAILQ_REMOVE(&symhead, sym, entry); 758 free(sym); 759 } 760 } 761 if ((sym = calloc(1, sizeof(*sym))) == NULL) 762 return (-1); 763 764 sym->nam = strdup(nam); 765 if (sym->nam == NULL) { 766 free(sym); 767 return (-1); 768 } 769 sym->val = strdup(val); 770 if (sym->val == NULL) { 771 free(sym->nam); 772 free(sym); 773 return (-1); 774 } 775 sym->used = 0; 776 sym->persist = persist; 777 TAILQ_INSERT_TAIL(&symhead, sym, entry); 778 return (0); 779} 780 781int 782cmdline_symset(char *s) 783{ 784 char *sym, *val; 785 int ret; 786 size_t len; 787 788 if ((val = strrchr(s, '=')) == NULL) 789 return (-1); 790 791 len = strlen(s) - strlen(val) + 1; 792 if ((sym = malloc(len)) == NULL) 793 errx(1, "cmdline_symset: malloc"); 794 795 strlcpy(sym, s, len); 796 797 ret = symset(sym, val + 1, 1); 798 free(sym); 799 800 return (ret); 801} 802 803char * 804symget(const char *nam) 805{ 806 struct sym *sym; 807 808 TAILQ_FOREACH(sym, &symhead, entry) 809 if (strcmp(nam, sym->nam) == 0) { 810 sym->used = 1; 811 return (sym->val); 812 } 813 return (NULL); 814} 815 816struct iface * 817conf_get_if(struct kif *kif, struct kif_addr *ka) 818{ 819 struct iface *i; 820 821 LIST_FOREACH(i, &conf->iface_list, entry) { 822 if (i->ifindex == kif->ifindex && 823 i->addr.s_addr == ka->addr.s_addr) { 824 yyerror("interface %s already configured", 825 kif->ifname); 826 return (NULL); 827 } 828 } 829 830 i = if_new(kif, ka); 831 832 return (i); 833} 834 835void 836clear_config(struct ldpd_conf *xconf) 837{ 838 struct iface *i; 839 840 while ((i = LIST_FIRST(&conf->iface_list)) != NULL) { 841 LIST_REMOVE(i, entry); 842 if_del(i); 843 } 844 845 free(xconf); 846} 847 848u_int32_t 849get_rtr_id(void) 850{ 851 struct ifaddrs *ifap, *ifa; 852 u_int32_t ip = 0, cur, localnet; 853 854 localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET); 855 856 if (getifaddrs(&ifap) == -1) 857 fatal("getifaddrs"); 858 859 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 860 if (strncmp(ifa->ifa_name, "carp", 4) == 0) 861 continue; 862 if (ifa->ifa_addr->sa_family != AF_INET) 863 continue; 864 cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; 865 if ((cur & localnet) == localnet) /* skip 127/8 */ 866 continue; 867 if (cur > ip || ip == 0) 868 ip = cur; 869 } 870 freeifaddrs(ifap); 871 872 if (ip == 0) 873 fatal("router-id is 0.0.0.0"); 874 875 return (ip); 876} 877 878int 879host(const char *s, struct in_addr *addr, struct in_addr *mask) 880{ 881 struct in_addr ina; 882 int bits = 32; 883 884 bzero(&ina, sizeof(struct in_addr)); 885 if (strrchr(s, '/') != NULL) { 886 if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1) 887 return (0); 888 } else { 889 if (inet_pton(AF_INET, s, &ina) != 1) 890 return (0); 891 } 892 893 addr->s_addr = ina.s_addr; 894 mask->s_addr = prefixlen2mask(bits); 895 896 return (1); 897} 898