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