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