NetBSD/sbin/setkey/parse.y
jonathan 887b782b0b Initial commit of a port of the FreeBSD implementation of RFC 2385
(MD5 signatures for TCP, as used with BGP).  Credit for original
FreeBSD code goes to Bruce M. Simpson, with FreeBSD sponsorship
credited to sentex.net.  Shortening of the setsockopt() name
attributed to Vincent Jardin.

This commit is a minimal, working version of the FreeBSD code, as
MFC'ed to FreeBSD-4. It has received minimal testing with a ttcp
modified to set the TCP-MD5 option; BMS's additions to tcpdump-current
(tcpdump -M) confirm that the MD5 signatures are correct.  Committed
as-is for further testing between a NetBSD BGP speaker (e.g., quagga)
and industry-standard BGP speakers (e.g., Cisco, Juniper).


NOTE: This version has two potential flaws. First, I do see any code
that verifies recieved TCP-MD5 signatures.  Second, the TCP-MD5
options are internally padded and assumed to be 32-bit aligned. A more
space-efficient scheme is to pack all TCP options densely (and
possibly unaligned) into the TCP header ; then do one final padding to
a 4-byte boundary.  Pre-existing comments note that accounting for
TCP-option space when we add SACK is yet to be done. For now, I'm
punting on that; we can solve it properly, in a way that will handle
SACK blocks, as a separate exercise.

In case a pullup to NetBSD-2 is requested, this adds sys/netipsec/xform_tcp.c
,and modifies:

sys/net/pfkeyv2.h,v 1.15
sys/netinet/files.netinet,v 1.5
sys/netinet/ip.h,v 1.25
sys/netinet/tcp.h,v 1.15
sys/netinet/tcp_input.c,v 1.200
sys/netinet/tcp_output.c,v 1.109
sys/netinet/tcp_subr.c,v 1.165
sys/netinet/tcp_usrreq.c,v 1.89
sys/netinet/tcp_var.h,v 1.109
sys/netipsec/files.netipsec,v 1.3
sys/netipsec/ipsec.c,v 1.11
sys/netipsec/ipsec.h,v 1.7
sys/netipsec/key.c,v 1.11
share/man/man4/tcp.4,v 1.16
lib/libipsec/pfkey.c,v 1.20
lib/libipsec/pfkey_dump.c,v 1.17
lib/libipsec/policy_token.l,v 1.8
sbin/setkey/parse.y,v 1.14
sbin/setkey/setkey.8,v 1.27
sbin/setkey/token.l,v 1.15

Note that the preceding two revisions to tcp.4 will be
required to cleanly apply this diff.
2004-04-25 22:25:03 +00:00

1232 lines
26 KiB
Plaintext

/* $FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/usr.sbin/setkey/parse.y,v 1.1.2.4 2004/04/06 10:02:12 bms Exp $ */
/* $KAME: parse.y,v 1.80 2003/06/27 07:15:45 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.
*/
%{
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <net/route.h>
#include <netinet/in.h>
#include <net/pfkeyv2.h>
#include <netkey/key_var.h>
#include <netinet6/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 "libpfkey.h"
#include "vchar.h"
#define ATOX(c) \
(isdigit(c) ? (c - '0') : (isupper(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;
caddr_t p_key_enc, p_key_auth;
time_t p_lt_hard, p_lt_soft;
static int p_aiflags = 0, p_aifamily = PF_UNSPEC;
static struct addrinfo *parse_addr __P((char *, char *));
static int setvarbuf __P((char *, int *, struct sadb_ext *, int, caddr_t, 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));
#ifdef SADB_X_EXT_TAG
static int setkeymsg_spdaddr_tag __P((unsigned int, char *, vchar_t *));
#endif
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 *));
extern int setkeymsg __P((char *, size_t *));
extern int sendkeymsg __P((char *, size_t));
extern int yylex __P((void));
extern void yyfatal __P((const char *));
extern void yyerror __P((const char *));
%}
%union {
int num;
unsigned long ulnum;
vchar_t val;
struct addrinfo *res;
}
%token EOT SLASH BLCL ELCL
%token ADD GET DELETE DELETEALL FLUSH DUMP
%token PR_ESP PR_AH PR_IPCOMP 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 DECSTRING QUOTEDSTRING HEXSTRING STRING ANY
/* SPD management */
%token SPDADD SPDDELETE SPDDUMP SPDFLUSH
%token F_POLICY PL_REQUESTS
%token F_AIFLAGS
%token TAGGED
%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_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> policy_spec
%type <res> ipaddr
%%
commands
: /*NOTHING*/
| commands command
{
free_buffer();
parse_init();
}
;
command
: add_command
| get_command
| delete_command
| deleteall_command
| flush_command
| dump_command
| spdadd_command
| spddelete_command
| spddump_command
| spdflush_command
;
/* commands concerned with management, there is in tail of this file. */
/* add command */
add_command
: ADD ipaddropts ipaddr ipaddr 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 ipaddr ipaddr 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
{
int status;
status = setkeymsg_addr(SADB_DELETE, $5, $3, $4, 1);
if (status < 0)
return -1;
}
;
/* get command */
get_command
: GET ipaddropts ipaddr ipaddr 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_TCP
{
$$ = SADB_X_SATYPE_TCPSIGNATURE;
}
;
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 = NULL;
}
| 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 = NULL;
}
| 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;
if (p_alg_auth == SADB_X_AALG_TCP_MD5) {
if ((p_key_auth_len < 1) || (p_key_auth_len >
80))
return -1;
} else 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; }
;
/* definition about command for SPD management */
/* spdadd */
spdadd_command
: SPDADD ipaddropts STRING prefix portstr STRING prefix portstr upper_spec policy_spec EOT
{
int status;
struct addrinfo *src, *dst;
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, &$10,
src, $4, dst, $7);
freeaddrinfo(src);
freeaddrinfo(dst);
if (status < 0)
return -1;
}
| SPDADD TAGGED QUOTEDSTRING policy_spec EOT
{
#ifdef SADB_X_EXT_TAG
int status;
status = setkeymsg_spdaddr_tag(SADB_X_SPDADD,
$3.buf, &$4);
if (status < 0)
return -1;
#else
return -1;
#endif
}
;
spddelete_command
: SPDDELETE ipaddropts STRING prefix portstr STRING prefix portstr upper_spec policy_spec EOT
{
int status;
struct addrinfo *src, *dst;
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, &$10,
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;
}
}
;
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();
}
;
policy_spec
: F_POLICY policy_requests
{
char *policy;
policy = ipsec_set_policy($2.buf, $2.len);
if (policy == NULL) {
yyerror(ipsec_strerror());
return -1;
}
$$.buf = policy;
$$.len = ipsec_get_policylen(policy);
}
;
policy_requests
: PL_REQUESTS { $$ = $1; }
;
%%
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;
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);
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 = s->ai_addr->sa_len;
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 = d->ai_addr->sa_len;
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), (caddr_t)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_TAG
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;
struct sadb_x_tag m_tag;
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;
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);
msg->sadb_msg_len = PFKEY_UNIT64(l);
sendkeymsg(buf, l);
return 0;
}
#endif
/* 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 = s->ai_addr->sa_len;
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), (caddr_t)sa, salen);
/* set dst */
sa = d->ai_addr;
salen = d->ai_addr->sa_len;
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), (caddr_t)sa, salen);
msg->sadb_msg_len = PFKEY_UNIT64(l);
sendkeymsg(buf, l);
n++;
}
}
if (n == 0)
return -1;
else
return 0;
}
/* 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) {
struct sadb_key m_key;
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,
(struct sadb_ext *)(void*)&m_key, sizeof(m_key),
(caddr_t)p_key_enc, p_key_enc_len);
}
/* set authentication algorithm, if present. */
if (p_key_auth) {
struct sadb_key m_key;
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,
(struct sadb_ext *)(void*)&m_key, sizeof(m_key),
(caddr_t)p_key_auth, p_key_auth_len);
}
/* set lifetime for HARD */
if (p_lt_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 = 0;
m_lt.sadb_lifetime_addtime = p_lt_hard;
m_lt.sadb_lifetime_usetime = 0;
memcpy(buf + l, &m_lt, slen);
l += len;
}
/* set lifetime for SOFT */
if (p_lt_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 = 0;
m_lt.sadb_lifetime_addtime = p_lt_soft;
m_lt.sadb_lifetime_usetime = 0;
memcpy(buf + l, &m_lt, slen);
l += len;
}
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 = s->ai_addr->sa_len;
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), (caddr_t)sa, salen);
/* set dst */
sa = d->ai_addr;
salen = d->ai_addr->sa_len;
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), (caddr_t)sa, salen);
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
setvarbuf(buf, off, ebuf, elen, vbuf, vlen)
char *buf;
int *off;
struct sadb_ext *ebuf;
int elen;
caddr_t 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_aiflags = 0;
p_aifamily = PF_UNSPEC;
return;
}
void
free_buffer()
{
/* we got tons of memory leaks in the parser anyways, leave them */
return;
}