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