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