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