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