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