pluto: Refactored PF_KEY capabilities registration.

Although we use the kernel interface from libhydra we still need this to make
the available algorithms known to pluto.
This commit is contained in:
Tobias Brunner
2010-09-02 19:04:23 +02:00
parent 4f898afc22
commit 296972aeaf
3 changed files with 108 additions and 239 deletions
+2 -4
View File
@@ -1823,8 +1823,6 @@ void init_kernel(void)
{
#ifdef KLIPS
init_pfkey();
#if defined(linux) && defined(KERNEL26_SUPPORT)
{
bool linux_ipsec = 0;
@@ -1844,8 +1842,8 @@ void init_kernel(void)
#endif
/* register SA types that we can negotiate */
can_do_IPcomp = FALSE; /* until we get a response from KLIPS */
kernel_ops->pfkey_register();
can_do_IPcomp = FALSE; /* until we get a response from the kernel */
pfkey_register();
INIT(kernel_handler,
.acquire = _acquire,
+98 -229
View File
@@ -1,7 +1,9 @@
/* pfkey interface to the kernel's IPsec mechanism
* Copyright (C) 1997 Angelos D. Keromytis.
* Copyright (C) 1998-2002 D. Hugh Redelmeier.
/*
* Copyright (C) 2010 Tobias Brunner
* Hochschule fuer Technik Rapperswil
* Copyright (C) 2003 Herbert Xu.
* Copyright (C) 1998-2002 D. Hugh Redelmeier.
* Copyright (C) 1997 Angelos D. Keromytis.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -17,38 +19,28 @@
#ifdef KLIPS
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <freeswan.h>
#include <pfkeyv2.h>
#include <pfkey.h>
#include "constants.h"
#include "defs.h"
#include "kernel.h"
#include "kernel_pfkey.h"
#include "log.h"
#include "whack.h" /* for RC_LOG_SERIOUS */
#include "demux.h"
#include "nat_traversal.h"
#include "alg_info.h"
#include "kernel_alg.h"
static int pfkeyfd = NULL_FD;
typedef u_int32_t pfkey_seq_t;
static pfkey_seq_t pfkey_seq = 0; /* sequence number for our PF_KEY messages */
static pfkey_seq_t pfkey_seq = 0; /* sequence number for our PF_KEY messages */
static pid_t pid;
@@ -77,106 +69,19 @@ static sparse_names pfkey_type_names = {
{ 0, sparse_end }
};
#ifdef NEVER /* not needed yet */
static sparse_names pfkey_ext_names = {
NE(SADB_EXT_RESERVED),
NE(SADB_EXT_SA),
NE(SADB_EXT_LIFETIME_CURRENT),
NE(SADB_EXT_LIFETIME_HARD),
NE(SADB_EXT_LIFETIME_SOFT),
NE(SADB_EXT_ADDRESS_SRC),
NE(SADB_EXT_ADDRESS_DST),
NE(SADB_EXT_ADDRESS_PROXY),
NE(SADB_EXT_KEY_AUTH),
NE(SADB_EXT_KEY_ENCRYPT),
NE(SADB_EXT_IDENTITY_SRC),
NE(SADB_EXT_IDENTITY_DST),
NE(SADB_EXT_SENSITIVITY),
NE(SADB_EXT_PROPOSAL),
NE(SADB_EXT_SUPPORTED_AUTH),
NE(SADB_EXT_SUPPORTED_ENCRYPT),
NE(SADB_EXT_SPIRANGE),
NE(SADB_X_EXT_KMPRIVATE),
NE(SADB_X_EXT_SATYPE2),
NE(SADB_X_EXT_SA2),
NE(SADB_X_EXT_ADDRESS_DST2),
NE(SADB_X_EXT_ADDRESS_SRC_FLOW),
NE(SADB_X_EXT_ADDRESS_DST_FLOW),
NE(SADB_X_EXT_ADDRESS_SRC_MASK),
NE(SADB_X_EXT_ADDRESS_DST_MASK),
NE(SADB_X_EXT_DEBUG),
{ 0, sparse_end }
};
#endif /* NEVER */
#undef NE
void
init_pfkey(void)
{
pid = getpid();
/* open PF_KEY socket */
pfkeyfd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
if (pfkeyfd == -1)
exit_log_errno((e, "socket() in init_pfkeyfd()"));
#ifdef NEVER /* apparently unsupported! */
if (fcntl(pfkeyfd, F_SETFL, O_NONBLOCK) != 0)
exit_log_errno((e, "fcntl(O_NONBLOCK) in init_pfkeyfd()"));
#endif
if (fcntl(pfkeyfd, F_SETFD, FD_CLOEXEC) != 0)
exit_log_errno((e, "fcntl(FD_CLOEXEC) in init_pfkeyfd()"));
DBG(DBG_KLIPS,
DBG_log("process %u listening for PF_KEY_V2 on file descriptor %d", (unsigned)pid, pfkeyfd));
}
/* Kinds of PF_KEY message from the kernel:
* - response to a request from us
* + ACK/NAK
* + Register: indicates transforms supported by kernel
* + SPI requested by getspi
* - Acquire, requesting us to deal with trapped clear packet
* - expiration of of one of our SAs
* - messages to other processes
*
* To minimize the effect on the event-driven structure of Pluto,
* responses are dealt with synchronously. We hope that the Kernel
* produces them synchronously. We must "read ahead" in the PF_KEY
* stream, saving Acquire and Expiry messages that are encountered.
* We ignore messages to other processes.
*/
typedef union {
unsigned char bytes[PFKEYv2_MAX_MSGSIZE];
struct sadb_msg msg;
} pfkey_buf;
/* queue of unprocessed PF_KEY messages input from kernel
* Note that the pfkey_buf may be partly allocated, reflecting
* the variable length nature of the messages. So the link field
* must come first.
*/
typedef struct pfkey_item {
struct pfkey_item *next;
pfkey_buf buf;
} pfkey_item;
static pfkey_item *pfkey_iq_head = NULL; /* oldest */
static pfkey_item *pfkey_iq_tail; /* youngest */
static bool
pfkey_input_ready(void)
{
fd_set readfds;
int ndes;
struct timeval tm;
tm.tv_sec = 0; /* don't wait at all */
tm.tv_usec = 0;
fd_set readfds;
struct timeval tm = { .tv_sec = 0 }; /* don't wait, polling */
FD_ZERO(&readfds); /* we only care about pfkeyfd */
FD_SET(pfkeyfd, &readfds);
@@ -190,16 +95,16 @@ pfkey_input_ready(void)
log_errno((e, "select() failed in pfkey_get()"));
return FALSE;
}
if (ndes == 0)
else if (ndes == 0)
{
return FALSE; /* nothing to read */
}
passert(ndes == 1 && FD_ISSET(pfkeyfd, &readfds));
return TRUE;
}
/* get a PF_KEY message from kernel.
* Returns TRUE is message found, FALSE if no message pending,
* Returns TRUE if message found, FALSE if no message pending,
* and aborts or keeps trying when an error is encountered.
* The only validation of the message is that the message length
* received matches that in the message header, and that the message
@@ -216,48 +121,48 @@ pfkey_get(pfkey_buf *buf)
ssize_t len;
if (!pfkey_input_ready())
{
return FALSE;
}
len = read(pfkeyfd, buf->bytes, sizeof(buf->bytes));
if (len < 0)
{
if (errno == EAGAIN)
{
return FALSE;
}
log_errno((e, "read() failed in pfkey_get()"));
return FALSE;
}
else if ((size_t) len < sizeof(buf->msg))
else if ((size_t)len < sizeof(buf->msg))
{
plog("pfkey_get read truncated PF_KEY message: %d bytes; ignoring message"
, (int) len);
plog("pfkey_get read truncated PF_KEY message: %d bytes; ignoring",
(int)len);
}
else if ((size_t) len != buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN)
else if ((size_t)len != buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN)
{
plog("pfkey_get read PF_KEY message with length %d that doesn't equal sadb_msg_len %u * %u; ignoring message"
, (int) len
, (unsigned) buf->msg.sadb_msg_len
, (unsigned) IPSEC_PFKEYv2_ALIGN);
plog("pfkey_get read PF_KEY message with length %d that doesn't"
" equal sadb_msg_len %u * %u; ignoring message", (int)len,
(unsigned)buf->msg.sadb_msg_len, (unsigned)IPSEC_PFKEYv2_ALIGN);
}
else if (!(buf->msg.sadb_msg_pid == (unsigned)pid
|| (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_ACQUIRE)
|| (buf->msg.sadb_msg_type == SADB_REGISTER)
|| (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_X_NAT_T_NEW_MAPPING)))
else if (buf->msg.sadb_msg_pid != (unsigned)pid)
{
/* not for us: ignore */
DBG(DBG_KLIPS,
DBG_log("pfkey_get: ignoring PF_KEY %s message %u for process %u"
, sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
, buf->msg.sadb_msg_seq
, buf->msg.sadb_msg_pid));
DBG_log("pfkey_get: ignoring PF_KEY %s message %u for process"
" %u", sparse_val_show(pfkey_type_names,
buf->msg.sadb_msg_type),
buf->msg.sadb_msg_seq, buf->msg.sadb_msg_pid));
}
else
{
DBG(DBG_KLIPS,
DBG_log("pfkey_get: %s message %u"
, sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
, buf->msg.sadb_msg_seq));
DBG_log("pfkey_get: %s message %u",
sparse_val_show(pfkey_type_names,
buf->msg.sadb_msg_type),
buf->msg.sadb_msg_seq));
return TRUE;
}
}
@@ -269,65 +174,38 @@ pfkey_get_response(pfkey_buf *buf, pfkey_seq_t seq)
{
while (pfkey_get(buf))
{
if (buf->msg.sadb_msg_pid == (unsigned)pid
&& buf->msg.sadb_msg_seq == seq)
if (buf->msg.sadb_msg_seq == seq)
{
return TRUE;
}
else
{
/* Not for us: queue it. */
size_t bl = buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN;
pfkey_item *it = malloc(offsetof(pfkey_item, buf) + bl);
memcpy(&it->buf, buf, bl);
it->next = NULL;
if (pfkey_iq_head == NULL)
{
pfkey_iq_head = it;
}
else
{
pfkey_iq_tail->next = it;
}
pfkey_iq_tail = it;
}
}
return FALSE;
}
static bool
pfkey_build(int error
, const char *description
, const char *text_said
, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
pfkey_build(int error, const char *description, const char *text_said,
struct sadb_ext *extensions[SADB_EXT_MAX + 1])
{
if (error == 0)
if (error != 0)
{
return TRUE;
}
else
{
loglog(RC_LOG_SERIOUS, "building of %s %s failed, code %d"
, description, text_said, error);
loglog(RC_LOG_SERIOUS, "building of %s %s failed, code %d", description,
text_said, error);
pfkey_extensions_free(extensions);
return FALSE;
}
return TRUE;
}
/* pfkey_extensions_init + pfkey_build + pfkey_msg_hdr_build */
static bool
pfkey_msg_start(u_int8_t msg_type
, u_int8_t satype
, const char *description
, const char *text_said
, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
pfkey_msg_start(u_int8_t msg_type, u_int8_t satype, const char *description,
const char *text_said,
struct sadb_ext *extensions[SADB_EXT_MAX + 1])
{
pfkey_extensions_init(extensions);
return pfkey_build(pfkey_msg_hdr_build(&extensions[0], msg_type
, satype, 0, ++pfkey_seq, pid)
, description, text_said, extensions);
return pfkey_build(pfkey_msg_hdr_build(&extensions[0], msg_type, satype, 0,
++pfkey_seq, pid),
description, text_said, extensions);
}
/* Finish (building, sending, accepting response for) PF_KEY message.
@@ -336,10 +214,9 @@ pfkey_msg_start(u_int8_t msg_type
* Returns TRUE iff all appears well.
*/
static bool
finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1]
, const char *description
, const char *text_said
, pfkey_buf *response)
finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1],
const char *description, const char *text_said,
pfkey_buf *response)
{
struct sadb_msg *pfkey_msg;
bool success = TRUE;
@@ -349,8 +226,8 @@ finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1]
if (error != 0)
{
loglog(RC_LOG_SERIOUS, "pfkey_msg_build of %s %s failed, code %d"
, description, text_said, error);
loglog(RC_LOG_SERIOUS, "pfkey_msg_build of %s %s failed, code %d",
description, text_said, error);
success = FALSE;
}
else
@@ -358,10 +235,9 @@ finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1]
size_t len = pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN;
DBG(DBG_KLIPS,
DBG_log("finish_pfkey_msg: %s message %u for %s %s"
, sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type)
, pfkey_msg->sadb_msg_seq
, description, text_said);
DBG_log("finish_pfkey_msg: %s message %u for %s %s",
sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type),
pfkey_msg->sadb_msg_seq, description, text_said);
DBG_dump(NULL, (void *) pfkey_msg, len));
if (!no_klips)
@@ -372,24 +248,18 @@ finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1]
{
if (r < 0)
{
log_errno((e
, "pfkey write() of %s message %u"
" for %s %s failed"
, sparse_val_show(pfkey_type_names
, pfkey_msg->sadb_msg_type)
, pfkey_msg->sadb_msg_seq
, description, text_said));
log_errno((e, "pfkey write() of %s message %u for %s %s"
" failed", sparse_val_show(pfkey_type_names,
pfkey_msg->sadb_msg_type), pfkey_msg->sadb_msg_seq,
description, text_said));
}
else
{
loglog(RC_LOG_SERIOUS
, "ERROR: pfkey write() of %s message %u"
" for %s %s truncated: %ld instead of %ld"
, sparse_val_show(pfkey_type_names
, pfkey_msg->sadb_msg_type)
, pfkey_msg->sadb_msg_seq
, description, text_said
, (long)r, (long)len);
loglog(RC_LOG_SERIOUS, "ERROR: pfkey write() of %s message"
" %u for %s %s truncated: %ld instead of %ld",
sparse_val_show(pfkey_type_names,
pfkey_msg->sadb_msg_type), pfkey_msg->sadb_msg_seq,
description, text_said, (long)r, (long)len);
}
success = FALSE;
@@ -403,46 +273,45 @@ finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1]
}
else
{
/* Check response from KLIPS.
/* Check response from kernel.
* It ought to be an echo, perhaps with additional info.
* If the caller wants it, response will point to space.
*/
pfkey_buf b;
pfkey_buf *bp = response != NULL? response : &b;
if (!pfkey_get_response(bp, ((struct sadb_msg *) extensions[0])->sadb_msg_seq))
if (!pfkey_get_response(bp,
((struct sadb_msg *)extensions[0])->sadb_msg_seq))
{
loglog(RC_LOG_SERIOUS
, "ERROR: no response to our PF_KEY %s message for %s %s"
, sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type)
, description, text_said);
loglog(RC_LOG_SERIOUS, "ERROR: no response to our PF_KEY %s"
" message for %s %s", sparse_val_show(pfkey_type_names,
pfkey_msg->sadb_msg_type), description, text_said);
success = FALSE;
}
else if (pfkey_msg->sadb_msg_type != bp->msg.sadb_msg_type)
{
loglog(RC_LOG_SERIOUS
, "FreeS/WAN ERROR: response to our PF_KEY %s message for %s %s was of wrong type (%s)"
, sparse_name(pfkey_type_names, pfkey_msg->sadb_msg_type)
, description, text_said
, sparse_val_show(pfkey_type_names, bp->msg.sadb_msg_type));
loglog(RC_LOG_SERIOUS, "ERROR: response to our PF_KEY %s"
" message for %s %s was of wrong type (%s)",
sparse_name(pfkey_type_names, pfkey_msg->sadb_msg_type),
description, text_said,
sparse_val_show(pfkey_type_names,
bp->msg.sadb_msg_type));
success = FALSE;
}
else if (response == NULL && bp->msg.sadb_msg_errno != 0)
{
/* KLIPS is signalling a problem */
loglog(RC_LOG_SERIOUS
, "ERROR: PF_KEY %s response for %s %s included errno %u: %s"
, sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type)
, description, text_said
, (unsigned) bp->msg.sadb_msg_errno
, strerror(bp->msg.sadb_msg_errno));
/* Kernel is signalling a problem */
loglog(RC_LOG_SERIOUS, "ERROR: PF_KEY %s response for %s %s"
" included errno %u: %s",
sparse_val_show(pfkey_type_names,
pfkey_msg->sadb_msg_type), description, text_said,
(unsigned) bp->msg.sadb_msg_errno,
strerror(bp->msg.sadb_msg_errno));
success = FALSE;
}
}
}
}
/* all paths must exit this way to free resources */
pfkey_extensions_free(extensions);
pfkey_msg_free(&pfkey_msg);
return success;
@@ -465,11 +334,10 @@ pfkey_register_response(const struct sadb_msg *msg)
kernel_alg_register_pfkey(msg, sizeof (pfkey_buf));
#endif
break;
case SADB_X_SATYPE_COMP:
case SADB_X_SATYPE_IPCOMP:
/* ??? There ought to be an extension to list the
* supported algorithms, but RFC 2367 doesn't
* list one for IPcomp. KLIPS uses SADB_X_CALG_DEFLATE.
* Since we only implement deflate, we'll assume this.
* list one for IPcomp.
*/
can_do_IPcomp = TRUE;
break;
@@ -479,40 +347,41 @@ pfkey_register_response(const struct sadb_msg *msg)
}
/** register SA types that can be negotiated */
void
static void
pfkey_register_proto(unsigned satype, const char *satypename)
{
struct sadb_ext *extensions[SADB_EXT_MAX + 1];
pfkey_buf pfb;
if (!(pfkey_msg_start(SADB_REGISTER
, satype
, satypename, NULL, extensions)
&& finish_pfkey_msg(extensions, satypename, "", &pfb)))
if (!(pfkey_msg_start(SADB_REGISTER, satype, satypename, NULL, extensions)
&& finish_pfkey_msg(extensions, satypename, "", &pfb)))
{
/* ??? should this be loglog */
plog("no KLIPS support for %s", satypename);
plog("no kernel support for %s", satypename);
}
else
{
kernel_ops->pfkey_register_response(&pfb.msg);
pfkey_register_response(&pfb.msg);
DBG(DBG_KLIPS,
DBG_log("%s registered with kernel.", satypename));
}
}
void
pfkey_close(void)
pfkey_register(void)
{
while (pfkey_iq_head != NULL)
{
pfkey_item *it = pfkey_iq_head;
pid = getpid();
pfkey_iq_head = it->next;
free(it);
pfkeyfd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
if (pfkeyfd == -1)
{
exit_log_errno((e, "socket() in init_pfkeyfd()"));
}
pfkey_register_proto(SADB_SATYPE_AH, "AH");
pfkey_register_proto(SADB_SATYPE_ESP, "ESP");
pfkey_register_proto(SADB_X_SATYPE_IPCOMP, "IPCOMP");
close(pfkeyfd);
pfkeyfd = NULL_FD;
}
#endif /* KLIPS */
+8 -6
View File
@@ -1,6 +1,6 @@
/* declarations of routines that interface with the kernel's pfkey mechanism
* Copyright (C) 1998-2001 D. Hugh Redelmeier.
* Copyright (C) 2003 Herbert Xu
/*
* Copyright (C) 2010 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -14,7 +14,9 @@
*/
#ifdef KLIPS
extern void init_pfkey(void);
extern void pfkey_register_proto(unsigned satype, const char *satypename);
extern void pfkey_close(void);
/**
* Register our capabilities via PF_KEY, also learn the kernel's capabilities,
* i.e. the supported algorithms.
*/
void pfkey_register();
#endif