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