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