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