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