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