first merge of NATT code
This commit is contained in:
@@ -36,13 +36,15 @@ encoding/payloads/sa_payload.h encoding/payloads/vendor_id_payload.c encoding/pa
|
||||
encoding/payloads/vendor_id_payload.h encoding/payloads/proposal_substructure.c encoding/payloads/payload.c \
|
||||
encoding/parser.h encoding/message.c encoding/generator.c encoding/message.h encoding/generator.h \
|
||||
encoding/parser.c daemon.c daemon.h network/packet.c \
|
||||
network/socket.c network/packet.h network/socket.h queues/jobs/job.h queues/jobs/job.c \
|
||||
network/interfaces.c network/interfaces.h network/socket.c network/packet.h network/socket.h queues/jobs/job.h queues/jobs/job.c \
|
||||
queues/jobs/delete_established_ike_sa_job.c queues/jobs/retransmit_request_job.h queues/jobs/initiate_ike_sa_job.h \
|
||||
queues/jobs/incoming_packet_job.c queues/jobs/delete_half_open_ike_sa_job.c \
|
||||
queues/jobs/delete_established_ike_sa_job.h queues/jobs/delete_half_open_ike_sa_job.h \
|
||||
queues/jobs/incoming_packet_job.h queues/jobs/retransmit_request_job.c queues/jobs/initiate_ike_sa_job.c \
|
||||
queues/jobs/send_keepalive_job.c queues/jobs/send_keepalive_job.h \
|
||||
queues/jobs/rekey_child_sa_job.c queues/jobs/rekey_child_sa_job.h \
|
||||
queues/jobs/delete_child_sa_job.c queues/jobs/delete_child_sa_job.h \
|
||||
queues/jobs/send_dpd_job.c queues/jobs/send_dpd_job.h \
|
||||
queues/job_queue.c queues/event_queue.c queues/send_queue.h queues/job_queue.h queues/event_queue.h \
|
||||
queues/send_queue.c threads/kernel_interface.c threads/thread_pool.c threads/scheduler.c threads/sender.c \
|
||||
threads/sender.h threads/kernel_interface.h threads/scheduler.h threads/receiver.c threads/stroke_interface.c \
|
||||
@@ -50,4 +52,4 @@ threads/thread_pool.h threads/receiver.h threads/stroke_interface.h
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon -I$(top_srcdir)/src/stroke
|
||||
AM_CFLAGS = -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\"
|
||||
charon_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lgmp -lpthread
|
||||
charon_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lgmp -lpthread -lm
|
||||
|
||||
@@ -21,28 +21,50 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
#include <types.h>
|
||||
|
||||
/**
|
||||
* First retransmit timeout in milliseconds.
|
||||
* Timeout value is increasing in each retransmit round.
|
||||
*/
|
||||
#define RETRANSMIT_TIMEOUT 2500
|
||||
|
||||
/**
|
||||
* Timeout in milliseconds after that a half open IKE_SA gets deleted.
|
||||
*/
|
||||
#define HALF_OPEN_IKE_SA_TIMEOUT 30000
|
||||
|
||||
/**
|
||||
* First retransmit timeout in milliseconds.
|
||||
* Timeout value is increasing in each retransmit round.
|
||||
*/
|
||||
#define RETRANSMIT_TIMEOUT 6000
|
||||
|
||||
/**
|
||||
* Base which is raised to the power of the retransmission count.
|
||||
*/
|
||||
#define RETRANSMIT_BASE 1.5
|
||||
|
||||
/**
|
||||
* Max retransmit count.
|
||||
* 0 for infinite. The max time a half open IKE_SA is alive is set by
|
||||
* RETRANSMIT_TIMEOUT.
|
||||
*/
|
||||
#define MAX_RETRANSMIT_COUNT 3
|
||||
#define MAX_RETRANSMIT_COUNT 6
|
||||
|
||||
/**
|
||||
* Keepalive interval in milliseconds.
|
||||
*/
|
||||
#define KEEPALIVE_INTERVAL 2000000
|
||||
|
||||
/**
|
||||
* Keepalive timeout in milliseconds.
|
||||
* Not implemented yet.
|
||||
*/
|
||||
#define KEEPALIVE_TIMEOUT 30000000
|
||||
|
||||
/**
|
||||
* DPD interval in milliseconds.
|
||||
*/
|
||||
#define DPD_INTERVAL 6000000
|
||||
|
||||
|
||||
typedef struct private_configuration_t private_configuration_t;
|
||||
@@ -64,19 +86,13 @@ struct private_configuration_t {
|
||||
*/
|
||||
static status_t get_retransmit_timeout (private_configuration_t *this, u_int32_t retransmit_count, u_int32_t *timeout)
|
||||
{
|
||||
int new_timeout = RETRANSMIT_TIMEOUT, i;
|
||||
if (retransmit_count >= MAX_RETRANSMIT_COUNT && MAX_RETRANSMIT_COUNT != 0)
|
||||
if (retransmit_count > MAX_RETRANSMIT_COUNT && MAX_RETRANSMIT_COUNT != 0)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
for (i = 0; i < retransmit_count; i++)
|
||||
{
|
||||
new_timeout *= 2;
|
||||
}
|
||||
|
||||
*timeout = new_timeout;
|
||||
|
||||
*timeout = (u_int32_t)(RETRANSMIT_TIMEOUT * pow(RETRANSMIT_BASE, retransmit_count));
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@@ -88,6 +104,30 @@ static u_int32_t get_half_open_ike_sa_timeout (private_configuration_t *this)
|
||||
return HALF_OPEN_IKE_SA_TIMEOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of configuration_t.get_keepalive_interval.
|
||||
*/
|
||||
static u_int32_t get_keepalive_interval (private_configuration_t *this)
|
||||
{
|
||||
return KEEPALIVE_INTERVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of configuration_t.get_keepalive_timeout.
|
||||
*/
|
||||
static u_int32_t get_keepalive_timeout (private_configuration_t *this)
|
||||
{
|
||||
return KEEPALIVE_TIMEOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of configuration_t.get_dpd_interval.
|
||||
*/
|
||||
static u_int32_t get_dpd_interval (private_configuration_t *this)
|
||||
{
|
||||
return DPD_INTERVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of configuration_t.destroy.
|
||||
*/
|
||||
@@ -107,6 +147,9 @@ configuration_t *configuration_create()
|
||||
this->public.destroy = (void(*)(configuration_t*))destroy;
|
||||
this->public.get_retransmit_timeout = (status_t (*) (configuration_t *, u_int32_t retransmit_count, u_int32_t *timeout))get_retransmit_timeout;
|
||||
this->public.get_half_open_ike_sa_timeout = (u_int32_t (*) (configuration_t *)) get_half_open_ike_sa_timeout;
|
||||
this->public.get_keepalive_interval = (u_int32_t (*) (configuration_t *)) get_keepalive_interval;
|
||||
this->public.get_keepalive_timeout = (u_int32_t (*) (configuration_t *)) get_keepalive_timeout;
|
||||
this->public.get_dpd_interval = (u_int32_t (*) (configuration_t *)) get_dpd_interval;
|
||||
|
||||
return (&this->public);
|
||||
}
|
||||
|
||||
@@ -69,6 +69,39 @@ struct configuration_t {
|
||||
*/
|
||||
u_int32_t (*get_half_open_ike_sa_timeout) (configuration_t *this);
|
||||
|
||||
/**
|
||||
* @brief Returns the keepalive interval in ms.
|
||||
*
|
||||
* The keepalive interval defines the idle time after which a
|
||||
* NAT keepalive packet should be sent.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return interval in milliseconds (ms)
|
||||
*/
|
||||
u_int32_t (*get_keepalive_interval) (configuration_t *this);
|
||||
|
||||
/**
|
||||
* @brief Returns the keepalive timeout in ms.
|
||||
*
|
||||
* The keepalive timeout defines how long we should keep sending
|
||||
* NAT keepalives after closing an IKE_SA.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return timeout in milliseconds (ms)
|
||||
*/
|
||||
u_int32_t (*get_keepalive_timeout) (configuration_t *this);
|
||||
|
||||
/**
|
||||
* @brief Returns the DPD interval in ms.
|
||||
*
|
||||
* The DPD interval defines the time after which a
|
||||
* DPD request packet should be sent.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return interval in milliseconds (ms)
|
||||
*/
|
||||
u_int32_t (*get_dpd_interval) (configuration_t *this);
|
||||
|
||||
/**
|
||||
* @brief Destroys a configuration_t object.
|
||||
*
|
||||
|
||||
+8
-1
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -170,7 +171,8 @@ static void initialize(private_daemon_t *this, bool strict)
|
||||
credential_store_t* credentials;
|
||||
|
||||
this->public.configuration = configuration_create();
|
||||
this->public.socket = socket_create(IKEV2_UDP_PORT);
|
||||
this->public.socket = socket_create(IKEV2_UDP_PORT, IKEV2_NATT_PORT);
|
||||
this->public.interfaces = interfaces_create(IKEV2_UDP_PORT);
|
||||
this->public.ike_sa_manager = ike_sa_manager_create();
|
||||
this->public.job_queue = job_queue_create();
|
||||
this->public.event_queue = event_queue_create();
|
||||
@@ -237,6 +239,10 @@ static void destroy(private_daemon_t *this)
|
||||
{
|
||||
this->public.event_queue->destroy(this->public.event_queue);
|
||||
}
|
||||
if (this->public.interfaces != NULL)
|
||||
{
|
||||
this->public.interfaces->destroy(this->public.interfaces);
|
||||
}
|
||||
if (this->public.configuration != NULL)
|
||||
{
|
||||
this->public.configuration->destroy(this->public.configuration);
|
||||
@@ -311,6 +317,7 @@ private_daemon_t *daemon_create(void)
|
||||
|
||||
/* NULL members for clean destruction */
|
||||
this->public.socket = NULL;
|
||||
this->public.interfaces = NULL;
|
||||
this->public.ike_sa_manager = NULL;
|
||||
this->public.job_queue = NULL;
|
||||
this->public.event_queue = NULL;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -30,6 +31,7 @@
|
||||
#include <threads/thread_pool.h>
|
||||
#include <threads/stroke_interface.h>
|
||||
#include <network/socket.h>
|
||||
#include <network/interfaces.h>
|
||||
#include <sa/ike_sa_manager.h>
|
||||
#include <queues/send_queue.h>
|
||||
#include <queues/job_queue.h>
|
||||
@@ -195,6 +197,13 @@
|
||||
*/
|
||||
#define IKEV2_UDP_PORT 500
|
||||
|
||||
/**
|
||||
* UDP Port to which the daemon will float to if NAT is detected.
|
||||
*
|
||||
* @ingroup charon
|
||||
*/
|
||||
#define IKEV2_NATT_PORT 4500
|
||||
|
||||
/**
|
||||
* PID file, in which charon stores its process id
|
||||
*
|
||||
@@ -264,6 +273,10 @@ struct daemon_t {
|
||||
* A socket_t instance.
|
||||
*/
|
||||
socket_t *socket;
|
||||
/**
|
||||
* A interfaces_t instance.
|
||||
*/
|
||||
interfaces_t *interfaces;
|
||||
|
||||
/**
|
||||
* A send_queue_t instance.
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -438,6 +439,14 @@ static u_int32_t get_message_id (private_message_t *this)
|
||||
return this->message_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of message_t.get_initiator_spi.
|
||||
*/
|
||||
static u_int64_t get_initiator_spi (private_message_t *this)
|
||||
{
|
||||
return (this->ike_sa_id->get_initiator_spi(this->ike_sa_id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of message_t.get_responder_spi.
|
||||
*/
|
||||
@@ -826,11 +835,13 @@ static status_t parse_body(private_message_t *this, crypter_t *crypter, signer_t
|
||||
}
|
||||
|
||||
if (current_payload_type == ENCRYPTED)
|
||||
status = this->decrypt_payloads(this,crypter,signer);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "could not decrypt payloads");
|
||||
return status;
|
||||
status = this->decrypt_payloads(this,crypter,signer);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "Could not decrypt payloads");
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
status = this->verify(this);
|
||||
@@ -1202,7 +1213,8 @@ message_t *message_create_from_packet(packet_t *packet)
|
||||
this->public.get_minor_version = (u_int8_t(*)(message_t*))get_minor_version;
|
||||
this->public.set_message_id = (void(*)(message_t*, u_int32_t))set_message_id;
|
||||
this->public.get_message_id = (u_int32_t(*)(message_t*))get_message_id;
|
||||
this->public.get_responder_spi = (u_int64_t(*)(message_t*))get_responder_spi;
|
||||
this->public.get_initiator_spi = (u_int64_t(*)(message_t*))get_initiator_spi;
|
||||
this->public.get_responder_spi = (u_int64_t(*)(message_t*))get_responder_spi;
|
||||
this->public.set_ike_sa_id = (void(*)(message_t*, ike_sa_id_t *))set_ike_sa_id;
|
||||
this->public.get_ike_sa_id = (status_t(*)(message_t*, ike_sa_id_t **))get_ike_sa_id;
|
||||
this->public.set_exchange_type = (void(*)(message_t*, exchange_type_t))set_exchange_type;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -100,6 +101,14 @@ struct message_t {
|
||||
*/
|
||||
u_int32_t (*get_message_id) (message_t *this);
|
||||
|
||||
/**
|
||||
* @brief Gets the initiator SPI of the message.
|
||||
*
|
||||
* @param this message_t object
|
||||
* @return initiator spi of the message
|
||||
*/
|
||||
u_int64_t (*get_initiator_spi) (message_t *this);
|
||||
|
||||
/**
|
||||
* @brief Gets the responder SPI of the message.
|
||||
*
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -48,6 +49,8 @@ mapping_t notify_message_type_m[] = {
|
||||
{INVALID_SELECTORS, "INVALID_SELECTORS"},
|
||||
{INITIAL_CONTACT, "INITIAL_CONTACT"},
|
||||
{SET_WINDOW_SIZE, "SET_WINDOW_SIZE"},
|
||||
{NAT_DETECTION_SOURCE_IP, "NAT_DETECTION_SOURCE_IP"},
|
||||
{NAT_DETECTION_DESTINATION_IP, "NAT_DETECTION_DESTINATION_IP"},
|
||||
{MAPPING_END, NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -65,6 +66,8 @@ enum notify_message_type_t {
|
||||
|
||||
INITIAL_CONTACT = 16384,
|
||||
SET_WINDOW_SIZE = 16385,
|
||||
NAT_DETECTION_SOURCE_IP = 16388,
|
||||
NAT_DETECTION_DESTINATION_IP = 16389,
|
||||
REKEY_SA = 16393,
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* @file interfaces.c
|
||||
*
|
||||
* @brief Implementation of interfaces_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <net/if.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "interfaces.h"
|
||||
|
||||
typedef struct private_interfaces_t private_interfaces_t;
|
||||
|
||||
/**
|
||||
* Private data of an interfaces_t object.
|
||||
*/
|
||||
struct private_interfaces_t {
|
||||
|
||||
/**
|
||||
* Public part of a interfaces_t object.
|
||||
*/
|
||||
interfaces_t public;
|
||||
|
||||
/**
|
||||
* port that gets added to the host_t obbjects
|
||||
*/
|
||||
u_int16_t port;
|
||||
|
||||
/**
|
||||
* list of addresses
|
||||
*/
|
||||
linked_list_t *addresses;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements interfaces_t.get_addresses
|
||||
*/
|
||||
static linked_list_t* get_addresses(private_interfaces_t *this)
|
||||
{
|
||||
return this->addresses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements interfaces_t.is_local_address
|
||||
*/
|
||||
static bool is_local_address(private_interfaces_t *this, host_t *host)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
host_t *lhost;
|
||||
|
||||
if (host->is_anyaddr(host))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
iterator = this->addresses->create_iterator(this->addresses, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)&lhost))
|
||||
{
|
||||
if (host->get_family(host) == lhost->get_family(lhost) &&
|
||||
streq(host->get_address(host), lhost->get_address(lhost)))
|
||||
{
|
||||
iterator->destroy(iterator);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
iterator->destroy(iterator);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements interfaces_t.destroy.
|
||||
*/
|
||||
static void destroy(private_interfaces_t *this)
|
||||
{
|
||||
host_t *host;
|
||||
while (this->addresses->remove_last(this->addresses, (void**)&host) == SUCCESS)
|
||||
{
|
||||
host->destroy(host);
|
||||
}
|
||||
this->addresses->destroy(this->addresses);
|
||||
free(this);
|
||||
}
|
||||
|
||||
static status_t initialize(private_interfaces_t *this)
|
||||
{
|
||||
struct ifaddrs *list;
|
||||
struct ifaddrs *cur;
|
||||
host_t *host;
|
||||
|
||||
if (getifaddrs(&list) < 0)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
for (cur = list; cur != NULL; cur = cur->ifa_next)
|
||||
{
|
||||
if (!(cur->ifa_flags & IFF_UP))
|
||||
continue;
|
||||
|
||||
if (cur->ifa_addr == NULL || cur->ifa_addr->sa_family != AF_INET)
|
||||
continue;
|
||||
|
||||
host = host_create_from_sockaddr(cur->ifa_addr);
|
||||
if (host) {
|
||||
host->set_port(host, this->port);
|
||||
this->addresses->insert_last(this->addresses, (void*) host);
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(list);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Documented in header
|
||||
*/
|
||||
interfaces_t *interfaces_create(u_int16_t port)
|
||||
{
|
||||
private_interfaces_t *this = malloc_thing(private_interfaces_t);
|
||||
|
||||
this->port = port;
|
||||
|
||||
this->public.get_addresses = (linked_list_t* (*) (interfaces_t*)) get_addresses;
|
||||
this->public.is_local_address = (bool (*) (interfaces_t*, host_t*)) is_local_address;
|
||||
this->public.destroy = (void (*) (interfaces_t*)) destroy;
|
||||
|
||||
this->addresses = linked_list_create();
|
||||
|
||||
if (initialize(this) != SUCCESS)
|
||||
{
|
||||
destroy(this);
|
||||
}
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @file interfaces.h
|
||||
*
|
||||
* @brief Interface of interfaces_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef INTERFACES_H_
|
||||
#define INTERFACES_H_
|
||||
|
||||
#include <utils/linked_list.h>
|
||||
#include <utils/host.h>
|
||||
|
||||
typedef struct interfaces_t interfaces_t;
|
||||
|
||||
/**
|
||||
* @brief Provides methods to enumerate local interfaces
|
||||
*
|
||||
* @b Constructors:
|
||||
* - interfaces_create()
|
||||
*
|
||||
* @todo Handle changes in interface list.
|
||||
*
|
||||
* @ingroup network
|
||||
*/
|
||||
struct interfaces_t {
|
||||
|
||||
/**
|
||||
* @brief Get addresses of local interfaces
|
||||
*
|
||||
* @param this calling object
|
||||
* @return linked_list_t of host_t objects
|
||||
*/
|
||||
linked_list_t* (*get_addresses) (interfaces_t *ifaces);
|
||||
|
||||
/**
|
||||
* @brief Check if address is associated with a local interface
|
||||
*
|
||||
* @param this calling object
|
||||
* @param host address to set as destination
|
||||
* @return TRUE if address is associated with a local interface, FALSE otherwise
|
||||
*/
|
||||
bool (*is_local_address) (interfaces_t *ifaces, host_t *host);
|
||||
|
||||
/**
|
||||
* @brief Destroy the object, freeing contained data.
|
||||
*
|
||||
* @param this object to destroy
|
||||
*/
|
||||
void (*destroy) (interfaces_t *ifaces);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create an object of type interfaces_t
|
||||
*
|
||||
* @param port the port that gets added to the addresses
|
||||
*
|
||||
* @return interfaces_t object
|
||||
*
|
||||
* @ingroup network
|
||||
*/
|
||||
interfaces_t *interfaces_create(u_int16_t port);
|
||||
|
||||
|
||||
#endif /*INTERFACES_H_*/
|
||||
+251
-297
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
* Copyright (C) 1998-2002 D. Hugh Redelmeier.
|
||||
@@ -32,9 +33,11 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <linux/ipsec.h>
|
||||
#include <linux/filter.h>
|
||||
|
||||
#include "socket.h"
|
||||
@@ -42,66 +45,20 @@
|
||||
#include <daemon.h>
|
||||
#include <utils/logger_manager.h>
|
||||
|
||||
/* constants for packet handling */
|
||||
#define IP_LEN sizeof(struct iphdr)
|
||||
#define UDP_LEN sizeof(struct udphdr)
|
||||
#define MARKER_LEN sizeof(u_int32_t)
|
||||
|
||||
/* offsets for packet handling */
|
||||
#define IP 0
|
||||
#define UDP IP + IP_LEN
|
||||
#define IKE UDP + UDP_LEN
|
||||
|
||||
#define IP_HEADER_LENGTH 20
|
||||
#define UDP_HEADER_LENGTH 8
|
||||
|
||||
|
||||
/**
|
||||
* This filter code filters out all non-IKEv2 traffic on
|
||||
* a SOCK_RAW IP_PROTP_UDP socket. Handling of other
|
||||
* IKE versions is done in pluto.
|
||||
*/
|
||||
struct sock_filter ikev2_filter_code[] =
|
||||
{
|
||||
/* Protocol must be UDP */
|
||||
BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 9),
|
||||
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IPPROTO_UDP, 0, 7),
|
||||
/* Destination Port must be 500 */
|
||||
BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 22),
|
||||
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 500, 0, 5),
|
||||
/* IKE version must be 2.0 */
|
||||
BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 45),
|
||||
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x20, 0, 3),
|
||||
/* packet length is length in IKEv2 header + ip header + udp header */
|
||||
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 52),
|
||||
BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, IP_HEADER_LENGTH + UDP_HEADER_LENGTH),
|
||||
BPF_STMT(BPF_RET+BPF_A, 0),
|
||||
/* packet doesn't match IKEv2, ignore */
|
||||
BPF_STMT(BPF_RET+BPF_K, 0),
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter struct to use with setsockopt
|
||||
*/
|
||||
struct sock_fprog ikev2_filter = {
|
||||
sizeof(ikev2_filter_code) / sizeof(struct sock_filter),
|
||||
ikev2_filter_code
|
||||
};
|
||||
|
||||
|
||||
typedef struct interface_t interface_t;
|
||||
|
||||
/**
|
||||
* An interface on which we listen.
|
||||
*/
|
||||
struct interface_t {
|
||||
|
||||
/**
|
||||
* Name of the interface
|
||||
*/
|
||||
char name[IFNAMSIZ];
|
||||
|
||||
/**
|
||||
* Associated socket
|
||||
*/
|
||||
int socket_fd;
|
||||
|
||||
/**
|
||||
* Host with listening address
|
||||
*/
|
||||
host_t *address;
|
||||
};
|
||||
/* from linux/in.h */
|
||||
#ifndef IP_IPSEC_POLICY
|
||||
#define IP_IPSEC_POLICY 16
|
||||
#endif /*IP_IPSEC_POLICY*/
|
||||
|
||||
typedef struct private_socket_t private_socket_t;
|
||||
|
||||
@@ -113,21 +70,52 @@ struct private_socket_t{
|
||||
* public functions
|
||||
*/
|
||||
socket_t public;
|
||||
|
||||
/**
|
||||
* regular port
|
||||
*/
|
||||
int port;
|
||||
|
||||
/**
|
||||
* port used for nat-t
|
||||
*/
|
||||
int natt_port;
|
||||
|
||||
/**
|
||||
* Master socket
|
||||
* raw socket (receiver)
|
||||
*/
|
||||
int master_fd;
|
||||
|
||||
int raw_fd;
|
||||
|
||||
/**
|
||||
* List of all socket to listen
|
||||
* send socket on regular port
|
||||
*/
|
||||
linked_list_t* interfaces;
|
||||
int send_fd;
|
||||
|
||||
/**
|
||||
* send socket on nat-t port
|
||||
*/
|
||||
int natt_fd;
|
||||
|
||||
/**
|
||||
* logger for this socket
|
||||
*/
|
||||
logger_t *logger;
|
||||
|
||||
/**
|
||||
* Setup a send socket
|
||||
*
|
||||
* @param this calling object
|
||||
* @param port the port
|
||||
* @param send_fd returns the file descriptor of this new socket
|
||||
*/
|
||||
status_t (*setup_send_socket) (private_socket_t *this, u_int16_t port, int *send_fd);
|
||||
|
||||
/**
|
||||
* Initialize
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
status_t (*initialize) (private_socket_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -138,96 +126,51 @@ static status_t receiver(private_socket_t *this, packet_t **packet)
|
||||
char buffer[MAX_PACKET];
|
||||
chunk_t data;
|
||||
packet_t *pkt;
|
||||
struct iphdr *ip;
|
||||
struct udphdr *udp;
|
||||
host_t *source, *dest;
|
||||
int bytes_read = 0;
|
||||
int data_offset, oldstate;
|
||||
|
||||
|
||||
while (bytes_read >= 0)
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "receive from raw socket");
|
||||
/* allow cancellation while blocking on recv() */
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
|
||||
bytes_read = recv(this->raw_fd, buffer, MAX_PACKET, 0);
|
||||
pthread_setcancelstate(oldstate, NULL);
|
||||
|
||||
if (bytes_read < 0)
|
||||
{
|
||||
int max_fd = 1;
|
||||
fd_set readfds;
|
||||
iterator_t *iterator;
|
||||
int oldstate;
|
||||
interface_t *interface;
|
||||
|
||||
/* build fd_set */
|
||||
FD_ZERO(&readfds);
|
||||
iterator = this->interfaces->create_iterator(this->interfaces, TRUE);
|
||||
while (iterator->has_next(iterator))
|
||||
{
|
||||
iterator->current(iterator, (void**)&interface);
|
||||
FD_SET(interface->socket_fd, &readfds);
|
||||
if (interface->socket_fd > max_fd)
|
||||
{
|
||||
max_fd = interface->socket_fd + 1;
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "waiting on sockets");
|
||||
|
||||
/* allow cancellation while select()-ing */
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
|
||||
bytes_read = select(max_fd, &readfds, NULL, NULL, NULL);
|
||||
pthread_setcancelstate(oldstate, NULL);
|
||||
|
||||
/* read on the first nonblocking socket */
|
||||
bytes_read = 0;
|
||||
iterator = this->interfaces->create_iterator(this->interfaces, TRUE);
|
||||
while (iterator->has_next(iterator))
|
||||
{
|
||||
iterator->current(iterator, (void**)&interface);
|
||||
if (FD_ISSET(interface->socket_fd, &readfds))
|
||||
{
|
||||
/* do the read */
|
||||
bytes_read = recv(interface->socket_fd, buffer, MAX_PACKET, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
|
||||
if (bytes_read < 0)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "error reading from socket: %s", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
/* insert a delay to simulate small bandwith/RTT */
|
||||
#ifdef PACKET_RECV_DELAY
|
||||
usleep(PACKET_RECV_DELAY * 1000);
|
||||
#endif
|
||||
/* simulate packet loss of every PACKET_RECV_LOSS'th packet */
|
||||
#ifdef PACKET_RECV_LOSS
|
||||
srandom(time(NULL) + getpid());
|
||||
if (random() % PACKET_RECV_LOSS == 0)
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
#endif
|
||||
if (bytes_read > IP_HEADER_LENGTH + UDP_HEADER_LENGTH)
|
||||
{
|
||||
/* read source/dest from raw IP/UDP header */
|
||||
chunk_t source_chunk = {buffer + 12, 4};
|
||||
chunk_t dest_chunk = {buffer + 16, 4};
|
||||
u_int16_t source_port = ntohs(*(u_int16_t*)(buffer + 20));
|
||||
u_int16_t dest_port = ntohs(*(u_int16_t*)(buffer + 22));
|
||||
source = host_create_from_chunk(AF_INET, source_chunk, source_port);
|
||||
dest = host_create_from_chunk(AF_INET, dest_chunk, dest_port);
|
||||
pkt = packet_create();
|
||||
pkt->set_source(pkt, source);
|
||||
pkt->set_destination(pkt, dest);
|
||||
break;
|
||||
}
|
||||
this->logger->log(this->logger, ERROR|LEVEL1, "too short packet received");
|
||||
this->logger->log(this->logger, ERROR, "error reading from socket: %s", strerror(errno));
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* read source/dest from raw IP/UDP header */
|
||||
ip = (struct iphdr*) buffer;
|
||||
udp = (struct udphdr*) (buffer + IP_LEN);
|
||||
|
||||
source = host_create_from_hdr(ip->saddr, udp->source);
|
||||
dest = host_create_from_hdr(ip->daddr, udp->dest);
|
||||
|
||||
pkt = packet_create();
|
||||
pkt->set_source(pkt, source);
|
||||
pkt->set_destination(pkt, dest);
|
||||
|
||||
this->logger->log(this->logger, CONTROL, "received packet: from %s:%d to %s:%d",
|
||||
source->get_address(source), source->get_port(source),
|
||||
dest->get_address(dest), dest->get_port(dest));
|
||||
|
||||
data_offset = IP_LEN + UDP_LEN;
|
||||
|
||||
/* remove non esp marker */
|
||||
if (dest->get_port(dest) == this->natt_port)
|
||||
{
|
||||
data_offset += MARKER_LEN;
|
||||
}
|
||||
|
||||
/* fill in packet */
|
||||
data.len = bytes_read - IP_HEADER_LENGTH - UDP_HEADER_LENGTH;
|
||||
data.len = bytes_read - data_offset;
|
||||
data.ptr = malloc(data.len);
|
||||
memcpy(data.ptr, buffer + IP_HEADER_LENGTH + UDP_HEADER_LENGTH, data.len);
|
||||
memcpy(data.ptr, buffer + data_offset, data.len);
|
||||
pkt->set_data(pkt, data);
|
||||
|
||||
/* return packet */
|
||||
@@ -241,8 +184,9 @@ static status_t receiver(private_socket_t *this, packet_t **packet)
|
||||
*/
|
||||
status_t sender(private_socket_t *this, packet_t *packet)
|
||||
{
|
||||
int sport, fd;
|
||||
ssize_t bytes_sent;
|
||||
chunk_t data;
|
||||
chunk_t data, marked;
|
||||
host_t *src, *dst;
|
||||
|
||||
src = packet->get_source(packet);
|
||||
@@ -252,20 +196,39 @@ status_t sender(private_socket_t *this, packet_t *packet)
|
||||
this->logger->log(this->logger, CONTROL, "sending packet: from %s:%d to %s:%d",
|
||||
src->get_address(src), src->get_port(src),
|
||||
dst->get_address(dst), dst->get_port(dst));
|
||||
/* insert a delay to simulate small bandwith/RTT */
|
||||
#ifdef PACKET_SEND_DELAY
|
||||
usleep(PACKET_SEND_DELAY * 1000);
|
||||
#endif
|
||||
/* simulate packet loss of every PACKET_LOSS'th packet */
|
||||
#ifdef PACKET_SEND_LOSS
|
||||
srandom(time(NULL) + getpid());
|
||||
if (random() % PACKET_SEND_LOSS == 0)
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* send data */
|
||||
bytes_sent = sendto(this->master_fd, data.ptr, data.len, 0,
|
||||
sport = src->get_port(src);
|
||||
if (sport == this->port)
|
||||
{
|
||||
fd = this->send_fd;
|
||||
}
|
||||
else if (sport == this->natt_port)
|
||||
{
|
||||
fd = this->natt_fd;
|
||||
/* NAT keepalives without marker */
|
||||
if (data.len != 1 || data.ptr[0] != 0xFF)
|
||||
{
|
||||
/* add non esp marker to packet */
|
||||
if (data.len > MAX_PACKET - MARKER_LEN)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "unable to send packet: it's too big");
|
||||
return FAILED;
|
||||
}
|
||||
marked = chunk_alloc(data.len + MARKER_LEN);
|
||||
memset(marked.ptr, 0, MARKER_LEN);
|
||||
memcpy(marked.ptr + MARKER_LEN, data.ptr, data.len);
|
||||
packet->set_data(packet, marked); /* let the packet do the clean up for us */
|
||||
data = marked;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "unable to locate a send socket for port: %d", sport);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
bytes_sent = sendto(fd, data.ptr, data.len, 0,
|
||||
dst->get_sockaddr(dst), *(dst->get_sockaddr_len(dst)));
|
||||
|
||||
if (bytes_sent != data.len)
|
||||
@@ -273,160 +236,153 @@ status_t sender(private_socket_t *this, packet_t *packet)
|
||||
this->logger->log(this->logger, ERROR, "error writing to socket: %s", strerror(errno));
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all suitable interfaces, bind them and add them to the list
|
||||
* setup a send socket on a specified port
|
||||
*/
|
||||
static status_t build_interface_list(private_socket_t *this, u_int16_t port)
|
||||
{
|
||||
static status_t setup_send_socket(private_socket_t *this, u_int16_t port, int *send_fd) {
|
||||
int on = TRUE;
|
||||
int i;
|
||||
struct sockaddr_in addr;
|
||||
struct ifconf ifconf;
|
||||
struct ifreq buf[300];
|
||||
|
||||
/* master socket for querying socket for a specific interfaces */
|
||||
this->master_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (this->master_fd == -1)
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (fd < 0)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "could not open IPv4 master socket!");
|
||||
this->logger->log(this->logger, ERROR, "could not open IPv4 send socket!");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* allow binding of multiplo sockets */
|
||||
if (setsockopt(this->master_fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "unable to set SO_REUSEADDR on master socket!");
|
||||
this->logger->log(this->logger, ERROR, "unable to set SO_REUSEADDR on send socket!");
|
||||
close(fd);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
struct sadb_x_policy policy;
|
||||
int level, opt;
|
||||
|
||||
/* bind the master socket */
|
||||
policy.sadb_x_policy_len = sizeof(policy) / sizeof(u_int64_t);
|
||||
policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
|
||||
policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS;
|
||||
policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND;
|
||||
policy.sadb_x_policy_reserved = 0;
|
||||
policy.sadb_x_policy_id = 0;
|
||||
|
||||
/* ipv6
|
||||
* level = IPPROTO_IPV6;
|
||||
* opt = IPV6_IPSEC_POLICY;
|
||||
*/
|
||||
level = IPPROTO_IP;
|
||||
opt = IP_IPSEC_POLICY;
|
||||
|
||||
if (setsockopt(fd, level, opt, &policy, sizeof(policy)) < 0)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "unable to set IPSEC_POLICY on send socket!");
|
||||
close(fd);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
|
||||
|
||||
if (setsockopt(fd, level, opt, &policy, sizeof(policy)) < 0)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "unable to set IPSEC_POLICY on send socket!");
|
||||
close(fd);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* bind the send socket */
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.sin_port = htons(port);
|
||||
if (bind(this->master_fd,(struct sockaddr*)&addr, sizeof(addr)) < 0)
|
||||
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "unable to bind master socket: %s!", strerror(errno));
|
||||
this->logger->log(this->logger, ERROR, "unable to bind send socket: %s!", strerror(errno));
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* get all interfaces */
|
||||
ifconf.ifc_len = sizeof(buf);
|
||||
ifconf.ifc_buf = (void*) buf;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
if (ioctl(this->master_fd, SIOCGIFCONF, &ifconf) == -1)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "unable to get interfaces!");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* add every interesting interfaces to our interface list */
|
||||
for (i = 0; (i+1) * sizeof(*buf) <= (size_t)ifconf.ifc_len; i++)
|
||||
{
|
||||
struct sockaddr_in *current = (struct sockaddr_in*) &buf[i].ifr_addr;
|
||||
struct ifreq auxinfo;
|
||||
int skt;
|
||||
interface_t *interface;
|
||||
|
||||
if (current->sin_family != AF_INET && current->sin_family != AF_INET6)
|
||||
{
|
||||
/* ignore all but IPv4 and IPv6 interfaces */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* get auxilary info about socket */
|
||||
memset(&auxinfo, 0, sizeof(auxinfo));
|
||||
memcpy(auxinfo.ifr_name, buf[i].ifr_name, IFNAMSIZ);
|
||||
if (ioctl(this->master_fd, SIOCGIFFLAGS, &auxinfo) == -1)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "unable to SIOCGIFFLAGS master socket!");
|
||||
continue;
|
||||
}
|
||||
if (!(auxinfo.ifr_flags & IFF_UP))
|
||||
{
|
||||
/* ignore an interface that isn't up */
|
||||
continue;
|
||||
}
|
||||
if (current->sin_addr.s_addr == 0)
|
||||
{
|
||||
/* ignore unconfigured interfaces */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* set up interface socket */
|
||||
skt = socket(current->sin_family, SOCK_RAW, IPPROTO_UDP);
|
||||
if (socket < 0)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "unable to open interface socket!");
|
||||
continue;
|
||||
}
|
||||
if (setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "unable to set SO_REUSEADDR on interface socket!");
|
||||
close(skt);
|
||||
continue;
|
||||
}
|
||||
current->sin_port = htons(port);
|
||||
|
||||
if (bind(skt, (struct sockaddr*)current, sizeof(struct sockaddr_in)) < 0)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "unable to bind interface socket!");
|
||||
close(skt);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (setsockopt(skt, SOL_SOCKET, SO_ATTACH_FILTER, &ikev2_filter, sizeof(ikev2_filter)) < 0)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "unable to attack IKEv2 filter to interface socket!");
|
||||
close(skt);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* add socket with interface name to list */
|
||||
interface = malloc_thing(interface_t);
|
||||
strncpy(interface->name, buf[i].ifr_name, IFNAMSIZ);
|
||||
interface->socket_fd = skt;
|
||||
interface->address = host_create_from_sockaddr((struct sockaddr*)current);
|
||||
this->logger->log(this->logger, CONTROL, "listening on %s (%s)",
|
||||
interface->name, interface->address->get_address(interface->address));
|
||||
this->interfaces->insert_last(this->interfaces, (void*)interface);
|
||||
}
|
||||
|
||||
if (this->interfaces->get_count(this->interfaces) == 0)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "unable to find any usable interface!");
|
||||
return FAILED;
|
||||
}
|
||||
*send_fd = fd;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* implementation of socket_t.is_listening_on
|
||||
* Initialize all sub sockets
|
||||
*/
|
||||
static bool is_listening_on(private_socket_t *this, host_t *host)
|
||||
static status_t initialize(private_socket_t *this)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
|
||||
/* listening on wildcard 0.0.0.0 is always FALSE */
|
||||
if (host->is_anyaddr(host))
|
||||
return FALSE;
|
||||
|
||||
/* compare host with all interfaces */
|
||||
iterator = this->interfaces->create_iterator(this->interfaces, TRUE);
|
||||
while (iterator->has_next(iterator))
|
||||
/* This filter code filters out all non-IKEv2 traffic on
|
||||
* a SOCK_RAW IP_PROTP_UDP socket. Handling of other
|
||||
* IKE versions is done in pluto.
|
||||
*/
|
||||
struct sock_filter ikev2_filter_code[] =
|
||||
{
|
||||
interface_t *interface;
|
||||
iterator->current(iterator, (void**)&interface);
|
||||
if (host->equals(host, interface->address))
|
||||
{
|
||||
iterator->destroy(iterator);
|
||||
return TRUE;
|
||||
}
|
||||
/* Protocol must be UDP */
|
||||
BPF_STMT(BPF_LD+BPF_B+BPF_ABS, IP + 9),
|
||||
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IPPROTO_UDP, 0, 15),
|
||||
/* Destination Port must be either port or natt_port */
|
||||
BPF_STMT(BPF_LD+BPF_H+BPF_ABS, UDP + 2),
|
||||
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, this->port, 1, 0),
|
||||
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, this->natt_port, 5, 12),
|
||||
/* port */
|
||||
/* IKE version must be 2.0 */
|
||||
BPF_STMT(BPF_LD+BPF_B+BPF_ABS, IKE + 17),
|
||||
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x20, 0, 10),
|
||||
/* packet length is length in IKEv2 header + ip header + udp header */
|
||||
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, IKE + 24),
|
||||
BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, IP_LEN + UDP_LEN),
|
||||
BPF_STMT(BPF_RET+BPF_A, 0),
|
||||
/* natt_port */
|
||||
/* nat-t: check for marker */
|
||||
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, IKE),
|
||||
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 5),
|
||||
/* nat-t: IKE version must be 2.0 */
|
||||
BPF_STMT(BPF_LD+BPF_B+BPF_ABS, IKE + MARKER_LEN + 17),
|
||||
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x20, 0, 3),
|
||||
/* nat-t: packet length is length in IKEv2 header + ip header + udp header + non esp marker */
|
||||
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, IKE + MARKER_LEN + 24),
|
||||
BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, IP_LEN + UDP_LEN + MARKER_LEN),
|
||||
BPF_STMT(BPF_RET+BPF_A, 0),
|
||||
/* packet doesn't match, ignore */
|
||||
BPF_STMT(BPF_RET+BPF_K, 0),
|
||||
};
|
||||
|
||||
/* Filter struct to use with setsockopt */
|
||||
struct sock_fprog ikev2_filter = {
|
||||
sizeof(ikev2_filter_code) / sizeof(struct sock_filter),
|
||||
ikev2_filter_code
|
||||
};
|
||||
|
||||
/* set up raw socket */
|
||||
this->raw_fd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
|
||||
if (this->raw_fd < 0)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "unable to create raw socket!");
|
||||
return FAILED;
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
return FALSE;
|
||||
|
||||
if (setsockopt(this->raw_fd, SOL_SOCKET, SO_ATTACH_FILTER, &ikev2_filter, sizeof(ikev2_filter)) < 0)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "unable to attach IKEv2 filter to raw socket!");
|
||||
close(this->raw_fd);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* setup the send sockets */
|
||||
if (this->setup_send_socket(this, this->port, &this->send_fd) != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "unable to setup send socket on port %d!", this->port);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (this->setup_send_socket(this, this->natt_port, &this->natt_fd) != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "unable to setup send socket on port %d!", this->natt_port);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -434,39 +390,37 @@ static bool is_listening_on(private_socket_t *this, host_t *host)
|
||||
*/
|
||||
static void destroy(private_socket_t *this)
|
||||
{
|
||||
interface_t *interface;
|
||||
while (this->interfaces->remove_last(this->interfaces, (void**)&interface) == SUCCESS)
|
||||
{
|
||||
interface->address->destroy(interface->address);
|
||||
close(interface->socket_fd);
|
||||
free(interface);
|
||||
}
|
||||
this->interfaces->destroy(this->interfaces);
|
||||
close(this->master_fd);
|
||||
close(this->natt_fd);
|
||||
close(this->send_fd);
|
||||
close(this->raw_fd);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* See header for description
|
||||
*/
|
||||
socket_t *socket_create(u_int16_t port)
|
||||
socket_t *socket_create(u_int16_t port, u_int16_t natt_port)
|
||||
{
|
||||
private_socket_t *this = malloc_thing(private_socket_t);
|
||||
|
||||
/* private functions */
|
||||
this->initialize = (status_t(*)(private_socket_t*))initialize;
|
||||
this->setup_send_socket = (status_t(*)(private_socket_t*,u_int16_t, int*))setup_send_socket;
|
||||
|
||||
/* public functions */
|
||||
this->public.send = (status_t(*)(socket_t*, packet_t*))sender;
|
||||
this->public.receive = (status_t(*)(socket_t*, packet_t**))receiver;
|
||||
this->public.is_listening_on = (bool (*)(socket_t*,host_t*))is_listening_on;
|
||||
this->public.destroy = (void(*)(socket_t*)) destroy;
|
||||
|
||||
|
||||
this->logger = logger_manager->get_logger(logger_manager, SOCKET);
|
||||
this->interfaces = linked_list_create();
|
||||
|
||||
if (build_interface_list(this, port) != SUCCESS)
|
||||
this->port = port;
|
||||
this->natt_port = natt_port;
|
||||
|
||||
if (this->initialize(this) != SUCCESS)
|
||||
{
|
||||
this->interfaces->destroy(this->interfaces);
|
||||
free(this);
|
||||
charon->kill(charon, "could not bind any interface!");
|
||||
charon->kill(charon, "could not init socket!");
|
||||
}
|
||||
|
||||
return (socket_t*)this;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -92,15 +93,6 @@ struct socket_t {
|
||||
*/
|
||||
status_t (*send) (socket_t *sock, packet_t *packet);
|
||||
|
||||
/**
|
||||
* @brief Check if socket listens on an address.
|
||||
*
|
||||
* @param sock socket_t object to work on
|
||||
* @param host address to check
|
||||
* @return TRUE if listening on host, FALSE otherwise
|
||||
*/
|
||||
bool (*is_listening_on) (socket_t *sock, host_t *host);
|
||||
|
||||
/**
|
||||
* @brief Destroy sockets.
|
||||
*
|
||||
@@ -114,15 +106,15 @@ struct socket_t {
|
||||
/**
|
||||
* @brief Create a socket_t, wich binds multiple sockets.
|
||||
*
|
||||
* currently creates one socket, listening on all addresses
|
||||
* on "port".
|
||||
* currently creates a raw socket and two send sockets
|
||||
*
|
||||
* @param port port to bind socket to
|
||||
* @param natt_port port to float to in NAT-T
|
||||
* @return socket_t object
|
||||
*
|
||||
* @ingroup network
|
||||
*/
|
||||
socket_t *socket_create(u_int16_t port);
|
||||
socket_t *socket_create(u_int16_t port, u_int16_t natt_port);
|
||||
|
||||
|
||||
#endif /*SOCKET_H_*/
|
||||
|
||||
@@ -88,8 +88,8 @@ struct event_queue_t {
|
||||
* removes the job.
|
||||
*
|
||||
* @param event_queue calling object
|
||||
* @param[in] job job to add to the queue (job is not copied)
|
||||
* @param[in] absolute time time, when the event has to get fired
|
||||
* @param[in] job job to add to the queue (job is not copied)
|
||||
* @param[in] time absolute time, when the event has to get fired
|
||||
*/
|
||||
void (*add_absolute) (event_queue_t *event_queue, job_t *job, timeval_t time);
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ mapping_t job_type_m[] = {
|
||||
{RETRANSMIT_REQUEST, "RETRANSMIT_REQUEST"},
|
||||
{INITIATE_IKE_SA, "INITIATE_IKE_SA"},
|
||||
{DELETE_HALF_OPEN_IKE_SA, "DELETE_HALF_OPEN_IKE_SA"},
|
||||
{DELETE_ESTABLISHED_IKE_SA, "DELETE_ESTABLISHED_IKE_SA"},
|
||||
{DELETE_ESTABLISHED_IKE_SA, "DELETE_ESTABLISHED_IKE_SA"},
|
||||
{SEND_KEEPALIVE, "SEND_KEEPALIVE"},
|
||||
{SEND_DPD, "SEND_DPD"},
|
||||
{MAPPING_END, NULL}
|
||||
};
|
||||
|
||||
@@ -83,6 +83,20 @@ enum job_type_t {
|
||||
* Job is implemented in class rekey_child_sa_job_t
|
||||
*/
|
||||
REKEY_CHILD_SA,
|
||||
|
||||
/**
|
||||
* Send a keepalive packet.
|
||||
*
|
||||
* Job is implemented in class type send_keepalive_job_t
|
||||
*/
|
||||
SEND_KEEPALIVE,
|
||||
|
||||
/**
|
||||
* Send a DPD packet.
|
||||
*
|
||||
* Job is implemented in class type send_dpd_job_t
|
||||
*/
|
||||
SEND_DPD
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -69,7 +69,7 @@ static job_type_t get_type(private_retransmit_request_job_t *this)
|
||||
*/
|
||||
static status_t execute(private_retransmit_request_job_t *this)
|
||||
{
|
||||
bool stop_retransmitting = FALSE;
|
||||
bool stop_retransmitting = FALSE, timed_out = FALSE;
|
||||
u_int32_t timeout;
|
||||
ike_sa_t *ike_sa;
|
||||
status_t status;
|
||||
@@ -87,14 +87,29 @@ static status_t execute(private_retransmit_request_job_t *this)
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
status = ike_sa->retransmit_request(ike_sa, this->message_id);
|
||||
if (status != SUCCESS)
|
||||
this->retransmit_count++;
|
||||
status = charon->configuration->get_retransmit_timeout(charon->configuration,
|
||||
this->retransmit_count, &timeout);
|
||||
timed_out = (status != SUCCESS);
|
||||
|
||||
if (ike_sa->retransmit_possible(ike_sa, this->message_id))
|
||||
{
|
||||
if (!timed_out)
|
||||
{
|
||||
status = ike_sa->retransmit_request(ike_sa, this->message_id);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL3,
|
||||
"Message doesn't have to be retransmitted");
|
||||
stop_retransmitting = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL3,
|
||||
"Message doesn't have to be retransmitted");
|
||||
stop_retransmitting = TRUE;
|
||||
}
|
||||
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "Checkin IKE SA %lld:%lld, role %s",
|
||||
this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
|
||||
this->ike_sa_id->get_responder_spi(this->ike_sa_id),
|
||||
@@ -106,19 +121,25 @@ static status_t execute(private_retransmit_request_job_t *this)
|
||||
this->logger->log(this->logger, ERROR, "Checkin of IKE SA failed!");
|
||||
}
|
||||
|
||||
if (timed_out)
|
||||
{
|
||||
/*
|
||||
* XXX: We should act depending on DPD policy here, or not act at all.
|
||||
*/
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "Timeout: Deleting SA!");
|
||||
status = charon->ike_sa_manager->delete(charon->ike_sa_manager, this->ike_sa_id);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1, "Cannot delete SA!");
|
||||
}
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
if (stop_retransmitting)
|
||||
{
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
this->retransmit_count++;
|
||||
status = charon->configuration->get_retransmit_timeout(charon->configuration,
|
||||
this->retransmit_count, &timeout);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "Message will not be retransmitted anymore");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
charon->event_queue->add_relative(charon->event_queue, (job_t *)this, timeout);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* @file send_dpd_job.c
|
||||
*
|
||||
* @brief Implementation of send_dpd_job_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "send_dpd_job.h"
|
||||
|
||||
#include <sa/ike_sa.h>
|
||||
#include <daemon.h>
|
||||
|
||||
|
||||
typedef struct private_send_dpd_job_t private_send_dpd_job_t;
|
||||
|
||||
/**
|
||||
* Private data of an send_dpd_job_t Object
|
||||
*/
|
||||
struct private_send_dpd_job_t {
|
||||
/**
|
||||
* public send_dpd_job_t interface
|
||||
*/
|
||||
send_dpd_job_t public;
|
||||
|
||||
/**
|
||||
* ID of the IKE_SA which the message belongs to.
|
||||
*/
|
||||
ike_sa_id_t *ike_sa_id;
|
||||
|
||||
/**
|
||||
* Logger reference.
|
||||
*/
|
||||
logger_t *logger;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements send_dpd_job_t.get_type.
|
||||
*/
|
||||
static job_type_t get_type(private_send_dpd_job_t *this)
|
||||
{
|
||||
return SEND_DPD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of job_t.execute.
|
||||
*/
|
||||
static status_t execute(private_send_dpd_job_t *this)
|
||||
{
|
||||
ike_sa_t *ike_sa;
|
||||
status_t status;
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "Checking out IKE SA %lld:%lld, role %s",
|
||||
this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
|
||||
this->ike_sa_id->get_responder_spi(this->ike_sa_id),
|
||||
this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder");
|
||||
|
||||
status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
|
||||
this->ike_sa_id, &ike_sa);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1,
|
||||
"IKE SA could not be checked out. Already deleted?");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
ike_sa->send_dpd_request(ike_sa);
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1,
|
||||
"DPD request packet scheduled");
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2,
|
||||
"Checkin IKE SA %lld:%lld, role %s",
|
||||
this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
|
||||
this->ike_sa_id->get_responder_spi(this->ike_sa_id),
|
||||
this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder");
|
||||
|
||||
status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "Checkin of IKE SA failed!");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements job_t.destroy.
|
||||
*/
|
||||
static void destroy(private_send_dpd_job_t *this)
|
||||
{
|
||||
this->ike_sa_id->destroy(this->ike_sa_id);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
send_dpd_job_t *send_dpd_job_create(ike_sa_id_t *ike_sa_id)
|
||||
{
|
||||
private_send_dpd_job_t *this = malloc_thing(private_send_dpd_job_t);
|
||||
|
||||
/* interface functions */
|
||||
this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
|
||||
this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
|
||||
this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
|
||||
|
||||
/* public functions */
|
||||
this->public.destroy = (void (*)(send_dpd_job_t *)) destroy;
|
||||
|
||||
/* private variables */
|
||||
this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
|
||||
this->logger = logger_manager->get_logger(logger_manager, WORKER);
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @file send_dpd_job.h
|
||||
*
|
||||
* @brief Interface of send_dpd_job_t.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef SEND_DPD_JOB_H_
|
||||
#define SEND_DPD_JOB_H_
|
||||
|
||||
#include <types.h>
|
||||
#include <queues/jobs/job.h>
|
||||
#include <config/connections/connection.h>
|
||||
#include <sa/ike_sa_id.h>
|
||||
|
||||
|
||||
typedef struct send_dpd_job_t send_dpd_job_t;
|
||||
|
||||
/**
|
||||
* @brief Class representing a SEND_DPD Job.
|
||||
*
|
||||
* Job to periodically send a Dead Peer Detection (DPD) request,
|
||||
* ie. an IKE request with no payloads other than the encrypted payload
|
||||
* required by the syntax.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - send_dpd_job_create()
|
||||
*
|
||||
* @ingroup jobs
|
||||
*/
|
||||
struct send_dpd_job_t {
|
||||
/**
|
||||
* implements job_t interface
|
||||
*/
|
||||
job_t job_interface;
|
||||
|
||||
/**
|
||||
* @brief Destroys an send_dpd_job_t object.
|
||||
*
|
||||
* @param this send_dpd_job_t object to destroy
|
||||
*/
|
||||
void (*destroy) (send_dpd_job_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creates a job of type SEND_DPD.
|
||||
*
|
||||
* @param ike_sa_id identification of the ike_sa as ike_sa_id_t object (gets cloned)
|
||||
* @return initiate_ike_sa_job_t object
|
||||
*
|
||||
* @ingroup jobs
|
||||
*/
|
||||
send_dpd_job_t *send_dpd_job_create(ike_sa_id_t *ike_sa_id);
|
||||
|
||||
#endif /*SEND_DPD_JOB_H_*/
|
||||
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* @file send_keepalive_job.c
|
||||
*
|
||||
* @brief Implementation of send_keepalive_job_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "send_keepalive_job.h"
|
||||
|
||||
#include <sa/ike_sa.h>
|
||||
#include <daemon.h>
|
||||
|
||||
|
||||
typedef struct private_send_keepalive_job_t private_send_keepalive_job_t;
|
||||
|
||||
/**
|
||||
* Private data of an send_keepalive_job_t Object
|
||||
*/
|
||||
struct private_send_keepalive_job_t {
|
||||
/**
|
||||
* public send_keepalive_job_t interface
|
||||
*/
|
||||
send_keepalive_job_t public;
|
||||
|
||||
/**
|
||||
* ID of the IKE_SA which the message belongs to.
|
||||
*/
|
||||
ike_sa_id_t *ike_sa_id;
|
||||
|
||||
/**
|
||||
* Logger reference.
|
||||
*/
|
||||
logger_t *logger;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements send_keepalive_job_t.get_type.
|
||||
*/
|
||||
static job_type_t get_type(private_send_keepalive_job_t *this)
|
||||
{
|
||||
return SEND_KEEPALIVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of job_t.execute.
|
||||
*/
|
||||
static status_t execute(private_send_keepalive_job_t *this)
|
||||
{
|
||||
ike_sa_t *ike_sa;
|
||||
status_t status;
|
||||
u_int32_t dt;
|
||||
u_int32_t interval = charon->configuration->get_keepalive_interval(charon->configuration);
|
||||
u_int32_t timeout = charon->configuration->get_keepalive_timeout(charon->configuration);
|
||||
struct timeval last_msg_tv, current_tv;
|
||||
packet_t *packet;
|
||||
host_t *host;
|
||||
connection_t *connection;
|
||||
chunk_t data;
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "Checking out IKE SA %lld:%lld, role %s",
|
||||
this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
|
||||
this->ike_sa_id->get_responder_spi(this->ike_sa_id),
|
||||
this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder");
|
||||
|
||||
status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
|
||||
this->ike_sa_id, &ike_sa);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1,
|
||||
"IKE SA could not be checked out. Already deleted?");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
last_msg_tv = ike_sa->get_last_msg_tv(ike_sa);
|
||||
if (0 > gettimeofday(¤t_tv, NULL) )
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1,
|
||||
"Warning: Failed to get time of day.");
|
||||
}
|
||||
dt = (current_tv.tv_sec - last_msg_tv.tv_sec) * 1000
|
||||
+ (current_tv.tv_usec - last_msg_tv.tv_usec) / 1000;
|
||||
|
||||
if (dt >= interval)
|
||||
{
|
||||
packet = packet_create();
|
||||
connection = ike_sa->get_connection(ike_sa);
|
||||
host = connection->get_my_host(connection);
|
||||
packet->set_source(packet, host->clone(host));
|
||||
host = connection->get_other_host(connection);
|
||||
packet->set_destination(packet, host->clone(host));
|
||||
data = chunk_alloc(1);
|
||||
data.ptr[0] = 0xFF;
|
||||
packet->set_data(packet, data);
|
||||
charon->send_queue->add(charon->send_queue, packet);
|
||||
dt = 0;
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1,
|
||||
"NAT keepalive packet scheduled");
|
||||
}
|
||||
charon->event_queue->add_relative(charon->event_queue,
|
||||
(job_t*) this, interval - dt);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2,
|
||||
"Checkin IKE SA %lld:%lld, role %s",
|
||||
this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
|
||||
this->ike_sa_id->get_responder_spi(this->ike_sa_id),
|
||||
this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder");
|
||||
|
||||
status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "Checkin of IKE SA failed!");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements job_t.destroy.
|
||||
*/
|
||||
static void destroy(private_send_keepalive_job_t *this)
|
||||
{
|
||||
this->ike_sa_id->destroy(this->ike_sa_id);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
send_keepalive_job_t *send_keepalive_job_create(ike_sa_id_t *ike_sa_id)
|
||||
{
|
||||
private_send_keepalive_job_t *this = malloc_thing(private_send_keepalive_job_t);
|
||||
|
||||
/* interface functions */
|
||||
this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
|
||||
this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
|
||||
this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
|
||||
|
||||
/* public functions */
|
||||
this->public.destroy = (void (*)(send_keepalive_job_t *)) destroy;
|
||||
|
||||
/* private variables */
|
||||
this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
|
||||
this->logger = logger_manager->get_logger(logger_manager, WORKER);
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* @file send_keepalive_job.h
|
||||
*
|
||||
* @brief Interface of send_keepalive_job_t.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef SEND_KEEPALIVE_JOB_H_
|
||||
#define SEND_KEEPALIVE_JOB_H_
|
||||
|
||||
#include <types.h>
|
||||
#include <queues/jobs/job.h>
|
||||
#include <config/connections/connection.h>
|
||||
#include <sa/ike_sa_id.h>
|
||||
|
||||
|
||||
typedef struct send_keepalive_job_t send_keepalive_job_t;
|
||||
|
||||
/**
|
||||
* @brief Class representing a SEND_KEEPALIVE Job.
|
||||
*
|
||||
* This job will send a NAT keepalive packet if the IKE SA is still alive,
|
||||
* and reinsert itself into the event queue.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - send_keepalive_job_create()
|
||||
*
|
||||
* @ingroup jobs
|
||||
*/
|
||||
struct send_keepalive_job_t {
|
||||
/**
|
||||
* implements job_t interface
|
||||
*/
|
||||
job_t job_interface;
|
||||
|
||||
/**
|
||||
* @brief Destroys an send_keepalive_job_t object.
|
||||
*
|
||||
* @param this send_keepalive_job_t object to destroy
|
||||
*/
|
||||
void (*destroy) (send_keepalive_job_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creates a job of type SEND_KEEPALIVE.
|
||||
*
|
||||
* @param ike_sa_id identification of the ike_sa as ike_sa_id_t object (gets cloned)
|
||||
* @return initiate_ike_sa_job_t object
|
||||
*
|
||||
* @ingroup jobs
|
||||
*/
|
||||
send_keepalive_job_t *send_keepalive_job_create(ike_sa_id_t *ike_sa_id);
|
||||
|
||||
#endif /*SEND_KEEPALIVE_JOB_H_*/
|
||||
+235
-54
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -111,6 +112,11 @@ struct private_child_sa_t {
|
||||
* has this CHILD_SA been rekeyed?
|
||||
*/
|
||||
bool rekeyed;
|
||||
|
||||
/**
|
||||
* Specifies if NAT traversal is used
|
||||
*/
|
||||
bool use_natt;
|
||||
|
||||
/**
|
||||
* CHILD_SAs own logger
|
||||
@@ -146,12 +152,54 @@ protocol_id_t get_protocol(private_child_sa_t *this)
|
||||
return this->protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate SPI for a single proposal
|
||||
*/
|
||||
static status_t alloc_proposal(private_child_sa_t *this, proposal_t *proposal)
|
||||
{
|
||||
protocol_id_t protocol = proposal->get_protocol(proposal);
|
||||
|
||||
if (protocol == PROTO_AH)
|
||||
{
|
||||
/* get a new spi for AH, if not already done */
|
||||
if (this->alloc_ah_spi == 0)
|
||||
{
|
||||
if (charon->kernel_interface->get_spi(
|
||||
charon->kernel_interface,
|
||||
this->other.addr, this->me.addr,
|
||||
PROTO_AH, this->reqid,
|
||||
&this->alloc_ah_spi) != SUCCESS)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
proposal->set_spi(proposal, this->alloc_ah_spi);
|
||||
}
|
||||
if (protocol == PROTO_ESP)
|
||||
{
|
||||
/* get a new spi for ESP, if not already done */
|
||||
if (this->alloc_esp_spi == 0)
|
||||
{
|
||||
if (charon->kernel_interface->get_spi(
|
||||
charon->kernel_interface,
|
||||
this->other.addr, this->me.addr,
|
||||
PROTO_ESP, this->reqid,
|
||||
&this->alloc_esp_spi) != SUCCESS)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
proposal->set_spi(proposal, this->alloc_esp_spi);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements child_sa_t.alloc
|
||||
*/
|
||||
static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
|
||||
{
|
||||
protocol_id_t protocol;
|
||||
iterator_t *iterator;
|
||||
proposal_t *proposal;
|
||||
|
||||
@@ -160,41 +208,11 @@ static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
|
||||
while(iterator->has_next(iterator))
|
||||
{
|
||||
iterator->current(iterator, (void**)&proposal);
|
||||
protocol = proposal->get_protocol(proposal);
|
||||
|
||||
if (protocol == PROTO_AH)
|
||||
if (alloc_proposal(this, proposal) != SUCCESS)
|
||||
{
|
||||
/* get a new spi for AH, if not already done */
|
||||
if (this->alloc_ah_spi == 0)
|
||||
{
|
||||
if (charon->kernel_interface->get_spi(
|
||||
charon->kernel_interface,
|
||||
this->other.addr, this->me.addr,
|
||||
PROTO_AH, this->reqid,
|
||||
&this->alloc_ah_spi) != SUCCESS)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
proposal->set_spi(proposal, this->alloc_ah_spi);
|
||||
iterator->destroy(iterator);
|
||||
return FAILED;
|
||||
}
|
||||
if (protocol == PROTO_ESP)
|
||||
{
|
||||
/* get a new spi for ESP, if not already done */
|
||||
if (this->alloc_esp_spi == 0)
|
||||
{
|
||||
if (charon->kernel_interface->get_spi(
|
||||
charon->kernel_interface,
|
||||
this->other.addr, this->me.addr,
|
||||
PROTO_ESP, this->reqid,
|
||||
&this->alloc_esp_spi) != SUCCESS)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
proposal->set_spi(proposal, this->alloc_esp_spi);
|
||||
}
|
||||
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
return SUCCESS;
|
||||
@@ -208,6 +226,7 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus
|
||||
algorithm_t int_algo_none = {AUTH_UNDEFINED, 0};
|
||||
host_t *src;
|
||||
host_t *dst;
|
||||
natt_conf_t *natt;
|
||||
status_t status;
|
||||
|
||||
this->protocol = proposal->get_protocol(proposal);
|
||||
@@ -275,17 +294,31 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus
|
||||
int_algo = &int_algo_none;
|
||||
}
|
||||
|
||||
/* setup nat-t */
|
||||
if (this->use_natt)
|
||||
{
|
||||
natt = alloca(sizeof(natt_conf_t));
|
||||
natt->sport = src->get_port(src);
|
||||
natt->dport = dst->get_port(dst);
|
||||
}
|
||||
else
|
||||
{
|
||||
natt = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* send SA down to the kernel */
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2,
|
||||
" SPI 0x%.8x, src %s dst %s",
|
||||
ntohl(spi), src->get_address(src), dst->get_address(dst));
|
||||
status = charon->kernel_interface->add_sa(charon->kernel_interface,
|
||||
src, dst,
|
||||
spi, this->protocol,
|
||||
this->reqid,
|
||||
mine ? 0 : this->soft_lifetime,
|
||||
this->hard_lifetime,
|
||||
enc_algo, int_algo, prf_plus, mine);
|
||||
src, dst,
|
||||
spi, this->protocol,
|
||||
this->reqid,
|
||||
mine ? 0 : this->soft_lifetime,
|
||||
this->hard_lifetime,
|
||||
enc_algo, int_algo,
|
||||
prf_plus, natt, mine);
|
||||
|
||||
this->install_time = time(NULL);
|
||||
|
||||
@@ -301,14 +334,10 @@ static status_t add(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *
|
||||
outbound_spi = proposal->get_spi(proposal);
|
||||
|
||||
/* get SPIs inbound SAs */
|
||||
list = linked_list_create();
|
||||
list->insert_last(list, proposal);
|
||||
if (alloc(this, list) != SUCCESS)
|
||||
if (alloc_proposal(this, proposal) != SUCCESS)
|
||||
{
|
||||
list->destroy(list);
|
||||
return FAILED;
|
||||
}
|
||||
list->destroy(list);
|
||||
inbound_spi = proposal->get_spi(proposal);
|
||||
|
||||
/* install inbound SAs */
|
||||
@@ -409,24 +438,21 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list
|
||||
policy->me.net, policy->other.net,
|
||||
policy->me.net_mask, policy->other.net_mask,
|
||||
XFRM_POLICY_OUT, policy->upper_proto,
|
||||
this->protocol,
|
||||
this->reqid);
|
||||
this->protocol, this->reqid);
|
||||
|
||||
status |= charon->kernel_interface->add_policy(charon->kernel_interface,
|
||||
this->other.addr, this->me.addr,
|
||||
policy->other.net, policy->me.net,
|
||||
policy->other.net_mask, policy->me.net_mask,
|
||||
XFRM_POLICY_IN, policy->upper_proto,
|
||||
this->protocol,
|
||||
this->reqid);
|
||||
this->protocol, this->reqid);
|
||||
|
||||
status |= charon->kernel_interface->add_policy(charon->kernel_interface,
|
||||
this->other.addr, this->me.addr,
|
||||
policy->other.net, policy->me.net,
|
||||
policy->other.net_mask, policy->me.net_mask,
|
||||
XFRM_POLICY_FWD, policy->upper_proto,
|
||||
this->protocol,
|
||||
this->reqid);
|
||||
this->protocol, this->reqid);
|
||||
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
@@ -513,6 +539,159 @@ static void log_status(private_child_sa_t *this, logger_t *logger, char* name)
|
||||
iterator->destroy(iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the host adress/port of a SA
|
||||
*/
|
||||
static status_t update_sa_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other,
|
||||
int my_changes, int other_changes, bool mine)
|
||||
{
|
||||
host_t *src, *dst, *new_src, *new_dst;
|
||||
int src_changes, dst_changes;
|
||||
status_t status;
|
||||
u_int32_t spi;
|
||||
|
||||
if (mine)
|
||||
{
|
||||
src = this->me.addr;
|
||||
dst = this->other.addr;
|
||||
new_src = new_me;
|
||||
new_dst = new_other;
|
||||
src_changes = my_changes;
|
||||
dst_changes = other_changes;
|
||||
spi = this->me.spi;
|
||||
}
|
||||
else
|
||||
{
|
||||
src = this->other.addr;
|
||||
dst = this->me.addr;
|
||||
new_src = new_other;
|
||||
new_dst = new_me;
|
||||
src_changes = other_changes;
|
||||
dst_changes = my_changes;
|
||||
spi = this->other.spi;
|
||||
}
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1,
|
||||
"updating %s SA 0x%x, from %s:%d..%s:%d to %s:%d..%s:%d",
|
||||
mapping_find(protocol_id_m, this->protocol), ntohl(spi),
|
||||
src->get_address(src), src->get_port(src),
|
||||
dst->get_address(dst), dst->get_port(dst),
|
||||
new_src->get_address(new_src), new_src->get_port(new_src),
|
||||
new_dst->get_address(new_dst), new_dst->get_port(new_dst));
|
||||
|
||||
status = charon->kernel_interface->update_sa_hosts(
|
||||
charon->kernel_interface,
|
||||
src, dst, new_src, new_dst,
|
||||
src_changes, dst_changes,
|
||||
spi, this->protocol);
|
||||
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the host adress/port of a policy
|
||||
*/
|
||||
static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
sa_policy_t *policy;
|
||||
status_t status;
|
||||
|
||||
iterator = this->policies->create_iterator(this->policies, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)&policy))
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1,
|
||||
"updating policy: %s/%d====%s/%d",
|
||||
policy->me.net->get_address(policy->me.net), policy->me.net_mask,
|
||||
policy->other.net->get_address(policy->other.net), policy->other.net_mask);
|
||||
|
||||
status = charon->kernel_interface->add_policy(
|
||||
charon->kernel_interface,
|
||||
new_me, new_other,
|
||||
policy->me.net, policy->other.net,
|
||||
policy->me.net_mask, policy->other.net_mask,
|
||||
XFRM_POLICY_OUT, policy->upper_proto,
|
||||
this->protocol, this->reqid);
|
||||
|
||||
status |= charon->kernel_interface->add_policy(
|
||||
charon->kernel_interface,
|
||||
new_other, new_me,
|
||||
policy->other.net, policy->me.net,
|
||||
policy->other.net_mask, policy->me.net_mask,
|
||||
XFRM_POLICY_IN, policy->upper_proto,
|
||||
this->protocol, this->reqid);
|
||||
|
||||
status |= charon->kernel_interface->add_policy(
|
||||
charon->kernel_interface,
|
||||
new_other, new_me,
|
||||
policy->other.net, policy->me.net,
|
||||
policy->other.net_mask, policy->me.net_mask,
|
||||
XFRM_POLICY_FWD, policy->upper_proto,
|
||||
this->protocol, this->reqid);
|
||||
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
iterator->destroy(iterator);
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_sa_t.update_hosts.
|
||||
*/
|
||||
static status_t update_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other,
|
||||
int my_changes, int other_changes)
|
||||
{
|
||||
if (!my_changes || !other_changes)
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* update our (initator) SAs */
|
||||
if (update_sa_hosts(this, new_me, new_other, my_changes, other_changes, TRUE) != SUCCESS)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* update his (responder) SAs */
|
||||
if (update_sa_hosts(this, new_me, new_other, my_changes, other_changes, FALSE) != SUCCESS)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* update policies */
|
||||
if (my_changes & HOST_DIFF_ADDR || other_changes & HOST_DIFF_ADDR)
|
||||
{
|
||||
if (update_policy_hosts(this, new_me, new_other) != SUCCESS)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/* update hosts */
|
||||
if (my_changes)
|
||||
{
|
||||
this->me.addr->destroy(this->me.addr);
|
||||
this->me.addr = new_me->clone(new_me);
|
||||
}
|
||||
|
||||
if (other_changes)
|
||||
{
|
||||
this->other.addr->destroy(this->other.addr);
|
||||
this->other.addr = new_other->clone(new_other);
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_sa_t.destroy.
|
||||
*/
|
||||
@@ -579,9 +758,10 @@ static void destroy(private_child_sa_t *this)
|
||||
* Described in header.
|
||||
*/
|
||||
child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
|
||||
u_int32_t soft_lifetime, u_int32_t hard_lifetime)
|
||||
u_int32_t soft_lifetime, u_int32_t hard_lifetime,
|
||||
bool use_natt)
|
||||
{
|
||||
static u_int32_t reqid = 2000000000;
|
||||
static u_int32_t reqid = REQID_START;
|
||||
private_child_sa_t *this = malloc_thing(private_child_sa_t);
|
||||
|
||||
/* public functions */
|
||||
@@ -604,6 +784,7 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
|
||||
this->other.spi = 0;
|
||||
this->alloc_ah_spi = 0;
|
||||
this->alloc_esp_spi = 0;
|
||||
this->use_natt = use_natt;
|
||||
this->soft_lifetime = soft_lifetime;
|
||||
this->hard_lifetime = hard_lifetime;
|
||||
/* reuse old reqid if we are rekeying an existing CHILD_SA */
|
||||
@@ -612,5 +793,5 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
|
||||
this->protocol = PROTO_NONE;
|
||||
this->rekeyed = FALSE;
|
||||
|
||||
return (&this->public);
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
+35
-21
@@ -6,7 +6,8 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005 Martin Willi
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -30,16 +31,19 @@
|
||||
#include <config/proposal.h>
|
||||
#include <utils/logger.h>
|
||||
|
||||
/**
|
||||
* Where we should start with reqid enumeration
|
||||
*/
|
||||
#define REQID_START 2000000000
|
||||
|
||||
typedef struct child_sa_t child_sa_t;
|
||||
|
||||
/**
|
||||
* @brief Represents multiple IPsec SAs between two hosts.
|
||||
*
|
||||
* A child_sa_t contains multiple SAs. SAs for both
|
||||
* directions are managed in one child_sa_t object, and
|
||||
* if both AH and ESP is set up, both protocols are managed
|
||||
* by one child_sa_t. This means we can have two or
|
||||
* in the AH+ESP case four IPsec-SAs in one child_sa_t.
|
||||
* A child_sa_t contains two SAs. SAs for both
|
||||
* directions are managed in one child_sa_t object. Both
|
||||
* SAs and the policies have the same reqid.
|
||||
*
|
||||
* The procedure for child sa setup is as follows:
|
||||
* - A gets SPIs for a proposal via child_sa_t.alloc
|
||||
@@ -92,45 +96,53 @@ struct child_sa_t {
|
||||
protocol_id_t (*get_protocol) (child_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Allocate SPIs for a given proposals.
|
||||
* @brief Allocate SPIs for given proposals.
|
||||
*
|
||||
* Since the kernel manages SPIs for us, we need
|
||||
* to allocate them. If the proposal contains more
|
||||
* to allocate them. If a proposal contains more
|
||||
* than one protocol, for each protocol an SPI is
|
||||
* allocated. SPIs are stored internally and written
|
||||
* back to the proposal.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param proposal proposal for which SPIs are allocated
|
||||
* @param proposals list of proposals for which SPIs are allocated
|
||||
*/
|
||||
status_t (*alloc)(child_sa_t *this, linked_list_t* proposals);
|
||||
|
||||
/**
|
||||
* @brief Install the kernel SAs for a proposal.
|
||||
*
|
||||
* Since the kernel manages SPIs for us, we need
|
||||
* to allocate them. If the proposal contains more
|
||||
* than one protocol, for each protocol an SPI is
|
||||
* allocated. SPIs are stored internally and written
|
||||
* back to the proposal.
|
||||
* @brief Install the kernel SAs for a proposal, without previous SPI allocation.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param proposal proposal for which SPIs are allocated
|
||||
* @param prf_plus key material to use for key derivation
|
||||
* @return SUCCESS or FAILED
|
||||
*/
|
||||
status_t (*add)(child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus);
|
||||
|
||||
/**
|
||||
* @brief Install the kernel SAs for a proposal, if SPIs already allocated.
|
||||
*
|
||||
* This one updates the SAs in the kernel, which are
|
||||
* allocated via alloc, with a selected proposals.
|
||||
* @brief Install the kernel SAs for a proposal, after SPIs have been allocated.
|
||||
*
|
||||
* Updates an SA, for which SPIs are already allocated via alloc().
|
||||
*
|
||||
* @param this calling object
|
||||
* @param proposal proposal for which SPIs are allocated
|
||||
* @param prf_plus key material to use for key derivation
|
||||
* @return SUCCESS or FAILED
|
||||
*/
|
||||
status_t (*update)(child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus);
|
||||
|
||||
/**
|
||||
* @brief Update the hosts in the kernel SAs and policies
|
||||
*
|
||||
* @warning only call this after update() has been called.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param new_me the new local host
|
||||
* @param new_other the new remote host
|
||||
* @return SUCCESS or FAILED
|
||||
*/
|
||||
status_t (*update_hosts) (child_sa_t *this, host_t *new_me, host_t *new_other,
|
||||
int my_changes, int other_changes);
|
||||
|
||||
/**
|
||||
* @brief Install the policies using some traffic selectors.
|
||||
@@ -187,11 +199,13 @@ struct child_sa_t {
|
||||
* @param other remote address
|
||||
* @param soft_lifetime time before rekeying
|
||||
* @param hard_lifteime time before delete
|
||||
* @param use_natt TRUE if NAT traversal is used
|
||||
* @return child_sa_t object
|
||||
*
|
||||
* @ingroup sa
|
||||
*/
|
||||
child_sa_t * child_sa_create(u_int32_t rekey_reqid, host_t *me, host_t *other,
|
||||
u_int32_t soft_lifetime, u_int32_t hard_lifetime);
|
||||
u_int32_t soft_lifetime, u_int32_t hard_lifetime,
|
||||
bool use_natt);
|
||||
|
||||
#endif /*CHILD_SA_H_*/
|
||||
|
||||
+273
-16
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -19,6 +20,8 @@
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ike_sa.h"
|
||||
@@ -32,6 +35,7 @@
|
||||
#include <crypto/diffie_hellman.h>
|
||||
#include <crypto/prf_plus.h>
|
||||
#include <crypto/crypters/crypter.h>
|
||||
#include <crypto/hashers/hasher.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <encoding/payloads/nonce_payload.h>
|
||||
#include <encoding/payloads/ke_payload.h>
|
||||
@@ -173,6 +177,31 @@ struct private_ike_sa_t {
|
||||
* A logger for this IKE_SA.
|
||||
*/
|
||||
logger_t *logger;
|
||||
|
||||
/**
|
||||
* NAT hasher.
|
||||
*/
|
||||
hasher_t *nat_hasher;
|
||||
|
||||
/**
|
||||
* NAT status of local host.
|
||||
*/
|
||||
bool nat_here;
|
||||
|
||||
/**
|
||||
* NAT status of remote host.
|
||||
*/
|
||||
bool nat_there;
|
||||
|
||||
/**
|
||||
* Timestamp of last IKE message sent or received on this SA
|
||||
*/
|
||||
struct timeval last_msg_tv;
|
||||
|
||||
/*
|
||||
* Message ID of last DPD message
|
||||
*/
|
||||
u_int32_t last_dpd_message_id;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -320,24 +349,25 @@ static identification_t* get_other_id(private_ike_sa_t *this)
|
||||
return this->policy->get_other_id(this->policy);;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.retransmit_possible.
|
||||
*/
|
||||
static bool retransmit_possible(private_ike_sa_t *this, u_int32_t message_id)
|
||||
{
|
||||
return ((this->last_requested_message)
|
||||
&& (message_id != this->last_replied_message_id)
|
||||
&& (message_id == this->last_requested_message->get_message_id(
|
||||
this->last_requested_message)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.retransmit_request.
|
||||
*/
|
||||
status_t retransmit_request (private_ike_sa_t *this, u_int32_t message_id)
|
||||
static status_t retransmit_request(private_ike_sa_t *this, u_int32_t message_id)
|
||||
{
|
||||
packet_t *packet;
|
||||
|
||||
if (this->last_requested_message == NULL)
|
||||
{
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
if (message_id == this->last_replied_message_id)
|
||||
{
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
if ((this->last_requested_message->get_message_id(this->last_requested_message)) != message_id)
|
||||
|
||||
if (!this->protected.public.retransmit_possible(&this->protected.public, message_id))
|
||||
{
|
||||
return NOT_FOUND;
|
||||
}
|
||||
@@ -349,7 +379,6 @@ status_t retransmit_request (private_ike_sa_t *this, u_int32_t message_id)
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of protected_ike_sa_t.build_transforms.
|
||||
*/
|
||||
@@ -648,6 +677,12 @@ static status_t send_request(private_ike_sa_t *this, message_t *message)
|
||||
"Increase message counter for outgoing messages from %d",
|
||||
this->message_id_out);
|
||||
this->message_id_out++;
|
||||
|
||||
/* bump last message sent timestamp */
|
||||
if (gettimeofday(&this->last_msg_tv, NULL) < 0)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1, "failed to get time of day");
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@@ -869,6 +904,158 @@ static status_t initiate_connection(private_ike_sa_t *this, connection_t *connec
|
||||
return current_state->initiate_connection(current_state, connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of protected_ike_sa_t.update_connection_hosts.
|
||||
*
|
||||
* Quoting RFC 4306:
|
||||
*
|
||||
* 2.11. Address and Port Agility
|
||||
*
|
||||
* IKE runs over UDP ports 500 and 4500, and implicitly sets up ESP and
|
||||
* AH associations for the same IP addresses it runs over. The IP
|
||||
* addresses and ports in the outer header are, however, not themselves
|
||||
* cryptographically protected, and IKE is designed to work even through
|
||||
* Network Address Translation (NAT) boxes. An implementation MUST
|
||||
* accept incoming requests even if the source port is not 500 or 4500,
|
||||
* and MUST respond to the address and port from which the request was
|
||||
* received. It MUST specify the address and port at which the request
|
||||
* was received as the source address and port in the response. IKE
|
||||
* functions identically over IPv4 or IPv6.
|
||||
*
|
||||
* [...]
|
||||
*
|
||||
* There are cases where a NAT box decides to remove mappings that
|
||||
* are still alive (for example, the keepalive interval is too long,
|
||||
* or the NAT box is rebooted). To recover in these cases, hosts
|
||||
* that are not behind a NAT SHOULD send all packets (including
|
||||
* retransmission packets) to the IP address and port from the last
|
||||
* valid authenticated packet from the other end (i.e., dynamically
|
||||
* update the address). A host behind a NAT SHOULD NOT do this
|
||||
* because it opens a DoS attack possibility. Any authenticated IKE
|
||||
* packet or any authenticated UDP-encapsulated ESP packet can be
|
||||
* used to detect that the IP address or the port has changed.
|
||||
*/
|
||||
static status_t update_connection_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
|
||||
{
|
||||
host_t *old_other = NULL;
|
||||
iterator_t *iterator = NULL;
|
||||
child_sa_t *child_sa = NULL;
|
||||
int my_changes, other_changes;
|
||||
ike_sa_state_t s;
|
||||
|
||||
my_changes = me->get_differences(me, this->connection->get_my_host(this->connection));
|
||||
|
||||
old_other = this->connection->get_other_host(this->connection);
|
||||
other_changes = other->get_differences(other, old_other);
|
||||
|
||||
if (!my_changes && !other_changes) {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
if (my_changes)
|
||||
{
|
||||
this->connection->update_my_host(this->connection, me->clone(me));
|
||||
}
|
||||
|
||||
s = this->protected.public.get_state(&this->protected.public);
|
||||
|
||||
if (s == RESPONDER_INIT || s == IKE_SA_INIT_REQUESTED || !this->nat_here)
|
||||
{
|
||||
if (other_changes)
|
||||
{
|
||||
this->connection->update_other_host(this->connection, other->clone(other));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (other_changes & HOST_DIFF_ADDR)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1,
|
||||
"Destination ip changed from %s to %s. As we are NATed this is not allowed!",
|
||||
old_other->get_address(old_other), other->get_address(other));
|
||||
return DESTROY_ME;
|
||||
}
|
||||
else if (other_changes & HOST_DIFF_PORT)
|
||||
{
|
||||
old_other->set_port(old_other, other->get_port(other));
|
||||
}
|
||||
}
|
||||
|
||||
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)&child_sa))
|
||||
{
|
||||
child_sa->update_hosts(child_sa,
|
||||
this->connection->get_my_host(this->connection),
|
||||
this->connection->get_other_host(this->connection),
|
||||
my_changes, other_changes);
|
||||
/* XXX error handling */
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of protected_ike_sa_t.build_transforms.
|
||||
* TODO: IPv6 support.
|
||||
*/
|
||||
static chunk_t generate_natd_hash(private_ike_sa_t *this, u_int64_t spi_i, u_int64_t spi_r, host_t *host)
|
||||
{
|
||||
chunk_t natd_string;
|
||||
chunk_t natd_hash;
|
||||
void *p;
|
||||
struct sockaddr_in* sai;
|
||||
char buf[512];
|
||||
|
||||
natd_hash = chunk_alloc(this->nat_hasher->get_hash_size(this->nat_hasher));
|
||||
natd_string = chunk_alloc(8 + 8 + 4 + 2);
|
||||
|
||||
sai = (struct sockaddr_in*)host->get_sockaddr(host);
|
||||
p = natd_string.ptr;
|
||||
*(u_int64_t*)p = spi_i; p += sizeof(spi_i);
|
||||
*(u_int64_t*)p = spi_r; p += sizeof(spi_r);
|
||||
*(u_int32_t*)p = sai->sin_addr.s_addr; p += sizeof(sai->sin_addr.s_addr);
|
||||
*(u_int16_t*)p = sai->sin_port; p += sizeof(sai->sin_port);
|
||||
|
||||
this->nat_hasher->get_hash(this->nat_hasher, natd_string, natd_hash.ptr);
|
||||
this->nat_hasher->reset(this->nat_hasher);
|
||||
|
||||
sprintf(buf, "natd_hash(%016llx %016llx %s:%d)\n == SHA1(", spi_i, spi_r,
|
||||
host->get_address(host), host->get_port(host));
|
||||
chunk_to_hex(buf + strlen(buf), sizeof(buf) - strlen(buf), natd_string);
|
||||
strcat(buf, ") == ");
|
||||
chunk_to_hex(buf + strlen(buf), sizeof(buf) - strlen(buf), natd_hash);
|
||||
this->logger->log(this->logger, CONTROL|LEVEL3, buf);
|
||||
|
||||
chunk_free(&natd_string);
|
||||
return natd_hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.send_dpd_request.
|
||||
*/
|
||||
static status_t send_dpd_request(private_ike_sa_t *this)
|
||||
{
|
||||
message_t *dpd_msg;
|
||||
status_t status;
|
||||
this->protected.build_message(&this->protected, INFORMATIONAL, TRUE, &dpd_msg);
|
||||
status = this->protected.send_request(&this->protected, dpd_msg);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
dpd_msg->destroy(dpd_msg);
|
||||
}
|
||||
this->last_dpd_message_id = dpd_msg->get_message_id(dpd_msg);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.get_last_dpd_message_id
|
||||
*/
|
||||
static u_int32_t get_last_dpd_message_id(private_ike_sa_t *this)
|
||||
{
|
||||
return this->last_dpd_message_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.get_child_sa.
|
||||
*/
|
||||
@@ -1026,7 +1213,8 @@ static status_t rekey_child_sa(private_ike_sa_t *this, u_int32_t reqid)
|
||||
this->connection->get_my_host(this->connection),
|
||||
this->connection->get_other_host(this->connection),
|
||||
this->policy->get_soft_lifetime(this->policy),
|
||||
this->policy->get_hard_lifetime(this->policy));
|
||||
this->policy->get_hard_lifetime(this->policy),
|
||||
this->nat_here || this->nat_there);
|
||||
child_sa->alloc(child_sa, proposals);
|
||||
sa_payload = sa_payload_create_from_proposal_list(proposals);
|
||||
request->add_payload(request, (payload_t*)sa_payload);
|
||||
@@ -1183,6 +1371,57 @@ static status_t delete_(private_ike_sa_t *this)
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.is_my_host_behind_nat.
|
||||
*/
|
||||
static bool is_my_host_behind_nat (private_ike_sa_t *this)
|
||||
{
|
||||
return this->nat_here;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.is_other_host_behind_nat.
|
||||
*/
|
||||
static bool is_other_host_behind_nat (private_ike_sa_t *this)
|
||||
{
|
||||
return this->nat_there;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.is_any_host_behind_nat.
|
||||
*/
|
||||
static bool is_any_host_behind_nat (private_ike_sa_t *this)
|
||||
{
|
||||
return this->nat_here || this->nat_there;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of protected_ike_sa_t.set_my_host_behind_nat.
|
||||
*/
|
||||
static void set_my_host_behind_nat (private_ike_sa_t *this, bool nat)
|
||||
{
|
||||
this->nat_here = nat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of protected_ike_sa_t.set_other_host_behind_nat.
|
||||
*/
|
||||
static void set_other_host_behind_nat (private_ike_sa_t *this, bool nat)
|
||||
{
|
||||
this->nat_there = nat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.get_last_msg_tv.
|
||||
*/
|
||||
static struct timeval get_last_msg_tv (private_ike_sa_t *this)
|
||||
{
|
||||
/*
|
||||
* XXX: query kernel for last activity time
|
||||
*/
|
||||
return this->last_msg_tv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of protected_ike_sa_t.destroy.
|
||||
*/
|
||||
@@ -1269,6 +1508,7 @@ static void destroy(private_ike_sa_t *this)
|
||||
{
|
||||
this->last_responded_message->destroy(this->last_responded_message);
|
||||
}
|
||||
this->nat_hasher->destroy(this->nat_hasher);
|
||||
this->ike_sa_id->destroy(this->ike_sa_id);
|
||||
this->randomizer->destroy(this->randomizer);
|
||||
this->current_state->destroy(this->current_state);
|
||||
@@ -1294,11 +1534,17 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
|
||||
this->protected.public.get_my_id = (identification_t*(*)(ike_sa_t*)) get_my_id;
|
||||
this->protected.public.get_other_id = (identification_t*(*)(ike_sa_t*)) get_other_id;
|
||||
this->protected.public.get_connection = (connection_t*(*)(ike_sa_t*)) get_connection;
|
||||
this->protected.public.retransmit_possible = (bool (*) (ike_sa_t *, u_int32_t)) retransmit_possible;
|
||||
this->protected.public.retransmit_request = (status_t (*) (ike_sa_t *, u_int32_t)) retransmit_request;
|
||||
this->protected.public.get_state = (ike_sa_state_t (*) (ike_sa_t *this)) get_state;
|
||||
this->protected.public.log_status = (void (*) (ike_sa_t*,logger_t*,char*))log_status;
|
||||
this->protected.public.delete = (status_t(*)(ike_sa_t*))delete_;
|
||||
this->protected.public.destroy = (void(*)(ike_sa_t*))destroy;
|
||||
this->protected.public.is_my_host_behind_nat = (bool(*)(ike_sa_t*)) is_my_host_behind_nat;
|
||||
this->protected.public.is_other_host_behind_nat = (bool(*)(ike_sa_t*)) is_other_host_behind_nat;
|
||||
this->protected.public.is_any_host_behind_nat = (bool(*)(ike_sa_t*)) is_any_host_behind_nat;
|
||||
this->protected.public.get_last_msg_tv = (struct timeval (*)(ike_sa_t*)) get_last_msg_tv;
|
||||
this->protected.public.send_dpd_request = (status_t (*)(ike_sa_t*)) send_dpd_request;
|
||||
|
||||
/* protected functions */
|
||||
this->protected.build_message = (void (*) (protected_ike_sa_t *, exchange_type_t,bool,message_t**)) build_message;
|
||||
@@ -1327,6 +1573,11 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
|
||||
this->protected.set_last_replied_message_id = (void (*) (protected_ike_sa_t *,u_int32_t)) set_last_replied_message_id;
|
||||
this->protected.destroy_child_sa = (u_int32_t (*)(protected_ike_sa_t*,u_int32_t))destroy_child_sa;
|
||||
this->protected.get_child_sa = (child_sa_t* (*)(protected_ike_sa_t*,u_int32_t))get_child_sa_by_spi;
|
||||
this->protected.set_my_host_behind_nat = (void(*)(protected_ike_sa_t*, bool)) set_my_host_behind_nat;
|
||||
this->protected.set_other_host_behind_nat = (void(*)(protected_ike_sa_t*, bool)) set_other_host_behind_nat;
|
||||
this->protected.generate_natd_hash = (chunk_t (*) (protected_ike_sa_t *, u_int64_t, u_int64_t, host_t*)) generate_natd_hash;
|
||||
this->protected.get_last_dpd_message_id = (u_int32_t (*) (protected_ike_sa_t*)) get_last_dpd_message_id;
|
||||
this->protected.update_connection_hosts = (status_t (*) (protected_ike_sa_t *, host_t*, host_t*)) update_connection_hosts;
|
||||
|
||||
/* initialize private fields */
|
||||
this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
|
||||
@@ -1350,7 +1601,13 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
|
||||
this->child_prf = NULL;
|
||||
this->connection = NULL;
|
||||
this->policy = NULL;
|
||||
|
||||
this->nat_hasher = hasher_create(HASH_SHA1);
|
||||
this->nat_here = FALSE;
|
||||
this->nat_there = FALSE;
|
||||
this->last_msg_tv.tv_sec = 0;
|
||||
this->last_msg_tv.tv_usec = 0;
|
||||
this->last_dpd_message_id = 0;
|
||||
|
||||
/* at creation time, IKE_SA is in a initiator state */
|
||||
if (ike_sa_id->is_initiator(ike_sa_id))
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -92,6 +93,17 @@ struct ike_sa_t {
|
||||
*/
|
||||
status_t (*initiate_connection) (ike_sa_t *this, connection_t *connection);
|
||||
|
||||
/**
|
||||
* @brief Checks whether retransmission is possible.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param message_id ID of the request to retransmit
|
||||
* @return
|
||||
* - TRUE if retransmit is possible
|
||||
* - FALSE if not
|
||||
*/
|
||||
bool (*retransmit_possible) (ike_sa_t *this, u_int32_t message_id);
|
||||
|
||||
/**
|
||||
* @brief Retransmits a request.
|
||||
*
|
||||
@@ -199,6 +211,38 @@ struct ike_sa_t {
|
||||
*/
|
||||
connection_t* (*get_connection) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Query NAT detection status for local host.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return TRUE if this host is behind NAT
|
||||
*/
|
||||
bool (*is_my_host_behind_nat) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Query NAT detection status for remote host.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return TRUE if other host is behind NAT
|
||||
*/
|
||||
bool (*is_other_host_behind_nat) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Query NAT detection status for any host.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return TRUE if this or other host is behind NAT
|
||||
*/
|
||||
bool (*is_any_host_behind_nat) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Query timeval of last message sent.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return time when the last message was sent
|
||||
*/
|
||||
struct timeval (*get_last_msg_tv) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the state of type of associated state object.
|
||||
*
|
||||
@@ -207,6 +251,13 @@ struct ike_sa_t {
|
||||
*/
|
||||
ike_sa_state_t (*get_state) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Sends a DPD request to the peer.
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
status_t (*send_dpd_request) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Log the status of a the ike sa to a logger.
|
||||
*
|
||||
@@ -507,6 +558,52 @@ struct protected_ike_sa_t {
|
||||
* @param this calling object
|
||||
*/
|
||||
void (*reset_message_buffers) (protected_ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* @brief Set NAT detection status for local host.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param nat if TRUE, local host is behing NAT
|
||||
*/
|
||||
void (*set_my_host_behind_nat) (protected_ike_sa_t *this, bool nat);
|
||||
|
||||
/**
|
||||
* @brief Set NAT detection status for remote host.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param nat if TRUE, remote host is behing NAT
|
||||
*/
|
||||
void (*set_other_host_behind_nat) (protected_ike_sa_t *this, bool nat);
|
||||
|
||||
/**
|
||||
* @brief Generate NAT-D payload hash.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param spi_i IKE SPI of initiator
|
||||
* @param spi_r IKE SPI of responder
|
||||
* @param host address and port of the host/interface
|
||||
* @return chunk containing calculated NAT-D hash
|
||||
*/
|
||||
chunk_t (*generate_natd_hash) (protected_ike_sa_t *this, u_int64_t spi_i, u_int64_t spi_r, host_t *host);
|
||||
|
||||
/**
|
||||
* @brief Dynamically update hosts on the associated connection.
|
||||
*
|
||||
* Warning: me and other host are cloned.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param me local address and port
|
||||
* @param other remote address and port
|
||||
*/
|
||||
status_t (*update_connection_hosts) (protected_ike_sa_t *this, host_t *me, host_t *other);
|
||||
|
||||
/**
|
||||
* @brief Return the message id of the last DPD message
|
||||
*
|
||||
* @param this calling object
|
||||
* @return the messages id
|
||||
*/
|
||||
u_int32_t (*get_last_dpd_message_id) (protected_ike_sa_t *this);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -286,6 +287,14 @@ static status_t process_message(private_ike_auth_requested_t *this, message_t *i
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
status = this->ike_sa->update_connection_hosts(this->ike_sa,
|
||||
ike_auth_reply->get_destination(ike_auth_reply),
|
||||
ike_auth_reply->get_source(ike_auth_reply));
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
/* process all payloads */
|
||||
status = this->process_idr_payload(this, idr_payload);
|
||||
if (status != SUCCESS)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -31,7 +32,7 @@
|
||||
#include <encoding/payloads/nonce_payload.h>
|
||||
#include <sa/child_sa.h>
|
||||
#include <sa/states/delete_ike_sa_requested.h>
|
||||
|
||||
#include <queues/jobs/send_dpd_job.h>
|
||||
|
||||
typedef struct private_ike_sa_established_t private_ike_sa_established_t;
|
||||
|
||||
@@ -85,6 +86,21 @@ struct private_ike_sa_established_t {
|
||||
logger_t *logger;
|
||||
};
|
||||
|
||||
/**
|
||||
* Schedule send dpd job
|
||||
*/
|
||||
static void schedule_dpd_job(private_ike_sa_established_t *this)
|
||||
{
|
||||
u_int32_t interval = charon->configuration->get_dpd_interval(charon->configuration);
|
||||
|
||||
if (interval)
|
||||
{
|
||||
charon->event_queue->add_relative(charon->event_queue,
|
||||
(job_t*)send_dpd_job_create(this->ike_sa->public.get_id(&this->ike_sa->public)),
|
||||
interval);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_ike_sa_established_t.build_sa_payload.
|
||||
*/
|
||||
@@ -99,6 +115,7 @@ static status_t build_sa_payload(private_ike_sa_established_t *this, sa_payload_
|
||||
connection_t *connection;
|
||||
policy_t *policy;
|
||||
u_int32_t reqid = 0;
|
||||
bool use_natt;
|
||||
|
||||
/* prepare reply */
|
||||
sa_response = sa_payload_create();
|
||||
@@ -142,11 +159,13 @@ static status_t build_sa_payload(private_ike_sa_established_t *this, sa_payload_
|
||||
{ /* reuse old reqid if we are rekeying */
|
||||
reqid = this->old_child_sa->get_reqid(this->old_child_sa);
|
||||
}
|
||||
use_natt = this->ike_sa->public.is_any_host_behind_nat(&this->ike_sa->public);
|
||||
this->child_sa = child_sa_create(reqid,
|
||||
connection->get_my_host(connection),
|
||||
connection->get_other_host(connection),
|
||||
policy->get_soft_lifetime(policy),
|
||||
policy->get_hard_lifetime(policy));
|
||||
policy->get_hard_lifetime(policy),
|
||||
use_natt);
|
||||
|
||||
status = this->child_sa->add(this->child_sa, proposal, prf_plus);
|
||||
prf_plus->destroy(prf_plus);
|
||||
@@ -404,6 +423,11 @@ static status_t process_informational(private_ike_sa_established_t *this, messag
|
||||
{
|
||||
delete_payload_t *delete_request = NULL;
|
||||
iterator_t *payloads = request->get_payload_iterator(request);
|
||||
|
||||
if (!payloads->get_count(payloads))
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "DPD request received.");
|
||||
}
|
||||
|
||||
while (payloads->has_next(payloads))
|
||||
{
|
||||
@@ -434,7 +458,7 @@ static status_t process_informational(private_ike_sa_established_t *this, messag
|
||||
if (delete_request->get_protocol_id(delete_request) == PROTO_IKE)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "DELETE request for IKE_SA received");
|
||||
/* switch to delete_ike_sa_requested. This is not absolutly correct, but we
|
||||
/* switch to delete_ike_sa_requested. This is not absolutely correct, but we
|
||||
* allow the clean destruction of an SA only in this state. */
|
||||
this->ike_sa->set_new_state(this->ike_sa, (state_t*)delete_ike_sa_requested_create(this->ike_sa));
|
||||
this->public.state_interface.destroy(&(this->public.state_interface));
|
||||
@@ -473,6 +497,53 @@ static status_t process_informational(private_ike_sa_established_t *this, messag
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an informational response
|
||||
*/
|
||||
static status_t process_informational_response(private_ike_sa_established_t *this, message_t *message)
|
||||
{
|
||||
iterator_t *payloads = message->get_payload_iterator(message);
|
||||
|
||||
if (!payloads->get_count(payloads))
|
||||
{
|
||||
if (message->get_message_id(message)
|
||||
!= this->ike_sa->get_last_dpd_message_id(this->ike_sa))
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1, "DPD response received that does not match our last sent dpd message.");
|
||||
payloads->destroy(payloads);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
this->logger->log(this->logger, CONTROL, "DPD response received. Schedule job.");
|
||||
schedule_dpd_job(this);
|
||||
|
||||
payloads->destroy(payloads);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
while (payloads->has_next(payloads))
|
||||
{
|
||||
payload_t *payload;
|
||||
payloads->current(payloads, (void**)&payload);
|
||||
|
||||
switch (payload->get_type(payload))
|
||||
{
|
||||
default:
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1, "Ignoring Payload %s (%d)",
|
||||
mapping_find(payload_type_m, payload->get_type(payload)),
|
||||
payload->get_type(payload));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* iterator can be destroyed */
|
||||
payloads->destroy(payloads);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements state_t.get_state
|
||||
* Implements state_t.process_message
|
||||
*/
|
||||
static status_t process_message(private_ike_sa_established_t *this, message_t *message)
|
||||
@@ -513,6 +584,13 @@ static status_t process_message(private_ike_sa_established_t *this, message_t *m
|
||||
return status;
|
||||
}
|
||||
|
||||
status = this->ike_sa->update_connection_hosts(this->ike_sa,
|
||||
message->get_destination(message), message->get_source(message));
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
/* prepare a reply of the same type */
|
||||
this->ike_sa->build_message(this->ike_sa, message->get_exchange_type(message), FALSE, &response);
|
||||
|
||||
@@ -570,6 +648,9 @@ ike_sa_established_t *ike_sa_established_create(protected_ike_sa_t *ike_sa)
|
||||
this->nonce_i = CHUNK_INITIALIZER;
|
||||
this->nonce_r = CHUNK_INITIALIZER;
|
||||
this->old_child_sa = NULL;
|
||||
|
||||
/* schedule initial dpd job */
|
||||
schedule_dpd_job(this);
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -90,6 +91,36 @@ struct private_ike_sa_init_requested_t {
|
||||
*/
|
||||
logger_t *logger;
|
||||
|
||||
/**
|
||||
* Precomputed NAT-D hash for initiator.
|
||||
*/
|
||||
chunk_t natd_hash_i;
|
||||
|
||||
/**
|
||||
* Flag indicating that an initiator NAT-D hash matched.
|
||||
*/
|
||||
bool natd_hash_i_matched;
|
||||
|
||||
/**
|
||||
* NAT-D payload count for NAT_DETECTION_SOURCE_IP.
|
||||
*/
|
||||
int natd_seen_i;
|
||||
|
||||
/**
|
||||
* Precomputed NAT-D hash of responder.
|
||||
*/
|
||||
chunk_t natd_hash_r;
|
||||
|
||||
/**
|
||||
* Flag indicating that a responder NAT-D hash matched.
|
||||
*/
|
||||
bool natd_hash_r_matched;
|
||||
|
||||
/**
|
||||
* NAT-D payload count for NAT_DETECTION_DESTINATION_IP.
|
||||
*/
|
||||
int natd_seen_r;
|
||||
|
||||
|
||||
/**
|
||||
* Process NONCE payload of IKE_SA_INIT response.
|
||||
@@ -271,6 +302,26 @@ static status_t process_message(private_ike_sa_init_requested_t *this, message_t
|
||||
ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public));
|
||||
ike_sa_id->set_responder_spi(ike_sa_id,responder_spi);
|
||||
|
||||
/*
|
||||
* Precompute NAT-D hashes.
|
||||
* Even though there SHOULD only be a single payload of each
|
||||
* Notify type, we precompute both hashes.
|
||||
*/
|
||||
this->natd_hash_i = this->ike_sa->generate_natd_hash(this->ike_sa,
|
||||
ike_sa_init_reply->get_initiator_spi(ike_sa_init_reply),
|
||||
ike_sa_init_reply->get_responder_spi(ike_sa_init_reply),
|
||||
ike_sa_init_reply->get_source(ike_sa_init_reply));
|
||||
this->natd_hash_i_matched = FALSE;
|
||||
this->natd_seen_i = 0;
|
||||
this->natd_hash_r = this->ike_sa->generate_natd_hash(this->ike_sa,
|
||||
ike_sa_init_reply->get_initiator_spi(ike_sa_init_reply),
|
||||
ike_sa_init_reply->get_responder_spi(ike_sa_init_reply),
|
||||
ike_sa_init_reply->get_destination(ike_sa_init_reply));
|
||||
this->natd_hash_r_matched = FALSE;
|
||||
this->natd_seen_r = 0;
|
||||
this->ike_sa->set_my_host_behind_nat(this->ike_sa, FALSE);
|
||||
this->ike_sa->set_other_host_behind_nat(this->ike_sa, FALSE);
|
||||
|
||||
/* Iterate over all payloads.
|
||||
*
|
||||
* The message is already checked for the right payload types.
|
||||
@@ -354,12 +405,59 @@ static status_t process_message(private_ike_sa_init_requested_t *this, message_t
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* apply the address on wich we really received the packet */
|
||||
/* NAT-D */
|
||||
if ((!this->natd_seen_i && this->natd_seen_r > 0)
|
||||
|| (this->natd_seen_i > 0 && !this->natd_seen_r))
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request contained wrong number of NAT-D payloads. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
if (this->natd_seen_r > 1)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "Warning: IKE_SA_INIT request contained multiple Notify(NAT_DETECTION_DESTINATION_IP) payloads.");
|
||||
}
|
||||
if (this->natd_seen_i > 0 && !this->natd_hash_i_matched)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "Remote host is behind NAT, using NAT-T.");
|
||||
this->ike_sa->set_other_host_behind_nat(this->ike_sa, TRUE);
|
||||
}
|
||||
if (this->natd_seen_r > 0 && !this->natd_hash_r_matched)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "Local host is behind NAT, using NAT-T.");
|
||||
this->ike_sa->set_my_host_behind_nat(this->ike_sa, TRUE);
|
||||
}
|
||||
|
||||
/* apply the address on wich we really received the packet,
|
||||
* and switch to port 4500 when using NAT-T and NAT was detected.
|
||||
*/
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
me = ike_sa_init_reply->get_destination(ike_sa_init_reply);
|
||||
other = ike_sa_init_reply->get_source(ike_sa_init_reply);
|
||||
connection->update_my_host(connection, me->clone(me));
|
||||
connection->update_other_host(connection, other->clone(other));
|
||||
|
||||
if (this->ike_sa->public.is_any_host_behind_nat((ike_sa_t*)this->ike_sa))
|
||||
{
|
||||
me->set_port(me, IKEV2_NATT_PORT);
|
||||
other->set_port(other, IKEV2_NATT_PORT);
|
||||
this->logger->log(this->logger, AUDIT, "Switching to port %d.", IKEV2_NATT_PORT);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "No NAT detected, not using NAT-T.");
|
||||
}
|
||||
|
||||
if (this->ike_sa->public.is_my_host_behind_nat(&this->ike_sa->public))
|
||||
{
|
||||
charon->event_queue->add_relative(charon->event_queue,
|
||||
(job_t*)send_keepalive_job_create(this->ike_sa->public.get_id((ike_sa_t*)this->ike_sa)),
|
||||
charon->configuration->get_keepalive_interval(charon->configuration));
|
||||
}
|
||||
|
||||
status = this->ike_sa->update_connection_hosts(this->ike_sa, me, other);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
policy->update_my_ts(policy, me);
|
||||
policy->update_other_ts(policy, other);
|
||||
@@ -575,7 +673,8 @@ static status_t build_sa_payload (private_ike_sa_init_requested_t *this, message
|
||||
connection->get_my_host(connection),
|
||||
connection->get_other_host(connection),
|
||||
policy->get_soft_lifetime(policy),
|
||||
policy->get_hard_lifetime(policy));
|
||||
policy->get_hard_lifetime(policy),
|
||||
this->ike_sa->public.is_any_host_behind_nat(&this->ike_sa->public));
|
||||
if (this->child_sa->alloc(this->child_sa, proposal_list) != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA");
|
||||
@@ -633,6 +732,7 @@ static status_t build_tsr_payload (private_ike_sa_init_requested_t *this, messag
|
||||
*/
|
||||
static status_t process_notify_payload(private_ike_sa_init_requested_t *this, notify_payload_t *notify_payload)
|
||||
{
|
||||
chunk_t notification_data;
|
||||
notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "Process notify type %s",
|
||||
@@ -701,6 +801,44 @@ static status_t process_notify_payload(private_ike_sa_init_requested_t *this, no
|
||||
}
|
||||
return FAILED;
|
||||
}
|
||||
case NAT_DETECTION_DESTINATION_IP:
|
||||
{
|
||||
this->natd_seen_r++;
|
||||
if (this->natd_hash_r_matched)
|
||||
return SUCCESS;
|
||||
|
||||
notification_data = notify_payload->get_notification_data(notify_payload);
|
||||
if (chunk_equals(notification_data, this->natd_hash_r))
|
||||
{
|
||||
this->natd_hash_r_matched = TRUE;
|
||||
this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash match");
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash mismatch");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
case NAT_DETECTION_SOURCE_IP:
|
||||
{
|
||||
this->natd_seen_i++;
|
||||
if (this->natd_hash_i_matched)
|
||||
return SUCCESS;
|
||||
|
||||
notification_data = notify_payload->get_notification_data(notify_payload);
|
||||
if (chunk_equals(notification_data, this->natd_hash_i))
|
||||
{
|
||||
this->natd_hash_i_matched = TRUE;
|
||||
this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash match");
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash mismatch");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
default:
|
||||
{
|
||||
/*
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -295,7 +296,14 @@ static status_t process_message(private_ike_sa_init_responded_t *this, message_t
|
||||
this->logger->log(this->logger, AUDIT, "IKE_AUTH reply did not contain all required payloads. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
|
||||
status = this->ike_sa->update_connection_hosts(this->ike_sa,
|
||||
request->get_destination(request), request->get_source(request));
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
/* build response */
|
||||
this->ike_sa->build_message(this->ike_sa, IKE_AUTH, FALSE, &response);
|
||||
|
||||
@@ -442,6 +450,7 @@ static status_t build_sa_payload(private_ike_sa_init_responded_t *this, sa_paylo
|
||||
status_t status;
|
||||
connection_t *connection;
|
||||
policy_t *policy;
|
||||
bool use_natt;
|
||||
|
||||
/* prepare reply */
|
||||
sa_response = sa_payload_create();
|
||||
@@ -477,11 +486,13 @@ static status_t build_sa_payload(private_ike_sa_init_responded_t *this, sa_paylo
|
||||
|
||||
policy = this->ike_sa->get_policy(this->ike_sa);
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
use_natt = this->ike_sa->public.is_any_host_behind_nat(&this->ike_sa->public);
|
||||
this->child_sa = child_sa_create(0,
|
||||
connection->get_my_host(connection),
|
||||
connection->get_other_host(connection),
|
||||
policy->get_soft_lifetime(policy),
|
||||
policy->get_hard_lifetime(policy));
|
||||
policy->get_hard_lifetime(policy),
|
||||
use_natt);
|
||||
|
||||
status = this->child_sa->add(this->child_sa, proposal, prf_plus);
|
||||
prf_plus->destroy(prf_plus);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -28,6 +29,7 @@
|
||||
#include <sa/states/ike_sa_init_requested.h>
|
||||
#include <queues/jobs/retransmit_request_job.h>
|
||||
#include <crypto/diffie_hellman.h>
|
||||
#include <crypto/hashers/hasher.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <encoding/payloads/ke_payload.h>
|
||||
#include <encoding/payloads/nonce_payload.h>
|
||||
@@ -92,7 +94,24 @@ struct private_initiator_init_t {
|
||||
* @param request message_t object to add the NONCE payload
|
||||
*/
|
||||
status_t (*build_nonce_payload) (private_initiator_init_t *this,message_t *request);
|
||||
|
||||
/**
|
||||
* Builds the NAT-T Notify(NAT_DETECTION_SOURCE_IP) and
|
||||
* Notify(NAT_DETECTION_DESTINATION_IP) payloads for this state.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param request message_t object to add the Notify payloads
|
||||
*/
|
||||
void (*build_natd_payload) (private_initiator_init_t *this, message_t *request, notify_message_type_t type, host_t *host);
|
||||
|
||||
/**
|
||||
* Builds the NAT-T Notify(NAT_DETECTION_SOURCE_IP) and
|
||||
* Notify(NAT_DETECTION_DESTINATION_IP) payloads for this state.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param request message_t object to add the Notify payloads
|
||||
*/
|
||||
void (*build_natd_payloads) (private_initiator_init_t *this, message_t *request);
|
||||
|
||||
/**
|
||||
* Destroy function called internally of this class after state change to state
|
||||
* IKE_SA_INIT_REQUESTED succeeded.
|
||||
@@ -187,6 +206,10 @@ status_t retry_initiate_connection (private_initiator_init_t *this, diffie_hellm
|
||||
message->destroy(message);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* build Notify(NAT-D) payloads */
|
||||
this->build_natd_payloads(this, message);
|
||||
|
||||
/* message can now be sent (must not be destroyed) */
|
||||
status = this->ike_sa->send_request(this->ike_sa, message);
|
||||
if (status != SUCCESS)
|
||||
@@ -286,6 +309,57 @@ static status_t build_nonce_payload(private_initiator_init_t *this, message_t *r
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_initiator_init_t.build_natd_payload.
|
||||
*/
|
||||
static void build_natd_payload(private_initiator_init_t *this, message_t *request, notify_message_type_t type, host_t *host)
|
||||
{
|
||||
chunk_t hash;
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "Building Notify(NAT-D) payload");
|
||||
notify_payload_t *notify_payload;
|
||||
notify_payload = notify_payload_create();
|
||||
/*notify_payload->set_protocol_id(notify_payload, NULL);*/
|
||||
/*notify_payload->set_spi(notify_payload, NULL);*/
|
||||
notify_payload->set_notify_message_type(notify_payload, type);
|
||||
hash = this->ike_sa->generate_natd_hash(this->ike_sa,
|
||||
request->get_initiator_spi(request),
|
||||
request->get_responder_spi(request),
|
||||
host);
|
||||
notify_payload->set_notification_data(notify_payload, hash);
|
||||
chunk_free(&hash);
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "Add Notify(NAT-D) payload to message");
|
||||
request->add_payload(request, (payload_t *) notify_payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_initiator_init_t.build_natd_payloads.
|
||||
*/
|
||||
static void build_natd_payloads(private_initiator_init_t *this, message_t *request)
|
||||
{
|
||||
connection_t *connection;
|
||||
linked_list_t *hostlist;
|
||||
iterator_t *hostiter;
|
||||
host_t *host;
|
||||
|
||||
/*
|
||||
* N(NAT_DETECTION_SOURCE_IP)+
|
||||
*/
|
||||
hostlist = charon->interfaces->get_addresses(charon->interfaces);
|
||||
hostiter = hostlist->create_iterator(hostlist, TRUE);
|
||||
while(hostiter->iterate(hostiter, (void**)&host)) {
|
||||
this->build_natd_payload(this, request, NAT_DETECTION_SOURCE_IP,
|
||||
host);
|
||||
}
|
||||
hostiter->destroy(hostiter);
|
||||
|
||||
/*
|
||||
* N(NAT_DETECTION_DESTINATION_IP)
|
||||
*/
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
this->build_natd_payload(this, request, NAT_DETECTION_DESTINATION_IP,
|
||||
connection->get_other_host(connection));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of state_t.process_message.
|
||||
*/
|
||||
@@ -352,6 +426,8 @@ initiator_init_t *initiator_init_create(protected_ike_sa_t *ike_sa)
|
||||
this->build_nonce_payload = build_nonce_payload;
|
||||
this->build_sa_payload = build_sa_payload;
|
||||
this->build_ke_payload = build_ke_payload;
|
||||
this->build_natd_payload = build_natd_payload;
|
||||
this->build_natd_payloads = build_natd_payloads;
|
||||
|
||||
/* private data */
|
||||
this->ike_sa = ike_sa;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -30,6 +31,7 @@
|
||||
#include <encoding/payloads/nonce_payload.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
#include <crypto/diffie_hellman.h>
|
||||
#include <queues/jobs/send_keepalive_job.h>
|
||||
|
||||
|
||||
typedef struct private_responder_init_t private_responder_init_t;
|
||||
@@ -90,6 +92,37 @@ struct private_responder_init_t {
|
||||
*/
|
||||
logger_t *logger;
|
||||
|
||||
/**
|
||||
* Precomputed NAT-D hash for initiator.
|
||||
*/
|
||||
chunk_t natd_hash_i;
|
||||
|
||||
/**
|
||||
* Flag indicating that an initiator NAT-D hash matched.
|
||||
*/
|
||||
bool natd_hash_i_matched;
|
||||
|
||||
/**
|
||||
* NAT-D payload count for NAT_DETECTION_SOURCE_IP.
|
||||
*/
|
||||
int natd_seen_i;
|
||||
|
||||
/**
|
||||
* Precomputed NAT-D hash of responder.
|
||||
*/
|
||||
chunk_t natd_hash_r;
|
||||
|
||||
/**
|
||||
* Flag indicating that a responder NAT-D hash matched.
|
||||
*/
|
||||
bool natd_hash_r_matched;
|
||||
|
||||
/**
|
||||
* NAT-D payload count for NAT_DETECTION_DESTINATION_IP.
|
||||
*/
|
||||
int natd_seen_r;
|
||||
|
||||
|
||||
/**
|
||||
* Handles received SA payload and builds the SA payload for the response.
|
||||
*
|
||||
@@ -124,6 +157,24 @@ struct private_responder_init_t {
|
||||
*/
|
||||
status_t (*build_nonce_payload) (private_responder_init_t *this,nonce_payload_t *nonce_request, message_t *response);
|
||||
|
||||
/**
|
||||
* Builds the NAT-T Notify(NAT_DETECTION_SOURCE_IP) and
|
||||
* Notify(NAT_DETECTION_DESTINATION_IP) payloads for this state.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param request message_t object to add the Notify payloads
|
||||
*/
|
||||
void (*build_natd_payload) (private_responder_init_t *this, message_t *request, notify_message_type_t type, host_t *host);
|
||||
|
||||
/**
|
||||
* Builds the NAT-T Notify(NAT_DETECTION_SOURCE_IP) and
|
||||
* Notify(NAT_DETECTION_DESTINATION_IP) payloads for this state.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param request message_t object to add the Notify payloads
|
||||
*/
|
||||
void (*build_natd_payloads) (private_responder_init_t *this, message_t *request);
|
||||
|
||||
/**
|
||||
* Sends a IKE_SA_INIT reply containing a notify payload.
|
||||
*
|
||||
@@ -185,7 +236,13 @@ static status_t process_message(private_responder_init_t *this, message_t *messa
|
||||
/* TODO: inform requestor */
|
||||
return DESTROY_ME;
|
||||
}
|
||||
this->ike_sa->set_connection(this->ike_sa,connection);
|
||||
this->ike_sa->set_connection(this->ike_sa, connection);
|
||||
status = this->ike_sa->update_connection_hosts(this->ike_sa,
|
||||
destination, source);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
/* parse incoming message */
|
||||
status = message->parse_body(message, NULL, NULL);
|
||||
@@ -204,7 +261,31 @@ static status_t process_message(private_responder_init_t *this, message_t *messa
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
payloads = message->get_payload_iterator(message);
|
||||
/*
|
||||
* Precompute NAT-D hashes.
|
||||
* Even though there SHOULD only be a single payload of Notify type
|
||||
* NAT_DETECTION_DESTINATION_IP we precompute both hashes.
|
||||
*/
|
||||
this->natd_hash_i = this->ike_sa->generate_natd_hash(this->ike_sa,
|
||||
message->get_initiator_spi(message),
|
||||
message->get_responder_spi(message),
|
||||
message->get_source(message));
|
||||
this->natd_hash_i_matched = FALSE;
|
||||
this->natd_seen_i = 0;
|
||||
this->natd_hash_r = this->ike_sa->generate_natd_hash(this->ike_sa,
|
||||
message->get_initiator_spi(message),
|
||||
message->get_responder_spi(message),
|
||||
message->get_destination(message));
|
||||
this->natd_hash_r_matched = FALSE;
|
||||
this->natd_seen_r = 0;
|
||||
this->ike_sa->set_my_host_behind_nat(this->ike_sa, FALSE);
|
||||
this->ike_sa->set_other_host_behind_nat(this->ike_sa, FALSE);
|
||||
|
||||
/* Iterate over all payloads.
|
||||
*
|
||||
* The message is already checked for the right payload types.
|
||||
*/
|
||||
payloads = message->get_payload_iterator(message);
|
||||
while (payloads->has_next(payloads))
|
||||
{
|
||||
payload_t *payload;
|
||||
@@ -237,6 +318,7 @@ static status_t process_message(private_responder_init_t *this, message_t *messa
|
||||
payloads->destroy(payloads);
|
||||
return status;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
@@ -251,10 +333,39 @@ static status_t process_message(private_responder_init_t *this, message_t *messa
|
||||
/* check if we have all payloads */
|
||||
if (!(sa_request && ke_request && nonce_request))
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain all required payloads. deleting IKE_SA");
|
||||
this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request did not contain all required payloads. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* NAT-D */
|
||||
if ((!this->natd_seen_i && this->natd_seen_r > 0)
|
||||
|| (this->natd_seen_i > 0 && !this->natd_seen_r))
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "IKE_SA_INIT request contained wrong number of NAT-D payloads. Deleting IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
if (this->natd_seen_r > 1)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "Warning: IKE_SA_INIT request contained multiple Notify(NAT_DETECTION_DESTINATION_IP) payloads.");
|
||||
}
|
||||
if (this->natd_seen_i > 0 && !this->natd_hash_i_matched)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "Remote host is behind NAT, using NAT-T.");
|
||||
this->ike_sa->set_other_host_behind_nat(this->ike_sa, TRUE);
|
||||
}
|
||||
if (this->natd_seen_r > 0 && !this->natd_hash_r_matched)
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "Local host is behind NAT, using NAT-T.");
|
||||
this->ike_sa->set_my_host_behind_nat(this->ike_sa, TRUE);
|
||||
charon->event_queue->add_relative(charon->event_queue,
|
||||
(job_t*)send_keepalive_job_create(this->ike_sa->public.get_id((ike_sa_t*)this->ike_sa)),
|
||||
charon->configuration->get_keepalive_interval(charon->configuration));
|
||||
}
|
||||
if (!this->ike_sa->public.is_any_host_behind_nat((ike_sa_t*)this->ike_sa))
|
||||
{
|
||||
this->logger->log(this->logger, AUDIT, "No NAT detected, not using NAT-T.");
|
||||
}
|
||||
|
||||
this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, FALSE, &response);
|
||||
|
||||
status = this->build_sa_payload(this, sa_request, response);
|
||||
@@ -277,7 +388,9 @@ static status_t process_message(private_responder_init_t *this, message_t *messa
|
||||
response->destroy(response);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* build Notify(NAT-D) payloads */
|
||||
this->build_natd_payloads(this, response);
|
||||
|
||||
/* derive all the keys used in the IKE_SA */
|
||||
status = this->ike_sa->build_transforms(this->ike_sa, this->proposal, this->diffie_hellman, this->received_nonce, this->sent_nonce);
|
||||
if (status != SUCCESS)
|
||||
@@ -458,27 +571,95 @@ static status_t build_nonce_payload(private_responder_init_t *this,nonce_payload
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_initiator_init_t.build_natd_payload.
|
||||
*/
|
||||
static void build_natd_payload(private_responder_init_t *this, message_t *request, notify_message_type_t type, host_t *host)
|
||||
{
|
||||
chunk_t hash;
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "Building Notify(NAT-D) payload");
|
||||
notify_payload_t *notify_payload;
|
||||
notify_payload = notify_payload_create();
|
||||
/*notify_payload->set_protocol_id(notify_payload, NULL);*/
|
||||
/*notify_payload->set_spi(notify_payload, NULL);*/
|
||||
notify_payload->set_notify_message_type(notify_payload, type);
|
||||
hash = this->ike_sa->generate_natd_hash(this->ike_sa,
|
||||
request->get_initiator_spi(request),
|
||||
request->get_responder_spi(request),
|
||||
host);
|
||||
notify_payload->set_notification_data(notify_payload, hash);
|
||||
chunk_free(&hash);
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "Add Notify(NAT-D) payload to message");
|
||||
request->add_payload(request, (payload_t *) notify_payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_initiator_init_t.build_natd_payloads.
|
||||
*/
|
||||
static void build_natd_payloads(private_responder_init_t *this, message_t *request)
|
||||
{
|
||||
connection_t *connection;
|
||||
connection = this->ike_sa->get_connection(this->ike_sa);
|
||||
this->build_natd_payload(this, request, NAT_DETECTION_SOURCE_IP,
|
||||
connection->get_my_host(connection));
|
||||
this->build_natd_payload(this, request, NAT_DETECTION_DESTINATION_IP,
|
||||
connection->get_other_host(connection));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_responder_init_t.process_notify_payload.
|
||||
*/
|
||||
static status_t process_notify_payload(private_responder_init_t *this, notify_payload_t *notify_payload)
|
||||
{
|
||||
chunk_t notification_data;
|
||||
notify_message_type_t notify_message_type = notify_payload->get_notify_message_type(notify_payload);
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "process notify type %s",
|
||||
mapping_find(notify_message_type_m, notify_message_type));
|
||||
|
||||
if (notify_payload->get_protocol_id(notify_payload) != PROTO_IKE)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR | LEVEL1, "notify reply not for IKE protocol.");
|
||||
return FAILED;
|
||||
}
|
||||
switch (notify_message_type)
|
||||
{
|
||||
case NAT_DETECTION_DESTINATION_IP:
|
||||
{
|
||||
this->natd_seen_r++;
|
||||
if (this->natd_hash_r_matched)
|
||||
return SUCCESS;
|
||||
|
||||
notification_data = notify_payload->get_notification_data(notify_payload);
|
||||
if (chunk_equals(notification_data, this->natd_hash_r))
|
||||
{
|
||||
this->natd_hash_r_matched = TRUE;
|
||||
this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash match");
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash mismatch");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
case NAT_DETECTION_SOURCE_IP:
|
||||
{
|
||||
this->natd_seen_i++;
|
||||
if (this->natd_hash_i_matched)
|
||||
return SUCCESS;
|
||||
|
||||
notification_data = notify_payload->get_notification_data(notify_payload);
|
||||
if (chunk_equals(notification_data, this->natd_hash_i))
|
||||
{
|
||||
this->natd_hash_i_matched = TRUE;
|
||||
this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash match");
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL3, "NAT-D hash mismatch");
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
default:
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL, "IKE_SA_INIT request contained a notify (%d), ignored.",
|
||||
notify_message_type);
|
||||
this->logger->log(this->logger, CONTROL, "IKE_SA_INIT request contained a notify (%d), ignored.",
|
||||
notify_message_type);
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -501,8 +682,12 @@ static void destroy(private_responder_init_t *this)
|
||||
|
||||
this->logger->log(this->logger, CONTROL | LEVEL2, "destroy nonces");
|
||||
chunk_free(&(this->sent_nonce));
|
||||
this->logger->log(this->logger, CONTROL | LEVEL2, "destroy received nonce");
|
||||
chunk_free(&(this->received_nonce));
|
||||
|
||||
chunk_free(&(this->natd_hash_i));
|
||||
chunk_free(&(this->natd_hash_r));
|
||||
|
||||
if (this->diffie_hellman != NULL)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL | LEVEL2, "destroy diffie_hellman_t hellman object");
|
||||
@@ -521,7 +706,10 @@ static void destroy(private_responder_init_t *this)
|
||||
*/
|
||||
static void destroy_after_state_change (private_responder_init_t *this)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL | LEVEL1, "going to destroy responder_init_t state object");
|
||||
this->logger->log(this->logger, CONTROL | LEVEL1, "Going to destroy responder_init_t state object");
|
||||
|
||||
chunk_free(&(this->natd_hash_i));
|
||||
chunk_free(&(this->natd_hash_r));
|
||||
|
||||
/* destroy diffie hellman object */
|
||||
if (this->diffie_hellman != NULL)
|
||||
@@ -556,6 +744,8 @@ responder_init_t *responder_init_create(protected_ike_sa_t *ike_sa)
|
||||
this->build_nonce_payload = build_nonce_payload;
|
||||
this->destroy_after_state_change = destroy_after_state_change;
|
||||
this->process_notify_payload = process_notify_payload;
|
||||
this->build_natd_payload = build_natd_payload;
|
||||
this->build_natd_payloads = build_natd_payloads;
|
||||
|
||||
/* private data */
|
||||
this->ike_sa = ike_sa;
|
||||
@@ -565,6 +755,12 @@ responder_init_t *responder_init_create(protected_ike_sa_t *ike_sa)
|
||||
this->dh_group_number = MODP_NONE;
|
||||
this->diffie_hellman = NULL;
|
||||
this->proposal = NULL;
|
||||
this->natd_hash_i = CHUNK_INITIALIZER;
|
||||
this->natd_hash_i_matched = FALSE;
|
||||
this->natd_seen_i = 0;
|
||||
this->natd_hash_r = CHUNK_INITIALIZER;
|
||||
this->natd_hash_r_matched = FALSE;
|
||||
this->natd_seen_r = 0;
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
|
||||
@@ -38,3 +38,4 @@ mapping_t ike_sa_state_m[] = {
|
||||
{DELETE_CHILD_SA_REQUESTED, "DELETE_CHILD_SA_REQUESTED"},
|
||||
{MAPPING_END, NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -14,13 +14,13 @@ hasher_test.h sender_test.c certificate_test.c job_queue_test.h scheduler_test.h
|
||||
rsa_test.c sender_test.h generator_test.c aes_cbc_crypter_test.c certificate_test.h prf_plus_test.c \
|
||||
rsa_test.h generator_test.h aes_cbc_crypter_test.h send_queue_test.c
|
||||
|
||||
testing_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lgmp -lpthread \
|
||||
testing_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lgmp -lpthread -lm \
|
||||
$(top_srcdir)/src/charon/connection.o $(top_srcdir)/src/charon/local_connection_store.o $(top_srcdir)/src/charon/policy.o \
|
||||
$(top_srcdir)/src/charon/local_policy_store.o $(top_srcdir)/src/charon/local_credential_store.o $(top_srcdir)/src/charon/traffic_selector.o \
|
||||
$(top_srcdir)/src/charon/proposal.o $(top_srcdir)/src/charon/configuration.o $(top_srcdir)/src/charon/state.o $(top_srcdir)/src/charon/ike_sa_init_requested.o \
|
||||
$(top_srcdir)/src/charon/ike_sa_init_responded.o $(top_srcdir)/src/charon/ike_sa_established.o $(top_srcdir)/src/charon/responder_init.o \
|
||||
$(top_srcdir)/src/charon/initiator_init.o $(top_srcdir)/src/charon/ike_auth_requested.o $(top_srcdir)/src/charon/delete_ike_sa_requested.o \
|
||||
$(top_srcdir)/src/charon/delete_child_sa_requested.o \
|
||||
$(top_srcdir)/src/charon/delete_child_sa_requested.o $(top_srcdir)/src/charon/create_child_sa_requested.o \
|
||||
$(top_srcdir)/src/charon/child_sa.o $(top_srcdir)/src/charon/ike_sa.o $(top_srcdir)/src/charon/ike_sa_manager.o $(top_srcdir)/src/charon/ike_sa_id.o \
|
||||
$(top_srcdir)/src/charon/authenticator.o $(top_srcdir)/src/charon/encryption_payload.o $(top_srcdir)/src/charon/cert_payload.o \
|
||||
$(top_srcdir)/src/charon/traffic_selector_substructure.o $(top_srcdir)/src/charon/transform_attribute.o $(top_srcdir)/src/charon/configuration_attribute.o \
|
||||
@@ -30,7 +30,7 @@ $(top_srcdir)/src/charon/ke_payload.o $(top_srcdir)/src/charon/unknown_payload.o
|
||||
$(top_srcdir)/src/charon/delete_payload.o $(top_srcdir)/src/charon/sa_payload.o $(top_srcdir)/src/charon/certreq_payload.o $(top_srcdir)/src/charon/vendor_id_payload.o \
|
||||
$(top_srcdir)/src/charon/proposal_substructure.o $(top_srcdir)/src/charon/payload.o $(top_srcdir)/src/charon/message.o $(top_srcdir)/src/charon/generator.o \
|
||||
$(top_srcdir)/src/charon/parser.o $(top_srcdir)/src/charon/packet.o $(top_srcdir)/src/charon/socket.o $(top_srcdir)/src/charon/job.o \
|
||||
$(top_srcdir)/src/charon/delete_child_sa_job.o $(top_srcdir)/src/charon/rekey_child_sa_job.o $(top_srcdir)/src/charon/create_child_sa_requested.o \
|
||||
$(top_srcdir)/src/charon/delete_child_sa_job.o $(top_srcdir)/src/charon/rekey_child_sa_job.o $(top_srcdir)/src/charon/send_keepalive_job.o $(top_srcdir)/src/charon/send_dpd_job.o \
|
||||
$(top_srcdir)/src/charon/delete_established_ike_sa_job.o $(top_srcdir)/src/charon/incoming_packet_job.o $(top_srcdir)/src/charon/delete_half_open_ike_sa_job.o \
|
||||
$(top_srcdir)/src/charon/retransmit_request_job.o $(top_srcdir)/src/charon/initiate_ike_sa_job.o $(top_srcdir)/src/charon/job_queue.o $(top_srcdir)/src/charon/event_queue.o \
|
||||
$(top_srcdir)/src/charon/send_queue.o $(top_srcdir)/src/charon/kernel_interface.o $(top_srcdir)/src/charon/thread_pool.o $(top_srcdir)/src/charon/scheduler.o \
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -34,6 +35,7 @@ void test_child_sa(protected_tester_t *tester)
|
||||
{
|
||||
proposal_t *proposal1, *proposal2;
|
||||
linked_list_t *list;
|
||||
connection_t *connection;
|
||||
host_t *local_me, *remote_me;
|
||||
host_t *local_other, *remote_other;
|
||||
child_sa_t *local_sa, *remote_sa;
|
||||
@@ -49,8 +51,8 @@ void test_child_sa(protected_tester_t *tester)
|
||||
remote_me = host_create(AF_INET, "192.168.0.3", 0);
|
||||
remote_other = host_create(AF_INET, "192.168.0.4", 0);
|
||||
|
||||
local_sa = child_sa_create(0, local_me, local_other, 5, 10);
|
||||
remote_sa = child_sa_create(0, remote_me, remote_other, 5, 10);
|
||||
local_sa = child_sa_create(0, local_me, local_other, 5, 10, FALSE);
|
||||
remote_sa = child_sa_create(0, remote_me, remote_other, 5, 10, FALSE);
|
||||
|
||||
proposal1 = proposal_create(PROTO_ESP);
|
||||
proposal1->add_algorithm(proposal1, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
|
||||
|
||||
@@ -710,7 +710,7 @@ void test_generator_with_notify_payload(protected_tester_t *tester)
|
||||
|
||||
notify_payload->set_protocol_id(notify_payload,255);
|
||||
notify_payload->set_notify_message_type(notify_payload,63333); /* Hex F765 */
|
||||
notify_payload->set_spi(notify_payload, 0x3132333435ll);
|
||||
notify_payload->set_spi(notify_payload, 0x31323334);
|
||||
notify_payload->set_notification_data(notify_payload,notification_data);
|
||||
|
||||
generator->generate_payload(generator,(payload_t *)notify_payload);
|
||||
@@ -719,11 +719,10 @@ void test_generator_with_notify_payload(protected_tester_t *tester)
|
||||
|
||||
u_int8_t expected_generation[] = {
|
||||
/* payload header */
|
||||
0x00,0x00,0x00,0x12,
|
||||
0xFF,0x05,0xF7,0x65,
|
||||
0x00,0x00,0x00,0x11,
|
||||
0xFF,0x04,0xF7,0x65,
|
||||
/* spi */
|
||||
0x31,0x32,0x33,0x34,
|
||||
0x35,
|
||||
/* notification data */
|
||||
0x36,0x37,0x38,0x39,
|
||||
0x30,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -20,8 +21,7 @@
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#include "kernel_interface_test.h"
|
||||
|
||||
#include <daemon.h>
|
||||
@@ -30,18 +30,19 @@
|
||||
#include <utils/host.h>
|
||||
|
||||
|
||||
/*
|
||||
* described in Header-File
|
||||
/**
|
||||
* @brief private method to test kernel_interface with optional NAT-T configuration data
|
||||
*/
|
||||
void test_kernel_interface(protected_tester_t *tester)
|
||||
void private_test_kernel_interface(protected_tester_t *tester, natt_conf_t *natt)
|
||||
{
|
||||
kernel_interface_t *kernel_interface;
|
||||
u_int32_t spi;
|
||||
host_t *me, *other, *left, *right;
|
||||
status_t status;
|
||||
prf_plus_t *prf_plus;
|
||||
prf_t *prf;
|
||||
prf_t *prf;
|
||||
u_int8_t key_bytes[] = {
|
||||
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
|
||||
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08
|
||||
};
|
||||
chunk_t key = chunk_from_buf(key_bytes);
|
||||
@@ -50,41 +51,125 @@ void test_kernel_interface(protected_tester_t *tester)
|
||||
|
||||
prf = prf_create(PRF_HMAC_MD5);
|
||||
prf->set_key(prf, key);
|
||||
prf_plus = prf_plus_create(prf, key);
|
||||
|
||||
prf_plus = prf_plus_create(prf, key);
|
||||
|
||||
|
||||
kernel_interface = kernel_interface_create();
|
||||
|
||||
me = host_create(AF_INET, "192.168.0.2", 0);
|
||||
other = host_create(AF_INET, "192.168.0.3", 0);
|
||||
|
||||
|
||||
status = kernel_interface->get_spi(kernel_interface, me, other, PROTO_ESP, 1234, &spi);
|
||||
tester->assert_true(tester, status == SUCCESS, "spi get");
|
||||
|
||||
status = kernel_interface->add_sa(kernel_interface, me, other, spi, PROTO_ESP, 1234, 0, 0, &enc_alg, &int_alg, prf_plus, TRUE);
|
||||
|
||||
status = kernel_interface->add_sa(kernel_interface, me, other, spi, PROTO_ESP, 1234, 5, 10, &enc_alg, &int_alg, prf_plus, natt, TRUE);
|
||||
tester->assert_true(tester, status == SUCCESS, "add sa");
|
||||
|
||||
|
||||
left = host_create(AF_INET, "10.1.0.0", 0);
|
||||
right = host_create(AF_INET, "10.2.0.0", 0);
|
||||
|
||||
status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 16, 16, XFRM_POLICY_OUT, 0, PROTO_ESP, 1234);
|
||||
tester->assert_true(tester, status == SUCCESS, "add policy");
|
||||
|
||||
status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 24, 24, XFRM_POLICY_OUT, 0, PROTO_ESP, 1234);
|
||||
tester->assert_true(tester, status == SUCCESS, "add policy OUT");
|
||||
status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 24, 24, XFRM_POLICY_IN, 0, PROTO_ESP, 1234);
|
||||
tester->assert_true(tester, status == SUCCESS, "add policy IN");
|
||||
status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 24, 24, XFRM_POLICY_FWD, 0, PROTO_ESP, 1234);
|
||||
tester->assert_true(tester, status == SUCCESS, "add policy FWD");
|
||||
|
||||
|
||||
kernel_interface->del_sa(kernel_interface, other, spi, PROTO_ESP);
|
||||
|
||||
sleep(10);
|
||||
|
||||
status = kernel_interface->del_policy(kernel_interface, me, other, left, right, 16, 16, XFRM_POLICY_OUT, 0);
|
||||
tester->assert_true(tester, status == SUCCESS, "del policy");
|
||||
|
||||
status = kernel_interface->del_sa(kernel_interface, other, spi, PROTO_ESP);
|
||||
tester->assert_true(tester, status == SUCCESS, "del sa");
|
||||
|
||||
me->destroy(me);
|
||||
other->destroy(other);
|
||||
left->destroy(left);
|
||||
right->destroy(right);
|
||||
|
||||
kernel_interface->destroy(kernel_interface);
|
||||
}
|
||||
|
||||
/*
|
||||
* described in Header-File
|
||||
*/
|
||||
void test_kernel_interface(protected_tester_t *tester)
|
||||
{
|
||||
private_test_kernel_interface(tester, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* described in Header-File
|
||||
*/
|
||||
void test_kernel_interface_with_nat(protected_tester_t *tester)
|
||||
{
|
||||
natt_conf_t natt;
|
||||
natt.sport = 4500;
|
||||
natt.dport = 9876;
|
||||
|
||||
private_test_kernel_interface(tester, &natt);
|
||||
}
|
||||
|
||||
void test_kernel_interface_update_hosts(protected_tester_t *tester)
|
||||
{
|
||||
kernel_interface_t *kernel_interface;
|
||||
u_int32_t spi;
|
||||
host_t *me, *other, *new_me, *new_other, *left, *right;
|
||||
status_t status;
|
||||
prf_plus_t *prf_plus;
|
||||
prf_t *prf;
|
||||
u_int8_t key_bytes[] = {
|
||||
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
|
||||
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08
|
||||
};
|
||||
chunk_t key = chunk_from_buf(key_bytes);
|
||||
algorithm_t int_alg = {AUTH_HMAC_MD5_96, 0};
|
||||
algorithm_t enc_alg = {ENCR_AES_CBC, 128};
|
||||
|
||||
prf = prf_create(PRF_HMAC_MD5);
|
||||
prf->set_key(prf, key);
|
||||
prf_plus = prf_plus_create(prf, key);
|
||||
|
||||
kernel_interface = kernel_interface_create();
|
||||
|
||||
me = host_create(AF_INET, "192.168.0.2", 0);
|
||||
other = host_create(AF_INET, "192.168.0.3", 0);
|
||||
|
||||
natt_conf_t natt;
|
||||
natt.sport = 4500;
|
||||
natt.dport = 9876;
|
||||
|
||||
status = kernel_interface->get_spi(kernel_interface, me, other, PROTO_ESP, 1234, &spi);
|
||||
tester->assert_true(tester, status == SUCCESS, "spi get");
|
||||
|
||||
status = kernel_interface->add_sa(kernel_interface, me, other, spi, PROTO_ESP, 1234, 5, 10, &enc_alg, &int_alg, prf_plus, &natt, TRUE);
|
||||
tester->assert_true(tester, status == SUCCESS, "add sa");
|
||||
|
||||
left = host_create(AF_INET, "10.1.0.0", 0);
|
||||
right = host_create(AF_INET, "10.2.0.0", 0);
|
||||
|
||||
status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 16, 16, XFRM_POLICY_OUT, 0, PROTO_ESP, 1234);
|
||||
tester->assert_true(tester, status == SUCCESS, "add policy OUT");
|
||||
status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 16, 16, XFRM_POLICY_IN, 0, PROTO_ESP, 1234);
|
||||
tester->assert_true(tester, status == SUCCESS, "add policy IN");
|
||||
status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 16, 16, XFRM_POLICY_FWD, 0, PROTO_ESP, 1234);
|
||||
tester->assert_true(tester, status == SUCCESS, "add policy FWD");
|
||||
|
||||
new_me = host_create(AF_INET, "192.168.1.12", 4500);
|
||||
new_other = host_create(AF_INET, "192.168.1.13", 6543);
|
||||
|
||||
status = kernel_interface->update_sa_hosts(kernel_interface, me, other, new_me, new_other, me->get_differences(me, new_me), other->get_differences(other, new_other), spi, PROTO_ESP);
|
||||
tester->assert_true(tester, status == SUCCESS, "update hosts on sa");
|
||||
|
||||
status = kernel_interface->del_policy(kernel_interface, me, other, left, right, 16, 16, XFRM_POLICY_OUT, 0);
|
||||
tester->assert_true(tester, status == SUCCESS, "del policy");
|
||||
|
||||
status = kernel_interface->del_sa(kernel_interface, other, spi, PROTO_ESP);
|
||||
tester->assert_true(tester, status == SUCCESS, "del sa");
|
||||
|
||||
me->destroy(me);
|
||||
other->destroy(other);
|
||||
new_me->destroy(new_me);
|
||||
new_other->destroy(new_other);
|
||||
left->destroy(left);
|
||||
right->destroy(right);
|
||||
|
||||
sleep(15);
|
||||
|
||||
kernel_interface->destroy(kernel_interface);
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -34,5 +35,23 @@
|
||||
*/
|
||||
void test_kernel_interface(protected_tester_t *tester);
|
||||
|
||||
/**
|
||||
* @brief Test function used to test the kernel_interface functionality. Incldes NAT-T configuration.
|
||||
*
|
||||
* @param tester associated tester object
|
||||
*
|
||||
* @ingroup testcases
|
||||
*/
|
||||
void test_kernel_interface_with_nat(protected_tester_t *tester);
|
||||
|
||||
/**
|
||||
* @brief Test function used to test the hosts update functionality in kernel_interface_t.
|
||||
*
|
||||
* @param tester associated tester object
|
||||
*
|
||||
* @ingroup testcases
|
||||
*/
|
||||
void test_kernel_interface_update_hosts(protected_tester_t *tester);
|
||||
|
||||
|
||||
#endif /*KERNEL_INTERFACE_TEST_H_*/
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -35,7 +36,7 @@ void test_socket(protected_tester_t *tester)
|
||||
{
|
||||
int packet_count = 10;
|
||||
int current;
|
||||
socket_t *skt = socket_create(500);
|
||||
socket_t *skt = socket_create(500, 4500);
|
||||
packet_t *pkt = packet_create();
|
||||
char test_data[] = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, /* spi */
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -126,7 +127,9 @@ test_t connection_test = {test_connection, "connection_t test"};
|
||||
test_t policy_test = {test_policy, "policy_t test"};
|
||||
test_t proposal_test = {test_proposal, "proposal_t test"};
|
||||
test_t rsa_test = {test_rsa, "RSA private/public key test"};
|
||||
test_t kernel_interface_test = {test_kernel_interface, "Kernel Interface"};
|
||||
test_t kernel_interface_test1 = {test_kernel_interface, "Kernel Interface"};
|
||||
test_t kernel_interface_test2 = {test_kernel_interface_with_nat, "Kernel Interface: NAT"};
|
||||
test_t kernel_interface_test3 = {test_kernel_interface_update_hosts, "Kernel Interface: Hosts update"};
|
||||
test_t child_sa_test = {test_child_sa, "Child SA"};
|
||||
test_t certificate_test = {test_certificate, "X509 Certificate"};
|
||||
test_t leak_detective_test = {test_leak_detective, "LEAK detective"};
|
||||
@@ -159,7 +162,7 @@ daemon_t *daemon_create()
|
||||
/* assign methods */
|
||||
charon->kill = daemon_kill;
|
||||
|
||||
//charon->socket = socket_create(500);
|
||||
charon->socket = socket_create(500, 4500);
|
||||
charon->ike_sa_manager = ike_sa_manager_create();
|
||||
charon->job_queue = job_queue_create();
|
||||
charon->event_queue = event_queue_create();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
* Copyright (C) 2003 Herbert Xu.
|
||||
@@ -26,6 +27,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
@@ -45,69 +47,12 @@
|
||||
|
||||
#define SPD_PRIORITY 1024
|
||||
|
||||
#define XFRM_DATA_LENGTH 1024
|
||||
#define BUFFER_SIZE 1024
|
||||
|
||||
|
||||
typedef struct xfrm_data_t xfrm_data_t;
|
||||
|
||||
/**
|
||||
* Lenght/Type/data struct for userdata in xfrm
|
||||
* We dont use the "I-don't-know-where-they-come-from"-structs
|
||||
* used in the kernel.
|
||||
*/
|
||||
struct xfrm_data_t {
|
||||
/**
|
||||
* length of the data
|
||||
*/
|
||||
u_int16_t length;
|
||||
|
||||
/**
|
||||
* type of data
|
||||
*/
|
||||
u_int16_t type;
|
||||
|
||||
/**
|
||||
* and the data itself, for different purposes
|
||||
*/
|
||||
union {
|
||||
/** algorithm */
|
||||
struct xfrm_algo algo;
|
||||
/** policy tmpl */
|
||||
struct xfrm_user_tmpl tmpl;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
typedef struct netlink_message_t netlink_message_t;
|
||||
|
||||
/**
|
||||
* Representation of ANY netlink message used
|
||||
*/
|
||||
struct netlink_message_t {
|
||||
|
||||
/**
|
||||
* header of the netlink message
|
||||
*/
|
||||
struct nlmsghdr hdr;
|
||||
|
||||
union {
|
||||
/** error message */
|
||||
struct nlmsgerr e;
|
||||
/** message for spi allocation */
|
||||
struct xfrm_userspi_info spi;
|
||||
/** message for SA manipulation */
|
||||
struct xfrm_usersa_id sa_id;
|
||||
/** message for SA installation */
|
||||
struct xfrm_usersa_info sa;
|
||||
/** message for policy manipulation */
|
||||
struct xfrm_userpolicy_id policy_id;
|
||||
/** message for policy installation */
|
||||
struct xfrm_userpolicy_info policy;
|
||||
/** expire message sent from kernel */
|
||||
struct xfrm_user_expire expire;
|
||||
};
|
||||
u_int8_t data[XFRM_DATA_LENGTH];
|
||||
};
|
||||
/* returns a pointer to the first rtattr following the nlmsghdr *nlh and the 'usual' netlink data x like 'struct xfrm_usersa_info' */
|
||||
#define XFRM_RTA(nlh, x) ((struct rtattr*)(NLMSG_DATA(nlh) + NLMSG_ALIGN(sizeof(x))))
|
||||
/* returns the total size of attached rta data (after 'usual' netlink data x like 'struct xfrm_usersa_info') */
|
||||
#define XFRM_PAYLOAD(nlh, x) NLMSG_PAYLOAD(nlh, sizeof(x))
|
||||
|
||||
typedef struct kernel_algorithm_t kernel_algorithm_t;
|
||||
|
||||
@@ -249,7 +194,7 @@ struct private_kernel_interface_t {
|
||||
/**
|
||||
* Sends a netlink_message_t down to the kernel and wait for reply.
|
||||
*/
|
||||
status_t (*send_message) (private_kernel_interface_t *this, netlink_message_t *request, netlink_message_t **response);
|
||||
status_t (*send_message) (private_kernel_interface_t *this, struct nlmsghdr *request, struct nlmsghdr **response);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -260,48 +205,53 @@ static status_t get_spi(private_kernel_interface_t *this,
|
||||
protocol_id_t protocol, u_int32_t reqid,
|
||||
u_int32_t *spi)
|
||||
{
|
||||
netlink_message_t request, *response;
|
||||
unsigned char request[BUFFER_SIZE];
|
||||
struct nlmsghdr *response;
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
status_t status = SUCCESS;
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "Getting SPI for reqid %d", reqid);
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "getting spi");
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.spi)));
|
||||
request.hdr.nlmsg_flags = NLM_F_REQUEST;
|
||||
request.hdr.nlmsg_type = XFRM_MSG_ALLOCSPI;
|
||||
request.spi.info.saddr = src->get_xfrm_addr(src);
|
||||
request.spi.info.id.daddr = dest->get_xfrm_addr(dest);
|
||||
request.spi.info.mode = TRUE; /* tunnel mode */
|
||||
request.spi.info.reqid = reqid;
|
||||
request.spi.info.id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
|
||||
request.spi.info.family = PF_INET;
|
||||
request.spi.min = 0xc0000000;
|
||||
request.spi.max = 0xcFFFFFFF;
|
||||
struct nlmsghdr *hdr = (struct nlmsghdr*)request;
|
||||
hdr->nlmsg_flags = NLM_F_REQUEST;
|
||||
hdr->nlmsg_type = XFRM_MSG_ALLOCSPI;
|
||||
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userspi_info));
|
||||
|
||||
struct xfrm_userspi_info *userspi = (struct xfrm_userspi_info*)NLMSG_DATA(hdr);
|
||||
userspi->info.saddr = src->get_xfrm_addr(src);
|
||||
userspi->info.id.daddr = dest->get_xfrm_addr(dest);
|
||||
userspi->info.id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
|
||||
userspi->info.mode = TRUE; /* tunnel mode */
|
||||
userspi->info.reqid = reqid;
|
||||
userspi->info.family = src->get_family(src);
|
||||
userspi->min = 0xc0000000;
|
||||
userspi->max = 0xcFFFFFFF;
|
||||
|
||||
if (this->send_message(this, &request, &response) != SUCCESS)
|
||||
if (this->send_message(this, hdr, &response) != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink communication failed");
|
||||
return FAILED;
|
||||
}
|
||||
else if (response->hdr.nlmsg_type == NLMSG_ERROR)
|
||||
else if (response->nlmsg_type == NLMSG_ERROR)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_ALLOCSPI got an error: %s",
|
||||
strerror(-response->e.error));
|
||||
strerror(-((struct nlmsgerr*)NLMSG_DATA(response))->error));
|
||||
status = FAILED;
|
||||
}
|
||||
else if (response->hdr.nlmsg_type != XFRM_MSG_NEWSA)
|
||||
else if (response->nlmsg_type != XFRM_MSG_NEWSA)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_ALLOCSPI got a unknown reply");
|
||||
status = FAILED;
|
||||
}
|
||||
else if (response->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(response->sa)))
|
||||
else if (response->nlmsg_len < NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)))
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_ALLOCSPI got an invalid reply");
|
||||
status = FAILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
*spi = response->sa.id.spi;
|
||||
*spi = ((struct xfrm_usersa_info*)NLMSG_DATA(response))->id.spi;
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "SPI is 0x%x", *spi);
|
||||
}
|
||||
free(response);
|
||||
@@ -312,59 +262,56 @@ static status_t get_spi(private_kernel_interface_t *this,
|
||||
/**
|
||||
* Implementation of kernel_interface_t.add_sa.
|
||||
*/
|
||||
static status_t add_sa( private_kernel_interface_t *this,
|
||||
host_t *me,
|
||||
host_t *other,
|
||||
u_int32_t spi,
|
||||
protocol_id_t protocol,
|
||||
u_int32_t reqid,
|
||||
u_int64_t expire_soft,
|
||||
u_int64_t expire_hard,
|
||||
algorithm_t *enc_alg,
|
||||
algorithm_t *int_alg,
|
||||
prf_plus_t *prf_plus,
|
||||
bool replace)
|
||||
static status_t add_sa(private_kernel_interface_t *this,
|
||||
host_t *me, host_t *other,
|
||||
u_int32_t spi, protocol_id_t protocol,
|
||||
u_int32_t reqid,
|
||||
u_int64_t expire_soft, u_int64_t expire_hard,
|
||||
algorithm_t *enc_alg, algorithm_t *int_alg,
|
||||
prf_plus_t *prf_plus, natt_conf_t *natt,
|
||||
bool replace)
|
||||
{
|
||||
netlink_message_t request, *response;
|
||||
status_t status = SUCCESS;
|
||||
int key_size;
|
||||
unsigned char request[BUFFER_SIZE];
|
||||
struct nlmsghdr *response;
|
||||
char *alg_name;
|
||||
size_t key_size;
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
status_t status = SUCCESS;
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "Adding %s SA with SPI 0x%x, reqid %d to kernel",
|
||||
mapping_find(protocol_id_m, protocol), htonl(spi), reqid);
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "adding SA");
|
||||
|
||||
struct nlmsghdr *hdr = (struct nlmsghdr*)request;
|
||||
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
hdr->nlmsg_type = replace ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA;
|
||||
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
|
||||
|
||||
request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
request.hdr.nlmsg_type = replace ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA;
|
||||
struct xfrm_usersa_info *sa = (struct xfrm_usersa_info*)NLMSG_DATA(hdr);
|
||||
sa->saddr = me->get_xfrm_addr(me);
|
||||
sa->id.daddr = other->get_xfrm_addr(other);
|
||||
|
||||
request.sa.saddr = me->get_xfrm_addr(me);
|
||||
request.sa.id.daddr = other->get_xfrm_addr(other);
|
||||
|
||||
request.sa.id.spi = spi;
|
||||
request.sa.id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
|
||||
request.sa.family = me->get_family(me);
|
||||
request.sa.mode = TRUE; /* tunnel mode */
|
||||
request.sa.replay_window = 32;
|
||||
request.sa.reqid = reqid;
|
||||
sa->id.spi = spi;
|
||||
sa->id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
|
||||
sa->family = me->get_family(me);
|
||||
sa->mode = TRUE; /* tunnel mode */
|
||||
sa->replay_window = 32;
|
||||
sa->reqid = reqid;
|
||||
/* we currently do not expire SAs by volume/packet count */
|
||||
request.sa.lft.soft_byte_limit = XFRM_INF;
|
||||
request.sa.lft.hard_byte_limit = XFRM_INF;
|
||||
request.sa.lft.soft_packet_limit = XFRM_INF;
|
||||
request.sa.lft.hard_packet_limit = XFRM_INF;
|
||||
sa->lft.soft_byte_limit = XFRM_INF;
|
||||
sa->lft.hard_byte_limit = XFRM_INF;
|
||||
sa->lft.soft_packet_limit = XFRM_INF;
|
||||
sa->lft.hard_packet_limit = XFRM_INF;
|
||||
/* we use lifetimes since added, not since used */
|
||||
request.sa.lft.soft_add_expires_seconds = expire_soft;
|
||||
request.sa.lft.hard_add_expires_seconds = expire_hard;
|
||||
request.sa.lft.soft_use_expires_seconds = 0;
|
||||
request.sa.lft.hard_use_expires_seconds = 0;
|
||||
|
||||
request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.sa)));
|
||||
sa->lft.soft_add_expires_seconds = expire_soft;
|
||||
sa->lft.hard_add_expires_seconds = expire_hard;
|
||||
sa->lft.soft_use_expires_seconds = 0;
|
||||
sa->lft.hard_use_expires_seconds = 0;
|
||||
|
||||
if (enc_alg->algorithm != ENCR_UNDEFINED)
|
||||
{
|
||||
xfrm_data_t *data = (xfrm_data_t*)(((u_int8_t*)&request) + request.hdr.nlmsg_len);
|
||||
struct rtattr *rthdr = (struct rtattr*)(request + hdr->nlmsg_len);
|
||||
|
||||
data->type = XFRMA_ALG_CRYPT;
|
||||
rthdr->rta_type = XFRMA_ALG_CRYPT;
|
||||
alg_name = lookup_algorithm(encryption_algs, enc_alg, &key_size);
|
||||
if (alg_name == NULL)
|
||||
{
|
||||
@@ -374,22 +321,25 @@ static status_t add_sa( private_kernel_interface_t *this,
|
||||
}
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, " using encryption algorithm %s with key size %d",
|
||||
mapping_find(encryption_algorithm_m, enc_alg->algorithm), key_size);
|
||||
data->length = 4 + sizeof(data->algo) + key_size;
|
||||
data->algo.alg_key_len = key_size;
|
||||
request.hdr.nlmsg_len += data->length;
|
||||
if (request.hdr.nlmsg_len > sizeof(request))
|
||||
|
||||
rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + key_size);
|
||||
hdr->nlmsg_len += rthdr->rta_len;
|
||||
if (hdr->nlmsg_len > sizeof(request))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
strcpy(data->algo.alg_name, alg_name);
|
||||
prf_plus->get_bytes(prf_plus, key_size / 8, data->algo.alg_key);
|
||||
|
||||
struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr);
|
||||
algo->alg_key_len = key_size;
|
||||
strcpy(algo->alg_name, alg_name);
|
||||
prf_plus->get_bytes(prf_plus, key_size / 8, algo->alg_key);
|
||||
}
|
||||
|
||||
if (int_alg->algorithm != AUTH_UNDEFINED)
|
||||
{
|
||||
xfrm_data_t *data = (xfrm_data_t*)(((u_int8_t*)&request) + request.hdr.nlmsg_len);
|
||||
struct rtattr *rthdr = (struct rtattr*)(request + hdr->nlmsg_len);
|
||||
|
||||
data->type = XFRMA_ALG_AUTH;
|
||||
rthdr->rta_type = XFRMA_ALG_AUTH;
|
||||
alg_name = lookup_algorithm(integrity_algs, int_alg, &key_size);
|
||||
if (alg_name == NULL)
|
||||
{
|
||||
@@ -399,33 +349,68 @@ static status_t add_sa( private_kernel_interface_t *this,
|
||||
}
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, " using integrity algorithm %s with key size %d",
|
||||
mapping_find(integrity_algorithm_m, int_alg->algorithm), key_size);
|
||||
data->length = 4 + sizeof(data->algo) + key_size;
|
||||
data->algo.alg_key_len = key_size;
|
||||
request.hdr.nlmsg_len += data->length;
|
||||
if (request.hdr.nlmsg_len > sizeof(request))
|
||||
|
||||
rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + key_size);
|
||||
hdr->nlmsg_len += rthdr->rta_len;
|
||||
if (hdr->nlmsg_len > sizeof(request))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
strcpy(data->algo.alg_name, alg_name);
|
||||
prf_plus->get_bytes(prf_plus, key_size / 8, data->algo.alg_key);
|
||||
|
||||
struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr);
|
||||
algo->alg_key_len = key_size;
|
||||
strcpy(algo->alg_name, alg_name);
|
||||
prf_plus->get_bytes(prf_plus, key_size / 8, algo->alg_key);
|
||||
}
|
||||
|
||||
/* TODO: add IPComp here*/
|
||||
/* TODO: add IPComp here */
|
||||
|
||||
if (this->send_message(this, &request, &response) != SUCCESS)
|
||||
if (natt)
|
||||
{
|
||||
struct rtattr *rthdr = (struct rtattr*)(request + hdr->nlmsg_len);
|
||||
|
||||
rthdr->rta_type = XFRMA_ENCAP;
|
||||
rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl));
|
||||
|
||||
hdr->nlmsg_len += rthdr->rta_len;
|
||||
if (hdr->nlmsg_len > sizeof(request))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
struct xfrm_encap_tmpl* encap = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr);
|
||||
/* UDP_ENCAP_ESPINUDP, see /usr/src/linux/include/linux/udp.h
|
||||
* we could probably use 3 here (as pluto does) although the
|
||||
* result is eventually the same. */
|
||||
encap->encap_type = 2;
|
||||
encap->encap_sport = ntohs(natt->sport);
|
||||
encap->encap_dport = ntohs(natt->dport);
|
||||
memset(&encap->encap_oa, 0, sizeof (xfrm_address_t));
|
||||
/* encap_oa could probably be derived from the
|
||||
* traffic selectors [rfc4306, p39]. In the netlink kernel implementation
|
||||
* pluto does the same as we do here but it uses encap_oa in the
|
||||
* pfkey implementation. BUT as /usr/src/linux/net/key/af_key.c indicates
|
||||
* the kernel ignores it anyway
|
||||
* -> does that mean that NAT-T encap doesn't work in transport mode?
|
||||
* No. The reason the kernel ignores NAT-OA is that it recomputes
|
||||
* (or, rather, just ignores) the checksum. If packets pass
|
||||
* the IPSec checks it marks them "checksum ok" so OA isn't needed. */
|
||||
}
|
||||
|
||||
if (this->send_message(this, hdr, &response) != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink communication failed");
|
||||
return FAILED;
|
||||
}
|
||||
else if (response->hdr.nlmsg_type != NLMSG_ERROR)
|
||||
else if (response->nlmsg_type != NLMSG_ERROR)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_NEWSA not acknowledged");
|
||||
status = FAILED;
|
||||
}
|
||||
else if (response->e.error)
|
||||
else if (((struct nlmsgerr*)NLMSG_DATA(response))->error)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_NEWSA received error: %s",
|
||||
strerror(-response->e.error));
|
||||
this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_NEWSA got an error: %s",
|
||||
strerror(-((struct nlmsgerr*)NLMSG_DATA(response))->error));
|
||||
status = FAILED;
|
||||
}
|
||||
|
||||
@@ -433,43 +418,158 @@ static status_t add_sa( private_kernel_interface_t *this,
|
||||
return status;
|
||||
}
|
||||
|
||||
static status_t update_sa_hosts(
|
||||
private_kernel_interface_t *this,
|
||||
host_t *src, host_t *dst,
|
||||
host_t *new_src, host_t *new_dst,
|
||||
int src_changes, int dst_changes,
|
||||
u_int32_t spi, protocol_id_t protocol)
|
||||
{
|
||||
unsigned char request[BUFFER_SIZE];
|
||||
struct nlmsghdr *update, *response;
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
status_t status = SUCCESS;
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "getting SA");
|
||||
|
||||
struct nlmsghdr *hdr = (struct nlmsghdr*)request;
|
||||
hdr->nlmsg_flags = NLM_F_REQUEST ;
|
||||
hdr->nlmsg_type = XFRM_MSG_GETSA;
|
||||
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
|
||||
|
||||
struct xfrm_usersa_id *sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr);
|
||||
sa_id->daddr = dst->get_xfrm_addr(dst);
|
||||
sa_id->spi = spi;
|
||||
sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
|
||||
sa_id->family = dst->get_family(dst);
|
||||
|
||||
if (this->send_message(this, hdr, &update) != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink communication failed");
|
||||
return FAILED;
|
||||
}
|
||||
else if (update->nlmsg_type == NLMSG_ERROR)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_GETSA got an error: %s",
|
||||
strerror(-((struct nlmsgerr*)NLMSG_DATA(update))->error));
|
||||
free(update);
|
||||
return FAILED;
|
||||
}
|
||||
else if (update->nlmsg_type != XFRM_MSG_NEWSA)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_GETSA got a unknown reply");
|
||||
free(update);
|
||||
return FAILED;
|
||||
}
|
||||
else if (update->nlmsg_len < NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)))
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_GETSA got an invalid reply");
|
||||
free(update);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "updating SA");
|
||||
update->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
update->nlmsg_type = XFRM_MSG_UPDSA;
|
||||
|
||||
struct xfrm_usersa_info *sa = (struct xfrm_usersa_info*)NLMSG_DATA(update);
|
||||
if (src_changes & HOST_DIFF_ADDR)
|
||||
{
|
||||
sa->saddr = new_src->get_xfrm_addr(new_src);
|
||||
}
|
||||
|
||||
if (dst_changes & HOST_DIFF_ADDR)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "destination address changed! replacing SA");
|
||||
|
||||
update->nlmsg_type = XFRM_MSG_NEWSA;
|
||||
sa->id.daddr = new_dst->get_xfrm_addr(new_dst);
|
||||
}
|
||||
|
||||
if (src_changes & HOST_DIFF_PORT || dst_changes & HOST_DIFF_PORT)
|
||||
{
|
||||
struct rtattr *rthdr = XFRM_RTA(update, struct xfrm_usersa_info);
|
||||
size_t rtsize = XFRM_PAYLOAD(update, struct xfrm_usersa_info);
|
||||
while (RTA_OK(rthdr, rtsize))
|
||||
{
|
||||
if (rthdr->rta_type == XFRMA_ENCAP)
|
||||
{
|
||||
struct xfrm_encap_tmpl* encap = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr);
|
||||
encap->encap_sport = ntohs(new_src->get_port(new_src));
|
||||
encap->encap_dport = ntohs(new_dst->get_port(new_dst));
|
||||
break;
|
||||
}
|
||||
rthdr = RTA_NEXT(rthdr, rtsize);
|
||||
}
|
||||
}
|
||||
|
||||
if (this->send_message(this, update, &response) != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink communication failed");
|
||||
free(update);
|
||||
return FAILED;
|
||||
}
|
||||
else if (response->nlmsg_type != NLMSG_ERROR)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_XXXSA not acknowledged");
|
||||
status = FAILED;
|
||||
}
|
||||
else if (((struct nlmsgerr*)NLMSG_DATA(response))->error)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_XXXSA got an error: %s",
|
||||
strerror(-((struct nlmsgerr*)NLMSG_DATA(response))->error));
|
||||
status = FAILED;
|
||||
}
|
||||
else if (dst_changes & HOST_DIFF_ADDR)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "deleting old SA");
|
||||
status = this->public.del_sa(&this->public, dst, spi, protocol);
|
||||
}
|
||||
|
||||
free(update);
|
||||
free(response);
|
||||
return status;
|
||||
}
|
||||
|
||||
static status_t del_sa( private_kernel_interface_t *this,
|
||||
host_t *dst,
|
||||
u_int32_t spi,
|
||||
protocol_id_t protocol)
|
||||
{
|
||||
netlink_message_t request, *response;
|
||||
unsigned char request[BUFFER_SIZE];
|
||||
struct nlmsghdr *response;
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
status_t status = SUCCESS;
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "Deleting %s SA with SPI 0x%x from kernel",
|
||||
mapping_find(protocol_id_m, protocol), htonl(spi));
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "deleting SA");
|
||||
|
||||
struct nlmsghdr *hdr = (struct nlmsghdr*)request;
|
||||
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
hdr->nlmsg_type = XFRM_MSG_DELSA;
|
||||
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id));
|
||||
|
||||
struct xfrm_usersa_id *sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr);
|
||||
sa_id->daddr = dst->get_xfrm_addr(dst);
|
||||
sa_id->spi = spi;
|
||||
sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
|
||||
sa_id->family = dst->get_family(dst);
|
||||
|
||||
request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
request.hdr.nlmsg_type = XFRM_MSG_DELSA;
|
||||
|
||||
request.sa_id.daddr = dst->get_xfrm_addr(dst);
|
||||
|
||||
request.sa_id.spi = spi;
|
||||
request.sa_id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
|
||||
request.sa_id.family = dst->get_family(dst);
|
||||
|
||||
request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.sa_id)));
|
||||
|
||||
if (this->send_message(this, &request, &response) != SUCCESS)
|
||||
if (this->send_message(this, hdr, &response) != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink communication failed");
|
||||
return FAILED;
|
||||
}
|
||||
else if (response->hdr.nlmsg_type != NLMSG_ERROR)
|
||||
else if (response->nlmsg_type != NLMSG_ERROR)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_DELSA not acknowledged");
|
||||
status = FAILED;
|
||||
}
|
||||
else if (response->e.error)
|
||||
else if (((struct nlmsgerr*)NLMSG_DATA(response))->error)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1, "netlink request XFRM_MSG_DELSA received error: %s",
|
||||
strerror(-response->e.error));
|
||||
this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_DELSA got an error: %s",
|
||||
strerror(-((struct nlmsgerr*)NLMSG_DATA(response))->error));
|
||||
status = FAILED;
|
||||
}
|
||||
|
||||
@@ -488,71 +588,84 @@ static status_t add_policy(private_kernel_interface_t *this,
|
||||
protocol_id_t protocol,
|
||||
u_int32_t reqid)
|
||||
{
|
||||
netlink_message_t request, *response;
|
||||
status_t status = SUCCESS;
|
||||
xfrm_data_t *data;
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "Adding %s policy with reqid %d to kernel",
|
||||
mapping_find(protocol_id_m, protocol), reqid);
|
||||
unsigned char request[BUFFER_SIZE];
|
||||
struct nlmsghdr *response;
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
status_t status = SUCCESS;
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "adding policy");
|
||||
|
||||
request.policy.sel.sport = htons(src->get_port(src));
|
||||
request.policy.sel.dport = htons(dst->get_port(dst));
|
||||
request.policy.sel.sport_mask = (request.policy.sel.sport) ? ~0 : 0;
|
||||
request.policy.sel.dport_mask = (request.policy.sel.dport) ? ~0 : 0;
|
||||
request.policy.sel.saddr = src->get_xfrm_addr(src);
|
||||
request.policy.sel.daddr = dst->get_xfrm_addr(dst);
|
||||
request.policy.sel.prefixlen_s = src_hostbits;
|
||||
request.policy.sel.prefixlen_d = dst_hostbits;
|
||||
request.policy.sel.proto = upper_proto;
|
||||
request.policy.sel.family = src->get_family(src);
|
||||
struct nlmsghdr *hdr = (struct nlmsghdr*)request;
|
||||
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
hdr->nlmsg_type = XFRM_MSG_UPDPOLICY;
|
||||
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info));
|
||||
|
||||
request.hdr.nlmsg_type = XFRM_MSG_UPDPOLICY;
|
||||
request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.policy)));
|
||||
request.policy.dir = direction;
|
||||
request.policy.priority = SPD_PRIORITY;
|
||||
request.policy.action = XFRM_POLICY_ALLOW;
|
||||
request.policy.share = XFRM_SHARE_ANY;
|
||||
struct xfrm_userpolicy_info *policy = (struct xfrm_userpolicy_info*)NLMSG_DATA(hdr);
|
||||
|
||||
policy->sel.sport = htons(src->get_port(src));
|
||||
policy->sel.sport_mask = (policy->sel.sport) ? ~0 : 0;
|
||||
policy->sel.saddr = src->get_xfrm_addr(src);
|
||||
policy->sel.prefixlen_s = src_hostbits;
|
||||
|
||||
policy->sel.dport = htons(dst->get_port(dst));
|
||||
policy->sel.dport_mask = (policy->sel.dport) ? ~0 : 0;
|
||||
policy->sel.daddr = dst->get_xfrm_addr(dst);
|
||||
policy->sel.prefixlen_d = dst_hostbits;
|
||||
|
||||
policy->sel.proto = upper_proto;
|
||||
policy->sel.family = src->get_family(src);
|
||||
|
||||
policy->dir = direction;
|
||||
policy->priority = SPD_PRIORITY;
|
||||
policy->action = XFRM_POLICY_ALLOW;
|
||||
policy->share = XFRM_SHARE_ANY;
|
||||
|
||||
/* policies currently don't expire */
|
||||
request.policy.lft.soft_byte_limit = XFRM_INF;
|
||||
request.policy.lft.soft_packet_limit = XFRM_INF;
|
||||
request.policy.lft.hard_byte_limit = XFRM_INF;
|
||||
request.policy.lft.hard_packet_limit = XFRM_INF;
|
||||
request.sa.lft.soft_add_expires_seconds = 0;
|
||||
request.sa.lft.hard_add_expires_seconds = 0;
|
||||
request.sa.lft.soft_use_expires_seconds = 0;
|
||||
request.sa.lft.hard_use_expires_seconds = 0;
|
||||
policy->lft.soft_byte_limit = XFRM_INF;
|
||||
policy->lft.soft_packet_limit = XFRM_INF;
|
||||
policy->lft.hard_byte_limit = XFRM_INF;
|
||||
policy->lft.hard_packet_limit = XFRM_INF;
|
||||
policy->lft.soft_add_expires_seconds = 0;
|
||||
policy->lft.hard_add_expires_seconds = 0;
|
||||
policy->lft.soft_use_expires_seconds = 0;
|
||||
policy->lft.hard_use_expires_seconds = 0;
|
||||
|
||||
data = (xfrm_data_t*)(((u_int8_t*)&request) + request.hdr.nlmsg_len);
|
||||
data->type = XFRMA_TMPL;
|
||||
struct rtattr *rthdr = (struct rtattr*)(request + hdr->nlmsg_len);
|
||||
rthdr->rta_type = XFRMA_TMPL;
|
||||
|
||||
rthdr->rta_len = sizeof(struct xfrm_user_tmpl);
|
||||
rthdr->rta_len = RTA_LENGTH(rthdr->rta_len);
|
||||
|
||||
hdr->nlmsg_len += rthdr->rta_len;
|
||||
if (hdr->nlmsg_len > sizeof(request))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
data->tmpl.reqid = reqid;
|
||||
data->tmpl.id.proto = protocol == PROTO_AH ? KERNEL_AH : KERNEL_ESP;
|
||||
data->tmpl.aalgos = data->tmpl.ealgos = data->tmpl.calgos = ~0;
|
||||
data->tmpl.mode = TRUE;
|
||||
data->tmpl.saddr = me->get_xfrm_addr(me);
|
||||
data->tmpl.id.daddr = me->get_xfrm_addr(other);
|
||||
struct xfrm_user_tmpl *tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rthdr);
|
||||
tmpl->reqid = reqid;
|
||||
tmpl->id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
|
||||
tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0;
|
||||
tmpl->mode = TRUE;
|
||||
|
||||
data->length = 4 + sizeof(struct xfrm_user_tmpl);
|
||||
request.hdr.nlmsg_len += data->length;
|
||||
tmpl->saddr = me->get_xfrm_addr(me);
|
||||
tmpl->id.daddr = other->get_xfrm_addr(other);
|
||||
|
||||
if (this->send_message(this, &request, &response) != SUCCESS)
|
||||
if (this->send_message(this, hdr, &response) != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink communication failed");
|
||||
return FAILED;
|
||||
}
|
||||
else if (response->hdr.nlmsg_type != NLMSG_ERROR)
|
||||
else if (response->nlmsg_type != NLMSG_ERROR)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_NEWPOLICY not acknowledged");
|
||||
status = FAILED;
|
||||
}
|
||||
else if (response->e.error)
|
||||
else if (((struct nlmsgerr*)NLMSG_DATA(response))->error)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_NEWPOLICY received error: %s",
|
||||
strerror(-response->e.error));
|
||||
this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_NEWPOLICY got an error: %s",
|
||||
strerror(-((struct nlmsgerr*)NLMSG_DATA(response))->error));
|
||||
status = FAILED;
|
||||
}
|
||||
|
||||
@@ -569,44 +682,49 @@ static status_t del_policy(private_kernel_interface_t *this,
|
||||
u_int8_t src_hostbits, u_int8_t dst_hostbits,
|
||||
int direction, int upper_proto)
|
||||
{
|
||||
netlink_message_t request, *response;
|
||||
status_t status = SUCCESS;
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1, "Removing policy from kernel");
|
||||
unsigned char request[BUFFER_SIZE];
|
||||
struct nlmsghdr *response;
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
|
||||
request.policy_id.sel.sport = htons(src->get_port(src));
|
||||
request.policy_id.sel.dport = htons(dst->get_port(dst));
|
||||
request.policy_id.sel.sport_mask = (request.policy.sel.sport) ? ~0 : 0;
|
||||
request.policy_id.sel.dport_mask = (request.policy.sel.dport) ? ~0 : 0;
|
||||
request.policy_id.sel.saddr = src->get_xfrm_addr(src);
|
||||
request.policy_id.sel.daddr = dst->get_xfrm_addr(dst);
|
||||
request.policy_id.sel.prefixlen_s = src_hostbits;
|
||||
request.policy_id.sel.prefixlen_d = dst_hostbits;
|
||||
request.policy_id.sel.proto = upper_proto;
|
||||
request.policy_id.sel.family = src->get_family(src);
|
||||
status_t status = SUCCESS;
|
||||
|
||||
request.policy_id.dir = direction;
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "deleting policy");
|
||||
|
||||
request.hdr.nlmsg_type = XFRM_MSG_DELPOLICY;
|
||||
request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.policy_id)));
|
||||
struct nlmsghdr *hdr = (struct nlmsghdr*)request;
|
||||
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
hdr->nlmsg_type = XFRM_MSG_DELPOLICY;
|
||||
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id));
|
||||
|
||||
struct xfrm_userpolicy_id *policy_id = (struct xfrm_userpolicy_id*)NLMSG_DATA(hdr);
|
||||
policy_id->sel.sport = htons(src->get_port(src));
|
||||
policy_id->sel.sport_mask = (policy_id->sel.sport) ? ~0 : 0;
|
||||
policy_id->sel.saddr = src->get_xfrm_addr(src);
|
||||
policy_id->sel.prefixlen_s = src_hostbits;
|
||||
|
||||
if (this->send_message(this, &request, &response) != SUCCESS)
|
||||
policy_id->sel.dport = htons(dst->get_port(dst));
|
||||
policy_id->sel.dport_mask = (policy_id->sel.dport) ? ~0 : 0;
|
||||
policy_id->sel.daddr = dst->get_xfrm_addr(dst);
|
||||
policy_id->sel.prefixlen_d = dst_hostbits;
|
||||
|
||||
policy_id->sel.proto = upper_proto;
|
||||
policy_id->sel.family = src->get_family(src);
|
||||
|
||||
policy_id->dir = direction;
|
||||
|
||||
if (this->send_message(this, hdr, &response) != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink communication failed");
|
||||
return FAILED;
|
||||
}
|
||||
else if (response->hdr.nlmsg_type != NLMSG_ERROR)
|
||||
else if (response->nlmsg_type != NLMSG_ERROR)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_DELPOLICY not acknowledged");
|
||||
status = FAILED;
|
||||
}
|
||||
else if (response->e.error)
|
||||
else if (((struct nlmsgerr*)NLMSG_DATA(response))->error)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_DELPOLICY received error: %s",
|
||||
strerror(-response->e.error));
|
||||
this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_DELPOLICY got an error: %s",
|
||||
strerror(-((struct nlmsgerr*)NLMSG_DATA(response))->error));
|
||||
status = FAILED;
|
||||
}
|
||||
|
||||
@@ -617,26 +735,26 @@ static status_t del_policy(private_kernel_interface_t *this,
|
||||
/**
|
||||
* Implementation of private_kernel_interface_t.send_message.
|
||||
*/
|
||||
static status_t send_message(private_kernel_interface_t *this, netlink_message_t *request, netlink_message_t **response)
|
||||
static status_t send_message(private_kernel_interface_t *this, struct nlmsghdr *request, struct nlmsghdr **response)
|
||||
{
|
||||
size_t length;
|
||||
struct sockaddr_nl addr;
|
||||
|
||||
request->hdr.nlmsg_seq = ++this->seq;
|
||||
request->hdr.nlmsg_pid = this->pid;
|
||||
request->nlmsg_seq = ++this->seq;
|
||||
request->nlmsg_pid = 0;
|
||||
|
||||
memset(&addr, 0, sizeof(struct sockaddr_nl));
|
||||
addr.nl_family = AF_NETLINK;
|
||||
addr.nl_pid = 0;
|
||||
addr.nl_groups = 0;
|
||||
|
||||
length = sendto(this->socket,(void *)request, request->hdr.nlmsg_len, 0, (struct sockaddr *)&addr, sizeof(addr));
|
||||
length = sendto(this->socket,(void *)request, request->nlmsg_len, 0, (struct sockaddr *)&addr, sizeof(addr));
|
||||
|
||||
if (length < 0)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
else if (length != request->hdr.nlmsg_len)
|
||||
else if (length != request->nlmsg_len)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
@@ -651,12 +769,13 @@ static status_t send_message(private_kernel_interface_t *this, netlink_message_t
|
||||
iterator = this->responses->create_iterator(this->responses, TRUE);
|
||||
while (iterator->has_next(iterator))
|
||||
{
|
||||
netlink_message_t *listed_response;
|
||||
struct nlmsghdr *listed_response;
|
||||
iterator->current(iterator, (void**)&listed_response);
|
||||
if (listed_response->hdr.nlmsg_seq == request->hdr.nlmsg_seq)
|
||||
if (listed_response->nlmsg_seq == request->nlmsg_seq)
|
||||
{
|
||||
/* matches our request, this is the reply */
|
||||
*response = listed_response;
|
||||
iterator->remove(iterator);
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
@@ -683,7 +802,8 @@ static void receive_messages(private_kernel_interface_t *this)
|
||||
{
|
||||
while(TRUE)
|
||||
{
|
||||
netlink_message_t response, *listed_response;
|
||||
unsigned char response[BUFFER_SIZE];
|
||||
struct nlmsghdr *hdr, *listed_response;
|
||||
while (TRUE)
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
@@ -692,7 +812,6 @@ static void receive_messages(private_kernel_interface_t *this)
|
||||
|
||||
addr_length = sizeof(addr);
|
||||
|
||||
response.hdr.nlmsg_type = XFRM_MSG_NEWSA;
|
||||
length = recvfrom(this->socket, &response, sizeof(response), 0, (struct sockaddr*)&addr, &addr_length);
|
||||
if (length < 0)
|
||||
{
|
||||
@@ -703,7 +822,7 @@ static void receive_messages(private_kernel_interface_t *this)
|
||||
}
|
||||
charon->kill(charon, "receiving from netlink socket failed");
|
||||
}
|
||||
if (!NLMSG_OK(&response.hdr, length))
|
||||
if (!NLMSG_OK((struct nlmsghdr *)response, length))
|
||||
{
|
||||
/* bad netlink message */
|
||||
continue;
|
||||
@@ -719,44 +838,52 @@ static void receive_messages(private_kernel_interface_t *this)
|
||||
|
||||
/* we handle ACQUIRE and EXPIRE messages directly
|
||||
*/
|
||||
if (response.hdr.nlmsg_type == XFRM_MSG_ACQUIRE)
|
||||
hdr = (struct nlmsghdr*)response;
|
||||
if (hdr->nlmsg_type == XFRM_MSG_ACQUIRE)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL,
|
||||
"Received a XFRM_MSG_ACQUIRE. Ignored");
|
||||
}
|
||||
else if (response.hdr.nlmsg_type == XFRM_MSG_EXPIRE)
|
||||
else if (hdr->nlmsg_type == XFRM_MSG_EXPIRE)
|
||||
{
|
||||
job_t *job;
|
||||
struct xfrm_user_expire *expire;
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1,
|
||||
"Received a XFRM_MSG_EXPIRE");
|
||||
if (response.expire.hard)
|
||||
expire = (struct xfrm_user_expire*)NLMSG_DATA(hdr);
|
||||
this->logger->log(this->logger, CONTROL|LEVEL0,
|
||||
"creating %s job for CHILD_SA with reqid %d",
|
||||
expire->hard ? "delete" : "rekey",
|
||||
expire->state.reqid);
|
||||
if (expire->hard)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL0,
|
||||
"creating delete job for CHILD_SA with reqid %d",
|
||||
response.expire.state.reqid);
|
||||
expire->state.reqid);
|
||||
job = (job_t*)delete_child_sa_job_create(
|
||||
response.expire.state.reqid);
|
||||
expire->state.reqid);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL0,
|
||||
"creating rekey job for CHILD_SA with reqid %d",
|
||||
response.expire.state.reqid);
|
||||
expire->state.reqid);
|
||||
job = (job_t*)rekey_child_sa_job_create(
|
||||
response.expire.state.reqid);
|
||||
expire->state.reqid);
|
||||
}
|
||||
charon->job_queue->add(charon->job_queue, job);
|
||||
}
|
||||
/* NLMSG_ERROR is send back for acknowledge (or on error), an
|
||||
* XFRM_MSG_NEWSA is returned when we alloc spis.
|
||||
/* NLMSG_ERROR is sent back for acknowledge (or on error), an
|
||||
* XFRM_MSG_NEWSA is returned when we alloc spis and when
|
||||
* updating SAs.
|
||||
* list these responses for the sender
|
||||
*/
|
||||
else if (response.hdr.nlmsg_type == NLMSG_ERROR ||
|
||||
response.hdr.nlmsg_type == XFRM_MSG_NEWSA)
|
||||
else if (hdr->nlmsg_type == NLMSG_ERROR ||
|
||||
hdr->nlmsg_type == XFRM_MSG_NEWSA)
|
||||
{
|
||||
/* add response to queue */
|
||||
listed_response = malloc(sizeof(response));
|
||||
memcpy(listed_response, &response, sizeof(response));
|
||||
listed_response = malloc(hdr->nlmsg_len);
|
||||
memcpy(listed_response, &response, hdr->nlmsg_len);
|
||||
|
||||
pthread_mutex_lock(&(this->mutex));
|
||||
this->responses->insert_last(this->responses, (void*)listed_response);
|
||||
@@ -792,8 +919,9 @@ kernel_interface_t *kernel_interface_create()
|
||||
|
||||
/* public functions */
|
||||
this->public.get_spi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi;
|
||||
this->public.add_sa = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,algorithm_t*,algorithm_t*,prf_plus_t*,bool))add_sa;
|
||||
this->public.add_sa = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,algorithm_t*,algorithm_t*,prf_plus_t*,natt_conf_t*,bool))add_sa;
|
||||
this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*, host_t*,host_t*,host_t*,u_int8_t,u_int8_t,int,int,protocol_id_t,u_int32_t))add_policy;
|
||||
this->public.update_sa_hosts = (status_t(*)(kernel_interface_t*,host_t*,host_t*,host_t*,host_t*,int,int,u_int32_t,protocol_id_t))update_sa_hosts;
|
||||
this->public.del_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t))del_sa;
|
||||
this->public.del_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,host_t*,host_t*,u_int8_t,u_int8_t,int,int))del_policy;
|
||||
|
||||
@@ -817,6 +945,7 @@ kernel_interface_t *kernel_interface_create()
|
||||
free(this);
|
||||
charon->kill(charon, "Unable to create netlink socket");
|
||||
}
|
||||
|
||||
/* bind the socket and reqister for ACQUIRE & EXPIRE */
|
||||
addr.nl_family = AF_NETLINK;
|
||||
addr.nl_pid = getpid();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -29,6 +30,15 @@
|
||||
#include <crypto/prf_plus.h>
|
||||
#include <encoding/payloads/proposal_substructure.h>
|
||||
|
||||
typedef struct natt_conf_t natt_conf_t;
|
||||
|
||||
/**
|
||||
* @brief Configuration for NAT-T
|
||||
*/
|
||||
struct natt_conf_t {
|
||||
u_int16_t sport, dport;
|
||||
};
|
||||
|
||||
typedef struct kernel_interface_t kernel_interface_t;
|
||||
|
||||
/**
|
||||
@@ -47,6 +57,10 @@ struct kernel_interface_t {
|
||||
|
||||
/**
|
||||
* @brief Get a SPI from the kernel.
|
||||
*
|
||||
* @warning get_spi() implicitely creates an SA with
|
||||
* the allocated SPI, therefore the replace flag
|
||||
* in add_sa() must be set when installing this SA.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param src source address of SA
|
||||
@@ -86,6 +100,7 @@ struct kernel_interface_t {
|
||||
* @param enc_alg Algorithm to use for encryption (ESP only)
|
||||
* @param int_alg Algorithm to use for integrity protection
|
||||
* @param prf_plus PRF to derive keys
|
||||
* @param natt NAT-T Configuration
|
||||
* @param replace Should an already installed SA be updated?
|
||||
* @return
|
||||
* - SUCCESS
|
||||
@@ -101,7 +116,34 @@ struct kernel_interface_t {
|
||||
algorithm_t *enc_alg,
|
||||
algorithm_t *int_alg,
|
||||
prf_plus_t *prf_plus,
|
||||
natt_conf_t *natt,
|
||||
bool replace);
|
||||
/**
|
||||
* @brief Update the hosts on an installed SA. Encapsulation ports are also updated.
|
||||
*
|
||||
* @note We cannot directly update the destination address as the kernel requires the spi,
|
||||
* the protocol AND the destination address (and family) to identify SAs. Therefore if the
|
||||
* destination address changed we create a new SA and delete the old one.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param src source address for this SA
|
||||
* @param dst destination address for this SA
|
||||
* @param new_src new source address for this SA
|
||||
* @param new_dst new destination address for this SA
|
||||
* @param src_changes changes in src
|
||||
* @param dst_changes changes in dst
|
||||
* @param spi SPI allocated by us or remote peer
|
||||
* @param protocol protocol for this SA (ESP/AH)
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - FAILED if kernel comm failed
|
||||
*/
|
||||
status_t (*update_sa_hosts)(kernel_interface_t *this,
|
||||
host_t *src, host_t *dst,
|
||||
host_t *new_src, host_t *new_dst,
|
||||
int src_changes, int dst_changes,
|
||||
u_int32_t spi, protocol_id_t protocol);
|
||||
|
||||
/**
|
||||
* @brief Delete a previusly installed SA from the SAD.
|
||||
*
|
||||
|
||||
@@ -203,7 +203,7 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
|
||||
return;
|
||||
}
|
||||
|
||||
if (charon->socket->is_listening_on(charon->socket, other_host))
|
||||
if (charon->interfaces->is_local_address(charon->interfaces, other_host))
|
||||
{
|
||||
stroke_end_t tmp_end;
|
||||
host_t *tmp_host;
|
||||
@@ -218,7 +218,7 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
|
||||
msg->add_conn.me = msg->add_conn.other;
|
||||
msg->add_conn.other = tmp_end;
|
||||
}
|
||||
else if (!charon->socket->is_listening_on(charon->socket, my_host))
|
||||
else if (!charon->interfaces->is_local_address(charon->interfaces, my_host))
|
||||
{
|
||||
this->stroke_logger->log(this->stroke_logger, ERROR, "left nor right host is our side, aborting");
|
||||
|
||||
|
||||
@@ -29,12 +29,6 @@
|
||||
|
||||
#include <daemon.h>
|
||||
#include <queues/job_queue.h>
|
||||
#include <queues/jobs/delete_half_open_ike_sa_job.h>
|
||||
#include <queues/jobs/delete_established_ike_sa_job.h>
|
||||
#include <queues/jobs/incoming_packet_job.h>
|
||||
#include <queues/jobs/initiate_ike_sa_job.h>
|
||||
#include <queues/jobs/retransmit_request_job.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
#include <utils/logger.h>
|
||||
|
||||
|
||||
@@ -145,13 +139,13 @@ thread_pool_t *thread_pool_create(size_t pool_size)
|
||||
this->public.destroy = (void(*)(thread_pool_t*))destroy;
|
||||
this->public.get_pool_size = (size_t(*)(thread_pool_t*))get_pool_size;
|
||||
|
||||
/* initialze memeber */
|
||||
/* initialize member */
|
||||
this->pool_size = pool_size;
|
||||
this->threads = malloc(sizeof(pthread_t) * pool_size);
|
||||
this->pool_logger = logger_manager->get_logger(logger_manager, THREAD_POOL);
|
||||
this->worker_logger = logger_manager->get_logger(logger_manager, WORKER);
|
||||
|
||||
/* try to create as many threads as possible, up tu pool_size */
|
||||
/* try to create as many threads as possible, up to pool_size */
|
||||
for (current = 0; current < pool_size; current++)
|
||||
{
|
||||
if (pthread_create(&(this->threads[current]), NULL, (void*(*)(void*))process_jobs, this) == 0)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -136,7 +137,7 @@ static chunk_t get_address_as_chunk(private_host_t *this)
|
||||
{
|
||||
case AF_INET:
|
||||
{
|
||||
/* allocate 4 bytes for IPV4 address*/
|
||||
/* allocate 4 bytes for IPv4 address*/
|
||||
address.ptr = malloc(4);
|
||||
address.len = 4;
|
||||
memcpy(address.ptr,&(this->address4.sin_addr.s_addr),4);
|
||||
@@ -188,6 +189,24 @@ static u_int16_t get_port(private_host_t *this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* implements host_t.set_port
|
||||
*/
|
||||
static void set_port(private_host_t *this, u_int16_t port)
|
||||
{
|
||||
switch (this->family)
|
||||
{
|
||||
case AF_INET:
|
||||
{
|
||||
this->address4.sin_port = htons(port);
|
||||
}
|
||||
default:
|
||||
{
|
||||
/**/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements host_t.clone.
|
||||
@@ -226,6 +245,26 @@ static bool ip_equals(private_host_t *this, private_host_t *other)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements host_t.get_differences
|
||||
*/
|
||||
static int get_differences(private_host_t *this, private_host_t *other)
|
||||
{
|
||||
int ret = HOST_DIFF_NONE;
|
||||
|
||||
if (!this->public.ip_equals(&this->public, &other->public))
|
||||
{
|
||||
ret |= HOST_DIFF_ADDR;
|
||||
}
|
||||
|
||||
if (this->public.get_port(&this->public) != other->public.get_port(&other->public))
|
||||
{
|
||||
ret |= HOST_DIFF_PORT;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Impelements host_t.equals
|
||||
*/
|
||||
@@ -271,6 +310,8 @@ static private_host_t *host_create_empty(void)
|
||||
this->public.get_address = (char* (*) (host_t *))get_address;
|
||||
this->public.get_address_as_chunk = (chunk_t (*) (host_t *)) get_address_as_chunk;
|
||||
this->public.get_port = (u_int16_t (*) (host_t *))get_port;
|
||||
this->public.set_port = (void (*) (host_t *,u_int16_t))set_port;
|
||||
this->public.get_differences = (int (*) (host_t *,host_t *)) get_differences;
|
||||
this->public.ip_equals = (bool (*) (host_t *,host_t *)) ip_equals;
|
||||
this->public.equals = (bool (*) (host_t *,host_t *)) equals;
|
||||
this->public.is_anyaddr = (bool (*) (host_t *)) is_anyaddr;
|
||||
@@ -311,6 +352,22 @@ host_t *host_create(int family, char *address, u_int16_t port)
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
host_t *host_create_from_hdr(u_long address, u_short port)
|
||||
{
|
||||
private_host_t *this = host_create_empty();
|
||||
|
||||
this->family = AF_INET;
|
||||
|
||||
this->address4.sin_family = AF_INET;
|
||||
this->address4.sin_addr.s_addr = address;
|
||||
this->address4.sin_port = port;
|
||||
this->socklen = sizeof(struct sockaddr_in);
|
||||
return &(this->public);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -34,6 +35,10 @@
|
||||
#include <types.h>
|
||||
|
||||
|
||||
#define HOST_DIFF_NONE 0
|
||||
#define HOST_DIFF_ADDR 1
|
||||
#define HOST_DIFF_PORT 2
|
||||
|
||||
typedef struct host_t host_t;
|
||||
|
||||
/**
|
||||
@@ -141,12 +146,18 @@ struct host_t {
|
||||
/**
|
||||
* @brief get the port of this host
|
||||
*
|
||||
* Mostly used for debugging purposes.
|
||||
*
|
||||
* @param this object to clone
|
||||
* @return port number
|
||||
*/
|
||||
u_int16_t (*get_port) (host_t *this);
|
||||
|
||||
/**
|
||||
* @brief set the port of this host
|
||||
*
|
||||
* @param this object to clone
|
||||
* @param port port numer
|
||||
*/
|
||||
void (*set_port) (host_t *this, u_int16_t port);
|
||||
|
||||
/**
|
||||
* @brief Compare the ips of two hosts hosts.
|
||||
@@ -165,6 +176,16 @@ struct host_t {
|
||||
* @return TRUE if addresses and ports are equal.
|
||||
*/
|
||||
bool (*equals) (host_t *this, host_t *other);
|
||||
|
||||
/**
|
||||
* @brief Compare two hosts and return the differences.
|
||||
*
|
||||
* @param this object to compare
|
||||
* @param other the other to compare
|
||||
* @return a combination of HOST_DIFF_NONE,
|
||||
* HOST_DIFF_ADDR and HOST_DIFF_PORT
|
||||
*/
|
||||
int (*get_differences) (host_t *this, host_t *other);
|
||||
|
||||
/**
|
||||
* @brief Destroy this host object
|
||||
@@ -191,6 +212,20 @@ struct host_t {
|
||||
*/
|
||||
host_t *host_create(int family, char *address, u_int16_t port);
|
||||
|
||||
/**
|
||||
* @brief Constructor to create a host_t object from raw header data
|
||||
*
|
||||
* only IPv4 (create host_create_from_hdr6 for IPv6)!
|
||||
*
|
||||
* @param address address in network byte order
|
||||
* @param port port number in network byte order
|
||||
* @return
|
||||
* - host_t object
|
||||
*
|
||||
* @ingroup network
|
||||
*/
|
||||
host_t *host_create_from_hdr(u_long address, u_short port);
|
||||
|
||||
/**
|
||||
* @brief Constructor to create a host_t object from an address chunk
|
||||
*
|
||||
|
||||
@@ -59,7 +59,7 @@ struct iterator_t {
|
||||
* @param this calling object
|
||||
* @param[out] value item
|
||||
* @return
|
||||
* - TRUE, if more elements are avaiable,
|
||||
* - TRUE, if there was an element available,
|
||||
* - FALSE otherwise
|
||||
*/
|
||||
bool (*iterate) (iterator_t *this, void** value);
|
||||
@@ -72,7 +72,7 @@ struct iterator_t {
|
||||
*
|
||||
* @param this calling object
|
||||
* @return
|
||||
* - TRUE, if more elements are avaiable,
|
||||
* - TRUE, if more elements are available,
|
||||
* - FALSE otherwise
|
||||
*/
|
||||
bool (*has_next) (iterator_t *this);
|
||||
|
||||
Reference in New Issue
Block a user