pluto: Refactored PF_KEY capabilities registration.
authorTobias Brunner <tobias@strongswan.org>
Mon, 16 Aug 2010 08:33:37 +0000 (10:33 +0200)
committerTobias Brunner <tobias@strongswan.org>
Thu, 2 Sep 2010 17:04:23 +0000 (19:04 +0200)
Although we use the kernel interface from libhydra we still need this to make
the available algorithms known to pluto.

src/pluto/kernel.c
src/pluto/kernel_pfkey.c
src/pluto/kernel_pfkey.h

index fbe5726..c140d67 100644 (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,
index 9aaf7ca..a0519de 100644 (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
 #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)
-       {
-               return TRUE;
-       }
-       else
+       if (error != 0)
        {
-               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 */
index 8a51820..87c3cb4 100644 (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