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