summaryrefslogtreecommitdiffstats
path: root/ipsec-tools/src/setkey/parse.y
diff options
context:
space:
mode:
Diffstat (limited to 'ipsec-tools/src/setkey/parse.y')
-rw-r--r--ipsec-tools/src/setkey/parse.y1670
1 files changed, 1670 insertions, 0 deletions
diff --git a/ipsec-tools/src/setkey/parse.y b/ipsec-tools/src/setkey/parse.y
new file mode 100644
index 00000000..fa3c45d3
--- /dev/null
+++ b/ipsec-tools/src/setkey/parse.y
@@ -0,0 +1,1670 @@
+/* $NetBSD: parse.y,v 1.14 2010/12/03 14:32:52 tteras Exp $ */
+
+/* $KAME: parse.y,v 1.81 2003/07/01 04:01:48 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+%{
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <net/pfkeyv2.h>
+#include PATH_IPSEC_H
+#include <arpa/inet.h>
+
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "libpfkey.h"
+#include "vchar.h"
+#include "extern.h"
+
+#define DEFAULT_NATT_PORT 4500
+
+#ifndef UDP_ENCAP_ESPINUDP
+#define UDP_ENCAP_ESPINUDP 2
+#endif
+
+#define ATOX(c) \
+ (isdigit((int)c) ? (c - '0') : \
+ (isupper((int)c) ? (c - 'A' + 10) : (c - 'a' + 10)))
+
+u_int32_t p_spi;
+u_int p_ext, p_alg_enc, p_alg_auth, p_replay, p_mode;
+u_int32_t p_reqid;
+u_int p_key_enc_len, p_key_auth_len;
+const char *p_key_enc;
+const char *p_key_auth;
+time_t p_lt_hard, p_lt_soft;
+size_t p_lb_hard, p_lb_soft;
+
+struct security_ctx {
+ u_int8_t doi;
+ u_int8_t alg;
+ u_int16_t len;
+ char *buf;
+};
+
+struct security_ctx sec_ctx;
+
+static u_int p_natt_type;
+static struct addrinfo * p_natt_oa = NULL;
+
+static int p_aiflags = 0, p_aifamily = PF_UNSPEC;
+
+static struct addrinfo *parse_addr __P((char *, char *));
+static int fix_portstr __P((int, vchar_t *, vchar_t *, vchar_t *));
+static int setvarbuf __P((char *, int *, struct sadb_ext *, int,
+ const void *, int));
+void parse_init __P((void));
+void free_buffer __P((void));
+
+int setkeymsg0 __P((struct sadb_msg *, unsigned int, unsigned int, size_t));
+static int setkeymsg_spdaddr __P((unsigned int, unsigned int, vchar_t *,
+ struct addrinfo *, int, struct addrinfo *, int));
+static int setkeymsg_spdaddr_tag __P((unsigned int, char *, vchar_t *));
+static int setkeymsg_addr __P((unsigned int, unsigned int,
+ struct addrinfo *, struct addrinfo *, int));
+static int setkeymsg_add __P((unsigned int, unsigned int,
+ struct addrinfo *, struct addrinfo *));
+%}
+
+%union {
+ int num;
+ unsigned long ulnum;
+ vchar_t val;
+ struct addrinfo *res;
+}
+
+%token EOT SLASH BLCL ELCL
+%token ADD GET DELETE DELETEALL FLUSH DUMP EXIT
+%token PR_ESP PR_AH PR_IPCOMP PR_ESPUDP PR_TCP
+%token F_PROTOCOL F_AUTH F_ENC F_REPLAY F_COMP F_RAWCPI
+%token F_MODE MODE F_REQID
+%token F_EXT EXTENSION NOCYCLICSEQ
+%token ALG_AUTH ALG_AUTH_NOKEY
+%token ALG_ENC ALG_ENC_NOKEY ALG_ENC_DESDERIV ALG_ENC_DES32IV ALG_ENC_OLD
+%token ALG_COMP
+%token F_LIFETIME_HARD F_LIFETIME_SOFT
+%token F_LIFEBYTE_HARD F_LIFEBYTE_SOFT
+%token DECSTRING QUOTEDSTRING HEXSTRING STRING ANY
+ /* SPD management */
+%token SPDADD SPDUPDATE SPDDELETE SPDDUMP SPDFLUSH
+%token F_POLICY PL_REQUESTS
+%token F_AIFLAGS
+%token TAGGED
+%token SECURITY_CTX
+
+%type <num> prefix protocol_spec upper_spec
+%type <num> ALG_ENC ALG_ENC_DESDERIV ALG_ENC_DES32IV ALG_ENC_OLD ALG_ENC_NOKEY
+%type <num> ALG_AUTH ALG_AUTH_NOKEY
+%type <num> ALG_COMP
+%type <num> PR_ESP PR_AH PR_IPCOMP PR_ESPUDP PR_TCP
+%type <num> EXTENSION MODE
+%type <ulnum> DECSTRING
+%type <val> PL_REQUESTS portstr key_string
+%type <val> policy_requests
+%type <val> QUOTEDSTRING HEXSTRING STRING
+%type <val> F_AIFLAGS
+%type <val> upper_misc_spec policy_spec
+%type <res> ipaddr ipandport
+
+%%
+commands
+ : /*NOTHING*/
+ | commands command
+ {
+ free_buffer();
+ parse_init();
+ }
+ ;
+
+command
+ : add_command
+ | get_command
+ | delete_command
+ | deleteall_command
+ | flush_command
+ | dump_command
+ | exit_command
+ | spdadd_command
+ | spdupdate_command
+ | spddelete_command
+ | spddump_command
+ | spdflush_command
+ ;
+ /* commands concerned with management, there is in tail of this file. */
+
+ /* add command */
+add_command
+ : ADD ipaddropts ipandport ipandport protocol_spec spi extension_spec algorithm_spec EOT
+ {
+ int status;
+
+ status = setkeymsg_add(SADB_ADD, $5, $3, $4);
+ if (status < 0)
+ return -1;
+ }
+ ;
+
+ /* delete */
+delete_command
+ : DELETE ipaddropts ipandport ipandport protocol_spec spi extension_spec EOT
+ {
+ int status;
+
+ if ($3->ai_next || $4->ai_next) {
+ yyerror("multiple address specified");
+ return -1;
+ }
+ if (p_mode != IPSEC_MODE_ANY)
+ yyerror("WARNING: mode is obsolete");
+
+ status = setkeymsg_addr(SADB_DELETE, $5, $3, $4, 0);
+ if (status < 0)
+ return -1;
+ }
+ ;
+
+ /* deleteall command */
+deleteall_command
+ : DELETEALL ipaddropts ipaddr ipaddr protocol_spec EOT
+ {
+#ifndef __linux__
+ if (setkeymsg_addr(SADB_DELETE, $5, $3, $4, 1) < 0)
+ return -1;
+#else /* __linux__ */
+ /* linux strictly adheres to RFC2367, and returns
+ * an error if we send an SADB_DELETE request without
+ * an SPI. Therefore, we must first retrieve a list
+ * of SPIs for all matching SADB entries, and then
+ * delete each one separately. */
+ u_int32_t *spi;
+ int i, n;
+
+ spi = sendkeymsg_spigrep($5, $3, $4, &n);
+ for (i = 0; i < n; i++) {
+ p_spi = spi[i];
+ if (setkeymsg_addr(SADB_DELETE,
+ $5, $3, $4, 0) < 0)
+ return -1;
+ }
+ free(spi);
+#endif /* __linux__ */
+ }
+ ;
+
+ /* get command */
+get_command
+ : GET ipaddropts ipandport ipandport protocol_spec spi extension_spec EOT
+ {
+ int status;
+
+ if (p_mode != IPSEC_MODE_ANY)
+ yyerror("WARNING: mode is obsolete");
+
+ status = setkeymsg_addr(SADB_GET, $5, $3, $4, 0);
+ if (status < 0)
+ return -1;
+ }
+ ;
+
+ /* flush */
+flush_command
+ : FLUSH protocol_spec EOT
+ {
+ struct sadb_msg msg;
+ setkeymsg0(&msg, SADB_FLUSH, $2, sizeof(msg));
+ sendkeymsg((char *)&msg, sizeof(msg));
+ }
+ ;
+
+ /* dump */
+dump_command
+ : DUMP protocol_spec EOT
+ {
+ struct sadb_msg msg;
+ setkeymsg0(&msg, SADB_DUMP, $2, sizeof(msg));
+ sendkeymsg((char *)&msg, sizeof(msg));
+ }
+ ;
+
+protocol_spec
+ : /*NOTHING*/
+ {
+ $$ = SADB_SATYPE_UNSPEC;
+ }
+ | PR_ESP
+ {
+ $$ = SADB_SATYPE_ESP;
+ if ($1 == 1)
+ p_ext |= SADB_X_EXT_OLD;
+ else
+ p_ext &= ~SADB_X_EXT_OLD;
+ }
+ | PR_AH
+ {
+ $$ = SADB_SATYPE_AH;
+ if ($1 == 1)
+ p_ext |= SADB_X_EXT_OLD;
+ else
+ p_ext &= ~SADB_X_EXT_OLD;
+ }
+ | PR_IPCOMP
+ {
+ $$ = SADB_X_SATYPE_IPCOMP;
+ }
+ | PR_ESPUDP
+ {
+ $$ = SADB_SATYPE_ESP;
+ p_ext &= ~SADB_X_EXT_OLD;
+ p_natt_oa = 0;
+ p_natt_type = UDP_ENCAP_ESPINUDP;
+ }
+ | PR_ESPUDP ipaddr
+ {
+ $$ = SADB_SATYPE_ESP;
+ p_ext &= ~SADB_X_EXT_OLD;
+ p_natt_oa = $2;
+ p_natt_type = UDP_ENCAP_ESPINUDP;
+ }
+ | PR_TCP
+ {
+#ifdef SADB_X_SATYPE_TCPSIGNATURE
+ $$ = SADB_X_SATYPE_TCPSIGNATURE;
+#endif
+ }
+ ;
+
+spi
+ : DECSTRING { p_spi = $1; }
+ | HEXSTRING
+ {
+ char *ep;
+ unsigned long v;
+
+ ep = NULL;
+ v = strtoul($1.buf, &ep, 16);
+ if (!ep || *ep) {
+ yyerror("invalid SPI");
+ return -1;
+ }
+ if (v & ~0xffffffff) {
+ yyerror("SPI too big.");
+ return -1;
+ }
+
+ p_spi = v;
+ }
+ ;
+
+algorithm_spec
+ : esp_spec
+ | ah_spec
+ | ipcomp_spec
+ ;
+
+esp_spec
+ : F_ENC enc_alg F_AUTH auth_alg
+ | F_ENC enc_alg
+ ;
+
+ah_spec
+ : F_AUTH auth_alg
+ ;
+
+ipcomp_spec
+ : F_COMP ALG_COMP
+ {
+ if ($2 < 0) {
+ yyerror("unsupported algorithm");
+ return -1;
+ }
+ p_alg_enc = $2;
+ }
+ | F_COMP ALG_COMP F_RAWCPI
+ {
+ if ($2 < 0) {
+ yyerror("unsupported algorithm");
+ return -1;
+ }
+ p_alg_enc = $2;
+ p_ext |= SADB_X_EXT_RAWCPI;
+ }
+ ;
+
+enc_alg
+ : ALG_ENC_NOKEY {
+ if ($1 < 0) {
+ yyerror("unsupported algorithm");
+ return -1;
+ }
+ p_alg_enc = $1;
+
+ p_key_enc_len = 0;
+ p_key_enc = "";
+ if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT,
+ p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) {
+ yyerror(ipsec_strerror());
+ return -1;
+ }
+ }
+ | ALG_ENC key_string {
+ if ($1 < 0) {
+ yyerror("unsupported algorithm");
+ return -1;
+ }
+ p_alg_enc = $1;
+
+ p_key_enc_len = $2.len;
+ p_key_enc = $2.buf;
+ if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT,
+ p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) {
+ yyerror(ipsec_strerror());
+ return -1;
+ }
+ }
+ | ALG_ENC_OLD {
+ if ($1 < 0) {
+ yyerror("unsupported algorithm");
+ return -1;
+ }
+ yyerror("WARNING: obsolete algorithm");
+ p_alg_enc = $1;
+
+ p_key_enc_len = 0;
+ p_key_enc = "";
+ if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT,
+ p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) {
+ yyerror(ipsec_strerror());
+ return -1;
+ }
+ }
+ | ALG_ENC_DESDERIV key_string
+ {
+ if ($1 < 0) {
+ yyerror("unsupported algorithm");
+ return -1;
+ }
+ p_alg_enc = $1;
+ if (p_ext & SADB_X_EXT_OLD) {
+ yyerror("algorithm mismatched");
+ return -1;
+ }
+ p_ext |= SADB_X_EXT_DERIV;
+
+ p_key_enc_len = $2.len;
+ p_key_enc = $2.buf;
+ if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT,
+ p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) {
+ yyerror(ipsec_strerror());
+ return -1;
+ }
+ }
+ | ALG_ENC_DES32IV key_string
+ {
+ if ($1 < 0) {
+ yyerror("unsupported algorithm");
+ return -1;
+ }
+ p_alg_enc = $1;
+ if (!(p_ext & SADB_X_EXT_OLD)) {
+ yyerror("algorithm mismatched");
+ return -1;
+ }
+ p_ext |= SADB_X_EXT_IV4B;
+
+ p_key_enc_len = $2.len;
+ p_key_enc = $2.buf;
+ if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT,
+ p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) {
+ yyerror(ipsec_strerror());
+ return -1;
+ }
+ }
+ ;
+
+auth_alg
+ : ALG_AUTH key_string {
+ if ($1 < 0) {
+ yyerror("unsupported algorithm");
+ return -1;
+ }
+ p_alg_auth = $1;
+
+ p_key_auth_len = $2.len;
+ p_key_auth = $2.buf;
+#ifdef SADB_X_AALG_TCP_MD5
+ if (p_alg_auth == SADB_X_AALG_TCP_MD5) {
+ if ((p_key_auth_len < 1) ||
+ (p_key_auth_len > 80))
+ return -1;
+ } else
+#endif
+ {
+ if (ipsec_check_keylen(SADB_EXT_SUPPORTED_AUTH,
+ p_alg_auth,
+ PFKEY_UNUNIT64(p_key_auth_len)) < 0) {
+ yyerror(ipsec_strerror());
+ return -1;
+ }
+ }
+ }
+ | ALG_AUTH_NOKEY {
+ if ($1 < 0) {
+ yyerror("unsupported algorithm");
+ return -1;
+ }
+ p_alg_auth = $1;
+
+ p_key_auth_len = 0;
+ p_key_auth = NULL;
+ }
+ ;
+
+key_string
+ : QUOTEDSTRING
+ {
+ $$ = $1;
+ }
+ | HEXSTRING
+ {
+ caddr_t pp_key;
+ caddr_t bp;
+ caddr_t yp = $1.buf;
+ int l;
+
+ l = strlen(yp) % 2 + strlen(yp) / 2;
+ if ((pp_key = malloc(l)) == 0) {
+ yyerror("not enough core");
+ return -1;
+ }
+ memset(pp_key, 0, l);
+
+ bp = pp_key;
+ if (strlen(yp) % 2) {
+ *bp = ATOX(yp[0]);
+ yp++, bp++;
+ }
+ while (*yp) {
+ *bp = (ATOX(yp[0]) << 4) | ATOX(yp[1]);
+ yp += 2, bp++;
+ }
+
+ $$.len = l;
+ $$.buf = pp_key;
+ }
+ ;
+
+extension_spec
+ : /*NOTHING*/
+ | extension_spec extension
+ ;
+
+extension
+ : F_EXT EXTENSION { p_ext |= $2; }
+ | F_EXT NOCYCLICSEQ { p_ext &= ~SADB_X_EXT_CYCSEQ; }
+ | F_MODE MODE { p_mode = $2; }
+ | F_MODE ANY { p_mode = IPSEC_MODE_ANY; }
+ | F_REQID DECSTRING { p_reqid = $2; }
+ | F_REPLAY DECSTRING
+ {
+ if ((p_ext & SADB_X_EXT_OLD) != 0) {
+ yyerror("replay prevention cannot be used with "
+ "ah/esp-old");
+ return -1;
+ }
+ p_replay = $2;
+ }
+ | F_LIFETIME_HARD DECSTRING { p_lt_hard = $2; }
+ | F_LIFETIME_SOFT DECSTRING { p_lt_soft = $2; }
+ | F_LIFEBYTE_HARD DECSTRING { p_lb_hard = $2; }
+ | F_LIFEBYTE_SOFT DECSTRING { p_lb_soft = $2; }
+ | SECURITY_CTX DECSTRING DECSTRING QUOTEDSTRING {
+ sec_ctx.doi = $2;
+ sec_ctx.alg = $3;
+ sec_ctx.len = $4.len+1;
+ sec_ctx.buf = $4.buf;
+ }
+ ;
+
+ /* definition about command for SPD management */
+ /* spdadd */
+spdadd_command
+ /* XXX merge with spdupdate ??? */
+ : SPDADD ipaddropts STRING prefix portstr STRING prefix portstr upper_spec upper_misc_spec context_spec policy_spec EOT
+ {
+ int status;
+ struct addrinfo *src, *dst;
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+ last_msg_type = SADB_X_SPDADD;
+#endif
+
+ /* fixed port fields if ulp is icmp */
+ if (fix_portstr($9, &$10, &$5, &$8))
+ return -1;
+
+ src = parse_addr($3.buf, $5.buf);
+ dst = parse_addr($6.buf, $8.buf);
+ if (!src || !dst) {
+ /* yyerror is already called */
+ return -1;
+ }
+ if (src->ai_next || dst->ai_next) {
+ yyerror("multiple address specified");
+ freeaddrinfo(src);
+ freeaddrinfo(dst);
+ return -1;
+ }
+
+ status = setkeymsg_spdaddr(SADB_X_SPDADD, $9, &$12,
+ src, $4, dst, $7);
+ freeaddrinfo(src);
+ freeaddrinfo(dst);
+ if (status < 0)
+ return -1;
+ }
+ | SPDADD TAGGED QUOTEDSTRING policy_spec EOT
+ {
+ int status;
+
+ status = setkeymsg_spdaddr_tag(SADB_X_SPDADD,
+ $3.buf, &$4);
+ if (status < 0)
+ return -1;
+ }
+ ;
+
+spdupdate_command
+ /* XXX merge with spdadd ??? */
+ : SPDUPDATE ipaddropts STRING prefix portstr STRING prefix portstr upper_spec upper_misc_spec context_spec policy_spec EOT
+ {
+ int status;
+ struct addrinfo *src, *dst;
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+ last_msg_type = SADB_X_SPDUPDATE;
+#endif
+
+ /* fixed port fields if ulp is icmp */
+ if (fix_portstr($9, &$10, &$5, &$8))
+ return -1;
+
+ src = parse_addr($3.buf, $5.buf);
+ dst = parse_addr($6.buf, $8.buf);
+ if (!src || !dst) {
+ /* yyerror is already called */
+ return -1;
+ }
+ if (src->ai_next || dst->ai_next) {
+ yyerror("multiple address specified");
+ freeaddrinfo(src);
+ freeaddrinfo(dst);
+ return -1;
+ }
+
+ status = setkeymsg_spdaddr(SADB_X_SPDUPDATE, $9, &$12,
+ src, $4, dst, $7);
+ freeaddrinfo(src);
+ freeaddrinfo(dst);
+ if (status < 0)
+ return -1;
+ }
+ | SPDUPDATE TAGGED QUOTEDSTRING policy_spec EOT
+ {
+ int status;
+
+ status = setkeymsg_spdaddr_tag(SADB_X_SPDUPDATE,
+ $3.buf, &$4);
+ if (status < 0)
+ return -1;
+ }
+ ;
+
+spddelete_command
+ : SPDDELETE ipaddropts STRING prefix portstr STRING prefix portstr upper_spec upper_misc_spec context_spec policy_spec EOT
+ {
+ int status;
+ struct addrinfo *src, *dst;
+
+ /* fixed port fields if ulp is icmp */
+ if (fix_portstr($9, &$10, &$5, &$8))
+ return -1;
+
+ src = parse_addr($3.buf, $5.buf);
+ dst = parse_addr($6.buf, $8.buf);
+ if (!src || !dst) {
+ /* yyerror is already called */
+ return -1;
+ }
+ if (src->ai_next || dst->ai_next) {
+ yyerror("multiple address specified");
+ freeaddrinfo(src);
+ freeaddrinfo(dst);
+ return -1;
+ }
+
+ status = setkeymsg_spdaddr(SADB_X_SPDDELETE, $9, &$12,
+ src, $4, dst, $7);
+ freeaddrinfo(src);
+ freeaddrinfo(dst);
+ if (status < 0)
+ return -1;
+ }
+ ;
+
+spddump_command:
+ SPDDUMP EOT
+ {
+ struct sadb_msg msg;
+ setkeymsg0(&msg, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC,
+ sizeof(msg));
+ sendkeymsg((char *)&msg, sizeof(msg));
+ }
+ ;
+
+spdflush_command
+ :
+ SPDFLUSH EOT
+ {
+ struct sadb_msg msg;
+ setkeymsg0(&msg, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC,
+ sizeof(msg));
+ sendkeymsg((char *)&msg, sizeof(msg));
+ }
+ ;
+
+ipaddropts
+ : /* nothing */
+ | ipaddropts ipaddropt
+ ;
+
+ipaddropt
+ : F_AIFLAGS
+ {
+ char *p;
+
+ for (p = $1.buf + 1; *p; p++)
+ switch (*p) {
+ case '4':
+ p_aifamily = AF_INET;
+ break;
+#ifdef INET6
+ case '6':
+ p_aifamily = AF_INET6;
+ break;
+#endif
+ case 'n':
+ p_aiflags = AI_NUMERICHOST;
+ break;
+ default:
+ yyerror("invalid flag");
+ return -1;
+ }
+ }
+ ;
+
+ipaddr
+ : STRING
+ {
+ $$ = parse_addr($1.buf, NULL);
+ if ($$ == NULL) {
+ /* yyerror already called by parse_addr */
+ return -1;
+ }
+ }
+ ;
+
+ipandport
+ : STRING
+ {
+ $$ = parse_addr($1.buf, NULL);
+ if ($$ == NULL) {
+ /* yyerror already called by parse_addr */
+ return -1;
+ }
+ }
+ | STRING portstr
+ {
+ $$ = parse_addr($1.buf, $2.buf);
+ if ($$ == NULL) {
+ /* yyerror already called by parse_addr */
+ return -1;
+ }
+ }
+ ;
+
+prefix
+ : /*NOTHING*/ { $$ = -1; }
+ | SLASH DECSTRING { $$ = $2; }
+ ;
+
+portstr
+ : /*NOTHING*/
+ {
+ $$.buf = strdup("0");
+ if (!$$.buf) {
+ yyerror("insufficient memory");
+ return -1;
+ }
+ $$.len = strlen($$.buf);
+ }
+ | BLCL ANY ELCL
+ {
+ $$.buf = strdup("0");
+ if (!$$.buf) {
+ yyerror("insufficient memory");
+ return -1;
+ }
+ $$.len = strlen($$.buf);
+ }
+ | BLCL DECSTRING ELCL
+ {
+ char buf[20];
+ snprintf(buf, sizeof(buf), "%lu", $2);
+ $$.buf = strdup(buf);
+ if (!$$.buf) {
+ yyerror("insufficient memory");
+ return -1;
+ }
+ $$.len = strlen($$.buf);
+ }
+ | BLCL STRING ELCL
+ {
+ $$ = $2;
+ }
+ ;
+
+upper_spec
+ : DECSTRING { $$ = $1; }
+ | ANY { $$ = IPSEC_ULPROTO_ANY; }
+ | PR_TCP {
+ $$ = IPPROTO_TCP;
+ }
+ | STRING
+ {
+ struct protoent *ent;
+
+ ent = getprotobyname($1.buf);
+ if (ent)
+ $$ = ent->p_proto;
+ else {
+ if (strcmp("icmp6", $1.buf) == 0) {
+ $$ = IPPROTO_ICMPV6;
+ } else if(strcmp("ip4", $1.buf) == 0) {
+ $$ = IPPROTO_IPV4;
+ } else {
+ yyerror("invalid upper layer protocol");
+ return -1;
+ }
+ }
+ endprotoent();
+ }
+ ;
+
+upper_misc_spec
+ : /*NOTHING*/
+ {
+ $$.buf = NULL;
+ $$.len = 0;
+ }
+ | STRING
+ {
+ $$.buf = strdup($1.buf);
+ if (!$$.buf) {
+ yyerror("insufficient memory");
+ return -1;
+ }
+ $$.len = strlen($$.buf);
+ }
+ ;
+
+context_spec
+ : /* NOTHING */
+ | SECURITY_CTX DECSTRING DECSTRING QUOTEDSTRING {
+ sec_ctx.doi = $2;
+ sec_ctx.alg = $3;
+ sec_ctx.len = $4.len+1;
+ sec_ctx.buf = $4.buf;
+ }
+ ;
+
+policy_spec
+ : F_POLICY policy_requests
+ {
+ char *policy;
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+ struct sadb_x_policy *xpl;
+#endif
+
+ policy = ipsec_set_policy($2.buf, $2.len);
+ if (policy == NULL) {
+ yyerror(ipsec_strerror());
+ return -1;
+ }
+
+ $$.buf = policy;
+ $$.len = ipsec_get_policylen(policy);
+
+#ifdef HAVE_PFKEY_POLICY_PRIORITY
+ xpl = (struct sadb_x_policy *) $$.buf;
+ last_priority = xpl->sadb_x_policy_priority;
+#endif
+ }
+ ;
+
+policy_requests
+ : PL_REQUESTS { $$ = $1; }
+ ;
+
+ /* exit */
+exit_command
+ : EXIT EOT
+ {
+ exit_now = 1;
+ YYACCEPT;
+ }
+ ;
+%%
+
+int
+setkeymsg0(msg, type, satype, l)
+ struct sadb_msg *msg;
+ unsigned int type;
+ unsigned int satype;
+ size_t l;
+{
+
+ msg->sadb_msg_version = PF_KEY_V2;
+ msg->sadb_msg_type = type;
+ msg->sadb_msg_errno = 0;
+ msg->sadb_msg_satype = satype;
+ msg->sadb_msg_reserved = 0;
+ msg->sadb_msg_seq = 0;
+ msg->sadb_msg_pid = getpid();
+ msg->sadb_msg_len = PFKEY_UNIT64(l);
+ return 0;
+}
+
+/* XXX NO BUFFER OVERRUN CHECK! BAD BAD! */
+static int
+setkeymsg_spdaddr(type, upper, policy, srcs, splen, dsts, dplen)
+ unsigned int type;
+ unsigned int upper;
+ vchar_t *policy;
+ struct addrinfo *srcs;
+ int splen;
+ struct addrinfo *dsts;
+ int dplen;
+{
+ struct sadb_msg *msg;
+ char buf[BUFSIZ];
+ int l, l0;
+ struct sadb_address m_addr;
+ struct addrinfo *s, *d;
+ int n;
+ int plen;
+ struct sockaddr *sa;
+ int salen;
+ struct sadb_x_policy *sp;
+#ifdef HAVE_POLICY_FWD
+ struct sadb_x_ipsecrequest *ps = NULL;
+ int saved_level, saved_id = 0;
+#endif
+
+ msg = (struct sadb_msg *)buf;
+
+ if (!srcs || !dsts)
+ return -1;
+
+ /* fix up length afterwards */
+ setkeymsg0(msg, type, SADB_SATYPE_UNSPEC, 0);
+ l = sizeof(struct sadb_msg);
+
+ sp = (struct sadb_x_policy*) (buf + l);
+ memcpy(buf + l, policy->buf, policy->len);
+ l += policy->len;
+
+ l0 = l;
+ n = 0;
+
+ /* do it for all src/dst pairs */
+ for (s = srcs; s; s = s->ai_next) {
+ for (d = dsts; d; d = d->ai_next) {
+ /* rewind pointer */
+ l = l0;
+
+ if (s->ai_addr->sa_family != d->ai_addr->sa_family)
+ continue;
+ switch (s->ai_addr->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+#endif
+ default:
+ continue;
+ }
+
+ /* set src */
+ sa = s->ai_addr;
+ salen = sysdep_sa_len(s->ai_addr);
+ m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) +
+ PFKEY_ALIGN8(salen));
+ m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+ m_addr.sadb_address_proto = upper;
+ m_addr.sadb_address_prefixlen =
+ (splen >= 0 ? splen : plen);
+ m_addr.sadb_address_reserved = 0;
+
+ setvarbuf(buf, &l, (struct sadb_ext *)&m_addr,
+ sizeof(m_addr), (caddr_t)sa, salen);
+
+ /* set dst */
+ sa = d->ai_addr;
+ salen = sysdep_sa_len(d->ai_addr);
+ m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) +
+ PFKEY_ALIGN8(salen));
+ m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+ m_addr.sadb_address_proto = upper;
+ m_addr.sadb_address_prefixlen =
+ (dplen >= 0 ? dplen : plen);
+ m_addr.sadb_address_reserved = 0;
+
+ setvarbuf(buf, &l, (struct sadb_ext *)&m_addr,
+ sizeof(m_addr), sa, salen);
+#ifdef SADB_X_EXT_SEC_CTX
+ /* Add security context label */
+ if (sec_ctx.doi) {
+ struct sadb_x_sec_ctx m_sec_ctx;
+ u_int slen = sizeof(struct sadb_x_sec_ctx);
+
+ memset(&m_sec_ctx, 0, slen);
+
+ m_sec_ctx.sadb_x_sec_len =
+ PFKEY_UNIT64(slen + PFKEY_ALIGN8(sec_ctx.len));
+
+ m_sec_ctx.sadb_x_sec_exttype =
+ SADB_X_EXT_SEC_CTX;
+ m_sec_ctx.sadb_x_ctx_len = sec_ctx.len;/*bytes*/
+ m_sec_ctx.sadb_x_ctx_doi = sec_ctx.doi;
+ m_sec_ctx.sadb_x_ctx_alg = sec_ctx.alg;
+ setvarbuf(buf, &l,
+ (struct sadb_ext *)&m_sec_ctx, slen,
+ (caddr_t)sec_ctx.buf, sec_ctx.len);
+ }
+#endif
+ msg->sadb_msg_len = PFKEY_UNIT64(l);
+
+ sendkeymsg(buf, l);
+
+#ifdef HAVE_POLICY_FWD
+ /* create extra call for FWD policy */
+ if (f_rfcmode && sp->sadb_x_policy_dir == IPSEC_DIR_INBOUND) {
+ sp->sadb_x_policy_dir = IPSEC_DIR_FWD;
+ ps = (struct sadb_x_ipsecrequest*) (sp+1);
+
+ /* if request level is unique, change it to
+ * require for fwd policy */
+ /* XXX: currently, only first policy is updated
+ * only. Update following too... */
+ saved_level = ps->sadb_x_ipsecrequest_level;
+ if (saved_level == IPSEC_LEVEL_UNIQUE) {
+ saved_id = ps->sadb_x_ipsecrequest_reqid;
+ ps->sadb_x_ipsecrequest_reqid=0;
+ ps->sadb_x_ipsecrequest_level=IPSEC_LEVEL_REQUIRE;
+ }
+
+ sendkeymsg(buf, l);
+ /* restoring for next message */
+ sp->sadb_x_policy_dir = IPSEC_DIR_INBOUND;
+ if (saved_level == IPSEC_LEVEL_UNIQUE) {
+ ps->sadb_x_ipsecrequest_reqid = saved_id;
+ ps->sadb_x_ipsecrequest_level = saved_level;
+ }
+ }
+#endif
+
+ n++;
+ }
+ }
+
+ if (n == 0)
+ return -1;
+ else
+ return 0;
+}
+
+static int
+setkeymsg_spdaddr_tag(type, tag, policy)
+ unsigned int type;
+ char *tag;
+ vchar_t *policy;
+{
+ struct sadb_msg *msg;
+ char buf[BUFSIZ];
+ int l, l0;
+#ifdef SADB_X_EXT_TAG
+ struct sadb_x_tag m_tag;
+#endif
+ int n;
+
+ msg = (struct sadb_msg *)buf;
+
+ /* fix up length afterwards */
+ setkeymsg0(msg, type, SADB_SATYPE_UNSPEC, 0);
+ l = sizeof(struct sadb_msg);
+
+ memcpy(buf + l, policy->buf, policy->len);
+ l += policy->len;
+
+ l0 = l;
+ n = 0;
+
+#ifdef SADB_X_EXT_TAG
+ memset(&m_tag, 0, sizeof(m_tag));
+ m_tag.sadb_x_tag_len = PFKEY_UNIT64(sizeof(m_tag));
+ m_tag.sadb_x_tag_exttype = SADB_X_EXT_TAG;
+ if (strlcpy(m_tag.sadb_x_tag_name, tag,
+ sizeof(m_tag.sadb_x_tag_name)) >= sizeof(m_tag.sadb_x_tag_name))
+ return -1;
+ memcpy(buf + l, &m_tag, sizeof(m_tag));
+ l += sizeof(m_tag);
+#endif
+
+ msg->sadb_msg_len = PFKEY_UNIT64(l);
+
+ sendkeymsg(buf, l);
+
+ return 0;
+}
+
+/* XXX NO BUFFER OVERRUN CHECK! BAD BAD! */
+static int
+setkeymsg_addr(type, satype, srcs, dsts, no_spi)
+ unsigned int type;
+ unsigned int satype;
+ struct addrinfo *srcs;
+ struct addrinfo *dsts;
+ int no_spi;
+{
+ struct sadb_msg *msg;
+ char buf[BUFSIZ];
+ int l, l0, len;
+ struct sadb_sa m_sa;
+ struct sadb_x_sa2 m_sa2;
+ struct sadb_address m_addr;
+ struct addrinfo *s, *d;
+ int n;
+ int plen;
+ struct sockaddr *sa;
+ int salen;
+
+ msg = (struct sadb_msg *)buf;
+
+ if (!srcs || !dsts)
+ return -1;
+
+ /* fix up length afterwards */
+ setkeymsg0(msg, type, satype, 0);
+ l = sizeof(struct sadb_msg);
+
+ if (!no_spi) {
+ len = sizeof(struct sadb_sa);
+ m_sa.sadb_sa_len = PFKEY_UNIT64(len);
+ m_sa.sadb_sa_exttype = SADB_EXT_SA;
+ m_sa.sadb_sa_spi = htonl(p_spi);
+ m_sa.sadb_sa_replay = p_replay;
+ m_sa.sadb_sa_state = 0;
+ m_sa.sadb_sa_auth = p_alg_auth;
+ m_sa.sadb_sa_encrypt = p_alg_enc;
+ m_sa.sadb_sa_flags = p_ext;
+
+ memcpy(buf + l, &m_sa, len);
+ l += len;
+
+ len = sizeof(struct sadb_x_sa2);
+ m_sa2.sadb_x_sa2_len = PFKEY_UNIT64(len);
+ m_sa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2;
+ m_sa2.sadb_x_sa2_mode = p_mode;
+ m_sa2.sadb_x_sa2_reqid = p_reqid;
+
+ memcpy(buf + l, &m_sa2, len);
+ l += len;
+ }
+
+ l0 = l;
+ n = 0;
+
+ /* do it for all src/dst pairs */
+ for (s = srcs; s; s = s->ai_next) {
+ for (d = dsts; d; d = d->ai_next) {
+ /* rewind pointer */
+ l = l0;
+
+ if (s->ai_addr->sa_family != d->ai_addr->sa_family)
+ continue;
+ switch (s->ai_addr->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+#endif
+ default:
+ continue;
+ }
+
+ /* set src */
+ sa = s->ai_addr;
+ salen = sysdep_sa_len(s->ai_addr);
+ m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) +
+ PFKEY_ALIGN8(salen));
+ m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+ m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY;
+ m_addr.sadb_address_prefixlen = plen;
+ m_addr.sadb_address_reserved = 0;
+
+ setvarbuf(buf, &l, (struct sadb_ext *)&m_addr,
+ sizeof(m_addr), sa, salen);
+
+ /* set dst */
+ sa = d->ai_addr;
+ salen = sysdep_sa_len(d->ai_addr);
+ m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) +
+ PFKEY_ALIGN8(salen));
+ m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+ m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY;
+ m_addr.sadb_address_prefixlen = plen;
+ m_addr.sadb_address_reserved = 0;
+
+ setvarbuf(buf, &l, (struct sadb_ext *)&m_addr,
+ sizeof(m_addr), sa, salen);
+
+ msg->sadb_msg_len = PFKEY_UNIT64(l);
+
+ sendkeymsg(buf, l);
+
+ n++;
+ }
+ }
+
+ if (n == 0)
+ return -1;
+ else
+ return 0;
+}
+
+#ifdef SADB_X_EXT_NAT_T_TYPE
+static u_int16_t get_port (struct addrinfo *addr)
+{
+ struct sockaddr *s = addr->ai_addr;
+ u_int16_t port = 0;
+
+ switch (s->sa_family) {
+ case AF_INET:
+ {
+ struct sockaddr_in *sin4 = (struct sockaddr_in *)s;
+ port = ntohs(sin4->sin_port);
+ break;
+ }
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)s;
+ port = ntohs(sin6->sin6_port);
+ break;
+ }
+ }
+
+ if (port == 0)
+ port = DEFAULT_NATT_PORT;
+
+ return port;
+}
+#endif
+
+/* XXX NO BUFFER OVERRUN CHECK! BAD BAD! */
+static int
+setkeymsg_add(type, satype, srcs, dsts)
+ unsigned int type;
+ unsigned int satype;
+ struct addrinfo *srcs;
+ struct addrinfo *dsts;
+{
+ struct sadb_msg *msg;
+ char buf[BUFSIZ];
+ int l, l0, len;
+ struct sadb_sa m_sa;
+ struct sadb_x_sa2 m_sa2;
+ struct sadb_address m_addr;
+ struct addrinfo *s, *d;
+ int n;
+ int plen;
+ struct sockaddr *sa;
+ int salen;
+
+ msg = (struct sadb_msg *)buf;
+
+ if (!srcs || !dsts)
+ return -1;
+
+ /* fix up length afterwards */
+ setkeymsg0(msg, type, satype, 0);
+ l = sizeof(struct sadb_msg);
+
+ /* set encryption algorithm, if present. */
+ if (satype != SADB_X_SATYPE_IPCOMP && p_key_enc) {
+ union {
+ struct sadb_key key;
+ struct sadb_ext ext;
+ } m;
+
+ m.key.sadb_key_len =
+ PFKEY_UNIT64(sizeof(m.key)
+ + PFKEY_ALIGN8(p_key_enc_len));
+ m.key.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
+ m.key.sadb_key_bits = p_key_enc_len * 8;
+ m.key.sadb_key_reserved = 0;
+
+ setvarbuf(buf, &l, &m.ext, sizeof(m.key),
+ p_key_enc, p_key_enc_len);
+ }
+
+ /* set authentication algorithm, if present. */
+ if (p_key_auth) {
+ union {
+ struct sadb_key key;
+ struct sadb_ext ext;
+ } m;
+
+ m.key.sadb_key_len =
+ PFKEY_UNIT64(sizeof(m.key)
+ + PFKEY_ALIGN8(p_key_auth_len));
+ m.key.sadb_key_exttype = SADB_EXT_KEY_AUTH;
+ m.key.sadb_key_bits = p_key_auth_len * 8;
+ m.key.sadb_key_reserved = 0;
+
+ setvarbuf(buf, &l, &m.ext, sizeof(m.key),
+ p_key_auth, p_key_auth_len);
+ }
+
+ /* set lifetime for HARD */
+ if (p_lt_hard != 0 || p_lb_hard != 0) {
+ struct sadb_lifetime m_lt;
+ u_int slen = sizeof(struct sadb_lifetime);
+
+ m_lt.sadb_lifetime_len = PFKEY_UNIT64(slen);
+ m_lt.sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
+ m_lt.sadb_lifetime_allocations = 0;
+ m_lt.sadb_lifetime_bytes = p_lb_hard;
+ m_lt.sadb_lifetime_addtime = p_lt_hard;
+ m_lt.sadb_lifetime_usetime = 0;
+
+ memcpy(buf + l, &m_lt, slen);
+ l += slen;
+ }
+
+ /* set lifetime for SOFT */
+ if (p_lt_soft != 0 || p_lb_soft != 0) {
+ struct sadb_lifetime m_lt;
+ u_int slen = sizeof(struct sadb_lifetime);
+
+ m_lt.sadb_lifetime_len = PFKEY_UNIT64(slen);
+ m_lt.sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT;
+ m_lt.sadb_lifetime_allocations = 0;
+ m_lt.sadb_lifetime_bytes = p_lb_soft;
+ m_lt.sadb_lifetime_addtime = p_lt_soft;
+ m_lt.sadb_lifetime_usetime = 0;
+
+ memcpy(buf + l, &m_lt, slen);
+ l += slen;
+ }
+
+#ifdef SADB_X_EXT_SEC_CTX
+ /* Add security context label */
+ if (sec_ctx.doi) {
+ struct sadb_x_sec_ctx m_sec_ctx;
+ u_int slen = sizeof(struct sadb_x_sec_ctx);
+
+ memset(&m_sec_ctx, 0, slen);
+
+ m_sec_ctx.sadb_x_sec_len = PFKEY_UNIT64(slen +
+ PFKEY_ALIGN8(sec_ctx.len));
+ m_sec_ctx.sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX;
+ m_sec_ctx.sadb_x_ctx_len = sec_ctx.len; /* bytes */
+ m_sec_ctx.sadb_x_ctx_doi = sec_ctx.doi;
+ m_sec_ctx.sadb_x_ctx_alg = sec_ctx.alg;
+ setvarbuf(buf, &l, (struct sadb_ext *)&m_sec_ctx, slen,
+ (caddr_t)sec_ctx.buf, sec_ctx.len);
+ }
+#endif
+
+ len = sizeof(struct sadb_sa);
+ m_sa.sadb_sa_len = PFKEY_UNIT64(len);
+ m_sa.sadb_sa_exttype = SADB_EXT_SA;
+ m_sa.sadb_sa_spi = htonl(p_spi);
+ m_sa.sadb_sa_replay = p_replay;
+ m_sa.sadb_sa_state = 0;
+ m_sa.sadb_sa_auth = p_alg_auth;
+ m_sa.sadb_sa_encrypt = p_alg_enc;
+ m_sa.sadb_sa_flags = p_ext;
+
+ memcpy(buf + l, &m_sa, len);
+ l += len;
+
+ len = sizeof(struct sadb_x_sa2);
+ m_sa2.sadb_x_sa2_len = PFKEY_UNIT64(len);
+ m_sa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2;
+ m_sa2.sadb_x_sa2_mode = p_mode;
+ m_sa2.sadb_x_sa2_reqid = p_reqid;
+
+ memcpy(buf + l, &m_sa2, len);
+ l += len;
+
+#ifdef SADB_X_EXT_NAT_T_TYPE
+ if (p_natt_type) {
+ struct sadb_x_nat_t_type natt_type;
+
+ len = sizeof(struct sadb_x_nat_t_type);
+ memset(&natt_type, 0, len);
+ natt_type.sadb_x_nat_t_type_len = PFKEY_UNIT64(len);
+ natt_type.sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE;
+ natt_type.sadb_x_nat_t_type_type = p_natt_type;
+
+ memcpy(buf + l, &natt_type, len);
+ l += len;
+
+ if (p_natt_oa) {
+ sa = p_natt_oa->ai_addr;
+ switch (sa->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+#endif
+ default:
+ return -1;
+ }
+ salen = sysdep_sa_len(sa);
+ m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) +
+ PFKEY_ALIGN8(salen));
+ m_addr.sadb_address_exttype = SADB_X_EXT_NAT_T_OA;
+ m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY;
+ m_addr.sadb_address_prefixlen = plen;
+ m_addr.sadb_address_reserved = 0;
+
+ setvarbuf(buf, &l, (struct sadb_ext *)&m_addr,
+ sizeof(m_addr), sa, salen);
+ }
+ }
+#endif
+
+ l0 = l;
+ n = 0;
+
+ /* do it for all src/dst pairs */
+ for (s = srcs; s; s = s->ai_next) {
+ for (d = dsts; d; d = d->ai_next) {
+ /* rewind pointer */
+ l = l0;
+
+ if (s->ai_addr->sa_family != d->ai_addr->sa_family)
+ continue;
+ switch (s->ai_addr->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+#endif
+ default:
+ continue;
+ }
+
+ /* set src */
+ sa = s->ai_addr;
+ salen = sysdep_sa_len(s->ai_addr);
+ m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) +
+ PFKEY_ALIGN8(salen));
+ m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+ m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY;
+ m_addr.sadb_address_prefixlen = plen;
+ m_addr.sadb_address_reserved = 0;
+
+ setvarbuf(buf, &l, (struct sadb_ext *)&m_addr,
+ sizeof(m_addr), sa, salen);
+
+ /* set dst */
+ sa = d->ai_addr;
+ salen = sysdep_sa_len(d->ai_addr);
+ m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) +
+ PFKEY_ALIGN8(salen));
+ m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+ m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY;
+ m_addr.sadb_address_prefixlen = plen;
+ m_addr.sadb_address_reserved = 0;
+
+ setvarbuf(buf, &l, (struct sadb_ext *)&m_addr,
+ sizeof(m_addr), sa, salen);
+
+#ifdef SADB_X_EXT_NAT_T_TYPE
+ if (p_natt_type) {
+ struct sadb_x_nat_t_port natt_port;
+
+ /* NATT_SPORT */
+ len = sizeof(struct sadb_x_nat_t_port);
+ memset(&natt_port, 0, len);
+ natt_port.sadb_x_nat_t_port_len = PFKEY_UNIT64(len);
+ natt_port.sadb_x_nat_t_port_exttype =
+ SADB_X_EXT_NAT_T_SPORT;
+ natt_port.sadb_x_nat_t_port_port = htons(get_port(s));
+
+ memcpy(buf + l, &natt_port, len);
+ l += len;
+
+ /* NATT_DPORT */
+ natt_port.sadb_x_nat_t_port_exttype =
+ SADB_X_EXT_NAT_T_DPORT;
+ natt_port.sadb_x_nat_t_port_port = htons(get_port(d));
+
+ memcpy(buf + l, &natt_port, len);
+ l += len;
+ }
+#endif
+ msg->sadb_msg_len = PFKEY_UNIT64(l);
+
+ sendkeymsg(buf, l);
+
+ n++;
+ }
+ }
+
+ if (n == 0)
+ return -1;
+ else
+ return 0;
+}
+
+static struct addrinfo *
+parse_addr(host, port)
+ char *host;
+ char *port;
+{
+ struct addrinfo hints, *res = NULL;
+ int error;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = p_aifamily;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ hints.ai_protocol = IPPROTO_UDP; /*dummy*/
+ hints.ai_flags = p_aiflags;
+ error = getaddrinfo(host, port, &hints, &res);
+ if (error != 0) {
+ yyerror(gai_strerror(error));
+ return NULL;
+ }
+ return res;
+}
+
+static int
+fix_portstr(ulproto, spec, sport, dport)
+ int ulproto;
+ vchar_t *spec, *sport, *dport;
+{
+ char sp[16], dp[16];
+ int a, b, c, d;
+ unsigned long u;
+
+ if (spec->buf == NULL)
+ return 0;
+
+ switch (ulproto) {
+ case IPPROTO_ICMP:
+ case IPPROTO_ICMPV6:
+ case IPPROTO_MH:
+ if (sscanf(spec->buf, "%d,%d", &a, &b) == 2) {
+ sprintf(sp, "%d", a);
+ sprintf(dp, "%d", b);
+ } else if (sscanf(spec->buf, "%d", &a) == 1) {
+ sprintf(sp, "%d", a);
+ } else {
+ yyerror("invalid an upper layer protocol spec");
+ return -1;
+ }
+ break;
+ case IPPROTO_GRE:
+ if (sscanf(spec->buf, "%d.%d.%d.%d", &a, &b, &c, &d) == 4) {
+ sprintf(sp, "%d", (a << 8) + b);
+ sprintf(dp, "%d", (c << 8) + d);
+ } else if (sscanf(spec->buf, "%lu", &u) == 1) {
+ sprintf(sp, "%d", (int) (u >> 16));
+ sprintf(dp, "%d", (int) (u & 0xffff));
+ } else {
+ yyerror("invalid an upper layer protocol spec");
+ return -1;
+ }
+ break;
+ }
+
+ free(sport->buf);
+ sport->buf = strdup(sp);
+ if (!sport->buf) {
+ yyerror("insufficient memory");
+ return -1;
+ }
+ sport->len = strlen(sport->buf);
+
+ free(dport->buf);
+ dport->buf = strdup(dp);
+ if (!dport->buf) {
+ yyerror("insufficient memory");
+ return -1;
+ }
+ dport->len = strlen(dport->buf);
+
+ return 0;
+}
+
+static int
+setvarbuf(buf, off, ebuf, elen, vbuf, vlen)
+ char *buf;
+ int *off;
+ struct sadb_ext *ebuf;
+ int elen;
+ const void *vbuf;
+ int vlen;
+{
+ memset(buf + *off, 0, PFKEY_UNUNIT64(ebuf->sadb_ext_len));
+ memcpy(buf + *off, (caddr_t)ebuf, elen);
+ memcpy(buf + *off + elen, vbuf, vlen);
+ (*off) += PFKEY_ALIGN8(elen + vlen);
+
+ return 0;
+}
+
+void
+parse_init()
+{
+ p_spi = 0;
+
+ p_ext = SADB_X_EXT_CYCSEQ;
+ p_alg_enc = SADB_EALG_NONE;
+ p_alg_auth = SADB_AALG_NONE;
+ p_mode = IPSEC_MODE_ANY;
+ p_reqid = 0;
+ p_replay = 0;
+ p_key_enc_len = p_key_auth_len = 0;
+ p_key_enc = p_key_auth = 0;
+ p_lt_hard = p_lt_soft = 0;
+ p_lb_hard = p_lb_soft = 0;
+
+ memset(&sec_ctx, 0, sizeof(struct security_ctx));
+
+ p_aiflags = 0;
+ p_aifamily = PF_UNSPEC;
+
+ /* Clear out any natt OA information */
+ if (p_natt_oa)
+ freeaddrinfo (p_natt_oa);
+ p_natt_oa = NULL;
+ p_natt_type = 0;
+
+ return;
+}
+
+void
+free_buffer()
+{
+ /* we got tons of memory leaks in the parser anyways, leave them */
+
+ return;
+}