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