Blob


1 /* $OpenBSD: parse.y,v 1.265 2026/05/31 12:44:06 rsadowski Exp $ */
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 */
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/time.h>
34 #include <sys/tree.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <net/if.h>
39 #include <net/pfvar.h>
40 #include <net/route.h>
42 #include <agentx.h>
43 #include <stdint.h>
44 #include <stdarg.h>
45 #include <stdio.h>
46 #include <unistd.h>
47 #include <ctype.h>
48 #include <err.h>
49 #include <endian.h>
50 #include <errno.h>
51 #include <limits.h>
52 #include <netdb.h>
53 #include <string.h>
54 #include <ifaddrs.h>
55 #include <syslog.h>
56 #include <md5.h>
58 #include "relayd.h"
59 #include "http.h"
60 #include "log.h"
62 TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
63 static struct file {
64 TAILQ_ENTRY(file) entry;
65 FILE *stream;
66 char *name;
67 size_t ungetpos;
68 size_t ungetsize;
69 u_char *ungetbuf;
70 int eof_reached;
71 int lineno;
72 int errors;
73 } *file, *topfile;
74 struct file *pushfile(const char *, int);
75 int popfile(void);
76 int check_file_secrecy(int, const char *);
77 int yyparse(void);
78 int yylex(void);
79 int yyerror(const char *, ...)
80 __attribute__((__format__ (printf, 1, 2)))
81 __attribute__((__nonnull__ (1)));
82 int kw_cmp(const void *, const void *);
83 int lookup(char *);
84 int igetc(void);
85 int lgetc(int);
86 void lungetc(int);
87 int findeol(void);
89 TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
90 struct sym {
91 TAILQ_ENTRY(sym) entry;
92 int used;
93 int persist;
94 char *nam;
95 char *val;
96 };
97 int symset(const char *, const char *, int);
98 char *symget(const char *);
100 struct relayd *conf = NULL;
101 static int errors = 0;
102 static int loadcfg = 0;
103 objid_t last_rdr_id = 0;
104 objid_t last_table_id = 0;
105 objid_t last_host_id = 0;
106 objid_t last_relay_id = 0;
107 objid_t last_proto_id = 0;
108 objid_t last_rt_id = 0;
109 objid_t last_nr_id = 0;
111 static struct rdr *rdr = NULL;
112 static struct table *table = NULL;
113 static struct relay *rlay = NULL;
114 static struct host *hst = NULL;
115 struct relaylist relays;
116 static struct protocol *proto = NULL;
117 static struct relay_rule *rule = NULL;
118 static struct router *router = NULL;
119 static int label = 0;
120 static int tagged = 0;
121 static int tag = 0;
122 static in_port_t tableport = 0;
123 static int dstmode;
124 static enum key_type keytype = KEY_TYPE_NONE;
125 static enum direction dir = RELAY_DIR_ANY;
126 static char *rulefile = NULL;
127 static union hashkey *hashkey = NULL;
129 struct address *host_ip(const char *);
130 int host_dns(const char *, struct addresslist *,
131 int, struct portrange *, const char *, int);
132 int host_if(const char *, struct addresslist *,
133 int, struct portrange *, const char *, int);
134 int host_ifaddr(struct sockaddr_storage *, struct ifaddrs *);
135 int host(const char *, struct addresslist *,
136 int, struct portrange *, const char *, int);
137 int host_local(struct addresslist *);
138 void host_free(struct addresslist *);
140 struct table *table_inherit(struct table *);
141 int relay_id(struct relay *);
142 struct relay *relay_inherit(struct relay *, struct relay *);
143 int getservice(char *);
144 int is_if_in_group(const char *, const char *);
145 static struct keyname *proto_keyname(char *);
147 typedef struct {
148 union {
149 int64_t number;
150 char *string;
151 struct host *host;
152 struct timeval tv;
153 struct table *table;
154 struct portrange port;
155 struct {
156 union hashkey key;
157 int keyset;
158 } key;
159 enum direction dir;
160 struct {
161 struct sockaddr_storage ss;
162 int prefixlen;
163 char name[HOST_NAME_MAX+1];
164 } addr;
165 struct {
166 enum digest_type type;
167 char *digest;
168 } digest;
169 } v;
170 int lineno;
171 } YYSTYPE;
173 %}
175 %token AGENTX APPEND BACKLOG BACKUP BINARY BUFFER CA CACHE SET CHECK CIPHERS
176 %token CODE COOKIE DEMOTE DIGEST DISABLE ERROR EXPECT PASS BLOCK EXTERNAL
177 %token FILENAME FORWARD FROM HASH HEADER HEADERLEN HOST HTTP ICMP INCLUDE INET
178 %token INET6 INTERFACE INTERVAL IP KEYPAIR LABEL LISTEN VALUE LOADBALANCE LOG
179 %token LOOKUP METHOD MODE NAT NO DESTINATION NODELAY NOTHING OCSP ON PARENT
180 %token PATH PFTAG PORT PREFORK PRIORITY PROTO QUERYSTR REAL REDIRECT RELAY
181 %token REMOVE REQUEST RESPONSE RETRY QUICK RETURN ROUNDROBIN ROUTE SACK SCRIPT
182 %token SEND SESSION SOCKET SPLICE STICKYADDR STRIP STYLE TABLE TAG TAGGED TCP
183 %token TIMEOUT TLS TO ROUTER RTLABEL TRANSPARENT URL WITH TTL RTABLE
184 %token MATCH PARAMS RANDOM LEASTSTATES SRCHASH KEY CERTIFICATE PASSWORD ECDHE
185 %token EDH TICKETS CONNECTION CONNECTIONS CONTEXT ERRORS STATE CHANGES CHECKS
186 %token WEBSOCKETS PFLOG CLIENT PROXYPROTO V1 V2
187 %token <v.string> STRING
188 %token <v.number> NUMBER
189 %type <v.string> context hostname interface table value path
190 %type <v.number> http_type loglevel quick
191 %type <v.number> dstmode flag forwardmode retry
192 %type <v.number> opttls opttlsclient optproxyproto
193 %type <v.number> redirect_proto relay_proto match pflog
194 %type <v.number> action ruleaf key_option
195 %type <v.port> port
196 %type <v.host> host
197 %type <v.addr> address rulesrc ruledst addrprefix
198 %type <v.tv> timeout
199 %type <v.digest> digest optdigest
200 %type <v.table> tablespec
201 %type <v.dir> dir
202 %type <v.key> hashkey
204 %%
206 grammar : /* empty */
207 | grammar include '\n'
208 | grammar '\n'
209 | grammar varset '\n'
210 | grammar main '\n'
211 | grammar rdr '\n'
212 | grammar tabledef '\n'
213 | grammar relay '\n'
214 | grammar proto '\n'
215 | grammar router '\n'
216 | grammar error '\n' { file->errors++; }
219 include : INCLUDE STRING {
220 struct file *nfile;
222 if ((nfile = pushfile($2, 0)) == NULL) {
223 yyerror("failed to include file %s", $2);
224 free($2);
225 YYERROR;
227 free($2);
229 file = nfile;
230 lungetc('\n');
234 opttls : /*empty*/ { $$ = 0; }
235 | TLS { $$ = 1; }
238 opttlsclient : /*empty*/ { $$ = 0; }
239 | WITH TLS { $$ = 1; }
242 http_type : HTTP { $$ = 0; }
243 | STRING {
244 if (strcmp("https", $1) == 0) {
245 $$ = 1;
246 } else {
247 yyerror("invalid check type: %s", $1);
248 free($1);
249 YYERROR;
251 free($1);
255 hostname : /* empty */ {
256 $$ = strdup("");
257 if ($$ == NULL)
258 fatal("calloc");
260 | HOST STRING {
261 if (asprintf(&$$, "Host: %s\r\nConnection: close\r\n",
262 $2) == -1)
263 fatal("asprintf");
267 relay_proto : /* empty */ { $$ = RELAY_PROTO_TCP; }
268 | TCP { $$ = RELAY_PROTO_TCP; }
269 | HTTP { $$ = RELAY_PROTO_HTTP; }
270 | STRING {
271 if (strcmp("dns", $1) == 0) {
272 $$ = RELAY_PROTO_DNS;
273 } else {
274 yyerror("invalid protocol type: %s", $1);
275 free($1);
276 YYERROR;
278 free($1);
282 redirect_proto : /* empty */ { $$ = IPPROTO_TCP; }
283 | TCP { $$ = IPPROTO_TCP; }
284 | STRING {
285 struct protoent *p;
287 if ((p = getprotobyname($1)) == NULL) {
288 yyerror("invalid protocol: %s", $1);
289 free($1);
290 YYERROR;
292 free($1);
294 $$ = p->p_proto;
298 eflags_l : eflags comma eflags_l
299 | eflags
302 opteflags : /* nothing */
303 | eflags
306 eflags : STYLE STRING
308 if ((proto->style = strdup($2)) == NULL)
309 fatal("out of memory");
310 free($2);
314 port : PORT HTTP {
315 int p = 0;
316 $$.op = PF_OP_EQ;
317 if ((p = getservice("http")) == -1)
318 YYERROR;
319 $$.val[0] = p;
320 $$.val[1] = 0;
322 | PORT STRING {
323 char *a, *b;
324 int p[2];
326 p[0] = p[1] = 0;
328 a = $2;
329 b = strchr($2, ':');
330 if (b == NULL)
331 $$.op = PF_OP_EQ;
332 else {
333 *b++ = '\0';
334 if ((p[1] = getservice(b)) == -1) {
335 free($2);
336 YYERROR;
338 $$.op = PF_OP_RRG;
340 if ((p[0] = getservice(a)) == -1) {
341 free($2);
342 YYERROR;
344 $$.val[0] = p[0];
345 $$.val[1] = p[1];
346 free($2);
348 | PORT NUMBER {
349 if ($2 <= 0 || $2 > (int)USHRT_MAX) {
350 yyerror("invalid port: %lld", $2);
351 YYERROR;
353 $$.val[0] = htons($2);
354 $$.op = PF_OP_EQ;
358 varset : STRING '=' STRING {
359 char *s = $1;
360 while (*s++) {
361 if (isspace((unsigned char)*s)) {
362 yyerror("macro name cannot contain "
363 "whitespace");
364 free($1);
365 free($3);
366 YYERROR;
369 if (symset($1, $3, 0) == -1)
370 fatal("cannot store variable");
371 free($1);
372 free($3);
376 sendbuf : NOTHING {
377 table->sendbuf = NULL;
379 | STRING {
380 table->sendbuf = strdup($1);
381 if (table->sendbuf == NULL)
382 fatal("out of memory");
383 free($1);
387 sendbinbuf : NOTHING {
388 table->sendbinbuf = NULL;
390 | STRING {
391 if (strlen($1) == 0) {
392 yyerror("empty binary send data");
393 free($1);
394 YYERROR;
396 table->sendbuf = strdup($1);
397 if (table->sendbuf == NULL)
398 fatal("out of memory");
399 table->sendbinbuf = string2binary($1);
400 if (table->sendbinbuf == NULL)
401 fatal("failed in binary send data");
402 free($1);
406 main : INTERVAL NUMBER {
407 if ((conf->sc_conf.interval.tv_sec = $2) < 0) {
408 yyerror("invalid interval: %lld", $2);
409 YYERROR;
412 | LOG loglevel {
413 conf->sc_conf.opts |= $2;
415 | TIMEOUT timeout {
416 bcopy(&$2, &conf->sc_conf.timeout,
417 sizeof(struct timeval));
419 | PREFORK NUMBER {
420 if ($2 <= 0 || $2 > PROC_MAX_INSTANCES) {
421 yyerror("invalid number of preforked "
422 "relays: %lld", $2);
423 YYERROR;
425 conf->sc_conf.prefork_relay = $2;
427 | AGENTX context path {
428 conf->sc_conf.flags |= F_AGENTX;
429 if ($2 != NULL) {
430 if (strlcpy(conf->sc_conf.agentx_context, $2,
431 sizeof(conf->sc_conf.agentx_context)) >=
432 sizeof(conf->sc_conf.agentx_context)) {
433 yyerror("agentx context too long");
434 free($2);
435 free($3);
436 YYERROR;
438 free($2);
439 } else
440 conf->sc_conf.agentx_context[0] = '\0';
441 if ($3 != NULL) {
442 if (strlcpy(conf->sc_conf.agentx_path, $3,
443 sizeof(conf->sc_conf.agentx_path)) >=
444 sizeof(conf->sc_conf.agentx_path)) {
445 yyerror("agentx path too long");
446 free($3);
447 YYERROR;
449 free($3);
450 } else
451 (void)strlcpy(conf->sc_conf.agentx_path,
452 AGENTX_MASTER_PATH,
453 sizeof(conf->sc_conf.agentx_path));
455 | SOCKET STRING {
456 conf->sc_ps->ps_csock.cs_name = $2;
460 path : /* nothing */ { $$ = NULL; }
461 | PATH STRING { $$ = $2; }
463 context : /* nothing */ { $$ = NULL; }
464 | CONTEXT STRING { $$ = $2; }
466 loglevel : STATE CHANGES { $$ = RELAYD_OPT_LOGUPDATE; }
467 | HOST CHECKS { $$ = RELAYD_OPT_LOGHOSTCHECK; }
468 | CONNECTION { $$ = (RELAYD_OPT_LOGCON |
469 RELAYD_OPT_LOGCONERR); }
470 | CONNECTION ERRORS { $$ = RELAYD_OPT_LOGCONERR; }
473 rdr : REDIRECT STRING {
474 struct rdr *srv;
476 conf->sc_conf.flags |= F_NEEDPF;
478 if (!loadcfg) {
479 free($2);
480 YYACCEPT;
483 TAILQ_FOREACH(srv, conf->sc_rdrs, entry)
484 if (!strcmp(srv->conf.name, $2))
485 break;
486 if (srv != NULL) {
487 yyerror("redirection %s defined twice", $2);
488 free($2);
489 YYERROR;
491 if ((srv = calloc(1, sizeof (*srv))) == NULL)
492 fatal("out of memory");
494 if (strlcpy(srv->conf.name, $2,
495 sizeof(srv->conf.name)) >=
496 sizeof(srv->conf.name)) {
497 yyerror("redirection name truncated: %s", $2);
498 free($2);
499 free(srv);
500 YYERROR;
502 free($2);
503 srv->conf.id = ++last_rdr_id;
504 srv->conf.timeout.tv_sec = RELAY_TIMEOUT;
505 if (last_rdr_id == INT_MAX) {
506 yyerror("too many redirections defined");
507 free(srv);
508 YYERROR;
510 rdr = srv;
511 } '{' optnl rdropts_l '}' {
512 if (rdr->table == NULL) {
513 yyerror("redirection %s has no table",
514 rdr->conf.name);
515 YYERROR;
517 if (TAILQ_EMPTY(&rdr->virts)) {
518 yyerror("redirection %s has no virtual ip",
519 rdr->conf.name);
520 YYERROR;
522 conf->sc_rdrcount++;
523 if (rdr->backup == NULL) {
524 rdr->conf.backup_id =
525 conf->sc_empty_table.conf.id;
526 rdr->backup = &conf->sc_empty_table;
527 } else if (rdr->backup->conf.port !=
528 rdr->table->conf.port) {
529 yyerror("redirection %s uses two different "
530 "ports for its table and backup table",
531 rdr->conf.name);
532 YYERROR;
534 if (!(rdr->conf.flags & F_DISABLE))
535 rdr->conf.flags |= F_ADD;
536 TAILQ_INSERT_TAIL(conf->sc_rdrs, rdr, entry);
537 tableport = 0;
538 rdr = NULL;
542 rdropts_l : rdropts_l rdroptsl nl
543 | rdroptsl optnl
546 rdroptsl : forwardmode TO tablespec interface {
547 if (hashkey != NULL) {
548 memcpy(&rdr->conf.key,
549 hashkey, sizeof(rdr->conf.key));
550 rdr->conf.flags |= F_HASHKEY;
551 free(hashkey);
552 hashkey = NULL;
555 switch ($1) {
556 case FWD_NORMAL:
557 if ($4 == NULL)
558 break;
559 yyerror("superfluous interface");
560 free($4);
561 YYERROR;
562 case FWD_ROUTE:
563 if ($4 != NULL)
564 break;
565 yyerror("missing interface to route to");
566 free($4);
567 YYERROR;
568 case FWD_TRANS:
569 yyerror("no transparent forward here");
570 if ($4 != NULL)
571 free($4);
572 YYERROR;
574 if ($4 != NULL) {
575 if (strlcpy($3->conf.ifname, $4,
576 sizeof($3->conf.ifname)) >=
577 sizeof($3->conf.ifname)) {
578 yyerror("interface name truncated");
579 free($4);
580 YYERROR;
582 free($4);
585 if ($3->conf.check == CHECK_NOCHECK) {
586 yyerror("table %s has no check", $3->conf.name);
587 purge_table(conf, conf->sc_tables, $3);
588 YYERROR;
590 if (rdr->backup) {
591 yyerror("only one backup table is allowed");
592 purge_table(conf, conf->sc_tables, $3);
593 YYERROR;
595 if (rdr->table) {
596 rdr->backup = $3;
597 rdr->conf.backup_id = $3->conf.id;
598 if (dstmode != rdr->conf.mode) {
599 yyerror("backup table for %s with "
600 "different mode", rdr->conf.name);
601 YYERROR;
603 } else {
604 rdr->table = $3;
605 rdr->conf.table_id = $3->conf.id;
606 rdr->conf.mode = dstmode;
608 $3->conf.fwdmode = $1;
609 $3->conf.rdrid = rdr->conf.id;
610 $3->conf.flags |= F_USED;
612 | LISTEN ON STRING redirect_proto port interface pflog {
613 if (host($3, &rdr->virts,
614 SRV_MAX_VIRTS, &$5, $6, $4) <= 0) {
615 yyerror("invalid virtual ip: %s", $3);
616 free($3);
617 free($6);
618 YYERROR;
620 free($3);
621 free($6);
622 if (rdr->conf.port == 0)
623 rdr->conf.port = $5.val[0];
624 tableport = rdr->conf.port;
625 if ($7)
626 rdr->conf.flags |= F_PFLOG;
628 | DISABLE { rdr->conf.flags |= F_DISABLE; }
629 | STICKYADDR { rdr->conf.flags |= F_STICKY; }
630 | match PFTAG STRING {
631 conf->sc_conf.flags |= F_NEEDPF;
632 if (strlcpy(rdr->conf.tag, $3,
633 sizeof(rdr->conf.tag)) >=
634 sizeof(rdr->conf.tag)) {
635 yyerror("redirection tag name truncated: %s",
636 $3);
637 free($3);
638 YYERROR;
640 if ($1)
641 rdr->conf.flags |= F_MATCH;
642 free($3);
644 | SESSION TIMEOUT NUMBER {
645 if ((rdr->conf.timeout.tv_sec = $3) < 0) {
646 yyerror("invalid timeout: %lld", $3);
647 YYERROR;
649 if (rdr->conf.timeout.tv_sec > INT_MAX) {
650 yyerror("timeout too large: %lld", $3);
651 YYERROR;
654 | include
657 match : /* empty */ { $$ = 0; }
658 | MATCH { $$ = 1; }
661 pflog : /* empty */ { $$ = 0; }
662 | PFLOG { $$ = 1; }
665 forwardmode : FORWARD { $$ = FWD_NORMAL; }
666 | ROUTE { $$ = FWD_ROUTE; }
667 | TRANSPARENT FORWARD { $$ = FWD_TRANS; }
670 table : '<' STRING '>' {
671 if (strlen($2) >= TABLE_NAME_SIZE) {
672 yyerror("invalid table name");
673 free($2);
674 YYERROR;
676 $$ = $2;
680 tabledef : TABLE table {
681 struct table *tb;
683 if (!loadcfg) {
684 free($2);
685 YYACCEPT;
688 TAILQ_FOREACH(tb, conf->sc_tables, entry)
689 if (!strcmp(tb->conf.name, $2))
690 break;
691 if (tb != NULL) {
692 yyerror("table %s defined twice", $2);
693 free($2);
694 YYERROR;
697 if ((tb = calloc(1, sizeof (*tb))) == NULL)
698 fatal("out of memory");
700 if (strlcpy(tb->conf.name, $2,
701 sizeof(tb->conf.name)) >= sizeof(tb->conf.name)) {
702 yyerror("table name truncated");
703 free($2);
704 YYERROR;
706 free($2);
708 tb->conf.id = 0; /* will be set later */
709 bcopy(&conf->sc_conf.timeout, &tb->conf.timeout,
710 sizeof(struct timeval));
711 TAILQ_INIT(&tb->hosts);
712 table = tb;
713 dstmode = RELAY_DSTMODE_DEFAULT;
714 } tabledefopts_l {
715 if (TAILQ_EMPTY(&table->hosts)) {
716 yyerror("table %s has no hosts",
717 table->conf.name);
718 YYERROR;
720 conf->sc_tablecount++;
721 TAILQ_INSERT_TAIL(conf->sc_tables, table, entry);
725 tabledefopts_l : tabledefopts_l tabledefopts
726 | tabledefopts
729 tabledefopts : DISABLE { table->conf.flags |= F_DISABLE; }
730 | '{' optnl tablelist_l '}'
733 tablelist_l : tablelist comma tablelist_l
734 | tablelist optnl
737 tablelist : host {
738 $1->conf.tableid = table->conf.id;
739 $1->tablename = table->conf.name;
740 TAILQ_INSERT_TAIL(&table->hosts, $1, entry);
742 | include
745 tablespec : table {
746 struct table *tb;
747 if ((tb = calloc(1, sizeof (*tb))) == NULL)
748 fatal("out of memory");
749 if (strlcpy(tb->conf.name, $1,
750 sizeof(tb->conf.name)) >= sizeof(tb->conf.name)) {
751 yyerror("table name truncated");
752 free($1);
753 YYERROR;
755 free($1);
756 table = tb;
757 dstmode = RELAY_DSTMODE_DEFAULT;
758 hashkey = NULL;
759 } tableopts_l {
760 struct table *tb;
761 if (table->conf.port == 0)
762 table->conf.port = tableport;
763 else
764 table->conf.flags |= F_PORT;
765 if ((tb = table_inherit(table)) == NULL)
766 YYERROR;
767 $$ = tb;
771 tableopts_l : tableopts tableopts_l
772 | tableopts
775 tableopts : CHECK tablecheck
776 | port {
777 if ($1.op != PF_OP_EQ) {
778 yyerror("invalid port");
779 YYERROR;
781 table->conf.port = $1.val[0];
783 | TIMEOUT timeout {
784 bcopy(&$2, &table->conf.timeout,
785 sizeof(struct timeval));
787 | DEMOTE STRING {
788 table->conf.flags |= F_DEMOTE;
789 if (strlcpy(table->conf.demote_group, $2,
790 sizeof(table->conf.demote_group))
791 >= sizeof(table->conf.demote_group)) {
792 yyerror("yyparse: demote group name too long");
793 free($2);
794 YYERROR;
796 free($2);
797 if (carp_demote_init(table->conf.demote_group, 1)
798 == -1) {
799 yyerror("yyparse: error initializing group "
800 "'%s'", table->conf.demote_group);
801 YYERROR;
804 | INTERVAL NUMBER {
805 if ($2 < conf->sc_conf.interval.tv_sec ||
806 $2 % conf->sc_conf.interval.tv_sec) {
807 yyerror("table interval must be "
808 "divisible by global interval");
809 YYERROR;
811 table->conf.skip_cnt =
812 ($2 / conf->sc_conf.interval.tv_sec) - 1;
814 | MODE dstmode hashkey {
815 switch ($2) {
816 case RELAY_DSTMODE_LOADBALANCE:
817 case RELAY_DSTMODE_HASH:
818 case RELAY_DSTMODE_SRCHASH:
819 if (hashkey != NULL) {
820 yyerror("key already specified");
821 free(hashkey);
822 YYERROR;
824 if ((hashkey = calloc(1,
825 sizeof(*hashkey))) == NULL)
826 fatal("out of memory");
827 memcpy(hashkey, &$3.key, sizeof(*hashkey));
828 break;
829 default:
830 if ($3.keyset) {
831 yyerror("key not supported by mode");
832 YYERROR;
834 hashkey = NULL;
835 break;
838 switch ($2) {
839 case RELAY_DSTMODE_LOADBALANCE:
840 case RELAY_DSTMODE_HASH:
841 if (rdr != NULL) {
842 yyerror("mode not supported "
843 "for redirections");
844 YYERROR;
846 /* FALLTHROUGH */
847 case RELAY_DSTMODE_RANDOM:
848 case RELAY_DSTMODE_ROUNDROBIN:
849 case RELAY_DSTMODE_SRCHASH:
850 dstmode = $2;
851 break;
852 case RELAY_DSTMODE_LEASTSTATES:
853 if (rdr == NULL) {
854 yyerror("mode not supported "
855 "for relays");
856 YYERROR;
858 dstmode = $2;
859 break;
864 /* should be in sync with sbin/pfctl/parse.y's hashkey */
865 hashkey : /* empty */ {
866 $$.keyset = 0;
867 $$.key.data[0] = arc4random();
868 $$.key.data[1] = arc4random();
869 $$.key.data[2] = arc4random();
870 $$.key.data[3] = arc4random();
872 | STRING {
873 /* manual key configuration */
874 $$.keyset = 1;
876 if (!strncmp($1, "0x", 2)) {
877 if (strlen($1) != 34) {
878 free($1);
879 yyerror("hex key must be 128 bits "
880 "(32 hex digits) long");
881 YYERROR;
884 if (sscanf($1, "0x%8x%8x%8x%8x",
885 &$$.key.data[0], &$$.key.data[1],
886 &$$.key.data[2], &$$.key.data[3]) != 4) {
887 free($1);
888 yyerror("invalid hex key");
889 YYERROR;
891 } else {
892 MD5_CTX context;
894 MD5Init(&context);
895 MD5Update(&context, (unsigned char *)$1,
896 strlen($1));
897 MD5Final((unsigned char *)$$.key.data,
898 &context);
899 HTONL($$.key.data[0]);
900 HTONL($$.key.data[1]);
901 HTONL($$.key.data[2]);
902 HTONL($$.key.data[3]);
904 free($1);
908 tablecheck : ICMP { table->conf.check = CHECK_ICMP; }
909 | TCP { table->conf.check = CHECK_TCP; }
910 | TLS {
911 table->conf.check = CHECK_TCP;
912 conf->sc_conf.flags |= F_TLS;
913 table->conf.flags |= F_TLS;
915 | http_type STRING hostname CODE NUMBER {
916 if ($1) {
917 conf->sc_conf.flags |= F_TLS;
918 table->conf.flags |= F_TLS;
920 table->conf.check = CHECK_HTTP_CODE;
921 if ((table->conf.retcode = $5) <= 0) {
922 yyerror("invalid HTTP code: %lld", $5);
923 free($2);
924 free($3);
925 YYERROR;
927 if (asprintf(&table->sendbuf,
928 "HEAD %s HTTP/1.%c\r\nUser-Agent: %s\r\n%s\r\n",
929 $2, strlen($3) ? '1' : '0', RELAYD_SERVERNAME, $3) == -1)
930 fatal("asprintf");
931 free($2);
932 free($3);
933 if (table->sendbuf == NULL)
934 fatal("out of memory");
936 | http_type STRING hostname digest {
937 if ($1) {
938 conf->sc_conf.flags |= F_TLS;
939 table->conf.flags |= F_TLS;
941 table->conf.check = CHECK_HTTP_DIGEST;
942 if (asprintf(&table->sendbuf,
943 "GET %s HTTP/1.%c\r\nUser-Agent: %s\r\n%s\r\n",
944 $2, strlen($3) ? '1' : '0', RELAYD_SERVERNAME, $3) == -1)
945 fatal("asprintf");
946 free($2);
947 free($3);
948 if (table->sendbuf == NULL)
949 fatal("out of memory");
950 if (strlcpy(table->conf.digest, $4.digest,
951 sizeof(table->conf.digest)) >=
952 sizeof(table->conf.digest)) {
953 yyerror("digest truncated");
954 free($4.digest);
955 YYERROR;
957 table->conf.digest_type = $4.type;
958 free($4.digest);
960 | SEND sendbuf EXPECT STRING opttls {
961 table->conf.check = CHECK_SEND_EXPECT;
962 if ($5) {
963 conf->sc_conf.flags |= F_TLS;
964 table->conf.flags |= F_TLS;
966 if (strlcpy(table->conf.exbuf, $4,
967 sizeof(table->conf.exbuf))
968 >= sizeof(table->conf.exbuf)) {
969 yyerror("yyparse: expect buffer truncated");
970 free($4);
971 YYERROR;
973 translate_string(table->conf.exbuf);
974 free($4);
976 | BINARY SEND sendbinbuf EXPECT STRING opttls {
977 table->conf.check = CHECK_BINSEND_EXPECT;
978 if ($6) {
979 conf->sc_conf.flags |= F_TLS;
980 table->conf.flags |= F_TLS;
982 if (strlen($5) == 0) {
983 yyerror("empty binary expect data");
984 free($5);
985 YYERROR;
987 if (strlcpy(table->conf.exbuf, $5,
988 sizeof(table->conf.exbuf))
989 >= sizeof(table->conf.exbuf)) {
990 yyerror("expect buffer truncated");
991 free($5);
992 YYERROR;
994 struct ibuf *ibuf = string2binary($5);
995 if (ibuf == NULL) {
996 yyerror("failed in binary expect data buffer");
997 ibuf_free(ibuf);
998 free($5);
999 YYERROR;
1001 memcpy(table->conf.exbinbuf, ibuf_data(ibuf),
1002 ibuf_size(ibuf));
1003 ibuf_free(ibuf);
1004 free($5);
1006 | SCRIPT STRING {
1007 table->conf.check = CHECK_SCRIPT;
1008 if (strlcpy(table->conf.path, $2,
1009 sizeof(table->conf.path)) >=
1010 sizeof(table->conf.path)) {
1011 yyerror("script path truncated");
1012 free($2);
1013 YYERROR;
1015 conf->sc_conf.flags |= F_SCRIPT;
1016 free($2);
1020 digest : DIGEST STRING
1022 switch (strlen($2)) {
1023 case 40:
1024 $$.type = DIGEST_SHA1;
1025 break;
1026 case 32:
1027 $$.type = DIGEST_MD5;
1028 break;
1029 default:
1030 yyerror("invalid http digest");
1031 free($2);
1032 YYERROR;
1034 $$.digest = $2;
1038 optdigest : digest {
1039 $$.digest = $1.digest;
1040 $$.type = $1.type;
1042 | STRING {
1043 $$.digest = $1;
1044 $$.type = DIGEST_NONE;
1048 proto : relay_proto PROTO STRING {
1049 struct protocol *p;
1051 if (!loadcfg) {
1052 free($3);
1053 YYACCEPT;
1056 if (strcmp($3, "default") == 0) {
1057 p = &conf->sc_proto_default;
1058 } else {
1059 TAILQ_FOREACH(p, conf->sc_protos, entry)
1060 if (!strcmp(p->name, $3))
1061 break;
1063 if (p != NULL) {
1064 yyerror("protocol %s defined twice", $3);
1065 free($3);
1066 YYERROR;
1068 if ((p = calloc(1, sizeof (*p))) == NULL)
1069 fatal("out of memory");
1071 if (strlcpy(p->name, $3, sizeof(p->name)) >=
1072 sizeof(p->name)) {
1073 yyerror("protocol name truncated");
1074 free($3);
1075 free(p);
1076 YYERROR;
1078 free($3);
1079 p->id = ++last_proto_id;
1080 p->type = $1;
1081 p->tcpflags = TCPFLAG_DEFAULT;
1082 p->tlsflags = TLSFLAG_DEFAULT;
1083 p->tcpbacklog = RELAY_BACKLOG;
1084 p->httpheaderlen = RELAY_DEFHEADERLENGTH;
1085 TAILQ_INIT(&p->rules);
1086 TAILQ_INIT(&p->tlscerts);
1087 (void)strlcpy(p->tlsciphers, TLSCIPHERS_DEFAULT,
1088 sizeof(p->tlsciphers));
1089 (void)strlcpy(p->tlsecdhecurves, TLSECDHECURVES_DEFAULT,
1090 sizeof(p->tlsecdhecurves));
1091 (void)strlcpy(p->tlsdhparams, TLSDHPARAM_DEFAULT,
1092 sizeof(p->tlsdhparams));
1093 if (last_proto_id == INT_MAX) {
1094 yyerror("too many protocols defined");
1095 free(p);
1096 YYERROR;
1098 proto = p;
1099 } protopts_n {
1100 conf->sc_protocount++;
1102 if ((proto->tlsflags & TLSFLAG_VERSION) == 0) {
1103 yyerror("invalid TLS protocol");
1104 YYERROR;
1106 TAILQ_INSERT_TAIL(conf->sc_protos, proto, entry);
1110 optproxyproto : /* empty */ { $$ = 0; }
1111 | PROXYPROTO V1 { $$ = F_PROXYV1; }
1112 | PROXYPROTO V2 { $$ = F_PROXYV2; }
1115 protopts_n : /* empty */
1116 | '{' '}'
1117 | '{' optnl protopts_l '}'
1120 protopts_l : protopts_l protoptsl nl
1121 | protoptsl optnl
1124 protoptsl : TLS {
1125 if (!(proto->type == RELAY_PROTO_TCP ||
1126 proto->type == RELAY_PROTO_HTTP)) {
1127 yyerror("can set tls options only for "
1128 "tcp or http protocols");
1129 YYERROR;
1131 } tlsflags
1132 | TLS {
1133 if (!(proto->type == RELAY_PROTO_TCP ||
1134 proto->type == RELAY_PROTO_HTTP)) {
1135 yyerror("can set tls options only for "
1136 "tcp or http protocols");
1137 YYERROR;
1139 } '{' tlsflags_l '}'
1140 | TCP {
1141 if (!(proto->type == RELAY_PROTO_TCP ||
1142 proto->type == RELAY_PROTO_HTTP)) {
1143 yyerror("can set tcp options only for "
1144 "tcp or http protocols");
1145 YYERROR;
1147 } tcpflags
1148 | TCP {
1149 if (!(proto->type == RELAY_PROTO_TCP ||
1150 proto->type == RELAY_PROTO_HTTP)) {
1151 yyerror("can set tcp options only for "
1152 "tcp or http protocols");
1153 YYERROR;
1155 } '{' tcpflags_l '}'
1156 | HTTP {
1157 if (proto->type != RELAY_PROTO_HTTP) {
1158 yyerror("can set http options only for "
1159 "http protocol");
1160 YYERROR;
1162 } httpflags
1163 | HTTP {
1164 if (proto->type != RELAY_PROTO_HTTP) {
1165 yyerror("can set http options only for "
1166 "http protocol");
1167 YYERROR;
1169 } '{' httpflags_l '}'
1170 | RETURN ERROR opteflags { proto->flags |= F_RETURN; }
1171 | RETURN ERROR '{' eflags_l '}' { proto->flags |= F_RETURN; }
1172 | filterrule
1173 | include
1177 httpflags_l : httpflags comma httpflags_l
1178 | httpflags
1181 httpflags : HEADERLEN NUMBER {
1182 if ($2 < 0 || $2 > RELAY_MAXHEADERLENGTH) {
1183 yyerror("invalid headerlen: %lld", $2);
1184 YYERROR;
1186 proto->httpheaderlen = $2;
1188 | WEBSOCKETS { proto->httpflags |= HTTPFLAG_WEBSOCKETS; }
1189 | NO WEBSOCKETS { proto->httpflags &= ~HTTPFLAG_WEBSOCKETS; }
1192 tcpflags_l : tcpflags comma tcpflags_l
1193 | tcpflags
1196 tcpflags : SACK { proto->tcpflags |= TCPFLAG_SACK; }
1197 | NO SACK { proto->tcpflags |= TCPFLAG_NSACK; }
1198 | NODELAY { proto->tcpflags |= TCPFLAG_NODELAY; }
1199 | NO NODELAY { proto->tcpflags |= TCPFLAG_NNODELAY; }
1200 | SPLICE { /* default */ }
1201 | NO SPLICE { proto->tcpflags |= TCPFLAG_NSPLICE; }
1202 | BACKLOG NUMBER {
1203 if ($2 < 0 || $2 > RELAY_MAX_BACKLOG) {
1204 yyerror("invalid backlog: %lld", $2);
1205 YYERROR;
1207 proto->tcpbacklog = $2;
1209 | SOCKET BUFFER NUMBER {
1210 proto->tcpflags |= TCPFLAG_BUFSIZ;
1211 if ((proto->tcpbufsiz = $3) < 0) {
1212 yyerror("invalid socket buffer size: %lld", $3);
1213 YYERROR;
1216 | IP STRING NUMBER {
1217 if ($3 < 0) {
1218 yyerror("invalid ttl: %lld", $3);
1219 free($2);
1220 YYERROR;
1222 if (strcasecmp("ttl", $2) == 0) {
1223 proto->tcpflags |= TCPFLAG_IPTTL;
1224 proto->tcpipttl = $3;
1225 } else if (strcasecmp("minttl", $2) == 0) {
1226 proto->tcpflags |= TCPFLAG_IPMINTTL;
1227 proto->tcpipminttl = $3;
1228 } else {
1229 yyerror("invalid TCP/IP flag: %s", $2);
1230 free($2);
1231 YYERROR;
1233 free($2);
1237 tlsflags_l : tlsflags comma tlsflags_l
1238 | tlsflags
1241 tlsflags : SESSION TICKETS { proto->tickets = 1; }
1242 | NO SESSION TICKETS { proto->tickets = 0; }
1243 | CIPHERS STRING {
1244 if (strlcpy(proto->tlsciphers, $2,
1245 sizeof(proto->tlsciphers)) >=
1246 sizeof(proto->tlsciphers)) {
1247 yyerror("tlsciphers truncated");
1248 free($2);
1249 YYERROR;
1251 free($2);
1253 | NO EDH {
1254 (void)strlcpy(proto->tlsdhparams, "none",
1255 sizeof(proto->tlsdhparams));
1257 | EDH {
1258 (void)strlcpy(proto->tlsdhparams, "auto",
1259 sizeof(proto->tlsdhparams));
1261 | EDH PARAMS STRING {
1262 struct tls_config *tls_cfg;
1263 if ((tls_cfg = tls_config_new()) == NULL) {
1264 yyerror("tls_config_new failed");
1265 free($3);
1266 YYERROR;
1268 if (tls_config_set_dheparams(tls_cfg, $3) != 0) {
1269 yyerror("tls edh params %s: %s", $3,
1270 tls_config_error(tls_cfg));
1271 tls_config_free(tls_cfg);
1272 free($3);
1273 YYERROR;
1275 tls_config_free(tls_cfg);
1276 if (strlcpy(proto->tlsdhparams, $3,
1277 sizeof(proto->tlsdhparams)) >=
1278 sizeof(proto->tlsdhparams)) {
1279 yyerror("tls edh truncated");
1280 free($3);
1281 YYERROR;
1283 free($3);
1285 | ECDHE STRING {
1286 struct tls_config *tls_cfg;
1287 if ((tls_cfg = tls_config_new()) == NULL) {
1288 yyerror("tls_config_new failed");
1289 free($2);
1290 YYERROR;
1292 if (tls_config_set_ecdhecurves(tls_cfg, $2) != 0) {
1293 yyerror("tls ecdhe %s: %s", $2,
1294 tls_config_error(tls_cfg));
1295 tls_config_free(tls_cfg);
1296 free($2);
1297 YYERROR;
1299 tls_config_free(tls_cfg);
1300 if (strlcpy(proto->tlsecdhecurves, $2,
1301 sizeof(proto->tlsecdhecurves)) >=
1302 sizeof(proto->tlsecdhecurves)) {
1303 yyerror("tls ecdhe curves truncated");
1304 free($2);
1305 YYERROR;
1307 free($2);
1309 | CA FILENAME STRING {
1310 if (strlcpy(proto->tlsca, $3,
1311 sizeof(proto->tlsca)) >=
1312 sizeof(proto->tlsca)) {
1313 yyerror("tlsca truncated");
1314 free($3);
1315 YYERROR;
1317 free($3);
1319 | CA KEY STRING PASSWORD STRING {
1320 if (strlcpy(proto->tlscakey, $3,
1321 sizeof(proto->tlscakey)) >=
1322 sizeof(proto->tlscakey)) {
1323 yyerror("tlscakey truncated");
1324 free($3);
1325 free($5);
1326 YYERROR;
1328 if ((proto->tlscapass = strdup($5)) == NULL) {
1329 yyerror("tlscapass");
1330 free($3);
1331 free($5);
1332 YYERROR;
1334 free($3);
1335 free($5);
1337 | CA CERTIFICATE STRING {
1338 if (strlcpy(proto->tlscacert, $3,
1339 sizeof(proto->tlscacert)) >=
1340 sizeof(proto->tlscacert)) {
1341 yyerror("tlscacert truncated");
1342 free($3);
1343 YYERROR;
1345 free($3);
1347 | KEYPAIR STRING {
1348 struct keyname *kname = NULL;
1350 if ((kname = proto_keyname($2)) == NULL) {
1351 free($2);
1352 YYERROR;
1354 free($2);
1356 | KEYPAIR STRING CERTIFICATE STRING {
1357 struct keyname *kname = NULL;
1359 if ((kname = proto_keyname($2)) == NULL) {
1360 free($2);
1361 free($4);
1362 YYERROR;
1365 if (strlen($4) >= PATH_MAX) {
1366 yyerror("keypair cert too long");
1367 free($2);
1368 free($4);
1369 YYERROR;
1371 if (strlcpy(kname->certificate, $4,
1372 sizeof(kname->certificate)) >=
1373 sizeof(kname->certificate)) {
1374 yyerror("keypair certificate truncated");
1375 free($2);
1376 free($4);
1377 YYERROR;
1379 free($2);
1380 free($4);
1382 | KEYPAIR STRING KEY STRING {
1383 struct keyname *kname = NULL;
1385 if ((kname = proto_keyname($2)) == NULL) {
1386 free($2);
1387 free($4);
1388 YYERROR;
1391 if (strlen($4) >= PATH_MAX) {
1392 yyerror("keypair certificate key too long");
1393 free($2);
1394 free($4);
1395 YYERROR;
1398 if (strlcpy(kname->key, $4,
1399 sizeof(kname->key)) >=
1400 sizeof(kname->key)) {
1401 yyerror("keypair certificate key truncated");
1402 free($2);
1403 free($4);
1404 YYERROR;
1406 free($2);
1407 free($4);
1409 | KEYPAIR STRING OCSP STRING {
1410 struct keyname *kname = NULL;
1412 if ((kname = proto_keyname($2)) == NULL) {
1413 free($2);
1414 free($4);
1415 YYERROR;
1418 if (strlen($4) >= PATH_MAX) {
1419 yyerror("keypair ocsp file too long");
1420 free($2);
1421 free($4);
1422 YYERROR;
1425 if (strlcpy(kname->ocsp, $4,
1426 sizeof(kname->ocsp)) >=
1427 sizeof(kname->ocsp)) {
1428 yyerror("ocsp truncated");
1429 free($2);
1430 free($4);
1431 YYERROR;
1433 free($2);
1434 free($4);
1436 | CLIENT CA STRING {
1437 if (strlcpy(proto->tlsclientca, $3,
1438 sizeof(proto->tlsclientca)) >=
1439 sizeof(proto->tlsclientca)) {
1440 yyerror("tlsclientca truncated");
1441 free($3);
1442 YYERROR;
1444 free($3);
1446 | NO flag { proto->tlsflags &= ~($2); }
1447 | flag { proto->tlsflags |= $1; }
1450 flag : STRING {
1451 if (strcmp("sslv3", $1) == 0)
1452 $$ = TLSFLAG_SSLV3;
1453 else if (strcmp("tlsv1", $1) == 0)
1454 $$ = TLSFLAG_TLSV1;
1455 else if (strcmp("tlsv1.0", $1) == 0)
1456 $$ = TLSFLAG_TLSV1_0;
1457 else if (strcmp("tlsv1.1", $1) == 0)
1458 $$ = TLSFLAG_TLSV1_1;
1459 else if (strcmp("tlsv1.2", $1) == 0)
1460 $$ = TLSFLAG_TLSV1_2;
1461 else if (strcmp("tlsv1.3", $1) == 0)
1462 $$ = TLSFLAG_TLSV1_3;
1463 else if (strcmp("cipher-server-preference", $1) == 0)
1464 $$ = TLSFLAG_CIPHER_SERVER_PREF;
1465 else if (strcmp("client-renegotiation", $1) == 0)
1466 $$ = TLSFLAG_CLIENT_RENEG;
1467 else {
1468 yyerror("invalid TLS flag: %s", $1);
1469 free($1);
1470 YYERROR;
1472 free($1);
1476 filterrule : action dir quick ruleaf rulesrc ruledst {
1477 if ((rule = calloc(1, sizeof(*rule))) == NULL)
1478 fatal("out of memory");
1480 rule->rule_action = $1;
1481 rule->rule_proto = proto->type;
1482 rule->rule_dir = $2;
1483 rule->rule_flags |= $3;
1484 rule->rule_af = $4;
1485 rule->rule_src.addr = $5.ss;
1486 rule->rule_src.addr_mask = $5.prefixlen;
1487 rule->rule_dst.addr = $6.ss;
1488 rule->rule_dst.addr_mask = $6.prefixlen;
1490 if (RELAY_AF_NEQ(rule->rule_af,
1491 rule->rule_src.addr.ss_family) ||
1492 RELAY_AF_NEQ(rule->rule_af,
1493 rule->rule_dst.addr.ss_family) ||
1494 RELAY_AF_NEQ(rule->rule_src.addr.ss_family,
1495 rule->rule_dst.addr.ss_family)) {
1496 yyerror("address family mismatch");
1497 YYERROR;
1500 rulefile = NULL;
1501 } ruleopts_l {
1502 if (rule_add(proto, rule, rulefile) == -1) {
1503 if (rulefile == NULL) {
1504 yyerror("failed to load rule");
1505 } else {
1506 yyerror("failed to load rules from %s",
1507 rulefile);
1508 free(rulefile);
1510 rule_free(rule);
1511 free(rule);
1512 YYERROR;
1514 if (rulefile)
1515 free(rulefile);
1516 rulefile = NULL;
1517 rule = NULL;
1518 keytype = KEY_TYPE_NONE;
1522 action : PASS { $$ = RULE_ACTION_PASS; }
1523 | BLOCK { $$ = RULE_ACTION_BLOCK; }
1524 | MATCH { $$ = RULE_ACTION_MATCH; }
1527 dir : /* empty */ {
1528 $$ = dir = RELAY_DIR_REQUEST;
1530 | REQUEST {
1531 $$ = dir = RELAY_DIR_REQUEST;
1533 | RESPONSE {
1534 $$ = dir = RELAY_DIR_RESPONSE;
1538 quick : /* empty */ { $$ = 0; }
1539 | QUICK { $$ = RULE_FLAG_QUICK; }
1542 ruleaf : /* empty */ { $$ = AF_UNSPEC; }
1543 | INET6 { $$ = AF_INET6; }
1544 | INET { $$ = AF_INET; }
1547 rulesrc : /* empty */ {
1548 memset(&$$, 0, sizeof($$));
1550 | FROM addrprefix {
1551 $$ = $2;
1555 ruledst : /* empty */ {
1556 memset(&$$, 0, sizeof($$));
1558 | TO addrprefix {
1559 $$ = $2;
1563 ruleopts_l : /* empty */
1564 | ruleopts_t
1567 ruleopts_t : ruleopts ruleopts_t
1568 | ruleopts
1571 ruleopts : METHOD STRING {
1572 u_int id;
1573 if ((id = relay_httpmethod_byname($2)) ==
1574 HTTP_METHOD_NONE) {
1575 yyerror("unknown HTTP method currently not "
1576 "supported");
1577 free($2);
1578 YYERROR;
1580 rule->rule_method = id;
1581 free($2);
1583 | COOKIE key_option STRING value {
1584 keytype = KEY_TYPE_COOKIE;
1585 rule->rule_kv[keytype].kv_key = strdup($3);
1586 rule->rule_kv[keytype].kv_option = $2;
1587 rule->rule_kv[keytype].kv_value = (($4 != NULL) ?
1588 strdup($4) : strdup("*"));
1589 if (rule->rule_kv[keytype].kv_key == NULL ||
1590 rule->rule_kv[keytype].kv_value == NULL)
1591 fatal("out of memory");
1592 free($3);
1593 if ($4)
1594 free($4);
1595 rule->rule_kv[keytype].kv_type = keytype;
1597 | COOKIE key_option {
1598 keytype = KEY_TYPE_COOKIE;
1599 rule->rule_kv[keytype].kv_option = $2;
1600 rule->rule_kv[keytype].kv_type = keytype;
1602 | HEADER key_option STRING value {
1603 keytype = KEY_TYPE_HEADER;
1604 memset(&rule->rule_kv[keytype], 0,
1605 sizeof(rule->rule_kv[keytype]));
1606 rule->rule_kv[keytype].kv_option = $2;
1607 rule->rule_kv[keytype].kv_key = strdup($3);
1608 rule->rule_kv[keytype].kv_value = (($4 != NULL) ?
1609 strdup($4) : strdup("*"));
1610 if (rule->rule_kv[keytype].kv_key == NULL ||
1611 rule->rule_kv[keytype].kv_value == NULL)
1612 fatal("out of memory");
1613 free($3);
1614 if ($4)
1615 free($4);
1616 rule->rule_kv[keytype].kv_type = keytype;
1618 | HEADER key_option {
1619 keytype = KEY_TYPE_HEADER;
1620 rule->rule_kv[keytype].kv_option = $2;
1621 rule->rule_kv[keytype].kv_type = keytype;
1623 | PATH key_option STRING value {
1624 keytype = KEY_TYPE_PATH;
1625 rule->rule_kv[keytype].kv_option = $2;
1626 rule->rule_kv[keytype].kv_key = strdup($3);
1627 rule->rule_kv[keytype].kv_value = (($4 != NULL) ?
1628 strdup($4) : strdup("*"));
1629 if (rule->rule_kv[keytype].kv_key == NULL ||
1630 rule->rule_kv[keytype].kv_value == NULL)
1631 fatal("out of memory");
1632 free($3);
1633 if ($4)
1634 free($4);
1635 rule->rule_kv[keytype].kv_type = keytype;
1637 | PATH key_option {
1638 keytype = KEY_TYPE_PATH;
1639 rule->rule_kv[keytype].kv_option = $2;
1640 rule->rule_kv[keytype].kv_type = keytype;
1642 | PATH STRIP NUMBER {
1643 char *strip = NULL;
1645 if ($3 < 0 || $3 > INT_MAX) {
1646 yyerror("invalid strip number");
1647 YYERROR;
1649 if (asprintf(&strip, "%lld", $3) <= 0)
1650 fatal("can't parse strip");
1651 keytype = KEY_TYPE_PATH;
1652 rule->rule_kv[keytype].kv_option = KEY_OPTION_STRIP;
1653 rule->rule_kv[keytype].kv_value = strip;
1654 rule->rule_kv[keytype].kv_type = keytype;
1656 | QUERYSTR key_option STRING value {
1657 switch ($2) {
1658 case KEY_OPTION_APPEND:
1659 case KEY_OPTION_SET:
1660 case KEY_OPTION_REMOVE:
1661 yyerror("combining query type and the given "
1662 "option is not supported");
1663 free($3);
1664 if ($4)
1665 free($4);
1666 YYERROR;
1667 break;
1669 keytype = KEY_TYPE_QUERY;
1670 rule->rule_kv[keytype].kv_option = $2;
1671 rule->rule_kv[keytype].kv_key = strdup($3);
1672 rule->rule_kv[keytype].kv_value = (($4 != NULL) ?
1673 strdup($4) : strdup("*"));
1674 if (rule->rule_kv[keytype].kv_key == NULL ||
1675 rule->rule_kv[keytype].kv_value == NULL)
1676 fatal("out of memory");
1677 free($3);
1678 if ($4)
1679 free($4);
1680 rule->rule_kv[keytype].kv_type = keytype;
1682 | QUERYSTR key_option {
1683 switch ($2) {
1684 case KEY_OPTION_APPEND:
1685 case KEY_OPTION_SET:
1686 case KEY_OPTION_REMOVE:
1687 yyerror("combining query type and the given "
1688 "option is not supported");
1689 YYERROR;
1690 break;
1692 keytype = KEY_TYPE_QUERY;
1693 rule->rule_kv[keytype].kv_option = $2;
1694 rule->rule_kv[keytype].kv_type = keytype;
1696 | URL key_option optdigest value {
1697 switch ($2) {
1698 case KEY_OPTION_APPEND:
1699 case KEY_OPTION_SET:
1700 case KEY_OPTION_REMOVE:
1701 yyerror("combining url type and the given "
1702 "option is not supported");
1703 free($3.digest);
1704 free($4);
1705 YYERROR;
1706 break;
1708 keytype = KEY_TYPE_URL;
1709 rule->rule_kv[keytype].kv_option = $2;
1710 rule->rule_kv[keytype].kv_key = strdup($3.digest);
1711 rule->rule_kv[keytype].kv_digest = $3.type;
1712 rule->rule_kv[keytype].kv_value = (($4 != NULL) ?
1713 strdup($4) : strdup("*"));
1714 if (rule->rule_kv[keytype].kv_key == NULL ||
1715 rule->rule_kv[keytype].kv_value == NULL)
1716 fatal("out of memory");
1717 free($3.digest);
1718 if ($4)
1719 free($4);
1720 rule->rule_kv[keytype].kv_type = keytype;
1722 | URL key_option {
1723 switch ($2) {
1724 case KEY_OPTION_APPEND:
1725 case KEY_OPTION_SET:
1726 case KEY_OPTION_REMOVE:
1727 yyerror("combining url type and the given "
1728 "option is not supported");
1729 YYERROR;
1730 break;
1732 keytype = KEY_TYPE_URL;
1733 rule->rule_kv[keytype].kv_option = $2;
1734 rule->rule_kv[keytype].kv_type = keytype;
1736 | FORWARD TO table {
1737 if (table_findbyname(conf, $3) == NULL) {
1738 yyerror("undefined forward table");
1739 free($3);
1740 YYERROR;
1742 if (strlcpy(rule->rule_tablename, $3,
1743 sizeof(rule->rule_tablename)) >=
1744 sizeof(rule->rule_tablename)) {
1745 yyerror("invalid forward table name");
1746 free($3);
1747 YYERROR;
1749 free($3);
1751 | TAG STRING {
1752 tag = tag_name2id($2);
1753 if (rule->rule_tag) {
1754 yyerror("tag already defined");
1755 free($2);
1756 rule_free(rule);
1757 free(rule);
1758 YYERROR;
1760 if (tag == 0) {
1761 yyerror("invalid tag");
1762 free($2);
1763 rule_free(rule);
1764 free(rule);
1765 YYERROR;
1767 rule->rule_tag = tag;
1768 if (strlcpy(rule->rule_tagname, $2,
1769 sizeof(rule->rule_tagname)) >=
1770 sizeof(rule->rule_tagname)) {
1771 yyerror("tag truncated");
1772 free($2);
1773 rule_free(rule);
1774 free(rule);
1775 YYERROR;
1777 free($2);
1779 | NO TAG {
1780 if (tag == 0) {
1781 yyerror("no tag defined");
1782 YYERROR;
1784 rule->rule_tag = -1;
1785 memset(rule->rule_tagname, 0,
1786 sizeof(rule->rule_tagname));
1788 | TAGGED STRING {
1789 tagged = tag_name2id($2);
1790 if (rule->rule_tagged) {
1791 yyerror("tagged already defined");
1792 free($2);
1793 rule_free(rule);
1794 free(rule);
1795 YYERROR;
1797 if (tagged == 0) {
1798 yyerror("invalid tag");
1799 free($2);
1800 rule_free(rule);
1801 free(rule);
1802 YYERROR;
1804 rule->rule_tagged = tagged;
1805 if (strlcpy(rule->rule_taggedname, $2,
1806 sizeof(rule->rule_taggedname)) >=
1807 sizeof(rule->rule_taggedname)) {
1808 yyerror("tagged truncated");
1809 free($2);
1810 rule_free(rule);
1811 free(rule);
1812 YYERROR;
1814 free($2);
1816 | LABEL STRING {
1817 label = label_name2id($2);
1818 if (rule->rule_label) {
1819 yyerror("label already defined");
1820 free($2);
1821 rule_free(rule);
1822 free(rule);
1823 YYERROR;
1825 if (label == 0) {
1826 yyerror("invalid label");
1827 free($2);
1828 rule_free(rule);
1829 free(rule);
1830 YYERROR;
1832 rule->rule_label = label;
1833 if (strlcpy(rule->rule_labelname, $2,
1834 sizeof(rule->rule_labelname)) >=
1835 sizeof(rule->rule_labelname)) {
1836 yyerror("label truncated");
1837 free($2);
1838 rule_free(rule);
1839 free(rule);
1840 YYERROR;
1842 free($2);
1844 | NO LABEL {
1845 if (label == 0) {
1846 yyerror("no label defined");
1847 YYERROR;
1849 rule->rule_label = -1;
1850 memset(rule->rule_labelname, 0,
1851 sizeof(rule->rule_labelname));
1853 | FILENAME STRING value {
1854 if (rulefile != NULL) {
1855 yyerror("only one file per rule supported");
1856 free($2);
1857 free($3);
1858 rule_free(rule);
1859 free(rule);
1860 YYERROR;
1862 if ($3) {
1863 if ((rule->rule_kv[keytype].kv_value =
1864 strdup($3)) == NULL)
1865 fatal("out of memory");
1866 free($3);
1867 } else
1868 rule->rule_kv[keytype].kv_value = NULL;
1869 rulefile = $2;
1873 value : /* empty */ { $$ = NULL; }
1874 | VALUE STRING { $$ = $2; }
1877 key_option : /* empty */ { $$ = KEY_OPTION_NONE; }
1878 | APPEND { $$ = KEY_OPTION_APPEND; }
1879 | SET { $$ = KEY_OPTION_SET; }
1880 | REMOVE { $$ = KEY_OPTION_REMOVE; }
1881 | HASH { $$ = KEY_OPTION_HASH; }
1882 | LOG { $$ = KEY_OPTION_LOG; }
1885 relay : RELAY STRING {
1886 struct relay *r;
1888 if (!loadcfg) {
1889 free($2);
1890 YYACCEPT;
1893 if ((r = calloc(1, sizeof (*r))) == NULL)
1894 fatal("out of memory");
1895 TAILQ_INIT(&relays);
1897 if (strlcpy(r->rl_conf.name, $2,
1898 sizeof(r->rl_conf.name)) >=
1899 sizeof(r->rl_conf.name)) {
1900 yyerror("relay name truncated");
1901 free($2);
1902 free(r);
1903 YYERROR;
1905 free($2);
1906 if (relay_id(r) == -1) {
1907 yyerror("too many relays defined");
1908 free(r);
1909 YYERROR;
1911 r->rl_conf.timeout.tv_sec = RELAY_TIMEOUT;
1912 r->rl_proto = NULL;
1913 r->rl_conf.proto = EMPTY_ID;
1914 r->rl_conf.dstretry = 0;
1915 r->rl_tls_ca_fd = -1;
1916 r->rl_tls_cacert_fd = -1;
1917 r->rl_tls_client_ca_fd = -1;
1918 TAILQ_INIT(&r->rl_tables);
1919 if (last_relay_id == INT_MAX) {
1920 yyerror("too many relays defined");
1921 free(r);
1922 YYERROR;
1924 dstmode = RELAY_DSTMODE_DEFAULT;
1925 rlay = r;
1926 } '{' optnl relayopts_l '}' {
1927 struct relay *r;
1928 struct relay_config *rlconf = &rlay->rl_conf;
1929 struct keyname *kname;
1931 if (relay_findbyname(conf, rlconf->name) != NULL ||
1932 relay_findbyaddr(conf, rlconf) != NULL) {
1933 yyerror("relay %s or listener defined twice",
1934 rlconf->name);
1935 YYERROR;
1938 if (rlay->rl_conf.ss.ss_family == AF_UNSPEC) {
1939 yyerror("relay %s has no listener",
1940 rlay->rl_conf.name);
1941 YYERROR;
1943 if ((rlay->rl_conf.flags & (F_NATLOOK|F_DIVERT)) ==
1944 (F_NATLOOK|F_DIVERT)) {
1945 yyerror("relay %s with conflicting nat lookup "
1946 "and peer options", rlay->rl_conf.name);
1947 YYERROR;
1949 if ((rlay->rl_conf.flags & (F_NATLOOK|F_DIVERT)) == 0 &&
1950 rlay->rl_conf.dstss.ss_family == AF_UNSPEC &&
1951 TAILQ_EMPTY(&rlay->rl_tables)) {
1952 yyerror("relay %s has no target, rdr, "
1953 "or table", rlay->rl_conf.name);
1954 YYERROR;
1956 if (rlay->rl_conf.proto == EMPTY_ID) {
1957 rlay->rl_proto = &conf->sc_proto_default;
1958 rlay->rl_conf.proto = conf->sc_proto_default.id;
1961 if (TAILQ_EMPTY(&rlay->rl_proto->tlscerts) &&
1962 relay_load_certfiles(conf, rlay, NULL) == -1) {
1963 yyerror("cannot load certificates for relay %s",
1964 rlay->rl_conf.name);
1965 YYERROR;
1967 TAILQ_FOREACH(kname, &rlay->rl_proto->tlscerts, entry) {
1968 if (relay_load_certfiles(conf,
1969 rlay, kname) == -1) {
1970 yyerror("cannot load keypair %s"
1971 " for relay %s", kname->name,
1972 rlay->rl_conf.name);
1973 YYERROR;
1977 conf->sc_relaycount++;
1978 SPLAY_INIT(&rlay->rl_sessions);
1979 TAILQ_INSERT_TAIL(conf->sc_relays, rlay, rl_entry);
1981 tableport = 0;
1983 while ((r = TAILQ_FIRST(&relays)) != NULL) {
1984 TAILQ_REMOVE(&relays, r, rl_entry);
1985 if (relay_inherit(rlay, r) == NULL) {
1986 YYERROR;
1989 rlay = NULL;
1993 relayopts_l : relayopts_l relayoptsl nl
1994 | relayoptsl optnl
1997 relayoptsl : LISTEN ON STRING port opttls {
1998 struct addresslist al;
1999 struct address *h;
2000 struct relay *nr, *r;
2001 int cnt = 0;
2003 if (rlay->rl_conf.ss.ss_family != AF_UNSPEC) {
2004 if ((r = calloc(1, sizeof(*r))) == NULL)
2005 fatal("out of memory");
2006 } else
2007 r = rlay;
2008 if ($4.op != PF_OP_EQ) {
2009 yyerror("invalid port");
2010 free($3);
2011 if (r != rlay)
2012 free(r);
2013 YYERROR;
2016 TAILQ_INIT(&al);
2017 if (host($3, &al, SRV_MAX_VIRTS, &$4, NULL, -1) <= 0) {
2018 yyerror("invalid listen ip: %s", $3);
2019 free($3);
2020 if (r != rlay)
2021 free(r);
2022 YYERROR;
2024 if (host_local(&al) == 0) {
2025 yyerror("no local listen ip: %s", $3);
2026 free($3);
2027 host_free(&al);
2028 if (r != rlay)
2029 free(r);
2030 YYERROR;
2032 free($3);
2033 TAILQ_FOREACH(h, &al, entry) {
2034 if (cnt == 0) {
2035 nr = r;
2036 if (nr != rlay)
2037 TAILQ_INSERT_TAIL(&relays, nr,
2038 rl_entry);
2039 } else {
2040 if ((nr = calloc(1, sizeof(*nr))) == NULL)
2041 fatal("out of memory");
2042 TAILQ_INSERT_TAIL(&relays, nr, rl_entry);
2044 bcopy(&h->ss, &nr->rl_conf.ss,
2045 sizeof(nr->rl_conf.ss));
2046 nr->rl_conf.port = h->port.val[0];
2047 if ($5)
2048 nr->rl_conf.flags |= F_TLS;
2049 cnt++;
2051 if ($5)
2052 conf->sc_conf.flags |= F_TLS;
2053 tableport = $4.val[0];
2054 host_free(&al);
2056 | forwardmode opttlsclient TO forwardspec dstaf optproxyproto {
2057 rlay->rl_conf.fwdmode = $1;
2058 if ($1 == FWD_ROUTE) {
2059 yyerror("no route for relays");
2060 YYERROR;
2062 if ($2) {
2063 rlay->rl_conf.flags |= F_TLSCLIENT;
2064 conf->sc_conf.flags |= F_TLSCLIENT;
2067 rlay->rl_conf.flags |= $6;
2069 | SESSION TIMEOUT NUMBER {
2070 if ((rlay->rl_conf.timeout.tv_sec = $3) < 0) {
2071 yyerror("invalid timeout: %lld", $3);
2072 YYERROR;
2074 if (rlay->rl_conf.timeout.tv_sec > INT_MAX) {
2075 yyerror("timeout too large: %lld", $3);
2076 YYERROR;
2079 | PROTO STRING {
2080 struct protocol *p;
2082 if (rlay->rl_conf.proto != EMPTY_ID) {
2083 yyerror("more than one protocol specified");
2084 YYERROR;
2087 TAILQ_FOREACH(p, conf->sc_protos, entry)
2088 if (!strcmp(p->name, $2))
2089 break;
2090 if (p == NULL) {
2091 yyerror("no such protocol: %s", $2);
2092 free($2);
2093 YYERROR;
2096 p->flags |= F_USED;
2097 rlay->rl_conf.proto = p->id;
2098 rlay->rl_proto = p;
2099 free($2);
2101 | DISABLE { rlay->rl_conf.flags |= F_DISABLE; }
2102 | include
2105 forwardspec : STRING port retry {
2106 struct addresslist al;
2107 struct address *h;
2109 if (rlay->rl_conf.dstss.ss_family != AF_UNSPEC) {
2110 yyerror("relay %s target or redirection "
2111 "already specified", rlay->rl_conf.name);
2112 free($1);
2113 YYERROR;
2115 if ($2.op != PF_OP_EQ) {
2116 yyerror("invalid port");
2117 free($1);
2118 YYERROR;
2121 TAILQ_INIT(&al);
2122 if (host($1, &al, 1, &$2, NULL, -1) <= 0) {
2123 yyerror("invalid forward ip: %s", $1);
2124 free($1);
2125 YYERROR;
2127 free($1);
2128 h = TAILQ_FIRST(&al);
2129 bcopy(&h->ss, &rlay->rl_conf.dstss,
2130 sizeof(rlay->rl_conf.dstss));
2131 rlay->rl_conf.dstport = h->port.val[0];
2132 rlay->rl_conf.dstretry = $3;
2133 host_free(&al);
2135 | NAT LOOKUP retry {
2136 conf->sc_conf.flags |= F_NEEDPF;
2137 rlay->rl_conf.flags |= F_NATLOOK;
2138 rlay->rl_conf.dstretry = $3;
2140 | DESTINATION retry {
2141 conf->sc_conf.flags |= F_NEEDPF;
2142 rlay->rl_conf.flags |= F_DIVERT;
2143 rlay->rl_conf.dstretry = $2;
2145 | tablespec {
2146 struct relay_table *rlt;
2148 if ((rlt = calloc(1, sizeof(*rlt))) == NULL) {
2149 yyerror("failed to allocate table reference");
2150 YYERROR;
2153 rlt->rlt_table = $1;
2154 rlt->rlt_table->conf.flags |= F_USED;
2155 rlt->rlt_mode = dstmode;
2156 rlt->rlt_flags = F_USED;
2157 if (!TAILQ_EMPTY(&rlay->rl_tables))
2158 rlt->rlt_flags |= F_BACKUP;
2160 if (hashkey != NULL &&
2161 (rlay->rl_conf.flags & F_HASHKEY) == 0) {
2162 memcpy(&rlay->rl_conf.hashkey,
2163 hashkey, sizeof(rlay->rl_conf.hashkey));
2164 rlay->rl_conf.flags |= F_HASHKEY;
2166 free(hashkey);
2167 hashkey = NULL;
2169 TAILQ_INSERT_TAIL(&rlay->rl_tables, rlt, rlt_entry);
2173 dstmode : /* empty */ { $$ = RELAY_DSTMODE_DEFAULT; }
2174 | LOADBALANCE { $$ = RELAY_DSTMODE_LOADBALANCE; }
2175 | ROUNDROBIN { $$ = RELAY_DSTMODE_ROUNDROBIN; }
2176 | HASH { $$ = RELAY_DSTMODE_HASH; }
2177 | LEASTSTATES { $$ = RELAY_DSTMODE_LEASTSTATES; }
2178 | SRCHASH { $$ = RELAY_DSTMODE_SRCHASH; }
2179 | RANDOM { $$ = RELAY_DSTMODE_RANDOM; }
2182 router : ROUTER STRING {
2183 struct router *rt = NULL;
2185 if (!loadcfg) {
2186 free($2);
2187 YYACCEPT;
2190 conf->sc_conf.flags |= F_NEEDRT;
2191 TAILQ_FOREACH(rt, conf->sc_rts, rt_entry)
2192 if (!strcmp(rt->rt_conf.name, $2))
2193 break;
2194 if (rt != NULL) {
2195 yyerror("router %s defined twice", $2);
2196 free($2);
2197 YYERROR;
2200 if ((rt = calloc(1, sizeof (*rt))) == NULL)
2201 fatal("out of memory");
2203 if (strlcpy(rt->rt_conf.name, $2,
2204 sizeof(rt->rt_conf.name)) >=
2205 sizeof(rt->rt_conf.name)) {
2206 yyerror("router name truncated");
2207 free(rt);
2208 YYERROR;
2210 free($2);
2211 rt->rt_conf.id = ++last_rt_id;
2212 if (last_rt_id == INT_MAX) {
2213 yyerror("too many routers defined");
2214 free(rt);
2215 YYERROR;
2217 TAILQ_INIT(&rt->rt_netroutes);
2218 router = rt;
2220 tableport = -1;
2221 } '{' optnl routeopts_l '}' {
2222 if (!router->rt_conf.nroutes) {
2223 yyerror("router %s without routes",
2224 router->rt_conf.name);
2225 free(router);
2226 router = NULL;
2227 YYERROR;
2230 conf->sc_routercount++;
2231 TAILQ_INSERT_TAIL(conf->sc_rts, router, rt_entry);
2232 router = NULL;
2234 tableport = 0;
2238 routeopts_l : routeopts_l routeoptsl nl
2239 | routeoptsl optnl
2242 routeoptsl : ROUTE addrprefix {
2243 struct netroute *nr;
2245 if (router->rt_conf.af == AF_UNSPEC)
2246 router->rt_conf.af = $2.ss.ss_family;
2247 else if (router->rt_conf.af != $2.ss.ss_family) {
2248 yyerror("router %s address family mismatch",
2249 router->rt_conf.name);
2250 YYERROR;
2253 if ((nr = calloc(1, sizeof(*nr))) == NULL)
2254 fatal("out of memory");
2256 nr->nr_conf.id = ++last_nr_id;
2257 if (last_nr_id == INT_MAX) {
2258 yyerror("too many routes defined");
2259 free(nr);
2260 YYERROR;
2262 nr->nr_conf.prefixlen = $2.prefixlen;
2263 nr->nr_conf.routerid = router->rt_conf.id;
2264 nr->nr_router = router;
2265 bcopy(&$2.ss, &nr->nr_conf.ss, sizeof($2.ss));
2267 router->rt_conf.nroutes++;
2268 conf->sc_routecount++;
2269 TAILQ_INSERT_TAIL(&router->rt_netroutes, nr, nr_entry);
2270 TAILQ_INSERT_TAIL(conf->sc_routes, nr, nr_route);
2272 | FORWARD TO tablespec {
2273 free(hashkey);
2274 hashkey = NULL;
2276 if (router->rt_gwtable) {
2277 yyerror("router %s table already specified",
2278 router->rt_conf.name);
2279 purge_table(conf, conf->sc_tables, $3);
2280 YYERROR;
2282 router->rt_gwtable = $3;
2283 router->rt_gwtable->conf.flags |= F_USED;
2284 router->rt_conf.gwtable = $3->conf.id;
2285 router->rt_conf.gwport = $3->conf.port;
2287 | RTABLE NUMBER {
2288 if (router->rt_conf.rtable) {
2289 yyerror("router %s rtable already specified",
2290 router->rt_conf.name);
2291 YYERROR;
2293 if ($2 < 0 || $2 > RT_TABLEID_MAX) {
2294 yyerror("invalid rtable id %lld", $2);
2295 YYERROR;
2297 router->rt_conf.rtable = $2;
2299 | RTLABEL STRING {
2300 if (strlcpy(router->rt_conf.label, $2,
2301 sizeof(router->rt_conf.label)) >=
2302 sizeof(router->rt_conf.label)) {
2303 yyerror("route label truncated");
2304 free($2);
2305 YYERROR;
2307 free($2);
2309 | DISABLE { rlay->rl_conf.flags |= F_DISABLE; }
2310 | include
2313 dstaf : /* empty */ {
2314 rlay->rl_conf.dstaf.ss_family = AF_UNSPEC;
2316 | INET {
2317 rlay->rl_conf.dstaf.ss_family = AF_INET;
2319 | INET6 STRING {
2320 struct sockaddr_in6 *sin6;
2322 sin6 = (struct sockaddr_in6 *)&rlay->rl_conf.dstaf;
2323 if (inet_pton(AF_INET6, $2, &sin6->sin6_addr) == -1) {
2324 yyerror("invalid ipv6 address %s", $2);
2325 free($2);
2326 YYERROR;
2328 free($2);
2330 sin6->sin6_family = AF_INET6;
2331 sin6->sin6_len = sizeof(*sin6);
2335 interface : /* empty */ { $$ = NULL; }
2336 | INTERFACE STRING { $$ = $2; }
2339 host : address {
2340 if ((hst = calloc(1, sizeof(*(hst)))) == NULL)
2341 fatal("out of memory");
2343 if (strlcpy(hst->conf.name, $1.name,
2344 sizeof(hst->conf.name)) >= sizeof(hst->conf.name)) {
2345 yyerror("host name truncated");
2346 free(hst);
2347 YYERROR;
2349 bcopy(&$1.ss, &hst->conf.ss, sizeof($1.ss));
2350 hst->conf.id = 0; /* will be set later */
2351 SLIST_INIT(&hst->children);
2352 } opthostflags {
2353 $$ = hst;
2354 hst = NULL;
2358 opthostflags : /* empty */
2359 | hostflags_l
2362 hostflags_l : hostflags hostflags_l
2363 | hostflags
2366 hostflags : RETRY NUMBER {
2367 if (hst->conf.retry) {
2368 yyerror("retry value already set");
2369 YYERROR;
2371 if ($2 < 0) {
2372 yyerror("invalid retry value: %lld\n", $2);
2373 YYERROR;
2375 hst->conf.retry = $2;
2377 | PARENT NUMBER {
2378 if (hst->conf.parentid) {
2379 yyerror("parent value already set");
2380 YYERROR;
2382 if ($2 < 0) {
2383 yyerror("invalid parent value: %lld\n", $2);
2384 YYERROR;
2386 hst->conf.parentid = $2;
2388 | PRIORITY NUMBER {
2389 if (hst->conf.priority) {
2390 yyerror("priority already set");
2391 YYERROR;
2393 if ($2 < 0 || $2 > RTP_MAX) {
2394 yyerror("invalid priority value: %lld\n", $2);
2395 YYERROR;
2397 hst->conf.priority = $2;
2399 | IP TTL NUMBER {
2400 if (hst->conf.ttl) {
2401 yyerror("ttl value already set");
2402 YYERROR;
2404 if ($3 < 0) {
2405 yyerror("invalid ttl value: %lld\n", $3);
2406 YYERROR;
2408 hst->conf.ttl = $3;
2412 address : STRING {
2413 struct address *h;
2414 struct addresslist al;
2416 if (strlcpy($$.name, $1,
2417 sizeof($$.name)) >= sizeof($$.name)) {
2418 yyerror("host name truncated");
2419 free($1);
2420 YYERROR;
2423 TAILQ_INIT(&al);
2424 if (host($1, &al, 1, NULL, NULL, -1) <= 0) {
2425 yyerror("invalid host %s", $1);
2426 free($1);
2427 YYERROR;
2429 free($1);
2430 h = TAILQ_FIRST(&al);
2431 memcpy(&$$.ss, &h->ss, sizeof($$.ss));
2432 host_free(&al);
2436 addrprefix : address '/' NUMBER {
2437 $$ = $1;
2438 if (($$.ss.ss_family == AF_INET &&
2439 ($3 > 32 || $3 < 0)) ||
2440 ($$.ss.ss_family == AF_INET6 &&
2441 ($3 > 128 || $3 < 0))) {
2442 yyerror("invalid prefixlen %lld", $3);
2443 YYERROR;
2445 $$.prefixlen = $3;
2447 | address {
2448 $$ = $1;
2449 if ($$.ss.ss_family == AF_INET)
2450 $$.prefixlen = 32;
2451 else if ($$.ss.ss_family == AF_INET6)
2452 $$.prefixlen = 128;
2456 retry : /* empty */ { $$ = 0; }
2457 | RETRY NUMBER {
2458 if (($$ = $2) < 0) {
2459 yyerror("invalid retry value: %lld\n", $2);
2460 YYERROR;
2465 timeout : NUMBER
2467 if ($1 < 0) {
2468 yyerror("invalid timeout: %lld\n", $1);
2469 YYERROR;
2471 $$.tv_sec = $1 / 1000;
2472 $$.tv_usec = ($1 % 1000) * 1000;
2476 comma : ','
2477 | nl
2478 | /* empty */
2481 optnl : '\n' optnl
2485 nl : '\n' optnl
2489 struct keywords {
2490 const char *k_name;
2491 int k_val;
2494 int
2495 yyerror(const char *fmt, ...)
2497 va_list ap;
2498 char *msg;
2500 file->errors++;
2501 va_start(ap, fmt);
2502 if (vasprintf(&msg, fmt, ap) == -1)
2503 fatalx("yyerror vasprintf");
2504 va_end(ap);
2505 logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
2506 free(msg);
2507 return (0);
2510 int
2511 kw_cmp(const void *k, const void *e)
2513 return (strcmp(k, ((const struct keywords *)e)->k_name));
2516 int
2517 lookup(char *s)
2519 /* this has to be sorted always */
2520 static const struct keywords keywords[] = {
2521 { "agentx", AGENTX },
2522 { "append", APPEND },
2523 { "backlog", BACKLOG },
2524 { "backup", BACKUP },
2525 { "binary", BINARY },
2526 { "block", BLOCK },
2527 { "buffer", BUFFER },
2528 { "ca", CA },
2529 { "cache", CACHE },
2530 { "cert", CERTIFICATE },
2531 { "changes", CHANGES },
2532 { "check", CHECK },
2533 { "checks", CHECKS },
2534 { "ciphers", CIPHERS },
2535 { "client", CLIENT },
2536 { "code", CODE },
2537 { "connection", CONNECTION },
2538 { "context", CONTEXT },
2539 { "cookie", COOKIE },
2540 { "demote", DEMOTE },
2541 { "destination", DESTINATION },
2542 { "digest", DIGEST },
2543 { "disable", DISABLE },
2544 { "ecdhe", ECDHE },
2545 { "edh", EDH },
2546 { "error", ERROR },
2547 { "errors", ERRORS },
2548 { "expect", EXPECT },
2549 { "external", EXTERNAL },
2550 { "file", FILENAME },
2551 { "forward", FORWARD },
2552 { "from", FROM },
2553 { "hash", HASH },
2554 { "header", HEADER },
2555 { "headerlen", HEADERLEN },
2556 { "host", HOST },
2557 { "http", HTTP },
2558 { "icmp", ICMP },
2559 { "include", INCLUDE },
2560 { "inet", INET },
2561 { "inet6", INET6 },
2562 { "interface", INTERFACE },
2563 { "interval", INTERVAL },
2564 { "ip", IP },
2565 { "key", KEY },
2566 { "keypair", KEYPAIR },
2567 { "label", LABEL },
2568 { "least-states", LEASTSTATES },
2569 { "listen", LISTEN },
2570 { "loadbalance", LOADBALANCE },
2571 { "log", LOG },
2572 { "lookup", LOOKUP },
2573 { "match", MATCH },
2574 { "method", METHOD },
2575 { "mode", MODE },
2576 { "nat", NAT },
2577 { "no", NO },
2578 { "nodelay", NODELAY },
2579 { "nothing", NOTHING },
2580 { "on", ON },
2581 { "params", PARAMS },
2582 { "parent", PARENT },
2583 { "pass", PASS },
2584 { "password", PASSWORD },
2585 { "path", PATH },
2586 { "pflog", PFLOG },
2587 { "pftag", PFTAG },
2588 { "port", PORT },
2589 { "prefork", PREFORK },
2590 { "priority", PRIORITY },
2591 { "protocol", PROTO },
2592 { "proxy-protocol", PROXYPROTO },
2593 { "query", QUERYSTR },
2594 { "quick", QUICK },
2595 { "random", RANDOM },
2596 { "real", REAL },
2597 { "redirect", REDIRECT },
2598 { "relay", RELAY },
2599 { "remove", REMOVE },
2600 { "request", REQUEST },
2601 { "response", RESPONSE },
2602 { "retry", RETRY },
2603 { "return", RETURN },
2604 { "roundrobin", ROUNDROBIN },
2605 { "route", ROUTE },
2606 { "router", ROUTER },
2607 { "rtable", RTABLE },
2608 { "rtlabel", RTLABEL },
2609 { "sack", SACK },
2610 { "script", SCRIPT },
2611 { "send", SEND },
2612 { "session", SESSION },
2613 { "set", SET },
2614 { "socket", SOCKET },
2615 { "source-hash", SRCHASH },
2616 { "splice", SPLICE },
2617 { "state", STATE },
2618 { "sticky-address", STICKYADDR },
2619 { "strip", STRIP },
2620 { "style", STYLE },
2621 { "table", TABLE },
2622 { "tag", TAG },
2623 { "tagged", TAGGED },
2624 { "tcp", TCP },
2625 { "tickets", TICKETS },
2626 { "timeout", TIMEOUT },
2627 { "tls", TLS },
2628 { "to", TO },
2629 { "transparent", TRANSPARENT },
2630 { "ttl", TTL },
2631 { "url", URL },
2632 { "v1", V1 },
2633 { "v2", V2 },
2634 { "value", VALUE },
2635 { "websockets", WEBSOCKETS },
2636 { "with", WITH }
2638 const struct keywords *p;
2640 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
2641 sizeof(keywords[0]), kw_cmp);
2643 if (p)
2644 return (p->k_val);
2645 else
2646 return (STRING);
2650 #define START_EXPAND 1
2651 #define DONE_EXPAND 2
2653 static int expanding;
2655 int
2656 igetc(void)
2658 int c;
2660 while (1) {
2661 if (file->ungetpos > 0)
2662 c = file->ungetbuf[--file->ungetpos];
2663 else c = getc(file->stream);
2665 if (c == START_EXPAND)
2666 expanding = 1;
2667 else if (c == DONE_EXPAND)
2668 expanding = 0;
2669 else
2670 break;
2672 return (c);
2675 int
2676 lgetc(int quotec)
2678 int c, next;
2680 if (quotec) {
2681 if ((c = igetc()) == EOF) {
2682 yyerror("reached end of file while parsing "
2683 "quoted string");
2684 if (file == topfile || popfile() == EOF)
2685 return (EOF);
2686 return (quotec);
2688 return (c);
2691 while ((c = igetc()) == '\\') {
2692 next = igetc();
2693 if (next != '\n') {
2694 c = next;
2695 break;
2697 yylval.lineno = file->lineno;
2698 file->lineno++;
2701 if (c == EOF) {
2703 * Fake EOL when hit EOF for the first time. This gets line
2704 * count right if last line in included file is syntactically
2705 * invalid and has no newline.
2707 if (file->eof_reached == 0) {
2708 file->eof_reached = 1;
2709 return ('\n');
2711 while (c == EOF) {
2712 if (file == topfile || popfile() == EOF)
2713 return (EOF);
2714 c = igetc();
2717 return (c);
2720 void
2721 lungetc(int c)
2723 if (c == EOF)
2724 return;
2726 if (file->ungetpos >= file->ungetsize) {
2727 void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
2728 if (p == NULL)
2729 err(1, "%s", __func__);
2730 file->ungetbuf = p;
2731 file->ungetsize *= 2;
2733 file->ungetbuf[file->ungetpos++] = c;
2736 int
2737 findeol(void)
2739 int c;
2741 /* skip to either EOF or the first real EOL */
2742 while (1) {
2743 c = lgetc(0);
2744 if (c == '\n') {
2745 file->lineno++;
2746 break;
2748 if (c == EOF)
2749 break;
2751 return (ERROR);
2754 int
2755 yylex(void)
2757 char buf[8096];
2758 char *p, *val;
2759 int quotec, next, c;
2760 int token;
2762 top:
2763 p = buf;
2764 while ((c = lgetc(0)) == ' ' || c == '\t')
2765 ; /* nothing */
2767 yylval.lineno = file->lineno;
2768 if (c == '#')
2769 while ((c = lgetc(0)) != '\n' && c != EOF)
2770 ; /* nothing */
2771 if (c == '$' && !expanding) {
2772 while (1) {
2773 if ((c = lgetc(0)) == EOF)
2774 return (0);
2776 if (p + 1 >= buf + sizeof(buf) - 1) {
2777 yyerror("string too long");
2778 return (findeol());
2780 if (isalnum(c) || c == '_') {
2781 *p++ = c;
2782 continue;
2784 *p = '\0';
2785 lungetc(c);
2786 break;
2788 val = symget(buf);
2789 if (val == NULL) {
2790 yyerror("macro '%s' not defined", buf);
2791 return (findeol());
2793 p = val + strlen(val) - 1;
2794 lungetc(DONE_EXPAND);
2795 while (p >= val) {
2796 lungetc((unsigned char)*p);
2797 p--;
2799 lungetc(START_EXPAND);
2800 goto top;
2803 switch (c) {
2804 case '\'':
2805 case '"':
2806 quotec = c;
2807 while (1) {
2808 if ((c = lgetc(quotec)) == EOF)
2809 return (0);
2810 if (c == '\n') {
2811 file->lineno++;
2812 continue;
2813 } else if (c == '\\') {
2814 if ((next = lgetc(quotec)) == EOF)
2815 return (0);
2816 if (next == quotec || next == ' ' ||
2817 next == '\t')
2818 c = next;
2819 else if (next == '\n') {
2820 file->lineno++;
2821 continue;
2822 } else
2823 lungetc(next);
2824 } else if (c == quotec) {
2825 *p = '\0';
2826 break;
2827 } else if (c == '\0') {
2828 yyerror("syntax error");
2829 return (findeol());
2831 if (p + 1 >= buf + sizeof(buf) - 1) {
2832 yyerror("string too long");
2833 return (findeol());
2835 *p++ = c;
2837 yylval.v.string = strdup(buf);
2838 if (yylval.v.string == NULL)
2839 err(1, "%s", __func__);
2840 return (STRING);
2843 #define allowed_to_end_number(x) \
2844 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
2846 if (c == '-' || isdigit(c)) {
2847 do {
2848 *p++ = c;
2849 if ((size_t)(p-buf) >= sizeof(buf)) {
2850 yyerror("string too long");
2851 return (findeol());
2853 } while ((c = lgetc(0)) != EOF && isdigit(c));
2854 lungetc(c);
2855 if (p == buf + 1 && buf[0] == '-')
2856 goto nodigits;
2857 if (c == EOF || allowed_to_end_number(c)) {
2858 const char *errstr = NULL;
2860 *p = '\0';
2861 yylval.v.number = strtonum(buf, LLONG_MIN,
2862 LLONG_MAX, &errstr);
2863 if (errstr) {
2864 yyerror("\"%s\" invalid number: %s",
2865 buf, errstr);
2866 return (findeol());
2868 return (NUMBER);
2869 } else {
2870 nodigits:
2871 while (p > buf + 1)
2872 lungetc((unsigned char)*--p);
2873 c = (unsigned char)*--p;
2874 if (c == '-')
2875 return (c);
2879 #define allowed_in_string(x) \
2880 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
2881 x != '{' && x != '}' && x != '<' && x != '>' && \
2882 x != '!' && x != '=' && x != '#' && \
2883 x != ',' && x != '/'))
2885 if (isalnum(c) || c == ':' || c == '_') {
2886 do {
2887 *p++ = c;
2888 if ((size_t)(p-buf) >= sizeof(buf)) {
2889 yyerror("string too long");
2890 return (findeol());
2892 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
2893 lungetc(c);
2894 *p = '\0';
2895 if ((token = lookup(buf)) == STRING)
2896 if ((yylval.v.string = strdup(buf)) == NULL)
2897 err(1, "%s", __func__);
2898 return (token);
2900 if (c == '\n') {
2901 yylval.lineno = file->lineno;
2902 file->lineno++;
2904 if (c == EOF)
2905 return (0);
2906 return (c);
2909 int
2910 check_file_secrecy(int fd, const char *fname)
2912 struct stat st;
2914 if (fstat(fd, &st)) {
2915 log_warn("cannot stat %s", fname);
2916 return (-1);
2918 if (st.st_uid != 0 && st.st_uid != getuid()) {
2919 log_warnx("%s: owner not root or current user", fname);
2920 return (-1);
2922 if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
2923 log_warnx("%s: group writable or world read/writable", fname);
2924 return (-1);
2926 return (0);
2929 struct file *
2930 pushfile(const char *name, int secret)
2932 struct file *nfile;
2934 if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
2935 log_warn("%s", __func__);
2936 return (NULL);
2938 if ((nfile->name = strdup(name)) == NULL) {
2939 log_warn("%s", __func__);
2940 free(nfile);
2941 return (NULL);
2943 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
2944 log_warn("%s: %s", __func__, nfile->name);
2945 free(nfile->name);
2946 free(nfile);
2947 return (NULL);
2948 } else if (secret &&
2949 check_file_secrecy(fileno(nfile->stream), nfile->name)) {
2950 fclose(nfile->stream);
2951 free(nfile->name);
2952 free(nfile);
2953 return (NULL);
2955 nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
2956 nfile->ungetsize = 16;
2957 nfile->ungetbuf = malloc(nfile->ungetsize);
2958 if (nfile->ungetbuf == NULL) {
2959 log_warn("%s", __func__);
2960 fclose(nfile->stream);
2961 free(nfile->name);
2962 free(nfile);
2963 return (NULL);
2965 TAILQ_INSERT_TAIL(&files, nfile, entry);
2966 return (nfile);
2969 int
2970 popfile(void)
2972 struct file *prev;
2974 if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
2975 prev->errors += file->errors;
2977 TAILQ_REMOVE(&files, file, entry);
2978 fclose(file->stream);
2979 free(file->name);
2980 free(file->ungetbuf);
2981 free(file);
2982 file = prev;
2983 return (file ? 0 : EOF);
2986 int
2987 parse_config(const char *filename, struct relayd *x_conf)
2989 struct sym *sym, *next;
2991 conf = x_conf;
2992 if (config_init(conf) == -1) {
2993 log_warn("%s: cannot initialize configuration", __func__);
2994 return (-1);
2997 errors = 0;
2999 if ((file = pushfile(filename, 0)) == NULL)
3000 return (-1);
3002 topfile = file;
3003 setservent(1);
3005 yyparse();
3006 errors = file->errors;
3007 while (popfile() != EOF)
3010 endservent();
3011 endprotoent();
3013 /* Free macros */
3014 TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
3015 if (!sym->persist) {
3016 free(sym->nam);
3017 free(sym->val);
3018 TAILQ_REMOVE(&symhead, sym, entry);
3019 free(sym);
3023 return (errors ? -1 : 0);
3026 int
3027 load_config(const char *filename, struct relayd *x_conf)
3029 struct sym *sym, *next;
3030 struct table *nexttb;
3031 struct host *h, *ph;
3032 struct relay_table *rlt;
3034 conf = x_conf;
3035 conf->sc_conf.flags = 0;
3037 loadcfg = 1;
3038 errors = 0;
3039 last_host_id = last_table_id = last_rdr_id = last_proto_id =
3040 last_relay_id = last_rt_id = last_nr_id = 0;
3042 rdr = NULL;
3043 table = NULL;
3044 rlay = NULL;
3045 proto = NULL;
3046 router = NULL;
3048 if ((file = pushfile(filename, 0)) == NULL)
3049 return (-1);
3051 topfile = file;
3052 setservent(1);
3054 yyparse();
3055 errors = file->errors;
3056 while (popfile() != EOF)
3059 endservent();
3060 endprotoent();
3062 /* Free macros and check which have not been used. */
3063 for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
3064 next = TAILQ_NEXT(sym, entry);
3065 if ((conf->sc_conf.opts & RELAYD_OPT_VERBOSE) && !sym->used)
3066 fprintf(stderr, "warning: macro '%s' not "
3067 "used\n", sym->nam);
3068 if (!sym->persist) {
3069 free(sym->nam);
3070 free(sym->val);
3071 TAILQ_REMOVE(&symhead, sym, entry);
3072 free(sym);
3076 if (TAILQ_EMPTY(conf->sc_rdrs) &&
3077 TAILQ_EMPTY(conf->sc_relays) &&
3078 TAILQ_EMPTY(conf->sc_rts)) {
3079 log_warnx("no actions, nothing to do");
3080 errors++;
3083 /* Cleanup relay list to inherit */
3084 while ((rlay = TAILQ_FIRST(&relays)) != NULL) {
3085 TAILQ_REMOVE(&relays, rlay, rl_entry);
3086 while ((rlt = TAILQ_FIRST(&rlay->rl_tables))) {
3087 TAILQ_REMOVE(&rlay->rl_tables, rlt, rlt_entry);
3088 free(rlt);
3090 free(rlay);
3093 if (timercmp(&conf->sc_conf.timeout, &conf->sc_conf.interval, >=)) {
3094 log_warnx("global timeout exceeds interval");
3095 errors++;
3098 /* Verify that every table is used */
3099 for (table = TAILQ_FIRST(conf->sc_tables); table != NULL;
3100 table = nexttb) {
3101 nexttb = TAILQ_NEXT(table, entry);
3102 if (table->conf.port == 0) {
3103 TAILQ_REMOVE(conf->sc_tables, table, entry);
3104 while ((h = TAILQ_FIRST(&table->hosts)) != NULL) {
3105 TAILQ_REMOVE(&table->hosts, h, entry);
3106 free(h);
3108 if (table->sendbuf != NULL)
3109 free(table->sendbuf);
3110 if (table->sendbinbuf != NULL)
3111 ibuf_free(table->sendbinbuf);
3112 free(table);
3113 continue;
3116 TAILQ_FOREACH(h, &table->hosts, entry) {
3117 if (h->conf.parentid) {
3118 ph = host_find(conf, h->conf.parentid);
3120 /* Validate the parent id */
3121 if (h->conf.id == h->conf.parentid ||
3122 ph == NULL || ph->conf.parentid)
3123 ph = NULL;
3125 if (ph == NULL) {
3126 log_warnx("host parent id %d invalid",
3127 h->conf.parentid);
3128 errors++;
3129 } else
3130 SLIST_INSERT_HEAD(&ph->children,
3131 h, child);
3135 if (!(table->conf.flags & F_USED)) {
3136 log_warnx("unused table: %s", table->conf.name);
3137 errors++;
3139 if (timercmp(&table->conf.timeout,
3140 &conf->sc_conf.interval, >=)) {
3141 log_warnx("table timeout exceeds interval: %s",
3142 table->conf.name);
3143 errors++;
3147 /* Verify that every non-default protocol is used */
3148 TAILQ_FOREACH(proto, conf->sc_protos, entry) {
3149 if (!(proto->flags & F_USED)) {
3150 log_warnx("unused protocol: %s", proto->name);
3154 return (errors ? -1 : 0);
3157 int
3158 symset(const char *nam, const char *val, int persist)
3160 struct sym *sym;
3162 TAILQ_FOREACH(sym, &symhead, entry) {
3163 if (strcmp(nam, sym->nam) == 0)
3164 break;
3167 if (sym != NULL) {
3168 if (sym->persist == 1)
3169 return (0);
3170 else {
3171 free(sym->nam);
3172 free(sym->val);
3173 TAILQ_REMOVE(&symhead, sym, entry);
3174 free(sym);
3177 if ((sym = calloc(1, sizeof(*sym))) == NULL)
3178 return (-1);
3180 sym->nam = strdup(nam);
3181 if (sym->nam == NULL) {
3182 free(sym);
3183 return (-1);
3185 sym->val = strdup(val);
3186 if (sym->val == NULL) {
3187 free(sym->nam);
3188 free(sym);
3189 return (-1);
3191 sym->used = 0;
3192 sym->persist = persist;
3193 TAILQ_INSERT_TAIL(&symhead, sym, entry);
3194 return (0);
3197 int
3198 cmdline_symset(char *s)
3200 char *sym, *val;
3201 int ret;
3203 if ((val = strrchr(s, '=')) == NULL)
3204 return (-1);
3205 sym = strndup(s, val - s);
3206 if (sym == NULL)
3207 errx(1, "%s: strndup", __func__);
3208 ret = symset(sym, val + 1, 1);
3209 free(sym);
3211 return (ret);
3214 char *
3215 symget(const char *nam)
3217 struct sym *sym;
3219 TAILQ_FOREACH(sym, &symhead, entry) {
3220 if (strcmp(nam, sym->nam) == 0) {
3221 sym->used = 1;
3222 return (sym->val);
3225 return (NULL);
3228 struct address *
3229 host_ip(const char *s)
3231 struct addrinfo hints, *res;
3232 struct address *h = NULL;
3234 memset(&hints, 0, sizeof(hints));
3235 hints.ai_family = AF_UNSPEC;
3236 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
3237 hints.ai_flags = AI_NUMERICHOST;
3238 if (getaddrinfo(s, "0", &hints, &res) == 0) {
3239 if (res->ai_family == AF_INET ||
3240 res->ai_family == AF_INET6) {
3241 if ((h = calloc(1, sizeof(*h))) == NULL)
3242 fatal(NULL);
3243 memcpy(&h->ss, res->ai_addr, res->ai_addrlen);
3245 freeaddrinfo(res);
3248 return (h);
3251 int
3252 host_dns(const char *s, struct addresslist *al, int max,
3253 struct portrange *port, const char *ifname, int ipproto)
3255 struct addrinfo hints, *res0, *res;
3256 int error, cnt = 0;
3257 struct address *h;
3259 if ((cnt = host_if(s, al, max, port, ifname, ipproto)) != 0)
3260 return (cnt);
3262 bzero(&hints, sizeof(hints));
3263 hints.ai_family = AF_UNSPEC;
3264 hints.ai_socktype = SOCK_DGRAM; /* DUMMY */
3265 hints.ai_flags = AI_ADDRCONFIG;
3266 error = getaddrinfo(s, NULL, &hints, &res0);
3267 if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME)
3268 return (0);
3269 if (error) {
3270 log_warnx("%s: could not parse \"%s\": %s", __func__, s,
3271 gai_strerror(error));
3272 return (-1);
3275 for (res = res0; res && cnt < max; res = res->ai_next) {
3276 if (res->ai_family != AF_INET &&
3277 res->ai_family != AF_INET6)
3278 continue;
3279 if ((h = calloc(1, sizeof(*h))) == NULL)
3280 fatal(__func__);
3282 if (port != NULL)
3283 bcopy(port, &h->port, sizeof(h->port));
3284 if (ifname != NULL) {
3285 if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >=
3286 sizeof(h->ifname))
3287 log_warnx("%s: interface name truncated",
3288 __func__);
3289 freeaddrinfo(res0);
3290 free(h);
3291 return (-1);
3293 if (ipproto != -1)
3294 h->ipproto = ipproto;
3296 memcpy(&h->ss, res->ai_addr, res->ai_addrlen);
3298 TAILQ_INSERT_HEAD(al, h, entry);
3299 cnt++;
3301 if (cnt == max && res) {
3302 log_warnx("%s: %s resolves to more than %d hosts", __func__,
3303 s, max);
3305 freeaddrinfo(res0);
3306 return (cnt);
3309 int
3310 host_if(const char *s, struct addresslist *al, int max,
3311 struct portrange *port, const char *ifname, int ipproto)
3313 struct ifaddrs *ifap, *p;
3314 struct sockaddr_in *sain;
3315 struct sockaddr_in6 *sin6;
3316 struct address *h;
3317 int cnt = 0, af;
3319 if (getifaddrs(&ifap) == -1)
3320 fatal("getifaddrs");
3322 /* First search for IPv4 addresses */
3323 af = AF_INET;
3325 nextaf:
3326 for (p = ifap; p != NULL && cnt < max; p = p->ifa_next) {
3327 if (p->ifa_addr == NULL ||
3328 p->ifa_addr->sa_family != af ||
3329 (strcmp(s, p->ifa_name) != 0 &&
3330 !is_if_in_group(p->ifa_name, s)))
3331 continue;
3332 if ((h = calloc(1, sizeof(*h))) == NULL)
3333 fatal("calloc");
3335 if (port != NULL)
3336 bcopy(port, &h->port, sizeof(h->port));
3337 if (ifname != NULL) {
3338 if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >=
3339 sizeof(h->ifname))
3340 log_warnx("%s: interface name truncated",
3341 __func__);
3342 freeifaddrs(ifap);
3343 free(h);
3344 return (-1);
3346 if (ipproto != -1)
3347 h->ipproto = ipproto;
3348 h->ss.ss_family = af;
3350 if (af == AF_INET) {
3351 sain = (struct sockaddr_in *)&h->ss;
3352 sain->sin_len = sizeof(struct sockaddr_in);
3353 sain->sin_addr.s_addr = ((struct sockaddr_in *)
3354 p->ifa_addr)->sin_addr.s_addr;
3355 } else {
3356 sin6 = (struct sockaddr_in6 *)&h->ss;
3357 sin6->sin6_len = sizeof(struct sockaddr_in6);
3358 memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *)
3359 p->ifa_addr)->sin6_addr, sizeof(struct in6_addr));
3360 sin6->sin6_scope_id = ((struct sockaddr_in6 *)
3361 p->ifa_addr)->sin6_scope_id;
3364 TAILQ_INSERT_HEAD(al, h, entry);
3365 cnt++;
3367 if (af == AF_INET) {
3368 /* Next search for IPv6 addresses */
3369 af = AF_INET6;
3370 goto nextaf;
3373 if (cnt > max) {
3374 log_warnx("%s: %s resolves to more than %d hosts", __func__,
3375 s, max);
3377 freeifaddrs(ifap);
3378 return (cnt);
3381 int
3382 host(const char *s, struct addresslist *al, int max,
3383 struct portrange *port, const char *ifname, int ipproto)
3385 struct address *h;
3387 if ((h = host_ip(s)) == NULL)
3388 return (host_dns(s, al, max, port, ifname, ipproto));
3390 if (port != NULL)
3391 bcopy(port, &h->port, sizeof(h->port));
3392 if (ifname != NULL) {
3393 if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >=
3394 sizeof(h->ifname)) {
3395 log_warnx("%s: interface name truncated",
3396 __func__);
3397 free(h);
3398 return (-1);
3401 if (ipproto != -1)
3402 h->ipproto = ipproto;
3404 TAILQ_INSERT_HEAD(al, h, entry);
3405 return (1);
3408 int
3409 host_ifaddr(struct sockaddr_storage *ss, struct ifaddrs *ifap)
3411 struct ifaddrs *p;
3412 struct sockaddr_in *sin;
3413 struct sockaddr_in6 *sin6;
3415 switch (ss->ss_family) {
3416 case AF_INET:
3417 sin = (struct sockaddr_in *)ss;
3418 if (sin->sin_addr.s_addr == INADDR_ANY)
3419 return (1);
3420 break;
3421 case AF_INET6:
3422 sin6 = (struct sockaddr_in6 *)ss;
3423 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
3424 return (1);
3425 break;
3426 default:
3427 return (0);
3430 for (p = ifap; p != NULL; p = p->ifa_next) {
3431 if (p->ifa_addr == NULL ||
3432 p->ifa_addr->sa_family != ss->ss_family ||
3433 sockaddr_cmp((struct sockaddr *)ss, p->ifa_addr, -1) != 0)
3434 continue;
3435 bzero(ss, sizeof(*ss));
3436 memcpy(ss, p->ifa_addr, p->ifa_addr->sa_len);
3437 return (1);
3440 return (0);
3443 int
3444 host_local(struct addresslist *al)
3446 struct ifaddrs *ifap;
3447 struct address *h, *next;
3448 int cnt = 0;
3450 if (getifaddrs(&ifap) == -1)
3451 fatal("getifaddrs");
3453 TAILQ_FOREACH_SAFE(h, al, entry, next) {
3454 if (host_ifaddr(&h->ss, ifap)) {
3455 cnt++;
3456 continue;
3458 TAILQ_REMOVE(al, h, entry);
3459 free(h);
3462 freeifaddrs(ifap);
3463 return (cnt);
3466 void
3467 host_free(struct addresslist *al)
3469 struct address *h;
3471 while ((h = TAILQ_FIRST(al)) != NULL) {
3472 TAILQ_REMOVE(al, h, entry);
3473 free(h);
3477 struct table *
3478 table_inherit(struct table *tb)
3480 char pname[TABLE_NAME_SIZE + 6];
3481 struct host *h, *dsth;
3482 struct table *dsttb, *oldtb;
3484 /* Get the table or table template */
3485 if ((dsttb = table_findbyname(conf, tb->conf.name)) == NULL) {
3486 yyerror("unknown table %s", tb->conf.name);
3487 goto fail;
3489 if (dsttb->conf.port != 0)
3490 fatal("invalid table"); /* should not happen */
3492 if (tb->conf.port == 0) {
3493 yyerror("invalid port");
3494 goto fail;
3497 /* Check if a matching table already exists */
3498 if (snprintf(pname, sizeof(pname), "%s:%u",
3499 tb->conf.name, ntohs(tb->conf.port)) >= (int)sizeof(pname)) {
3500 yyerror("invalid table name");
3501 goto fail;
3503 if (strlcpy(tb->conf.name, pname, sizeof(tb->conf.name)) >=
3504 sizeof(tb->conf.name)) {
3505 yyerror("invalid table mame");
3506 goto fail;
3508 if ((oldtb = table_findbyconf(conf, tb)) != NULL) {
3509 purge_table(conf, NULL, tb);
3510 return (oldtb);
3513 /* Create a new table */
3514 tb->conf.id = ++last_table_id;
3515 if (last_table_id == INT_MAX) {
3516 yyerror("too many tables defined");
3517 goto fail;
3519 tb->conf.flags |= dsttb->conf.flags;
3521 /* Inherit global table options */
3522 if (tb->conf.timeout.tv_sec == 0 && tb->conf.timeout.tv_usec == 0)
3523 bcopy(&dsttb->conf.timeout, &tb->conf.timeout,
3524 sizeof(struct timeval));
3526 /* Copy the associated hosts */
3527 TAILQ_INIT(&tb->hosts);
3528 TAILQ_FOREACH(dsth, &dsttb->hosts, entry) {
3529 if ((h = (struct host *)
3530 calloc(1, sizeof (*h))) == NULL)
3531 fatal("out of memory");
3532 bcopy(dsth, h, sizeof(*h));
3533 h->conf.id = ++last_host_id;
3534 if (last_host_id == INT_MAX) {
3535 yyerror("too many hosts defined");
3536 free(h);
3537 goto fail;
3539 h->conf.tableid = tb->conf.id;
3540 h->tablename = tb->conf.name;
3541 SLIST_INIT(&h->children);
3542 TAILQ_INSERT_TAIL(&tb->hosts, h, entry);
3543 TAILQ_INSERT_TAIL(&conf->sc_hosts, h, globalentry);
3546 conf->sc_tablecount++;
3547 TAILQ_INSERT_TAIL(conf->sc_tables, tb, entry);
3549 return (tb);
3551 fail:
3552 purge_table(conf, NULL, tb);
3553 return (NULL);
3556 int
3557 relay_id(struct relay *rl)
3559 rl->rl_conf.id = ++last_relay_id;
3561 if (last_relay_id == INT_MAX)
3562 return (-1);
3564 return (0);
3567 struct relay *
3568 relay_inherit(struct relay *ra, struct relay *rb)
3570 struct relay_config rc;
3571 struct keyname *name;
3572 struct relay_table *rta, *rtb;
3574 bcopy(&rb->rl_conf, &rc, sizeof(rc));
3575 bcopy(ra, rb, sizeof(*rb));
3577 bcopy(&rc.ss, &rb->rl_conf.ss, sizeof(rb->rl_conf.ss));
3578 rb->rl_conf.port = rc.port;
3579 rb->rl_conf.flags =
3580 (ra->rl_conf.flags & ~F_TLS) | (rc.flags & F_TLS);
3581 if (!(rb->rl_conf.flags & F_TLS)) {
3582 rb->rl_tls_cacert_fd = -1;
3583 rb->rl_tls_ca_fd = -1;
3584 rb->rl_tls_client_ca_fd = -1;
3586 TAILQ_INIT(&rb->rl_tables);
3588 if (relay_id(rb) == -1) {
3589 yyerror("too many relays defined");
3590 goto err;
3593 if (snprintf(rb->rl_conf.name, sizeof(rb->rl_conf.name), "%s%u:%u",
3594 ra->rl_conf.name, rb->rl_conf.id, ntohs(rc.port)) >=
3595 (int)sizeof(rb->rl_conf.name)) {
3596 yyerror("invalid relay name");
3597 goto err;
3600 if (relay_findbyname(conf, rb->rl_conf.name) != NULL ||
3601 relay_findbyaddr(conf, &rb->rl_conf) != NULL) {
3602 yyerror("relay %s or listener defined twice",
3603 rb->rl_conf.name);
3604 goto err;
3607 if (TAILQ_EMPTY(&rb->rl_proto->tlscerts) &&
3608 relay_load_certfiles(conf, rb, NULL) == -1) {
3609 yyerror("cannot load certificates for relay %s",
3610 rb->rl_conf.name);
3611 goto err;
3613 TAILQ_FOREACH(name, &rb->rl_proto->tlscerts, entry) {
3614 if (relay_load_certfiles(conf, rb, name) == -1) {
3615 yyerror("cannot load keypair %s for relay %s",
3616 name->name, rb->rl_conf.name);
3617 goto err;
3621 TAILQ_FOREACH(rta, &ra->rl_tables, rlt_entry) {
3622 if ((rtb = calloc(1, sizeof(*rtb))) == NULL) {
3623 yyerror("cannot allocate relay table");
3624 goto err;
3626 rtb->rlt_table = rta->rlt_table;
3627 rtb->rlt_mode = rta->rlt_mode;
3628 rtb->rlt_flags = rta->rlt_flags;
3630 TAILQ_INSERT_TAIL(&rb->rl_tables, rtb, rlt_entry);
3633 conf->sc_relaycount++;
3634 SPLAY_INIT(&rlay->rl_sessions);
3635 TAILQ_INSERT_TAIL(conf->sc_relays, rb, rl_entry);
3637 return (rb);
3639 err:
3640 while ((rtb = TAILQ_FIRST(&rb->rl_tables))) {
3641 TAILQ_REMOVE(&rb->rl_tables, rtb, rlt_entry);
3642 free(rtb);
3644 free(rb);
3645 return (NULL);
3648 int
3649 getservice(char *n)
3651 struct servent *s;
3652 const char *errstr;
3653 long long llval;
3655 llval = strtonum(n, 0, UINT16_MAX, &errstr);
3656 if (errstr) {
3657 s = getservbyname(n, "tcp");
3658 if (s == NULL)
3659 s = getservbyname(n, "udp");
3660 if (s == NULL) {
3661 yyerror("unknown port %s", n);
3662 return (-1);
3664 return (s->s_port);
3667 return (htons((u_short)llval));
3670 int
3671 is_if_in_group(const char *ifname, const char *groupname)
3673 unsigned int len;
3674 struct ifgroupreq ifgr;
3675 struct ifg_req *ifg;
3676 int s;
3677 int ret = 0;
3679 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
3680 err(1, "socket");
3682 memset(&ifgr, 0, sizeof(ifgr));
3683 if (strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ) >= IFNAMSIZ)
3684 err(1, "IFNAMSIZ");
3685 if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) {
3686 if (errno == EINVAL || errno == ENOTTY)
3687 goto end;
3688 err(1, "SIOCGIFGROUP");
3691 len = ifgr.ifgr_len;
3692 ifgr.ifgr_groups = calloc(len / sizeof(struct ifg_req),
3693 sizeof(struct ifg_req));
3694 if (ifgr.ifgr_groups == NULL)
3695 err(1, "getifgroups");
3696 if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1)
3697 err(1, "SIOCGIFGROUP");
3699 ifg = ifgr.ifgr_groups;
3700 for (; ifg && len >= sizeof(struct ifg_req); ifg++) {
3701 len -= sizeof(struct ifg_req);
3702 if (strcmp(ifg->ifgrq_group, groupname) == 0) {
3703 ret = 1;
3704 break;
3707 free(ifgr.ifgr_groups);
3709 end:
3710 close(s);
3711 return (ret);
3714 struct keyname*
3715 proto_keyname(char *name)
3717 struct keyname *kname = NULL, *key;
3719 if (strlen(name) >= PATH_MAX) {
3720 yyerror("keypair name too long");
3721 return NULL;
3725 TAILQ_FOREACH(key, &proto->tlscerts, entry) {
3726 if (strcmp(key->name, name) == 0)
3727 return key;
3730 if ((kname = calloc(1, sizeof(*kname))) == NULL) {
3731 return NULL;
3734 if ((kname->name = strdup(name)) == NULL) {
3735 free(kname);
3736 return NULL;
3738 TAILQ_INSERT_TAIL(&proto->tlscerts, kname, entry);
3739 return kname;