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