userland support to process notifies for new NAT mappings detected in UDP encapsulation
authorMartin Willi <martin@strongswan.org>
Tue, 7 Oct 2008 07:55:28 +0000 (07:55 -0000)
committerMartin Willi <martin@strongswan.org>
Tue, 7 Oct 2008 07:55:28 +0000 (07:55 -0000)
src/charon/Makefile.am
src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c
src/charon/processing/jobs/update_sa_job.c [new file with mode: 0644]
src/charon/processing/jobs/update_sa_job.h [new file with mode: 0644]
src/charon/sa/ike_sa.c
src/include/linux/xfrm.h

index eec14cc..464d82f 100644 (file)
@@ -59,6 +59,7 @@ processing/jobs/retransmit_job.c processing/jobs/retransmit_job.h \
 processing/jobs/send_dpd_job.c processing/jobs/send_dpd_job.h \
 processing/jobs/send_keepalive_job.c processing/jobs/send_keepalive_job.h \
 processing/jobs/roam_job.c processing/jobs/roam_job.h \
+processing/jobs/update_sa_job.c processing/jobs/update_sa_job.h \
 processing/scheduler.c processing/scheduler.h \
 processing/processor.c processing/processor.h  \
 sa/authenticators/authenticator.c sa/authenticators/authenticator.h \
index 58900b8..3fe6823 100644 (file)
@@ -41,6 +41,7 @@
 #include <processing/jobs/acquire_job.h>
 #include <processing/jobs/rekey_child_sa_job.h>
 #include <processing/jobs/delete_child_sa_job.h>
+#include <processing/jobs/update_sa_job.h>
 
 /** required for Linux 2.6.26 kernel and later */
 #ifndef XFRM_STATE_AF_UNSPEC
 #define PRIO_HIGH 2000
 
 /**
+ * Create ORable bitfield of XFRM NL groups
+ */
+#define XFRMNLGRP(x) (1<<(XFRMNLGRP_##x-1))
+
+/**
  * returns a pointer to the first rtattr following the nlmsghdr *nlh and the 
  * 'usual' netlink data x like 'struct xfrm_usersa_info' 
  */
@@ -312,6 +318,27 @@ static void host2xfrm(host_t *host, xfrm_address_t *xfrm)
 }
 
 /**
+ * convert a struct xfrm_address to a host_t
+ */
+static host_t* xfrm2host(int family, xfrm_address_t *xfrm, u_int16_t port)
+{
+       chunk_t chunk;
+       
+       switch (family)
+       {
+               case AF_INET:
+                       chunk = chunk_create((u_char*)&xfrm->a4, sizeof(xfrm->a4));
+                       break;
+               case AF_INET6:
+                       chunk = chunk_create((u_char*)&xfrm->a6, sizeof(xfrm->a6));
+                       break;
+               default:
+                       return NULL;
+       }
+       return host_create_from_chunk(family, chunk, ntohs(port));
+}
+
+/**
  * convert a traffic selector address range to subnet and its mask.
  */
 static void ts2subnet(traffic_selector_t* ts, 
@@ -484,6 +511,37 @@ static void process_expire(private_kernel_netlink_ipsec_t *this, struct nlmsghdr
 }
 
 /**
+ * process a XFRM_MSG_MAPPING from kernel
+ */
+static void process_mapping(private_kernel_netlink_ipsec_t *this,
+                                                       struct nlmsghdr *hdr)
+{
+       job_t *job;
+       u_int32_t spi, reqid;
+       struct xfrm_user_mapping *mapping;
+       host_t *host;
+       
+       mapping = (struct xfrm_user_mapping*)NLMSG_DATA(hdr);
+       spi = mapping->id.spi;
+       reqid = mapping->reqid;
+       
+       DBG2(DBG_KNL, "received a XFRM_MSG_MAPPING");
+       
+       if (proto_kernel2ike(mapping->id.proto) == PROTO_ESP)
+       {
+               host = xfrm2host(mapping->id.family, &mapping->new_saddr,
+                                                mapping->new_sport);
+               if (host)
+               {
+                       DBG1(DBG_KNL, "NAT mappings of ESP CHILD_SA with SPI %.8x and "
+                               "reqid {%d} changed, queueing update job", ntohl(spi), reqid);
+                       job = (job_t*)update_sa_job_create(reqid, host);
+                       charon->processor->queue_job(charon->processor, job);
+               }
+       }
+}
+
+/**
  * Receives events from kernel
  */
 static job_requeue_t receive_events(private_kernel_netlink_ipsec_t *this)
@@ -531,6 +589,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_MAPPING:
+                               process_mapping(this, hdr);
+                               break;
                        default:
                                break;
                }
@@ -1686,7 +1747,7 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
        {
                charon->kill(charon, "unable to create XFRM event socket");
        }
-       addr.nl_groups = XFRMGRP_ACQUIRE | XFRMGRP_EXPIRE;
+       addr.nl_groups = XFRMNLGRP(ACQUIRE) | XFRMNLGRP(EXPIRE) | XFRMNLGRP(MAPPING);
        if (bind(this->socket_xfrm_events, (struct sockaddr*)&addr, sizeof(addr)))
        {
                charon->kill(charon, "unable to bind XFRM event socket");
diff --git a/src/charon/processing/jobs/update_sa_job.c b/src/charon/processing/jobs/update_sa_job.c
new file mode 100644 (file)
index 0000000..acf263d
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * 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
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * $Id$
+ */
+
+#include <stdlib.h>
+
+#include "update_sa_job.h"
+
+#include <sa/ike_sa.h>
+#include <daemon.h>
+
+
+typedef struct private_update_sa_job_t private_update_sa_job_t;
+
+/**
+ * Private data of an update_sa_job_t Object
+ */
+struct private_update_sa_job_t {
+       /**
+        * public update_sa_job_t interface
+        */
+       update_sa_job_t public;
+       
+       /**
+        * reqid of the CHILD_SA
+        */
+       u_int32_t reqid;
+       
+       /**
+        * New SA address and port
+        */
+       host_t *new;
+};
+
+/**
+ * Implements job_t.destroy.
+ */
+static void destroy(private_update_sa_job_t *this)
+{
+       this->new->destroy(this->new);
+       free(this);
+}
+
+/**
+ * Implementation of job_t.execute. 
+ */ 
+static void execute(private_update_sa_job_t *this)
+{
+       ike_sa_t *ike_sa;
+       
+       ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+                                                                                                       this->reqid, TRUE);
+       if (ike_sa == NULL)
+       {
+               DBG1(DBG_JOB, "CHILD_SA with reqid %d not found for update", this->reqid);
+       }
+       else
+       {
+               /* we update only if other host is NATed, but not our */
+               if (ike_sa->has_condition(ike_sa, COND_NAT_THERE) &&
+                       !ike_sa->has_condition(ike_sa, COND_NAT_HERE))
+               {
+                       ike_sa->update_hosts(ike_sa, NULL, this->new);
+               }
+               charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+       }
+       destroy(this);
+}
+
+/*
+ * Described in header
+ */
+update_sa_job_t *update_sa_job_create(u_int32_t reqid, host_t *new)
+{
+       private_update_sa_job_t *this = malloc_thing(private_update_sa_job_t);
+       
+       this->public.job_interface.execute = (void (*) (job_t *)) execute;
+       this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
+       
+       this->reqid = reqid;
+       this->new = new;
+
+       return &this->public;
+}
+
diff --git a/src/charon/processing/jobs/update_sa_job.h b/src/charon/processing/jobs/update_sa_job.h
new file mode 100644 (file)
index 0000000..5a350d9
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * 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
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * $Id$
+ */
+
+/**
+ * @defgroup update_sa_job update_sa_job
+ * @{ @ingroup jobs
+ */
+
+#ifndef UPDATE_SA_JOB_H_
+#define UPDATE_SA_JOB_H_
+
+typedef struct update_sa_job_t update_sa_job_t;
+
+#include <library.h>
+#include <utils/host.h>
+#include <processing/jobs/job.h>
+
+/**
+ * Update the addresses of an IKE and its CHILD_SAs.
+ */
+struct update_sa_job_t {
+
+       /**
+        * implements job_t interface
+        */
+       job_t job_interface;
+};
+
+/**
+ * Creates a job to update IKE and CHILD_SA addresses.
+ * 
+ * @param reqid                        reqid of the CHILD_SA
+ * @param new                  new address and port
+ * @return                             update_sa_job_t object
+ */
+update_sa_job_t *update_sa_job_create(u_int32_t reqid, host_t *new);
+
+#endif /*UPDATE_SA_JOB_H_ @} */
index 351e282..575ae4d 100644 (file)
@@ -877,11 +877,6 @@ static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
 {
        bool update = FALSE;
        
-       if (supports_extension(this, EXT_MOBIKE))
-       {       /* if peer speaks mobike, address updates are explicit only */
-               return;
-       }
-       
        if (me == NULL)
        {
                me = this->my_host;
@@ -1461,7 +1456,10 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
                if (this->state == IKE_CREATED || this->state == IKE_CONNECTING ||
                        message->get_exchange_type(message) != IKE_SA_INIT)
                {
-                       update_hosts(this, me, other);
+                       if (!supports_extension(this, EXT_MOBIKE))
+                       {       /* with MOBIKE, we do no implicit updates */
+                               update_hosts(this, me, other);
+                       }
                        this->time.inbound = time(NULL);
                }
                status = this->task_manager->process_message(this->task_manager, message);
index d4e9e50..759885c 100644 (file)
@@ -97,10 +97,10 @@ struct xfrm_algo {
 };
 
 struct xfrm_algo_aead {
-       char    alg_name[64];
-       int     alg_key_len;    /* in bits */
-       int     alg_icv_len;    /* in bits */
-       char    alg_key[0];
+       char            alg_name[64];
+       unsigned int    alg_key_len;    /* in bits */
+       unsigned int    alg_icv_len;    /* in bits */
+       char            alg_key[0];
 };
 
 struct xfrm_stats {
@@ -113,7 +113,8 @@ enum
 {
        XFRM_POLICY_TYPE_MAIN   = 0,
        XFRM_POLICY_TYPE_SUB    = 1,
-       XFRM_POLICY_TYPE_MAX    = 2
+       XFRM_POLICY_TYPE_MAX    = 2,
+       XFRM_POLICY_TYPE_ANY    = 255
 };
 
 enum
@@ -198,6 +199,9 @@ enum {
 #define XFRM_MSG_NEWSPDINFO XFRM_MSG_NEWSPDINFO
        XFRM_MSG_GETSPDINFO,
 #define XFRM_MSG_GETSPDINFO XFRM_MSG_GETSPDINFO
+
+       XFRM_MSG_MAPPING,
+#define XFRM_MSG_MAPPING XFRM_MSG_MAPPING
        __XFRM_MSG_MAX
 };
 #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1)
@@ -427,6 +431,15 @@ struct xfrm_user_migrate {
        __u16                           new_family;
 };
 
+struct xfrm_user_mapping {
+       struct xfrm_usersa_id           id;
+       __u32                           reqid;
+       xfrm_address_t                  old_saddr;
+       xfrm_address_t                  new_saddr;
+       __be16                          old_sport;
+       __be16                          new_sport;
+};
+
 #ifndef __KERNEL__
 /* backwards compatibility for userspace */
 #define XFRMGRP_ACQUIRE                1
@@ -453,6 +466,8 @@ enum xfrm_nlgroups {
 #define XFRMNLGRP_REPORT       XFRMNLGRP_REPORT
        XFRMNLGRP_MIGRATE,
 #define XFRMNLGRP_MIGRATE      XFRMNLGRP_MIGRATE
+       XFRMNLGRP_MAPPING,
+#define XFRMNLGRP_MAPPING      XFRMNLGRP_MAPPING
        __XFRMNLGRP_MAX
 };
 #define XFRMNLGRP_MAX  (__XFRMNLGRP_MAX - 1)