parse.y revision 1.55
1/*	$OpenBSD: parse.y,v 1.55 2006/03/30 15:30:18 hshoexer Exp $	*/
2
3/*
4 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
5 * Copyright (c) 2001 Markus Friedl.  All rights reserved.
6 * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
7 * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
8 * Copyright (c) 2004, 2005 Hans-Joerg Hoexer <hshoexer@openbsd.org>
9 *
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
23%{
24#include <sys/types.h>
25#include <sys/ioctl.h>
26#include <sys/queue.h>
27#include <sys/socket.h>
28#include <sys/stat.h>
29#include <net/if.h>
30#include <netinet/in.h>
31#include <netinet/ip_ipsp.h>
32#include <arpa/inet.h>
33
34#include <ctype.h>
35#include <err.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <ifaddrs.h>
39#include <limits.h>
40#include <stdarg.h>
41#include <stdio.h>
42#include <string.h>
43#include <syslog.h>
44#include <unistd.h>
45
46#include "ipsecctl.h"
47
48#define KEYSIZE_LIMIT	1024
49
50static struct ipsecctl	*ipsec = NULL;
51static FILE		*fin = NULL;
52static int		 lineno = 1;
53static int		 errors = 0;
54static int		 debug = 0;
55
56const struct ipsec_xf authxfs[] = {
57	{ "unknown",		AUTHXF_UNKNOWN,		0,	0 },
58	{ "none",		AUTHXF_NONE,		0,	0 },
59	{ "hmac-md5",		AUTHXF_HMAC_MD5,	16,	0 },
60	{ "hmac-ripemd160",	AUTHXF_HMAC_RIPEMD160,	20,	0 },
61	{ "hmac-sha1",		AUTHXF_HMAC_SHA1,	20,	0 },
62	{ "hmac-sha2-256",	AUTHXF_HMAC_SHA2_256,	32,	0 },
63	{ "hmac-sha2-384",	AUTHXF_HMAC_SHA2_384,	48,	0 },
64	{ "hmac-sha2-512",	AUTHXF_HMAC_SHA2_512,	64,	0 },
65	{ NULL,			0,			0,	0 },
66};
67
68const struct ipsec_xf encxfs[] = {
69	{ "unknown",		ENCXF_UNKNOWN,		0,	0 },
70	{ "none",		ENCXF_NONE,		0,	0 },
71	{ "3des-cbc",		ENCXF_3DES_CBC,		24,	24 },
72	{ "des-cbc",		ENCXF_DES_CBC,		8,	8 },
73	{ "aes",		ENCXF_AES,		16,	32 },
74	{ "aesctr",		ENCXF_AESCTR,		16+4,	32+4 },
75	{ "blowfish",		ENCXF_BLOWFISH,		5,	56 },
76	{ "cast128",		ENCXF_CAST128,		5,	16 },
77	{ "null",		ENCXF_NULL,		0,	0 },
78	{ "skipjack",		ENCXF_SKIPJACK,		10,	10 },
79	{ NULL,			0,			0,	0 },
80};
81
82const struct ipsec_xf compxfs[] = {
83	{ "unknown",		COMPXF_UNKNOWN,		0,	0 },
84	{ "deflate",		COMPXF_DEFLATE,		0,	0 },
85	{ "lzs",		COMPXF_LZS,		0,	0 },
86	{ NULL,			0,			0,	0 },
87};
88
89int			 yyerror(const char *, ...);
90int			 yyparse(void);
91int			 kw_cmp(const void *, const void *);
92int			 lookup(char *);
93int			 lgetc(FILE *);
94int			 lungetc(int);
95int			 findeol(void);
96int			 yylex(void);
97
98TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
99struct sym {
100	TAILQ_ENTRY(sym)	 entries;
101	int		 used;
102	int		 persist;
103	char		*nam;
104	char		*val;
105};
106
107int			 symset(const char *, const char *, int);
108int			 cmdline_symset(char *);
109char			*symget(const char *);
110int			 atoul(char *, u_long *);
111int			 atospi(char *, u_int32_t *);
112u_int8_t		 x2i(unsigned char *);
113struct ipsec_key	*parsekey(unsigned char *, size_t);
114struct ipsec_key	*parsekeyfile(char *);
115struct ipsec_addr_wrap	*host(const char *);
116struct ipsec_addr_wrap	*host_v4(const char *, int);
117struct ipsec_addr_wrap	*host_if(const char *, int);
118void			 ifa_load(void);
119int			 ifa_exists(const char *);
120struct ipsec_addr_wrap	*ifa_lookup(const char *ifa_name);
121void			 set_ipmask(struct ipsec_addr_wrap *, u_int8_t);
122struct ipsec_addr_wrap	*copyhost(const struct ipsec_addr_wrap *);
123const struct ipsec_xf	*parse_xf(const char *, const struct ipsec_xf *);
124struct ipsec_transforms *copytransforms(const struct ipsec_transforms *);
125int			 validate_sa(u_int32_t, u_int8_t,
126			     struct ipsec_transforms *, struct ipsec_key *,
127			     struct ipsec_key *, u_int8_t);
128struct ipsec_rule	*create_sa(u_int8_t, u_int8_t, struct ipsec_addr_wrap *,
129			     struct ipsec_addr_wrap *, u_int32_t,
130			     struct ipsec_transforms *, struct ipsec_key *,
131			     struct ipsec_key *);
132struct ipsec_rule	*reverse_sa(struct ipsec_rule *, u_int32_t,
133			     struct ipsec_key *, struct ipsec_key *);
134struct ipsec_rule	*create_flow(u_int8_t, struct ipsec_addr_wrap *, struct
135			     ipsec_addr_wrap *, struct ipsec_addr_wrap *, struct
136			     ipsec_addr_wrap *, u_int8_t, char *, char *,
137			     u_int8_t);
138struct ipsec_rule	*reverse_rule(struct ipsec_rule *);
139struct ipsec_rule	*create_ike(struct ipsec_addr_wrap *, struct
140			     ipsec_addr_wrap *, struct ipsec_addr_wrap *,
141			     struct ipsec_transforms *, struct
142			     ipsec_transforms *, u_int8_t, u_int8_t, char *,
143			     char *, struct ike_auth *);
144
145struct ipsec_transforms *ipsec_transforms;
146
147typedef struct {
148	union {
149		u_int32_t	 number;
150		u_int8_t	 ikemode;
151		u_int8_t	 dir;
152		u_int8_t	 protocol;
153		u_int8_t	 tmode;
154		char		*string;
155		struct {
156			struct ipsec_addr_wrap *src;
157			struct ipsec_addr_wrap *dst;
158		} hosts;
159		struct ipsec_addr_wrap *local;
160		struct ipsec_addr_wrap *peer;
161		struct ipsec_addr_wrap *host;
162		struct {
163			char *srcid;
164			char *dstid;
165		} ids;
166		char		*id;
167		u_int8_t	 type;
168		struct ike_auth	 ikeauth;
169		struct {
170			u_int32_t	spiout;
171			u_int32_t	spiin;
172		} spis;
173		struct {
174			struct ipsec_key *keyout;
175			struct ipsec_key *keyin;
176		} authkeys;
177		struct {
178			struct ipsec_key *keyout;
179			struct ipsec_key *keyin;
180		} enckeys;
181		struct {
182			struct ipsec_key *keyout;
183			struct ipsec_key *keyin;
184		} keys;
185		struct ipsec_transforms *transforms;
186		struct ipsec_transforms *mmxfs;
187		struct ipsec_transforms *qmxfs;
188	} v;
189	int lineno;
190} YYSTYPE;
191
192%}
193
194%token	FLOW FROM ESP AH IN PEER ON OUT TO SRCID DSTID RSA PSK TCPMD5 SPI
195%token	AUTHKEY ENCKEY FILENAME AUTHXF ENCXF ERROR IKE MAIN QUICK PASSIVE
196%token	ACTIVE ANY IPIP IPCOMP COMPXF TUNNEL TRANSPORT DYNAMIC
197%token	TYPE DENY BYPASS LOCAL
198%token	<v.string>		STRING
199%type	<v.string>		string
200%type	<v.dir>			dir
201%type	<v.protocol>		protocol
202%type	<v.tmode>		tmode
203%type	<v.number>		number
204%type	<v.hosts>		hosts
205%type	<v.local>		local
206%type	<v.peer>		peer
207%type	<v.host>		host
208%type	<v.ids>			ids
209%type	<v.id>			id
210%type	<v.spis>		spispec
211%type	<v.authkeys>		authkeyspec
212%type	<v.enckeys>		enckeyspec
213%type	<v.keys>		keyspec
214%type	<v.transforms>		transforms
215%type	<v.mmxfs>		mmxfs
216%type	<v.qmxfs>		qmxfs
217%type	<v.ikemode>		ikemode
218%type	<v.ikeauth>		ikeauth
219%type	<v.type>		type
220%%
221
222grammar		: /* empty */
223		| grammar '\n'
224		| grammar ikerule '\n'
225		| grammar flowrule '\n'
226		| grammar sarule '\n'
227		| grammar tcpmd5rule '\n'
228		| grammar varset '\n'
229		| grammar error '\n'		{ errors++; }
230		;
231
232number		: STRING			{
233			unsigned long	ulval;
234
235			if (atoul($1, &ulval) == -1) {
236				yyerror("%s is not a number", $1);
237				free($1);
238				YYERROR;
239			}
240			if (ulval > UINT_MAX) {
241				yyerror("0x%lx out of range", ulval);
242				free($1);
243				YYERROR;
244			}
245			$$ = (u_int32_t)ulval;
246			free($1);
247		}
248		;
249
250tcpmd5rule	: TCPMD5 hosts spispec authkeyspec	{
251			struct ipsec_rule	*r;
252
253			r = create_sa(IPSEC_TCPMD5, IPSEC_TRANSPORT, $2.src,
254			    $2.dst, $3.spiout, NULL, $4.keyout, NULL);
255			if (r == NULL)
256				YYERROR;
257			r->nr = ipsec->rule_nr++;
258
259			if (ipsecctl_add_rule(ipsec, r))
260				errx(1, "tcpmd5rule: ipsecctl_add_rule");
261
262			/* Create and add reverse SA rule. */
263			if ($3.spiin != 0 || $4.keyin != NULL) {
264				r = reverse_sa(r, $3.spiin, $4.keyin, NULL);
265				if (r == NULL)
266					YYERROR;
267				r->nr = ipsec->rule_nr++;
268
269				if (ipsecctl_add_rule(ipsec, r))
270					errx(1, "tcpmd5rule: "
271					    "ipsecctl_add_rule");
272			}
273		}
274		;
275
276sarule		: protocol tmode hosts spispec transforms authkeyspec
277		    enckeyspec {
278			struct ipsec_rule	*r;
279
280			r = create_sa($1, $2, $3.src, $3.dst, $4.spiout, $5,
281			    $6.keyout, $7.keyout);
282			if (r == NULL)
283				YYERROR;
284			r->nr = ipsec->rule_nr++;
285
286			if (ipsecctl_add_rule(ipsec, r))
287				errx(1, "sarule: ipsecctl_add_rule");
288
289			/* Create and add reverse SA rule. */
290			if ($4.spiin != 0 || $6.keyin || $7.keyin) {
291				r = reverse_sa(r, $4.spiin, $6.keyin,
292				    $7.keyin);
293				if (r == NULL)
294					YYERROR;
295				r->nr = ipsec->rule_nr++;
296
297				if (ipsecctl_add_rule(ipsec, r))
298					errx(1, "sarule: ipsecctl_add_rule");
299			}
300		}
301		;
302
303flowrule	: FLOW protocol dir hosts local peer ids type {
304			struct ipsec_rule	*r;
305
306			r = create_flow($3, $4.src, $4.dst, $5, $6, $2,
307			    $7.srcid, $7.dstid, $8);
308			if (r == NULL)
309				YYERROR;
310			r->nr = ipsec->rule_nr++;
311
312			if (ipsecctl_add_rule(ipsec, r))
313				errx(1, "flowrule: ipsecctl_add_rule");
314
315			/* Create and add reverse flow rule. */
316			if ($8 == TYPE_UNKNOWN && $3 == IPSEC_INOUT) {
317				r = reverse_rule(r);
318				r->nr = ipsec->rule_nr++;
319
320				if (ipsecctl_add_rule(ipsec, r))
321					errx(1, "flowrule: ipsecctl_add_rule");
322			}
323		}
324		;
325
326ikerule		: IKE ikemode protocol hosts peer mmxfs qmxfs ids ikeauth {
327			struct ipsec_rule	*r;
328
329			r = create_ike($4.src, $4.dst, $5, $6, $7, $3, $2,
330			    $8.srcid, $8.dstid, &$9);
331			if (r == NULL)
332				YYERROR;
333			r->nr = ipsec->rule_nr++;
334
335			if (ipsecctl_add_rule(ipsec, r))
336				errx(1, "ikerule: ipsecctl_add_rule");
337		}
338		;
339
340protocol	: /* empty */			{ $$ = IPSEC_ESP; }
341		| ESP				{ $$ = IPSEC_ESP; }
342		| AH				{ $$ = IPSEC_AH; }
343		| IPCOMP			{ $$ = IPSEC_IPCOMP; }
344		| IPIP				{ $$ = IPSEC_IPIP; }
345		;
346
347tmode		: /* empty */			{ $$ = IPSEC_TUNNEL; }
348		| TUNNEL			{ $$ = IPSEC_TUNNEL; }
349		| TRANSPORT			{ $$ = IPSEC_TRANSPORT; }
350		;
351
352dir		: /* empty */			{ $$ = IPSEC_INOUT; }
353		| IN				{ $$ = IPSEC_IN; }
354		| OUT				{ $$ = IPSEC_OUT; }
355		;
356
357hosts		: FROM host TO host		{
358			$$.src = $2;
359			$$.dst = $4;
360		}
361		| TO host FROM host		{
362			$$.src = $4;
363			$$.dst = $2;
364		}
365		;
366
367peer		: /* empty */			{ $$ = NULL; }
368		| PEER STRING			{
369			if (($$ = host($2)) == NULL) {
370				free($2);
371				yyerror("could not parse host specification");
372				YYERROR;
373			}
374			free($2);
375		}
376		;
377
378local		: /* empty */			{ $$ = NULL; }
379		| LOCAL STRING			{
380			if (($$ = host($2)) == NULL) {
381				free($2);
382				yyerror("could not parse host specification");
383				YYERROR;
384			}
385			free($2);
386		}
387		;
388
389host		: STRING			{
390			if (($$ = host($1)) == NULL) {
391				free($1);
392				yyerror("could not parse host specification");
393				YYERROR;
394			}
395			free($1);
396		}
397		| STRING '/' number		{
398			char	*buf;
399
400			if (asprintf(&buf, "%s/%u", $1, $3) == -1)
401				err(1, "host: asprintf");
402			free($1);
403			if (($$ = host(buf)) == NULL)	{
404				free(buf);
405				yyerror("could not parse host specification");
406				YYERROR;
407			}
408			free(buf);
409		}
410		| ANY				{
411			struct ipsec_addr_wrap	*ipa;
412
413			ipa = calloc(1, sizeof(struct ipsec_addr_wrap));
414			if (ipa == NULL)
415				err(1, "host: calloc");
416
417			ipa->af = AF_INET;
418			ipa->netaddress = 1;
419			if ((ipa->name = strdup("0.0.0.0/0")) == NULL)
420				err(1, "host: strdup");
421			$$ = ipa;
422		}
423		;
424
425ids		: /* empty */			{
426			$$.srcid = NULL;
427			$$.dstid = NULL;
428		}
429		| SRCID id DSTID id		{
430			$$.srcid = $2;
431			$$.dstid = $4;
432		}
433		| SRCID id			{
434			$$.srcid = $2;
435			$$.dstid = NULL;
436		}
437		| DSTID id			{
438			$$.srcid = NULL;
439			$$.dstid = $2;
440		}
441		;
442
443type		: /* empty */			{
444			$$ = TYPE_UNKNOWN;
445		}
446		| TYPE DENY			{
447			$$ = TYPE_DENY;
448		}
449		| TYPE BYPASS			{
450			$$ = TYPE_BYPASS;
451		}
452		;
453
454id		: STRING			{ $$ = $1; }
455		;
456
457spispec		: SPI STRING			{
458			u_int32_t	 spi;
459			char		*p = strchr($2, ':');
460
461			if (p != NULL) {
462				*p++ = 0;
463
464				if (atospi(p, &spi) == -1) {
465					yyerror("%s is not a valid spi", p);
466					free($2);
467					YYERROR;
468				}
469				$$.spiin = spi;
470			}
471			if (atospi($2, &spi) == -1) {
472				yyerror("%s is not a valid spi", $2);
473				free($2);
474				YYERROR;
475			}
476			$$.spiout = spi;
477
478
479			free($2);
480		}
481		;
482
483transforms	:					{
484			if ((ipsec_transforms = calloc(1,
485			    sizeof(struct ipsec_transforms))) == NULL)
486				err(1, "transforms: calloc");
487		}
488		    transforms_l			{ $$ = ipsec_transforms; }
489		| /* empty */				{
490			if (($$ = calloc(1,
491			    sizeof(struct ipsec_transforms))) == NULL)
492				err(1, "transforms: calloc");
493		}
494		;
495
496transforms_l	: transforms_l transform
497		| transform
498		;
499
500transform	: AUTHXF STRING			{
501			if (ipsec_transforms->authxf)
502				yyerror("auth already set");
503			else {
504				ipsec_transforms->authxf = parse_xf($2,
505				    authxfs);
506				if (!ipsec_transforms->authxf)
507					yyerror("%s not a valid transform", $2);
508			}
509		}
510		| ENCXF STRING			{
511			if (ipsec_transforms->encxf)
512				yyerror("enc already set");
513			else {
514				ipsec_transforms->encxf = parse_xf($2, encxfs);
515				if (!ipsec_transforms->encxf)
516					yyerror("%s not a valid transform", $2);
517			}
518		}
519		| COMPXF STRING			{
520			if (ipsec_transforms->compxf)
521				yyerror("comp already set");
522			else {
523				ipsec_transforms->compxf = parse_xf($2,
524				    compxfs);
525				if (!ipsec_transforms->compxf)
526					yyerror("%s not a valid transform", $2);
527			}
528		}
529		;
530
531mmxfs		: /* empty */			{
532			struct ipsec_transforms *xfs;
533
534			/* We create just an empty transform */
535			if ((xfs = calloc(1, sizeof(struct ipsec_transforms)))
536			    == NULL)
537				err(1, "mmxfs: calloc");
538			$$ = xfs;
539		}
540		| MAIN transforms		{ $$ = $2; }
541		;
542
543qmxfs		: /* empty */			{
544			struct ipsec_transforms *xfs;
545
546			/* We create just an empty transform */
547			if ((xfs = calloc(1, sizeof(struct ipsec_transforms)))
548			    == NULL)
549				err(1, "qmxfs: calloc");
550			$$ = xfs;
551		}
552		| QUICK transforms		{ $$ = $2; }
553		;
554
555authkeyspec	: /* empty */			{
556			$$.keyout = NULL;
557			$$.keyin = NULL;
558		}
559		| AUTHKEY keyspec		{
560			$$.keyout = $2.keyout;
561			$$.keyin = $2.keyin;
562		}
563		;
564
565enckeyspec	: /* empty */			{
566			$$.keyout = NULL;
567			$$.keyin = NULL;
568		}
569		| ENCKEY keyspec		{
570			$$.keyout = $2.keyout;
571			$$.keyin = $2.keyin;
572		}
573		;
574
575keyspec		: STRING			{
576			unsigned char	*hex;
577			unsigned char	*p = strchr($1, ':');
578
579			if (p != NULL ) {
580				*p++ = 0;
581
582				if (!strncmp(p, "0x", 2))
583					p += 2;
584				$$.keyin = parsekey(p, strlen(p));
585			}
586
587			hex = $1;
588			if (!strncmp(hex, "0x", 2))
589				hex += 2;
590			$$.keyout = parsekey(hex, strlen(hex));
591
592			free($1);
593		}
594		| FILENAME STRING		{
595			unsigned char	*p = strchr($2, ':');
596
597			if (p != NULL) {
598				*p++ = 0;
599				$$.keyin = parsekeyfile(p);
600			}
601			$$.keyout = parsekeyfile($2);
602			free($2);
603		}
604		;
605
606ikemode		: /* empty */			{ $$ = IKE_ACTIVE; }
607		| PASSIVE			{ $$ = IKE_PASSIVE; }
608		| DYNAMIC			{ $$ = IKE_DYNAMIC; }
609		| ACTIVE			{ $$ = IKE_ACTIVE; }
610		;
611
612ikeauth		: /* empty */			{
613			$$.type = IKE_AUTH_RSA;
614			$$.string = NULL;
615		}
616		| RSA				{
617			$$.type = IKE_AUTH_RSA;
618			$$.string = NULL;
619		}
620		| PSK STRING			{
621			$$.type = IKE_AUTH_PSK;
622			if (($$.string = strdup($2)) == NULL)
623				err(1, "ikeauth: strdup");
624		}
625		;
626
627string		: string STRING
628		{
629			if (asprintf(&$$, "%s %s", $1, $2) == -1)
630				err(1, "string: asprintf");
631			free($1);
632			free($2);
633		}
634		| STRING
635		;
636
637varset		: STRING '=' string
638		{
639			if (ipsec->opts & IPSECCTL_OPT_VERBOSE)
640				printf("%s = \"%s\"\n", $1, $3);
641			if (symset($1, $3, 0) == -1)
642				err(1, "cannot store variable");
643			free($1);
644			free($3);
645		}
646		;
647
648%%
649
650struct keywords {
651	const char	*k_name;
652	int		 k_val;
653};
654
655int
656yyerror(const char *fmt, ...)
657{
658	va_list		 ap;
659	extern char	*infile;
660
661	errors = 1;
662	va_start(ap, fmt);
663	fprintf(stderr, "%s: %d: ", infile, yyval.lineno);
664	vfprintf(stderr, fmt, ap);
665	fprintf(stderr, "\n");
666	va_end(ap);
667	return (0);
668}
669
670int
671kw_cmp(const void *k, const void *e)
672{
673	return (strcmp(k, ((const struct keywords *)e)->k_name));
674}
675
676int
677lookup(char *s)
678{
679	/* this has to be sorted always */
680	static const struct keywords keywords[] = {
681		{ "active",		ACTIVE },
682		{ "ah",			AH },
683		{ "any",		ANY },
684		{ "auth",		AUTHXF },
685		{ "authkey",		AUTHKEY },
686		{ "bypass",		BYPASS },
687		{ "comp",		COMPXF },
688		{ "deny",		DENY },
689		{ "dstid",		DSTID },
690		{ "dynamic",		DYNAMIC },
691		{ "enc",		ENCXF },
692		{ "enckey",		ENCKEY },
693		{ "esp",		ESP },
694		{ "file",		FILENAME },
695		{ "flow",		FLOW },
696		{ "from",		FROM },
697		{ "ike",		IKE },
698		{ "in",			IN },
699		{ "ipcomp",		IPCOMP },
700		{ "ipip",		IPIP },
701		{ "local",		LOCAL },
702		{ "main",		MAIN },
703		{ "out",		OUT },
704		{ "passive",		PASSIVE },
705		{ "peer",		PEER },
706		{ "psk",		PSK },
707		{ "quick",		QUICK },
708		{ "rsa",		RSA },
709		{ "spi",		SPI },
710		{ "srcid",		SRCID },
711		{ "tcpmd5",		TCPMD5 },
712		{ "to",			TO },
713		{ "transport",		TRANSPORT },
714		{ "tunnel",		TUNNEL },
715		{ "type",		TYPE },
716	};
717	const struct keywords	*p;
718
719	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
720	    sizeof(keywords[0]), kw_cmp);
721
722	if (p) {
723		if (debug > 1)
724			fprintf(stderr, "%s: %d\n", s, p->k_val);
725		return (p->k_val);
726	} else {
727		if (debug > 1)
728			fprintf(stderr, "string: %s\n", s);
729		return (STRING);
730	}
731}
732
733#define MAXPUSHBACK	128
734
735char	*parsebuf;
736int	 parseindex;
737char	 pushback_buffer[MAXPUSHBACK];
738int	 pushback_index = 0;
739
740int
741lgetc(FILE *f)
742{
743	int	c, next;
744
745	if (parsebuf) {
746		/* Read character from the parsebuffer instead of input. */
747		if (parseindex >= 0) {
748			c = parsebuf[parseindex++];
749			if (c != '\0')
750				return (c);
751			parsebuf = NULL;
752		} else
753			parseindex++;
754	}
755
756	if (pushback_index)
757		return (pushback_buffer[--pushback_index]);
758
759	while ((c = getc(f)) == '\\') {
760		next = getc(f);
761		if (next != '\n') {
762			if (isspace(next))
763				yyerror("whitespace after \\");
764			ungetc(next, f);
765			break;
766		}
767		yylval.lineno = lineno;
768		lineno++;
769	}
770	if (c == '\t' || c == ' ') {
771		/* Compress blanks to a single space. */
772		do {
773			c = getc(f);
774		} while (c == '\t' || c == ' ');
775		ungetc(c, f);
776		c = ' ';
777	}
778
779	return (c);
780}
781
782int
783lungetc(int c)
784{
785	if (c == EOF)
786		return (EOF);
787	if (parsebuf) {
788		parseindex--;
789		if (parseindex >= 0)
790			return (c);
791	}
792	if (pushback_index < MAXPUSHBACK-1)
793		return (pushback_buffer[pushback_index++] = c);
794	else
795		return (EOF);
796}
797
798int
799findeol(void)
800{
801	int	c;
802
803	parsebuf = NULL;
804	pushback_index = 0;
805
806	/* skip to either EOF or the first real EOL */
807	while (1) {
808		c = lgetc(fin);
809		if (c == '\n') {
810			lineno++;
811			break;
812		}
813		if (c == EOF)
814			break;
815	}
816	return (ERROR);
817}
818
819int
820yylex(void)
821{
822	char	 buf[8096];
823	char	*p, *val;
824	int	 endc, c;
825	int	 token;
826
827top:
828	p = buf;
829	while ((c = lgetc(fin)) == ' ')
830		; /* nothing */
831
832	yylval.lineno = lineno;
833	if (c == '#')
834		while ((c = lgetc(fin)) != '\n' && c != EOF)
835			; /* nothing */
836	if (c == '$' && parsebuf == NULL) {
837		while (1) {
838			if ((c = lgetc(fin)) == EOF)
839				return (0);
840
841			if (p + 1 >= buf + sizeof(buf) - 1) {
842				yyerror("string too long");
843				return (findeol());
844			}
845			if (isalnum(c) || c == '_') {
846				*p++ = (char)c;
847				continue;
848			}
849			*p = '\0';
850			lungetc(c);
851			break;
852		}
853		val = symget(buf);
854		if (val == NULL) {
855			yyerror("macro \"%s\" not defined", buf);
856			return (findeol());
857		}
858		parsebuf = val;
859		parseindex = 0;
860		goto top;
861	}
862
863	switch (c) {
864	case '\'':
865	case '"':
866		endc = c;
867		while (1) {
868			if ((c = lgetc(fin)) == EOF)
869				return (0);
870			if (c == endc) {
871				*p = '\0';
872				break;
873			}
874			if (c == '\n') {
875				lineno++;
876				continue;
877			}
878			if (p + 1 >= buf + sizeof(buf) - 1) {
879				yyerror("string too long");
880				return (findeol());
881			}
882			*p++ = (char)c;
883		}
884		yylval.v.string = strdup(buf);
885		if (yylval.v.string == NULL)
886			err(1, "yylex: strdup");
887		return (STRING);
888	}
889
890#define allowed_in_string(x) \
891	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
892	x != '{' && x != '}' && x != '<' && x != '>' && \
893	x != '!' && x != '=' && x != '/' && x != '#' && \
894	x != ','))
895
896	if (isalnum(c) || c == ':' || c == '_' || c == '*') {
897		do {
898			*p++ = c;
899			if ((unsigned)(p-buf) >= sizeof(buf)) {
900				yyerror("string too long");
901				return (findeol());
902			}
903		} while ((c = lgetc(fin)) != EOF && (allowed_in_string(c)));
904		lungetc(c);
905		*p = '\0';
906		if ((token = lookup(buf)) == STRING)
907			if ((yylval.v.string = strdup(buf)) == NULL)
908				err(1, "yylex: strdup");
909		return (token);
910	}
911	if (c == '\n') {
912		yylval.lineno = lineno;
913		lineno++;
914	}
915	if (c == EOF)
916		return (0);
917	return (c);
918}
919
920int
921parse_rules(FILE *input, struct ipsecctl *ipsecx)
922{
923	struct sym	*sym;
924
925	ipsec = ipsecx;
926	fin = input;
927	lineno = 1;
928	errors = 0;
929
930	yyparse();
931
932	/* Free macros and check which have not been used. */
933	while ((sym = TAILQ_FIRST(&symhead))) {
934		if ((ipsec->opts & IPSECCTL_OPT_VERBOSE2) && !sym->used)
935			fprintf(stderr, "warning: macro '%s' not "
936			    "used\n", sym->nam);
937		TAILQ_REMOVE(&symhead, sym, entries);
938		free(sym->nam);
939		free(sym->val);
940		free(sym);
941	}
942
943	return (errors ? -1 : 0);
944}
945
946int
947symset(const char *nam, const char *val, int persist)
948{
949	struct sym	*sym;
950
951	for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
952	    sym = TAILQ_NEXT(sym, entries))
953		;	/* nothing */
954
955	if (sym != NULL) {
956		if (sym->persist == 1)
957			return (0);
958		else {
959			TAILQ_REMOVE(&symhead, sym, entries);
960			free(sym->nam);
961			free(sym->val);
962			free(sym);
963		}
964	}
965	if ((sym = calloc(1, sizeof(*sym))) == NULL)
966		return (-1);
967
968	sym->nam = strdup(nam);
969	if (sym->nam == NULL) {
970		free(sym);
971		return (-1);
972	}
973	sym->val = strdup(val);
974	if (sym->val == NULL) {
975		free(sym->nam);
976		free(sym);
977		return (-1);
978	}
979	sym->used = 0;
980	sym->persist = persist;
981	TAILQ_INSERT_TAIL(&symhead, sym, entries);
982	return (0);
983}
984
985int
986cmdline_symset(char *s)
987{
988	char	*sym, *val;
989	int	ret;
990	size_t	len;
991
992	if ((val = strrchr(s, '=')) == NULL)
993		return (-1);
994
995	len = strlen(s) - strlen(val) + 1;
996	if ((sym = malloc(len)) == NULL)
997		err(1, "cmdline_symset: malloc");
998
999	strlcpy(sym, s, len);
1000
1001	ret = symset(sym, val + 1, 1);
1002	free(sym);
1003
1004	return (ret);
1005}
1006
1007char *
1008symget(const char *nam)
1009{
1010	struct sym	*sym;
1011
1012	TAILQ_FOREACH(sym, &symhead, entries)
1013		if (strcmp(nam, sym->nam) == 0) {
1014			sym->used = 1;
1015			return (sym->val);
1016		}
1017	return (NULL);
1018}
1019
1020int
1021atoul(char *s, u_long *ulvalp)
1022{
1023	u_long	 ulval;
1024	char	*ep;
1025
1026	errno = 0;
1027	ulval = strtoul(s, &ep, 0);
1028	if (s[0] == '\0' || *ep != '\0')
1029		return (-1);
1030	if (errno == ERANGE && ulval == ULONG_MAX)
1031		return (-1);
1032	*ulvalp = ulval;
1033	return (0);
1034}
1035
1036int
1037atospi(char *s, u_int32_t *spivalp)
1038{
1039	unsigned long	ulval;
1040
1041	if (atoul(s, &ulval) == -1)
1042		return (-1);
1043	if (ulval >= SPI_RESERVED_MIN && ulval <= SPI_RESERVED_MAX) {
1044		yyerror("illegal SPI value");
1045		return (-1);
1046	}
1047	*spivalp = ulval;
1048	return (0);
1049}
1050
1051u_int8_t
1052x2i(unsigned char *s)
1053{
1054	char	ss[3];
1055
1056	ss[0] = s[0];
1057	ss[1] = s[1];
1058	ss[2] = 0;
1059
1060	if (!isxdigit(s[0]) || !isxdigit(s[1])) {
1061		yyerror("keys need to be specified in hex digits");
1062		return (-1);
1063	}
1064	return ((u_int8_t)strtoul(ss, NULL, 16));
1065}
1066
1067struct ipsec_key *
1068parsekey(unsigned char *hexkey, size_t len)
1069{
1070	struct ipsec_key *key;
1071	int		  i;
1072
1073	key = calloc(1, sizeof(struct ipsec_key));
1074	if (key == NULL)
1075		err(1, "parsekey: calloc");
1076
1077	key->len = len / 2;
1078	key->data = calloc(key->len, sizeof(u_int8_t));
1079	if (key->data == NULL)
1080		err(1, "parsekey: calloc");
1081
1082	for (i = 0; i < (int)key->len; i++)
1083		key->data[i] = x2i(hexkey + 2 * i);
1084
1085	return (key);
1086}
1087
1088struct ipsec_key *
1089parsekeyfile(char *filename)
1090{
1091	struct stat	 sb;
1092	int		 fd;
1093	unsigned char	*hex;
1094
1095	if ((fd = open(filename, O_RDONLY)) < 0)
1096		err(1, "parsekeyfile: open");
1097	if (fstat(fd, &sb) < 0)
1098		err(1, "parsekeyfile: stat %s", filename);
1099	if ((sb.st_size > KEYSIZE_LIMIT) || (sb.st_size == 0))
1100		errx(1, "parsekeyfile: key too %s", sb.st_size ? "large" :
1101		    "small");
1102	if ((hex = calloc(sb.st_size, sizeof(unsigned char))) == NULL)
1103		err(1, "parsekeyfile: calloc");
1104	if (read(fd, hex, sb.st_size) < sb.st_size)
1105		err(1, "parsekeyfile: read");
1106	close(fd);
1107	return (parsekey(hex, sb.st_size));
1108}
1109
1110struct ipsec_addr_wrap *
1111host(const char *s)
1112{
1113	struct ipsec_addr_wrap	*ipa = NULL;
1114	int			 mask, v4mask, cont = 1;
1115	char			*p, *q, *ps;
1116
1117	if ((p = strrchr(s, '/')) != NULL) {
1118		mask = strtol(p + 1, &q, 0);
1119		if (!q || *q || mask > 32 || q == (p + 1))
1120			errx(1, "host: invalid netmask '%s'", p);
1121		if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL)
1122			err(1, "host: calloc");
1123		strlcpy(ps, s, strlen(s) - strlen(p) + 1);
1124		v4mask = mask;
1125	} else {
1126		if ((ps = strdup(s)) == NULL)
1127			err(1, "host: strdup");
1128		v4mask = 32;
1129		mask = -1;
1130	}
1131
1132	/* Does interface with this name exist? */
1133	if (cont && (ipa = host_if(ps, mask)) != NULL)
1134		cont = 0;
1135
1136	/* IPv4 address? */
1137	if (cont && (ipa = host_v4(s, mask)) != NULL)
1138		cont = 0;
1139
1140#if notyet
1141	/* IPv6 address? */
1142	if (cont && (ipa = host_dns(ps, v4mask, 0)) != NULL)
1143		cont = 0;
1144#endif
1145	free(ps);
1146
1147	if (ipa == NULL || cont == 1) {
1148		fprintf(stderr, "no IP address found for %s\n", s);
1149		return (NULL);
1150	}
1151	return (ipa);
1152}
1153
1154struct ipsec_addr_wrap *
1155host_v4(const char *s, int mask)
1156{
1157	struct ipsec_addr_wrap	*ipa = NULL;
1158	struct in_addr		 ina;
1159	int			 bits = 32;
1160
1161	bzero(&ina, sizeof(struct in_addr));
1162	if (strrchr(s, '/') != NULL) {
1163		if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
1164			return (NULL);
1165	} else {
1166		if (inet_pton(AF_INET, s, &ina) != 1)
1167			return (NULL);
1168	}
1169
1170	ipa = calloc(1, sizeof(struct ipsec_addr_wrap));
1171	if (ipa == NULL)
1172		err(1, "host_v4: calloc");
1173
1174	ipa->address.v4 = ina;
1175	ipa->name = strdup(s);
1176	if (ipa->name == NULL)
1177		err(1, "host_v4: strdup");
1178	ipa->af = AF_INET;
1179
1180	set_ipmask(ipa, bits);
1181	if (bits != (ipa->af == AF_INET ? 32 : 128))
1182		ipa->netaddress = 1;
1183
1184	return (ipa);
1185}
1186
1187struct ipsec_addr_wrap *
1188host_if(const char *s, int mask)
1189{
1190	struct ipsec_addr_wrap *ipa = NULL;
1191	char			*ps;
1192
1193	if ((ps = strdup(s)) == NULL)
1194		err(1, "host_if: strdup");
1195
1196	if (ifa_exists(ps))
1197		ipa = ifa_lookup(ps);
1198
1199	free(ps);
1200	return (ipa);
1201}
1202
1203/* interface lookup routintes */
1204
1205struct addr_node	*iftab;
1206
1207void
1208ifa_load(void)
1209{
1210	struct ifaddrs		*ifap, *ifa;
1211	struct addr_node	*n = NULL, *h = NULL;
1212
1213	if (getifaddrs(&ifap) < 0)
1214		err(1, "ifa_load: getiffaddrs");
1215
1216	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1217		if (!(ifa->ifa_addr->sa_family == AF_INET ||
1218		    ifa->ifa_addr->sa_family == AF_INET6 ||
1219		    ifa->ifa_addr->sa_family == AF_LINK))
1220			continue;
1221		n = calloc(1, sizeof(struct addr_node));
1222		if (n == NULL)
1223			err(1, "ifa_load: calloc");
1224		n->af = ifa->ifa_addr->sa_family;
1225		if ((n->addr.name = strdup(ifa->ifa_name)) == NULL)
1226			err(1, "ifa_load: strdup");
1227		if (n->af == AF_INET) {
1228			n->addr.af = AF_INET;
1229			memcpy(&n->addr.address.v4, &((struct sockaddr_in *)
1230			    ifa->ifa_addr)->sin_addr.s_addr,
1231			    sizeof(struct in_addr));
1232			memcpy(&n->addr.mask.v4, &((struct sockaddr_in *)
1233			    ifa->ifa_netmask)->sin_addr.s_addr,
1234			    sizeof(struct in_addr));
1235		} else if (n->af == AF_INET6) {
1236			n->addr.af = AF_INET6;
1237			memcpy(&n->addr.address.v6, &((struct sockaddr_in6 *)
1238			    ifa->ifa_addr)->sin6_addr.s6_addr,
1239			    sizeof(struct in6_addr));
1240			memcpy(&n->addr.mask.v6, &((struct sockaddr_in6 *)
1241			    ifa->ifa_netmask)->sin6_addr.s6_addr,
1242			    sizeof(struct in6_addr));
1243		}
1244		if ((n->addr.name = strdup(ifa->ifa_name)) == NULL)
1245			err(1, "ifa_load: strdup");
1246		n->next = NULL;
1247		n->tail = n;
1248		if (h == NULL)
1249			h = n;
1250		else {
1251			h->tail->next = n;
1252			h->tail = n;
1253		}
1254	}
1255
1256	iftab = h;
1257	freeifaddrs(ifap);
1258}
1259
1260int
1261ifa_exists(const char *ifa_name)
1262{
1263	struct addr_node	*n;
1264
1265	if (iftab == NULL)
1266		ifa_load();
1267
1268	for (n = iftab; n; n = n->next) {
1269		if (n->af == AF_LINK && !strncmp(n->addr.name, ifa_name,
1270		    IFNAMSIZ))
1271			return (1);
1272	}
1273
1274	return (0);
1275}
1276
1277struct ipsec_addr_wrap *
1278ifa_lookup(const char *ifa_name)
1279{
1280	struct addr_node	*p = NULL;
1281	struct ipsec_addr_wrap	*ipa = NULL;
1282
1283	if (iftab == NULL)
1284		ifa_load();
1285
1286	for (p = iftab; p; p = p->next) {
1287		if (p->af != AF_INET)
1288			continue;
1289		if (strncmp(p->addr.name, ifa_name, IFNAMSIZ))
1290			continue;
1291		ipa = calloc(1, sizeof(struct ipsec_addr_wrap));
1292		if (ipa == NULL)
1293			err(1, "ifa_lookup: calloc");
1294		memcpy(ipa, &p->addr, sizeof(struct ipsec_addr_wrap));
1295		if ((ipa->name = strdup(p->addr.name)) == NULL)
1296			err(1, "ifa_lookup: strdup");
1297		set_ipmask(ipa, 32);
1298		break;
1299	}
1300
1301	return (ipa);
1302}
1303
1304void
1305set_ipmask(struct ipsec_addr_wrap *address, u_int8_t b)
1306{
1307	struct ipsec_addr	*ipa;
1308	int			 i, j = 0;
1309
1310	ipa = &address->mask;
1311	bzero(ipa, sizeof(struct ipsec_addr));
1312
1313	while (b >= 32) {
1314		ipa->addr32[j++] = 0xffffffff;
1315		b -= 32;
1316	}
1317	for (i = 31; i > 31 - b; --i)
1318		ipa->addr32[j] |= (1 << i);
1319	if (b)
1320		ipa->addr32[j] = htonl(ipa->addr32[j]);
1321}
1322
1323struct ipsec_addr_wrap *
1324copyhost(const struct ipsec_addr_wrap *src)
1325{
1326	struct ipsec_addr_wrap *dst;
1327
1328	dst = calloc(1, sizeof(struct ipsec_addr_wrap));
1329	if (dst == NULL)
1330		err(1, "copyhost: calloc");
1331
1332	memcpy(dst, src, sizeof(struct ipsec_addr_wrap));
1333
1334	if ((dst->name = strdup(src->name)) == NULL)
1335		err(1, "copyhost: strdup");
1336
1337	return dst;
1338}
1339
1340const struct ipsec_xf *
1341parse_xf(const char *name, const struct ipsec_xf xfs[])
1342{
1343	int		i;
1344
1345	for (i = 0; xfs[i].name != NULL; i++) {
1346		if (strncmp(name, xfs[i].name, strlen(name)))
1347			continue;
1348		return &xfs[i];
1349	}
1350	return (NULL);
1351}
1352
1353struct ipsec_transforms *
1354copytransforms(const struct ipsec_transforms *xfs)
1355{
1356	struct ipsec_transforms *newxfs;
1357
1358	if (xfs == NULL)
1359		return (NULL);
1360
1361	newxfs = calloc(1, sizeof(struct ipsec_transforms));
1362	if (newxfs == NULL)
1363		err(1, "copytransforms: calloc");
1364
1365	memcpy(newxfs, xfs, sizeof(struct ipsec_transforms));
1366	return (newxfs);
1367}
1368
1369int
1370validate_sa(u_int32_t spi, u_int8_t protocol, struct ipsec_transforms *xfs,
1371    struct ipsec_key *authkey, struct ipsec_key *enckey, u_int8_t tmode)
1372{
1373	/* Sanity checks */
1374	if (spi == 0) {
1375		yyerror("no SPI specified");
1376		return (0);
1377	}
1378	if (protocol == IPSEC_AH) {
1379		if (!xfs) {
1380			yyerror("no transforms specified");
1381			return (0);
1382		}
1383		if (!xfs->authxf)
1384			xfs->authxf = &authxfs[AUTHXF_HMAC_SHA2_256];
1385		if (xfs->encxf) {
1386			yyerror("ah does not provide encryption");
1387			return (0);
1388		}
1389		if (xfs->compxf) {
1390			yyerror("ah does not provide compression");
1391			return (0);
1392		}
1393	}
1394	if (protocol == IPSEC_ESP) {
1395		if (!xfs) {
1396			yyerror("no transforms specified");
1397			return (0);
1398		}
1399		if (xfs->compxf) {
1400			yyerror("esp does not provide compression");
1401			return (0);
1402		}
1403		if (!xfs->authxf)
1404			xfs->authxf = &authxfs[AUTHXF_HMAC_SHA2_256];
1405		if (!xfs->encxf)
1406			xfs->encxf = &encxfs[ENCXF_AESCTR];
1407	}
1408	if (protocol == IPSEC_IPCOMP) {
1409		if (!xfs) {
1410			yyerror("no transform specified");
1411			return (0);
1412		}
1413		if (xfs->authxf || xfs->encxf) {
1414			yyerror("no encryption or authenticaion with ipcomp");
1415			return (0);
1416		}
1417		if (!xfs->compxf)
1418			xfs->compxf = &compxfs[COMPXF_DEFLATE];
1419	}
1420	if (protocol == IPSEC_IPIP) {
1421		if (!xfs) {
1422			yyerror("no transform specified");
1423			return (0);
1424		}
1425		if (xfs->authxf || xfs->encxf || xfs->compxf) {
1426			yyerror("no encryption, authenticaion or compression"
1427			    " with ipip");
1428			return (0);
1429		}
1430	}
1431	if (protocol == IPSEC_TCPMD5 && authkey == NULL && tmode !=
1432	    IPSEC_TRANSPORT) {
1433		yyerror("authentication key needed for tcpmd5");
1434		return (0);
1435	}
1436	if (xfs && xfs->authxf) {
1437		if (!authkey) {
1438			yyerror("no authentication key specified");
1439			return (0);
1440		}
1441		if (authkey->len != xfs->authxf->keymin) {
1442			yyerror("wrong authentication key length, needs to be "
1443			    "%d bits", xfs->authxf->keymin * 8);
1444			return (0);
1445		}
1446	}
1447	if (xfs && xfs->encxf) {
1448		if (!enckey && xfs->encxf != &encxfs[ENCXF_NULL]) {
1449			yyerror("no encryption key specified");
1450			return (0);
1451		}
1452		if (enckey) {
1453			if (enckey->len < xfs->encxf->keymin) {
1454				yyerror("encryption key too short, "
1455				    "minimum %d bits", xfs->encxf->keymin * 8);
1456				return (0);
1457			}
1458			if (xfs->encxf->keymax < enckey->len) {
1459				yyerror("encryption key too long, "
1460				    "maximum %d bits", xfs->encxf->keymax * 8);
1461				return (0);
1462			}
1463		}
1464	}
1465
1466	return 1;
1467}
1468
1469struct ipsec_rule *
1470create_sa(u_int8_t protocol, u_int8_t tmode, struct ipsec_addr_wrap *src, struct
1471    ipsec_addr_wrap *dst, u_int32_t spi, struct ipsec_transforms *xfs,
1472    struct ipsec_key *authkey, struct ipsec_key *enckey)
1473{
1474	struct ipsec_rule *r;
1475
1476	if (validate_sa(spi, protocol, xfs, authkey, enckey, tmode) == 0)
1477		return (NULL);
1478
1479	r = calloc(1, sizeof(struct ipsec_rule));
1480	if (r == NULL)
1481		err(1, "create_sa: calloc");
1482
1483	r->type |= RULE_SA;
1484	r->proto = protocol;
1485	r->tmode = tmode;
1486	r->src = src;
1487	r->dst = dst;
1488	r->spi = spi;
1489	r->xfs = xfs;
1490	r->authkey = authkey;
1491	r->enckey = enckey;
1492
1493	return r;
1494}
1495
1496struct ipsec_rule *
1497reverse_sa(struct ipsec_rule *rule, u_int32_t spi, struct ipsec_key *authkey,
1498    struct ipsec_key *enckey)
1499{
1500	struct ipsec_rule *reverse;
1501
1502	if (validate_sa(spi, rule->proto, rule->xfs, authkey, enckey,
1503	    rule->tmode) == 0)
1504		return (NULL);
1505
1506	reverse = calloc(1, sizeof(struct ipsec_rule));
1507	if (reverse == NULL)
1508		err(1, "reverse_sa: calloc");
1509
1510	reverse->type |= RULE_SA;
1511	reverse->proto = rule->proto;
1512	reverse->tmode = rule->tmode;
1513	reverse->src = copyhost(rule->dst);
1514	reverse->dst = copyhost(rule->src);
1515	reverse->spi = spi;
1516	reverse->xfs = copytransforms(rule->xfs);
1517	reverse->authkey = authkey;
1518	reverse->enckey = enckey;
1519
1520	return (reverse);
1521}
1522
1523struct ipsec_rule *
1524create_flow(u_int8_t dir, struct ipsec_addr_wrap *src, struct ipsec_addr_wrap
1525    *dst, struct ipsec_addr_wrap *local, struct ipsec_addr_wrap *peer,
1526    u_int8_t proto, char *srcid, char *dstid, u_int8_t type)
1527{
1528	struct ipsec_rule *r;
1529
1530	r = calloc(1, sizeof(struct ipsec_rule));
1531	if (r == NULL)
1532		err(1, "create_flow: calloc");
1533
1534	r->type |= RULE_FLOW;
1535
1536	if (dir == IPSEC_INOUT)
1537		r->direction = IPSEC_OUT;
1538	else
1539		r->direction = dir;
1540
1541	r->proto = proto;
1542	r->src = src;
1543	r->dst = dst;
1544
1545	if (type != TYPE_UNKNOWN) {
1546		r->flowtype = type;
1547		return (r);
1548	}
1549
1550	if (r->direction == IPSEC_IN)
1551		r->flowtype = TYPE_USE;
1552	else
1553		r->flowtype = TYPE_REQUIRE;
1554
1555	r->local = local;
1556	if (peer == NULL) {
1557		/* Set peer to remote host.  Must be a host address. */
1558		if (r->direction == IPSEC_IN) {
1559			if (r->src->netaddress) {
1560				yyerror("no peer specified");
1561				goto errout;
1562			}
1563			r->peer = copyhost(r->src);
1564		} else {
1565			if (r->dst->netaddress) {
1566				yyerror("no peer specified");
1567				goto errout;
1568			}
1569			r->peer = copyhost(r->dst);
1570		}
1571	} else
1572		r->peer = peer;
1573
1574	r->auth = calloc(1, sizeof(struct ipsec_auth));
1575	if (r->auth == NULL)
1576		err(1, "create_flow: calloc");
1577	r->auth->srcid = srcid;
1578	r->auth->dstid = dstid;
1579	r->auth->idtype = ID_FQDN;	/* XXX For now only FQDN. */
1580
1581	return r;
1582
1583errout:
1584	free(r);
1585	if (srcid)
1586		free(srcid);
1587	if (dstid)
1588		free(dstid);
1589	free(src);
1590	free(dst);
1591
1592	return NULL;
1593}
1594
1595struct ipsec_rule *
1596reverse_rule(struct ipsec_rule *rule)
1597{
1598	struct ipsec_rule *reverse;
1599
1600	reverse = calloc(1, sizeof(struct ipsec_rule));
1601	if (reverse == NULL)
1602		err(1, "reverse_rule: calloc");
1603
1604	reverse->type |= RULE_FLOW;
1605
1606	if (rule->direction == (u_int8_t)IPSEC_OUT) {
1607		reverse->direction = (u_int8_t)IPSEC_IN;
1608		reverse->flowtype = TYPE_USE;
1609	} else {
1610		reverse->direction = (u_int8_t)IPSEC_OUT;
1611		reverse->flowtype = TYPE_REQUIRE;
1612	}
1613
1614	reverse->src = copyhost(rule->dst);
1615	reverse->dst = copyhost(rule->src);
1616	if (rule->local)
1617		reverse->local = copyhost(rule->local);
1618	reverse->peer = copyhost(rule->peer);
1619	reverse->proto = (u_int8_t)rule->proto;
1620
1621	reverse->auth = calloc(1, sizeof(struct ipsec_auth));
1622	if (reverse->auth == NULL)
1623		err(1, "reverse_rule: calloc");
1624	if (rule->auth->dstid && (reverse->auth->dstid =
1625	    strdup(rule->auth->dstid)) == NULL)
1626		err(1, "reverse_rule: strdup");
1627	if (rule->auth->srcid && (reverse->auth->srcid =
1628	    strdup(rule->auth->srcid)) == NULL)
1629		err(1, "reverse_rule: strdup");
1630	reverse->auth->idtype = rule->auth->idtype;
1631	reverse->auth->type = rule->auth->type;
1632
1633	return reverse;
1634}
1635
1636struct ipsec_rule *
1637create_ike(struct ipsec_addr_wrap *src, struct ipsec_addr_wrap *dst, struct
1638    ipsec_addr_wrap * peer, struct ipsec_transforms *mmxfs, struct
1639    ipsec_transforms *qmxfs, u_int8_t proto, u_int8_t mode, char *srcid, char
1640    *dstid, struct ike_auth *authtype)
1641{
1642	struct ipsec_rule *r;
1643
1644	r = calloc(1, sizeof(struct ipsec_rule));
1645	if (r == NULL)
1646		err(1, "create_ike: calloc");
1647
1648	r->type = RULE_IKE;
1649
1650	r->src = src;
1651	r->dst = dst;
1652
1653	if (peer == NULL) {
1654		/* Set peer to remote host.  Must be a host address. */
1655		if (r->direction == IPSEC_IN) {
1656			if (r->src->netaddress) {
1657				yyerror("no peer specified");
1658				goto errout;
1659			}
1660			r->peer = copyhost(r->src);
1661		} else {
1662			if (r->dst->netaddress) {
1663				yyerror("no peer specified");
1664				goto errout;
1665			}
1666			r->peer = copyhost(r->dst);
1667		}
1668	} else
1669		r->peer = peer;
1670
1671	r->proto = proto;
1672	r->ikemode = mode;
1673	r->mmxfs = mmxfs;
1674	r->qmxfs = qmxfs;
1675	r->auth = calloc(1, sizeof(struct ipsec_auth));
1676	if (r->auth == NULL)
1677		err(1, "create_ike: calloc");
1678	r->auth->srcid = srcid;
1679	r->auth->dstid = dstid;
1680	r->auth->idtype = ID_FQDN;	/* XXX For now only FQDN. */
1681	r->ikeauth = calloc(1, sizeof(struct ike_auth));
1682	if (r->ikeauth == NULL)
1683		err(1, "create_ike: calloc");
1684	r->ikeauth->type = authtype->type;
1685	r->ikeauth->string = authtype->string;
1686
1687	return (r);
1688
1689errout:
1690	free(r);
1691	if (srcid)
1692		free(srcid);
1693	if (dstid)
1694		free(dstid);
1695	free(src);
1696	free(dst);
1697	if (authtype->string)
1698		free(authtype->string);
1699
1700	return (NULL);
1701}
1702