parse xfrm and pf_key acquire messages and subscribe to migrate messages
authorAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 31 Oct 2008 01:43:23 +0000 (01:43 -0000)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 31 Oct 2008 01:43:23 +0000 (01:43 -0000)
src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c
src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
src/charon/processing/jobs/acquire_job.c
src/charon/processing/jobs/acquire_job.h

index 1b526e6..d5ff479 100644 (file)
@@ -381,6 +381,53 @@ static struct xfrm_selector ts2selector(traffic_selector_t *src,
        return sel;
 }
 
+/**
+ * convert a xfrm_selector to a src|dst traffic_selector 
+ */
+static traffic_selector_t* selector2ts(struct xfrm_selector *sel, bool src)
+{
+       ts_type_t type;
+       chunk_t addr;
+       u_int16_t port, port_mask, from_port, to_port;
+
+       if (src)
+       {
+               addr.ptr = (u_char*)&sel->saddr;
+               port = sel->sport;
+               port_mask = sel->sport_mask;
+       }
+    else
+       {
+               addr.ptr = (u_char*)&sel->daddr;
+               port = sel->dport;
+               port_mask = sel->dport_mask;
+       }
+       /* The Linux 2.6 kernel does not set the selector's family field,
+     * so as a kludge we additionally test the prefix length. 
+        */
+       if (sel->family == AF_INET || sel->prefixlen_d == 32)
+       {
+               type = TS_IPV4_ADDR_RANGE;
+               addr.len = 4;
+       }
+       else
+       {
+               type = TS_IPV6_ADDR_RANGE;
+               addr.len = 16;
+       } 
+       if (port_mask == 0)
+       {
+               from_port = 0;
+               to_port = 65535;
+       }
+       else
+       {
+               from_port = to_port = ntohs(port); 
+       }
+               
+       return traffic_selector_create_from_bytes(sel->proto, type,
+                                                                                         addr, from_port, addr, to_port);
+}
 
 /**
  * process a XFRM_MSG_ACQUIRE from kernel
@@ -389,15 +436,22 @@ static void process_acquire(private_kernel_netlink_ipsec_t *this, struct nlmsghd
 {
        u_int32_t reqid = 0;
        int proto = 0;
+       traffic_selector_t *src_ts, *dst_ts;
+       struct xfrm_user_acquire *acquire;
+       struct rtattr *rtattr;
+       size_t rtsize;
        job_t *job;
-       struct rtattr *rtattr = XFRM_RTA(hdr, struct xfrm_user_acquire);
-       size_t rtsize = XFRM_PAYLOAD(hdr, struct xfrm_user_tmpl);
        
+       rtattr = XFRM_RTA(hdr, struct xfrm_user_acquire);
+       rtsize = XFRM_PAYLOAD(hdr, struct xfrm_user_tmpl);
+
        if (RTA_OK(rtattr, rtsize))
        {
                if (rtattr->rta_type == XFRMA_TMPL)
                {
-                       struct xfrm_user_tmpl* tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rtattr);
+                       struct xfrm_user_tmpl* tmpl;
+
+                       tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rtattr);
                        reqid = tmpl->reqid;
                        proto = tmpl->id.proto;
                }
@@ -412,14 +466,14 @@ static void process_acquire(private_kernel_netlink_ipsec_t *this, struct nlmsghd
                        /* acquire for AH/ESP only, not for IPCOMP */
                        return;
        }
-       if (reqid == 0)
-       {
-               DBG1(DBG_KNL, "received a XFRM_MSG_ACQUIRE, but no reqid found");
-               return;
-       }
        DBG2(DBG_KNL, "received a XFRM_MSG_ACQUIRE");
-       DBG1(DBG_KNL, "creating acquire job for CHILD_SA with reqid {%d}", reqid);
-       job = (job_t*)acquire_job_create(reqid);
+
+       acquire = (struct xfrm_user_acquire*)NLMSG_DATA(hdr);
+       src_ts = selector2ts(&acquire->sel, TRUE);
+       dst_ts = selector2ts(&acquire->sel, FALSE);
+       DBG1(DBG_KNL, "creating acquire job %R === %R for CHILD_SA with reqid {%d}",
+                                       src_ts, dst_ts, reqid);
+       job = (job_t*)acquire_job_create(reqid, src_ts, dst_ts);
        charon->processor->queue_job(charon->processor, job);
 }
 
@@ -462,6 +516,14 @@ static void process_expire(private_kernel_netlink_ipsec_t *this, struct nlmsghdr
 }
 
 /**
+ * process a XFRM_MSG_MIGRATE from kernel
+ */
+static void process_migrate(private_kernel_netlink_ipsec_t *this, struct nlmsghdr *hdr)
+{
+       DBG2(DBG_KNL, "received a XFRM_MSG_MIGRATE");
+}
+
+/**
  * process a XFRM_MSG_MAPPING from kernel
  */
 static void process_mapping(private_kernel_netlink_ipsec_t *this,
@@ -540,6 +602,9 @@ static job_requeue_t receive_events(private_kernel_netlink_ipsec_t *this)
                        case XFRM_MSG_EXPIRE:
                                process_expire(this, hdr);
                                break;
+                       case XFRM_MSG_MIGRATE:
+                               process_migrate(this, hdr);
+                               break;
                        case XFRM_MSG_MAPPING:
                                process_mapping(this, hdr);
                                break;
index 50d6322..cb4d006 100644 (file)
@@ -28,6 +28,7 @@
 #include "kernel_pfkey_ipsec.h"
 
 #include <daemon.h>
+#include <utils/host.h>
 #include <processing/jobs/callback_job.h>
 #include <processing/jobs/acquire_job.h>
 #include <processing/jobs/rekey_child_sa_job.h>
@@ -39,7 +40,7 @@
 #define PRIO_HIGH 2000
 
 /** buffer size for PF_KEY messages */
-#define PFKEY_BUFFER_SIZE 2048
+#define PFKEY_BUFFER_SIZE 4096
 
 /** PF_KEY messages are 64 bit aligned */
 #define PFKEY_ALIGNMENT 8
@@ -289,10 +290,39 @@ struct pfkey_msg_t
                        struct sadb_x_nat_t_port *x_natt_dport; /* SADB_X_EXT_NAT_T_DPORT */
                        struct sadb_address *x_natt_oa;                 /* SADB_X_EXT_NAT_T_OA */
                        struct sadb_x_sec_ctx *x_sec_ctx;               /* SADB_X_EXT_SEC_CTX */
+                       struct sadb_x_kmaddress *x_kmaddress;   /* SADB_X_EXT_KMADDRESS */
                } __attribute__((__packed__));
        };
 };
 
+ENUM(sadb_ext_type_names, SADB_EXT_RESERVED, SADB_X_EXT_KMADDRESS,
+       "SADB_EXT_RESERVED",
+       "SADB_EXT_SA",
+       "SADB_EXT_LIFETIME_CURRENT",
+       "SADB_EXT_LIFETIME_HARD",
+       "SADB_EXT_LIFETIME_SOFT",
+       "SADB_EXT_ADDRESS_SRC",
+       "SADB_EXT_ADDRESS_DST",
+       "SADB_EXT_ADDRESS_PROXY",
+       "SADB_EXT_KEY_AUTH",
+       "SADB_EXT_KEY_ENCRYPT",
+       "SADB_EXT_IDENTITY_SRC",
+       "SADB_EXT_IDENTITY_DST",
+       "SADB_EXT_SENSITIVITY",
+       "SADB_EXT_PROPOSAL",
+       "SADB_EXT_SUPPORTED_AUTH",
+       "SADB_EXT_SUPPORTED_ENCRYPT",
+       "SADB_EXT_SPIRANGE",
+       "SADB_X_EXT_KMPRIVATE",
+       "SADB_X_EXT_POLICY",
+       "SADB_X_EXT_SA2",
+       "SADB_X_EXT_NAT_T_TYPE",
+       "SADB_X_EXT_NAT_T_SPORT",
+       "SADB_X_EXT_NAT_T_DPORT",
+       "SADB_X_EXT_NAT_T_OA",
+       "SADB_X_EXT_SEC_CTX",
+       "SADB_X_EXT_KMADDRESS"
+);
 /**
  * convert a IKEv2 specific protocol identifier to the PF_KEY sa type
  */
@@ -415,13 +445,13 @@ static kernel_algorithm_t encryption_algs[] = {
 /*     {ENCR_DES_IV32,                         0                                                       }, */
        {ENCR_NULL,                             SADB_EALG_NULL                          },
        {ENCR_AES_CBC,                          SADB_X_EALG_AESCBC                      },
-/*     {ENCR_AES_CTR,                          0                                                       }, */
-/*     {ENCR_AES_CCM_ICV8,                     0                                                       }, */
-/*     {ENCR_AES_CCM_ICV12,            0                                                       }, */
-/*     {ENCR_AES_CCM_ICV16,            0                                                       }, */
-/*     {ENCR_AES_GCM_ICV8,                     0                                                       }, */
-/*     {ENCR_AES_GCM_ICV12,            0                                                       }, */
-/*     {ENCR_AES_GCM_ICV16,            0                                                       }, */
+/*     {ENCR_AES_CTR,                          SADB_X_EALG_AESCTR                      }, */
+/*  {ENCR_AES_CCM_ICV8,                        SADB_X_EALG_AES_CCM_ICV8        }, */
+/*     {ENCR_AES_CCM_ICV12,            SADB_X_EALG_AES_CCM_ICV12       }, */
+/*     {ENCR_AES_CCM_ICV16,            SADB_X_EALG_AES_CCM_ICV16       }, */
+/*     {ENCR_AES_GCM_ICV8,                     SADB_X_EALG_AES_GCM_ICV8        }, */
+/*     {ENCR_AES_GCM_ICV12,            SADB_X_EALG_AES_GCM_ICV12       }, */
+/*     {ENCR_AES_GCM_ICV16,            SADB_X_EALG_AES_GCM_ICV16       }, */
        {END_OF_LIST,                           0                                                       },
 };
 
@@ -506,6 +536,40 @@ static void add_encap_ext(struct sadb_msg *msg, host_t *src, host_t *dst)
 }
 
 /**
+ * Convert a sadb_address to a traffic_selector
+ */
+static traffic_selector_t* sadb_address2ts(struct sadb_address *address)
+{
+       traffic_selector_t *ts;
+       ts_type_t type;
+       chunk_t addr;
+       host_t *host;
+       u_int16_t port, from_port, to_port;
+
+       /* The Linux 2.6 kernel does not set the protocol and port information
+     * in the src and dst sadb_address extensions of the SADB_ACQUIRE message.
+     */
+       host = host_create_from_sockaddr((sockaddr_t*)&address[1])      ;
+       type = (host->get_family(host) == AF_INET) ? TS_IPV4_ADDR_RANGE :
+                                                                                                TS_IPV6_ADDR_RANGE;
+       addr = host->get_address(host);
+       port = host->get_port(host);
+       if (port == 0)
+       {
+               from_port = 0;
+               to_port = 65535;
+       }
+       else
+       {
+               from_port = to_port = port; 
+       }
+       ts = traffic_selector_create_from_bytes(address->sadb_address_proto, type,
+                                                                                       addr, from_port, addr, to_port);
+       host->destroy(host);
+       return ts;
+}
+
+/**
  * Parses a pfkey message received from the kernel
  */
 static status_t parse_pfkey_message(struct sadb_msg *msg, pfkey_msg_t *out)
@@ -523,10 +587,12 @@ static status_t parse_pfkey_message(struct sadb_msg *msg, pfkey_msg_t *out)
        
        while (len >= PFKEY_LEN(sizeof(struct sadb_ext)))
        {
+               DBG2(DBG_KNL, "  %N", sadb_ext_type_names, ext->sadb_ext_type);
                if (ext->sadb_ext_len < PFKEY_LEN(sizeof(struct sadb_ext)) ||
                        ext->sadb_ext_len > len)
                {
-                       DBG1(DBG_KNL, "length of PF_KEY extension (%d) is invalid", ext->sadb_ext_type);
+                       DBG1(DBG_KNL, "length of %N extension is invalid",
+                                                  sadb_ext_type_names, ext->sadb_ext_type);
                        break;
                }
                
@@ -538,7 +604,8 @@ static status_t parse_pfkey_message(struct sadb_msg *msg, pfkey_msg_t *out)
                
                if (out->ext[ext->sadb_ext_type])
                {
-                       DBG1(DBG_KNL, "duplicate PF_KEY extension of type (%d)", ext->sadb_ext_type);                   
+                       DBG1(DBG_KNL, "duplicate %N extension",                 
+                                                  sadb_ext_type_names, ext->sadb_ext_type);
                        break;
                }
                
@@ -670,7 +737,8 @@ static status_t pfkey_send(private_kernel_pfkey_ipsec_t *this,
 static void process_acquire(private_kernel_pfkey_ipsec_t *this, struct sadb_msg* msg)
 {
        pfkey_msg_t response;
-       u_int32_t index, reqid;
+       u_int32_t index, reqid = 0;
+       traffic_selector_t *src_ts, *dst_ts;
        policy_entry_t *policy;
        job_t *job;
        
@@ -684,6 +752,7 @@ static void process_acquire(private_kernel_pfkey_ipsec_t *this, struct sadb_msg*
                        /* acquire for AH/ESP only */
                        return;
        }
+       DBG2(DBG_KNL, "received an SADB_ACQUIRE");
        
        if (parse_pfkey_message(msg, &response) != SUCCESS)
        {
@@ -692,22 +761,24 @@ static void process_acquire(private_kernel_pfkey_ipsec_t *this, struct sadb_msg*
        }
        
        index = response.x_policy->sadb_x_policy_id;
-       DBG2(DBG_KNL, "received an SADB_ACQUIRE, %d", index);
        pthread_mutex_lock(&this->mutex);
        if (this->policies->find_first(this->policies,
-                       (linked_list_match_t)policy_entry_match_byindex, (void**)&policy, &index) != SUCCESS)
+                       (linked_list_match_t)policy_entry_match_byindex, (void**)&policy, &index) == SUCCESS)
        {
-               DBG1(DBG_KNL, "received an SADB_ACQUIRE, but found no matching policy");
-               pthread_mutex_unlock(&this->mutex);
-               return;
+               reqid = policy->reqid;
        }
-       reqid = policy->reqid;
-       DBG2(DBG_KNL, "received an SADB_ACQUIRE, %d", reqid);
+       else
+       {
+               DBG1(DBG_KNL, "received an SADB_ACQUIRE with policy id %d but no matching policy found",
+                                          index);
+       }
+       src_ts = sadb_address2ts(response.src);
+       dst_ts = sadb_address2ts(response.dst);
        pthread_mutex_unlock(&this->mutex);
        
-       DBG2(DBG_KNL, "received an SADB_ACQUIRE");
-       DBG1(DBG_KNL, "creating acquire job for CHILD_SA with reqid {%d}", reqid);
-       job = (job_t*)acquire_job_create(reqid);
+       DBG1(DBG_KNL, "creating acquire job %R === %R for CHILD_SA with reqid {%d}",
+                                       src_ts, dst_ts, reqid);
+       job = (job_t*)acquire_job_create(reqid, src_ts, dst_ts);
        charon->processor->queue_job(charon->processor, job);
 }
 
@@ -757,6 +828,22 @@ static void process_expire(private_kernel_pfkey_ipsec_t *this, struct sadb_msg*
 }
 
 /**
+ * Process a SADB_MIGRATE message from the kernel
+ */
+static void process_migrate(private_kernel_pfkey_ipsec_t *this, struct sadb_msg* msg)
+{
+       pfkey_msg_t response;
+
+       DBG2(DBG_KNL, "received an SADB_X_MIGRATE");
+
+       if (parse_pfkey_message(msg, &response) != SUCCESS)
+       {
+               DBG1(DBG_KNL, "parsing SADB_X_MIGRATE from kernel failed");
+               return;
+       }
+}
+
+/**
  * Process a SADB_X_NAT_T_NEW_MAPPING message from the kernel
  */
 static void process_mapping(private_kernel_pfkey_ipsec_t *this, struct sadb_msg* msg)
@@ -866,6 +953,9 @@ static job_requeue_t receive_events(private_kernel_pfkey_ipsec_t *this)
                case SADB_EXPIRE:
                        process_expire(this, msg);
                        break;
+               case SADB_X_MIGRATE:
+                       process_migrate(this, msg);
+                       break;
                case SADB_X_NAT_T_NEW_MAPPING:
                        process_mapping(this, msg);
                        break;
index e066cba..9767496 100644 (file)
@@ -35,6 +35,16 @@ struct private_acquire_job_t {
         * reqid of the child to rekey
         */
        u_int32_t reqid;
+
+       /**
+        * acquired source traffic selector
+        */
+       traffic_selector_t *src_ts;
+
+       /**
+        * acquired destination traffic selector
+        */
+       traffic_selector_t *dst_ts;
 };
 
 /**
@@ -42,6 +52,8 @@ struct private_acquire_job_t {
  */
 static void destroy(private_acquire_job_t *this)
 {
+       DESTROY_IF(this->src_ts);
+       DESTROY_IF(this->dst_ts);
        free(this);
 }
 
@@ -50,13 +62,16 @@ static void destroy(private_acquire_job_t *this)
  */
 static void execute(private_acquire_job_t *this)
 {
-       ike_sa_t *ike_sa;
+       ike_sa_t *ike_sa = NULL;
        
-       ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
-                                                                                                       this->reqid, TRUE);
+       if (this->reqid)
+       {
+               ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+                                                                                                               this->reqid, TRUE);
+       }
        if (ike_sa == NULL)
        {
-               DBG2(DBG_JOB, "CHILD_SA with reqid %d not found for acquiring",
+               DBG1(DBG_JOB, "acquire job found no CHILD_SA with reqid {%d}",
                         this->reqid);
        }
        else
@@ -71,7 +86,9 @@ static void execute(private_acquire_job_t *this)
 /*
  * Described in header
  */
-acquire_job_t *acquire_job_create(u_int32_t reqid)
+acquire_job_t *acquire_job_create(u_int32_t reqid,
+                                                                 traffic_selector_t *src_ts,
+                                                                 traffic_selector_t *dst_ts)
 {
        private_acquire_job_t *this = malloc_thing(private_acquire_job_t);
        
@@ -81,6 +98,8 @@ acquire_job_t *acquire_job_create(u_int32_t reqid)
        
        /* private variables */
        this->reqid = reqid;
+       this->src_ts = src_ts;
+       this->dst_ts = dst_ts;
        
        return &this->public;
 }
index b256c7f..edbd51d 100644 (file)
@@ -26,6 +26,7 @@
 typedef struct acquire_job_t acquire_job_t;
 
 #include <library.h>
+#include <config/traffic_selector.h>
 #include <processing/jobs/job.h>
 
 /**
@@ -46,8 +47,12 @@ struct acquire_job_t {
  * We use the reqid to find the routed CHILD_SA.
  *
  * @param reqid                reqid of the CHILD_SA to acquire
+ * @param src_ts       source traffic selector
+ * @param dst_ts       destination traffic selector
  * @return                     acquire_job_t object
  */
-acquire_job_t *acquire_job_create(u_int32_t reqid);
+acquire_job_t *acquire_job_create(u_int32_t reqid,
+                                                                 traffic_selector_t *src_ts,
+                                                                 traffic_selector_t *dst_ts);
 
 #endif /* REKEY_CHILD_SA_JOB_H_ @} */