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