parse.y revision 1.15
1/*	$OpenBSD: parse.y,v 1.15 2005/08/02 15:47:25 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/queue.h>
26#include <sys/socket.h>
27#include <sys/stat.h>
28#include <netinet/in.h>
29#include <netinet/ip_ipsp.h>
30#include <arpa/inet.h>
31
32#include <ctype.h>
33#include <err.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <limits.h>
37#include <stdarg.h>
38#include <stdio.h>
39#include <string.h>
40#include <syslog.h>
41#include <unistd.h>
42
43#include "ipsecctl.h"
44
45#define KEYSIZE_LIMIT	1024
46
47static struct ipsecctl	*ipsec = NULL;
48static FILE		*fin = NULL;
49static int		 lineno = 1;
50static int		 errors = 0;
51static int		 debug = 0;
52
53int			 yyerror(const char *, ...);
54int			 yyparse(void);
55int			 kw_cmp(const void *, const void *);
56int			 lookup(char *);
57int			 lgetc(FILE *);
58int			 lungetc(int);
59int			 findeol(void);
60int			 yylex(void);
61
62TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
63struct sym {
64	TAILQ_ENTRY(sym)	 entries;
65	int		 used;
66	int		 persist;
67	char		*nam;
68	char		*val;
69};
70
71int			 symset(const char *, const char *, int);
72int			 cmdline_symset(char *);
73char			*symget(const char *);
74int			 atoul(char *, u_long *);
75int			 atospi(char *, u_int32_t *);
76u_int8_t		 x2i(unsigned char *);
77struct ipsec_key	*parsekey(unsigned char *, size_t);
78struct ipsec_addr	*host(const char *);
79struct ipsec_addr	*copyhost(const struct ipsec_addr *);
80struct ipsec_rule	*create_sa(struct ipsec_addr *, struct ipsec_addr *,
81			 u_int32_t, struct ipsec_key *);
82
83struct ipsec_rule	*reverse_sa(struct ipsec_rule *, u_int32_t,
84			     struct ipsec_key *);
85struct ipsec_rule	*create_flow(u_int8_t, struct ipsec_addr *, struct
86			     ipsec_addr *, struct ipsec_addr *, u_int8_t,
87			     char *, char *, u_int16_t);
88struct ipsec_rule	*reverse_rule(struct ipsec_rule *);
89
90typedef struct {
91	union {
92		u_int32_t	 number;
93		u_int8_t	 dir;
94		char		*string;
95		int		 log;
96		u_int8_t	 protocol;
97		struct {
98			struct ipsec_addr *src;
99			struct ipsec_addr *dst;
100		} hosts;
101		struct ipsec_addr *peer;
102		struct ipsec_addr *host;
103		struct {
104			char *srcid;
105			char *dstid;
106		} ids;
107		char		*id;
108		u_int16_t	 authtype;
109		struct {
110			u_int32_t	spiout;
111			u_int32_t	spiin;
112		} spis;
113		struct {
114			struct ipsec_key *keyout;
115			struct ipsec_key *keyin;
116		} keys;
117	} v;
118	int lineno;
119} YYSTYPE;
120
121%}
122
123%token	FLOW FROM ESP AH IN PEER ON OUT TO SRCID DSTID RSA PSK TCPMD5 SPI KEY
124%token	KEYFILE ERROR
125%token	<v.string>		STRING
126%type	<v.dir>			dir
127%type	<v.protocol>		protocol
128%type	<v.number>		number
129%type	<v.hosts>		hosts
130%type	<v.peer>		peer
131%type	<v.host>		host
132%type	<v.ids>			ids
133%type	<v.id>			id
134%type	<v.authtype>		authtype
135%type	<v.spis>		spispec
136%type	<v.keys>		keyspec
137%%
138
139grammar		: /* empty */
140		| grammar '\n'
141		| grammar flowrule '\n'
142		| grammar tcpmd5rule '\n'
143		| grammar error '\n'		{ errors++; }
144		;
145
146number		: STRING			{
147			unsigned long	ulval;
148
149			if (atoul($1, &ulval) == -1) {
150				yyerror("%s is not a number", $1);
151				free($1);
152				YYERROR;
153			}
154			if (ulval > UINT_MAX) {
155				yyerror("0x%lx out of range", ulval);
156				free($1);
157				YYERROR;
158			}
159			$$ = (u_int32_t)ulval;
160			free($1);
161		}
162
163flowrule	: FLOW ipsecrule		{ }
164		;
165
166tcpmd5rule	: TCPMD5 hosts spispec keyspec	{
167			struct ipsec_rule	*r;
168
169			r = create_sa($2.src, $2.dst, $3.spiout, $4.keyout);
170			if (r == NULL)
171				YYERROR;
172			r->nr = ipsec->rule_nr++;
173
174			if (ipsecctl_add_rule(ipsec, r))
175				errx(1, "tcpmd5rule: ipsecctl_add_rule");
176
177			/* Create and add reverse SA rule. */
178			if ($3.spiin != 0 || $4.keyin != NULL) {
179				r = reverse_sa(r, $3.spiin, $4.keyin);
180				if (r == NULL)
181					YYERROR;
182				r->nr = ipsec->rule_nr++;
183
184				if (ipsecctl_add_rule(ipsec, r))
185					errx(1, "tcpmd5rule: ipsecctl_add_rule");
186			}
187		}
188		;
189
190ipsecrule	: protocol dir hosts peer ids authtype	{
191			struct ipsec_rule	*r;
192
193			r = create_flow($2, $3.src, $3.dst, $4, $1, $5.srcid,
194			    $5.dstid, $6);
195			if (r == NULL)
196				YYERROR;
197			r->nr = ipsec->rule_nr++;
198
199			if (ipsecctl_add_rule(ipsec, r))
200				errx(1, "ipsecrule: ipsecctl_add_rule");
201
202			/* Create and add reverse flow rule. */
203			if ($2 == IPSEC_INOUT) {
204				r = reverse_rule(r);
205				r->nr = ipsec->rule_nr++;
206
207				if (ipsecctl_add_rule(ipsec, r))
208					errx(1, "ipsecrule: ipsecctl_add_rule");
209			}
210		}
211		;
212
213protocol	: /* empty */			{ $$ = IPSEC_ESP; }
214		| ESP				{ $$ = IPSEC_ESP; }
215		| AH				{ $$ = IPSEC_AH; }
216		;
217
218dir		: /* empty */			{ $$ = IPSEC_INOUT; }
219		| IN				{ $$ = IPSEC_IN; }
220		| OUT				{ $$ = IPSEC_OUT; }
221		;
222
223hosts		: FROM host TO host		{
224			$$.src = $2;
225			$$.dst = $4;
226		}
227		;
228
229peer		: /* empty */			{ $$ = NULL; }
230		| PEER STRING			{
231			if (($$ = host($2)) == NULL) {
232				free($2);
233				yyerror("could not parse host specification");
234				YYERROR;
235			}
236			free($2);
237		}
238		;
239
240host		: STRING			{
241			if (($$ = host($1)) == NULL) {
242				free($1);
243				yyerror("could not parse host specification");
244				YYERROR;
245			}
246			free($1);
247		}
248		| STRING '/' number		{
249			char	*buf;
250
251			if (asprintf(&buf, "%s/%u", $1, $3) == -1)
252				err(1, "host: asprintf");
253			free($1);
254			if (($$ = host(buf)) == NULL)	{
255				free(buf);
256				yyerror("could not parse host specification");
257				YYERROR;
258			}
259			free(buf);
260		}
261		;
262
263ids		: /* empty */			{
264			$$.srcid = NULL;
265			$$.dstid = NULL;
266		}
267		| SRCID id DSTID id		{
268			$$.srcid = $2;
269			$$.dstid = $4;
270		}
271		| SRCID id			{
272			$$.srcid = $2;
273			$$.dstid = NULL;
274		}
275		| DSTID id			{
276			$$.srcid = NULL;
277			$$.dstid = $2;
278		}
279		;
280
281id		: STRING			{ $$ = $1; }
282		;
283
284authtype	: /* empty */			{ $$ = 0; }
285		| RSA				{ $$ = AUTH_RSA; }
286		| PSK				{ $$ = AUTH_PSK; }
287		;
288
289spispec		: SPI STRING			{
290			u_int32_t	 spi;
291			char		*p = strchr($2, ':');
292
293			if (p != NULL) {
294				*p++ = 0;
295
296				if (atospi(p, &spi) == -1) {
297					yyerror("%s is not a valid spi", p);
298					free($2);
299					YYERROR;
300				}
301				$$.spiin = spi;
302			}
303			if (atospi($2, &spi) == -1) {
304				yyerror("%s is not a valid spi", $2);
305				free($2);
306				YYERROR;
307			}
308			$$.spiout = spi;
309
310
311			free($2);
312		}
313		;
314
315keyspec		: /* empty */			{
316			$$.keyout = NULL;
317			$$.keyin = NULL;
318		}
319		| KEY STRING			{
320			unsigned char	*hex;
321			unsigned char	*p = strchr($2, ':');
322
323			if (p != NULL ) {
324				*p++ = 0;
325
326				if (!strncmp(p, "0x", 2))
327					p += 2;
328				$$.keyin = parsekey(p, strlen(p));
329			}
330
331			hex = $2;
332			if (!strncmp(hex, "0x", 2))
333				hex += 2;
334			$$.keyout = parsekey(hex, strlen(hex));
335
336			free($2);
337		}
338		| KEYFILE STRING		{
339			struct stat	 sb;
340			int		 fd;
341			unsigned char	*hex;
342
343			if (stat($2, &sb) < 0)
344				err(1, "stat");
345			if ((sb.st_size > KEYSIZE_LIMIT) || (sb.st_size == 0))
346				errx(1, "key too %s", sb.st_size ? "large" :
347				    "small");
348			if ((hex = calloc(sb.st_size, sizeof(unsigned char)))
349			    == NULL)
350				err(1, "calloc");
351			if ((fd = open($2, O_RDONLY)) < 0)
352				err(1, "open");
353			if (read(fd, hex, sb.st_size) < sb.st_size)
354				err(1, "read");
355			close(fd);
356			$$.keyout = parsekey(hex, sb.st_size);
357
358			free($2);
359		}
360		;
361%%
362
363struct keywords {
364	const char	*k_name;
365	int		 k_val;
366};
367
368int
369yyerror(const char *fmt, ...)
370{
371	va_list		 ap;
372	extern char 	*infile;
373
374	errors = 1;
375	va_start(ap, fmt);
376	fprintf(stderr, "%s: %d: ", infile, yyval.lineno);
377	vfprintf(stderr, fmt, ap);
378	fprintf(stderr, "\n");
379	va_end(ap);
380	return (0);
381}
382
383int
384kw_cmp(const void *k, const void *e)
385{
386	return (strcmp(k, ((const struct keywords *)e)->k_name));
387}
388
389int
390lookup(char *s)
391{
392	/* this has to be sorted always */
393	static const struct keywords keywords[] = {
394		{ "ah",			AH},
395		{ "dstid",		DSTID},
396		{ "esp",		ESP},
397		{ "flow",		FLOW},
398		{ "from",		FROM},
399		{ "in",			IN},
400		{ "key",		KEY},
401		{ "keyfile",		KEYFILE},
402		{ "out",		OUT},
403		{ "peer",		PEER},
404		{ "psk",		PSK},
405		{ "rsa",		RSA},
406		{ "spi",		SPI},
407		{ "srcid",		SRCID},
408		{ "tcpmd5",		TCPMD5},
409		{ "to",			TO},
410	};
411	const struct keywords	*p;
412
413	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
414	    sizeof(keywords[0]), kw_cmp);
415
416	if (p) {
417		if (debug > 1)
418			fprintf(stderr, "%s: %d\n", s, p->k_val);
419		return (p->k_val);
420	} else {
421		if (debug > 1)
422			fprintf(stderr, "string: %s\n", s);
423		return (STRING);
424	}
425}
426
427#define MAXPUSHBACK	128
428
429char	*parsebuf;
430int	 parseindex;
431char	 pushback_buffer[MAXPUSHBACK];
432int	 pushback_index = 0;
433
434int
435lgetc(FILE *f)
436{
437	int	c, next;
438
439	if (parsebuf) {
440		/* Read character from the parsebuffer instead of input. */
441		if (parseindex >= 0) {
442			c = parsebuf[parseindex++];
443			if (c != '\0')
444				return (c);
445			parsebuf = NULL;
446		} else
447			parseindex++;
448	}
449
450	if (pushback_index)
451		return (pushback_buffer[--pushback_index]);
452
453	while ((c = getc(f)) == '\\') {
454		next = getc(f);
455		if (next != '\n') {
456			if (isspace(next))
457				yyerror("whitespace after \\");
458			ungetc(next, f);
459			break;
460		}
461		yylval.lineno = lineno;
462		lineno++;
463	}
464	if (c == '\t' || c == ' ') {
465		/* Compress blanks to a single space. */
466		do {
467			c = getc(f);
468		} while (c == '\t' || c == ' ');
469		ungetc(c, f);
470		c = ' ';
471	}
472
473	return (c);
474}
475
476int
477lungetc(int c)
478{
479	if (c == EOF)
480		return (EOF);
481	if (parsebuf) {
482		parseindex--;
483		if (parseindex >= 0)
484			return (c);
485	}
486	if (pushback_index < MAXPUSHBACK-1)
487		return (pushback_buffer[pushback_index++] = c);
488	else
489		return (EOF);
490}
491
492int
493findeol(void)
494{
495	int	c;
496
497	parsebuf = NULL;
498	pushback_index = 0;
499
500	/* skip to either EOF or the first real EOL */
501	while (1) {
502		c = lgetc(fin);
503		if (c == '\n') {
504			lineno++;
505			break;
506		}
507		if (c == EOF)
508			break;
509	}
510	return (ERROR);
511}
512
513int
514yylex(void)
515{
516	char	 buf[8096];
517	char	*p, *val;
518	int	 endc, c;
519	int	 token;
520
521top:
522	p = buf;
523	while ((c = lgetc(fin)) == ' ')
524		; /* nothing */
525
526	yylval.lineno = lineno;
527	if (c == '#')
528		while ((c = lgetc(fin)) != '\n' && c != EOF)
529			; /* nothing */
530	if (c == '$' && parsebuf == NULL) {
531		while (1) {
532			if ((c = lgetc(fin)) == EOF)
533				return (0);
534
535			if (p + 1 >= buf + sizeof(buf) - 1) {
536				yyerror("string too long");
537				return (findeol());
538			}
539			if (isalnum(c) || c == '_') {
540				*p++ = (char)c;
541				continue;
542			}
543			*p = '\0';
544			lungetc(c);
545			break;
546		}
547		val = symget(buf);
548		if (val == NULL) {
549			yyerror("macro \"%s\" not defined", buf);
550			return (findeol());
551		}
552		parsebuf = val;
553		parseindex = 0;
554		goto top;
555	}
556
557	switch (c) {
558	case '\'':
559	case '"':
560		endc = c;
561		while (1) {
562			if ((c = lgetc(fin)) == EOF)
563				return (0);
564			if (c == endc) {
565				*p = '\0';
566				break;
567			}
568			if (c == '\n') {
569				lineno++;
570				continue;
571			}
572			if (p + 1 >= buf + sizeof(buf) - 1) {
573				yyerror("string too long");
574				return (findeol());
575			}
576			*p++ = (char)c;
577		}
578		yylval.v.string = strdup(buf);
579		if (yylval.v.string == NULL)
580			err(1, "yylex: strdup");
581		return (STRING);
582	}
583
584#define allowed_in_string(x) \
585	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
586	x != '{' && x != '}' && x != '<' && x != '>' && \
587	x != '!' && x != '=' && x != '/' && x != '#' && \
588	x != ','))
589
590	if (isalnum(c) || c == ':' || c == '_' || c == '*') {
591		do {
592			*p++ = c;
593			if ((unsigned)(p-buf) >= sizeof(buf)) {
594				yyerror("string too long");
595				return (findeol());
596			}
597		} while ((c = lgetc(fin)) != EOF && (allowed_in_string(c)));
598		lungetc(c);
599		*p = '\0';
600		if ((token = lookup(buf)) == STRING)
601			if ((yylval.v.string = strdup(buf)) == NULL)
602				err(1, "yylex: strdup");
603		return (token);
604	}
605	if (c == '\n') {
606		yylval.lineno = lineno;
607		lineno++;
608	}
609	if (c == EOF)
610		return (0);
611	return (c);
612}
613
614int
615parse_rules(FILE *input, struct ipsecctl *ipsecx)
616{
617	struct sym	*sym, *next;
618
619	ipsec = ipsecx;
620	fin = input;
621	lineno = 1;
622	errors = 0;
623
624	yyparse();
625
626	/* Free macros and check which have not been used. */
627	for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
628		next = TAILQ_NEXT(sym, entries);
629		free(sym->nam);
630		free(sym->val);
631		TAILQ_REMOVE(&symhead, sym, entries);
632		free(sym);
633	}
634
635	return (errors ? -1 : 0);
636}
637
638int
639symset(const char *nam, const char *val, int persist)
640{
641	struct sym	*sym;
642
643	for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
644	    sym = TAILQ_NEXT(sym, entries))
645		;	/* nothing */
646
647	if (sym != NULL) {
648		if (sym->persist == 1)
649			return (0);
650		else {
651			free(sym->nam);
652			free(sym->val);
653			TAILQ_REMOVE(&symhead, sym, entries);
654			free(sym);
655		}
656	}
657	if ((sym = calloc(1, sizeof(*sym))) == NULL)
658		return (-1);
659
660	sym->nam = strdup(nam);
661	if (sym->nam == NULL) {
662		free(sym);
663		return (-1);
664	}
665	sym->val = strdup(val);
666	if (sym->val == NULL) {
667		free(sym->nam);
668		free(sym);
669		return (-1);
670	}
671	sym->used = 0;
672	sym->persist = persist;
673	TAILQ_INSERT_TAIL(&symhead, sym, entries);
674	return (0);
675}
676
677int
678cmdline_symset(char *s)
679{
680	char	*sym, *val;
681	int	ret;
682	size_t	len;
683
684	if ((val = strrchr(s, '=')) == NULL)
685		return (-1);
686
687	len = strlen(s) - strlen(val) + 1;
688	if ((sym = malloc(len)) == NULL)
689		err(1, "cmdline_symset: malloc");
690
691	strlcpy(sym, s, len);
692
693	ret = symset(sym, val + 1, 1);
694	free(sym);
695
696	return (ret);
697}
698
699char *
700symget(const char *nam)
701{
702	struct sym	*sym;
703
704	TAILQ_FOREACH(sym, &symhead, entries)
705		if (strcmp(nam, sym->nam) == 0) {
706			sym->used = 1;
707			return (sym->val);
708		}
709	return (NULL);
710}
711
712int
713atoul(char *s, u_long *ulvalp)
714{
715	u_long	 ulval;
716	char	*ep;
717
718	errno = 0;
719	ulval = strtoul(s, &ep, 0);
720	if (s[0] == '\0' || *ep != '\0')
721		return (-1);
722	if (errno == ERANGE && ulval == ULONG_MAX)
723		return (-1);
724	*ulvalp = ulval;
725	return (0);
726}
727
728int
729atospi(char *s, u_int32_t *spivalp)
730{
731	unsigned long	ulval;
732
733	if (atoul(s, &ulval) == -1)
734		return (-1);
735	if (ulval >= SPI_RESERVED_MIN && ulval <= SPI_RESERVED_MAX)
736		return (-1);
737	*spivalp = ulval;
738	return (0);
739}
740
741u_int8_t
742x2i(unsigned char *s)
743{
744	char	ss[3];
745
746	ss[0] = s[0];
747	ss[1] = s[1];
748	ss[2] = 0;
749
750	if (!isxdigit(s[0]) || !isxdigit(s[1])) {
751		yyerror("keys need to be specified in hex digits");
752		return -1;
753	}
754	return ((u_int8_t)strtoul(ss, NULL, 16));
755}
756
757struct ipsec_key *
758parsekey(unsigned char *hexkey, size_t len)
759{
760	struct ipsec_key *key;
761	int		  i;
762
763	key = calloc(1, sizeof(struct ipsec_key));
764	if (key == NULL)
765		err(1, "calloc");
766
767	key->len = len / 2;
768	key->data = calloc(key->len, sizeof(u_int8_t));
769	if (key->data == NULL)
770		err(1, "calloc");
771
772	for (i = 0; i < (int)key->len; i++)
773		key->data[i] = x2i(hexkey + 2 * i);
774
775	return (key);
776}
777
778struct ipsec_addr *
779host(const char *s)
780{
781	struct ipsec_addr	*ipa;
782	int			 i, bits = 32;
783
784	/* XXX for now only AF_INET. */
785
786	ipa = calloc(1, sizeof(struct ipsec_addr));
787	if (ipa == NULL)
788		err(1, "calloc");
789
790	if (strrchr(s, '/') != NULL) {
791		bits = inet_net_pton(AF_INET, s, &ipa->v4, sizeof(ipa->v4));
792		if (bits == -1 || bits > 32) {
793			free(ipa);
794			return(NULL);
795		}
796	} else {
797		if (inet_pton(AF_INET, s, &ipa->v4) != 1) {
798			free(ipa);
799			return NULL;
800		}
801	}
802
803	bzero(&ipa->v4mask, sizeof(ipa->v4mask));
804	if (bits == 32) {
805		ipa->v4mask.mask32 = 0xffffffff;
806		ipa->netaddress = 0;
807	} else {
808		for (i = 31; i > 31 - bits; i--)
809			ipa->v4mask.mask32 |= (1 << i);
810		ipa->v4mask.mask32 = htonl(ipa->v4mask.mask32);
811		ipa->netaddress = 1;
812	}
813
814	ipa->af = AF_INET;
815
816	return ipa;
817}
818
819struct ipsec_addr *
820copyhost(const struct ipsec_addr *src)
821{
822	struct ipsec_addr *dst;
823
824	dst = calloc(1, sizeof(struct ipsec_addr));
825	if (dst == NULL)
826		err(1, "calloc");
827
828	memcpy(dst, src, sizeof(struct ipsec_addr));
829	return dst;
830}
831
832struct ipsec_rule *
833create_sa(struct ipsec_addr *src, struct ipsec_addr *dst, u_int32_t spi,
834    struct ipsec_key *key)
835{
836	struct ipsec_rule *r;
837
838	if (spi == 0 || key == NULL)
839		return (NULL);
840
841	r = calloc(1, sizeof(struct ipsec_rule));
842	if (r == NULL)
843		err(1, "calloc");
844
845	r->type |= RULE_SA;
846
847	r->src = src;
848	r->dst = dst;
849	r->spi = spi;
850	r->key = key;
851
852	return r;
853}
854
855struct ipsec_rule *
856reverse_sa(struct ipsec_rule *rule, u_int32_t spi, struct ipsec_key *key)
857{
858	struct ipsec_rule *reverse;
859
860	if (spi == 0 || key == NULL)
861		return (NULL);
862
863	reverse = calloc(1, sizeof(struct ipsec_rule));
864	if (reverse == NULL)
865		err(1, "calloc");
866
867	reverse->type |= RULE_SA;
868	reverse->src = copyhost(rule->dst);
869	reverse->dst = copyhost(rule->src);
870	reverse->spi = spi;
871	reverse->key = key;
872
873	return (reverse);
874}
875
876struct ipsec_rule *
877create_flow(u_int8_t dir, struct ipsec_addr *src, struct ipsec_addr *dst,
878    struct ipsec_addr *peer, u_int8_t proto, char *srcid, char *dstid,
879    u_int16_t authtype)
880{
881	struct ipsec_rule *r;
882
883	r = calloc(1, sizeof(struct ipsec_rule));
884	if (r == NULL)
885		err(1, "calloc");
886
887	r->type |= RULE_FLOW;
888
889	if (dir == IPSEC_INOUT)
890		r->direction = IPSEC_OUT;
891	else
892		r->direction = dir;
893
894	if (r->direction == IPSEC_IN)
895		r->flowtype = TYPE_USE;
896	else
897		r->flowtype = TYPE_REQUIRE;
898
899	r->src = src;
900	r->dst = dst;
901
902	if (peer == NULL) {
903		/* Set peer to remote host.  Must be a host address. */
904		if (r->direction == IPSEC_IN) {
905			if (r->src->netaddress) {
906				yyerror("no peer specified");
907				goto errout;
908			}
909			r->peer = copyhost(r->src);
910		} else {
911			if (r->dst->netaddress) {
912				yyerror("no peer specified");
913				goto errout;
914			}
915			r->peer = copyhost(r->dst);
916		}
917	} else
918		r->peer = peer;
919
920	r->proto = proto;
921	r->auth = calloc(1, sizeof(struct ipsec_auth));
922	if (r->auth == NULL)
923		err(1, "calloc");
924	r->auth->srcid = srcid;
925	r->auth->dstid = dstid;
926	r->auth->idtype = ID_FQDN;	/* XXX For now only FQDN. */
927#ifdef notyet
928	r->auth->type = authtype;
929#endif
930
931	return r;
932
933errout:
934	free(r);
935	if (srcid)
936		free(srcid);
937	if (dstid)
938		free(dstid);
939	free(src);
940	free(dst);
941
942	return NULL;
943}
944
945struct ipsec_rule *
946reverse_rule(struct ipsec_rule *rule)
947{
948	struct ipsec_rule *reverse;
949
950	reverse = calloc(1, sizeof(struct ipsec_rule));
951	if (reverse == NULL)
952		err(1, "calloc");
953
954	reverse->type |= RULE_FLOW;
955
956	if (rule->direction == (u_int8_t)IPSEC_OUT) {
957		reverse->direction = (u_int8_t)IPSEC_IN;
958		reverse->flowtype = TYPE_USE;
959	} else {
960		reverse->direction = (u_int8_t)IPSEC_OUT;
961		reverse->flowtype = TYPE_REQUIRE;
962	}
963
964	reverse->src = copyhost(rule->dst);
965	reverse->dst = copyhost(rule->src);
966	reverse->peer = copyhost(rule->peer);
967	reverse->proto = (u_int8_t)rule->proto;
968
969	reverse->auth = calloc(1, sizeof(struct ipsec_auth));
970	if (reverse->auth == NULL)
971		err(1, "calloc");
972	if (rule->auth->dstid && (reverse->auth->dstid =
973	    strdup(rule->auth->dstid)) == NULL)
974		err(1, "strdup");
975	if (rule->auth->srcid && (reverse->auth->srcid =
976	    strdup(rule->auth->srcid)) == NULL)
977		err(1, "strdup");
978	reverse->auth->idtype = rule->auth->idtype;
979	reverse->auth->type = rule->auth->type;
980
981	return reverse;
982}
983