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
{
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;
}
/* 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);
}
}
/**
+ * 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,
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;
#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>
#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
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
*/
/* {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 },
};
}
/**
+ * 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)
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;
}
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;
}
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;
/* acquire for AH/ESP only */
return;
}
+ DBG2(DBG_KNL, "received an SADB_ACQUIRE");
if (parse_pfkey_message(msg, &response) != SUCCESS)
{
}
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);
}
}
/**
+ * 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)
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;