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