parse.y revision 1.35
1/* $OpenBSD: parse.y,v 1.35 2007/03/07 17:40:32 reyk Exp $ */ 2 3/* 4 * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org> 5 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 6 * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org> 7 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> 8 * Copyright (c) 2001 Markus Friedl. All rights reserved. 9 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. 10 * Copyright (c) 2001 Theo de Raadt. All rights reserved. 11 * 12 * Permission to use, copy, modify, and distribute this software for any 13 * purpose with or without fee is hereby granted, provided that the above 14 * copyright notice and this permission notice appear in all copies. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 17 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 19 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 21 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 22 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 23 */ 24 25%{ 26#include <sys/types.h> 27#include <sys/socket.h> 28#include <sys/queue.h> 29#include <netinet/in.h> 30#include <net/if.h> 31#include <arpa/inet.h> 32#include <arpa/nameser.h> 33 34#include <ctype.h> 35#include <err.h> 36#include <errno.h> 37#include <event.h> 38#include <limits.h> 39#include <stdint.h> 40#include <stdarg.h> 41#include <stdio.h> 42#include <netdb.h> 43#include <string.h> 44 45#include <openssl/ssl.h> 46 47#include "hoststated.h" 48 49struct hoststated *conf = NULL; 50static FILE *fin = NULL; 51static int lineno = 1; 52static int errors = 0; 53const char *infile; 54objid_t last_service_id = 0; 55objid_t last_table_id = 0; 56objid_t last_host_id = 0; 57objid_t last_relay_id = 0; 58objid_t last_proto_id = 0; 59 60static struct service *service = NULL; 61static struct table *table = NULL; 62static struct relay *rlay = NULL; 63static struct protocol *proto = NULL; 64static struct protonode node; 65 66int yyerror(const char *, ...); 67int yyparse(void); 68int kw_cmp(const void *, const void *); 69int lookup(char *); 70int lgetc(FILE *, int *); 71int lungetc(int); 72int findeol(void); 73int yylex(void); 74 75TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); 76struct sym { 77 TAILQ_ENTRY(sym) entries; 78 int used; 79 int persist; 80 char *nam; 81 char *val; 82}; 83 84int symset(const char *, const char *, int); 85char *symget(const char *); 86 87struct address *host_v4(const char *); 88struct address *host_v6(const char *); 89int host_dns(const char *, struct addresslist *, 90 int, in_port_t, const char *); 91int host(const char *, struct addresslist *, 92 int, in_port_t, const char *); 93 94typedef struct { 95 union { 96 u_int32_t number; 97 char *string; 98 struct host *host; 99 struct timeval tv; 100 } v; 101 int lineno; 102} YYSTYPE; 103 104%} 105 106%token SERVICE TABLE BACKUP HOST REAL 107%token CHECK TCP ICMP EXTERNAL REQUEST RESPONSE 108%token TIMEOUT CODE DIGEST PORT TAG INTERFACE 109%token VIRTUAL INTERVAL DISABLE STICKYADDR BACKLOG 110%token SEND EXPECT NOTHING SSL LOADBALANCE ROUNDROBIN CIPHERS COOKIE 111%token RELAY LISTEN ON FORWARD TO NAT LOOKUP PREFORK NO MARK MARKED 112%token PROTO SESSION CACHE APPEND CHANGE REMOVE FROM FILTER HASH HEADER 113%token LOG UPDATES ALL DEMOTE NODELAY SACK SOCKET BUFFER URL RETRY 114%token ERROR 115%token <v.string> STRING 116%type <v.string> interface 117%type <v.number> number port http_type loglevel sslcache optssl 118%type <v.number> proto_type dstmode docheck retry log flag direction 119%type <v.host> host 120%type <v.tv> timeout 121 122%% 123 124grammar : /* empty */ 125 | grammar '\n' 126 | grammar varset '\n' 127 | grammar main '\n' 128 | grammar service '\n' 129 | grammar table '\n' 130 | grammar relay '\n' 131 | grammar proto '\n' 132 | grammar error '\n' { errors++; } 133 ; 134 135number : STRING { 136 const char *estr; 137 138 $$ = strtonum($1, 0, UINT_MAX, &estr); 139 if (estr) { 140 yyerror("cannot parse number %s : %s", 141 $1, estr); 142 free($1); 143 YYERROR; 144 } 145 free($1); 146 } 147 ; 148 149optssl : /*empty*/ { $$ = 0; } 150 | SSL { $$ = 1; } 151 ; 152 153http_type : STRING { 154 if (strcmp("https", $1) == 0) { 155 $$ = 1; 156 } else if (strcmp("http", $1) == 0) { 157 $$ = 0; 158 } else { 159 yyerror("invalid check type: $1", $1); 160 free($1); 161 YYERROR; 162 } 163 free($1); 164 } 165 ; 166 167proto_type : TCP { $$ = RELAY_PROTO_TCP; } 168 | STRING { 169 if (strcmp("http", $1) == 0) { 170 $$ = RELAY_PROTO_HTTP; 171 } else { 172 yyerror("invalid protocol type: $1", $1); 173 free($1); 174 YYERROR; 175 } 176 free($1); 177 } 178 ; 179 180port : PORT STRING { 181 const char *estr; 182 struct servent *servent; 183 184 $$ = strtonum($2, 1, USHRT_MAX, &estr); 185 if (estr) { 186 if (errno == ERANGE) { 187 yyerror("port %s is out of range", $2); 188 free($2); 189 YYERROR; 190 } 191 servent = getservbyname($2, "tcp"); 192 if (servent == NULL) { 193 yyerror("port %s is invalid", $2); 194 free($2); 195 YYERROR; 196 } 197 $$ = servent->s_port; 198 } else 199 $$ = htons($$); 200 free($2); 201 } 202 ; 203 204varset : STRING '=' STRING { 205 if (symset($1, $3, 0) == -1) 206 fatal("cannot store variable"); 207 free($1); 208 free($3); 209 } 210 ; 211 212sendbuf : NOTHING { 213 table->sendbuf = NULL; 214 } 215 | STRING { 216 table->sendbuf = strdup($1); 217 if (table->sendbuf == NULL) 218 fatal("out of memory"); 219 free($1); 220 } 221 ; 222 223main : INTERVAL number { conf->interval.tv_sec = $2; } 224 | LOG loglevel { conf->opts |= $2; } 225 | TIMEOUT timeout { 226 bcopy(&$2, &conf->timeout, sizeof(struct timeval)); 227 } 228 | PREFORK number { 229 if ($2 <= 0 || $2 > RELAY_MAXPROC) { 230 yyerror("invalid number of preforked " 231 "relays: %d", $2); 232 YYERROR; 233 } 234 conf->prefork_relay = $2; 235 } 236 | DEMOTE STRING { 237 conf->flags |= F_DEMOTE; 238 if (strlcpy(conf->demote_group, $2, 239 sizeof(conf->demote_group)) 240 >= sizeof(conf->demote_group)) { 241 yyerror("yyparse: demote group name too long"); 242 free($2); 243 YYERROR; 244 } 245 free($2); 246 if (carp_demote_init(conf->demote_group, 1) == -1) { 247 yyerror("yyparse: error initializing group '%s'", 248 conf->demote_group); 249 YYERROR; 250 } 251 } 252 ; 253 254loglevel : UPDATES { $$ = HOSTSTATED_OPT_LOGUPDATE; } 255 | ALL { $$ = HOSTSTATED_OPT_LOGALL; } 256 ; 257 258service : SERVICE STRING { 259 struct service *srv; 260 261 TAILQ_FOREACH(srv, &conf->services, entry) 262 if (!strcmp(srv->name, $2)) 263 break; 264 if (srv != NULL) { 265 yyerror("service %s defined twice", $2); 266 free($2); 267 YYERROR; 268 } 269 if ((srv = calloc(1, sizeof (*srv))) == NULL) 270 fatal("out of memory"); 271 272 if (strlcpy(srv->name, $2, sizeof(srv->name)) >= 273 sizeof(srv->name)) { 274 yyerror("service name truncated"); 275 YYERROR; 276 } 277 free($2); 278 srv->id = last_service_id++; 279 if (last_service_id == INT_MAX) { 280 yyerror("too many services defined"); 281 YYERROR; 282 } 283 service = srv; 284 } '{' optnl serviceopts_l '}' { 285 if (service->table == NULL) { 286 yyerror("service %s has no table", 287 service->name); 288 YYERROR; 289 } 290 if (TAILQ_EMPTY(&service->virts)) { 291 yyerror("service %s has no virtual ip", 292 service->name); 293 YYERROR; 294 } 295 conf->servicecount++; 296 if (service->backup == NULL) 297 service->backup = &conf->empty_table; 298 else if (service->backup->port != 299 service->table->port) { 300 yyerror("service %s uses two different ports " 301 "for its table and backup table", 302 service->name); 303 YYERROR; 304 } 305 306 if (!(service->flags & F_DISABLE)) 307 service->flags |= F_ADD; 308 TAILQ_INSERT_HEAD(&conf->services, service, entry); 309 } 310 ; 311 312serviceopts_l : serviceopts_l serviceoptsl nl 313 | serviceoptsl optnl 314 ; 315 316serviceoptsl : TABLE STRING { 317 struct table *tb; 318 319 TAILQ_FOREACH(tb, &conf->tables, entry) 320 if (!strcmp(tb->name, $2)) 321 break; 322 if (tb == NULL) { 323 yyerror("no such table: %s", $2); 324 free($2); 325 YYERROR; 326 } else { 327 service->table = tb; 328 service->table->serviceid = service->id; 329 service->table->flags |= F_USED; 330 free($2); 331 } 332 } 333 | BACKUP TABLE STRING { 334 struct table *tb; 335 336 if (service->backup) { 337 yyerror("backup already specified"); 338 free($3); 339 YYERROR; 340 } 341 342 TAILQ_FOREACH(tb, &conf->tables, entry) 343 if (!strcmp(tb->name, $3)) 344 break; 345 346 if (tb == NULL) { 347 yyerror("no such table: %s", $3); 348 free($3); 349 YYERROR; 350 } else { 351 service->backup = tb; 352 service->backup->serviceid = service->id; 353 service->backup->flags |= (F_USED|F_BACKUP); 354 free($3); 355 } 356 } 357 | VIRTUAL HOST STRING port interface { 358 if (host($3, &service->virts, 359 SRV_MAX_VIRTS, $4, $5) <= 0) { 360 yyerror("invalid virtual ip: %s", $3); 361 free($3); 362 free($5); 363 YYERROR; 364 } 365 free($3); 366 free($5); 367 } 368 | DISABLE { service->flags |= F_DISABLE; } 369 | STICKYADDR { service->flags |= F_STICKY; } 370 | TAG STRING { 371 if (strlcpy(service->tag, $2, sizeof(service->tag)) >= 372 sizeof(service->tag)) { 373 yyerror("service tag name truncated"); 374 free($2); 375 YYERROR; 376 } 377 free($2); 378 } 379 ; 380 381table : TABLE STRING { 382 struct table *tb; 383 384 TAILQ_FOREACH(tb, &conf->tables, entry) 385 if (!strcmp(tb->name, $2)) 386 break; 387 if (tb != NULL) { 388 yyerror("table %s defined twice"); 389 free($2); 390 YYERROR; 391 } 392 393 if ((tb = calloc(1, sizeof (*tb))) == NULL) 394 fatal("out of memory"); 395 396 if (strlcpy(tb->name, $2, sizeof(tb->name)) >= 397 sizeof(tb->name)) { 398 yyerror("table name truncated"); 399 YYERROR; 400 } 401 tb->id = last_table_id++; 402 bcopy(&conf->timeout, &tb->timeout, 403 sizeof(struct timeval)); 404 if (last_table_id == INT_MAX) { 405 yyerror("too many tables defined"); 406 YYERROR; 407 } 408 free($2); 409 table = tb; 410 } '{' optnl tableopts_l '}' { 411 if (table->port == 0) { 412 yyerror("table %s has no port", table->name); 413 YYERROR; 414 } 415 if (TAILQ_EMPTY(&table->hosts)) { 416 yyerror("table %s has no hosts", table->name); 417 YYERROR; 418 } 419 if (table->check == CHECK_NOCHECK) { 420 yyerror("table %s has no check", table->name); 421 YYERROR; 422 } 423 conf->tablecount++; 424 TAILQ_INSERT_HEAD(&conf->tables, table, entry); 425 } 426 ; 427 428tableopts_l : tableopts_l tableoptsl nl 429 | tableoptsl optnl 430 ; 431 432tableoptsl : host { 433 $1->tableid = table->id; 434 $1->tablename = table->name; 435 TAILQ_INSERT_HEAD(&table->hosts, $1, entry); 436 } 437 | TIMEOUT timeout { 438 bcopy(&$2, &table->timeout, sizeof(struct timeval)); 439 } 440 | CHECK ICMP { 441 table->check = CHECK_ICMP; 442 } 443 | CHECK TCP { 444 table->check = CHECK_TCP; 445 } 446 | CHECK SSL { 447 table->check = CHECK_TCP; 448 conf->flags |= F_SSL; 449 table->flags |= F_SSL; 450 } 451 | CHECK http_type STRING CODE number { 452 if ($2) { 453 conf->flags |= F_SSL; 454 table->flags |= F_SSL; 455 } 456 table->check = CHECK_HTTP_CODE; 457 table->retcode = $5; 458 if (asprintf(&table->sendbuf, 459 "HEAD %s HTTP/1.0\r\n\r\n", $3) == -1) 460 fatal("asprintf"); 461 free($3); 462 if (table->sendbuf == NULL) 463 fatal("out of memory"); 464 } 465 | CHECK http_type STRING DIGEST STRING { 466 if ($2) { 467 conf->flags |= F_SSL; 468 table->flags |= F_SSL; 469 } 470 table->check = CHECK_HTTP_DIGEST; 471 if (asprintf(&table->sendbuf, 472 "GET %s HTTP/1.0\r\n\r\n", $3) == -1) 473 fatal("asprintf"); 474 free($3); 475 if (table->sendbuf == NULL) 476 fatal("out of memory"); 477 if (strlcpy(table->digest, $5, 478 sizeof(table->digest)) >= sizeof(table->digest)) { 479 yyerror("http digest truncated"); 480 free($5); 481 YYERROR; 482 } 483 free($5); 484 } 485 | CHECK SEND sendbuf EXPECT STRING optssl { 486 table->check = CHECK_SEND_EXPECT; 487 if ($6) { 488 conf->flags |= F_SSL; 489 table->flags |= F_SSL; 490 } 491 if (strlcpy(table->exbuf, $5, sizeof(table->exbuf)) 492 >= sizeof(table->exbuf)) { 493 yyerror("yyparse: expect buffer truncated"); 494 free($5); 495 YYERROR; 496 } 497 free($5); 498 } 499 | REAL port { 500 table->port = $2; 501 } 502 | DEMOTE STRING { 503 table->flags |= F_DEMOTE; 504 if (strlcpy(table->demote_group, $2, 505 sizeof(table->demote_group)) 506 >= sizeof(table->demote_group)) { 507 yyerror("yyparse: demote group name too long"); 508 free($2); 509 YYERROR; 510 } 511 free($2); 512 if (carp_demote_init(table->demote_group, 1) == -1) { 513 yyerror("yyparse: error initializing group " 514 "'%s'", table->demote_group); 515 YYERROR; 516 } 517 } 518 | DISABLE { table->flags |= F_DISABLE; } 519 ; 520 521proto : PROTO STRING { 522 struct protocol *p; 523 524 TAILQ_FOREACH(p, &conf->protos, entry) 525 if (!strcmp(p->name, $2)) 526 break; 527 if (p != NULL) { 528 yyerror("protocol %s defined twice", $2); 529 free($2); 530 YYERROR; 531 } 532 if ((p = calloc(1, sizeof (*p))) == NULL) 533 fatal("out of memory"); 534 535 if (strlcpy(p->name, $2, sizeof(p->name)) >= 536 sizeof(p->name)) { 537 yyerror("protocol name truncated"); 538 YYERROR; 539 } 540 free($2); 541 p->id = last_proto_id++; 542 p->cache = RELAY_CACHESIZE; 543 p->type = RELAY_PROTO_TCP; 544 p->tcpflags = TCPFLAG_DEFAULT; 545 p->sslflags = SSLFLAG_DEFAULT; 546 p->sslciphers = NULL; 547 p->tcpbacklog = RELAY_BACKLOG; 548 if (last_proto_id == INT_MAX) { 549 yyerror("too many protocols defined"); 550 YYERROR; 551 } 552 RB_INIT(&p->request_tree); 553 RB_INIT(&p->response_tree); 554 proto = p; 555 } '{' optnl protopts_l '}' { 556 conf->protocount++; 557 558 if ((proto->sslflags & SSLFLAG_VERSION) == 0) { 559 yyerror("invalid SSL protocol"); 560 YYERROR; 561 } 562 563 TAILQ_INSERT_HEAD(&conf->protos, proto, entry); 564 } 565 ; 566 567protopts_l : protopts_l protoptsl nl 568 | protoptsl optnl 569 ; 570 571protoptsl : SSL sslflags 572 | SSL '{' sslflags_l '}' 573 | TCP tcpflags 574 | TCP '{' tcpflags_l '}' 575 | PROTO proto_type { proto->type = $2; } 576 | direction protonode log { 577 struct protonode *pn, pk; 578 struct proto_tree *tree; 579 580 if ($1 == RELAY_DIR_RESPONSE) 581 tree = &proto->response_tree; 582 else 583 tree = &proto->request_tree; 584 pn = RB_FIND(proto_tree, tree, &node); 585 if (pn != NULL) { 586 yyerror("protocol node %s defined twice", 587 node.key); 588 YYERROR; 589 } 590 if ((pn = calloc(1, sizeof (*pn))) == NULL) 591 fatal("out of memory"); 592 593 bcopy(&node, pn, sizeof(*pn)); 594 pn->key = node.key; 595 pn->value = node.value; 596 pn->type = node.type; 597 if ($1 == RELAY_DIR_RESPONSE) 598 pn->id = proto->response_nodes++; 599 else 600 pn->id = proto->request_nodes++; 601 if ($3) 602 pn->flags |= PNFLAG_LOG; 603 if (pn->id == INT_MAX) { 604 yyerror("too many protocol nodes defined"); 605 YYERROR; 606 } 607 RB_INSERT(proto_tree, tree, pn); 608 609 if (node.type == NODE_TYPE_COOKIE) 610 pk.key = "Cookie"; 611 else 612 pk.key = "GET"; 613 if (node.type != NODE_TYPE_HEADER) { 614 pk.type = NODE_TYPE_HEADER; 615 pn = RB_FIND(proto_tree, tree, &pk); 616 if (pn == NULL) { 617 if ((pn = (struct protonode *) 618 calloc(1, sizeof(*pn))) == NULL) 619 fatal("out of memory"); 620 pn->key = strdup(pk.key); 621 if (pn->key == NULL) 622 fatal("out of memory"); 623 pn->value = NULL; 624 pn->action = NODE_ACTION_NONE; 625 pn->type = pk.type; 626 if ($1 == RELAY_DIR_RESPONSE) 627 pn->id = 628 proto->response_nodes++; 629 else 630 pn->id = proto->request_nodes++; 631 if (pn->id == INT_MAX) { 632 yyerror("too many protocol " 633 "nodes defined"); 634 YYERROR; 635 } 636 RB_INSERT(proto_tree, tree, pn); 637 } 638 switch (node.type) { 639 case NODE_TYPE_URL: 640 pn->flags |= PNFLAG_LOOKUP_URL; 641 break; 642 case NODE_TYPE_COOKIE: 643 pn->flags |= PNFLAG_LOOKUP_COOKIE; 644 break; 645 default: 646 break; 647 } 648 } 649 650 bzero(&node, sizeof(node)); 651 } 652 ; 653 654direction : /* empty */ { $$ = RELAY_DIR_REQUEST; } 655 | REQUEST { $$ = RELAY_DIR_REQUEST; } 656 | RESPONSE { $$ = RELAY_DIR_RESPONSE; } 657 ; 658 659tcpflags_l : tcpflags comma tcpflags_l 660 | tcpflags 661 ; 662 663tcpflags : SACK { proto->tcpflags |= TCPFLAG_SACK; } 664 | NO SACK { proto->tcpflags |= TCPFLAG_NSACK; } 665 | NODELAY { proto->tcpflags |= TCPFLAG_NODELAY; } 666 | NO NODELAY { proto->tcpflags |= TCPFLAG_NNODELAY; } 667 | BACKLOG number { 668 if ($2 > RELAY_MAX_SESSIONS) { 669 yyerror("invalid backlog: %d", $2); 670 YYERROR; 671 } 672 proto->tcpbacklog = $2; 673 } 674 | SOCKET BUFFER number { 675 proto->tcpflags |= TCPFLAG_BUFSIZ; 676 proto->tcpbufsiz = $3; 677 } 678 ; 679 680sslflags_l : sslflags comma sslflags_l 681 | sslflags 682 ; 683 684sslflags : SESSION CACHE sslcache { proto->cache = $3; } 685 | CIPHERS STRING { 686 proto->sslciphers = strdup($2); 687 if (proto->sslciphers == NULL) 688 fatal("out of memory"); 689 free($2); 690 } 691 | NO flag { proto->sslflags &= ~($2); } 692 | flag { proto->sslflags |= $1; } 693 ; 694 695flag : STRING { 696 if (strcmp("sslv2", $1) == 0) 697 $$ = SSLFLAG_SSLV2; 698 else if (strcmp("sslv3", $1) == 0) 699 $$ = SSLFLAG_SSLV3; 700 else if (strcmp("tlsv1", $1) == 0) 701 $$ = SSLFLAG_TLSV1; 702 else { 703 yyerror("invalid SSL flag: %s", $1); 704 free($1); 705 YYERROR; 706 } 707 free($1); 708 } 709 ; 710 711protonode : nodetype APPEND STRING TO STRING marked { 712 node.action = NODE_ACTION_APPEND; 713 node.key = strdup($5); 714 node.value = strdup($3); 715 if (node.key == NULL || node.value == NULL) 716 fatal("out of memory"); 717 if (strchr(node.value, '$') != NULL) 718 node.flags |= PNFLAG_MACRO; 719 free($5); 720 free($3); 721 } 722 | nodetype CHANGE STRING TO STRING marked { 723 node.action = NODE_ACTION_CHANGE; 724 node.key = strdup($3); 725 node.value = strdup($5); 726 if (node.key == NULL || node.value == NULL) 727 fatal("out of memory"); 728 if (strchr(node.value, '$') != NULL) 729 node.flags |= PNFLAG_MACRO; 730 free($5); 731 free($3); 732 } 733 | nodetype REMOVE STRING marked { 734 node.action = NODE_ACTION_REMOVE; 735 node.key = strdup($3); 736 node.value = NULL; 737 if (node.key == NULL) 738 fatal("out of memory"); 739 free($3); 740 } 741 | nodetype EXPECT STRING FROM STRING mark { 742 node.action = NODE_ACTION_EXPECT; 743 node.key = strdup($5); 744 node.value = strdup($3);; 745 if (node.key == NULL || node.value == NULL) 746 fatal("out of memory"); 747 free($5); 748 free($3); 749 } 750 | nodetype FILTER STRING FROM STRING mark { 751 node.action = NODE_ACTION_FILTER; 752 node.key = strdup($5); 753 node.value = strdup($3);; 754 if (node.key == NULL || node.value == NULL) 755 fatal("out of memory"); 756 free($5); 757 free($3); 758 } 759 | nodetype HASH STRING marked { 760 node.action = NODE_ACTION_HASH; 761 node.key = strdup($3); 762 node.value = NULL; 763 if (node.key == NULL) 764 fatal("out of memory"); 765 free($3); 766 proto->lateconnect++; 767 } 768 | nodetype LOG STRING marked { 769 node.action = NODE_ACTION_LOG; 770 node.key = strdup($3); 771 node.value = NULL; 772 node.flags |= PNFLAG_LOG; 773 if (node.key == NULL) 774 fatal("out of memory"); 775 free($3); 776 } 777 ; 778 779mark : /* empty */ 780 | MARK { node.flags |= PNFLAG_MARK; } 781 ; 782 783marked : /* empty */ 784 | MARKED { node.flags |= PNFLAG_MARK; } 785 ; 786 787nodetype : HEADER { node.type = NODE_TYPE_HEADER; } 788 | URL { node.type = NODE_TYPE_URL; } 789 | COOKIE { node.type = NODE_TYPE_COOKIE; } 790 ; 791 792sslcache : number { $$ = $1; } 793 | DISABLE { $$ = -2; } 794 ; 795 796relay : RELAY STRING { 797 struct relay *r; 798 799 TAILQ_FOREACH(r, &conf->relays, entry) 800 if (!strcmp(r->name, $2)) 801 break; 802 if (r != NULL) { 803 yyerror("relay %s defined twice", $2); 804 free($2); 805 YYERROR; 806 } 807 if ((r = calloc(1, sizeof (*r))) == NULL) 808 fatal("out of memory"); 809 810 if (strlcpy(r->name, $2, sizeof(r->name)) >= 811 sizeof(r->name)) { 812 yyerror("relay name truncated"); 813 YYERROR; 814 } 815 free($2); 816 r->id = last_relay_id++; 817 r->timeout.tv_sec = RELAY_TIMEOUT; 818 r->proto = NULL; 819 r->dsttable = NULL; 820 if (last_relay_id == INT_MAX) { 821 yyerror("too many relays defined"); 822 YYERROR; 823 } 824 rlay = r; 825 } '{' optnl relayopts_l '}' { 826 if (rlay->ss.ss_family == AF_UNSPEC) { 827 yyerror("relay %s has no listener", 828 rlay->name); 829 YYERROR; 830 } 831 if ((rlay->flags & F_NATLOOK) == 0 && 832 rlay->dstss.ss_family == AF_UNSPEC && 833 rlay->dsttable == NULL) { 834 yyerror("relay %s has no target, service, " 835 "or table", rlay->name); 836 YYERROR; 837 } 838 if (rlay->proto == NULL) 839 rlay->proto = &conf->proto_default; 840 conf->relaycount++; 841 TAILQ_INIT(&rlay->sessions); 842 TAILQ_INSERT_HEAD(&conf->relays, rlay, entry); 843 } 844 ; 845 846relayopts_l : relayopts_l relayoptsl nl 847 | relayoptsl optnl 848 ; 849 850relayoptsl : LISTEN ON STRING port optssl { 851 struct addresslist al; 852 struct address *h; 853 854 if (rlay->ss.ss_family != AF_UNSPEC) { 855 yyerror("relay %s listener already specified", 856 rlay->name); 857 YYERROR; 858 } 859 860 TAILQ_INIT(&al); 861 if (host($3, &al, 1, $4, NULL) <= 0) { 862 yyerror("invalid listen ip: %s", $3); 863 free($3); 864 YYERROR; 865 } 866 free($3); 867 h = TAILQ_FIRST(&al); 868 bcopy(&h->ss, &rlay->ss, sizeof(rlay->ss)); 869 rlay->port = h->port; 870 if ($5) { 871 rlay->flags |= F_SSL; 872 conf->flags |= F_SSL; 873 } 874 } 875 | FORWARD TO STRING port { 876 struct addresslist al; 877 struct address *h; 878 879 if (rlay->dstss.ss_family != AF_UNSPEC) { 880 yyerror("relay %s target or service already " 881 "specified", rlay->name); 882 free($3); 883 YYERROR; 884 } 885 886 TAILQ_INIT(&al); 887 if (host($3, &al, 1, $4, NULL) <= 0) { 888 yyerror("invalid listen ip: %s", $3); 889 free($3); 890 YYERROR; 891 } 892 free($3); 893 h = TAILQ_FIRST(&al); 894 bcopy(&h->ss, &rlay->dstss, sizeof(rlay->dstss)); 895 rlay->dstport = h->port; 896 } 897 | SERVICE STRING { 898 struct service *svc; 899 struct address *h; 900 901 if (rlay->dstss.ss_family != AF_UNSPEC) { 902 yyerror("relay %s target or service already " 903 "specified", rlay->name); 904 free($2); 905 YYERROR; 906 } 907 908 if ((svc = service_findbyname(conf, $2)) == NULL) { 909 yyerror("relay %s for unknown service %s", 910 rlay->name, $2); 911 free($2); 912 YYERROR; 913 } 914 free($2); 915 h = TAILQ_FIRST(&svc->virts); 916 bcopy(&h->ss, &rlay->dstss, sizeof(rlay->dstss)); 917 rlay->dstport = h->port; 918 } 919 | TABLE STRING dstmode docheck { 920 struct table *dsttable; 921 922 if ((dsttable = table_findbyname(conf, $2)) == NULL) { 923 yyerror("relay %d for unknown table %s", 924 rlay->name, $2); 925 free($2); 926 YYERROR; 927 } 928 free($2); 929 rlay->dsttable = dsttable; 930 rlay->dstmode = $3; 931 rlay->dstcheck = $4; 932 rlay->dsttable->flags |= F_USED; 933 } 934 | PROTO STRING { 935 struct protocol *p; 936 937 TAILQ_FOREACH(p, &conf->protos, entry) 938 if (!strcmp(p->name, $2)) 939 break; 940 if (p == NULL) { 941 yyerror("no such protocol: %s", $2); 942 free($2); 943 YYERROR; 944 } 945 p->flags |= F_USED; 946 rlay->proto = p; 947 free($2); 948 } 949 | NAT LOOKUP { rlay->flags |= F_NATLOOK; } 950 | TIMEOUT number { rlay->timeout.tv_sec = $2; } 951 | DISABLE { rlay->flags |= F_DISABLE; } 952 ; 953 954dstmode : /* empty */ { $$ = RELAY_DSTMODE_DEFAULT; } 955 | LOADBALANCE { $$ = RELAY_DSTMODE_LOADBALANCE; } 956 | ROUNDROBIN { $$ = RELAY_DSTMODE_ROUNDROBIN; } 957 | HASH { $$ = RELAY_DSTMODE_HASH; } 958 ; 959 960docheck : /* empty */ { $$ = 1; } 961 | NO CHECK { $$ = 0; } 962 ; 963 964interface : /*empty*/ { $$ = NULL; } 965 | INTERFACE STRING { $$ = $2; } 966 ; 967 968host : HOST STRING retry { 969 struct address *a; 970 struct addresslist al; 971 972 if (($$ = calloc(1, sizeof(*($$)))) == NULL) 973 fatal("out of memory"); 974 975 TAILQ_INIT(&al); 976 if (host($2, &al, 1, 0, NULL) <= 0) { 977 yyerror("invalid host %s", $2); 978 free($2); 979 free($$); 980 YYERROR; 981 } 982 a = TAILQ_FIRST(&al); 983 memcpy(&$$->ss, &a->ss, sizeof($$->ss)); 984 free(a); 985 986 if (strlcpy($$->name, $2, sizeof($$->name)) >= 987 sizeof($$->name)) { 988 yyerror("host name truncated"); 989 free($2); 990 free($$); 991 YYERROR; 992 } 993 free($2); 994 $$->id = last_host_id++; 995 $$->retry = $3; 996 if (last_host_id == INT_MAX) { 997 yyerror("too many hosts defined"); 998 free($$); 999 YYERROR; 1000 } 1001 } 1002 ; 1003 1004retry : /* nothing */ { $$ = 0; } 1005 | RETRY number { $$ = $2; } 1006 ; 1007 1008timeout : number 1009 { 1010 $$.tv_sec = $1 / 1000; 1011 $$.tv_usec = ($1 % 1000) * 1000; 1012 } 1013 ; 1014 1015log : /* empty */ { $$ = 0; } 1016 | LOG { $$ = 1; } 1017 ; 1018 1019comma : ',' 1020 | /* empty */ 1021 ; 1022 1023optnl : '\n' optnl 1024 | 1025 ; 1026 1027nl : '\n' optnl 1028 ; 1029 1030%% 1031 1032struct keywords { 1033 const char *k_name; 1034 int k_val; 1035}; 1036 1037int 1038yyerror(const char *fmt, ...) 1039{ 1040 va_list ap; 1041 1042 errors = 1; 1043 va_start(ap, fmt); 1044 fprintf(stderr, "%s:%d: ", infile, yylval.lineno); 1045 vfprintf(stderr, fmt, ap); 1046 fprintf(stderr, "\n"); 1047 va_end(ap); 1048 return (0); 1049} 1050 1051int 1052kw_cmp(const void *k, const void *e) 1053{ 1054 1055 return (strcmp(k, ((const struct keywords *)e)->k_name)); 1056} 1057 1058int 1059lookup(char *s) 1060{ 1061 /* this has to be sorted always */ 1062 static const struct keywords keywords[] = { 1063 { "all", ALL }, 1064 { "append", APPEND }, 1065 { "backlog", BACKLOG }, 1066 { "backup", BACKUP }, 1067 { "buffer", BUFFER }, 1068 { "cache", CACHE }, 1069 { "change", CHANGE }, 1070 { "check", CHECK }, 1071 { "ciphers", CIPHERS }, 1072 { "code", CODE }, 1073 { "cookie", COOKIE }, 1074 { "demote", DEMOTE }, 1075 { "digest", DIGEST }, 1076 { "disable", DISABLE }, 1077 { "expect", EXPECT }, 1078 { "external", EXTERNAL }, 1079 { "filter", FILTER }, 1080 { "forward", FORWARD }, 1081 { "from", FROM }, 1082 { "hash", HASH }, 1083 { "header", HEADER }, 1084 { "host", HOST }, 1085 { "icmp", ICMP }, 1086 { "interface", INTERFACE }, 1087 { "interval", INTERVAL }, 1088 { "listen", LISTEN }, 1089 { "loadbalance", LOADBALANCE }, 1090 { "log", LOG }, 1091 { "lookup", LOOKUP }, 1092 { "mark", MARK }, 1093 { "marked", MARKED }, 1094 { "nat", NAT }, 1095 { "no", NO }, 1096 { "nodelay", NODELAY }, 1097 { "nothing", NOTHING }, 1098 { "on", ON }, 1099 { "port", PORT }, 1100 { "prefork", PREFORK }, 1101 { "protocol", PROTO }, 1102 { "real", REAL }, 1103 { "relay", RELAY }, 1104 { "remove", REMOVE }, 1105 { "request", REQUEST }, 1106 { "response", RESPONSE }, 1107 { "retry", RETRY }, 1108 { "roundrobin", ROUNDROBIN }, 1109 { "sack", SACK }, 1110 { "send", SEND }, 1111 { "service", SERVICE }, 1112 { "session", SESSION }, 1113 { "socket", SOCKET }, 1114 { "ssl", SSL }, 1115 { "sticky-address", STICKYADDR }, 1116 { "table", TABLE }, 1117 { "tag", TAG }, 1118 { "tcp", TCP }, 1119 { "timeout", TIMEOUT }, 1120 { "to", TO }, 1121 { "updates", UPDATES }, 1122 { "url", URL }, 1123 { "virtual", VIRTUAL } 1124 }; 1125 const struct keywords *p; 1126 1127 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 1128 sizeof(keywords[0]), kw_cmp); 1129 1130 if (p) 1131 return (p->k_val); 1132 else 1133 return (STRING); 1134} 1135 1136#define MAXPUSHBACK 128 1137 1138char *parsebuf; 1139int parseindex; 1140char pushback_buffer[MAXPUSHBACK]; 1141int pushback_index = 0; 1142 1143int 1144lgetc(FILE *f, int *keep) 1145{ 1146 int c, next; 1147 1148 *keep = 0; 1149 if (parsebuf) { 1150 /* Read character from the parsebuffer instead of input. */ 1151 if (parseindex >= 0) { 1152 c = parsebuf[parseindex++]; 1153 if (c != '\0') 1154 return (c); 1155 parsebuf = NULL; 1156 } else 1157 parseindex++; 1158 } 1159 1160 if (pushback_index) 1161 return (pushback_buffer[--pushback_index]); 1162 1163 while ((c = getc(f)) == '\\') { 1164 next = getc(f); 1165 if (next == 'n') { 1166 *keep = 1; 1167 c = '\n'; 1168 break; 1169 } else if (next == 'r') { 1170 *keep = 1; 1171 c = '\r'; 1172 break; 1173 } else if (next != '\n') { 1174 c = next; 1175 break; 1176 } 1177 yylval.lineno = lineno; 1178 lineno++; 1179 } 1180 if (c == '\t' || c == ' ') { 1181 /* Compress blanks to a single space. */ 1182 do { 1183 c = getc(f); 1184 } while (c == '\t' || c == ' '); 1185 ungetc(c, f); 1186 c = ' '; 1187 } 1188 1189 return (c); 1190} 1191 1192int 1193lungetc(int c) 1194{ 1195 if (c == EOF) 1196 return (EOF); 1197 if (parsebuf) { 1198 parseindex--; 1199 if (parseindex >= 0) 1200 return (c); 1201 } 1202 if (pushback_index < MAXPUSHBACK-1) 1203 return (pushback_buffer[pushback_index++] = c); 1204 else 1205 return (EOF); 1206} 1207 1208int 1209findeol(void) 1210{ 1211 int c; 1212 int k; 1213 1214 parsebuf = NULL; 1215 pushback_index = 0; 1216 1217 /* skip to either EOF or the first real EOL */ 1218 while (1) { 1219 c = lgetc(fin, &k); 1220 if (c == '\n' && k == 0) { 1221 lineno++; 1222 break; 1223 } 1224 if (c == EOF) 1225 break; 1226 } 1227 return (ERROR); 1228} 1229 1230int 1231yylex(void) 1232{ 1233 char buf[8096]; 1234 char *p, *val; 1235 int endc, c; 1236 int token; 1237 int keep; 1238 1239top: 1240 p = buf; 1241 while ((c = lgetc(fin, &keep)) == ' ') 1242 ; /* nothing */ 1243 1244 yylval.lineno = lineno; 1245 if (c == '#') 1246 do { 1247 while ((c = lgetc(fin, &keep)) != '\n' && c != EOF) 1248 ; /* nothing */ 1249 } while (keep == 1); 1250 if (c == '$' && parsebuf == NULL) { 1251 while (1) { 1252 if ((c = lgetc(fin, &keep)) == EOF) 1253 return (0); 1254 1255 if (p + 1 >= buf + sizeof(buf) - 1) { 1256 yyerror("string too long"); 1257 return (findeol()); 1258 } 1259 if (isalnum(c) || c == '_') { 1260 *p++ = (char)c; 1261 continue; 1262 } 1263 *p = '\0'; 1264 lungetc(c); 1265 break; 1266 } 1267 val = symget(buf); 1268 if (val == NULL) { 1269 yyerror("macro '%s' not defined", buf); 1270 return (findeol()); 1271 } 1272 parsebuf = val; 1273 parseindex = 0; 1274 goto top; 1275 } 1276 1277 switch (c) { 1278 case '\'': 1279 case '"': 1280 endc = c; 1281 while (1) { 1282 if ((c = lgetc(fin, &keep)) == EOF) 1283 return (0); 1284 if (c == endc) { 1285 *p = '\0'; 1286 break; 1287 } 1288 if (c == '\n' && keep == 0) { 1289 lineno++; 1290 continue; 1291 } 1292 if (p + 1 >= buf + sizeof(buf) - 1) { 1293 yyerror("string too long"); 1294 return (findeol()); 1295 } 1296 *p++ = (char)c; 1297 } 1298 yylval.v.string = strdup(buf); 1299 if (yylval.v.string == NULL) 1300 errx(1, "yylex: strdup"); 1301 return (STRING); 1302 } 1303 1304#define allowed_in_string(x) \ 1305 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 1306 x != '{' && x != '}' && \ 1307 x != '!' && x != '=' && x != '#' && \ 1308 x != ',')) 1309 1310 if (isalnum(c) || c == ':' || c == '_') { 1311 do { 1312 *p++ = c; 1313 if ((unsigned)(p-buf) >= sizeof(buf)) { 1314 yyerror("string too long"); 1315 return (findeol()); 1316 } 1317 } while ((c = lgetc(fin, &keep)) != EOF && 1318 (allowed_in_string(c))); 1319 lungetc(c); 1320 *p = '\0'; 1321 if ((token = lookup(buf)) == STRING) 1322 if ((yylval.v.string = strdup(buf)) == NULL) 1323 err(1, "yylex: strdup"); 1324 return (token); 1325 } 1326 if (c == '\n') { 1327 yylval.lineno = lineno; 1328 lineno++; 1329 } 1330 if (c == EOF) 1331 return (0); 1332 return (c); 1333} 1334 1335int 1336parse_config(struct hoststated *x_conf, const char *filename, int opts) 1337{ 1338 struct sym *sym, *next; 1339 1340 conf = x_conf; 1341 1342 TAILQ_INIT(&conf->services); 1343 TAILQ_INIT(&conf->tables); 1344 TAILQ_INIT(&conf->protos); 1345 TAILQ_INIT(&conf->relays); 1346 1347 memset(&conf->empty_table, 0, sizeof(conf->empty_table)); 1348 conf->empty_table.id = EMPTY_TABLE; 1349 conf->empty_table.flags |= F_DISABLE; 1350 (void)strlcpy(conf->empty_table.name, "empty", 1351 sizeof(conf->empty_table.name)); 1352 1353 bzero(&conf->proto_default, sizeof(conf->proto_default)); 1354 conf->proto_default.flags = F_USED; 1355 conf->proto_default.cache = RELAY_CACHESIZE; 1356 conf->proto_default.type = RELAY_PROTO_TCP; 1357 (void)strlcpy(conf->proto_default.name, "default", 1358 sizeof(conf->proto_default.name)); 1359 RB_INIT(&conf->proto_default.request_tree); 1360 RB_INIT(&conf->proto_default.response_tree); 1361 TAILQ_INSERT_TAIL(&conf->protos, &conf->proto_default, entry); 1362 1363 conf->timeout.tv_sec = CHECK_TIMEOUT / 1000; 1364 conf->timeout.tv_usec = (CHECK_TIMEOUT % 1000) * 1000; 1365 conf->interval.tv_sec = CHECK_INTERVAL; 1366 conf->interval.tv_usec = 0; 1367 conf->prefork_relay = RELAY_NUMPROC; 1368 conf->statinterval.tv_sec = RELAY_STATINTERVAL; 1369 conf->opts = opts; 1370 1371 if ((fin = fopen(filename, "r")) == NULL) { 1372 warn("%s", filename); 1373 return (0); 1374 } 1375 infile = filename; 1376 setservent(1); 1377 yyparse(); 1378 endservent(); 1379 fclose(fin); 1380 1381 /* Free macros and check which have not been used. */ 1382 for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) { 1383 next = TAILQ_NEXT(sym, entries); 1384 if ((conf->opts & HOSTSTATED_OPT_VERBOSE) && !sym->used) 1385 fprintf(stderr, "warning: macro '%s' not " 1386 "used\n", sym->nam); 1387 if (!sym->persist) { 1388 free(sym->nam); 1389 free(sym->val); 1390 TAILQ_REMOVE(&symhead, sym, entries); 1391 free(sym); 1392 } 1393 } 1394 1395 if (TAILQ_EMPTY(&conf->services) && TAILQ_EMPTY(&conf->relays)) { 1396 log_warnx("no services, nothing to do"); 1397 errors++; 1398 } 1399 1400 if (timercmp(&conf->timeout, &conf->interval, >=)) { 1401 log_warnx("global timeout exceeds interval"); 1402 errors++; 1403 } 1404 1405 /* Verify that every table is used */ 1406 TAILQ_FOREACH(table, &conf->tables, entry) { 1407 if (!(table->flags & F_USED)) { 1408 log_warnx("unused table: %s", table->name); 1409 errors++; 1410 } 1411 if (timercmp(&table->timeout, &conf->interval, >=)) { 1412 log_warnx("table timeout exceeds interval: %s", 1413 table->name); 1414 errors++; 1415 } 1416 } 1417 1418 /* Verify that every non-default protocol is used */ 1419 TAILQ_FOREACH(proto, &conf->protos, entry) { 1420 if (!(proto->flags & F_USED)) { 1421 log_warnx("unused protocol: %s", proto->name); 1422 errors++; 1423 } 1424 } 1425 1426 if (errors) { 1427 bzero(&conf, sizeof (*conf)); 1428 return (-1); 1429 } 1430 1431 return (0); 1432} 1433 1434int 1435symset(const char *nam, const char *val, int persist) 1436{ 1437 struct sym *sym; 1438 1439 for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); 1440 sym = TAILQ_NEXT(sym, entries)) 1441 ; /* nothing */ 1442 1443 if (sym != NULL) { 1444 if (sym->persist == 1) 1445 return (0); 1446 else { 1447 free(sym->nam); 1448 free(sym->val); 1449 TAILQ_REMOVE(&symhead, sym, entries); 1450 free(sym); 1451 } 1452 } 1453 if ((sym = calloc(1, sizeof(*sym))) == NULL) 1454 return (-1); 1455 1456 sym->nam = strdup(nam); 1457 if (sym->nam == NULL) { 1458 free(sym); 1459 return (-1); 1460 } 1461 sym->val = strdup(val); 1462 if (sym->val == NULL) { 1463 free(sym->nam); 1464 free(sym); 1465 return (-1); 1466 } 1467 sym->used = 0; 1468 sym->persist = persist; 1469 TAILQ_INSERT_TAIL(&symhead, sym, entries); 1470 return (0); 1471} 1472 1473int 1474cmdline_symset(char *s) 1475{ 1476 char *sym, *val; 1477 int ret; 1478 size_t len; 1479 1480 if ((val = strrchr(s, '=')) == NULL) 1481 return (-1); 1482 1483 len = strlen(s) - strlen(val) + 1; 1484 if ((sym = malloc(len)) == NULL) 1485 errx(1, "cmdline_symset: malloc"); 1486 1487 (void)strlcpy(sym, s, len); 1488 1489 ret = symset(sym, val + 1, 1); 1490 free(sym); 1491 1492 return (ret); 1493} 1494 1495char * 1496symget(const char *nam) 1497{ 1498 struct sym *sym; 1499 1500 TAILQ_FOREACH(sym, &symhead, entries) 1501 if (strcmp(nam, sym->nam) == 0) { 1502 sym->used = 1; 1503 return (sym->val); 1504 } 1505 return (NULL); 1506} 1507 1508struct address * 1509host_v4(const char *s) 1510{ 1511 struct in_addr ina; 1512 struct sockaddr_in *sain; 1513 struct address *h; 1514 1515 bzero(&ina, sizeof(ina)); 1516 if (inet_pton(AF_INET, s, &ina) != 1) 1517 return (NULL); 1518 1519 if ((h = calloc(1, sizeof(*h))) == NULL) 1520 fatal(NULL); 1521 sain = (struct sockaddr_in *)&h->ss; 1522 sain->sin_len = sizeof(struct sockaddr_in); 1523 sain->sin_family = AF_INET; 1524 sain->sin_addr.s_addr = ina.s_addr; 1525 1526 return (h); 1527} 1528 1529struct address * 1530host_v6(const char *s) 1531{ 1532 struct in6_addr ina6; 1533 struct sockaddr_in6 *sin6; 1534 struct address *h; 1535 1536 bzero(&ina6, sizeof(ina6)); 1537 if (inet_pton(AF_INET6, s, &ina6) != 1) 1538 return (NULL); 1539 1540 if ((h = calloc(1, sizeof(*h))) == NULL) 1541 fatal(NULL); 1542 sin6 = (struct sockaddr_in6 *)&h->ss; 1543 sin6->sin6_len = sizeof(struct sockaddr_in6); 1544 sin6->sin6_family = AF_INET6; 1545 memcpy(&sin6->sin6_addr, &ina6, sizeof(ina6)); 1546 1547 return (h); 1548} 1549 1550int 1551host_dns(const char *s, struct addresslist *al, int max, 1552 in_port_t port, const char *ifname) 1553{ 1554 struct addrinfo hints, *res0, *res; 1555 int error, cnt = 0; 1556 struct sockaddr_in *sain; 1557 struct sockaddr_in6 *sin6; 1558 struct address *h; 1559 1560 bzero(&hints, sizeof(hints)); 1561 hints.ai_family = PF_UNSPEC; 1562 hints.ai_socktype = SOCK_DGRAM; /* DUMMY */ 1563 error = getaddrinfo(s, NULL, &hints, &res0); 1564 if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME) 1565 return (0); 1566 if (error) { 1567 log_warnx("host_dns: could not parse \"%s\": %s", s, 1568 gai_strerror(error)); 1569 return (-1); 1570 } 1571 1572 for (res = res0; res && cnt < max; res = res->ai_next) { 1573 if (res->ai_family != AF_INET && 1574 res->ai_family != AF_INET6) 1575 continue; 1576 if ((h = calloc(1, sizeof(*h))) == NULL) 1577 fatal(NULL); 1578 1579 h->port = port; 1580 if (ifname != NULL) { 1581 if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >= 1582 sizeof(h->ifname)) 1583 log_warnx("host_dns: interface name truncated"); 1584 return (-1); 1585 } 1586 h->ss.ss_family = res->ai_family; 1587 if (res->ai_family == AF_INET) { 1588 sain = (struct sockaddr_in *)&h->ss; 1589 sain->sin_len = sizeof(struct sockaddr_in); 1590 sain->sin_addr.s_addr = ((struct sockaddr_in *) 1591 res->ai_addr)->sin_addr.s_addr; 1592 } else { 1593 sin6 = (struct sockaddr_in6 *)&h->ss; 1594 sin6->sin6_len = sizeof(struct sockaddr_in6); 1595 memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *) 1596 res->ai_addr)->sin6_addr, sizeof(struct in6_addr)); 1597 } 1598 1599 TAILQ_INSERT_HEAD(al, h, entry); 1600 cnt++; 1601 } 1602 if (cnt == max && res) { 1603 log_warnx("host_dns: %s resolves to more than %d hosts", 1604 s, max); 1605 } 1606 freeaddrinfo(res0); 1607 return (cnt); 1608} 1609 1610int 1611host(const char *s, struct addresslist *al, int max, 1612 in_port_t port, const char *ifname) 1613{ 1614 struct address *h; 1615 1616 h = host_v4(s); 1617 1618 /* IPv6 address? */ 1619 if (h == NULL) 1620 h = host_v6(s); 1621 1622 if (h != NULL) { 1623 h->port = port; 1624 if (ifname != NULL) { 1625 if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >= 1626 sizeof(h->ifname)) { 1627 log_warnx("host: interface name truncated"); 1628 return (-1); 1629 } 1630 } 1631 1632 TAILQ_INSERT_HEAD(al, h, entry); 1633 return (1); 1634 } 1635 1636 return (host_dns(s, al, max, port, ifname)); 1637} 1638