parse.y revision 1.46
1/*	$OpenBSD: parse.y,v 1.46 2007/05/29 18:59:54 pyr Exp $	*/
2
3/*
4 * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org>
5 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
6 * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
7 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
8 * Copyright (c) 2001 Markus Friedl.  All rights reserved.
9 * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
10 * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
11 *
12 * Permission to use, copy, modify, and distribute this software for any
13 * purpose with or without fee is hereby granted, provided that the above
14 * copyright notice and this permission notice appear in all copies.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
17 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
19 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
21 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
22 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 */
24
25%{
26#include <sys/types.h>
27#include <sys/socket.h>
28#include <sys/queue.h>
29#include <netinet/in.h>
30#include <net/if.h>
31#include <arpa/inet.h>
32#include <arpa/nameser.h>
33
34#include <ctype.h>
35#include <err.h>
36#include <errno.h>
37#include <event.h>
38#include <limits.h>
39#include <stdint.h>
40#include <stdarg.h>
41#include <stdio.h>
42#include <netdb.h>
43#include <string.h>
44
45#include <openssl/ssl.h>
46
47#include "hoststated.h"
48
49struct hoststated		*conf = NULL;
50static FILE			*fin = NULL;
51static int			 lineno = 1;
52static int			 errors = 0;
53const char			*infile;
54objid_t				 last_service_id = 0;
55objid_t				 last_table_id = 0;
56objid_t				 last_host_id = 0;
57objid_t				 last_relay_id = 0;
58objid_t				 last_proto_id = 0;
59
60static struct service		*service = NULL;
61static struct table		*table = NULL;
62static struct relay		*rlay = NULL;
63static struct protocol		*proto = NULL;
64static struct protonode		 node;
65
66int	 yyerror(const char *, ...);
67int	 yyparse(void);
68int	 kw_cmp(const void *, const void *);
69int	 lookup(char *);
70int	 lgetc(FILE *, int *);
71int	 lungetc(int);
72int	 findeol(void);
73int	 yylex(void);
74
75TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
76struct sym {
77	TAILQ_ENTRY(sym)	 entries;
78	int			 used;
79	int			 persist;
80	char			*nam;
81	char			*val;
82};
83
84int		 symset(const char *, const char *, int);
85char		*symget(const char *);
86
87struct address	*host_v4(const char *);
88struct address	*host_v6(const char *);
89int		 host_dns(const char *, struct addresslist *,
90		    int, in_port_t, const char *);
91int		 host(const char *, struct addresslist *,
92		    int, in_port_t, const char *);
93
94struct table	*table_inherit(const char *, in_port_t);
95
96typedef struct {
97	union {
98		u_int32_t	 number;
99		char		*string;
100		struct host	*host;
101		struct timeval	 tv;
102	} v;
103	int lineno;
104} YYSTYPE;
105
106%}
107
108%token	SERVICE TABLE BACKUP HOST REAL
109%token  CHECK TCP ICMP EXTERNAL REQUEST RESPONSE
110%token  TIMEOUT CODE DIGEST PORT TAG INTERFACE
111%token	VIRTUAL INTERVAL DISABLE STICKYADDR BACKLOG PATH SCRIPT
112%token	SEND EXPECT NOTHING SSL LOADBALANCE ROUNDROBIN CIPHERS COOKIE
113%token	RELAY LISTEN ON FORWARD TO NAT LOOKUP PREFORK NO MARK MARKED
114%token	PROTO SESSION CACHE APPEND CHANGE REMOVE FROM FILTER HASH HEADER
115%token	LOG UPDATES ALL DEMOTE NODELAY SACK SOCKET BUFFER URL RETRY IP
116%token	ERROR
117%token	<v.string>	STRING
118%type	<v.string>	interface
119%type	<v.number>	number port http_type loglevel sslcache optssl dstport
120%type	<v.number>	proto_type dstmode docheck retry log flag direction
121%type	<v.host>	host
122%type	<v.tv>		timeout
123
124%%
125
126grammar		: /* empty */
127		| grammar '\n'
128		| grammar varset '\n'
129		| grammar main '\n'
130		| grammar service '\n'
131		| grammar table '\n'
132		| grammar relay '\n'
133		| grammar proto '\n'
134		| grammar error '\n'		{ errors++; }
135		;
136
137number		: STRING	{
138			const char	*estr;
139
140			$$ = strtonum($1, 0, UINT_MAX, &estr);
141			if (estr) {
142				yyerror("cannot parse number %s : %s",
143				    $1, estr);
144				free($1);
145				YYERROR;
146			}
147			free($1);
148		}
149		;
150
151optssl		: /*empty*/	{ $$ = 0; }
152		| SSL		{ $$ = 1; }
153		;
154
155http_type	: STRING	{
156			if (strcmp("https", $1) == 0) {
157				$$ = 1;
158			} else if (strcmp("http", $1) == 0) {
159				$$ = 0;
160			} else {
161				yyerror("invalid check type: $1", $1);
162				free($1);
163				YYERROR;
164			}
165			free($1);
166		}
167		;
168
169proto_type	: TCP				{ $$ = RELAY_PROTO_TCP; }
170		| STRING			{
171			if (strcmp("http", $1) == 0) {
172				$$ = RELAY_PROTO_HTTP;
173			} else {
174				yyerror("invalid protocol type: $1", $1);
175				free($1);
176				YYERROR;
177			}
178			free($1);
179		}
180		;
181
182port		: PORT STRING {
183			const char	*estr;
184			struct servent	*servent;
185
186			$$ = strtonum($2, 1, USHRT_MAX, &estr);
187                        if (estr) {
188				if (errno == ERANGE) {
189					yyerror("port %s is out of range", $2);
190					free($2);
191					YYERROR;
192				}
193				servent = getservbyname($2, "tcp");
194				if (servent == NULL) {
195					yyerror("port %s is invalid", $2);
196					free($2);
197					YYERROR;
198				}
199				$$ = servent->s_port;
200			} else
201				$$ = htons($$);
202			free($2);
203		}
204		;
205
206varset		: STRING '=' STRING	{
207			if (symset($1, $3, 0) == -1)
208				fatal("cannot store variable");
209			free($1);
210			free($3);
211		}
212		;
213
214sendbuf		: NOTHING		{
215			table->sendbuf = NULL;
216			table->sendbuf_len = 0;
217		}
218		| STRING		{
219			table->sendbuf = strdup($1);
220			if (table->sendbuf == NULL)
221				fatal("out of memory");
222			table->sendbuf_len = strlen(table->sendbuf);
223			free($1);
224		}
225		;
226
227main		: INTERVAL number	{ conf->interval.tv_sec = $2; }
228		| LOG loglevel		{ conf->opts |= $2; }
229		| TIMEOUT timeout	{
230			bcopy(&$2, &conf->timeout, sizeof(struct timeval));
231		}
232		| PREFORK number	{
233			if ($2 <= 0 || $2 > RELAY_MAXPROC) {
234				yyerror("invalid number of preforked "
235				    "relays: %d", $2);
236				YYERROR;
237			}
238			conf->prefork_relay = $2;
239		}
240		| DEMOTE STRING		{
241			conf->flags |= F_DEMOTE;
242			if (strlcpy(conf->demote_group, $2,
243			    sizeof(conf->demote_group))
244			    >= sizeof(conf->demote_group)) {
245				yyerror("yyparse: demote group name too long");
246				free($2);
247				YYERROR;
248			}
249			free($2);
250			if (carp_demote_init(conf->demote_group, 1) == -1) {
251				yyerror("yyparse: error initializing group '%s'",
252				    conf->demote_group);
253				YYERROR;
254			}
255		}
256		;
257
258loglevel	: UPDATES		{ $$ = HOSTSTATED_OPT_LOGUPDATE; }
259		| ALL			{ $$ = HOSTSTATED_OPT_LOGALL; }
260		;
261
262service		: SERVICE STRING	{
263			struct service *srv;
264
265			TAILQ_FOREACH(srv, &conf->services, entry)
266				if (!strcmp(srv->conf.name, $2))
267					break;
268			if (srv != NULL) {
269				yyerror("service %s defined twice", $2);
270				free($2);
271				YYERROR;
272			}
273			if ((srv = calloc(1, sizeof (*srv))) == NULL)
274				fatal("out of memory");
275
276			if (strlcpy(srv->conf.name, $2,
277			    sizeof(srv->conf.name)) >=
278			    sizeof(srv->conf.name)) {
279				yyerror("service name truncated");
280				YYERROR;
281			}
282			free($2);
283			srv->conf.id = last_service_id++;
284			if (last_service_id == INT_MAX) {
285				yyerror("too many services defined");
286				YYERROR;
287			}
288			service = srv;
289		} '{' optnl serviceopts_l '}'	{
290			if (service->table == NULL) {
291				yyerror("service %s has no table",
292				    service->conf.name);
293				YYERROR;
294			}
295			if (TAILQ_EMPTY(&service->virts)) {
296				yyerror("service %s has no virtual ip",
297				    service->conf.name);
298				YYERROR;
299			}
300			conf->servicecount++;
301			if (service->backup == NULL) {
302				service->conf.backup_id =
303				    conf->empty_table.conf.id;
304				service->backup = &conf->empty_table;
305			} else if (service->backup->conf.port !=
306			    service->table->conf.port) {
307				yyerror("service %s uses two different ports "
308				    "for its table and backup table",
309				    service->conf.name);
310				YYERROR;
311			}
312
313			if (!(service->conf.flags & F_DISABLE))
314				service->conf.flags |= F_ADD;
315			TAILQ_INSERT_HEAD(&conf->services, service, entry);
316		}
317		;
318
319serviceopts_l	: serviceopts_l serviceoptsl nl
320		| serviceoptsl optnl
321		;
322
323serviceoptsl	: TABLE STRING dstport	{
324			struct table	*tb;
325			in_port_t	 port;
326
327			port = $3;
328			if (port == 0)
329				port = service->conf.port;
330			if ((tb = table_inherit($2, port)) == NULL) {
331				free($2);
332				YYERROR;
333			}
334			free($2);
335
336			service->table = tb;
337			service->table->conf.serviceid = service->conf.id;
338			service->table->conf.flags |= F_USED;
339		}
340		| BACKUP TABLE STRING dstport	{
341			struct table	*tb;
342			in_port_t	 port;
343
344			if (service->backup) {
345				yyerror("backup already specified");
346				free($3);
347				YYERROR;
348			}
349
350			port = $4;
351			if (port == 0)
352				port = service->conf.port;
353			if ((tb = table_inherit($3, port)) == NULL) {
354				free($3);
355				YYERROR;
356			}
357			free($3);
358
359			service->backup = tb;
360			service->backup->conf.serviceid = service->conf.id;
361			service->backup->conf.flags |= (F_USED|F_BACKUP);
362		}
363		| VIRTUAL HOST STRING port interface {
364			if (host($3, &service->virts,
365				 SRV_MAX_VIRTS, $4, $5) <= 0) {
366				yyerror("invalid virtual ip: %s", $3);
367				free($3);
368				free($5);
369				YYERROR;
370			}
371			free($3);
372			free($5);
373			if (service->conf.port == 0)
374				service->conf.port = $4;
375		}
376		| DISABLE		{ service->conf.flags |= F_DISABLE; }
377		| STICKYADDR		{ service->conf.flags |= F_STICKY; }
378		| TAG STRING {
379			if (strlcpy(service->conf.tag, $2,
380			    sizeof(service->conf.tag)) >=
381			    sizeof(service->conf.tag)) {
382				yyerror("service tag name truncated");
383				free($2);
384				YYERROR;
385			}
386			free($2);
387		}
388		;
389
390table		: TABLE STRING	{
391			struct table *tb;
392
393			TAILQ_FOREACH(tb, &conf->tables, entry)
394				if (!strcmp(tb->conf.name, $2))
395					break;
396			if (tb != NULL) {
397				yyerror("table %s defined twice");
398				free($2);
399				YYERROR;
400			}
401
402			if ((tb = calloc(1, sizeof (*tb))) == NULL)
403				fatal("out of memory");
404
405			if (strlcpy(tb->conf.name, $2, sizeof(tb->conf.name)) >=
406			    sizeof(tb->conf.name)) {
407				yyerror("table name truncated");
408				YYERROR;
409			}
410			tb->conf.id = last_table_id++;
411			bcopy(&conf->timeout, &tb->conf.timeout,
412			    sizeof(struct timeval));
413			if (last_table_id == INT_MAX) {
414				yyerror("too many tables defined");
415				YYERROR;
416			}
417			free($2);
418			table = tb;
419		} '{' optnl tableopts_l '}'	{
420			if (TAILQ_EMPTY(&table->hosts)) {
421				yyerror("table %s has no hosts",
422				    table->conf.name);
423				YYERROR;
424			}
425			if (table->conf.check == CHECK_NOCHECK) {
426				yyerror("table %s has no check",
427				    table->conf.name);
428				YYERROR;
429			}
430			conf->tablecount++;
431			TAILQ_INSERT_HEAD(&conf->tables, table, entry);
432		}
433		;
434
435tableopts_l	: tableopts_l tableoptsl nl
436		| tableoptsl optnl
437		;
438
439tableoptsl	: host			{
440			$1->conf.tableid = table->conf.id;
441			$1->tablename = table->conf.name;
442			TAILQ_INSERT_HEAD(&table->hosts, $1, entry);
443		}
444		| TIMEOUT timeout	{
445			bcopy(&$2, &table->conf.timeout,
446			    sizeof(struct timeval));
447		}
448		| CHECK ICMP		{
449			table->conf.check = CHECK_ICMP;
450		}
451		| CHECK TCP		{
452			table->conf.check = CHECK_TCP;
453		}
454		| CHECK SSL		{
455			table->conf.check = CHECK_TCP;
456			conf->flags |= F_SSL;
457			table->conf.flags |= F_SSL;
458		}
459		| CHECK http_type STRING CODE number {
460			if ($2) {
461				conf->flags |= F_SSL;
462				table->conf.flags |= F_SSL;
463			}
464			table->conf.check = CHECK_HTTP_CODE;
465			table->conf.retcode = $5;
466			if (asprintf(&table->sendbuf,
467			    "HEAD %s HTTP/1.0\r\n\r\n", $3) == -1)
468				fatal("asprintf");
469			free($3);
470			if (table->sendbuf == NULL)
471				fatal("out of memory");
472			table->sendbuf_len = strlen(table->sendbuf);
473		}
474		| CHECK http_type STRING DIGEST STRING {
475			if ($2) {
476				conf->flags |= F_SSL;
477				table->conf.flags |= F_SSL;
478			}
479			table->conf.check = CHECK_HTTP_DIGEST;
480			if (asprintf(&table->sendbuf,
481			    "GET %s HTTP/1.0\r\n\r\n", $3) == -1)
482				fatal("asprintf");
483			free($3);
484			if (table->sendbuf == NULL)
485				fatal("out of memory");
486			table->sendbuf_len = strlen(table->sendbuf);
487			if (strlcpy(table->conf.digest, $5,
488			    sizeof(table->conf.digest)) >=
489			    sizeof(table->conf.digest)) {
490				yyerror("http digest truncated");
491				free($5);
492				YYERROR;
493			}
494			free($5);
495		}
496		| CHECK SEND sendbuf EXPECT STRING optssl {
497			table->conf.check = CHECK_SEND_EXPECT;
498			if ($6) {
499				conf->flags |= F_SSL;
500				table->conf.flags |= F_SSL;
501			}
502			if (strlcpy(table->conf.exbuf, $5,
503			    sizeof(table->conf.exbuf))
504			    >= sizeof(table->conf.exbuf)) {
505				yyerror("yyparse: expect buffer truncated");
506				free($5);
507				YYERROR;
508			}
509			free($5);
510		}
511		| CHECK SCRIPT STRING {
512			table->conf.check = CHECK_SCRIPT;
513			if (strlcpy(table->conf.path, $3,
514			    sizeof(table->conf.path)) >=
515			    sizeof(table->conf.path)) {
516				yyerror("script path truncated");
517				free($3);
518				YYERROR;
519			}
520			free($3);
521		}
522		| REAL port {
523			table->conf.port = $2;
524		}
525		| DEMOTE STRING	{
526			table->conf.flags |= F_DEMOTE;
527			if (strlcpy(table->conf.demote_group, $2,
528			    sizeof(table->conf.demote_group))
529			    >= sizeof(table->conf.demote_group)) {
530				yyerror("yyparse: demote group name too long");
531				free($2);
532				YYERROR;
533			}
534			free($2);
535			if (carp_demote_init(table->conf.demote_group, 1)
536			    == -1) {
537				yyerror("yyparse: error initializing group "
538				    "'%s'", table->conf.demote_group);
539				YYERROR;
540			}
541		}
542		| DISABLE			{
543			table->conf.flags |= F_DISABLE;
544		}
545		;
546
547proto		: PROTO STRING	{
548			struct protocol *p;
549
550			TAILQ_FOREACH(p, &conf->protos, entry)
551				if (!strcmp(p->name, $2))
552					break;
553			if (p != NULL) {
554				yyerror("protocol %s defined twice", $2);
555				free($2);
556				YYERROR;
557			}
558			if ((p = calloc(1, sizeof (*p))) == NULL)
559				fatal("out of memory");
560
561			if (strlcpy(p->name, $2, sizeof(p->name)) >=
562			    sizeof(p->name)) {
563				yyerror("protocol name truncated");
564				YYERROR;
565			}
566			free($2);
567			p->id = last_proto_id++;
568			p->cache = RELAY_CACHESIZE;
569			p->type = RELAY_PROTO_TCP;
570			p->tcpflags = TCPFLAG_DEFAULT;
571			p->sslflags = SSLFLAG_DEFAULT;
572			p->tcpbacklog = RELAY_BACKLOG;
573			(void)strlcpy(p->sslciphers, SSLCIPHERS_DEFAULT,
574			    sizeof(p->sslciphers));
575			if (last_proto_id == INT_MAX) {
576				yyerror("too many protocols defined");
577				YYERROR;
578			}
579			RB_INIT(&p->request_tree);
580			RB_INIT(&p->response_tree);
581			proto = p;
582		} '{' optnl protopts_l '}'	{
583			conf->protocount++;
584
585			if ((proto->sslflags & SSLFLAG_VERSION) == 0) {
586				yyerror("invalid SSL protocol");
587				YYERROR;
588			}
589
590			TAILQ_INSERT_HEAD(&conf->protos, proto, entry);
591		}
592		;
593
594protopts_l	: protopts_l protoptsl nl
595		| protoptsl optnl
596		;
597
598protoptsl	: SSL sslflags
599		| SSL '{' sslflags_l '}'
600		| TCP tcpflags
601		| TCP '{' tcpflags_l '}'
602		| PROTO proto_type		{ proto->type = $2; }
603		| direction protonode log	{
604			struct protonode 	*pn, pk;
605			struct proto_tree	*tree;
606
607			if ($1 == RELAY_DIR_RESPONSE)
608				tree = &proto->response_tree;
609			else
610				tree = &proto->request_tree;
611			pn = RB_FIND(proto_tree, tree, &node);
612			if (pn != NULL) {
613				yyerror("protocol node %s defined twice",
614				    node.key);
615				YYERROR;
616			}
617			if ((pn = calloc(1, sizeof (*pn))) == NULL)
618				fatal("out of memory");
619
620			bcopy(&node, pn, sizeof(*pn));
621			pn->key = node.key;
622			pn->value = node.value;
623			pn->type = node.type;
624			if ($1 == RELAY_DIR_RESPONSE)
625				pn->id = proto->response_nodes++;
626			else
627				pn->id = proto->request_nodes++;
628			if ($3)
629				pn->flags |= PNFLAG_LOG;
630			if (pn->id == INT_MAX) {
631				yyerror("too many protocol nodes defined");
632				YYERROR;
633			}
634			RB_INSERT(proto_tree, tree, pn);
635
636			if (node.type == NODE_TYPE_COOKIE)
637				pk.key = "Cookie";
638			else
639				pk.key = "GET";
640			if (node.type != NODE_TYPE_HEADER) {
641				pk.type = NODE_TYPE_HEADER;
642				pn = RB_FIND(proto_tree, tree, &pk);
643				if (pn == NULL) {
644					if ((pn = (struct protonode *)
645					    calloc(1, sizeof(*pn))) == NULL)
646						fatal("out of memory");
647					pn->key = strdup(pk.key);
648					if (pn->key == NULL)
649						fatal("out of memory");
650					pn->value = NULL;
651					pn->action = NODE_ACTION_NONE;
652					pn->type = pk.type;
653					if ($1 == RELAY_DIR_RESPONSE)
654						pn->id =
655						    proto->response_nodes++;
656					else
657						pn->id = proto->request_nodes++;
658					if (pn->id == INT_MAX) {
659						yyerror("too many protocol "
660						    "nodes defined");
661						YYERROR;
662					}
663					RB_INSERT(proto_tree, tree, pn);
664				}
665				switch (node.type) {
666				case NODE_TYPE_URL:
667					pn->flags |= PNFLAG_LOOKUP_URL;
668					break;
669				case NODE_TYPE_COOKIE:
670					pn->flags |= PNFLAG_LOOKUP_COOKIE;
671					break;
672				default:
673					break;
674				}
675			}
676
677			bzero(&node, sizeof(node));
678		}
679		;
680
681direction	: /* empty */		{ $$ = RELAY_DIR_REQUEST; }
682		| REQUEST		{ $$ = RELAY_DIR_REQUEST; }
683		| RESPONSE		{ $$ = RELAY_DIR_RESPONSE; }
684		;
685
686tcpflags_l	: tcpflags comma tcpflags_l
687		| tcpflags
688		;
689
690tcpflags	: SACK 			{ proto->tcpflags |= TCPFLAG_SACK; }
691		| NO SACK		{ proto->tcpflags |= TCPFLAG_NSACK; }
692		| NODELAY		{ proto->tcpflags |= TCPFLAG_NODELAY; }
693		| NO NODELAY		{ proto->tcpflags |= TCPFLAG_NNODELAY; }
694		| BACKLOG number	{
695			if ($2 > RELAY_MAX_SESSIONS) {
696				yyerror("invalid backlog: %d", $2);
697				YYERROR;
698			}
699			proto->tcpbacklog = $2;
700		}
701		| SOCKET BUFFER number	{
702			proto->tcpflags |= TCPFLAG_BUFSIZ;
703			proto->tcpbufsiz = $3;
704		}
705		| IP STRING number	{
706			if (strcasecmp("ttl", $2) == 0) {
707				proto->tcpflags |= TCPFLAG_IPTTL;
708				proto->tcpipttl = $3;
709			} else if (strcasecmp("minttl", $2) == 0) {
710				proto->tcpflags |= TCPFLAG_IPMINTTL;
711				proto->tcpipminttl = $3;
712			} else {
713				yyerror("invalid TCP/IP flag: %s", $2);
714				free($2);
715				YYERROR;
716			}
717			free($2);
718		}
719		;
720
721sslflags_l	: sslflags comma sslflags_l
722		| sslflags
723		;
724
725sslflags	: SESSION CACHE sslcache	{ proto->cache = $3; }
726		| CIPHERS STRING		{
727			if (strlcpy(proto->sslciphers, $2,
728			    sizeof(proto->sslciphers)) >=
729			    sizeof(proto->sslciphers)) {
730				yyerror("sslciphers truncated");
731				free($2);
732				YYERROR;
733			}
734			free($2);
735		}
736		| NO flag			{ proto->sslflags &= ~($2); }
737		| flag				{ proto->sslflags |= $1; }
738		;
739
740flag		: STRING			{
741			if (strcmp("sslv2", $1) == 0)
742				$$ = SSLFLAG_SSLV2;
743			else if (strcmp("sslv3", $1) == 0)
744				$$ = SSLFLAG_SSLV3;
745			else if (strcmp("tlsv1", $1) == 0)
746				$$ = SSLFLAG_TLSV1;
747			else {
748				yyerror("invalid SSL flag: %s", $1);
749				free($1);
750				YYERROR;
751			}
752			free($1);
753		}
754		;
755
756protonode	: nodetype APPEND STRING TO STRING marked	{
757			node.action = NODE_ACTION_APPEND;
758			node.key = strdup($5);
759			node.value = strdup($3);
760			if (node.key == NULL || node.value == NULL)
761				fatal("out of memory");
762			if (strchr(node.value, '$') != NULL)
763				node.flags |= PNFLAG_MACRO;
764			free($5);
765			free($3);
766		}
767		| nodetype CHANGE STRING TO STRING marked {
768			node.action = NODE_ACTION_CHANGE;
769			node.key = strdup($3);
770			node.value = strdup($5);
771			if (node.key == NULL || node.value == NULL)
772				fatal("out of memory");
773			if (strchr(node.value, '$') != NULL)
774				node.flags |= PNFLAG_MACRO;
775			free($5);
776			free($3);
777		}
778		| nodetype REMOVE STRING marked	{
779			node.action = NODE_ACTION_REMOVE;
780			node.key = strdup($3);
781			node.value = NULL;
782			if (node.key == NULL)
783				fatal("out of memory");
784			free($3);
785		}
786		| nodetype EXPECT STRING FROM STRING mark	{
787			node.action = NODE_ACTION_EXPECT;
788			node.key = strdup($5);
789			node.value = strdup($3);;
790			if (node.key == NULL || node.value == NULL)
791				fatal("out of memory");
792			free($5);
793			free($3);
794		}
795		| nodetype FILTER STRING FROM STRING mark	{
796			node.action = NODE_ACTION_FILTER;
797			node.key = strdup($5);
798			node.value = strdup($3);;
799			if (node.key == NULL || node.value == NULL)
800				fatal("out of memory");
801			free($5);
802			free($3);
803		}
804		| nodetype HASH STRING marked			{
805			node.action = NODE_ACTION_HASH;
806			node.key = strdup($3);
807			node.value = NULL;
808			if (node.key == NULL)
809				fatal("out of memory");
810			free($3);
811			proto->lateconnect++;
812		}
813		| nodetype LOG STRING marked			{
814			node.action = NODE_ACTION_LOG;
815			node.key = strdup($3);
816			node.value = NULL;
817			node.flags |= PNFLAG_LOG;
818			if (node.key == NULL)
819				fatal("out of memory");
820			free($3);
821		}
822		;
823
824mark		: /* empty */
825		| MARK				{ node.flags |= PNFLAG_MARK; }
826		;
827
828marked		: /* empty */
829		| MARKED			{ node.flags |= PNFLAG_MARK; }
830		;
831
832nodetype	: HEADER			{ node.type = NODE_TYPE_HEADER; }
833		| URL				{ node.type = NODE_TYPE_URL; }
834		| COOKIE			{ node.type = NODE_TYPE_COOKIE; }
835		| PATH				{
836				proto->flags |= F_LOOKUP_PATH;
837				node.type = NODE_TYPE_PATH;
838		}
839		;
840
841sslcache	: number			{ $$ = $1; }
842		| DISABLE			{ $$ = -2; }
843		;
844
845relay		: RELAY STRING	{
846			struct relay *r;
847
848			TAILQ_FOREACH(r, &conf->relays, entry)
849				if (!strcmp(r->conf.name, $2))
850					break;
851			if (r != NULL) {
852				yyerror("relay %s defined twice", $2);
853				free($2);
854				YYERROR;
855			}
856			if ((r = calloc(1, sizeof (*r))) == NULL)
857				fatal("out of memory");
858
859			if (strlcpy(r->conf.name, $2, sizeof(r->conf.name)) >=
860			    sizeof(r->conf.name)) {
861				yyerror("relay name truncated");
862				YYERROR;
863			}
864			free($2);
865			r->conf.id = last_relay_id++;
866			r->conf.timeout.tv_sec = RELAY_TIMEOUT;
867			r->proto = NULL;
868			r->conf.proto = EMPTY_ID;
869			r->conf.dsttable = EMPTY_ID;
870			r->conf.dstretry = 0;
871			if (last_relay_id == INT_MAX) {
872				yyerror("too many relays defined");
873				YYERROR;
874			}
875			rlay = r;
876		} '{' optnl relayopts_l '}'	{
877			if (rlay->conf.ss.ss_family == AF_UNSPEC) {
878				yyerror("relay %s has no listener",
879				    rlay->conf.name);
880				YYERROR;
881			}
882			if ((rlay->conf.flags & F_NATLOOK) == 0 &&
883			    rlay->conf.dstss.ss_family == AF_UNSPEC &&
884			    rlay->conf.dsttable == EMPTY_ID) {
885				yyerror("relay %s has no target, service, "
886				    "or table", rlay->conf.name);
887				YYERROR;
888			}
889			if (rlay->conf.proto == EMPTY_ID) {
890				rlay->proto = &conf->proto_default;
891				rlay->conf.proto = conf->proto_default.id;
892			}
893			conf->relaycount++;
894			TAILQ_INIT(&rlay->sessions);
895			TAILQ_INSERT_HEAD(&conf->relays, rlay, entry);
896		}
897		;
898
899relayopts_l	: relayopts_l relayoptsl nl
900		| relayoptsl optnl
901		;
902
903relayoptsl	: LISTEN ON STRING port optssl {
904			struct addresslist 	 al;
905			struct address		*h;
906
907			if (rlay->conf.ss.ss_family != AF_UNSPEC) {
908				yyerror("relay %s listener already specified",
909				    rlay->conf.name);
910				YYERROR;
911			}
912
913			TAILQ_INIT(&al);
914			if (host($3, &al, 1, $4, NULL) <= 0) {
915				yyerror("invalid listen ip: %s", $3);
916				free($3);
917				YYERROR;
918			}
919			free($3);
920			h = TAILQ_FIRST(&al);
921			bcopy(&h->ss, &rlay->conf.ss, sizeof(rlay->conf.ss));
922			rlay->conf.port = h->port;
923			if ($5) {
924				rlay->conf.flags |= F_SSL;
925				conf->flags |= F_SSL;
926			}
927		}
928		| FORWARD TO STRING port retry {
929			struct addresslist 	 al;
930			struct address		*h;
931
932			if (rlay->conf.dstss.ss_family != AF_UNSPEC) {
933				yyerror("relay %s target or service already "
934				    "specified", rlay->conf.name);
935				free($3);
936				YYERROR;
937			}
938
939			TAILQ_INIT(&al);
940			if (host($3, &al, 1, $4, NULL) <= 0) {
941				yyerror("invalid listen ip: %s", $3);
942				free($3);
943				YYERROR;
944			}
945			free($3);
946			h = TAILQ_FIRST(&al);
947			bcopy(&h->ss, &rlay->conf.dstss,
948			    sizeof(rlay->conf.dstss));
949			rlay->conf.dstport = h->port;
950			rlay->conf.dstretry = $5;
951		}
952		| SERVICE STRING retry {
953			struct service	*svc;
954			struct address	*h;
955
956			if (rlay->conf.dstss.ss_family != AF_UNSPEC) {
957				yyerror("relay %s target or service already "
958				    "specified", rlay->conf.name);
959				free($2);
960				YYERROR;
961			}
962
963			if ((svc = service_findbyname(conf, $2)) == NULL) {
964				yyerror("relay %s for unknown service %s",
965				    rlay->conf.name, $2);
966				free($2);
967				YYERROR;
968			}
969			free($2);
970			h = TAILQ_FIRST(&svc->virts);
971			bcopy(&h->ss, &rlay->conf.dstss,
972			    sizeof(rlay->conf.dstss));
973			rlay->conf.dstport = h->port;
974			rlay->conf.dstretry = $3;
975		}
976		| TABLE STRING dstport dstmode docheck {
977			struct table	*tb;
978
979			rlay->conf.dstport = $3;
980			if (rlay->conf.dstport == 0)
981				rlay->conf.dstport = rlay->conf.port;
982
983			if ((tb = table_inherit($2, rlay->conf.dstport)) ==
984			    NULL) {
985				free($2);
986				YYERROR;
987			}
988			free($2);
989			rlay->conf.dsttable = tb->conf.id;
990			rlay->dsttable = tb;
991			rlay->conf.dstmode = $4;
992			rlay->conf.dstcheck = $5;
993			rlay->dsttable->conf.flags |= F_USED;
994		}
995		| PROTO STRING {
996			struct protocol *p;
997
998			TAILQ_FOREACH(p, &conf->protos, entry)
999				if (!strcmp(p->name, $2))
1000					break;
1001			if (p == NULL) {
1002				yyerror("no such protocol: %s", $2);
1003				free($2);
1004				YYERROR;
1005			}
1006			p->flags |= F_USED;
1007			rlay->conf.proto = p->id;
1008			rlay->proto = p;
1009			free($2);
1010		}
1011		| NAT LOOKUP retry	{
1012			rlay->conf.flags |= F_NATLOOK;
1013			rlay->conf.dstretry = $3;
1014		}
1015		| TIMEOUT number	{ rlay->conf.timeout.tv_sec = $2; }
1016		| DISABLE		{ rlay->conf.flags |= F_DISABLE; }
1017		;
1018
1019dstmode		: /* empty */		{ $$ = RELAY_DSTMODE_DEFAULT; }
1020		| LOADBALANCE		{ $$ = RELAY_DSTMODE_LOADBALANCE; }
1021		| ROUNDROBIN		{ $$ = RELAY_DSTMODE_ROUNDROBIN; }
1022		| HASH			{ $$ = RELAY_DSTMODE_HASH; }
1023		;
1024
1025docheck		: /* empty */		{ $$ = 1; }
1026		| NO CHECK		{ $$ = 0; }
1027		;
1028
1029interface	: /*empty*/		{ $$ = NULL; }
1030		| INTERFACE STRING	{ $$ = $2; }
1031		;
1032
1033dstport		: /* empty */		{ $$ = 0; }
1034		| port			{ $$ = $1; }
1035		;
1036
1037host		: HOST STRING retry {
1038			struct address *a;
1039			struct addresslist al;
1040
1041			if (($$ = calloc(1, sizeof(*($$)))) == NULL)
1042				fatal("out of memory");
1043
1044			TAILQ_INIT(&al);
1045			if (host($2, &al, 1, 0, NULL) <= 0) {
1046				yyerror("invalid host %s", $2);
1047				free($2);
1048				free($$);
1049				YYERROR;
1050			}
1051			a = TAILQ_FIRST(&al);
1052			memcpy(&$$->conf.ss, &a->ss, sizeof($$->conf.ss));
1053			free(a);
1054
1055			if (strlcpy($$->conf.name, $2, sizeof($$->conf.name)) >=
1056			    sizeof($$->conf.name)) {
1057				yyerror("host name truncated");
1058				free($2);
1059				free($$);
1060				YYERROR;
1061			}
1062			free($2);
1063			$$->conf.id = last_host_id++;
1064			$$->conf.retry = $3;
1065			if (last_host_id == INT_MAX) {
1066				yyerror("too many hosts defined");
1067				free($$);
1068				YYERROR;
1069			}
1070		}
1071		;
1072
1073retry		: /* nothing */		{ $$ = 0; }
1074		| RETRY number		{ $$ = $2; }
1075		;
1076
1077timeout		: number
1078		{
1079			$$.tv_sec = $1 / 1000;
1080			$$.tv_usec = ($1 % 1000) * 1000;
1081		}
1082		;
1083
1084log		: /* empty */		{ $$ = 0; }
1085		| LOG			{ $$ = 1; }
1086		;
1087
1088comma		: ','
1089		| /* empty */
1090		;
1091
1092optnl		: '\n' optnl
1093		|
1094		;
1095
1096nl		: '\n' optnl
1097		;
1098
1099%%
1100
1101struct keywords {
1102	const char	*k_name;
1103	int		 k_val;
1104};
1105
1106int
1107yyerror(const char *fmt, ...)
1108{
1109	va_list	ap;
1110
1111	errors = 1;
1112	va_start(ap, fmt);
1113	fprintf(stderr, "%s:%d: ", infile, yylval.lineno);
1114	vfprintf(stderr, fmt, ap);
1115	fprintf(stderr, "\n");
1116	va_end(ap);
1117	return (0);
1118}
1119
1120int
1121kw_cmp(const void *k, const void *e)
1122{
1123
1124	return (strcmp(k, ((const struct keywords *)e)->k_name));
1125}
1126
1127int
1128lookup(char *s)
1129{
1130	/* this has to be sorted always */
1131	static const struct keywords keywords[] = {
1132		{ "all",		ALL },
1133		{ "append",		APPEND },
1134		{ "backlog",		BACKLOG },
1135		{ "backup",		BACKUP },
1136		{ "buffer",		BUFFER },
1137		{ "cache",		CACHE },
1138		{ "change",		CHANGE },
1139		{ "check",		CHECK },
1140		{ "ciphers",		CIPHERS },
1141		{ "code",		CODE },
1142		{ "cookie",		COOKIE },
1143		{ "demote",		DEMOTE },
1144		{ "digest",		DIGEST },
1145		{ "disable",		DISABLE },
1146		{ "expect",		EXPECT },
1147		{ "external",		EXTERNAL },
1148		{ "filter",		FILTER },
1149		{ "forward",		FORWARD },
1150		{ "from",		FROM },
1151		{ "hash",		HASH },
1152		{ "header",		HEADER },
1153		{ "host",		HOST },
1154		{ "icmp",		ICMP },
1155		{ "interface",		INTERFACE },
1156		{ "interval",		INTERVAL },
1157		{ "ip",			IP },
1158		{ "listen",		LISTEN },
1159		{ "loadbalance",	LOADBALANCE },
1160		{ "log",		LOG },
1161		{ "lookup",		LOOKUP },
1162		{ "mark",		MARK },
1163		{ "marked",		MARKED },
1164		{ "nat",		NAT },
1165		{ "no",			NO },
1166		{ "nodelay",		NODELAY },
1167		{ "nothing",		NOTHING },
1168		{ "on",			ON },
1169		{ "path",		PATH },
1170		{ "port",		PORT },
1171		{ "prefork",		PREFORK },
1172		{ "protocol",		PROTO },
1173		{ "real",		REAL },
1174		{ "relay",		RELAY },
1175		{ "remove",		REMOVE },
1176		{ "request",		REQUEST },
1177		{ "response",		RESPONSE },
1178		{ "retry",		RETRY },
1179		{ "roundrobin",		ROUNDROBIN },
1180		{ "sack",		SACK },
1181		{ "script",		SCRIPT },
1182		{ "send",		SEND },
1183		{ "service",		SERVICE },
1184		{ "session",		SESSION },
1185		{ "socket",		SOCKET },
1186		{ "ssl",		SSL },
1187		{ "sticky-address",	STICKYADDR },
1188		{ "table",		TABLE },
1189		{ "tag",		TAG },
1190		{ "tcp",		TCP },
1191		{ "timeout",		TIMEOUT },
1192		{ "to",			TO },
1193		{ "updates",		UPDATES },
1194		{ "url",		URL },
1195		{ "virtual",		VIRTUAL }
1196	};
1197	const struct keywords	*p;
1198
1199	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
1200	    sizeof(keywords[0]), kw_cmp);
1201
1202	if (p)
1203		return (p->k_val);
1204	else
1205		return (STRING);
1206}
1207
1208#define MAXPUSHBACK	128
1209
1210char	*parsebuf;
1211int	 parseindex;
1212char	 pushback_buffer[MAXPUSHBACK];
1213int	 pushback_index = 0;
1214
1215int
1216lgetc(FILE *f, int *keep)
1217{
1218	int	c, next;
1219
1220	*keep = 0;
1221	if (parsebuf) {
1222		/* Read character from the parsebuffer instead of input. */
1223		if (parseindex >= 0) {
1224			c = parsebuf[parseindex++];
1225			if (c != '\0')
1226				return (c);
1227			parsebuf = NULL;
1228		} else
1229			parseindex++;
1230	}
1231
1232	if (pushback_index)
1233		return (pushback_buffer[--pushback_index]);
1234
1235	while ((c = getc(f)) == '\\') {
1236		next = getc(f);
1237		if (next == 'n') {
1238			*keep = 1;
1239			c = '\n';
1240			break;
1241		} else if (next == 'r') {
1242			*keep = 1;
1243			c = '\r';
1244			break;
1245		} else if (next != '\n') {
1246			c = next;
1247			break;
1248		}
1249		yylval.lineno = lineno;
1250		lineno++;
1251	}
1252	if (c == '\t' || c == ' ') {
1253		/* Compress blanks to a single space. */
1254		do {
1255			c = getc(f);
1256		} while (c == '\t' || c == ' ');
1257		ungetc(c, f);
1258		c = ' ';
1259	}
1260
1261	return (c);
1262}
1263
1264int
1265lungetc(int c)
1266{
1267	if (c == EOF)
1268		return (EOF);
1269	if (parsebuf) {
1270		parseindex--;
1271		if (parseindex >= 0)
1272			return (c);
1273	}
1274	if (pushback_index < MAXPUSHBACK-1)
1275		return (pushback_buffer[pushback_index++] = c);
1276	else
1277		return (EOF);
1278}
1279
1280int
1281findeol(void)
1282{
1283	int	c;
1284	int	k;
1285
1286	parsebuf = NULL;
1287	pushback_index = 0;
1288
1289	/* skip to either EOF or the first real EOL */
1290	while (1) {
1291		c = lgetc(fin, &k);
1292		if (c == '\n' && k == 0) {
1293			lineno++;
1294			break;
1295		}
1296		if (c == EOF)
1297			break;
1298	}
1299	return (ERROR);
1300}
1301
1302int
1303yylex(void)
1304{
1305	char	 buf[8096];
1306	char	*p, *val;
1307	int	 endc, c;
1308	int	 token;
1309	int	 keep;
1310
1311top:
1312	p = buf;
1313	while ((c = lgetc(fin, &keep)) == ' ')
1314		; /* nothing */
1315
1316	yylval.lineno = lineno;
1317	if (c == '#')
1318		do {
1319			while ((c = lgetc(fin, &keep)) != '\n' && c != EOF)
1320				; /* nothing */
1321		} while (keep == 1);
1322	if (c == '$' && parsebuf == NULL) {
1323		while (1) {
1324			if ((c = lgetc(fin, &keep)) == EOF)
1325				return (0);
1326
1327			if (p + 1 >= buf + sizeof(buf) - 1) {
1328				yyerror("string too long");
1329				return (findeol());
1330			}
1331			if (isalnum(c) || c == '_') {
1332				*p++ = (char)c;
1333				continue;
1334			}
1335			*p = '\0';
1336			lungetc(c);
1337			break;
1338		}
1339		val = symget(buf);
1340		if (val == NULL) {
1341			yyerror("macro '%s' not defined", buf);
1342			return (findeol());
1343		}
1344		parsebuf = val;
1345		parseindex = 0;
1346		goto top;
1347	}
1348
1349	switch (c) {
1350	case '\'':
1351	case '"':
1352		endc = c;
1353		while (1) {
1354			if ((c = lgetc(fin, &keep)) == EOF)
1355				return (0);
1356			if (c == endc) {
1357				*p = '\0';
1358				break;
1359			}
1360			if (c == '\n' && keep == 0) {
1361				lineno++;
1362				continue;
1363			}
1364			if (p + 1 >= buf + sizeof(buf) - 1) {
1365				yyerror("string too long");
1366				return (findeol());
1367			}
1368			*p++ = (char)c;
1369		}
1370		yylval.v.string = strdup(buf);
1371		if (yylval.v.string == NULL)
1372			errx(1, "yylex: strdup");
1373		return (STRING);
1374	}
1375
1376#define allowed_in_string(x) \
1377	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
1378	x != '{' && x != '}' && \
1379	x != '!' && x != '=' && x != '#' && \
1380	x != ','))
1381
1382	if (isalnum(c) || c == ':' || c == '_') {
1383		do {
1384			*p++ = c;
1385			if ((unsigned)(p-buf) >= sizeof(buf)) {
1386				yyerror("string too long");
1387				return (findeol());
1388			}
1389		} while ((c = lgetc(fin, &keep)) != EOF &&
1390		    (allowed_in_string(c)));
1391		lungetc(c);
1392		*p = '\0';
1393		if ((token = lookup(buf)) == STRING)
1394			if ((yylval.v.string = strdup(buf)) == NULL)
1395				err(1, "yylex: strdup");
1396		return (token);
1397	}
1398	if (c == '\n') {
1399		yylval.lineno = lineno;
1400		lineno++;
1401	}
1402	if (c == EOF)
1403		return (0);
1404	return (c);
1405}
1406
1407struct hoststated *
1408parse_config(const char *filename, int opts)
1409{
1410	struct sym	*sym, *next;
1411	struct table	*nexttb;
1412	struct host	*h;
1413
1414	if ((conf = calloc(1, sizeof(*conf))) == NULL)
1415		return (NULL);
1416
1417	TAILQ_INIT(&conf->services);
1418	TAILQ_INIT(&conf->tables);
1419	TAILQ_INIT(&conf->protos);
1420	TAILQ_INIT(&conf->relays);
1421
1422	memset(&conf->empty_table, 0, sizeof(conf->empty_table));
1423	conf->empty_table.conf.id = EMPTY_TABLE;
1424	conf->empty_table.conf.flags |= F_DISABLE;
1425	(void)strlcpy(conf->empty_table.conf.name, "empty",
1426	    sizeof(conf->empty_table.conf.name));
1427
1428	bzero(&conf->proto_default, sizeof(conf->proto_default));
1429	conf->proto_default.flags = F_USED;
1430	conf->proto_default.cache = RELAY_CACHESIZE;
1431	conf->proto_default.type = RELAY_PROTO_TCP;
1432	(void)strlcpy(conf->proto_default.name, "default",
1433	    sizeof(conf->proto_default.name));
1434	RB_INIT(&conf->proto_default.request_tree);
1435	RB_INIT(&conf->proto_default.response_tree);
1436	TAILQ_INSERT_TAIL(&conf->protos, &conf->proto_default, entry);
1437
1438	conf->timeout.tv_sec = CHECK_TIMEOUT / 1000;
1439	conf->timeout.tv_usec = (CHECK_TIMEOUT % 1000) * 1000;
1440	conf->interval.tv_sec = CHECK_INTERVAL;
1441	conf->interval.tv_usec = 0;
1442	conf->prefork_relay = RELAY_NUMPROC;
1443	conf->statinterval.tv_sec = RELAY_STATINTERVAL;
1444	conf->opts = opts;
1445	conf->confpath = filename;
1446
1447	if ((fin = fopen(filename, "r")) == NULL) {
1448		warn("%s", filename);
1449		free(conf);
1450		return (NULL);
1451	}
1452	infile = filename;
1453	setservent(1);
1454	yyparse();
1455	endservent();
1456	fclose(fin);
1457
1458	/* Free macros and check which have not been used. */
1459	for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
1460		next = TAILQ_NEXT(sym, entries);
1461		if ((conf->opts & HOSTSTATED_OPT_VERBOSE) && !sym->used)
1462			fprintf(stderr, "warning: macro '%s' not "
1463			    "used\n", sym->nam);
1464		if (!sym->persist) {
1465			free(sym->nam);
1466			free(sym->val);
1467			TAILQ_REMOVE(&symhead, sym, entries);
1468			free(sym);
1469		}
1470	}
1471
1472	if (TAILQ_EMPTY(&conf->services) && TAILQ_EMPTY(&conf->relays)) {
1473		log_warnx("no services, nothing to do");
1474		errors++;
1475	}
1476
1477	if (TAILQ_EMPTY(&conf->relays))
1478		conf->prefork_relay = 0;
1479
1480	if (timercmp(&conf->timeout, &conf->interval, >=)) {
1481		log_warnx("global timeout exceeds interval");
1482		errors++;
1483	}
1484
1485	/* Verify that every table is used */
1486	for (table = TAILQ_FIRST(&conf->tables); table != NULL;
1487	     table = nexttb) {
1488		nexttb = TAILQ_NEXT(table, entry);
1489		if (table->conf.port == 0) {
1490			TAILQ_REMOVE(&conf->tables, table, entry);
1491			while ((h = TAILQ_FIRST(&table->hosts)) != NULL) {
1492				TAILQ_REMOVE(&table->hosts, h, entry);
1493				free(h);
1494			}
1495			if (table->sendbuf != NULL)
1496				free(table->sendbuf);
1497			free(table);
1498			continue;
1499		}
1500		if (!(table->conf.flags & F_USED)) {
1501			log_warnx("unused table: %s", table->conf.name);
1502			errors++;
1503		}
1504		if (timercmp(&table->conf.timeout, &conf->interval, >=)) {
1505			log_warnx("table timeout exceeds interval: %s",
1506			    table->conf.name);
1507			errors++;
1508		}
1509	}
1510
1511	/* Verify that every non-default protocol is used */
1512	TAILQ_FOREACH(proto, &conf->protos, entry) {
1513		if (!(proto->flags & F_USED)) {
1514			log_warnx("unused protocol: %s", proto->name);
1515			errors++;
1516		}
1517	}
1518
1519	if (errors) {
1520		free(conf);
1521		return (NULL);
1522	}
1523
1524	return (conf);
1525}
1526
1527int
1528symset(const char *nam, const char *val, int persist)
1529{
1530	struct sym	*sym;
1531
1532	for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
1533	    sym = TAILQ_NEXT(sym, entries))
1534		;	/* nothing */
1535
1536	if (sym != NULL) {
1537		if (sym->persist == 1)
1538			return (0);
1539		else {
1540			free(sym->nam);
1541			free(sym->val);
1542			TAILQ_REMOVE(&symhead, sym, entries);
1543			free(sym);
1544		}
1545	}
1546	if ((sym = calloc(1, sizeof(*sym))) == NULL)
1547		return (-1);
1548
1549	sym->nam = strdup(nam);
1550	if (sym->nam == NULL) {
1551		free(sym);
1552		return (-1);
1553	}
1554	sym->val = strdup(val);
1555	if (sym->val == NULL) {
1556		free(sym->nam);
1557		free(sym);
1558		return (-1);
1559	}
1560	sym->used = 0;
1561	sym->persist = persist;
1562	TAILQ_INSERT_TAIL(&symhead, sym, entries);
1563	return (0);
1564}
1565
1566int
1567cmdline_symset(char *s)
1568{
1569	char	*sym, *val;
1570	int	ret;
1571	size_t	len;
1572
1573	if ((val = strrchr(s, '=')) == NULL)
1574		return (-1);
1575
1576	len = strlen(s) - strlen(val) + 1;
1577	if ((sym = malloc(len)) == NULL)
1578		errx(1, "cmdline_symset: malloc");
1579
1580	(void)strlcpy(sym, s, len);
1581
1582	ret = symset(sym, val + 1, 1);
1583	free(sym);
1584
1585	return (ret);
1586}
1587
1588char *
1589symget(const char *nam)
1590{
1591	struct sym	*sym;
1592
1593	TAILQ_FOREACH(sym, &symhead, entries)
1594		if (strcmp(nam, sym->nam) == 0) {
1595			sym->used = 1;
1596			return (sym->val);
1597		}
1598	return (NULL);
1599}
1600
1601struct address *
1602host_v4(const char *s)
1603{
1604	struct in_addr		 ina;
1605	struct sockaddr_in	*sain;
1606	struct address		*h;
1607
1608	bzero(&ina, sizeof(ina));
1609	if (inet_pton(AF_INET, s, &ina) != 1)
1610		return (NULL);
1611
1612	if ((h = calloc(1, sizeof(*h))) == NULL)
1613		fatal(NULL);
1614	sain = (struct sockaddr_in *)&h->ss;
1615	sain->sin_len = sizeof(struct sockaddr_in);
1616	sain->sin_family = AF_INET;
1617	sain->sin_addr.s_addr = ina.s_addr;
1618
1619	return (h);
1620}
1621
1622struct address *
1623host_v6(const char *s)
1624{
1625	struct in6_addr		 ina6;
1626	struct sockaddr_in6	*sin6;
1627	struct address		*h;
1628
1629	bzero(&ina6, sizeof(ina6));
1630	if (inet_pton(AF_INET6, s, &ina6) != 1)
1631		return (NULL);
1632
1633	if ((h = calloc(1, sizeof(*h))) == NULL)
1634		fatal(NULL);
1635	sin6 = (struct sockaddr_in6 *)&h->ss;
1636	sin6->sin6_len = sizeof(struct sockaddr_in6);
1637	sin6->sin6_family = AF_INET6;
1638	memcpy(&sin6->sin6_addr, &ina6, sizeof(ina6));
1639
1640	return (h);
1641}
1642
1643int
1644host_dns(const char *s, struct addresslist *al, int max,
1645	 in_port_t port, const char *ifname)
1646{
1647	struct addrinfo		 hints, *res0, *res;
1648	int			 error, cnt = 0;
1649	struct sockaddr_in	*sain;
1650	struct sockaddr_in6	*sin6;
1651	struct address		*h;
1652
1653	bzero(&hints, sizeof(hints));
1654	hints.ai_family = PF_UNSPEC;
1655	hints.ai_socktype = SOCK_DGRAM; /* DUMMY */
1656	error = getaddrinfo(s, NULL, &hints, &res0);
1657	if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME)
1658		return (0);
1659	if (error) {
1660		log_warnx("host_dns: could not parse \"%s\": %s", s,
1661		    gai_strerror(error));
1662		return (-1);
1663	}
1664
1665	for (res = res0; res && cnt < max; res = res->ai_next) {
1666		if (res->ai_family != AF_INET &&
1667		    res->ai_family != AF_INET6)
1668			continue;
1669		if ((h = calloc(1, sizeof(*h))) == NULL)
1670			fatal(NULL);
1671
1672		h->port = port;
1673		if (ifname != NULL) {
1674			if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >=
1675			    sizeof(h->ifname))
1676				log_warnx("host_dns: interface name truncated");
1677			return (-1);
1678		}
1679		h->ss.ss_family = res->ai_family;
1680		if (res->ai_family == AF_INET) {
1681			sain = (struct sockaddr_in *)&h->ss;
1682			sain->sin_len = sizeof(struct sockaddr_in);
1683			sain->sin_addr.s_addr = ((struct sockaddr_in *)
1684			    res->ai_addr)->sin_addr.s_addr;
1685		} else {
1686			sin6 = (struct sockaddr_in6 *)&h->ss;
1687			sin6->sin6_len = sizeof(struct sockaddr_in6);
1688			memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *)
1689			    res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
1690		}
1691
1692		TAILQ_INSERT_HEAD(al, h, entry);
1693		cnt++;
1694	}
1695	if (cnt == max && res) {
1696		log_warnx("host_dns: %s resolves to more than %d hosts",
1697		    s, max);
1698	}
1699	freeaddrinfo(res0);
1700	return (cnt);
1701}
1702
1703int
1704host(const char *s, struct addresslist *al, int max,
1705    in_port_t port, const char *ifname)
1706{
1707	struct address *h;
1708
1709	h = host_v4(s);
1710
1711	/* IPv6 address? */
1712	if (h == NULL)
1713		h = host_v6(s);
1714
1715	if (h != NULL) {
1716		h->port = port;
1717		if (ifname != NULL) {
1718			if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >=
1719			    sizeof(h->ifname)) {
1720				log_warnx("host: interface name truncated");
1721				return (-1);
1722			}
1723		}
1724
1725		TAILQ_INSERT_HEAD(al, h, entry);
1726		return (1);
1727	}
1728
1729	return (host_dns(s, al, max, port, ifname));
1730}
1731
1732struct table *
1733table_inherit(const char *name, in_port_t port)
1734{
1735	char		pname[TABLE_NAME_SIZE + 6];
1736	struct host	*h, *dsth;
1737	struct table	*dsttb, *tb;
1738
1739	/* Get the table or table template */
1740	if ((dsttb = table_findbyname(conf, name)) == NULL) {
1741		yyerror("unknown table or template %s", name);
1742		return (NULL);
1743	}
1744	if (dsttb->conf.port != 0)
1745		return (dsttb);
1746
1747	if (port == 0) {
1748		yyerror("invalid port");
1749		return (NULL);
1750	}
1751
1752	/* Check if a matching table already exists */
1753	snprintf(pname, sizeof(pname), "%s:%u", name, ntohs(port));
1754	if ((tb = table_findbyname(conf, pname)) != NULL) {
1755		if (tb->conf.port == 0) {
1756			yyerror("invalid table");
1757			return (NULL);
1758		}
1759		return (tb);
1760	}
1761
1762	/* Create a new table */
1763	if ((tb = calloc(1, sizeof (*tb))) == NULL)
1764		fatal("out of memory");
1765	bcopy(dsttb, tb, sizeof(*tb));
1766	if (strlcpy(tb->conf.name, pname, sizeof(tb->conf.name))
1767	    >= sizeof(tb->conf.name)) {
1768		yyerror("table name truncated");
1769		return (NULL);
1770	}
1771	if (dsttb->sendbuf != NULL &&
1772	    (tb->sendbuf = strdup(dsttb->sendbuf)) == NULL)
1773		fatal("out of memory");
1774	tb->conf.port = port;
1775	tb->conf.id = last_table_id++;
1776	if (last_table_id == INT_MAX) {
1777		yyerror("too many tables defined");
1778		return (NULL);
1779	}
1780
1781	/* Copy the associated hosts */
1782	bzero(&tb->hosts, sizeof(tb->hosts));
1783	TAILQ_FOREACH(dsth, &dsttb->hosts, entry) {
1784		if ((h = (struct host *)
1785		    calloc(1, sizeof (*h))) == NULL)
1786			fatal("out of memory");
1787		bcopy(dsth, h, sizeof(*h));
1788		h->conf.id = last_host_id++;
1789		if (last_host_id == INT_MAX) {
1790			yyerror("too many hosts defined");
1791			return (NULL);
1792		}
1793		h->conf.tableid = tb->conf.id;
1794		h->tablename = tb->conf.name;
1795		TAILQ_INSERT_HEAD(&tb->hosts, h, entry);
1796	}
1797
1798	conf->tablecount++;
1799	TAILQ_INSERT_HEAD(&conf->tables, tb, entry);
1800
1801	return (tb);
1802}
1803