parse.y revision 1.161
1/* $OpenBSD: parse.y,v 1.161 2012/01/21 13:40:48 camield Exp $ */ 2 3/* 4 * Copyright (c) 2007-2011 Reyk Floeter <reyk@openbsd.org> 5 * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> 6 * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> 7 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 8 * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org> 9 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> 10 * Copyright (c) 2001 Markus Friedl. All rights reserved. 11 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. 12 * Copyright (c) 2001 Theo de Raadt. All rights reserved. 13 * 14 * Permission to use, copy, modify, and distribute this software for any 15 * purpose with or without fee is hereby granted, provided that the above 16 * copyright notice and this permission notice appear in all copies. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 19 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 20 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 21 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 22 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 23 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 24 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 25 */ 26 27%{ 28#include <sys/types.h> 29#include <sys/socket.h> 30#include <sys/stat.h> 31#include <sys/queue.h> 32#include <sys/ioctl.h> 33 34#include <net/if.h> 35#include <net/pfvar.h> 36#include <netinet/in.h> 37#include <arpa/inet.h> 38#include <arpa/nameser.h> 39#include <net/route.h> 40 41#include <ctype.h> 42#include <unistd.h> 43#include <err.h> 44#include <errno.h> 45#include <event.h> 46#include <limits.h> 47#include <stdint.h> 48#include <stdarg.h> 49#include <stdio.h> 50#include <netdb.h> 51#include <string.h> 52#include <ifaddrs.h> 53 54#include <openssl/ssl.h> 55 56#include "relayd.h" 57 58TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); 59static struct file { 60 TAILQ_ENTRY(file) entry; 61 FILE *stream; 62 char *name; 63 int lineno; 64 int errors; 65} *file, *topfile; 66struct file *pushfile(const char *, int); 67int popfile(void); 68int check_file_secrecy(int, const char *); 69int yyparse(void); 70int yylex(void); 71int yyerror(const char *, ...); 72int kw_cmp(const void *, const void *); 73int lookup(char *); 74int lgetc(int); 75int lungetc(int); 76int findeol(void); 77 78TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); 79struct sym { 80 TAILQ_ENTRY(sym) entry; 81 int used; 82 int persist; 83 char *nam; 84 char *val; 85}; 86int symset(const char *, const char *, int); 87char *symget(const char *); 88 89struct relayd *conf = NULL; 90static int errors = 0; 91static int loadcfg = 0; 92objid_t last_rdr_id = 0; 93objid_t last_table_id = 0; 94objid_t last_host_id = 0; 95objid_t last_relay_id = 0; 96objid_t last_proto_id = 0; 97objid_t last_rt_id = 0; 98objid_t last_nr_id = 0; 99 100static struct rdr *rdr = NULL; 101static struct table *table = NULL; 102static struct relay *rlay = NULL; 103static struct host *hst = NULL; 104struct relaylist relays; 105static struct protocol *proto = NULL; 106static struct protonode node; 107static struct router *router = NULL; 108static u_int16_t label = 0; 109static in_port_t tableport = 0; 110static int nodedirection; 111 112struct address *host_v4(const char *); 113struct address *host_v6(const char *); 114int host_dns(const char *, struct addresslist *, 115 int, struct portrange *, const char *, int); 116int host_if(const char *, struct addresslist *, 117 int, struct portrange *, const char *, int); 118int host(const char *, struct addresslist *, 119 int, struct portrange *, const char *, int); 120void host_free(struct addresslist *); 121 122struct table *table_inherit(struct table *); 123struct relay *relay_inherit(struct relay *, struct relay *); 124int getservice(char *); 125int is_if_in_group(const char *, const char *); 126 127typedef struct { 128 union { 129 int64_t number; 130 char *string; 131 struct host *host; 132 struct timeval tv; 133 struct table *table; 134 struct portrange port; 135 struct { 136 struct sockaddr_storage ss; 137 char name[MAXHOSTNAMELEN]; 138 } addr; 139 struct { 140 enum digest_type type; 141 char *digest; 142 } digest; 143 } v; 144 int lineno; 145} YYSTYPE; 146 147%} 148 149%token ALL APPEND BACKLOG BACKUP BUFFER CA CACHE CHANGE CHECK 150%token CIPHERS CODE COOKIE DEMOTE DIGEST DISABLE ERROR EXPECT 151%token EXTERNAL FILENAME FILTER FORWARD FROM HASH HEADER HOST ICMP 152%token INCLUDE INET INET6 INTERFACE INTERVAL IP LABEL LISTEN 153%token LOADBALANCE LOG LOOKUP MARK MARKED MODE NAT NO DESTINATION 154%token NODELAY NOTHING ON PARENT PATH PORT PREFORK PRIORITY PROTO 155%token QUERYSTR REAL REDIRECT RELAY REMOVE REQUEST RESPONSE RETRY 156%token RETURN ROUNDROBIN ROUTE SACK SCRIPT SEND SESSION SOCKET SPLICE 157%token SSL STICKYADDR STYLE TABLE TAG TCP TIMEOUT TO ROUTER RTLABEL 158%token TRANSPARENT TRAP UPDATES URL VIRTUAL WITH TTL RTABLE MATCH 159%token <v.string> STRING 160%token <v.number> NUMBER 161%type <v.string> hostname interface table 162%type <v.number> http_type loglevel mark 163%type <v.number> direction dstmode flag forwardmode retry 164%type <v.number> optssl optsslclient sslcache 165%type <v.number> redirect_proto relay_proto match 166%type <v.port> port 167%type <v.host> host 168%type <v.addr> address 169%type <v.tv> timeout 170%type <v.digest> digest 171%type <v.table> tablespec 172 173%% 174 175grammar : /* empty */ 176 | grammar include '\n' 177 | grammar '\n' 178 | grammar varset '\n' 179 | grammar main '\n' 180 | grammar rdr '\n' 181 | grammar tabledef '\n' 182 | grammar relay '\n' 183 | grammar proto '\n' 184 | grammar router '\n' 185 | grammar error '\n' { file->errors++; } 186 ; 187 188include : INCLUDE STRING { 189 struct file *nfile; 190 191 if ((nfile = pushfile($2, 0)) == NULL) { 192 yyerror("failed to include file %s", $2); 193 free($2); 194 YYERROR; 195 } 196 free($2); 197 198 file = nfile; 199 lungetc('\n'); 200 } 201 ; 202 203optssl : /*empty*/ { $$ = 0; } 204 | SSL { $$ = 1; } 205 ; 206 207optsslclient : /*empty*/ { $$ = 0; } 208 | WITH SSL { $$ = 1; } 209 ; 210 211http_type : STRING { 212 if (strcmp("https", $1) == 0) { 213 $$ = 1; 214 } else if (strcmp("http", $1) == 0) { 215 $$ = 0; 216 } else { 217 yyerror("invalid check type: %s", $1); 218 free($1); 219 YYERROR; 220 } 221 free($1); 222 } 223 ; 224 225hostname : /* empty */ { 226 $$ = strdup(""); 227 if ($$ == NULL) 228 fatal("calloc"); 229 } 230 | HOST STRING { 231 if (asprintf(&$$, "Host: %s\r\nConnection: close\r\n", 232 $2) == -1) 233 fatal("asprintf"); 234 } 235 ; 236 237relay_proto : /* empty */ { $$ = RELAY_PROTO_TCP; } 238 | TCP { $$ = RELAY_PROTO_TCP; } 239 | STRING { 240 if (strcmp("http", $1) == 0) { 241 $$ = RELAY_PROTO_HTTP; 242 } else if (strcmp("dns", $1) == 0) { 243 $$ = RELAY_PROTO_DNS; 244 } else { 245 yyerror("invalid protocol type: %s", $1); 246 free($1); 247 YYERROR; 248 } 249 free($1); 250 } 251 ; 252 253redirect_proto : /* empty */ { $$ = IPPROTO_TCP; } 254 | TCP { $$ = IPPROTO_TCP; } 255 | STRING { 256 struct protoent *p; 257 258 if ((p = getprotobyname($1)) == NULL) { 259 yyerror("invalid protocol: %s", $1); 260 free($1); 261 YYERROR; 262 } 263 free($1); 264 265 $$ = p->p_proto; 266 } 267 ; 268 269eflags_l : eflags comma eflags_l 270 | eflags 271 ; 272 273opteflags : /* nothing */ 274 | eflags 275 ; 276 277eflags : STYLE STRING 278 { 279 if ((proto->style = strdup($2)) == NULL) 280 fatal("out of memory"); 281 free($2); 282 } 283 ; 284 285port : PORT STRING { 286 char *a, *b; 287 int p[2]; 288 289 p[0] = p[1] = 0; 290 291 a = $2; 292 b = strchr($2, ':'); 293 if (b == NULL) 294 $$.op = PF_OP_EQ; 295 else { 296 *b++ = '\0'; 297 if ((p[1] = getservice(b)) == -1) { 298 free($2); 299 YYERROR; 300 } 301 $$.op = PF_OP_RRG; 302 } 303 if ((p[0] = getservice(a)) == -1) { 304 free($2); 305 YYERROR; 306 } 307 $$.val[0] = p[0]; 308 $$.val[1] = p[1]; 309 free($2); 310 } 311 | PORT NUMBER { 312 if ($2 <= 0 || $2 >= (int)USHRT_MAX) { 313 yyerror("invalid port: %d", $2); 314 YYERROR; 315 } 316 $$.val[0] = htons($2); 317 $$.op = PF_OP_EQ; 318 } 319 ; 320 321varset : STRING '=' STRING { 322 if (symset($1, $3, 0) == -1) 323 fatal("cannot store variable"); 324 free($1); 325 free($3); 326 } 327 ; 328 329sendbuf : NOTHING { 330 table->sendbuf = NULL; 331 } 332 | STRING { 333 table->sendbuf = strdup($1); 334 if (table->sendbuf == NULL) 335 fatal("out of memory"); 336 free($1); 337 } 338 ; 339 340main : INTERVAL NUMBER { 341 if (loadcfg) 342 break; 343 if ((conf->sc_interval.tv_sec = $2) < 0) { 344 yyerror("invalid interval: %d", $2); 345 YYERROR; 346 } 347 } 348 | LOG loglevel { 349 if (loadcfg) 350 break; 351 conf->sc_opts |= $2; 352 } 353 | TIMEOUT timeout { 354 if (loadcfg) 355 break; 356 bcopy(&$2, &conf->sc_timeout, sizeof(struct timeval)); 357 } 358 | PREFORK NUMBER { 359 if (loadcfg) 360 break; 361 if ($2 <= 0 || $2 > RELAY_MAXPROC) { 362 yyerror("invalid number of preforked " 363 "relays: %d", $2); 364 YYERROR; 365 } 366 conf->sc_prefork_relay = $2; 367 } 368 | SEND TRAP { 369 if (loadcfg) 370 break; 371 conf->sc_flags |= F_TRAP; 372 } 373 ; 374 375loglevel : UPDATES { $$ = RELAYD_OPT_LOGUPDATE; } 376 | ALL { $$ = RELAYD_OPT_LOGALL; } 377 ; 378 379rdr : REDIRECT STRING { 380 struct rdr *srv; 381 382 conf->sc_flags |= F_NEEDPF; 383 384 if (!loadcfg) { 385 free($2); 386 YYACCEPT; 387 } 388 389 TAILQ_FOREACH(srv, conf->sc_rdrs, entry) 390 if (!strcmp(srv->conf.name, $2)) 391 break; 392 if (srv != NULL) { 393 yyerror("redirection %s defined twice", $2); 394 free($2); 395 YYERROR; 396 } 397 if ((srv = calloc(1, sizeof (*srv))) == NULL) 398 fatal("out of memory"); 399 400 if (strlcpy(srv->conf.name, $2, 401 sizeof(srv->conf.name)) >= 402 sizeof(srv->conf.name)) { 403 yyerror("redirection name truncated"); 404 free(srv); 405 YYERROR; 406 } 407 free($2); 408 srv->conf.id = ++last_rdr_id; 409 srv->conf.timeout.tv_sec = RELAY_TIMEOUT; 410 if (last_rdr_id == INT_MAX) { 411 yyerror("too many redirections defined"); 412 free(srv); 413 YYERROR; 414 } 415 rdr = srv; 416 } '{' optnl rdropts_l '}' { 417 if (rdr->table == NULL) { 418 yyerror("redirection %s has no table", 419 rdr->conf.name); 420 YYERROR; 421 } 422 if (TAILQ_EMPTY(&rdr->virts)) { 423 yyerror("redirection %s has no virtual ip", 424 rdr->conf.name); 425 YYERROR; 426 } 427 conf->sc_rdrcount++; 428 if (rdr->backup == NULL) { 429 rdr->conf.backup_id = 430 conf->sc_empty_table.conf.id; 431 rdr->backup = &conf->sc_empty_table; 432 } else if (rdr->backup->conf.port != 433 rdr->table->conf.port) { 434 yyerror("redirection %s uses two different " 435 "ports for its table and backup table", 436 rdr->conf.name); 437 YYERROR; 438 } 439 if (!(rdr->conf.flags & F_DISABLE)) 440 rdr->conf.flags |= F_ADD; 441 TAILQ_INSERT_TAIL(conf->sc_rdrs, rdr, entry); 442 tableport = 0; 443 rdr = NULL; 444 } 445 ; 446 447rdropts_l : rdropts_l rdroptsl nl 448 | rdroptsl optnl 449 ; 450 451rdroptsl : forwardmode TO tablespec interface { 452 switch ($1) { 453 case FWD_NORMAL: 454 if ($4 == NULL) 455 break; 456 yyerror("superfluous interface"); 457 YYERROR; 458 case FWD_ROUTE: 459 if ($4 != NULL) 460 break; 461 yyerror("missing interface to route to"); 462 YYERROR; 463 case FWD_TRANS: 464 yyerror("no transparent forward here"); 465 YYERROR; 466 } 467 if ($4 != NULL) { 468 strlcpy($3->conf.ifname, $4, 469 sizeof($3->conf.ifname)); 470 free($4); 471 } 472 473 if ($3->conf.check == CHECK_NOCHECK) { 474 yyerror("table %s has no check", $3->conf.name); 475 purge_table(conf->sc_tables, $3); 476 YYERROR; 477 } 478 if (rdr->backup) { 479 yyerror("only one backup table is allowed"); 480 purge_table(conf->sc_tables, $3); 481 YYERROR; 482 } 483 if (rdr->table) { 484 rdr->backup = $3; 485 rdr->conf.backup_id = $3->conf.id; 486 } else { 487 rdr->table = $3; 488 rdr->conf.table_id = $3->conf.id; 489 } 490 $3->conf.fwdmode = $1; 491 $3->conf.rdrid = rdr->conf.id; 492 $3->conf.flags |= F_USED; 493 } 494 | LISTEN ON STRING redirect_proto port interface { 495 if (host($3, &rdr->virts, 496 SRV_MAX_VIRTS, &$5, $6, $4) <= 0) { 497 yyerror("invalid virtual ip: %s", $3); 498 free($3); 499 free($6); 500 YYERROR; 501 } 502 free($3); 503 free($6); 504 if (rdr->conf.port == 0) 505 rdr->conf.port = $5.val[0]; 506 tableport = rdr->conf.port; 507 } 508 | DISABLE { rdr->conf.flags |= F_DISABLE; } 509 | STICKYADDR { rdr->conf.flags |= F_STICKY; } 510 | match TAG STRING { 511 conf->sc_flags |= F_NEEDPF; 512 if (strlcpy(rdr->conf.tag, $3, 513 sizeof(rdr->conf.tag)) >= 514 sizeof(rdr->conf.tag)) { 515 yyerror("redirection tag name truncated"); 516 free($3); 517 YYERROR; 518 } 519 if ($1) 520 rdr->conf.flags |= F_MATCH; 521 free($3); 522 } 523 | SESSION TIMEOUT NUMBER { 524 if ((rdr->conf.timeout.tv_sec = $3) < 0) { 525 yyerror("invalid timeout: %d", $3); 526 YYERROR; 527 } 528 } 529 | include 530 ; 531 532match : /* empty */ { $$ = 0; } 533 | MATCH { $$ = 1; } 534 ; 535 536forwardmode : FORWARD { $$ = FWD_NORMAL; } 537 | ROUTE { $$ = FWD_ROUTE; } 538 | TRANSPARENT FORWARD { $$ = FWD_TRANS; } 539 ; 540 541table : '<' STRING '>' { 542 if (strlen($2) >= TABLE_NAME_SIZE) { 543 yyerror("invalid table name"); 544 free($2); 545 YYERROR; 546 } 547 $$ = $2; 548 } 549 ; 550 551tabledef : TABLE table { 552 struct table *tb; 553 554 if (!loadcfg) { 555 free($2); 556 YYACCEPT; 557 } 558 559 TAILQ_FOREACH(tb, conf->sc_tables, entry) 560 if (!strcmp(tb->conf.name, $2)) 561 break; 562 if (tb != NULL) { 563 yyerror("table %s defined twice", $2); 564 free($2); 565 YYERROR; 566 } 567 568 if ((tb = calloc(1, sizeof (*tb))) == NULL) 569 fatal("out of memory"); 570 571 (void)strlcpy(tb->conf.name, $2, sizeof(tb->conf.name)); 572 free($2); 573 574 tb->conf.id = 0; /* will be set later */ 575 bcopy(&conf->sc_timeout, &tb->conf.timeout, 576 sizeof(struct timeval)); 577 TAILQ_INIT(&tb->hosts); 578 table = tb; 579 } tabledefopts_l { 580 if (TAILQ_EMPTY(&table->hosts)) { 581 yyerror("table %s has no hosts", 582 table->conf.name); 583 YYERROR; 584 } 585 conf->sc_tablecount++; 586 TAILQ_INSERT_TAIL(conf->sc_tables, table, entry); 587 } 588 ; 589 590tabledefopts_l : tabledefopts_l tabledefopts 591 | tabledefopts 592 ; 593 594tabledefopts : DISABLE { table->conf.flags |= F_DISABLE; } 595 | '{' optnl tablelist_l '}' 596 ; 597 598tablelist_l : tablelist comma tablelist_l 599 | tablelist optnl 600 ; 601 602tablelist : host { 603 $1->conf.tableid = table->conf.id; 604 $1->tablename = table->conf.name; 605 TAILQ_INSERT_TAIL(&table->hosts, $1, entry); 606 } 607 | include 608 ; 609 610tablespec : table { 611 struct table *tb; 612 if ((tb = calloc(1, sizeof (*tb))) == NULL) 613 fatal("out of memory"); 614 (void)strlcpy(tb->conf.name, $1, sizeof(tb->conf.name)); 615 free($1); 616 table = tb; 617 } tableopts_l { 618 struct table *tb; 619 if (table->conf.port == 0) 620 table->conf.port = tableport; 621 else 622 table->conf.flags |= F_PORT; 623 if ((tb = table_inherit(table)) == NULL) 624 YYERROR; 625 $$ = tb; 626 } 627 ; 628 629tableopts_l : tableopts tableopts_l 630 | tableopts 631 ; 632 633tableopts : CHECK tablecheck 634 | port { 635 if ($1.op != PF_OP_EQ) { 636 yyerror("invalid port"); 637 YYERROR; 638 } 639 table->conf.port = $1.val[0]; 640 } 641 | TIMEOUT timeout { 642 bcopy(&$2, &table->conf.timeout, 643 sizeof(struct timeval)); 644 } 645 | DEMOTE STRING { 646 table->conf.flags |= F_DEMOTE; 647 if (strlcpy(table->conf.demote_group, $2, 648 sizeof(table->conf.demote_group)) 649 >= sizeof(table->conf.demote_group)) { 650 yyerror("yyparse: demote group name too long"); 651 free($2); 652 YYERROR; 653 } 654 free($2); 655 if (carp_demote_init(table->conf.demote_group, 1) 656 == -1) { 657 yyerror("yyparse: error initializing group " 658 "'%s'", table->conf.demote_group); 659 YYERROR; 660 } 661 } 662 | INTERVAL NUMBER { 663 if ($2 < conf->sc_interval.tv_sec || 664 $2 % conf->sc_interval.tv_sec) { 665 yyerror("table interval must be " 666 "divisible by global interval"); 667 YYERROR; 668 } 669 table->conf.skip_cnt = ($2 / conf->sc_interval.tv_sec) - 1; 670 } 671 | MODE dstmode { 672 switch ($2) { 673 case RELAY_DSTMODE_LOADBALANCE: 674 case RELAY_DSTMODE_HASH: 675 if (rdr != NULL) { 676 yyerror("mode not supported " 677 "for redirections"); 678 YYERROR; 679 } 680 /* FALLTHROUGH */ 681 case RELAY_DSTMODE_ROUNDROBIN: 682 if (rlay != NULL) 683 rlay->rl_conf.dstmode = $2; 684 break; 685 } 686 } 687 ; 688 689tablecheck : ICMP { table->conf.check = CHECK_ICMP; } 690 | TCP { table->conf.check = CHECK_TCP; } 691 | SSL { 692 table->conf.check = CHECK_TCP; 693 conf->sc_flags |= F_SSL; 694 table->conf.flags |= F_SSL; 695 } 696 | http_type STRING hostname CODE NUMBER { 697 if ($1) { 698 conf->sc_flags |= F_SSL; 699 table->conf.flags |= F_SSL; 700 } 701 table->conf.check = CHECK_HTTP_CODE; 702 if ((table->conf.retcode = $5) <= 0) { 703 yyerror("invalid HTTP code: %d", $5); 704 free($2); 705 free($3); 706 YYERROR; 707 } 708 if (asprintf(&table->sendbuf, 709 "HEAD %s HTTP/1.%c\r\n%s\r\n", 710 $2, strlen($3) ? '1' : '0', $3) == -1) 711 fatal("asprintf"); 712 free($2); 713 free($3); 714 if (table->sendbuf == NULL) 715 fatal("out of memory"); 716 } 717 | http_type STRING hostname digest { 718 if ($1) { 719 conf->sc_flags |= F_SSL; 720 table->conf.flags |= F_SSL; 721 } 722 table->conf.check = CHECK_HTTP_DIGEST; 723 if (asprintf(&table->sendbuf, 724 "GET %s HTTP/1.%c\r\n%s\r\n", 725 $2, strlen($3) ? '1' : '0', $3) == -1) 726 fatal("asprintf"); 727 free($2); 728 free($3); 729 if (table->sendbuf == NULL) 730 fatal("out of memory"); 731 (void)strlcpy(table->conf.digest, $4.digest, 732 sizeof(table->conf.digest)); 733 table->conf.digest_type = $4.type; 734 free($4.digest); 735 } 736 | SEND sendbuf EXPECT STRING optssl { 737 table->conf.check = CHECK_SEND_EXPECT; 738 if ($5) { 739 conf->sc_flags |= F_SSL; 740 table->conf.flags |= F_SSL; 741 } 742 if (strlcpy(table->conf.exbuf, $4, 743 sizeof(table->conf.exbuf)) 744 >= sizeof(table->conf.exbuf)) { 745 yyerror("yyparse: expect buffer truncated"); 746 free($4); 747 YYERROR; 748 } 749 translate_string(table->conf.exbuf); 750 free($4); 751 } 752 | SCRIPT STRING { 753 table->conf.check = CHECK_SCRIPT; 754 if (strlcpy(table->conf.path, $2, 755 sizeof(table->conf.path)) >= 756 sizeof(table->conf.path)) { 757 yyerror("script path truncated"); 758 free($2); 759 YYERROR; 760 } 761 conf->sc_flags |= F_SCRIPT; 762 free($2); 763 } 764 ; 765 766digest : DIGEST STRING 767 { 768 switch (strlen($2)) { 769 case 40: 770 $$.type = DIGEST_SHA1; 771 break; 772 case 32: 773 $$.type = DIGEST_MD5; 774 break; 775 default: 776 yyerror("invalid http digest"); 777 free($2); 778 YYERROR; 779 } 780 $$.digest = $2; 781 } 782 ; 783 784proto : relay_proto PROTO STRING { 785 struct protocol *p; 786 787 if (!loadcfg) { 788 free($3); 789 YYACCEPT; 790 } 791 792 if (strcmp($3, "default") == 0) { 793 p = &conf->sc_proto_default; 794 } else { 795 TAILQ_FOREACH(p, conf->sc_protos, entry) 796 if (!strcmp(p->name, $3)) 797 break; 798 } 799 if (p != NULL) { 800 yyerror("protocol %s defined twice", $3); 801 free($3); 802 YYERROR; 803 } 804 if ((p = calloc(1, sizeof (*p))) == NULL) 805 fatal("out of memory"); 806 807 if (strlcpy(p->name, $3, sizeof(p->name)) >= 808 sizeof(p->name)) { 809 yyerror("protocol name truncated"); 810 free(p); 811 YYERROR; 812 } 813 free($3); 814 p->id = ++last_proto_id; 815 p->type = $1; 816 p->cache = RELAY_CACHESIZE; 817 p->tcpflags = TCPFLAG_DEFAULT; 818 p->sslflags = SSLFLAG_DEFAULT; 819 p->tcpbacklog = RELAY_BACKLOG; 820 (void)strlcpy(p->sslciphers, SSLCIPHERS_DEFAULT, 821 sizeof(p->sslciphers)); 822 if (last_proto_id == INT_MAX) { 823 yyerror("too many protocols defined"); 824 free(p); 825 YYERROR; 826 } 827 RB_INIT(&p->request_tree); 828 RB_INIT(&p->response_tree); 829 proto = p; 830 } protopts_n { 831 conf->sc_protocount++; 832 833 if ((proto->sslflags & SSLFLAG_VERSION) == 0) { 834 yyerror("invalid SSL protocol"); 835 YYERROR; 836 } 837 838 TAILQ_INSERT_TAIL(conf->sc_protos, proto, entry); 839 } 840 ; 841 842protopts_n : /* empty */ 843 | '{' '}' 844 | '{' optnl protopts_l '}' 845 ; 846 847protopts_l : protopts_l protoptsl nl 848 | protoptsl optnl 849 ; 850 851protoptsl : SSL sslflags 852 | SSL '{' sslflags_l '}' 853 | TCP tcpflags 854 | TCP '{' tcpflags_l '}' 855 | RETURN ERROR opteflags { proto->flags |= F_RETURN; } 856 | RETURN ERROR '{' eflags_l '}' { proto->flags |= F_RETURN; } 857 | LABEL STRING { 858 label = pn_name2id($2); 859 free($2); 860 if (label == 0) { 861 yyerror("invalid protocol action label"); 862 YYERROR; 863 } 864 } 865 | NO LABEL { 866 label = 0; 867 } 868 | direction { 869 node.label = label; 870 nodedirection = $1; 871 } protonode { 872 if (nodedirection != -1 && 873 protonode_add(nodedirection, proto, &node) == -1) { 874 yyerror("failed to add protocol node"); 875 YYERROR; 876 } 877 bzero(&node, sizeof(node)); 878 } 879 | include 880 ; 881 882direction : /* empty */ { $$ = RELAY_DIR_REQUEST; } 883 | REQUEST { $$ = RELAY_DIR_REQUEST; } 884 | RESPONSE { $$ = RELAY_DIR_RESPONSE; } 885 ; 886 887tcpflags_l : tcpflags comma tcpflags_l 888 | tcpflags 889 ; 890 891tcpflags : SACK { proto->tcpflags |= TCPFLAG_SACK; } 892 | NO SACK { proto->tcpflags |= TCPFLAG_NSACK; } 893 | NODELAY { proto->tcpflags |= TCPFLAG_NODELAY; } 894 | NO NODELAY { proto->tcpflags |= TCPFLAG_NNODELAY; } 895 | SPLICE { /* default */ } 896 | NO SPLICE { proto->tcpflags |= TCPFLAG_NSPLICE; } 897 | BACKLOG NUMBER { 898 if ($2 < 0 || $2 > RELAY_MAX_SESSIONS) { 899 yyerror("invalid backlog: %d", $2); 900 YYERROR; 901 } 902 proto->tcpbacklog = $2; 903 } 904 | SOCKET BUFFER NUMBER { 905 proto->tcpflags |= TCPFLAG_BUFSIZ; 906 if ((proto->tcpbufsiz = $3) < 0) { 907 yyerror("invalid socket buffer size: %d", $3); 908 YYERROR; 909 } 910 } 911 | IP STRING NUMBER { 912 if ($3 < 0) { 913 yyerror("invalid ttl: %d", $3); 914 free($2); 915 YYERROR; 916 } 917 if (strcasecmp("ttl", $2) == 0) { 918 proto->tcpflags |= TCPFLAG_IPTTL; 919 proto->tcpipttl = $3; 920 } else if (strcasecmp("minttl", $2) == 0) { 921 proto->tcpflags |= TCPFLAG_IPMINTTL; 922 proto->tcpipminttl = $3; 923 } else { 924 yyerror("invalid TCP/IP flag: %s", $2); 925 free($2); 926 YYERROR; 927 } 928 free($2); 929 } 930 ; 931 932sslflags_l : sslflags comma sslflags_l 933 | sslflags 934 ; 935 936sslflags : SESSION CACHE sslcache { proto->cache = $3; } 937 | CIPHERS STRING { 938 if (strlcpy(proto->sslciphers, $2, 939 sizeof(proto->sslciphers)) >= 940 sizeof(proto->sslciphers)) { 941 yyerror("sslciphers truncated"); 942 free($2); 943 YYERROR; 944 } 945 free($2); 946 } 947 | CA FILENAME STRING { 948 if (strlcpy(proto->sslca, $3, 949 sizeof(proto->sslca)) >= 950 sizeof(proto->sslca)) { 951 yyerror("sslca truncated"); 952 free($3); 953 YYERROR; 954 } 955 free($3); 956 } 957 | NO flag { proto->sslflags &= ~($2); } 958 | flag { proto->sslflags |= $1; } 959 ; 960 961flag : STRING { 962 if (strcmp("sslv2", $1) == 0) 963 $$ = SSLFLAG_SSLV2; 964 else if (strcmp("sslv3", $1) == 0) 965 $$ = SSLFLAG_SSLV3; 966 else if (strcmp("tlsv1", $1) == 0) 967 $$ = SSLFLAG_TLSV1; 968 else { 969 yyerror("invalid SSL flag: %s", $1); 970 free($1); 971 YYERROR; 972 } 973 free($1); 974 } 975 ; 976 977protonode : nodetype APPEND STRING TO STRING nodeopts { 978 node.action = NODE_ACTION_APPEND; 979 node.key = strdup($5); 980 node.value = strdup($3); 981 if (node.key == NULL || node.value == NULL) 982 fatal("out of memory"); 983 if (strchr(node.value, '$') != NULL) 984 node.flags |= PNFLAG_MACRO; 985 free($5); 986 free($3); 987 } 988 | nodetype CHANGE STRING TO STRING nodeopts { 989 node.action = NODE_ACTION_CHANGE; 990 node.key = strdup($3); 991 node.value = strdup($5); 992 if (node.key == NULL || node.value == NULL) 993 fatal("out of memory"); 994 if (strchr(node.value, '$') != NULL) 995 node.flags |= PNFLAG_MACRO; 996 free($5); 997 free($3); 998 } 999 | nodetype REMOVE STRING nodeopts { 1000 node.action = NODE_ACTION_REMOVE; 1001 node.key = strdup($3); 1002 node.value = NULL; 1003 if (node.key == NULL) 1004 fatal("out of memory"); 1005 free($3); 1006 } 1007 | nodetype REMOVE { 1008 node.action = NODE_ACTION_REMOVE; 1009 node.key = NULL; 1010 node.value = NULL; 1011 } nodefile 1012 | nodetype EXPECT STRING FROM STRING nodeopts { 1013 node.action = NODE_ACTION_EXPECT; 1014 node.key = strdup($5); 1015 node.value = strdup($3); 1016 if (node.key == NULL || node.value == NULL) 1017 fatal("out of memory"); 1018 free($5); 1019 free($3); 1020 proto->lateconnect++; 1021 } 1022 | nodetype EXPECT STRING nodeopts { 1023 node.action = NODE_ACTION_EXPECT; 1024 node.key = strdup($3); 1025 node.value = strdup("*"); 1026 if (node.key == NULL || node.value == NULL) 1027 fatal("out of memory"); 1028 free($3); 1029 proto->lateconnect++; 1030 } 1031 | nodetype EXPECT { 1032 node.action = NODE_ACTION_EXPECT; 1033 node.key = NULL; 1034 node.value = "*"; 1035 proto->lateconnect++; 1036 } nodefile 1037 | nodetype EXPECT digest nodeopts { 1038 if (node.type != NODE_TYPE_URL) { 1039 yyerror("digest not supported for this type"); 1040 free($3.digest); 1041 YYERROR; 1042 } 1043 node.action = NODE_ACTION_EXPECT; 1044 node.key = strdup($3.digest); 1045 node.flags |= PNFLAG_LOOKUP_DIGEST($3.type); 1046 node.value = strdup("*"); 1047 if (node.key == NULL || node.value == NULL) 1048 fatal("out of memory"); 1049 free($3.digest); 1050 proto->lateconnect++; 1051 } 1052 | nodetype FILTER STRING FROM STRING nodeopts { 1053 node.action = NODE_ACTION_FILTER; 1054 node.key = strdup($5); 1055 node.value = strdup($3); 1056 if (node.key == NULL || node.value == NULL) 1057 fatal("out of memory"); 1058 free($5); 1059 free($3); 1060 proto->lateconnect++; 1061 } 1062 | nodetype FILTER STRING nodeopts { 1063 node.action = NODE_ACTION_FILTER; 1064 node.key = strdup($3); 1065 node.value = strdup("*"); 1066 if (node.key == NULL || node.value == NULL) 1067 fatal("out of memory"); 1068 free($3); 1069 proto->lateconnect++; 1070 } 1071 | nodetype FILTER { 1072 node.action = NODE_ACTION_FILTER; 1073 node.key = NULL; 1074 node.value = "*"; 1075 proto->lateconnect++; 1076 } nodefile 1077 | nodetype FILTER digest nodeopts { 1078 if (node.type != NODE_TYPE_URL) { 1079 yyerror("digest not supported for this type"); 1080 free($3.digest); 1081 YYERROR; 1082 } 1083 node.action = NODE_ACTION_FILTER; 1084 node.key = strdup($3.digest); 1085 node.flags |= PNFLAG_LOOKUP_DIGEST($3.type); 1086 node.value = strdup("*"); 1087 if (node.key == NULL || node.value == NULL) 1088 fatal("out of memory"); 1089 free($3.digest); 1090 proto->lateconnect++; 1091 } 1092 | nodetype HASH STRING nodeopts { 1093 node.action = NODE_ACTION_HASH; 1094 node.key = strdup($3); 1095 node.value = NULL; 1096 if (node.key == NULL) 1097 fatal("out of memory"); 1098 free($3); 1099 proto->lateconnect++; 1100 } 1101 | nodetype LOG STRING nodeopts { 1102 node.action = NODE_ACTION_LOG; 1103 node.key = strdup($3); 1104 node.value = NULL; 1105 node.flags |= PNFLAG_LOG; 1106 if (node.key == NULL) 1107 fatal("out of memory"); 1108 free($3); 1109 } 1110 | nodetype LOG { 1111 node.action = NODE_ACTION_LOG; 1112 node.key = NULL; 1113 node.value = NULL; 1114 node.flags |= PNFLAG_LOG; 1115 } nodefile 1116 | nodetype MARK STRING FROM STRING WITH mark log { 1117 node.action = NODE_ACTION_MARK; 1118 node.key = strdup($5); 1119 node.value = strdup($3); 1120 node.mark = $7; 1121 if (node.key == NULL || node.value == NULL) 1122 fatal("out of memory"); 1123 free($3); 1124 free($5); 1125 } 1126 | nodetype MARK STRING WITH mark nodeopts { 1127 node.action = NODE_ACTION_MARK; 1128 node.key = strdup($3); 1129 node.value = strdup("*"); 1130 node.mark = $5; /* overwrite */ 1131 if (node.key == NULL || node.value == NULL) 1132 fatal("out of memory"); 1133 free($3); 1134 } 1135 ; 1136 1137nodefile : FILENAME STRING nodeopts { 1138 if (protonode_load(nodedirection, 1139 proto, &node, $2) == -1) { 1140 yyerror("failed to load from file: %s", $2); 1141 free($2); 1142 YYERROR; 1143 } 1144 free($2); 1145 nodedirection = -1; /* don't add template node */ 1146 } 1147 ; 1148 1149nodeopts : marked log 1150 ; 1151 1152marked : /* empty */ 1153 | MARKED mark { node.mark = $2; } 1154 ; 1155 1156log : /* empty */ 1157 | LOG { node.flags |= PNFLAG_LOG; } 1158 ; 1159 1160mark : NUMBER { 1161 if ($1 <= 0 || $1 >= (int)USHRT_MAX) { 1162 yyerror("invalid mark: %d", $1); 1163 YYERROR; 1164 } 1165 $$ = $1; 1166 } 1167 ; 1168 1169nodetype : HEADER { 1170 node.type = NODE_TYPE_HEADER; 1171 } 1172 | QUERYSTR { node.type = NODE_TYPE_QUERY; } 1173 | COOKIE { 1174 node.type = NODE_TYPE_COOKIE; 1175 } 1176 | PATH { 1177 proto->flags |= F_LOOKUP_PATH; 1178 node.type = NODE_TYPE_PATH; 1179 } 1180 | URL { node.type = NODE_TYPE_URL; } 1181 ; 1182 1183sslcache : NUMBER { 1184 if ($1 < 0) { 1185 yyerror("invalid sslcache value: %d", $1); 1186 YYERROR; 1187 } 1188 $$ = $1; 1189 } 1190 | DISABLE { $$ = -2; } 1191 ; 1192 1193relay : RELAY STRING { 1194 struct relay *r; 1195 1196 if (!loadcfg) { 1197 free($2); 1198 YYACCEPT; 1199 } 1200 1201 TAILQ_FOREACH(r, conf->sc_relays, rl_entry) 1202 if (!strcmp(r->rl_conf.name, $2)) 1203 break; 1204 if (r != NULL) { 1205 yyerror("relay %s defined twice", $2); 1206 free($2); 1207 YYERROR; 1208 } 1209 TAILQ_INIT(&relays); 1210 1211 if ((r = calloc(1, sizeof (*r))) == NULL) 1212 fatal("out of memory"); 1213 1214 if (strlcpy(r->rl_conf.name, $2, sizeof(r->rl_conf.name)) >= 1215 sizeof(r->rl_conf.name)) { 1216 yyerror("relay name truncated"); 1217 free(r); 1218 YYERROR; 1219 } 1220 free($2); 1221 r->rl_conf.id = ++last_relay_id; 1222 r->rl_conf.timeout.tv_sec = RELAY_TIMEOUT; 1223 r->rl_proto = NULL; 1224 r->rl_conf.proto = EMPTY_ID; 1225 r->rl_conf.dsttable = EMPTY_ID; 1226 r->rl_conf.dstmode = RELAY_DSTMODE_DEFAULT; 1227 r->rl_conf.dstretry = 0; 1228 if (last_relay_id == INT_MAX) { 1229 yyerror("too many relays defined"); 1230 free(r); 1231 YYERROR; 1232 } 1233 rlay = r; 1234 } '{' optnl relayopts_l '}' { 1235 struct relay *r; 1236 1237 if (rlay->rl_conf.ss.ss_family == AF_UNSPEC) { 1238 yyerror("relay %s has no listener", 1239 rlay->rl_conf.name); 1240 YYERROR; 1241 } 1242 if ((rlay->rl_conf.flags & (F_NATLOOK|F_DIVERT)) == 1243 (F_NATLOOK|F_DIVERT)) { 1244 yyerror("relay %s with conflicting nat lookup " 1245 "and peer options", rlay->rl_conf.name); 1246 YYERROR; 1247 } 1248 if ((rlay->rl_conf.flags & (F_NATLOOK|F_DIVERT)) == 0 && 1249 rlay->rl_conf.dstss.ss_family == AF_UNSPEC && 1250 rlay->rl_conf.dsttable == EMPTY_ID) { 1251 yyerror("relay %s has no target, rdr, " 1252 "or table", rlay->rl_conf.name); 1253 YYERROR; 1254 } 1255 if (rlay->rl_backuptable == NULL) { 1256 rlay->rl_conf.backuptable = 1257 conf->sc_empty_table.conf.id; 1258 rlay->rl_backuptable = &conf->sc_empty_table; 1259 } 1260 if (rlay->rl_conf.proto == EMPTY_ID) { 1261 rlay->rl_proto = &conf->sc_proto_default; 1262 rlay->rl_conf.proto = conf->sc_proto_default.id; 1263 } 1264 if (relay_load_certfiles(rlay) == -1) { 1265 yyerror("cannot load certificates for relay %s", 1266 rlay->rl_conf.name); 1267 YYERROR; 1268 } 1269 conf->sc_relaycount++; 1270 SPLAY_INIT(&rlay->rl_sessions); 1271 TAILQ_INSERT_TAIL(conf->sc_relays, rlay, rl_entry); 1272 1273 tableport = 0; 1274 1275 while ((r = TAILQ_FIRST(&relays)) != NULL) { 1276 TAILQ_REMOVE(&relays, r, rl_entry); 1277 if (relay_inherit(rlay, r) == NULL) { 1278 YYERROR; 1279 } 1280 } 1281 rlay = NULL; 1282 } 1283 ; 1284 1285relayopts_l : relayopts_l relayoptsl nl 1286 | relayoptsl optnl 1287 ; 1288 1289relayoptsl : LISTEN ON STRING port optssl { 1290 struct addresslist al; 1291 struct address *h; 1292 struct relay *r; 1293 1294 if (rlay->rl_conf.ss.ss_family != AF_UNSPEC) { 1295 if ((r = calloc(1, sizeof (*r))) == NULL) 1296 fatal("out of memory"); 1297 TAILQ_INSERT_TAIL(&relays, r, rl_entry); 1298 } else 1299 r = rlay; 1300 if ($4.op != PF_OP_EQ) { 1301 yyerror("invalid port"); 1302 free($3); 1303 YYERROR; 1304 } 1305 1306 TAILQ_INIT(&al); 1307 if (host($3, &al, 1, &$4, NULL, -1) <= 0) { 1308 yyerror("invalid listen ip: %s", $3); 1309 free($3); 1310 YYERROR; 1311 } 1312 free($3); 1313 h = TAILQ_FIRST(&al); 1314 bcopy(&h->ss, &r->rl_conf.ss, sizeof(r->rl_conf.ss)); 1315 r->rl_conf.port = h->port.val[0]; 1316 if ($5) { 1317 r->rl_conf.flags |= F_SSL; 1318 conf->sc_flags |= F_SSL; 1319 } 1320 tableport = h->port.val[0]; 1321 host_free(&al); 1322 } 1323 | forwardmode optsslclient TO forwardspec interface dstaf { 1324 rlay->rl_conf.fwdmode = $1; 1325 switch ($1) { 1326 case FWD_NORMAL: 1327 if ($5 == NULL) 1328 break; 1329 yyerror("superfluous interface"); 1330 YYERROR; 1331 case FWD_ROUTE: 1332 yyerror("no route for redirections"); 1333 YYERROR; 1334 case FWD_TRANS: 1335 if ($5 != NULL) 1336 break; 1337 yyerror("missing interface"); 1338 YYERROR; 1339 } 1340 if ($5 != NULL) { 1341 strlcpy(rlay->rl_conf.ifname, $5, 1342 sizeof(rlay->rl_conf.ifname)); 1343 free($5); 1344 } 1345 if ($2) { 1346 rlay->rl_conf.flags |= F_SSLCLIENT; 1347 conf->sc_flags |= F_SSLCLIENT; 1348 } 1349 } 1350 | SESSION TIMEOUT NUMBER { 1351 if ((rlay->rl_conf.timeout.tv_sec = $3) < 0) { 1352 yyerror("invalid timeout: %d", $3); 1353 YYERROR; 1354 } 1355 } 1356 | PROTO STRING { 1357 struct protocol *p; 1358 1359 TAILQ_FOREACH(p, conf->sc_protos, entry) 1360 if (!strcmp(p->name, $2)) 1361 break; 1362 if (p == NULL) { 1363 yyerror("no such protocol: %s", $2); 1364 free($2); 1365 YYERROR; 1366 } 1367 p->flags |= F_USED; 1368 rlay->rl_conf.proto = p->id; 1369 rlay->rl_proto = p; 1370 free($2); 1371 } 1372 | DISABLE { rlay->rl_conf.flags |= F_DISABLE; } 1373 | include 1374 ; 1375 1376forwardspec : STRING port retry { 1377 struct addresslist al; 1378 struct address *h; 1379 1380 if (rlay->rl_conf.dstss.ss_family != AF_UNSPEC) { 1381 yyerror("relay %s target or redirection already " 1382 "specified", rlay->rl_conf.name); 1383 free($1); 1384 YYERROR; 1385 } 1386 if ($2.op != PF_OP_EQ) { 1387 yyerror("invalid port"); 1388 free($1); 1389 YYERROR; 1390 } 1391 1392 TAILQ_INIT(&al); 1393 if (host($1, &al, 1, &$2, NULL, -1) <= 0) { 1394 yyerror("invalid listen ip: %s", $1); 1395 free($1); 1396 YYERROR; 1397 } 1398 free($1); 1399 h = TAILQ_FIRST(&al); 1400 bcopy(&h->ss, &rlay->rl_conf.dstss, 1401 sizeof(rlay->rl_conf.dstss)); 1402 rlay->rl_conf.dstport = h->port.val[0]; 1403 rlay->rl_conf.dstretry = $3; 1404 host_free(&al); 1405 } 1406 | NAT LOOKUP retry { 1407 conf->sc_flags |= F_NEEDPF; 1408 rlay->rl_conf.flags |= F_NATLOOK; 1409 rlay->rl_conf.dstretry = $3; 1410 } 1411 | DESTINATION retry { 1412 conf->sc_flags |= F_NEEDPF; 1413 rlay->rl_conf.flags |= F_DIVERT; 1414 rlay->rl_conf.dstretry = $2; 1415 } 1416 | tablespec { 1417 if (rlay->rl_backuptable) { 1418 yyerror("only one backup table is allowed"); 1419 YYERROR; 1420 } 1421 if (rlay->rl_dsttable) { 1422 rlay->rl_backuptable = $1; 1423 rlay->rl_backuptable->conf.flags |= F_USED; 1424 rlay->rl_conf.backuptable = $1->conf.id; 1425 } else { 1426 rlay->rl_dsttable = $1; 1427 rlay->rl_dsttable->conf.flags |= F_USED; 1428 rlay->rl_conf.dsttable = $1->conf.id; 1429 rlay->rl_conf.dstport = $1->conf.port; 1430 } 1431 } 1432 ; 1433 1434dstmode : /* empty */ { $$ = RELAY_DSTMODE_DEFAULT; } 1435 | LOADBALANCE { $$ = RELAY_DSTMODE_LOADBALANCE; } 1436 | ROUNDROBIN { $$ = RELAY_DSTMODE_ROUNDROBIN; } 1437 | HASH { $$ = RELAY_DSTMODE_HASH; } 1438 ; 1439 1440router : ROUTER STRING { 1441 struct router *rt = NULL; 1442 1443 if (!loadcfg) { 1444 free($2); 1445 YYACCEPT; 1446 } 1447 1448 conf->sc_flags |= F_NEEDRT; 1449 TAILQ_FOREACH(rt, conf->sc_rts, rt_entry) 1450 if (!strcmp(rt->rt_conf.name, $2)) 1451 break; 1452 if (rt != NULL) { 1453 yyerror("router %s defined twice", $2); 1454 free($2); 1455 YYERROR; 1456 } 1457 1458 if ((rt = calloc(1, sizeof (*rt))) == NULL) 1459 fatal("out of memory"); 1460 1461 if (strlcpy(rt->rt_conf.name, $2, 1462 sizeof(rt->rt_conf.name)) >= 1463 sizeof(rt->rt_conf.name)) { 1464 yyerror("router name truncated"); 1465 free(rt); 1466 YYERROR; 1467 } 1468 free($2); 1469 rt->rt_conf.id = ++last_rt_id; 1470 if (last_rt_id == INT_MAX) { 1471 yyerror("too many routers defined"); 1472 free(rt); 1473 YYERROR; 1474 } 1475 TAILQ_INIT(&rt->rt_netroutes); 1476 router = rt; 1477 1478 tableport = -1; 1479 } '{' optnl routeopts_l '}' { 1480 if (!router->rt_conf.nroutes) { 1481 yyerror("router %s without routes", 1482 router->rt_conf.name); 1483 free(router); 1484 router = NULL; 1485 YYERROR; 1486 } 1487 1488 conf->sc_routercount++; 1489 TAILQ_INSERT_TAIL(conf->sc_rts, router, rt_entry); 1490 router = NULL; 1491 1492 tableport = 0; 1493 } 1494 ; 1495 1496routeopts_l : routeopts_l routeoptsl nl 1497 | routeoptsl optnl 1498 ; 1499 1500routeoptsl : ROUTE address '/' NUMBER { 1501 struct netroute *nr; 1502 1503 if (router->rt_conf.af == AF_UNSPEC) 1504 router->rt_conf.af = $2.ss.ss_family; 1505 else if (router->rt_conf.af != $2.ss.ss_family) { 1506 yyerror("router %s address family mismatch", 1507 router->rt_conf.name); 1508 YYERROR; 1509 } 1510 1511 if ((router->rt_conf.af == AF_INET && 1512 ($4 > 32 || $4 < 0)) || 1513 (router->rt_conf.af == AF_INET6 && 1514 ($4 > 128 || $4 < 0))) { 1515 yyerror("invalid prefixlen %d", $4); 1516 YYERROR; 1517 } 1518 1519 if ((nr = calloc(1, sizeof(*nr))) == NULL) 1520 fatal("out of memory"); 1521 1522 nr->nr_conf.id = ++last_nr_id; 1523 if (last_nr_id == INT_MAX) { 1524 yyerror("too many routes defined"); 1525 free(nr); 1526 YYERROR; 1527 } 1528 nr->nr_conf.prefixlen = $4; 1529 nr->nr_conf.routerid = router->rt_conf.id; 1530 nr->nr_router = router; 1531 bcopy(&$2.ss, &nr->nr_conf.ss, sizeof($2.ss)); 1532 1533 router->rt_conf.nroutes++; 1534 conf->sc_routecount++; 1535 TAILQ_INSERT_TAIL(&router->rt_netroutes, nr, nr_entry); 1536 TAILQ_INSERT_TAIL(conf->sc_routes, nr, nr_route); 1537 } 1538 | FORWARD TO tablespec { 1539 if (router->rt_gwtable) { 1540 yyerror("router %s table already specified", 1541 router->rt_conf.name); 1542 purge_table(conf->sc_tables, $3); 1543 YYERROR; 1544 } 1545 router->rt_gwtable = $3; 1546 router->rt_gwtable->conf.flags |= F_USED; 1547 router->rt_conf.gwtable = $3->conf.id; 1548 router->rt_conf.gwport = $3->conf.port; 1549 } 1550 | RTABLE NUMBER { 1551 if (router->rt_conf.rtable) { 1552 yyerror("router %s rtable already specified", 1553 router->rt_conf.name); 1554 YYERROR; 1555 } 1556 if ($2 < 0 || $2 > RT_TABLEID_MAX) { 1557 yyerror("invalid rtable id %d", $2); 1558 YYERROR; 1559 } 1560 router->rt_conf.rtable = $2; 1561 } 1562 | RTLABEL STRING { 1563 if (strlcpy(router->rt_conf.label, $2, 1564 sizeof(router->rt_conf.label)) >= 1565 sizeof(router->rt_conf.label)) { 1566 yyerror("route label truncated"); 1567 free($2); 1568 YYERROR; 1569 } 1570 free($2); 1571 } 1572 | DISABLE { rlay->rl_conf.flags |= F_DISABLE; } 1573 | include 1574 ; 1575 1576dstaf : /* empty */ { 1577 rlay->rl_conf.dstaf.ss_family = AF_UNSPEC; 1578 } 1579 | INET { 1580 rlay->rl_conf.dstaf.ss_family = AF_INET; 1581 } 1582 | INET6 STRING { 1583 struct sockaddr_in6 *sin6; 1584 1585 sin6 = (struct sockaddr_in6 *)&rlay->rl_conf.dstaf; 1586 if (inet_pton(AF_INET6, $2, &sin6->sin6_addr) == -1) { 1587 yyerror("invalid ipv6 address %s", $2); 1588 free($2); 1589 YYERROR; 1590 } 1591 free($2); 1592 1593 sin6->sin6_family = AF_INET6; 1594 sin6->sin6_len = sizeof(*sin6); 1595 } 1596 ; 1597 1598interface : /*empty*/ { $$ = NULL; } 1599 | INTERFACE STRING { $$ = $2; } 1600 ; 1601 1602host : address { 1603 if ((hst = calloc(1, sizeof(*(hst)))) == NULL) 1604 fatal("out of memory"); 1605 1606 if (strlcpy(hst->conf.name, $1.name, 1607 sizeof(hst->conf.name)) >= sizeof(hst->conf.name)) { 1608 yyerror("host name truncated"); 1609 free(hst); 1610 YYERROR; 1611 } 1612 bcopy(&$1.ss, &hst->conf.ss, sizeof($1.ss)); 1613 hst->conf.id = 0; /* will be set later */ 1614 SLIST_INIT(&hst->children); 1615 } opthostflags { 1616 $$ = hst; 1617 hst = NULL; 1618 } 1619 ; 1620 1621opthostflags : /* empty */ 1622 | hostflags_l 1623 ; 1624 1625hostflags_l : hostflags hostflags_l 1626 | hostflags 1627 ; 1628 1629hostflags : RETRY NUMBER { 1630 if (hst->conf.retry) { 1631 yyerror("retry value already set"); 1632 YYERROR; 1633 } 1634 if ($2 < 0) { 1635 yyerror("invalid retry value: %d\n", $2); 1636 YYERROR; 1637 } 1638 hst->conf.retry = $2; 1639 } 1640 | PARENT NUMBER { 1641 if (hst->conf.parentid) { 1642 yyerror("parent value already set"); 1643 YYERROR; 1644 } 1645 if ($2 < 0) { 1646 yyerror("invalid parent value: %d\n", $2); 1647 YYERROR; 1648 } 1649 hst->conf.parentid = $2; 1650 } 1651 | PRIORITY NUMBER { 1652 if (hst->conf.priority) { 1653 yyerror("priority already set"); 1654 YYERROR; 1655 } 1656 if ($2 < 0 || $2 > RTP_MAX) { 1657 yyerror("invalid priority value: %d\n", $2); 1658 YYERROR; 1659 } 1660 hst->conf.priority = $2; 1661 } 1662 | IP TTL NUMBER { 1663 if (hst->conf.ttl) { 1664 yyerror("ttl value already set"); 1665 YYERROR; 1666 } 1667 if ($3 < 0) { 1668 yyerror("invalid ttl value: %d\n", $3); 1669 YYERROR; 1670 } 1671 hst->conf.ttl = $3; 1672 } 1673 ; 1674 1675address : STRING { 1676 struct address *h; 1677 struct addresslist al; 1678 1679 if (strlcpy($$.name, $1, 1680 sizeof($$.name)) >= sizeof($$.name)) { 1681 yyerror("host name truncated"); 1682 free($1); 1683 YYERROR; 1684 } 1685 1686 TAILQ_INIT(&al); 1687 if (host($1, &al, 1, NULL, NULL, -1) <= 0) { 1688 yyerror("invalid host %s", $1); 1689 free($1); 1690 YYERROR; 1691 } 1692 free($1); 1693 h = TAILQ_FIRST(&al); 1694 memcpy(&$$.ss, &h->ss, sizeof($$.ss)); 1695 host_free(&al); 1696 } 1697 ; 1698 1699retry : /* empty */ { $$ = 0; } 1700 | RETRY NUMBER { 1701 if (($$ = $2) < 0) { 1702 yyerror("invalid retry value: %d\n", $2); 1703 YYERROR; 1704 } 1705 } 1706 ; 1707 1708timeout : NUMBER 1709 { 1710 if ($1 < 0) { 1711 yyerror("invalid timeout: %d\n", $1); 1712 YYERROR; 1713 } 1714 $$.tv_sec = $1 / 1000; 1715 $$.tv_usec = ($1 % 1000) * 1000; 1716 } 1717 ; 1718 1719comma : ',' 1720 | nl 1721 | /* empty */ 1722 ; 1723 1724optnl : '\n' optnl 1725 | 1726 ; 1727 1728nl : '\n' optnl 1729 ; 1730 1731%% 1732 1733struct keywords { 1734 const char *k_name; 1735 int k_val; 1736}; 1737 1738int 1739yyerror(const char *fmt, ...) 1740{ 1741 va_list ap; 1742 1743 file->errors++; 1744 va_start(ap, fmt); 1745 fprintf(stderr, "%s:%d: ", file->name, yylval.lineno); 1746 vfprintf(stderr, fmt, ap); 1747 fprintf(stderr, "\n"); 1748 va_end(ap); 1749 return (0); 1750} 1751 1752int 1753kw_cmp(const void *k, const void *e) 1754{ 1755 return (strcmp(k, ((const struct keywords *)e)->k_name)); 1756} 1757 1758int 1759lookup(char *s) 1760{ 1761 /* this has to be sorted always */ 1762 static const struct keywords keywords[] = { 1763 { "all", ALL }, 1764 { "append", APPEND }, 1765 { "backlog", BACKLOG }, 1766 { "backup", BACKUP }, 1767 { "buffer", BUFFER }, 1768 { "ca", CA }, 1769 { "cache", CACHE }, 1770 { "change", CHANGE }, 1771 { "check", CHECK }, 1772 { "ciphers", CIPHERS }, 1773 { "code", CODE }, 1774 { "cookie", COOKIE }, 1775 { "demote", DEMOTE }, 1776 { "destination", DESTINATION }, 1777 { "digest", DIGEST }, 1778 { "disable", DISABLE }, 1779 { "error", ERROR }, 1780 { "expect", EXPECT }, 1781 { "external", EXTERNAL }, 1782 { "file", FILENAME }, 1783 { "filter", FILTER }, 1784 { "forward", FORWARD }, 1785 { "from", FROM }, 1786 { "hash", HASH }, 1787 { "header", HEADER }, 1788 { "host", HOST }, 1789 { "icmp", ICMP }, 1790 { "include", INCLUDE }, 1791 { "inet", INET }, 1792 { "inet6", INET6 }, 1793 { "interface", INTERFACE }, 1794 { "interval", INTERVAL }, 1795 { "ip", IP }, 1796 { "label", LABEL }, 1797 { "listen", LISTEN }, 1798 { "loadbalance", LOADBALANCE }, 1799 { "log", LOG }, 1800 { "lookup", LOOKUP }, 1801 { "mark", MARK }, 1802 { "marked", MARKED }, 1803 { "match", MATCH }, 1804 { "mode", MODE }, 1805 { "nat", NAT }, 1806 { "no", NO }, 1807 { "nodelay", NODELAY }, 1808 { "nothing", NOTHING }, 1809 { "on", ON }, 1810 { "parent", PARENT }, 1811 { "path", PATH }, 1812 { "port", PORT }, 1813 { "prefork", PREFORK }, 1814 { "priority", PRIORITY }, 1815 { "protocol", PROTO }, 1816 { "query", QUERYSTR }, 1817 { "real", REAL }, 1818 { "redirect", REDIRECT }, 1819 { "relay", RELAY }, 1820 { "remove", REMOVE }, 1821 { "request", REQUEST }, 1822 { "response", RESPONSE }, 1823 { "retry", RETRY }, 1824 { "return", RETURN }, 1825 { "roundrobin", ROUNDROBIN }, 1826 { "route", ROUTE }, 1827 { "router", ROUTER }, 1828 { "rtable", RTABLE }, 1829 { "rtlabel", RTLABEL }, 1830 { "sack", SACK }, 1831 { "script", SCRIPT }, 1832 { "send", SEND }, 1833 { "session", SESSION }, 1834 { "socket", SOCKET }, 1835 { "splice", SPLICE }, 1836 { "ssl", SSL }, 1837 { "sticky-address", STICKYADDR }, 1838 { "style", STYLE }, 1839 { "table", TABLE }, 1840 { "tag", TAG }, 1841 { "tcp", TCP }, 1842 { "timeout", TIMEOUT }, 1843 { "to", TO }, 1844 { "transparent", TRANSPARENT }, 1845 { "trap", TRAP }, 1846 { "ttl", TTL }, 1847 { "updates", UPDATES }, 1848 { "url", URL }, 1849 { "virtual", VIRTUAL }, 1850 { "with", WITH } 1851 }; 1852 const struct keywords *p; 1853 1854 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 1855 sizeof(keywords[0]), kw_cmp); 1856 1857 if (p) 1858 return (p->k_val); 1859 else 1860 return (STRING); 1861} 1862 1863#define MAXPUSHBACK 128 1864 1865char *parsebuf; 1866int parseindex; 1867char pushback_buffer[MAXPUSHBACK]; 1868int pushback_index = 0; 1869 1870int 1871lgetc(int quotec) 1872{ 1873 int c, next; 1874 1875 if (parsebuf) { 1876 /* Read character from the parsebuffer instead of input. */ 1877 if (parseindex >= 0) { 1878 c = parsebuf[parseindex++]; 1879 if (c != '\0') 1880 return (c); 1881 parsebuf = NULL; 1882 } else 1883 parseindex++; 1884 } 1885 1886 if (pushback_index) 1887 return (pushback_buffer[--pushback_index]); 1888 1889 if (quotec) { 1890 if ((c = getc(file->stream)) == EOF) { 1891 yyerror("reached end of file while parsing " 1892 "quoted string"); 1893 if (file == topfile || popfile() == EOF) 1894 return (EOF); 1895 return (quotec); 1896 } 1897 return (c); 1898 } 1899 1900 while ((c = getc(file->stream)) == '\\') { 1901 next = getc(file->stream); 1902 if (next != '\n') { 1903 c = next; 1904 break; 1905 } 1906 yylval.lineno = file->lineno; 1907 file->lineno++; 1908 } 1909 1910 while (c == EOF) { 1911 if (file == topfile || popfile() == EOF) 1912 return (EOF); 1913 c = getc(file->stream); 1914 } 1915 return (c); 1916} 1917 1918int 1919lungetc(int c) 1920{ 1921 if (c == EOF) 1922 return (EOF); 1923 if (parsebuf) { 1924 parseindex--; 1925 if (parseindex >= 0) 1926 return (c); 1927 } 1928 if (pushback_index < MAXPUSHBACK-1) 1929 return (pushback_buffer[pushback_index++] = c); 1930 else 1931 return (EOF); 1932} 1933 1934int 1935findeol(void) 1936{ 1937 int c; 1938 1939 parsebuf = NULL; 1940 1941 /* skip to either EOF or the first real EOL */ 1942 while (1) { 1943 if (pushback_index) 1944 c = pushback_buffer[--pushback_index]; 1945 else 1946 c = lgetc(0); 1947 if (c == '\n') { 1948 file->lineno++; 1949 break; 1950 } 1951 if (c == EOF) 1952 break; 1953 } 1954 return (ERROR); 1955} 1956 1957int 1958yylex(void) 1959{ 1960 char buf[8096]; 1961 char *p, *val; 1962 int quotec, next, c; 1963 int token; 1964 1965top: 1966 p = buf; 1967 while ((c = lgetc(0)) == ' ' || c == '\t') 1968 ; /* nothing */ 1969 1970 yylval.lineno = file->lineno; 1971 if (c == '#') 1972 while ((c = lgetc(0)) != '\n' && c != EOF) 1973 ; /* nothing */ 1974 if (c == '$' && parsebuf == NULL) { 1975 while (1) { 1976 if ((c = lgetc(0)) == EOF) 1977 return (0); 1978 1979 if (p + 1 >= buf + sizeof(buf) - 1) { 1980 yyerror("string too long"); 1981 return (findeol()); 1982 } 1983 if (isalnum(c) || c == '_') { 1984 *p++ = (char)c; 1985 continue; 1986 } 1987 *p = '\0'; 1988 lungetc(c); 1989 break; 1990 } 1991 val = symget(buf); 1992 if (val == NULL) { 1993 yyerror("macro '%s' not defined", buf); 1994 return (findeol()); 1995 } 1996 parsebuf = val; 1997 parseindex = 0; 1998 goto top; 1999 } 2000 2001 switch (c) { 2002 case '\'': 2003 case '"': 2004 quotec = c; 2005 while (1) { 2006 if ((c = lgetc(quotec)) == EOF) 2007 return (0); 2008 if (c == '\n') { 2009 file->lineno++; 2010 continue; 2011 } else if (c == '\\') { 2012 if ((next = lgetc(quotec)) == EOF) 2013 return (0); 2014 if (next == quotec || c == ' ' || c == '\t') 2015 c = next; 2016 else if (next == '\n') { 2017 file->lineno++; 2018 continue; 2019 } else 2020 lungetc(next); 2021 } else if (c == quotec) { 2022 *p = '\0'; 2023 break; 2024 } 2025 if (p + 1 >= buf + sizeof(buf) - 1) { 2026 yyerror("string too long"); 2027 return (findeol()); 2028 } 2029 *p++ = (char)c; 2030 } 2031 yylval.v.string = strdup(buf); 2032 if (yylval.v.string == NULL) 2033 err(1, "yylex: strdup"); 2034 return (STRING); 2035 } 2036 2037#define allowed_to_end_number(x) \ 2038 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 2039 2040 if (c == '-' || isdigit(c)) { 2041 do { 2042 *p++ = c; 2043 if ((unsigned)(p-buf) >= sizeof(buf)) { 2044 yyerror("string too long"); 2045 return (findeol()); 2046 } 2047 } while ((c = lgetc(0)) != EOF && isdigit(c)); 2048 lungetc(c); 2049 if (p == buf + 1 && buf[0] == '-') 2050 goto nodigits; 2051 if (c == EOF || allowed_to_end_number(c)) { 2052 const char *errstr = NULL; 2053 2054 *p = '\0'; 2055 yylval.v.number = strtonum(buf, LLONG_MIN, 2056 LLONG_MAX, &errstr); 2057 if (errstr) { 2058 yyerror("\"%s\" invalid number: %s", 2059 buf, errstr); 2060 return (findeol()); 2061 } 2062 return (NUMBER); 2063 } else { 2064nodigits: 2065 while (p > buf + 1) 2066 lungetc(*--p); 2067 c = *--p; 2068 if (c == '-') 2069 return (c); 2070 } 2071 } 2072 2073#define allowed_in_string(x) \ 2074 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 2075 x != '{' && x != '}' && x != '<' && x != '>' && \ 2076 x != '!' && x != '=' && x != '#' && \ 2077 x != ',' && x != '/')) 2078 2079 if (isalnum(c) || c == ':' || c == '_') { 2080 do { 2081 *p++ = c; 2082 if ((unsigned)(p-buf) >= sizeof(buf)) { 2083 yyerror("string too long"); 2084 return (findeol()); 2085 } 2086 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 2087 lungetc(c); 2088 *p = '\0'; 2089 if ((token = lookup(buf)) == STRING) 2090 if ((yylval.v.string = strdup(buf)) == NULL) 2091 err(1, "yylex: strdup"); 2092 return (token); 2093 } 2094 if (c == '\n') { 2095 yylval.lineno = file->lineno; 2096 file->lineno++; 2097 } 2098 if (c == EOF) 2099 return (0); 2100 return (c); 2101} 2102 2103int 2104check_file_secrecy(int fd, const char *fname) 2105{ 2106 struct stat st; 2107 2108 if (fstat(fd, &st)) { 2109 log_warn("cannot stat %s", fname); 2110 return (-1); 2111 } 2112 if (st.st_uid != 0 && st.st_uid != getuid()) { 2113 log_warnx("%s: owner not root or current user", fname); 2114 return (-1); 2115 } 2116 if (st.st_mode & (S_IRWXG | S_IRWXO)) { 2117 log_warnx("%s: group/world readable/writeable", fname); 2118 return (-1); 2119 } 2120 return (0); 2121} 2122 2123struct file * 2124pushfile(const char *name, int secret) 2125{ 2126 struct file *nfile; 2127 2128 if ((nfile = calloc(1, sizeof(struct file))) == NULL) { 2129 log_warn("%s: malloc", __func__); 2130 return (NULL); 2131 } 2132 if ((nfile->name = strdup(name)) == NULL) { 2133 log_warn("%s: malloc", __func__); 2134 free(nfile); 2135 return (NULL); 2136 } 2137 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 2138 log_warn("%s: %s", __func__, nfile->name); 2139 free(nfile->name); 2140 free(nfile); 2141 return (NULL); 2142 } else if (secret && 2143 check_file_secrecy(fileno(nfile->stream), nfile->name)) { 2144 fclose(nfile->stream); 2145 free(nfile->name); 2146 free(nfile); 2147 return (NULL); 2148 } 2149 nfile->lineno = 1; 2150 TAILQ_INSERT_TAIL(&files, nfile, entry); 2151 return (nfile); 2152} 2153 2154int 2155popfile(void) 2156{ 2157 struct file *prev; 2158 2159 if ((prev = TAILQ_PREV(file, files, entry)) != NULL) 2160 prev->errors += file->errors; 2161 2162 TAILQ_REMOVE(&files, file, entry); 2163 fclose(file->stream); 2164 free(file->name); 2165 free(file); 2166 file = prev; 2167 return (file ? 0 : EOF); 2168} 2169 2170int 2171parse_config(const char *filename, struct relayd *x_conf) 2172{ 2173 struct sym *sym, *next; 2174 2175 conf = x_conf; 2176 if (config_init(conf) == -1) { 2177 log_warn("%s: cannot initialize configuration", __func__); 2178 return (-1); 2179 } 2180 2181 errors = 0; 2182 2183 if ((file = pushfile(filename, 0)) == NULL) 2184 return (-1); 2185 2186 topfile = file; 2187 setservent(1); 2188 2189 yyparse(); 2190 errors = file->errors; 2191 popfile(); 2192 2193 endservent(); 2194 endprotoent(); 2195 2196 /* Free macros */ 2197 for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) { 2198 next = TAILQ_NEXT(sym, entry); 2199 if (!sym->persist) { 2200 free(sym->nam); 2201 free(sym->val); 2202 TAILQ_REMOVE(&symhead, sym, entry); 2203 free(sym); 2204 } 2205 } 2206 2207 return (errors ? -1 : 0); 2208} 2209 2210int 2211load_config(const char *filename, struct relayd *x_conf) 2212{ 2213 struct sym *sym, *next; 2214 struct table *nexttb; 2215 struct host *h, *ph; 2216 2217 conf = x_conf; 2218 conf->sc_flags = 0; 2219 2220 loadcfg = 1; 2221 errors = 0; 2222 last_host_id = last_table_id = last_rdr_id = last_proto_id = 2223 last_relay_id = last_rt_id = last_nr_id = 0; 2224 2225 rdr = NULL; 2226 table = NULL; 2227 rlay = NULL; 2228 proto = NULL; 2229 router = NULL; 2230 2231 if ((file = pushfile(filename, 0)) == NULL) 2232 return (-1); 2233 2234 topfile = file; 2235 setservent(1); 2236 2237 yyparse(); 2238 errors = file->errors; 2239 popfile(); 2240 2241 endservent(); 2242 endprotoent(); 2243 2244 /* Free macros and check which have not been used. */ 2245 for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) { 2246 next = TAILQ_NEXT(sym, entry); 2247 if ((conf->sc_opts & RELAYD_OPT_VERBOSE) && !sym->used) 2248 fprintf(stderr, "warning: macro '%s' not " 2249 "used\n", sym->nam); 2250 if (!sym->persist) { 2251 free(sym->nam); 2252 free(sym->val); 2253 TAILQ_REMOVE(&symhead, sym, entry); 2254 free(sym); 2255 } 2256 } 2257 2258 if (TAILQ_EMPTY(conf->sc_rdrs) && 2259 TAILQ_EMPTY(conf->sc_relays) && 2260 TAILQ_EMPTY(conf->sc_rts)) { 2261 log_warnx("no actions, nothing to do"); 2262 errors++; 2263 } 2264 2265 /* Cleanup relay list to inherit */ 2266 while ((rlay = TAILQ_FIRST(&relays)) != NULL) { 2267 TAILQ_REMOVE(&relays, rlay, rl_entry); 2268 free(rlay); 2269 } 2270 2271 if (timercmp(&conf->sc_timeout, &conf->sc_interval, >=)) { 2272 log_warnx("global timeout exceeds interval"); 2273 errors++; 2274 } 2275 2276 /* Verify that every table is used */ 2277 for (table = TAILQ_FIRST(conf->sc_tables); table != NULL; 2278 table = nexttb) { 2279 nexttb = TAILQ_NEXT(table, entry); 2280 if (table->conf.port == 0) { 2281 TAILQ_REMOVE(conf->sc_tables, table, entry); 2282 while ((h = TAILQ_FIRST(&table->hosts)) != NULL) { 2283 TAILQ_REMOVE(&table->hosts, h, entry); 2284 free(h); 2285 } 2286 if (table->sendbuf != NULL) 2287 free(table->sendbuf); 2288 free(table); 2289 continue; 2290 } 2291 2292 TAILQ_FOREACH(h, &table->hosts, entry) { 2293 if (h->conf.parentid) { 2294 ph = host_find(conf, h->conf.parentid); 2295 2296 /* Validate the parent id */ 2297 if (h->conf.id == h->conf.parentid || 2298 ph == NULL || ph->conf.parentid) 2299 ph = NULL; 2300 2301 if (ph == NULL) { 2302 log_warnx("host parent id %d invalid", 2303 h->conf.parentid); 2304 errors++; 2305 } else 2306 SLIST_INSERT_HEAD(&ph->children, 2307 h, child); 2308 } 2309 } 2310 2311 if (!(table->conf.flags & F_USED)) { 2312 log_warnx("unused table: %s", table->conf.name); 2313 errors++; 2314 } 2315 if (timercmp(&table->conf.timeout, &conf->sc_interval, >=)) { 2316 log_warnx("table timeout exceeds interval: %s", 2317 table->conf.name); 2318 errors++; 2319 } 2320 } 2321 2322 /* Verify that every non-default protocol is used */ 2323 TAILQ_FOREACH(proto, conf->sc_protos, entry) { 2324 if (!(proto->flags & F_USED)) { 2325 log_warnx("unused protocol: %s", proto->name); 2326 } 2327 } 2328 2329 return (errors ? -1 : 0); 2330} 2331 2332int 2333symset(const char *nam, const char *val, int persist) 2334{ 2335 struct sym *sym; 2336 2337 for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); 2338 sym = TAILQ_NEXT(sym, entry)) 2339 ; /* nothing */ 2340 2341 if (sym != NULL) { 2342 if (sym->persist == 1) 2343 return (0); 2344 else { 2345 free(sym->nam); 2346 free(sym->val); 2347 TAILQ_REMOVE(&symhead, sym, entry); 2348 free(sym); 2349 } 2350 } 2351 if ((sym = calloc(1, sizeof(*sym))) == NULL) 2352 return (-1); 2353 2354 sym->nam = strdup(nam); 2355 if (sym->nam == NULL) { 2356 free(sym); 2357 return (-1); 2358 } 2359 sym->val = strdup(val); 2360 if (sym->val == NULL) { 2361 free(sym->nam); 2362 free(sym); 2363 return (-1); 2364 } 2365 sym->used = 0; 2366 sym->persist = persist; 2367 TAILQ_INSERT_TAIL(&symhead, sym, entry); 2368 return (0); 2369} 2370 2371int 2372cmdline_symset(char *s) 2373{ 2374 char *sym, *val; 2375 int ret; 2376 size_t len; 2377 2378 if ((val = strrchr(s, '=')) == NULL) 2379 return (-1); 2380 2381 len = strlen(s) - strlen(val) + 1; 2382 if ((sym = malloc(len)) == NULL) 2383 errx(1, "cmdline_symset: malloc"); 2384 2385 (void)strlcpy(sym, s, len); 2386 2387 ret = symset(sym, val + 1, 1); 2388 free(sym); 2389 2390 return (ret); 2391} 2392 2393char * 2394symget(const char *nam) 2395{ 2396 struct sym *sym; 2397 2398 TAILQ_FOREACH(sym, &symhead, entry) 2399 if (strcmp(nam, sym->nam) == 0) { 2400 sym->used = 1; 2401 return (sym->val); 2402 } 2403 return (NULL); 2404} 2405 2406struct address * 2407host_v4(const char *s) 2408{ 2409 struct in_addr ina; 2410 struct sockaddr_in *sain; 2411 struct address *h; 2412 2413 bzero(&ina, sizeof(ina)); 2414 if (inet_pton(AF_INET, s, &ina) != 1) 2415 return (NULL); 2416 2417 if ((h = calloc(1, sizeof(*h))) == NULL) 2418 fatal(NULL); 2419 sain = (struct sockaddr_in *)&h->ss; 2420 sain->sin_len = sizeof(struct sockaddr_in); 2421 sain->sin_family = AF_INET; 2422 sain->sin_addr.s_addr = ina.s_addr; 2423 2424 return (h); 2425} 2426 2427struct address * 2428host_v6(const char *s) 2429{ 2430 struct addrinfo hints, *res; 2431 struct sockaddr_in6 *sa_in6; 2432 struct address *h = NULL; 2433 2434 bzero(&hints, sizeof(hints)); 2435 hints.ai_family = AF_INET6; 2436 hints.ai_socktype = SOCK_DGRAM; /* dummy */ 2437 hints.ai_flags = AI_NUMERICHOST; 2438 if (getaddrinfo(s, "0", &hints, &res) == 0) { 2439 if ((h = calloc(1, sizeof(*h))) == NULL) 2440 fatal(NULL); 2441 sa_in6 = (struct sockaddr_in6 *)&h->ss; 2442 sa_in6->sin6_len = sizeof(struct sockaddr_in6); 2443 sa_in6->sin6_family = AF_INET6; 2444 memcpy(&sa_in6->sin6_addr, 2445 &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, 2446 sizeof(sa_in6->sin6_addr)); 2447 sa_in6->sin6_scope_id = 2448 ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; 2449 2450 freeaddrinfo(res); 2451 } 2452 2453 return (h); 2454} 2455 2456int 2457host_dns(const char *s, struct addresslist *al, int max, 2458 struct portrange *port, const char *ifname, int ipproto) 2459{ 2460 struct addrinfo hints, *res0, *res; 2461 int error, cnt = 0; 2462 struct sockaddr_in *sain; 2463 struct sockaddr_in6 *sin6; 2464 struct address *h; 2465 2466 if ((cnt = host_if(s, al, max, port, ifname, ipproto)) != 0) 2467 return (cnt); 2468 2469 bzero(&hints, sizeof(hints)); 2470 hints.ai_family = PF_UNSPEC; 2471 hints.ai_socktype = SOCK_DGRAM; /* DUMMY */ 2472 error = getaddrinfo(s, NULL, &hints, &res0); 2473 if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME) 2474 return (0); 2475 if (error) { 2476 log_warnx("%s: could not parse \"%s\": %s", __func__, s, 2477 gai_strerror(error)); 2478 return (-1); 2479 } 2480 2481 for (res = res0; res && cnt < max; res = res->ai_next) { 2482 if (res->ai_family != AF_INET && 2483 res->ai_family != AF_INET6) 2484 continue; 2485 if ((h = calloc(1, sizeof(*h))) == NULL) 2486 fatal(NULL); 2487 2488 if (port != NULL) 2489 bcopy(port, &h->port, sizeof(h->port)); 2490 if (ifname != NULL) { 2491 if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >= 2492 sizeof(h->ifname)) 2493 log_warnx("%s: interface name truncated", 2494 __func__); 2495 freeaddrinfo(res0); 2496 free(h); 2497 return (-1); 2498 } 2499 if (ipproto != -1) 2500 h->ipproto = ipproto; 2501 h->ss.ss_family = res->ai_family; 2502 2503 if (res->ai_family == AF_INET) { 2504 sain = (struct sockaddr_in *)&h->ss; 2505 sain->sin_len = sizeof(struct sockaddr_in); 2506 sain->sin_addr.s_addr = ((struct sockaddr_in *) 2507 res->ai_addr)->sin_addr.s_addr; 2508 } else { 2509 sin6 = (struct sockaddr_in6 *)&h->ss; 2510 sin6->sin6_len = sizeof(struct sockaddr_in6); 2511 memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *) 2512 res->ai_addr)->sin6_addr, sizeof(struct in6_addr)); 2513 } 2514 2515 TAILQ_INSERT_HEAD(al, h, entry); 2516 cnt++; 2517 } 2518 if (cnt == max && res) { 2519 log_warnx("%s: %s resolves to more than %d hosts", __func__, 2520 s, max); 2521 } 2522 freeaddrinfo(res0); 2523 return (cnt); 2524} 2525 2526int 2527host_if(const char *s, struct addresslist *al, int max, 2528 struct portrange *port, const char *ifname, int ipproto) 2529{ 2530 struct ifaddrs *ifap, *p; 2531 struct sockaddr_in *sain; 2532 struct sockaddr_in6 *sin6; 2533 struct address *h; 2534 int cnt = 0, af; 2535 2536 if (getifaddrs(&ifap) == -1) 2537 fatal("getifaddrs"); 2538 2539 /* First search for IPv4 addresses */ 2540 af = AF_INET; 2541 2542 nextaf: 2543 for (p = ifap; p != NULL && cnt < max; p = p->ifa_next) { 2544 if (p->ifa_addr->sa_family != af || 2545 (strcmp(s, p->ifa_name) != 0 && 2546 !is_if_in_group(p->ifa_name, s))) 2547 continue; 2548 if ((h = calloc(1, sizeof(*h))) == NULL) 2549 fatal("calloc"); 2550 2551 if (port != NULL) 2552 bcopy(port, &h->port, sizeof(h->port)); 2553 if (ifname != NULL) { 2554 if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >= 2555 sizeof(h->ifname)) 2556 log_warnx("%s: interface name truncated", 2557 __func__); 2558 freeifaddrs(ifap); 2559 return (-1); 2560 } 2561 if (ipproto != -1) 2562 h->ipproto = ipproto; 2563 h->ss.ss_family = af; 2564 2565 if (af == AF_INET) { 2566 sain = (struct sockaddr_in *)&h->ss; 2567 sain->sin_len = sizeof(struct sockaddr_in); 2568 sain->sin_addr.s_addr = ((struct sockaddr_in *) 2569 p->ifa_addr)->sin_addr.s_addr; 2570 } else { 2571 sin6 = (struct sockaddr_in6 *)&h->ss; 2572 sin6->sin6_len = sizeof(struct sockaddr_in6); 2573 memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *) 2574 p->ifa_addr)->sin6_addr, sizeof(struct in6_addr)); 2575 sin6->sin6_scope_id = ((struct sockaddr_in6 *) 2576 p->ifa_addr)->sin6_scope_id; 2577 } 2578 2579 TAILQ_INSERT_HEAD(al, h, entry); 2580 cnt++; 2581 } 2582 if (af == AF_INET) { 2583 /* Next search for IPv6 addresses */ 2584 af = AF_INET6; 2585 goto nextaf; 2586 } 2587 2588 if (cnt > max) { 2589 log_warnx("%s: %s resolves to more than %d hosts", __func__, 2590 s, max); 2591 } 2592 freeifaddrs(ifap); 2593 return (cnt); 2594} 2595 2596int 2597host(const char *s, struct addresslist *al, int max, 2598 struct portrange *port, const char *ifname, int ipproto) 2599{ 2600 struct address *h; 2601 2602 h = host_v4(s); 2603 2604 /* IPv6 address? */ 2605 if (h == NULL) 2606 h = host_v6(s); 2607 2608 if (h != NULL) { 2609 if (port != NULL) 2610 bcopy(port, &h->port, sizeof(h->port)); 2611 if (ifname != NULL) { 2612 if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >= 2613 sizeof(h->ifname)) { 2614 log_warnx("%s: interface name truncated", 2615 __func__); 2616 free(h); 2617 return (-1); 2618 } 2619 } 2620 if (ipproto != -1) 2621 h->ipproto = ipproto; 2622 2623 TAILQ_INSERT_HEAD(al, h, entry); 2624 return (1); 2625 } 2626 2627 return (host_dns(s, al, max, port, ifname, ipproto)); 2628} 2629 2630void 2631host_free(struct addresslist *al) 2632{ 2633 struct address *h; 2634 2635 while ((h = TAILQ_FIRST(al)) != NULL) { 2636 TAILQ_REMOVE(al, h, entry); 2637 free(h); 2638 } 2639} 2640 2641struct table * 2642table_inherit(struct table *tb) 2643{ 2644 char pname[TABLE_NAME_SIZE + 6]; 2645 struct host *h, *dsth; 2646 struct table *dsttb, *oldtb; 2647 2648 /* Get the table or table template */ 2649 if ((dsttb = table_findbyname(conf, tb->conf.name)) == NULL) { 2650 yyerror("unknown table %s", tb->conf.name); 2651 goto fail; 2652 } 2653 if (dsttb->conf.port != 0) 2654 fatal("invalid table"); /* should not happen */ 2655 2656 if (tb->conf.port == 0) { 2657 yyerror("invalid port"); 2658 goto fail; 2659 } 2660 2661 /* Check if a matching table already exists */ 2662 if (snprintf(pname, sizeof(pname), "%s:%u", 2663 tb->conf.name, ntohs(tb->conf.port)) >= (int)sizeof(pname)) { 2664 yyerror("invalid table name"); 2665 goto fail; 2666 } 2667 (void)strlcpy(tb->conf.name, pname, sizeof(tb->conf.name)); 2668 if ((oldtb = table_findbyconf(conf, tb)) != NULL) { 2669 purge_table(NULL, tb); 2670 return (oldtb); 2671 } 2672 2673 /* Create a new table */ 2674 tb->conf.id = ++last_table_id; 2675 if (last_table_id == INT_MAX) { 2676 yyerror("too many tables defined"); 2677 goto fail; 2678 } 2679 tb->conf.flags |= dsttb->conf.flags; 2680 2681 /* Inherit global table options */ 2682 bcopy(&dsttb->conf.timeout, &tb->conf.timeout, sizeof(struct timeval)); 2683 2684 /* Copy the associated hosts */ 2685 TAILQ_INIT(&tb->hosts); 2686 TAILQ_FOREACH(dsth, &dsttb->hosts, entry) { 2687 if ((h = (struct host *) 2688 calloc(1, sizeof (*h))) == NULL) 2689 fatal("out of memory"); 2690 bcopy(dsth, h, sizeof(*h)); 2691 h->conf.id = ++last_host_id; 2692 if (last_host_id == INT_MAX) { 2693 yyerror("too many hosts defined"); 2694 goto fail; 2695 } 2696 h->conf.tableid = tb->conf.id; 2697 h->tablename = tb->conf.name; 2698 SLIST_INIT(&h->children); 2699 TAILQ_INSERT_TAIL(&tb->hosts, h, entry); 2700 } 2701 2702 conf->sc_tablecount++; 2703 TAILQ_INSERT_TAIL(conf->sc_tables, tb, entry); 2704 2705 return (tb); 2706 2707 fail: 2708 purge_table(NULL, tb); 2709 return (NULL); 2710} 2711 2712struct relay * 2713relay_inherit(struct relay *ra, struct relay *rb) 2714{ 2715 struct relay_config rc; 2716 2717 bcopy(&rb->rl_conf, &rc, sizeof(rc)); 2718 bcopy(ra, rb, sizeof(*rb)); 2719 2720 bcopy(&rc.ss, &rb->rl_conf.ss, sizeof(rb->rl_conf.ss)); 2721 rb->rl_conf.port = rc.port; 2722 rb->rl_conf.flags = 2723 (ra->rl_conf.flags & ~F_SSL) | (rc.flags & F_SSL); 2724 2725 rb->rl_conf.id = ++last_relay_id; 2726 if (last_relay_id == INT_MAX) { 2727 yyerror("too many relays defined"); 2728 goto err; 2729 } 2730 2731 if (snprintf(rb->rl_conf.name, sizeof(rb->rl_conf.name), "%s%u:%u", 2732 ra->rl_conf.name, rb->rl_conf.id, ntohs(rc.port)) >= 2733 (int)sizeof(rb->rl_conf.name)) { 2734 yyerror("invalid relay name"); 2735 goto err; 2736 } 2737 2738 if (relay_findbyname(conf, rb->rl_conf.name) != NULL || 2739 relay_findbyaddr(conf, &rb->rl_conf) != NULL) { 2740 yyerror("relay %s defined twice", rb->rl_conf.name); 2741 goto err; 2742 } 2743 if (relay_load_certfiles(rb) == -1) { 2744 yyerror("cannot load certificates for relay %s", 2745 rb->rl_conf.name); 2746 goto err; 2747 } 2748 2749 conf->sc_relaycount++; 2750 SPLAY_INIT(&rlay->rl_sessions); 2751 TAILQ_INSERT_TAIL(conf->sc_relays, rb, rl_entry); 2752 2753 return (rb); 2754 2755 err: 2756 free(rb); 2757 return (NULL); 2758} 2759 2760int 2761getservice(char *n) 2762{ 2763 struct servent *s; 2764 const char *errstr; 2765 long long llval; 2766 2767 llval = strtonum(n, 0, UINT16_MAX, &errstr); 2768 if (errstr) { 2769 s = getservbyname(n, "tcp"); 2770 if (s == NULL) 2771 s = getservbyname(n, "udp"); 2772 if (s == NULL) { 2773 yyerror("unknown port %s", n); 2774 return (-1); 2775 } 2776 return (s->s_port); 2777 } 2778 2779 return (htons((u_short)llval)); 2780} 2781 2782int 2783is_if_in_group(const char *ifname, const char *groupname) 2784{ 2785 unsigned int len; 2786 struct ifgroupreq ifgr; 2787 struct ifg_req *ifg; 2788 int s; 2789 int ret = 0; 2790 2791 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 2792 err(1, "socket"); 2793 2794 memset(&ifgr, 0, sizeof(ifgr)); 2795 strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ); 2796 if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) { 2797 if (errno == EINVAL || errno == ENOTTY) 2798 goto end; 2799 err(1, "SIOCGIFGROUP"); 2800 } 2801 2802 len = ifgr.ifgr_len; 2803 ifgr.ifgr_groups = 2804 (struct ifg_req *)calloc(len / sizeof(struct ifg_req), 2805 sizeof(struct ifg_req)); 2806 if (ifgr.ifgr_groups == NULL) 2807 err(1, "getifgroups"); 2808 if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) 2809 err(1, "SIOCGIFGROUP"); 2810 2811 ifg = ifgr.ifgr_groups; 2812 for (; ifg && len >= sizeof(struct ifg_req); ifg++) { 2813 len -= sizeof(struct ifg_req); 2814 if (strcmp(ifg->ifgrq_group, groupname) == 0) { 2815 ret = 1; 2816 break; 2817 } 2818 } 2819 free(ifgr.ifgr_groups); 2820 2821end: 2822 close(s); 2823 return (ret); 2824} 2825