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