parse.y revision 1.63
1/* $OpenBSD: parse.y,v 1.63 2018/06/11 09:34:46 denis Exp $ */ 2 3/* 4 * Copyright (c) 2013, 2015, 2016 Renato Westphal <renato@openbsd.org> 5 * Copyright (c) 2004, 2005, 2008 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/stat.h> 27#include <arpa/inet.h> 28#include <ctype.h> 29#include <err.h> 30#include <unistd.h> 31#include <ifaddrs.h> 32#include <net/if_types.h> 33#include <limits.h> 34#include <stdio.h> 35#include <syslog.h> 36 37#include "ldpd.h" 38#include "ldpe.h" 39#include "lde.h" 40#include "log.h" 41 42struct file { 43 TAILQ_ENTRY(file) entry; 44 FILE *stream; 45 char *name; 46 size_t ungetpos; 47 size_t ungetsize; 48 u_char *ungetbuf; 49 int eof_reached; 50 int lineno; 51 int errors; 52}; 53TAILQ_HEAD(files, file); 54 55struct sym { 56 TAILQ_ENTRY(sym) entry; 57 int used; 58 int persist; 59 char *nam; 60 char *val; 61}; 62TAILQ_HEAD(symhead, sym); 63 64struct config_defaults { 65 uint16_t keepalive; 66 uint16_t lhello_holdtime; 67 uint16_t lhello_interval; 68 uint16_t thello_holdtime; 69 uint16_t thello_interval; 70 union ldpd_addr trans_addr; 71 int afflags; 72 uint8_t pwflags; 73}; 74 75typedef struct { 76 union { 77 int64_t number; 78 char *string; 79 } v; 80 int lineno; 81} YYSTYPE; 82 83static int yyerror(const char *, ...) 84 __attribute__((__format__ (printf, 1, 2))) 85 __attribute__((__nonnull__ (1))); 86static int kw_cmp(const void *, const void *); 87static int lookup(char *); 88static int igetc(void); 89static int lgetc(int); 90void lungetc(int); 91static int findeol(void); 92static int yylex(void); 93static int check_file_secrecy(int, const char *); 94static struct file *pushfile(const char *, int); 95static int popfile(void); 96static int yyparse(void); 97static int symset(const char *, const char *, int); 98static char *symget(const char *); 99static struct iface *conf_get_if(struct kif *); 100static struct tnbr *conf_get_tnbr(union ldpd_addr *); 101static struct nbr_params *conf_get_nbrp(struct in_addr); 102static struct l2vpn *conf_get_l2vpn(char *); 103static struct l2vpn_if *conf_get_l2vpn_if(struct l2vpn *, struct kif *); 104static struct l2vpn_pw *conf_get_l2vpn_pw(struct l2vpn *, struct kif *); 105int conf_check_rdomain(unsigned int); 106static void clear_config(struct ldpd_conf *xconf); 107static uint32_t get_rtr_id(void); 108static int get_address(const char *, union ldpd_addr *); 109static int get_af_address(const char *, int *, union ldpd_addr *); 110 111static struct file *file, *topfile; 112static struct files files = TAILQ_HEAD_INITIALIZER(files); 113static struct symhead symhead = TAILQ_HEAD_INITIALIZER(symhead); 114static struct ldpd_conf *conf; 115static int errors; 116 117static int af; 118static struct ldpd_af_conf *af_conf; 119static struct iface *iface; 120static struct iface_af *ia; 121static struct tnbr *tnbr; 122static struct nbr_params *nbrp; 123static struct l2vpn *l2vpn; 124static struct l2vpn_pw *pw; 125 126static struct config_defaults globaldefs; 127static struct config_defaults afdefs; 128static struct config_defaults ifacedefs; 129static struct config_defaults tnbrdefs; 130static struct config_defaults pwdefs; 131static struct config_defaults *defs; 132 133%} 134 135%token INTERFACE TNEIGHBOR ROUTERID FIBUPDATE RDOMAIN EXPNULL 136%token LHELLOHOLDTIME LHELLOINTERVAL 137%token THELLOHOLDTIME THELLOINTERVAL 138%token THELLOACCEPT AF IPV4 IPV6 GTSMENABLE GTSMHOPS 139%token KEEPALIVE TRANSADDRESS TRANSPREFERENCE DSCISCOINTEROP 140%token NEIGHBOR PASSWORD 141%token L2VPN TYPE VPLS PWTYPE MTU BRIDGE 142%token ETHERNET ETHERNETTAGGED STATUSTLV CONTROLWORD 143%token PSEUDOWIRE NEIGHBORID NEIGHBORADDR PWID 144%token EXTTAG 145%token YES NO 146%token INCLUDE 147%token ERROR 148%token <v.string> STRING 149%token <v.number> NUMBER 150%type <v.number> yesno ldp_af l2vpn_type pw_type 151%type <v.string> string 152 153%% 154 155grammar : /* empty */ 156 | grammar include '\n' 157 | grammar '\n' 158 | grammar conf_main '\n' 159 | grammar varset '\n' 160 | grammar af '\n' 161 | grammar neighbor '\n' 162 | grammar l2vpn '\n' 163 | grammar error '\n' { file->errors++; } 164 ; 165 166include : INCLUDE STRING { 167 struct file *nfile; 168 169 if ((nfile = pushfile($2, 170 !(global.cmd_opts & LDPD_OPT_NOACTION))) == NULL) { 171 yyerror("failed to include file %s", $2); 172 free($2); 173 YYERROR; 174 } 175 free($2); 176 177 file = nfile; 178 lungetc('\n'); 179 } 180 ; 181 182string : string STRING { 183 if (asprintf(&$$, "%s %s", $1, $2) == -1) { 184 free($1); 185 free($2); 186 yyerror("string: asprintf"); 187 YYERROR; 188 } 189 free($1); 190 free($2); 191 } 192 | STRING 193 ; 194 195yesno : YES { $$ = 1; } 196 | NO { $$ = 0; } 197 ; 198 199ldp_af : IPV4 { $$ = AF_INET; } 200 | IPV6 { $$ = AF_INET6; } 201 ; 202 203l2vpn_type : VPLS { $$ = L2VPN_TYPE_VPLS; } 204 ; 205 206pw_type : ETHERNET { $$ = PW_TYPE_ETHERNET; } 207 | ETHERNETTAGGED { $$ = PW_TYPE_ETHERNET_TAGGED; } 208 ; 209 210varset : STRING '=' string { 211 char *s = $1; 212 if (global.cmd_opts & LDPD_OPT_VERBOSE) 213 printf("%s = \"%s\"\n", $1, $3); 214 while (*s++) { 215 if (isspace((unsigned char)*s)) { 216 yyerror("macro name cannot contain " 217 "whitespace"); 218 free($1); 219 free($3); 220 YYERROR; 221 } 222 } 223 if (symset($1, $3, 0) == -1) 224 fatal("cannot store variable"); 225 free($1); 226 free($3); 227 } 228 ; 229 230conf_main : ROUTERID STRING { 231 if (!inet_aton($2, &conf->rtr_id)) { 232 yyerror("error parsing router-id"); 233 free($2); 234 YYERROR; 235 } 236 free($2); 237 if (bad_addr_v4(conf->rtr_id)) { 238 yyerror("invalid router-id"); 239 YYERROR; 240 } 241 } 242 | FIBUPDATE yesno { 243 if ($2 == 0) 244 conf->flags |= F_LDPD_NO_FIB_UPDATE; 245 else 246 conf->flags &= ~F_LDPD_NO_FIB_UPDATE; 247 } 248 | RDOMAIN NUMBER { 249 if ($2 < 0 || $2 > RT_TABLEID_MAX) { 250 yyerror("invalid rdomain"); 251 YYERROR; 252 } 253 conf->rdomain = $2; 254 } 255 | TRANSPREFERENCE ldp_af { 256 conf->trans_pref = $2; 257 258 switch (conf->trans_pref) { 259 case AF_INET: 260 conf->trans_pref = DUAL_STACK_LDPOV4; 261 break; 262 case AF_INET6: 263 conf->trans_pref = DUAL_STACK_LDPOV6; 264 break; 265 default: 266 yyerror("invalid address-family"); 267 YYERROR; 268 } 269 } 270 | DSCISCOINTEROP yesno { 271 if ($2 == 1) 272 conf->flags |= F_LDPD_DS_CISCO_INTEROP; 273 else 274 conf->flags &= ~F_LDPD_DS_CISCO_INTEROP; 275 } 276 | af_defaults 277 | iface_defaults 278 | tnbr_defaults 279 ; 280 281af : AF ldp_af { 282 af = $2; 283 switch (af) { 284 case AF_INET: 285 af_conf = &conf->ipv4; 286 break; 287 case AF_INET6: 288 af_conf = &conf->ipv6; 289 break; 290 default: 291 yyerror("invalid address-family"); 292 YYERROR; 293 } 294 295 afdefs = *defs; 296 defs = &afdefs; 297 } af_block { 298 af_conf->keepalive = defs->keepalive; 299 af_conf->thello_holdtime = defs->thello_holdtime; 300 af_conf->thello_interval = defs->thello_interval; 301 af_conf->flags = defs->afflags; 302 af_conf->flags |= F_LDPD_AF_ENABLED; 303 af_conf = NULL; 304 af = AF_UNSPEC; 305 defs = &globaldefs; 306 } 307 ; 308 309af_block : '{' optnl afopts_l '}' 310 | '{' optnl '}' 311 | 312 ; 313 314afopts_l : afopts_l afoptsl nl 315 | afoptsl optnl 316 ; 317 318afoptsl : TRANSADDRESS STRING { 319 if (get_address($2, &af_conf->trans_addr) == -1) { 320 yyerror("error parsing transport-address"); 321 free($2); 322 YYERROR; 323 } 324 free($2); 325 if (bad_addr(af, &af_conf->trans_addr)) { 326 yyerror("invalid transport-address"); 327 YYERROR; 328 } 329 if (af == AF_INET6 && 330 IN6_IS_SCOPE_EMBED(&af_conf->trans_addr.v6)) { 331 yyerror("ipv6 transport-address can not be " 332 "link-local"); 333 YYERROR; 334 } 335 } 336 | GTSMENABLE yesno { 337 if ($2 == 0) 338 defs->afflags |= F_LDPD_AF_NO_GTSM; 339 } 340 | af_defaults 341 | iface_defaults 342 | tnbr_defaults 343 | interface 344 | tneighbor 345 ; 346 347af_defaults : THELLOACCEPT yesno { 348 if ($2 == 0) 349 defs->afflags &= ~F_LDPD_AF_THELLO_ACCEPT; 350 else 351 defs->afflags |= F_LDPD_AF_THELLO_ACCEPT; 352 } 353 | EXPNULL yesno { 354 if ($2 == 0) 355 defs->afflags &= ~F_LDPD_AF_EXPNULL; 356 else 357 defs->afflags |= F_LDPD_AF_EXPNULL; 358 } 359 | KEEPALIVE NUMBER { 360 if ($2 < MIN_KEEPALIVE || $2 > MAX_KEEPALIVE) { 361 yyerror("keepalive out of range (%d-%d)", 362 MIN_KEEPALIVE, MAX_KEEPALIVE); 363 YYERROR; 364 } 365 defs->keepalive = $2; 366 } 367 ; 368 369iface_defaults : LHELLOHOLDTIME NUMBER { 370 if ($2 < MIN_HOLDTIME || $2 > MAX_HOLDTIME) { 371 yyerror("hello-holdtime out of range (%d-%d)", 372 MIN_HOLDTIME, MAX_HOLDTIME); 373 YYERROR; 374 } 375 defs->lhello_holdtime = $2; 376 } 377 | LHELLOINTERVAL NUMBER { 378 if ($2 < MIN_HELLO_INTERVAL || 379 $2 > MAX_HELLO_INTERVAL) { 380 yyerror("hello-interval out of range (%d-%d)", 381 MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL); 382 YYERROR; 383 } 384 defs->lhello_interval = $2; 385 } 386 ; 387 388tnbr_defaults : THELLOHOLDTIME NUMBER { 389 if ($2 < MIN_HOLDTIME || $2 > MAX_HOLDTIME) { 390 yyerror("hello-holdtime out of range (%d-%d)", 391 MIN_HOLDTIME, MAX_HOLDTIME); 392 YYERROR; 393 } 394 defs->thello_holdtime = $2; 395 } 396 | THELLOINTERVAL NUMBER { 397 if ($2 < MIN_HELLO_INTERVAL || 398 $2 > MAX_HELLO_INTERVAL) { 399 yyerror("hello-interval out of range (%d-%d)", 400 MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL); 401 YYERROR; 402 } 403 defs->thello_interval = $2; 404 } 405 ; 406 407nbr_opts : KEEPALIVE NUMBER { 408 if ($2 < MIN_KEEPALIVE || $2 > MAX_KEEPALIVE) { 409 yyerror("keepalive out of range (%d-%d)", 410 MIN_KEEPALIVE, MAX_KEEPALIVE); 411 YYERROR; 412 } 413 nbrp->keepalive = $2; 414 nbrp->flags |= F_NBRP_KEEPALIVE; 415 } 416 | PASSWORD STRING { 417 if (strlcpy(nbrp->auth.md5key, $2, 418 sizeof(nbrp->auth.md5key)) >= 419 sizeof(nbrp->auth.md5key)) { 420 yyerror("tcp md5sig password too long: max %zu", 421 sizeof(nbrp->auth.md5key) - 1); 422 free($2); 423 YYERROR; 424 } 425 nbrp->auth.md5key_len = strlen($2); 426 nbrp->auth.method = AUTH_MD5SIG; 427 free($2); 428 } 429 | GTSMENABLE yesno { 430 nbrp->flags |= F_NBRP_GTSM; 431 nbrp->gtsm_enabled = $2; 432 } 433 | GTSMHOPS NUMBER { 434 if ($2 < 1 || $2 > 255) { 435 yyerror("invalid number of hops %lld", $2); 436 YYERROR; 437 } 438 nbrp->gtsm_hops = $2; 439 nbrp->flags |= F_NBRP_GTSM_HOPS; 440 } 441 ; 442 443pw_defaults : STATUSTLV yesno { 444 if ($2 == 1) 445 defs->pwflags |= F_PW_STATUSTLV_CONF; 446 else 447 defs->pwflags &= ~F_PW_STATUSTLV_CONF; 448 } 449 | CONTROLWORD yesno { 450 if ($2 == 1) 451 defs->pwflags |= F_PW_CWORD_CONF; 452 else 453 defs->pwflags &= ~F_PW_CWORD_CONF; 454 } 455 ; 456 457pwopts : PWID NUMBER { 458 if ($2 < MIN_PWID_ID || 459 $2 > MAX_PWID_ID) { 460 yyerror("pw-id out of range (%d-%d)", 461 MIN_PWID_ID, MAX_PWID_ID); 462 YYERROR; 463 } 464 465 pw->pwid = $2; 466 } 467 | NEIGHBORID STRING { 468 struct in_addr addr; 469 470 if (!inet_aton($2, &addr)) { 471 yyerror("error parsing neighbor-id"); 472 free($2); 473 YYERROR; 474 } 475 free($2); 476 if (bad_addr_v4(addr)) { 477 yyerror("invalid neighbor-id"); 478 YYERROR; 479 } 480 481 pw->lsr_id = addr; 482 } 483 | NEIGHBORADDR STRING { 484 int family; 485 union ldpd_addr addr; 486 487 if (get_af_address($2, &family, &addr) == -1) { 488 yyerror("error parsing neighbor address"); 489 free($2); 490 YYERROR; 491 } 492 free($2); 493 if (bad_addr(family, &addr)) { 494 yyerror("invalid neighbor address"); 495 YYERROR; 496 } 497 if (family == AF_INET6 && 498 IN6_IS_SCOPE_EMBED(&addr.v6)) { 499 yyerror("neighbor address can not be " 500 "link-local"); 501 YYERROR; 502 } 503 504 pw->af = family; 505 pw->addr = addr; 506 } 507 | pw_defaults 508 ; 509 510pseudowire : PSEUDOWIRE STRING { 511 struct kif *kif; 512 513 if ((kif = kif_findname($2)) == NULL) { 514 yyerror("unknown interface %s", $2); 515 free($2); 516 YYERROR; 517 } 518 free($2); 519 520 if (kif->if_type != IFT_MPLSTUNNEL) { 521 yyerror("unsupported interface type on " 522 "interface %s", kif->ifname); 523 YYERROR; 524 } 525 526 pw = conf_get_l2vpn_pw(l2vpn, kif); 527 if (pw == NULL) 528 YYERROR; 529 530 pwdefs = *defs; 531 defs = &pwdefs; 532 } pw_block { 533 struct l2vpn *l; 534 struct l2vpn_pw *p; 535 536 /* check for errors */ 537 if (pw->pwid == 0) { 538 yyerror("missing pseudowire id"); 539 YYERROR; 540 } 541 if (pw->lsr_id.s_addr == INADDR_ANY) { 542 yyerror("missing pseudowire neighbor-id"); 543 YYERROR; 544 } 545 LIST_FOREACH(l, &conf->l2vpn_list, entry) { 546 LIST_FOREACH(p, &l->pw_list, entry) { 547 if (pw != p && 548 pw->pwid == p->pwid && 549 pw->af == p->af && 550 pw->lsr_id.s_addr == 551 p->lsr_id.s_addr) { 552 yyerror("pseudowire already " 553 "configured"); 554 YYERROR; 555 } 556 } 557 } 558 559 /* 560 * If the neighbor address is not specified, use the 561 * neighbor id. 562 */ 563 if (pw->af == AF_UNSPEC) { 564 pw->af = AF_INET; 565 pw->addr.v4 = pw->lsr_id; 566 } 567 568 pw->flags = defs->pwflags; 569 pw = NULL; 570 defs = &globaldefs; 571 } 572 ; 573 574pw_block : '{' optnl pwopts_l '}' 575 | '{' optnl '}' 576 | /* nothing */ 577 ; 578 579pwopts_l : pwopts_l pwopts nl 580 | pwopts optnl 581 ; 582 583l2vpnopts : PWTYPE pw_type { 584 l2vpn->pw_type = $2; 585 } 586 | MTU NUMBER { 587 if ($2 < MIN_L2VPN_MTU || 588 $2 > MAX_L2VPN_MTU) { 589 yyerror("l2vpn mtu out of range (%d-%d)", 590 MIN_L2VPN_MTU, MAX_L2VPN_MTU); 591 YYERROR; 592 } 593 l2vpn->mtu = $2; 594 } 595 | pw_defaults 596 | BRIDGE STRING { 597 struct l2vpn *l; 598 struct kif *kif; 599 600 if ((kif = kif_findname($2)) == NULL) { 601 yyerror("unknown interface %s", $2); 602 free($2); 603 YYERROR; 604 } 605 free($2); 606 607 if (l2vpn->br_ifindex != 0) { 608 yyerror("bridge interface cannot be " 609 "redefined on l2vpn %s", l2vpn->name); 610 YYERROR; 611 } 612 613 if (kif->if_type != IFT_BRIDGE) { 614 yyerror("unsupported interface type on " 615 "interface %s", kif->ifname); 616 YYERROR; 617 } 618 619 LIST_FOREACH(l, &conf->l2vpn_list, entry) { 620 if (l->br_ifindex == kif->ifindex) { 621 yyerror("bridge %s is already being " 622 "used by l2vpn %s", kif->ifname, 623 l->name); 624 YYERROR; 625 } 626 } 627 628 l2vpn->br_ifindex = kif->ifindex; 629 strlcpy(l2vpn->br_ifname, kif->ifname, 630 sizeof(l2vpn->br_ifname)); 631 } 632 | INTERFACE STRING { 633 struct kif *kif; 634 struct l2vpn_if *lif; 635 636 if ((kif = kif_findname($2)) == NULL) { 637 yyerror("unknown interface %s", $2); 638 free($2); 639 YYERROR; 640 } 641 free($2); 642 643 lif = conf_get_l2vpn_if(l2vpn, kif); 644 if (lif == NULL) 645 YYERROR; 646 } 647 | pseudowire 648 ; 649 650optnl : '\n' optnl 651 | 652 ; 653 654nl : '\n' optnl /* one newline or more */ 655 ; 656 657interface : INTERFACE STRING { 658 struct kif *kif; 659 660 if ((kif = kif_findname($2)) == NULL) { 661 yyerror("unknown interface %s", $2); 662 free($2); 663 YYERROR; 664 } 665 free($2); 666 667 iface = conf_get_if(kif); 668 if (iface == NULL) 669 YYERROR; 670 671 ia = iface_af_get(iface, af); 672 if (ia->enabled) { 673 yyerror("interface %s already configured for " 674 "address-family %s", kif->ifname, 675 af_name(af)); 676 YYERROR; 677 } 678 ia->enabled = 1; 679 680 ifacedefs = *defs; 681 defs = &ifacedefs; 682 } interface_block { 683 ia->hello_holdtime = defs->lhello_holdtime; 684 ia->hello_interval = defs->lhello_interval; 685 iface = NULL; 686 defs = &afdefs; 687 } 688 ; 689 690interface_block : '{' optnl interfaceopts_l '}' 691 | '{' optnl '}' 692 | /* nothing */ 693 ; 694 695interfaceopts_l : interfaceopts_l iface_defaults nl 696 | iface_defaults optnl 697 ; 698 699tneighbor : TNEIGHBOR STRING { 700 union ldpd_addr addr; 701 702 if (get_address($2, &addr) == -1) { 703 yyerror("error parsing targeted-neighbor " 704 "address"); 705 free($2); 706 YYERROR; 707 } 708 free($2); 709 if (bad_addr(af, &addr)) { 710 yyerror("invalid targeted-neighbor address"); 711 YYERROR; 712 } 713 if (af == AF_INET6 && 714 IN6_IS_SCOPE_EMBED(&addr.v6)) { 715 yyerror("targeted-neighbor address can not be " 716 "link-local"); 717 YYERROR; 718 } 719 720 tnbr = conf_get_tnbr(&addr); 721 if (tnbr == NULL) 722 YYERROR; 723 724 tnbrdefs = *defs; 725 defs = &tnbrdefs; 726 } tneighbor_block { 727 tnbr->hello_holdtime = defs->thello_holdtime; 728 tnbr->hello_interval = defs->thello_interval; 729 tnbr = NULL; 730 defs = &afdefs; 731 } 732 ; 733 734tneighbor_block : '{' optnl tneighboropts_l '}' 735 | '{' optnl '}' 736 | /* nothing */ 737 ; 738 739tneighboropts_l : tneighboropts_l tnbr_defaults nl 740 | tnbr_defaults optnl 741 ; 742 743neighbor : NEIGHBOR STRING { 744 struct in_addr addr; 745 746 if (inet_aton($2, &addr) == 0) { 747 yyerror("error parsing neighbor-id"); 748 free($2); 749 YYERROR; 750 } 751 free($2); 752 if (bad_addr_v4(addr)) { 753 yyerror("invalid neighbor-id"); 754 YYERROR; 755 } 756 757 nbrp = conf_get_nbrp(addr); 758 if (nbrp == NULL) 759 YYERROR; 760 } neighbor_block { 761 nbrp = NULL; 762 } 763 ; 764 765neighbor_block : '{' optnl neighboropts_l '}' 766 | '{' optnl '}' 767 | /* nothing */ 768 ; 769 770neighboropts_l : neighboropts_l nbr_opts nl 771 | nbr_opts optnl 772 ; 773 774l2vpn : L2VPN STRING TYPE l2vpn_type { 775 l2vpn = conf_get_l2vpn($2); 776 if (l2vpn == NULL) 777 YYERROR; 778 l2vpn->type = $4; 779 } l2vpn_block { 780 l2vpn = NULL; 781 } 782 ; 783 784l2vpn_block : '{' optnl l2vpnopts_l '}' 785 | '{' optnl '}' 786 | /* nothing */ 787 ; 788 789l2vpnopts_l : l2vpnopts_l l2vpnopts nl 790 | l2vpnopts optnl 791 ; 792 793%% 794 795struct keywords { 796 const char *k_name; 797 int k_val; 798}; 799 800static int 801yyerror(const char *fmt, ...) 802{ 803 va_list ap; 804 char *msg; 805 806 file->errors++; 807 va_start(ap, fmt); 808 if (vasprintf(&msg, fmt, ap) == -1) 809 fatalx("yyerror vasprintf"); 810 va_end(ap); 811 logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); 812 free(msg); 813 return (0); 814} 815 816static int 817kw_cmp(const void *k, const void *e) 818{ 819 return (strcmp(k, ((const struct keywords *)e)->k_name)); 820} 821 822static int 823lookup(char *s) 824{ 825 /* this has to be sorted always */ 826 static const struct keywords keywords[] = { 827 {"address-family", AF}, 828 {"bridge", BRIDGE}, 829 {"control-word", CONTROLWORD}, 830 {"ds-cisco-interop", DSCISCOINTEROP}, 831 {"ethernet", ETHERNET}, 832 {"ethernet-tagged", ETHERNETTAGGED}, 833 {"explicit-null", EXPNULL}, 834 {"fib-update", FIBUPDATE}, 835 {"gtsm-enable", GTSMENABLE}, 836 {"gtsm-hops", GTSMHOPS}, 837 {"include", INCLUDE}, 838 {"interface", INTERFACE}, 839 {"ipv4", IPV4}, 840 {"ipv6", IPV6}, 841 {"keepalive", KEEPALIVE}, 842 {"l2vpn", L2VPN}, 843 {"link-hello-holdtime", LHELLOHOLDTIME}, 844 {"link-hello-interval", LHELLOINTERVAL}, 845 {"mtu", MTU}, 846 {"neighbor", NEIGHBOR}, 847 {"neighbor-addr", NEIGHBORADDR}, 848 {"neighbor-id", NEIGHBORID}, 849 {"no", NO}, 850 {"password", PASSWORD}, 851 {"pseudowire", PSEUDOWIRE}, 852 {"pw-id", PWID}, 853 {"pw-type", PWTYPE}, 854 {"rdomain", RDOMAIN}, 855 {"router-id", ROUTERID}, 856 {"status-tlv", STATUSTLV}, 857 {"targeted-hello-accept", THELLOACCEPT}, 858 {"targeted-hello-holdtime", THELLOHOLDTIME}, 859 {"targeted-hello-interval", THELLOINTERVAL}, 860 {"targeted-neighbor", TNEIGHBOR}, 861 {"transport-address", TRANSADDRESS}, 862 {"transport-preference", TRANSPREFERENCE}, 863 {"type", TYPE}, 864 {"vpls", VPLS}, 865 {"yes", YES} 866 }; 867 const struct keywords *p; 868 869 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 870 sizeof(keywords[0]), kw_cmp); 871 872 if (p) 873 return (p->k_val); 874 else 875 return (STRING); 876} 877 878#define START_EXPAND 1 879#define DONE_EXPAND 2 880 881static int expanding; 882 883int 884igetc(void) 885{ 886 int c; 887 888 while (1) { 889 if (file->ungetpos > 0) 890 c = file->ungetbuf[--file->ungetpos]; 891 else 892 c = getc(file->stream); 893 894 if (c == START_EXPAND) 895 expanding = 1; 896 else if (c == DONE_EXPAND) 897 expanding = 0; 898 else 899 break; 900 } 901 return (c); 902} 903 904static int 905lgetc(int quotec) 906{ 907 int c, next; 908 909 if (quotec) { 910 if ((c = igetc()) == EOF) { 911 yyerror("reached end of file while parsing " 912 "quoted string"); 913 if (file == topfile || popfile() == EOF) 914 return (EOF); 915 return (quotec); 916 } 917 return (c); 918 } 919 920 while ((c = igetc()) == '\\') { 921 next = igetc(); 922 if (next != '\n') { 923 c = next; 924 break; 925 } 926 yylval.lineno = file->lineno; 927 file->lineno++; 928 } 929 930 if (c == EOF) { 931 /* 932 * Fake EOL when hit EOF for the first time. This gets line 933 * count right if last line in included file is syntactically 934 * invalid and has no newline. 935 */ 936 if (file->eof_reached == 0) { 937 file->eof_reached = 1; 938 return ('\n'); 939 } 940 while (c == EOF) { 941 if (file == topfile || popfile() == EOF) 942 return (EOF); 943 c = igetc(); 944 } 945 } 946 return (c); 947} 948 949void 950lungetc(int c) 951{ 952 if (c == EOF) 953 return; 954 955 if (file->ungetpos >= file->ungetsize) { 956 void *p = reallocarray(file->ungetbuf, file->ungetsize, 2); 957 if (p == NULL) 958 err(1, "lungetc"); 959 file->ungetbuf = p; 960 file->ungetsize *= 2; 961 } 962 file->ungetbuf[file->ungetpos++] = c; 963} 964 965static int 966findeol(void) 967{ 968 int c; 969 970 /* skip to either EOF or the first real EOL */ 971 while (1) { 972 c = lgetc(0); 973 if (c == '\n') { 974 file->lineno++; 975 break; 976 } 977 if (c == EOF) 978 break; 979 } 980 return (ERROR); 981} 982 983static int 984yylex(void) 985{ 986 unsigned char buf[8096]; 987 unsigned char *p, *val; 988 int quotec, next, c; 989 int token; 990 991 top: 992 p = buf; 993 while ((c = lgetc(0)) == ' ' || c == '\t') 994 ; /* nothing */ 995 996 yylval.lineno = file->lineno; 997 if (c == '#') 998 while ((c = lgetc(0)) != '\n' && c != EOF) 999 ; /* nothing */ 1000 if (c == '$' && !expanding) { 1001 while (1) { 1002 if ((c = lgetc(0)) == EOF) 1003 return (0); 1004 1005 if (p + 1 >= buf + sizeof(buf) - 1) { 1006 yyerror("string too long"); 1007 return (findeol()); 1008 } 1009 if (isalnum(c) || c == '_') { 1010 *p++ = c; 1011 continue; 1012 } 1013 *p = '\0'; 1014 lungetc(c); 1015 break; 1016 } 1017 val = symget(buf); 1018 if (val == NULL) { 1019 yyerror("macro '%s' not defined", buf); 1020 return (findeol()); 1021 } 1022 p = val + strlen(val) - 1; 1023 lungetc(DONE_EXPAND); 1024 while (p >= val) { 1025 lungetc(*p); 1026 p--; 1027 } 1028 lungetc(START_EXPAND); 1029 goto top; 1030 } 1031 1032 switch (c) { 1033 case '\'': 1034 case '"': 1035 quotec = c; 1036 while (1) { 1037 if ((c = lgetc(quotec)) == EOF) 1038 return (0); 1039 if (c == '\n') { 1040 file->lineno++; 1041 continue; 1042 } else if (c == '\\') { 1043 if ((next = lgetc(quotec)) == EOF) 1044 return (0); 1045 if (next == quotec || c == ' ' || c == '\t') 1046 c = next; 1047 else if (next == '\n') { 1048 file->lineno++; 1049 continue; 1050 } else 1051 lungetc(next); 1052 } else if (c == quotec) { 1053 *p = '\0'; 1054 break; 1055 } else if (c == '\0') { 1056 yyerror("syntax error"); 1057 return (findeol()); 1058 } 1059 if (p + 1 >= buf + sizeof(buf) - 1) { 1060 yyerror("string too long"); 1061 return (findeol()); 1062 } 1063 *p++ = c; 1064 } 1065 yylval.v.string = strdup(buf); 1066 if (yylval.v.string == NULL) 1067 err(1, "yylex: strdup"); 1068 return (STRING); 1069 } 1070 1071#define allowed_to_end_number(x) \ 1072 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 1073 1074 if (c == '-' || isdigit(c)) { 1075 do { 1076 *p++ = c; 1077 if ((unsigned)(p-buf) >= sizeof(buf)) { 1078 yyerror("string too long"); 1079 return (findeol()); 1080 } 1081 } while ((c = lgetc(0)) != EOF && isdigit(c)); 1082 lungetc(c); 1083 if (p == buf + 1 && buf[0] == '-') 1084 goto nodigits; 1085 if (c == EOF || allowed_to_end_number(c)) { 1086 const char *errstr = NULL; 1087 1088 *p = '\0'; 1089 yylval.v.number = strtonum(buf, LLONG_MIN, 1090 LLONG_MAX, &errstr); 1091 if (errstr) { 1092 yyerror("\"%s\" invalid number: %s", 1093 buf, errstr); 1094 return (findeol()); 1095 } 1096 return (NUMBER); 1097 } else { 1098 nodigits: 1099 while (p > buf + 1) 1100 lungetc(*--p); 1101 c = *--p; 1102 if (c == '-') 1103 return (c); 1104 } 1105 } 1106 1107#define allowed_in_string(x) \ 1108 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 1109 x != '{' && x != '}' && \ 1110 x != '!' && x != '=' && x != '#' && \ 1111 x != ',')) 1112 1113 if (isalnum(c) || c == ':' || c == '_') { 1114 do { 1115 *p++ = c; 1116 if ((unsigned)(p-buf) >= sizeof(buf)) { 1117 yyerror("string too long"); 1118 return (findeol()); 1119 } 1120 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 1121 lungetc(c); 1122 *p = '\0'; 1123 if ((token = lookup(buf)) == STRING) 1124 if ((yylval.v.string = strdup(buf)) == NULL) 1125 err(1, "yylex: strdup"); 1126 return (token); 1127 } 1128 if (c == '\n') { 1129 yylval.lineno = file->lineno; 1130 file->lineno++; 1131 } 1132 if (c == EOF) 1133 return (0); 1134 return (c); 1135} 1136 1137static int 1138check_file_secrecy(int fd, const char *fname) 1139{ 1140 struct stat st; 1141 1142 if (fstat(fd, &st)) { 1143 log_warn("cannot stat %s", fname); 1144 return (-1); 1145 } 1146 if (st.st_uid != 0 && st.st_uid != getuid()) { 1147 log_warnx("%s: owner not root or current user", fname); 1148 return (-1); 1149 } 1150 if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { 1151 log_warnx("%s: group writable or world read/writable", fname); 1152 return (-1); 1153 } 1154 return (0); 1155} 1156 1157static struct file * 1158pushfile(const char *name, int secret) 1159{ 1160 struct file *nfile; 1161 1162 if ((nfile = calloc(1, sizeof(struct file))) == NULL) { 1163 log_warn("calloc"); 1164 return (NULL); 1165 } 1166 if ((nfile->name = strdup(name)) == NULL) { 1167 log_warn("strdup"); 1168 free(nfile); 1169 return (NULL); 1170 } 1171 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 1172 log_warn("%s", nfile->name); 1173 free(nfile->name); 1174 free(nfile); 1175 return (NULL); 1176 } else if (secret && 1177 check_file_secrecy(fileno(nfile->stream), nfile->name)) { 1178 fclose(nfile->stream); 1179 free(nfile->name); 1180 free(nfile); 1181 return (NULL); 1182 } 1183 nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0; 1184 nfile->ungetsize = 16; 1185 nfile->ungetbuf = malloc(nfile->ungetsize); 1186 if (nfile->ungetbuf == NULL) { 1187 log_warn("malloc"); 1188 fclose(nfile->stream); 1189 free(nfile->name); 1190 free(nfile); 1191 return (NULL); 1192 } 1193 TAILQ_INSERT_TAIL(&files, nfile, entry); 1194 return (nfile); 1195} 1196 1197static int 1198popfile(void) 1199{ 1200 struct file *prev; 1201 1202 if ((prev = TAILQ_PREV(file, files, entry)) != NULL) 1203 prev->errors += file->errors; 1204 1205 TAILQ_REMOVE(&files, file, entry); 1206 fclose(file->stream); 1207 free(file->name); 1208 free(file->ungetbuf); 1209 free(file); 1210 file = prev; 1211 return (file ? 0 : EOF); 1212} 1213 1214struct ldpd_conf * 1215parse_config(char *filename) 1216{ 1217 struct sym *sym, *next; 1218 1219 conf = config_new_empty(); 1220 conf->rdomain = 0; 1221 conf->trans_pref = DUAL_STACK_LDPOV6; 1222 1223 defs = &globaldefs; 1224 defs->keepalive = DEFAULT_KEEPALIVE; 1225 defs->lhello_holdtime = LINK_DFLT_HOLDTIME; 1226 defs->lhello_interval = DEFAULT_HELLO_INTERVAL; 1227 defs->thello_holdtime = TARGETED_DFLT_HOLDTIME; 1228 defs->thello_interval = DEFAULT_HELLO_INTERVAL; 1229 defs->pwflags = F_PW_STATUSTLV_CONF|F_PW_CWORD_CONF; 1230 1231 if ((file = pushfile(filename, 1232 !(global.cmd_opts & LDPD_OPT_NOACTION))) == NULL) { 1233 free(conf); 1234 return (NULL); 1235 } 1236 topfile = file; 1237 1238 yyparse(); 1239 errors = file->errors; 1240 popfile(); 1241 1242 /* Free macros and check which have not been used. */ 1243 TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { 1244 if ((global.cmd_opts & LDPD_OPT_VERBOSE2) && !sym->used) 1245 fprintf(stderr, "warning: macro '%s' not " 1246 "used\n", sym->nam); 1247 if (!sym->persist) { 1248 free(sym->nam); 1249 free(sym->val); 1250 TAILQ_REMOVE(&symhead, sym, entry); 1251 free(sym); 1252 } 1253 } 1254 1255 /* check that all interfaces belong to the configured rdomain */ 1256 errors += conf_check_rdomain(conf->rdomain); 1257 1258 /* free global config defaults */ 1259 if (errors) { 1260 clear_config(conf); 1261 return (NULL); 1262 } 1263 1264 if (conf->rtr_id.s_addr == INADDR_ANY) 1265 conf->rtr_id.s_addr = get_rtr_id(); 1266 1267 /* if the ipv4 transport-address is not set, use the router-id */ 1268 if ((conf->ipv4.flags & F_LDPD_AF_ENABLED) && 1269 conf->ipv4.trans_addr.v4.s_addr == INADDR_ANY) 1270 conf->ipv4.trans_addr.v4 = conf->rtr_id; 1271 1272 return (conf); 1273} 1274 1275static int 1276symset(const char *nam, const char *val, int persist) 1277{ 1278 struct sym *sym; 1279 1280 TAILQ_FOREACH(sym, &symhead, entry) { 1281 if (strcmp(nam, sym->nam) == 0) 1282 break; 1283 } 1284 1285 if (sym != NULL) { 1286 if (sym->persist == 1) 1287 return (0); 1288 else { 1289 free(sym->nam); 1290 free(sym->val); 1291 TAILQ_REMOVE(&symhead, sym, entry); 1292 free(sym); 1293 } 1294 } 1295 if ((sym = calloc(1, sizeof(*sym))) == NULL) 1296 return (-1); 1297 1298 sym->nam = strdup(nam); 1299 if (sym->nam == NULL) { 1300 free(sym); 1301 return (-1); 1302 } 1303 sym->val = strdup(val); 1304 if (sym->val == NULL) { 1305 free(sym->nam); 1306 free(sym); 1307 return (-1); 1308 } 1309 sym->used = 0; 1310 sym->persist = persist; 1311 TAILQ_INSERT_TAIL(&symhead, sym, entry); 1312 return (0); 1313} 1314 1315int 1316cmdline_symset(char *s) 1317{ 1318 char *sym, *val; 1319 int ret; 1320 size_t len; 1321 1322 if ((val = strrchr(s, '=')) == NULL) 1323 return (-1); 1324 1325 len = strlen(s) - strlen(val) + 1; 1326 if ((sym = malloc(len)) == NULL) 1327 errx(1, "cmdline_symset: malloc"); 1328 1329 strlcpy(sym, s, len); 1330 1331 ret = symset(sym, val + 1, 1); 1332 free(sym); 1333 1334 return (ret); 1335} 1336 1337static char * 1338symget(const char *nam) 1339{ 1340 struct sym *sym; 1341 1342 TAILQ_FOREACH(sym, &symhead, entry) { 1343 if (strcmp(nam, sym->nam) == 0) { 1344 sym->used = 1; 1345 return (sym->val); 1346 } 1347 } 1348 return (NULL); 1349} 1350 1351static struct iface * 1352conf_get_if(struct kif *kif) 1353{ 1354 struct iface *i; 1355 struct l2vpn *l; 1356 1357 if (kif->if_type == IFT_LOOP || 1358 kif->if_type == IFT_CARP || 1359 kif->if_type == IFT_BRIDGE || 1360 kif->if_type == IFT_MPLSTUNNEL) { 1361 yyerror("unsupported interface type on interface %s", 1362 kif->ifname); 1363 return (NULL); 1364 } 1365 1366 LIST_FOREACH(l, &conf->l2vpn_list, entry) 1367 if (l2vpn_if_find(l, kif->ifindex)) { 1368 yyerror("interface %s already configured under " 1369 "l2vpn %s", kif->ifname, l->name); 1370 return (NULL); 1371 } 1372 1373 LIST_FOREACH(i, &conf->iface_list, entry) 1374 if (i->ifindex == kif->ifindex) 1375 return (i); 1376 1377 i = if_new(kif); 1378 LIST_INSERT_HEAD(&conf->iface_list, i, entry); 1379 return (i); 1380} 1381 1382static struct tnbr * 1383conf_get_tnbr(union ldpd_addr *addr) 1384{ 1385 struct tnbr *t; 1386 1387 t = tnbr_find(conf, af, addr); 1388 if (t) { 1389 yyerror("targeted neighbor %s already configured", 1390 log_addr(af, addr)); 1391 return (NULL); 1392 } 1393 1394 t = tnbr_new(conf, af, addr); 1395 t->flags |= F_TNBR_CONFIGURED; 1396 LIST_INSERT_HEAD(&conf->tnbr_list, t, entry); 1397 return (t); 1398} 1399 1400static struct nbr_params * 1401conf_get_nbrp(struct in_addr lsr_id) 1402{ 1403 struct nbr_params *n; 1404 1405 LIST_FOREACH(n, &conf->nbrp_list, entry) { 1406 if (n->lsr_id.s_addr == lsr_id.s_addr) { 1407 yyerror("neighbor %s already configured", 1408 inet_ntoa(lsr_id)); 1409 return (NULL); 1410 } 1411 } 1412 1413 n = nbr_params_new(lsr_id); 1414 LIST_INSERT_HEAD(&conf->nbrp_list, n, entry); 1415 return (n); 1416} 1417 1418static struct l2vpn * 1419conf_get_l2vpn(char *name) 1420{ 1421 struct l2vpn *l; 1422 1423 if (l2vpn_find(conf, name)) { 1424 yyerror("l2vpn %s already configured", name); 1425 return (NULL); 1426 } 1427 1428 l = l2vpn_new(name); 1429 LIST_INSERT_HEAD(&conf->l2vpn_list, l, entry); 1430 return (l); 1431} 1432 1433static struct l2vpn_if * 1434conf_get_l2vpn_if(struct l2vpn *l, struct kif *kif) 1435{ 1436 struct iface *i; 1437 struct l2vpn *ltmp; 1438 struct l2vpn_if *f; 1439 1440 if (kif->if_type == IFT_LOOP || 1441 kif->if_type == IFT_CARP || 1442 kif->if_type == IFT_BRIDGE || 1443 kif->if_type == IFT_MPLSTUNNEL) { 1444 yyerror("unsupported interface type on interface %s", 1445 kif->ifname); 1446 return (NULL); 1447 } 1448 1449 LIST_FOREACH(ltmp, &conf->l2vpn_list, entry) 1450 if (l2vpn_if_find(ltmp, kif->ifindex)) { 1451 yyerror("interface %s already configured under " 1452 "l2vpn %s", kif->ifname, ltmp->name); 1453 return (NULL); 1454 } 1455 1456 LIST_FOREACH(i, &conf->iface_list, entry) { 1457 if (i->ifindex == kif->ifindex) { 1458 yyerror("interface %s already configured", 1459 kif->ifname); 1460 return (NULL); 1461 } 1462 } 1463 1464 f = l2vpn_if_new(l, kif); 1465 LIST_INSERT_HEAD(&l2vpn->if_list, f, entry); 1466 return (f); 1467} 1468 1469static struct l2vpn_pw * 1470conf_get_l2vpn_pw(struct l2vpn *l, struct kif *kif) 1471{ 1472 struct l2vpn *ltmp; 1473 struct l2vpn_pw *p; 1474 1475 LIST_FOREACH(ltmp, &conf->l2vpn_list, entry) { 1476 if (l2vpn_pw_find(ltmp, kif->ifindex)) { 1477 yyerror("pseudowire %s is already being " 1478 "used by l2vpn %s", kif->ifname, ltmp->name); 1479 return (NULL); 1480 } 1481 } 1482 1483 p = l2vpn_pw_new(l, kif); 1484 LIST_INSERT_HEAD(&l2vpn->pw_list, p, entry); 1485 return (p); 1486} 1487 1488int 1489conf_check_rdomain(unsigned int rdomain) 1490{ 1491 struct iface *i; 1492 int errs = 0; 1493 1494 LIST_FOREACH(i, &conf->iface_list, entry) { 1495 if (i->rdomain != rdomain) { 1496 logit(LOG_CRIT, "interface %s not in rdomain %u", 1497 i->name, rdomain); 1498 errs++; 1499 } 1500 } 1501 1502 return (errs); 1503} 1504 1505static void 1506clear_config(struct ldpd_conf *xconf) 1507{ 1508 struct iface *i; 1509 struct tnbr *t; 1510 struct nbr_params *n; 1511 struct l2vpn *l; 1512 struct l2vpn_if *f; 1513 struct l2vpn_pw *p; 1514 1515 while ((i = LIST_FIRST(&xconf->iface_list)) != NULL) { 1516 LIST_REMOVE(i, entry); 1517 free(i); 1518 } 1519 1520 while ((t = LIST_FIRST(&xconf->tnbr_list)) != NULL) { 1521 LIST_REMOVE(t, entry); 1522 free(t); 1523 } 1524 1525 while ((n = LIST_FIRST(&xconf->nbrp_list)) != NULL) { 1526 LIST_REMOVE(n, entry); 1527 free(n); 1528 } 1529 1530 while ((l = LIST_FIRST(&xconf->l2vpn_list)) != NULL) { 1531 while ((f = LIST_FIRST(&l->if_list)) != NULL) { 1532 LIST_REMOVE(f, entry); 1533 free(f); 1534 } 1535 while ((p = LIST_FIRST(&l->pw_list)) != NULL) { 1536 LIST_REMOVE(p, entry); 1537 free(p); 1538 } 1539 LIST_REMOVE(l, entry); 1540 free(l); 1541 } 1542 1543 free(xconf); 1544} 1545 1546static uint32_t 1547get_rtr_id(void) 1548{ 1549 struct ifaddrs *ifap, *ifa; 1550 uint32_t ip = 0, cur, localnet; 1551 1552 localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET); 1553 1554 if (getifaddrs(&ifap) == -1) { 1555 log_warn("getifaddrs"); 1556 return (0); 1557 } 1558 1559 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 1560 if (strncmp(ifa->ifa_name, "carp", 4) == 0) 1561 continue; 1562 if (ifa->ifa_addr->sa_family != AF_INET) 1563 continue; 1564 cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; 1565 if ((cur & localnet) == localnet) /* skip 127/8 */ 1566 continue; 1567 if (ntohl(cur) < ntohl(ip) || ip == 0) 1568 ip = cur; 1569 } 1570 freeifaddrs(ifap); 1571 1572 return (ip); 1573} 1574 1575static int 1576get_address(const char *s, union ldpd_addr *addr) 1577{ 1578 switch (af) { 1579 case AF_INET: 1580 if (inet_pton(AF_INET, s, &addr->v4) != 1) 1581 return (-1); 1582 break; 1583 case AF_INET6: 1584 if (inet_pton(AF_INET6, s, &addr->v6) != 1) 1585 return (-1); 1586 break; 1587 default: 1588 return (-1); 1589 } 1590 1591 return (0); 1592} 1593 1594static int 1595get_af_address(const char *s, int *family, union ldpd_addr *addr) 1596{ 1597 if (inet_pton(AF_INET, s, &addr->v4) == 1) { 1598 *family = AF_INET; 1599 return (0); 1600 } 1601 1602 if (inet_pton(AF_INET6, s, &addr->v6) == 1) { 1603 *family = AF_INET6; 1604 return (0); 1605 } 1606 1607 return (-1); 1608} 1609