summaryrefslogtreecommitdiff
path: root/src/libcharon
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@debian.org>2015-11-18 14:49:27 +0100
committerYves-Alexis Perez <corsac@debian.org>2015-11-18 14:49:27 +0100
commit1e980d6be0ef0e243c6fe82b5e855454b97e24a4 (patch)
tree0d59eec2ce2ed332434ae80fc78a44db9ad293c5 /src/libcharon
parent5dca9ea0e2931f0e2a056c7964d311bcc30a01b8 (diff)
downloadvyos-strongswan-1e980d6be0ef0e243c6fe82b5e855454b97e24a4.tar.gz
vyos-strongswan-1e980d6be0ef0e243c6fe82b5e855454b97e24a4.zip
Imported Upstream version 5.3.4
Diffstat (limited to 'src/libcharon')
-rw-r--r--src/libcharon/Android.mk1
-rw-r--r--src/libcharon/bus/listeners/file_logger.c32
-rw-r--r--src/libcharon/bus/listeners/file_logger.h7
-rw-r--r--src/libcharon/config/peer_cfg.c2
-rw-r--r--src/libcharon/daemon.c46
-rw-r--r--src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c115
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_provider.c32
-rw-r--r--src/libcharon/plugins/error_notify/error_notify_listener.c2
-rw-r--r--src/libcharon/plugins/ha/ha_child.c2
-rw-r--r--src/libcharon/plugins/ha/ha_dispatcher.c2
-rw-r--r--src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c7
-rw-r--r--src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c9
-rw-r--r--src/libcharon/plugins/load_tester/load_tester_ipsec.c5
-rw-r--r--src/libcharon/plugins/socket_default/socket_default_socket.c281
-rw-r--r--src/libcharon/plugins/socket_dynamic/socket_dynamic_socket.c94
-rw-r--r--src/libcharon/plugins/stroke/stroke_config.c6
-rw-r--r--src/libcharon/plugins/stroke/stroke_control.c71
-rw-r--r--src/libcharon/plugins/stroke/stroke_list.c6
-rw-r--r--src/libcharon/plugins/vici/README.md21
-rw-r--r--src/libcharon/plugins/vici/vici_attribute.c28
-rw-r--r--src/libcharon/plugins/vici/vici_cred.c12
-rw-r--r--src/libcharon/plugins/vici/vici_query.c47
-rw-r--r--src/libcharon/processing/jobs/initiate_mediation_job.c4
-rw-r--r--src/libcharon/sa/child_sa.c178
-rw-r--r--src/libcharon/sa/ike_sa_manager.c84
-rw-r--r--src/libcharon/sa/ike_sa_manager.h21
-rw-r--r--src/libcharon/sa/ikev1/keymat_v1.c20
-rw-r--r--src/libcharon/sa/ikev1/task_manager_v1.c110
-rw-r--r--src/libcharon/sa/ikev1/tasks/mode_config.c4
-rw-r--r--src/libcharon/sa/ikev1/tasks/quick_delete.c4
-rw-r--r--src/libcharon/sa/ikev1/tasks/quick_mode.c6
-rw-r--r--src/libcharon/sa/ikev1/tasks/xauth.c10
-rw-r--r--src/libcharon/sa/ikev2/keymat_v2.c1
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_create.c4
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_delete.c4
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_mobike.c6
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_natd.c28
-rw-r--r--src/libcharon/sa/shunt_manager.c66
-rw-r--r--src/libcharon/sa/trap_manager.c2
39 files changed, 979 insertions, 401 deletions
diff --git a/src/libcharon/Android.mk b/src/libcharon/Android.mk
index 5eef6fdc6..10085794b 100644
--- a/src/libcharon/Android.mk
+++ b/src/libcharon/Android.mk
@@ -228,7 +228,6 @@ endif
# build libcharon --------------------------------------------------------------
LOCAL_C_INCLUDES += \
- $(strongswan_PATH)/src/include \
$(strongswan_PATH)/src/libhydra \
$(strongswan_PATH)/src/libstrongswan
diff --git a/src/libcharon/bus/listeners/file_logger.c b/src/libcharon/bus/listeners/file_logger.c
index e3661bde6..7a53e9338 100644
--- a/src/libcharon/bus/listeners/file_logger.c
+++ b/src/libcharon/bus/listeners/file_logger.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012-2015 Tobias Brunner
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -65,6 +65,11 @@ struct private_file_logger_t {
char *time_format;
/**
+ * Add milliseconds after the time string
+ */
+ bool add_ms;
+
+ /**
* Print the name/# of the IKE_SA?
*/
bool ike_name;
@@ -87,7 +92,9 @@ METHOD(logger_t, log_, void,
char timestr[128], namestr[128] = "";
const char *current = message, *next;
struct tm tm;
- time_t t;
+ timeval_t tv;
+ time_t s;
+ u_int ms = 0;
this->lock->read_lock(this->lock);
if (!this->out)
@@ -97,8 +104,10 @@ METHOD(logger_t, log_, void,
}
if (this->time_format)
{
- t = time(NULL);
- localtime_r(&t, &tm);
+ gettimeofday(&tv, NULL);
+ s = tv.tv_sec;
+ ms = tv.tv_usec / 1000;
+ localtime_r(&s, &tm);
strftime(timestr, sizeof(timestr), this->time_format, &tm);
}
if (this->ike_name && ike_sa)
@@ -126,8 +135,16 @@ METHOD(logger_t, log_, void,
next = strchr(current, '\n');
if (this->time_format)
{
- fprintf(this->out, "%s %.2d[%N]%s ",
- timestr, thread, debug_names, group, namestr);
+ if (this->add_ms)
+ {
+ fprintf(this->out, "%s.%03u %.2d[%N]%s ",
+ timestr, ms, thread, debug_names, group, namestr);
+ }
+ else
+ {
+ fprintf(this->out, "%s %.2d[%N]%s ",
+ timestr, thread, debug_names, group, namestr);
+ }
}
else
{
@@ -182,11 +199,12 @@ METHOD(file_logger_t, set_level, void,
}
METHOD(file_logger_t, set_options, void,
- private_file_logger_t *this, char *time_format, bool ike_name)
+ private_file_logger_t *this, char *time_format, bool add_ms, bool ike_name)
{
this->lock->write_lock(this->lock);
free(this->time_format);
this->time_format = strdupnull(time_format);
+ this->add_ms = add_ms;
this->ike_name = ike_name;
this->lock->unlock(this->lock);
}
diff --git a/src/libcharon/bus/listeners/file_logger.h b/src/libcharon/bus/listeners/file_logger.h
index 9e5aed50b..1bcfec150 100644
--- a/src/libcharon/bus/listeners/file_logger.h
+++ b/src/libcharon/bus/listeners/file_logger.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012-2015 Tobias Brunner
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -48,9 +48,12 @@ struct file_logger_t {
* Set options used by this logger
*
* @param time_format format of timestamp prefix, as in strftime(), cloned
+ * @param add_ms TRUE to add the number of milliseconds within the
+ * current second after the timestamp
* @param ike_name TRUE to prefix the name of the IKE_SA
*/
- void (*set_options) (file_logger_t *this, char *time_format, bool ike_name);
+ void (*set_options) (file_logger_t *this, char *time_format, bool add_ms,
+ bool ike_name);
/**
* Open (or reopen) the log file according to the given parameters
diff --git a/src/libcharon/config/peer_cfg.c b/src/libcharon/config/peer_cfg.c
index ce9301006..aa2a39ce5 100644
--- a/src/libcharon/config/peer_cfg.c
+++ b/src/libcharon/config/peer_cfg.c
@@ -302,7 +302,7 @@ METHOD(peer_cfg_t, select_child_cfg, child_cfg_t*,
enumerator_t *enumerator;
int best = 0;
- DBG2(DBG_CFG, "looking for a child config for %#R=== %#R", my_ts, other_ts);
+ DBG2(DBG_CFG, "looking for a child config for %#R === %#R", my_ts, other_ts);
enumerator = create_child_cfg_enumerator(this);
while (enumerator->enumerate(enumerator, &current))
{
diff --git a/src/libcharon/daemon.c b/src/libcharon/daemon.c
index 316be7611..dce2a7144 100644
--- a/src/libcharon/daemon.c
+++ b/src/libcharon/daemon.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006-2012 Tobias Brunner
+ * Copyright (C) 2006-2015 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005 Jan Hutter
@@ -324,11 +324,13 @@ static void load_file_logger(private_daemon_t *this, char *filename,
file_logger_t *file_logger;
debug_t group;
level_t def;
- bool ike_name, flush_line, append;
+ bool add_ms, ike_name, flush_line, append;
char *time_format;
time_format = lib->settings->get_str(lib->settings,
"%s.filelog.%s.time_format", NULL, lib->ns, filename);
+ add_ms = lib->settings->get_bool(lib->settings,
+ "%s.filelog.%s.time_add_ms", FALSE, lib->ns, filename);
ike_name = lib->settings->get_bool(lib->settings,
"%s.filelog.%s.ike_name", FALSE, lib->ns, filename);
flush_line = lib->settings->get_bool(lib->settings,
@@ -337,7 +339,7 @@ static void load_file_logger(private_daemon_t *this, char *filename,
"%s.filelog.%s.append", TRUE, lib->ns, filename);
file_logger = add_file_logger(this, filename, current_loggers);
- file_logger->set_options(file_logger, time_format, ike_name);
+ file_logger->set_options(file_logger, time_format, add_ms, ike_name);
file_logger->open(file_logger, flush_line, append);
def = lib->settings->get_int(lib->settings, "%s.filelog.%s.default", 1,
@@ -486,8 +488,6 @@ static void destroy(private_daemon_t *this)
DESTROY_IF(this->kernel_handler);
DESTROY_IF(this->public.traps);
DESTROY_IF(this->public.shunts);
- DESTROY_IF(this->public.child_sa_manager);
- DESTROY_IF(this->public.ike_sa_manager);
DESTROY_IF(this->public.controller);
DESTROY_IF(this->public.eap);
DESTROY_IF(this->public.xauth);
@@ -560,7 +560,6 @@ METHOD(daemon_t, start, void,
run_scripts(this, "start");
}
-
/**
* Initialize/deinitialize sender and receiver
*/
@@ -584,12 +583,36 @@ static bool sender_receiver_cb(void *plugin, plugin_feature_t *feature,
return TRUE;
}
+/**
+ * Initialize/deinitialize IKE_SA/CHILD_SA managers
+ */
+static bool sa_managers_cb(void *plugin, plugin_feature_t *feature,
+ bool reg, private_daemon_t *this)
+{
+ if (reg)
+ {
+ this->public.ike_sa_manager = ike_sa_manager_create();
+ if (!this->public.ike_sa_manager)
+ {
+ return FALSE;
+ }
+ this->public.child_sa_manager = child_sa_manager_create();
+ }
+ else
+ {
+ DESTROY_IF(this->public.ike_sa_manager);
+ DESTROY_IF(this->public.child_sa_manager);
+ }
+ return TRUE;
+}
+
METHOD(daemon_t, initialize, bool,
private_daemon_t *this, char *plugins)
{
plugin_feature_t features[] = {
PLUGIN_PROVIDE(CUSTOM, "libcharon"),
PLUGIN_DEPENDS(NONCE_GEN),
+ PLUGIN_DEPENDS(CUSTOM, "libcharon-sa-managers"),
PLUGIN_DEPENDS(CUSTOM, "libcharon-receiver"),
PLUGIN_DEPENDS(CUSTOM, "kernel-ipsec"),
PLUGIN_DEPENDS(CUSTOM, "kernel-net"),
@@ -598,6 +621,10 @@ METHOD(daemon_t, initialize, bool,
PLUGIN_DEPENDS(HASHER, HASH_SHA1),
PLUGIN_DEPENDS(RNG, RNG_STRONG),
PLUGIN_DEPENDS(CUSTOM, "socket"),
+ PLUGIN_CALLBACK((plugin_feature_callback_t)sa_managers_cb, this),
+ PLUGIN_PROVIDE(CUSTOM, "libcharon-sa-managers"),
+ PLUGIN_DEPENDS(HASHER, HASH_SHA1),
+ PLUGIN_DEPENDS(RNG, RNG_WEAK),
};
lib->plugins->add_static_features(lib->plugins, lib->ns, features,
countof(features), TRUE, NULL, NULL);
@@ -608,13 +635,6 @@ METHOD(daemon_t, initialize, bool,
return FALSE;
}
- this->public.ike_sa_manager = ike_sa_manager_create();
- if (this->public.ike_sa_manager == NULL)
- {
- return FALSE;
- }
- this->public.child_sa_manager = child_sa_manager_create();
-
/* Queue start_action job */
lib->processor->queue_job(lib->processor, (job_t*)start_action_job_create());
diff --git a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c
index f7f39f984..16978f486 100644
--- a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c
+++ b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Tobias Brunner
+ * Copyright (C) 2009-2015 Tobias Brunner
* Copyright (C) 2010 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -81,6 +81,21 @@ struct private_eap_mschapv2_t
* Number of retries
*/
int retries;
+
+ /**
+ * Provide EAP-Identity
+ */
+ auth_cfg_t *auth;
+
+ /**
+ * Current state
+ */
+ enum {
+ S_EXPECT_CHALLENGE,
+ S_EXPECT_RESPONSE,
+ S_EXPECT_SUCCESS,
+ S_DONE,
+ } state;
};
/**
@@ -628,6 +643,7 @@ METHOD(eap_method_t, initiate_server, status_t,
memcpy(cha->name, name, sizeof(MSCHAPV2_HOST_NAME) - 1);
*out = eap_payload_create_data(chunk_create((void*) eap, len));
+ this->state = S_EXPECT_RESPONSE;
return NEED_MORE;
}
@@ -747,6 +763,7 @@ static status_t process_peer_challenge(private_eap_mschapv2_t *this,
memcpy(res->name, userid.ptr, userid.len);
*out = eap_payload_create_data(chunk_create((void*) eap, len));
+ this->state = S_EXPECT_SUCCESS;
return NEED_MORE;
}
@@ -829,6 +846,7 @@ static status_t process_peer_success(private_eap_mschapv2_t *this,
*out = eap_payload_create_data(chunk_create((void*) eap, len));
status = NEED_MORE;
+ this->state = S_DONE;
error:
chunk_free(&auth_string);
@@ -922,6 +940,7 @@ static status_t process_peer_failure(private_eap_mschapv2_t *this,
*/
status = FAILED;
+ this->state = S_DONE;
error:
chunk_free(&challenge);
@@ -946,26 +965,38 @@ METHOD(eap_method_t, process_peer, status_t,
eap = (eap_mschapv2_header_t*)data.ptr;
+ switch (this->state)
+ {
+ case S_EXPECT_CHALLENGE:
+ if (eap->opcode == MSCHAPV2_CHALLENGE)
+ {
+ return process_peer_challenge(this, in, out);
+ }
+ break;
+ case S_EXPECT_SUCCESS:
+ switch (eap->opcode)
+ {
+ case MSCHAPV2_SUCCESS:
+ return process_peer_success(this, in, out);
+ case MSCHAPV2_FAILURE:
+ return process_peer_failure(this, in, out);
+ }
+ break;
+ default:
+ break;
+ }
switch (eap->opcode)
{
case MSCHAPV2_CHALLENGE:
- {
- return process_peer_challenge(this, in, out);
- }
case MSCHAPV2_SUCCESS:
- {
- return process_peer_success(this, in, out);
- }
case MSCHAPV2_FAILURE:
- {
- return process_peer_failure(this, in, out);
- }
+ DBG1(DBG_IKE, "received unexpected EAP-MS-CHAPv2 message with "
+ "OpCode (%N)!", mschapv2_opcode_names, eap->opcode);
+ break;
default:
- {
DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported "
"OpCode (%N)!", mschapv2_opcode_names, eap->opcode);
break;
- }
}
return FAILED;
}
@@ -1027,6 +1058,8 @@ static status_t process_server_retry(private_eap_mschapv2_t *this,
/* delay the response for some time to make brute-force attacks harder */
sleep(RETRY_DELAY);
+ /* since the error is retryable the state does not change, we still
+ * expect an MSCHAPV2_RESPONSE from the peer */
return NEED_MORE;
}
@@ -1058,7 +1091,10 @@ static status_t process_server_response(private_eap_mschapv2_t *this,
name_len = min(data.len - RESPONSE_PAYLOAD_LEN, 255);
snprintf(buf, sizeof(buf), "%.*s", name_len, res->name);
userid = identification_create_from_string(buf);
- DBG2(DBG_IKE, "EAP-MS-CHAPv2 username: '%Y'", userid);
+ if (!userid->equals(userid, this->peer))
+ {
+ DBG1(DBG_IKE, "EAP-MS-CHAPv2 username: '%Y'", userid);
+ }
/* userid can only be destroyed after the last use of username */
username = extract_username(userid->get_encoding(userid));
@@ -1084,7 +1120,6 @@ static status_t process_server_response(private_eap_mschapv2_t *this,
chunk_clear(&nt_hash);
return FAILED;
}
- userid->destroy(userid);
chunk_clear(&nt_hash);
if (memeq_const(res->response.nt_response, this->nt_response.ptr,
@@ -1109,9 +1144,12 @@ static status_t process_server_response(private_eap_mschapv2_t *this,
chunk_free(&hex);
memcpy(eap->data, msg, AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE));
*out = eap_payload_create_data(chunk_create((void*) eap, len));
+
+ this->auth->add(this->auth, AUTH_RULE_EAP_IDENTITY, userid);
+ this->state = S_EXPECT_SUCCESS;
return NEED_MORE;
}
-
+ userid->destroy(userid);
return process_server_retry(this, out);
}
@@ -1137,26 +1175,39 @@ METHOD(eap_method_t, process_server, status_t,
eap = (eap_mschapv2_header_t*)data.ptr;
+ switch (this->state)
+ {
+ case S_EXPECT_RESPONSE:
+ if (eap->opcode == MSCHAPV2_RESPONSE)
+ {
+ return process_server_response(this, in, out);
+ }
+ break;
+ case S_EXPECT_SUCCESS:
+ if (eap->opcode == MSCHAPV2_SUCCESS &&
+ this->msk.ptr)
+ {
+ return SUCCESS;
+ }
+ break;
+ default:
+ break;
+ }
switch (eap->opcode)
{
- case MSCHAPV2_RESPONSE:
- {
- return process_server_response(this, in, out);
- }
- case MSCHAPV2_SUCCESS:
- {
- return SUCCESS;
- }
case MSCHAPV2_FAILURE:
- {
+ /* the client may abort the authentication by sending us a failure
+ * in any state */
return FAILED;
- }
+ case MSCHAPV2_RESPONSE:
+ case MSCHAPV2_SUCCESS:
+ DBG1(DBG_IKE, "received unexpected EAP-MS-CHAPv2 message with "
+ "OpCode (%N)!", mschapv2_opcode_names, eap->opcode);
+ break;
default:
- {
DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported "
"OpCode (%N)!", mschapv2_opcode_names, eap->opcode);
break;
- }
}
return FAILED;
}
@@ -1197,11 +1248,18 @@ METHOD(eap_method_t, is_mutual, bool,
return FALSE;
}
+METHOD(eap_method_t, get_auth, auth_cfg_t*,
+ private_eap_mschapv2_t *this)
+{
+ return this->auth;
+}
+
METHOD(eap_method_t, destroy, void,
private_eap_mschapv2_t *this)
{
this->peer->destroy(this->peer);
this->server->destroy(this->server);
+ this->auth->destroy(this->auth);
chunk_free(&this->challenge);
chunk_free(&this->nt_response);
chunk_free(&this->auth_response);
@@ -1224,11 +1282,14 @@ static private_eap_mschapv2_t *eap_mschapv2_create_generic(identification_t *ser
.get_msk = _get_msk,
.get_identifier = _get_identifier,
.set_identifier = _set_identifier,
+ .get_auth = _get_auth,
.destroy = _destroy,
},
},
.peer = peer->clone(peer),
.server = server->clone(server),
+ .auth = auth_cfg_create(),
+ .state = S_EXPECT_CHALLENGE,
);
return this;
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_provider.c b/src/libcharon/plugins/eap_radius/eap_radius_provider.c
index 0cf723711..0f207fbe6 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius_provider.c
+++ b/src/libcharon/plugins/eap_radius/eap_radius_provider.c
@@ -178,18 +178,38 @@ static void add_addr(private_eap_radius_provider_t *this,
* Remove the next address from the locked hashtable stored for given id
*/
static host_t* remove_addr(private_eap_radius_provider_t *this,
- hashtable_t *hashtable, uintptr_t id)
+ hashtable_t *hashtable, uintptr_t id, host_t *addr)
{
+ enumerator_t *enumerator;
entry_t *entry;
- host_t *addr = NULL;
+ host_t *found = NULL, *current;
entry = hashtable->remove(hashtable, (void*)id);
if (entry)
{
- entry->addrs->remove_first(entry->addrs, (void**)&addr);
+ enumerator = entry->addrs->create_enumerator(entry->addrs);
+ while (enumerator->enumerate(enumerator, &current))
+ {
+ if (addr->ip_equals(addr, current))
+ { /* prefer an exact match */
+ entry->addrs->remove_at(entry->addrs, enumerator);
+ enumerator->destroy(enumerator);
+ put_or_destroy_entry(hashtable, entry);
+ return current;
+ }
+ if (!found && addr->get_family(addr) == current->get_family(current))
+ { /* fallback to the first IP with a matching address family */
+ found = current;
+ }
+ }
+ enumerator->destroy(enumerator);
+ if (found)
+ {
+ entry->addrs->remove(entry->addrs, found, NULL);
+ }
put_or_destroy_entry(hashtable, entry);
}
- return addr;
+ return found;
}
/**
@@ -326,7 +346,7 @@ METHOD(attribute_provider_t, acquire_address, host_t*,
if (streq(name, "radius"))
{
this->listener.mutex->lock(this->listener.mutex);
- addr = remove_addr(this, this->listener.unclaimed, sa);
+ addr = remove_addr(this, this->listener.unclaimed, sa, requested);
if (addr)
{
add_addr(this, this->listener.claimed, sa, addr->clone(addr));
@@ -357,7 +377,7 @@ METHOD(attribute_provider_t, release_address, bool,
if (streq(name, "radius"))
{
this->listener.mutex->lock(this->listener.mutex);
- found = remove_addr(this, this->listener.claimed, sa);
+ found = remove_addr(this, this->listener.claimed, sa, address);
this->listener.mutex->unlock(this->listener.mutex);
break;
}
diff --git a/src/libcharon/plugins/error_notify/error_notify_listener.c b/src/libcharon/plugins/error_notify/error_notify_listener.c
index f7a1f49ec..ce577c62c 100644
--- a/src/libcharon/plugins/error_notify/error_notify_listener.c
+++ b/src/libcharon/plugins/error_notify/error_notify_listener.c
@@ -110,7 +110,7 @@ METHOD(listener_t, alert, bool,
list = va_arg(args, linked_list_t*);
list2 = va_arg(args, linked_list_t*);
snprintf(msg.str, sizeof(msg.str), "the received traffic selectors "
- "did not match: %#R=== %#R", list, list2);
+ "did not match: %#R === %#R", list, list2);
break;
case ALERT_INSTALL_CHILD_SA_FAILED:
msg.type = htonl(ERROR_NOTIFY_INSTALL_CHILD_SA_FAILED);
diff --git a/src/libcharon/plugins/ha/ha_child.c b/src/libcharon/plugins/ha/ha_child.c
index 17f2d50d1..dbb6adc8f 100644
--- a/src/libcharon/plugins/ha/ha_child.c
+++ b/src/libcharon/plugins/ha/ha_child.c
@@ -126,7 +126,7 @@ METHOD(listener_t, child_keys, bool,
ike_sa->get_my_host(ike_sa), child_sa->get_spi(child_sa, TRUE));
seg_o = this->kernel->get_segment_spi(this->kernel,
ike_sa->get_other_host(ike_sa), child_sa->get_spi(child_sa, FALSE));
- DBG1(DBG_CFG, "handling HA CHILD_SA %s{%d} %#R=== %#R "
+ DBG1(DBG_CFG, "handling HA CHILD_SA %s{%d} %#R === %#R "
"(segment in: %d%s, out: %d%s)", child_sa->get_name(child_sa),
child_sa->get_unique_id(child_sa), local_ts, remote_ts,
seg_i, this->segments->is_active(this->segments, seg_i) ? "*" : "",
diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c
index afa099309..07ef607c6 100644
--- a/src/libcharon/plugins/ha/ha_dispatcher.c
+++ b/src/libcharon/plugins/ha/ha_dispatcher.c
@@ -848,7 +848,7 @@ static void process_child_add(private_ha_dispatcher_t *this,
seg_o = this->kernel->get_segment_spi(this->kernel,
ike_sa->get_other_host(ike_sa), outbound_spi);
- DBG1(DBG_CFG, "installed HA CHILD_SA %s{%d} %#R=== %#R "
+ DBG1(DBG_CFG, "installed HA CHILD_SA %s{%d} %#R === %#R "
"(segment in: %d%s, out: %d%s)", child_sa->get_name(child_sa),
child_sa->get_unique_id(child_sa), local_ts, remote_ts,
seg_i, this->segments->is_active(this->segments, seg_i) ? "*" : "",
diff --git a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c
index 6246dc505..d738e6d13 100644
--- a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c
+++ b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c
@@ -563,15 +563,16 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
}
METHOD(kernel_ipsec_t, del_policy, status_t,
- private_kernel_libipsec_ipsec_t *this, traffic_selector_t *src_ts,
- traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
+ private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst,
+ traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
+ policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, policy_priority_t priority)
{
policy_entry_t *policy, *found = NULL;
status_t status;
status = ipsec->policies->del_policy(ipsec->policies, src_ts, dst_ts,
- direction, reqid, mark, priority);
+ direction, sa->reqid, mark, priority);
policy = create_policy_entry(src_ts, dst_ts, direction);
diff --git a/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c
index b38ded846..95f79f168 100644
--- a/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c
+++ b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c
@@ -2456,15 +2456,16 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
}
METHOD(kernel_ipsec_t, del_policy, status_t,
- private_kernel_wfp_ipsec_t *this, traffic_selector_t *src_ts,
- traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
+ private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst,
+ traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
+ policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, policy_priority_t priority)
{
if (direction == POLICY_OUT && priority == POLICY_PRIORITY_ROUTED)
{
- if (remove_trap(this, reqid, FALSE, src_ts, dst_ts))
+ if (remove_trap(this, sa->reqid, FALSE, src_ts, dst_ts))
{
- remove_trap(this, reqid, TRUE, src_ts, dst_ts);
+ remove_trap(this, sa->reqid, TRUE, src_ts, dst_ts);
return SUCCESS;
}
return NOT_FOUND;
diff --git a/src/libcharon/plugins/load_tester/load_tester_ipsec.c b/src/libcharon/plugins/load_tester/load_tester_ipsec.c
index 62d43e302..6a86bb899 100644
--- a/src/libcharon/plugins/load_tester/load_tester_ipsec.c
+++ b/src/libcharon/plugins/load_tester/load_tester_ipsec.c
@@ -103,8 +103,9 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
}
METHOD(kernel_ipsec_t, del_policy, status_t,
- private_load_tester_ipsec_t *this, traffic_selector_t *src_ts,
- traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
+ private_load_tester_ipsec_t *this, host_t *src, host_t *dst,
+ traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
+ policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
mark_t mark, policy_priority_t priority)
{
return SUCCESS;
diff --git a/src/libcharon/plugins/socket_default/socket_default_socket.c b/src/libcharon/plugins/socket_default/socket_default_socket.c
index dbfddbb81..13bf3e775 100644
--- a/src/libcharon/plugins/socket_default/socket_default_socket.c
+++ b/src/libcharon/plugins/socket_default/socket_default_socket.c
@@ -148,6 +148,91 @@ struct private_socket_default_socket_t {
u_int rr_counter;
};
+/**
+ * Get the destination IPv4 address of a received packet, depending on the
+ * available mechanism.
+ */
+#ifdef IP_PKTINFO
+
+static host_t *get_dst_v4(struct cmsghdr *cmsgptr, u_int16_t port)
+{
+ struct sockaddr_in dst = {
+ .sin_family = AF_INET,
+ .sin_port = htons(port),
+ };
+ struct in_pktinfo *pktinfo;
+ struct in_addr *addr;
+
+ if (cmsgptr->cmsg_type == IP_PKTINFO)
+ {
+ pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsgptr);
+ addr = &pktinfo->ipi_addr;
+ memcpy(&dst.sin_addr, addr, sizeof(dst.sin_addr));
+ return host_create_from_sockaddr((sockaddr_t*)&dst);
+ }
+ return NULL;
+}
+
+#elif defined(IP_RECVDSTADDR)
+
+static host_t *get_dst_v4(struct cmsghdr *cmsgptr, u_int16_t port)
+{
+ struct sockaddr_in dst = {
+ .sin_family = AF_INET,
+ .sin_port = htons(port),
+ };
+ struct in_addr *addr;
+
+ if (cmsgptr->cmsg_type == IP_RECVDSTADDR)
+ {
+ addr = (struct in_addr*)CMSG_DATA(cmsgptr);
+ memcpy(&dst.sin_addr, addr, sizeof(dst.sin_addr));
+ return host_create_from_sockaddr((sockaddr_t*)&dst);
+ }
+ return NULL;
+}
+
+#else /* IP_PKTINFO || IP_RECVDSTADDR */
+
+static host_t *get_dst_v4(struct cmsghdr *cmsgptr, u_int16_t port)
+{
+ return NULL;
+}
+
+#endif /* IP_PKTINFO || IP_RECVDSTADDR */
+
+/**
+ * Get the destination IPv6 address of a received packet, depending on the
+ * available mechanism.
+ */
+#ifdef HAVE_IN6_PKTINFO
+
+static host_t *get_dst_v6(struct cmsghdr *cmsgptr, u_int16_t port)
+{
+ struct in6_pktinfo *pktinfo;
+ struct sockaddr_in6 dst = {
+ .sin6_family = AF_INET6,
+ .sin6_port = htons(port),
+ };
+
+ if (cmsgptr->cmsg_type == IPV6_PKTINFO)
+ {
+ pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsgptr);
+ memcpy(&dst.sin6_addr, &pktinfo->ipi6_addr, sizeof(dst.sin6_addr));
+ return host_create_from_sockaddr((sockaddr_t*)&dst);
+ }
+ return NULL;
+}
+
+#else /* HAVE_IN6_PKTINFO */
+
+static host_t *get_dst_v6(struct cmsghdr *cmsgptr, u_int16_t port)
+{
+ return NULL;
+}
+
+#endif /* HAVE_IN6_PKTINFO */
+
METHOD(socket_t, receiver, status_t,
private_socket_default_socket_t *this, packet_t **packet)
{
@@ -233,48 +318,13 @@ METHOD(socket_t, receiver, status_t,
DBG1(DBG_NET, "error reading ancillary data");
return FAILED;
}
-
-#ifdef HAVE_IN6_PKTINFO
- if (cmsgptr->cmsg_level == SOL_IPV6 &&
- cmsgptr->cmsg_type == IPV6_PKTINFO)
+ if (cmsgptr->cmsg_level == SOL_IP)
{
- struct in6_pktinfo *pktinfo;
- pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsgptr);
- struct sockaddr_in6 dst;
-
- memset(&dst, 0, sizeof(dst));
- memcpy(&dst.sin6_addr, &pktinfo->ipi6_addr, sizeof(dst.sin6_addr));
- dst.sin6_family = AF_INET6;
- dst.sin6_port = htons(port);
- dest = host_create_from_sockaddr((sockaddr_t*)&dst);
+ dest = get_dst_v4(cmsgptr, port);
}
-#endif /* HAVE_IN6_PKTINFO */
- if (cmsgptr->cmsg_level == SOL_IP &&
-#ifdef IP_PKTINFO
- cmsgptr->cmsg_type == IP_PKTINFO
-#elif defined(IP_RECVDSTADDR)
- cmsgptr->cmsg_type == IP_RECVDSTADDR
-#else
- FALSE
-#endif
- )
+ else if (cmsgptr->cmsg_level == SOL_IPV6)
{
- struct in_addr *addr;
- struct sockaddr_in dst;
-
-#ifdef IP_PKTINFO
- struct in_pktinfo *pktinfo;
- pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsgptr);
- addr = &pktinfo->ipi_addr;
-#elif defined(IP_RECVDSTADDR)
- addr = (struct in_addr*)CMSG_DATA(cmsgptr);
-#endif
- memset(&dst, 0, sizeof(dst));
- memcpy(&dst.sin_addr, addr, sizeof(dst.sin_addr));
-
- dst.sin_family = AF_INET;
- dst.sin_port = htons(port);
- dest = host_create_from_sockaddr((sockaddr_t*)&dst);
+ dest = get_dst_v6(cmsgptr, port);
}
if (dest)
{
@@ -305,6 +355,107 @@ METHOD(socket_t, receiver, status_t,
return SUCCESS;
}
+/**
+ * Generic function to send a message.
+ */
+static ssize_t send_msg_generic(int skt, struct msghdr *msg)
+{
+ return sendmsg(skt, msg, 0);
+}
+
+/**
+ * Send a message with the IPv4 source address set, if possible.
+ */
+#ifdef IP_PKTINFO
+
+static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src)
+{
+ char buf[CMSG_SPACE(sizeof(struct in_pktinfo))] = {};
+ struct cmsghdr *cmsg;
+ struct in_addr *addr;
+ struct in_pktinfo *pktinfo;
+ struct sockaddr_in *sin;
+
+ msg->msg_control = buf;
+ msg->msg_controllen = sizeof(buf);
+ cmsg = CMSG_FIRSTHDR(msg);
+ cmsg->cmsg_level = SOL_IP;
+ cmsg->cmsg_type = IP_PKTINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+
+ pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
+ addr = &pktinfo->ipi_spec_dst;
+
+ sin = (struct sockaddr_in*)src->get_sockaddr(src);
+ memcpy(addr, &sin->sin_addr, sizeof(struct in_addr));
+ return send_msg_generic(skt, msg);
+}
+
+#elif defined(IP_SENDSRCADDR)
+
+static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src)
+{
+ char buf[CMSG_SPACE(sizeof(struct in_addr))] = {};
+ struct cmsghdr *cmsg;
+ struct in_addr *addr;
+ struct sockaddr_in *sin;
+
+ msg->msg_control = buf;
+ msg->msg_controllen = sizeof(buf);
+ cmsg = CMSG_FIRSTHDR(msg);
+ cmsg->cmsg_level = SOL_IP;
+ cmsg->cmsg_type = IP_SENDSRCADDR;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
+
+ addr = (struct in_addr*)CMSG_DATA(cmsg);
+
+ sin = (struct sockaddr_in*)src->get_sockaddr(src);
+ memcpy(addr, &sin->sin_addr, sizeof(struct in_addr));
+ return send_msg_generic(skt, msg);
+}
+
+#else /* IP_PKTINFO || IP_RECVDSTADDR */
+
+static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src)
+{
+ return send_msg_generic(skt, msg);
+}
+
+#endif /* IP_PKTINFO || IP_RECVDSTADDR */
+
+/**
+ * Send a message with the IPv6 source address set, if possible.
+ */
+#ifdef HAVE_IN6_PKTINFO
+
+static ssize_t send_msg_v6(int skt, struct msghdr *msg, host_t *src)
+{
+ char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))] = {};
+ struct cmsghdr *cmsg;
+ struct in6_pktinfo *pktinfo;
+ struct sockaddr_in6 *sin;
+
+ msg->msg_control = buf;
+ msg->msg_controllen = sizeof(buf);
+ cmsg = CMSG_FIRSTHDR(msg);
+ cmsg->cmsg_level = SOL_IPV6;
+ cmsg->cmsg_type = IPV6_PKTINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
+ sin = (struct sockaddr_in6*)src->get_sockaddr(src);
+ memcpy(&pktinfo->ipi6_addr, &sin->sin6_addr, sizeof(struct in6_addr));
+ return send_msg_generic(skt, msg);
+}
+
+#else /* HAVE_IN6_PKTINFO */
+
+static ssize_t send_msg_v6(int skt, struct msghdr *msg, host_t *src)
+{
+ return send_msg_generic(skt, msg);
+}
+
+#endif /* HAVE_IN6_PKTINFO */
+
METHOD(socket_t, sender, status_t,
private_socket_default_socket_t *this, packet_t *packet)
{
@@ -313,7 +464,6 @@ METHOD(socket_t, sender, status_t,
chunk_t data;
host_t *src, *dst;
struct msghdr msg;
- struct cmsghdr *cmsg;
struct iovec iov;
u_int8_t *dscp;
@@ -415,56 +565,17 @@ METHOD(socket_t, sender, status_t,
{
if (family == AF_INET)
{
-#if defined(IP_PKTINFO) || defined(IP_SENDSRCADDR)
- struct in_addr *addr;
- struct sockaddr_in *sin;
-#ifdef IP_PKTINFO
- char buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
- struct in_pktinfo *pktinfo;
-#elif defined(IP_SENDSRCADDR)
- char buf[CMSG_SPACE(sizeof(struct in_addr))];
-#endif
- memset(buf, 0, sizeof(buf));
- msg.msg_control = buf;
- msg.msg_controllen = sizeof(buf);
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_IP;
-#ifdef IP_PKTINFO
- cmsg->cmsg_type = IP_PKTINFO;
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
- pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
- addr = &pktinfo->ipi_spec_dst;
-#elif defined(IP_SENDSRCADDR)
- cmsg->cmsg_type = IP_SENDSRCADDR;
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
- addr = (struct in_addr*)CMSG_DATA(cmsg);
-#endif
- sin = (struct sockaddr_in*)src->get_sockaddr(src);
- memcpy(addr, &sin->sin_addr, sizeof(struct in_addr));
-#endif /* IP_PKTINFO || IP_SENDSRCADDR */
+ bytes_sent = send_msg_v4(skt, &msg, src);
}
-#ifdef HAVE_IN6_PKTINFO
else
{
- char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
- struct in6_pktinfo *pktinfo;
- struct sockaddr_in6 *sin;
-
- memset(buf, 0, sizeof(buf));
- msg.msg_control = buf;
- msg.msg_controllen = sizeof(buf);
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_IPV6;
- cmsg->cmsg_type = IPV6_PKTINFO;
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
- pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
- sin = (struct sockaddr_in6*)src->get_sockaddr(src);
- memcpy(&pktinfo->ipi6_addr, &sin->sin6_addr, sizeof(struct in6_addr));
+ bytes_sent = send_msg_v6(skt, &msg, src);
}
-#endif /* HAVE_IN6_PKTINFO */
}
-
- bytes_sent = sendmsg(skt, &msg, 0);
+ else
+ {
+ bytes_sent = send_msg_generic(skt, &msg);
+ }
if (bytes_sent != data.len)
{
diff --git a/src/libcharon/plugins/socket_dynamic/socket_dynamic_socket.c b/src/libcharon/plugins/socket_dynamic/socket_dynamic_socket.c
index b82a69e1b..a032134c3 100644
--- a/src/libcharon/plugins/socket_dynamic/socket_dynamic_socket.c
+++ b/src/libcharon/plugins/socket_dynamic/socket_dynamic_socket.c
@@ -527,6 +527,62 @@ static dynsock_t *find_socket(private_socket_dynamic_socket_t *this,
return skt;
}
+/**
+ * Generic function to send a message.
+ */
+static ssize_t send_msg_generic(int skt, struct msghdr *msg)
+{
+ return sendmsg(skt, msg, 0);
+}
+
+/**
+ * Send a message with the IPv4 source address set.
+ */
+static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src)
+{
+ char buf[CMSG_SPACE(sizeof(struct in_pktinfo))] = {};
+ struct cmsghdr *cmsg;
+ struct in_addr *addr;
+ struct in_pktinfo *pktinfo;
+ struct sockaddr_in *sin;
+
+ msg->msg_control = buf;
+ msg->msg_controllen = sizeof(buf);
+ cmsg = CMSG_FIRSTHDR(msg);
+ cmsg->cmsg_level = SOL_IP;
+ cmsg->cmsg_type = IP_PKTINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+
+ pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
+ addr = &pktinfo->ipi_spec_dst;
+
+ sin = (struct sockaddr_in*)src->get_sockaddr(src);
+ memcpy(addr, &sin->sin_addr, sizeof(struct in_addr));
+ return send_msg_generic(skt, msg);
+}
+
+/**
+ * Send a message with the IPv6 source address set.
+ */
+static ssize_t send_msg_v6(int skt, struct msghdr *msg, host_t *src)
+{
+ char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))] = {};
+ struct cmsghdr *cmsg;
+ struct in6_pktinfo *pktinfo;
+ struct sockaddr_in6 *sin;
+
+ msg->msg_control = buf;
+ msg->msg_controllen = sizeof(buf);
+ cmsg = CMSG_FIRSTHDR(msg);
+ cmsg->cmsg_level = SOL_IPV6;
+ cmsg->cmsg_type = IPV6_PKTINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
+ sin = (struct sockaddr_in6*)src->get_sockaddr(src);
+ memcpy(&pktinfo->ipi6_addr, &sin->sin6_addr, sizeof(struct in6_addr));
+ return send_msg_generic(skt, msg);
+}
+
METHOD(socket_t, sender, status_t,
private_socket_dynamic_socket_t *this, packet_t *packet)
{
@@ -536,7 +592,6 @@ METHOD(socket_t, sender, status_t,
ssize_t len;
chunk_t data;
struct msghdr msg;
- struct cmsghdr *cmsg;
struct iovec iov;
src = packet->get_source(packet);
@@ -564,43 +619,18 @@ METHOD(socket_t, sender, status_t,
{
if (family == AF_INET)
{
- struct in_addr *addr;
- struct sockaddr_in *sin;
- char buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
- struct in_pktinfo *pktinfo;
-
- memset(buf, 0, sizeof(buf));
- msg.msg_control = buf;
- msg.msg_controllen = sizeof(buf);
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_IP;
- cmsg->cmsg_type = IP_PKTINFO;
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
- pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
- addr = &pktinfo->ipi_spec_dst;
- sin = (struct sockaddr_in*)src->get_sockaddr(src);
- memcpy(addr, &sin->sin_addr, sizeof(struct in_addr));
+ len = send_msg_v4(skt->fd, &msg, src);
}
else
{
- char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
- struct in6_pktinfo *pktinfo;
- struct sockaddr_in6 *sin;
-
- memset(buf, 0, sizeof(buf));
- msg.msg_control = buf;
- msg.msg_controllen = sizeof(buf);
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_IPV6;
- cmsg->cmsg_type = IPV6_PKTINFO;
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
- pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
- sin = (struct sockaddr_in6*)src->get_sockaddr(src);
- memcpy(&pktinfo->ipi6_addr, &sin->sin6_addr, sizeof(struct in6_addr));
+ len = send_msg_v6(skt->fd, &msg, src);
}
}
+ else
+ {
+ len = send_msg_generic(skt->fd, &msg);
+ }
- len = sendmsg(skt->fd, &msg, 0);
if (len != data.len)
{
DBG1(DBG_NET, "error writing to socket: %s", strerror(errno));
diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c
index f71719458..68cf83089 100644
--- a/src/libcharon/plugins/stroke/stroke_config.c
+++ b/src/libcharon/plugins/stroke/stroke_config.c
@@ -346,9 +346,9 @@ static void parse_pubkey_constraints(char *auth, auth_cfg_t *cfg)
{ "sha256", SIGN_ECDSA_256, KEY_ECDSA, },
{ "sha384", SIGN_ECDSA_384, KEY_ECDSA, },
{ "sha512", SIGN_ECDSA_521, KEY_ECDSA, },
- { "sha256", SIGN_BLISS_WITH_SHA256, KEY_BLISS, },
- { "sha384", SIGN_BLISS_WITH_SHA384, KEY_BLISS, },
- { "sha512", SIGN_BLISS_WITH_SHA512, KEY_BLISS, },
+ { "sha256", SIGN_BLISS_WITH_SHA2_256, KEY_BLISS, },
+ { "sha384", SIGN_BLISS_WITH_SHA2_384, KEY_BLISS, },
+ { "sha512", SIGN_BLISS_WITH_SHA2_512, KEY_BLISS, },
};
if (rsa_len || ecdsa_len || bliss_strength)
diff --git a/src/libcharon/plugins/stroke/stroke_control.c b/src/libcharon/plugins/stroke/stroke_control.c
index 0125d17c6..5a1a5074d 100644
--- a/src/libcharon/plugins/stroke/stroke_control.c
+++ b/src/libcharon/plugins/stroke/stroke_control.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Tobias Brunner
+ * Copyright (C) 2013-2015 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -298,6 +298,41 @@ static void report_terminate_status(private_stroke_control_t *this,
}
}
+/**
+ * Call the charon controller to terminate a CHILD_SA
+ */
+static void charon_terminate(private_stroke_control_t *this, u_int32_t id,
+ stroke_msg_t *msg, FILE *out, bool child)
+{
+ if (msg->output_verbosity >= 0)
+ {
+ stroke_log_info_t info = { msg->output_verbosity, out };
+ status_t status;
+
+ if (child)
+ {
+ status = charon->controller->terminate_child(charon->controller, id,
+ (controller_cb_t)stroke_log, &info, this->timeout);
+ }
+ else
+ {
+ status = charon->controller->terminate_ike(charon->controller, id,
+ (controller_cb_t)stroke_log, &info, this->timeout);
+ }
+ report_terminate_status(this, status, out, id, child);
+ }
+ else if (child)
+ {
+ charon->controller->terminate_child(charon->controller, id,
+ NULL, NULL, 0);
+ }
+ else
+ {
+ charon->controller->terminate_ike(charon->controller, id,
+ NULL, NULL, 0);
+ }
+}
+
METHOD(stroke_control_t, terminate, void,
private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
{
@@ -307,9 +342,7 @@ METHOD(stroke_control_t, terminate, void,
ike_sa_t *ike_sa;
enumerator_t *enumerator;
linked_list_t *ike_list, *child_list;
- stroke_log_info_t info;
uintptr_t del;
- status_t status;
if (!parse_specifier(msg->terminate.name, &id, &name, &child, &all))
{
@@ -317,22 +350,9 @@ METHOD(stroke_control_t, terminate, void,
return;
}
- info.out = out;
- info.level = msg->output_verbosity;
-
if (id)
{
- if (child)
- {
- status = charon->controller->terminate_child(charon->controller, id,
- (controller_cb_t)stroke_log, &info, this->timeout);
- }
- else
- {
- status = charon->controller->terminate_ike(charon->controller, id,
- (controller_cb_t)stroke_log, &info, this->timeout);
- }
- return report_terminate_status(this, status, out, id, child);
+ return charon_terminate(this, id, msg, out, child);
}
ike_list = linked_list_create();
@@ -380,18 +400,14 @@ METHOD(stroke_control_t, terminate, void,
enumerator = child_list->create_enumerator(child_list);
while (enumerator->enumerate(enumerator, &del))
{
- status = charon->controller->terminate_child(charon->controller, del,
- (controller_cb_t)stroke_log, &info, this->timeout);
- report_terminate_status(this, status, out, del, TRUE);
+ charon_terminate(this, del, msg, out, TRUE);
}
enumerator->destroy(enumerator);
enumerator = ike_list->create_enumerator(ike_list);
while (enumerator->enumerate(enumerator, &del))
{
- status = charon->controller->terminate_ike(charon->controller, del,
- (controller_cb_t)stroke_log, &info, this->timeout);
- report_terminate_status(this, status, out, del, FALSE);
+ charon_terminate(this, del, msg, out, FALSE);
}
enumerator->destroy(enumerator);
@@ -548,11 +564,6 @@ METHOD(stroke_control_t, purge_ike, void,
child_sa_t *child_sa;
linked_list_t *list;
uintptr_t del;
- stroke_log_info_t info;
- status_t status;
-
- info.out = out;
- info.level = msg->output_verbosity;
list = linked_list_create();
enumerator = charon->controller->create_ike_sa_enumerator(
@@ -572,9 +583,7 @@ METHOD(stroke_control_t, purge_ike, void,
enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, &del))
{
- status = charon->controller->terminate_ike(charon->controller, del,
- (controller_cb_t)stroke_log, &info, this->timeout);
- report_terminate_status(this, status, out, del, TRUE);
+ charon_terminate(this, del, msg, out, FALSE);
}
enumerator->destroy(enumerator);
list->destroy(list);
diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c
index c7e4c9c65..c0192b5c0 100644
--- a/src/libcharon/plugins/stroke/stroke_list.c
+++ b/src/libcharon/plugins/stroke/stroke_list.c
@@ -334,7 +334,7 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
child_sa->create_ts_enumerator(child_sa, TRUE));
other_ts = linked_list_create_from_enumerator(
child_sa->create_ts_enumerator(child_sa, FALSE));
- fprintf(out, "\n%12s{%d}: %#R=== %#R\n",
+ fprintf(out, "\n%12s{%d}: %#R === %#R\n",
child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
my_ts, other_ts);
my_ts->destroy(my_ts);
@@ -586,7 +586,7 @@ METHOD(stroke_list_t, status, void,
{
my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
- fprintf(out, "%12s: child: %#R=== %#R%N",
+ fprintf(out, "%12s: child: %#R === %#R %N",
child_cfg->get_name(child_cfg), my_ts, other_ts,
ipsec_mode_names, child_cfg->get_mode(child_cfg));
my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
@@ -620,7 +620,7 @@ METHOD(stroke_list_t, status, void,
}
my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
- fprintf(out, "%12s: %#R=== %#R%N\n",
+ fprintf(out, "%12s: %#R === %#R %N\n",
child_cfg->get_name(child_cfg), my_ts, other_ts,
ipsec_mode_names, child_cfg->get_mode(child_cfg));
my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md
index e20e8ab26..b9531d8a5 100644
--- a/src/libcharon/plugins/vici/README.md
+++ b/src/libcharon/plugins/vici/README.md
@@ -526,12 +526,21 @@ Unloading fails for pools with leases currently online.
List the currently loaded pools.
- {} => {
+ {
+ leases = <set to yes to include leases>
+ } => {
<pool name>* = {
base = <virtual IP pool base address>
size = <total number of addresses in the pool>
online = <number of leases online>
offline = <number of leases offline>
+ leases = {
+ <zero-based index>* = {
+ address = <IP address>
+ identity = <assigned identity>
+ status = <online|offline>
+ }
+ }
}
}
@@ -587,6 +596,10 @@ command.
initiator = <yes, if initiator of IKE_SA>
initiator-spi = <hex encoded initiator SPI / cookie>
responder-spi = <hex encoded responder SPI / cookie>
+ nat-local = <yes, if local endpoint is behind a NAT>
+ nat-remote = <yes, if remote endpoint is behind a NAT>
+ nat-fake = <yes, if NAT situation has been faked as responder>
+ nat-any = <yes, if any endpoint is behind a NAT (also if faked)>
encr-alg = <IKE encryption algorithm string>
encr-keysize = <key size for encr-alg, if applicable>
integ-alg = <IKE integrity algorithm string>
@@ -596,6 +609,12 @@ command.
established = <seconds the IKE_SA has been established>
rekey-time = <seconds before IKE_SA gets rekeyed>
reauth-time = <seconds before IKE_SA gets re-authenticated>
+ local-vips = [
+ <list of virtual IPs assigned by the remote peer, installed locally>
+ ]
+ remote-vips = [
+ <list of virtual IPs assigned to the remote peer>
+ ]
tasks-queued = [
<list of currently queued tasks for execution>
]
diff --git a/src/libcharon/plugins/vici/vici_attribute.c b/src/libcharon/plugins/vici/vici_attribute.c
index f04bae774..9064d3d8c 100644
--- a/src/libcharon/plugins/vici/vici_attribute.c
+++ b/src/libcharon/plugins/vici/vici_attribute.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 Tobias Brunner
+ * Copyright (C) 2014-2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2014 Martin Willi
@@ -662,9 +662,16 @@ CALLBACK(get_pools, vici_message_t*,
vici_message_t *message)
{
vici_builder_t *builder;
- enumerator_t *enumerator;
+ enumerator_t *enumerator, *leases;
mem_pool_t *vips;
pool_t *pool;
+ identification_t *uid;
+ host_t *lease;
+ bool list_leases, on;
+ char buf[32];
+ int i;
+
+ list_leases = message->get_bool(message, FALSE, "leases");
builder = vici_builder_create();
@@ -681,6 +688,23 @@ CALLBACK(get_pools, vici_message_t*,
builder->add_kv(builder, "online", "%u", vips->get_online(vips));
builder->add_kv(builder, "offline", "%u", vips->get_offline(vips));
+ if (list_leases)
+ {
+ i = 0;
+ builder->begin_section(builder, "leases");
+ leases = vips->create_lease_enumerator(vips);
+ while (leases && leases->enumerate(leases, &uid, &lease, &on))
+ {
+ snprintf(buf, sizeof(buf), "%d", i++);
+ builder->begin_section(builder, buf);
+ builder->add_kv(builder, "address", "%H", lease);
+ builder->add_kv(builder, "identity", "%Y", uid);
+ builder->add_kv(builder, "status", on ? "online" : "offline");
+ builder->end_section(builder);
+ }
+ leases->destroy(leases);
+ builder->end_section(builder);
+ }
builder->end_section(builder);
}
enumerator->destroy(enumerator);
diff --git a/src/libcharon/plugins/vici/vici_cred.c b/src/libcharon/plugins/vici/vici_cred.c
index ffdc034ea..6631184b5 100644
--- a/src/libcharon/plugins/vici/vici_cred.c
+++ b/src/libcharon/plugins/vici/vici_cred.c
@@ -71,6 +71,7 @@ CALLBACK(load_cert, vici_message_t*,
certificate_t *cert;
x509_t *x509;
chunk_t data;
+ bool trusted = TRUE;
char *str;
str = message->get_str(message, NULL, "type");
@@ -99,6 +100,7 @@ CALLBACK(load_cert, vici_message_t*,
else if (strcaseeq(str, "x509ac"))
{
type = CERT_X509_AC;
+ trusted = FALSE;
}
else
{
@@ -131,8 +133,14 @@ CALLBACK(load_cert, vici_message_t*,
DBG1(DBG_CFG, "loaded certificate '%Y'", cert->get_subject(cert));
- this->creds->add_cert(this->creds, TRUE, cert);
-
+ if (type == CERT_X509_CRL)
+ {
+ this->creds->add_crl(this->creds, (crl_t*)cert);
+ }
+ else
+ {
+ this->creds->add_cert(this->creds, trusted, cert);
+ }
return create_reply(NULL);
}
diff --git a/src/libcharon/plugins/vici/vici_query.c b/src/libcharon/plugins/vici/vici_query.c
index 98d264fca..9a3d832da 100644
--- a/src/libcharon/plugins/vici/vici_query.c
+++ b/src/libcharon/plugins/vici/vici_query.c
@@ -222,6 +222,45 @@ static void list_task_queue(private_vici_query_t *this, vici_builder_t *b,
}
/**
+ * Add an IKE_SA condition to the given builder
+ */
+static void add_condition(vici_builder_t *b, ike_sa_t *ike_sa,
+ char *key, ike_condition_t cond)
+{
+ if (ike_sa->has_condition(ike_sa, cond))
+ {
+ b->add_kv(b, key, "yes");
+ }
+}
+
+/**
+ * List virtual IPs
+ */
+static void list_vips(private_vici_query_t *this, vici_builder_t *b,
+ ike_sa_t *ike_sa, bool local, char *name)
+{
+ enumerator_t *enumerator;
+ bool has = FALSE;
+ host_t *vip;
+
+ enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, local);
+ while (enumerator->enumerate(enumerator, &vip))
+ {
+ if (!has)
+ {
+ b->begin_list(b, name);
+ has = TRUE;
+ }
+ b->add_li(b, "%H", vip);
+ }
+ enumerator->destroy(enumerator);
+ if (has)
+ {
+ b->end_list(b);
+ }
+}
+
+/**
* List details of an IKE_SA
*/
static void list_ike(private_vici_query_t *this, vici_builder_t *b,
@@ -265,6 +304,11 @@ static void list_ike(private_vici_query_t *this, vici_builder_t *b,
b->add_kv(b, "initiator-spi", "%.16"PRIx64, id->get_initiator_spi(id));
b->add_kv(b, "responder-spi", "%.16"PRIx64, id->get_responder_spi(id));
+ add_condition(b, ike_sa, "nat-local", COND_NAT_HERE);
+ add_condition(b, ike_sa, "nat-remote", COND_NAT_THERE);
+ add_condition(b, ike_sa, "nat-fake", COND_NAT_FAKE);
+ add_condition(b, ike_sa, "nat-any", COND_NAT_ANY);
+
proposal = ike_sa->get_proposal(ike_sa);
if (proposal)
{
@@ -310,6 +354,9 @@ static void list_ike(private_vici_query_t *this, vici_builder_t *b,
}
}
+ list_vips(this, b, ike_sa, TRUE, "local-vips");
+ list_vips(this, b, ike_sa, FALSE, "remote-vips");
+
list_task_queue(this, b, ike_sa, TASK_QUEUE_QUEUED, "tasks-queued");
list_task_queue(this, b, ike_sa, TASK_QUEUE_ACTIVE, "tasks-active");
list_task_queue(this, b, ike_sa, TASK_QUEUE_PASSIVE, "tasks-passive");
diff --git a/src/libcharon/processing/jobs/initiate_mediation_job.c b/src/libcharon/processing/jobs/initiate_mediation_job.c
index 5b5fb9d98..6c01ffe95 100644
--- a/src/libcharon/processing/jobs/initiate_mediation_job.c
+++ b/src/libcharon/processing/jobs/initiate_mediation_job.c
@@ -161,6 +161,10 @@ METHOD(job_t, initiate, job_requeue_t,
}
mediated_cfg->destroy(mediated_cfg);
}
+ else
+ { /* newly created IKE_SA is not checked in yet, try again */
+ return JOB_RESCHEDULE_MS(100);
+ }
return JOB_REQUEUE_NONE;
}
diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c
index 73f2ec9d3..b0f163c83 100644
--- a/src/libcharon/sa/child_sa.c
+++ b/src/libcharon/sa/child_sa.c
@@ -413,8 +413,14 @@ METHOD(enumerator_t, policy_enumerate, bool,
{ /* protocol mismatch */
continue;
}
- *my_out = this->ts;
- *other_out = other_ts;
+ if (my_out)
+ {
+ *my_out = this->ts;
+ }
+ if (other_out)
+ {
+ *other_out = other_ts;
+ }
return TRUE;
}
return FALSE;
@@ -775,6 +781,50 @@ static bool require_policy_update()
}
/**
+ * Prepare SA config to install/delete policies
+ */
+static void prepare_sa_cfg(private_child_sa_t *this, ipsec_sa_cfg_t *my_sa,
+ ipsec_sa_cfg_t *other_sa)
+{
+ enumerator_t *enumerator;
+
+ *my_sa = (ipsec_sa_cfg_t){
+ .mode = this->mode,
+ .reqid = this->reqid,
+ .ipcomp = {
+ .transform = this->ipcomp,
+ },
+ };
+ *other_sa = *my_sa;
+
+ my_sa->ipcomp.cpi = this->my_cpi;
+ other_sa->ipcomp.cpi = this->other_cpi;
+
+ if (this->protocol == PROTO_ESP)
+ {
+ my_sa->esp.use = TRUE;
+ my_sa->esp.spi = this->my_spi;
+ other_sa->esp.use = TRUE;
+ other_sa->esp.spi = this->other_spi;
+ }
+ else
+ {
+ my_sa->ah.use = TRUE;
+ my_sa->ah.spi = this->my_spi;
+ other_sa->ah.use = TRUE;
+ other_sa->ah.spi = this->other_spi;
+ }
+
+ enumerator = create_policy_enumerator(this);
+ while (enumerator->enumerate(enumerator, NULL, NULL))
+ {
+ my_sa->policy_count++;
+ other_sa->policy_count++;
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
* Install 3 policies: out, in and forward
*/
static status_t install_policies_internal(private_child_sa_t *this,
@@ -806,20 +856,22 @@ static status_t install_policies_internal(private_child_sa_t *this,
* Delete 3 policies: out, in and forward
*/
static void del_policies_internal(private_child_sa_t *this,
- traffic_selector_t *my_ts, traffic_selector_t *other_ts,
- policy_priority_t priority)
+ host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
+ traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
+ ipsec_sa_cfg_t *other_sa, policy_type_t type, policy_priority_t priority)
{
+
hydra->kernel_interface->del_policy(hydra->kernel_interface,
- my_ts, other_ts, POLICY_OUT, this->reqid,
- this->mark_out, priority);
+ my_addr, other_addr, my_ts, other_ts, POLICY_OUT, type,
+ other_sa, this->mark_out, priority);
hydra->kernel_interface->del_policy(hydra->kernel_interface,
- other_ts, my_ts, POLICY_IN, this->reqid,
- this->mark_in, priority);
+ other_addr, my_addr, other_ts, my_ts, POLICY_IN,
+ type, my_sa, this->mark_in, priority);
if (this->mode != MODE_TRANSPORT)
{
hydra->kernel_interface->del_policy(hydra->kernel_interface,
- other_ts, my_ts, POLICY_FWD, this->reqid,
- this->mark_in, priority);
+ other_addr, my_addr, other_ts, my_ts, POLICY_FWD,
+ type, my_sa, this->mark_in, priority);
}
}
@@ -864,31 +916,9 @@ METHOD(child_sa_t, add_policies, status_t,
if (this->config->install_policy(this->config))
{
policy_priority_t priority;
- ipsec_sa_cfg_t my_sa = {
- .mode = this->mode,
- .reqid = this->reqid,
- .ipcomp = {
- .transform = this->ipcomp,
- },
- }, other_sa = my_sa;
-
- my_sa.ipcomp.cpi = this->my_cpi;
- other_sa.ipcomp.cpi = this->other_cpi;
-
- if (this->protocol == PROTO_ESP)
- {
- my_sa.esp.use = TRUE;
- my_sa.esp.spi = this->my_spi;
- other_sa.esp.use = TRUE;
- other_sa.esp.spi = this->other_spi;
- }
- else
- {
- my_sa.ah.use = TRUE;
- my_sa.ah.spi = this->my_spi;
- other_sa.ah.use = TRUE;
- other_sa.ah.spi = this->other_spi;
- }
+ ipsec_sa_cfg_t my_sa, other_sa;
+
+ prepare_sa_cfg(this, &my_sa, &other_sa);
/* if we're not in state CHILD_INSTALLING (i.e. if there is no SAD
* entry) we install a trap policy */
@@ -896,14 +926,6 @@ METHOD(child_sa_t, add_policies, status_t,
priority = this->trap ? POLICY_PRIORITY_ROUTED
: POLICY_PRIORITY_DEFAULT;
- enumerator = create_policy_enumerator(this);
- while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
- {
- my_sa.policy_count++;
- other_sa.policy_count++;
- }
- enumerator->destroy(enumerator);
-
/* enumerate pairs of traffic selectors */
enumerator = create_policy_enumerator(this);
while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
@@ -1006,47 +1028,24 @@ METHOD(child_sa_t, update, status_t,
if (this->config->install_policy(this->config) && require_policy_update())
{
- ipsec_sa_cfg_t my_sa = {
- .mode = this->mode,
- .reqid = this->reqid,
- .ipcomp = {
- .transform = this->ipcomp,
- },
- }, other_sa = my_sa;
-
- my_sa.ipcomp.cpi = this->my_cpi;
- other_sa.ipcomp.cpi = this->other_cpi;
-
- if (this->protocol == PROTO_ESP)
- {
- my_sa.esp.use = TRUE;
- my_sa.esp.spi = this->my_spi;
- other_sa.esp.use = TRUE;
- other_sa.esp.spi = this->other_spi;
- }
- else
- {
- my_sa.ah.use = TRUE;
- my_sa.ah.spi = this->my_spi;
- other_sa.ah.use = TRUE;
- other_sa.ah.spi = this->other_spi;
- }
-
- /* update policies */
if (!me->ip_equals(me, this->my_addr) ||
!other->ip_equals(other, this->other_addr))
{
+ ipsec_sa_cfg_t my_sa, other_sa;
enumerator_t *enumerator;
traffic_selector_t *my_ts, *other_ts;
+ prepare_sa_cfg(this, &my_sa, &other_sa);
+
/* always use high priorities, as hosts getting updated are INSTALLED */
enumerator = create_policy_enumerator(this);
while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
{
traffic_selector_t *old_my_ts = NULL, *old_other_ts = NULL;
/* remove old policies first */
- del_policies_internal(this, my_ts, other_ts,
- POLICY_PRIORITY_DEFAULT);
+ del_policies_internal(this, this->my_addr, this->other_addr,
+ my_ts, other_ts, &my_sa, &other_sa,
+ POLICY_IPSEC, POLICY_PRIORITY_DEFAULT);
/* check if we have to update a "dynamic" traffic selector */
if (!me->ip_equals(me, this->my_addr) &&
@@ -1068,21 +1067,20 @@ METHOD(child_sa_t, update, status_t,
/* reinstall updated policies */
install_policies_internal(this, me, other, my_ts, other_ts,
- &my_sa, &other_sa, POLICY_IPSEC,
- POLICY_PRIORITY_DEFAULT);
+ &my_sa, &other_sa, POLICY_IPSEC,
+ POLICY_PRIORITY_DEFAULT);
/* update fallback policies after the new policy is in place */
- if (old_my_ts || old_other_ts)
- {
- del_policies_internal(this, old_my_ts ?: my_ts,
- old_other_ts ?: other_ts,
+ del_policies_internal(this, this->my_addr, this->other_addr,
+ old_my_ts ?: my_ts,
+ old_other_ts ?: other_ts,
+ &my_sa, &other_sa, POLICY_DROP,
+ POLICY_PRIORITY_FALLBACK);
+ install_policies_internal(this, me, other, my_ts, other_ts,
+ &my_sa, &other_sa, POLICY_DROP,
POLICY_PRIORITY_FALLBACK);
- install_policies_internal(this, me, other, my_ts, other_ts,
- &my_sa, &other_sa, POLICY_DROP,
- POLICY_PRIORITY_FALLBACK);
- DESTROY_IF(old_my_ts);
- DESTROY_IF(old_other_ts);
- }
+ DESTROY_IF(old_my_ts);
+ DESTROY_IF(old_other_ts);
}
enumerator->destroy(enumerator);
}
@@ -1122,15 +1120,21 @@ METHOD(child_sa_t, destroy, void,
if (this->config->install_policy(this->config))
{
+ ipsec_sa_cfg_t my_sa, other_sa;
+
+ prepare_sa_cfg(this, &my_sa, &other_sa);
+
/* delete all policies in the kernel */
enumerator = create_policy_enumerator(this);
while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
{
- del_policies_internal(this, my_ts, other_ts, priority);
+ del_policies_internal(this, this->my_addr, this->other_addr,
+ my_ts, other_ts, &my_sa, &other_sa, POLICY_IPSEC, priority);
if (priority == POLICY_PRIORITY_DEFAULT && require_policy_update())
{
- del_policies_internal(this, my_ts, other_ts,
- POLICY_PRIORITY_FALLBACK);
+ del_policies_internal(this, this->my_addr, this->other_addr,
+ my_ts, other_ts, &my_sa, &other_sa, POLICY_DROP,
+ POLICY_PRIORITY_FALLBACK);
}
}
enumerator->destroy(enumerator);
diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c
index 37d69874d..4625df5b8 100644
--- a/src/libcharon/sa/ike_sa_manager.c
+++ b/src/libcharon/sa/ike_sa_manager.c
@@ -394,9 +394,17 @@ struct private_ike_sa_manager_t {
rng_t *rng;
/**
- * Lock to access the RNG instance
+ * Registered callback for IKE SPIs
*/
- rwlock_t *rng_lock;
+ struct {
+ spi_cb_t cb;
+ void *data;
+ } spi_cb;
+
+ /**
+ * Lock to access the RNG instance and the callback
+ */
+ rwlock_t *spi_lock;
/**
* reuse existing IKE_SAs in checkout_by_config
@@ -971,13 +979,17 @@ static u_int64_t get_spi(private_ike_sa_manager_t *this)
{
u_int64_t spi;
- this->rng_lock->read_lock(this->rng_lock);
- if (!this->rng ||
- !this->rng->get_bytes(this->rng, sizeof(spi), (u_int8_t*)&spi))
+ this->spi_lock->read_lock(this->spi_lock);
+ if (this->spi_cb.cb)
+ {
+ spi = this->spi_cb.cb(this->spi_cb.data);
+ }
+ else if (!this->rng ||
+ !this->rng->get_bytes(this->rng, sizeof(spi), (u_int8_t*)&spi))
{
spi = 0;
}
- this->rng_lock->unlock(this->rng_lock);
+ this->spi_lock->unlock(this->spi_lock);
return spi;
}
@@ -1188,11 +1200,15 @@ METHOD(ike_sa_manager_t, checkout_new, ike_sa_t*,
*/
static u_int32_t get_message_id_or_hash(message_t *message)
{
- /* Use the message ID, or the message hash in IKEv1 Main/Aggressive mode */
- if (message->get_major_version(message) == IKEV1_MAJOR_VERSION &&
- message->get_message_id(message) == 0)
+ if (message->get_major_version(message) == IKEV1_MAJOR_VERSION)
{
- return chunk_hash(message->get_packet_data(message));
+ /* Use a hash for IKEv1 Phase 1, where we don't have a MID, and Quick
+ * Mode, where all three messages use the same message ID */
+ if (message->get_message_id(message) == 0 ||
+ message->get_exchange_type(message) == QUICK_MODE)
+ {
+ return chunk_hash(message->get_packet_data(message));
+ }
}
return message->get_message_id(message);
}
@@ -1384,7 +1400,8 @@ METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*,
continue;
}
if (entry->ike_sa->get_state(entry->ike_sa) == IKE_DELETING)
- { /* skip IKE_SAs which are not usable */
+ { /* skip IKE_SAs which are not usable, wake other waiting threads */
+ entry->condvar->signal(entry->condvar);
continue;
}
@@ -1402,6 +1419,8 @@ METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*,
break;
}
}
+ /* other threads might be waiting for this entry */
+ entry->condvar->signal(entry->condvar);
}
enumerator->destroy(enumerator);
@@ -1434,6 +1453,8 @@ METHOD(ike_sa_manager_t, checkout_by_id, ike_sa_t*,
entry->checked_out = TRUE;
break;
}
+ /* other threads might be waiting for this entry */
+ entry->condvar->signal(entry->condvar);
}
}
enumerator->destroy(enumerator);
@@ -1490,6 +1511,8 @@ METHOD(ike_sa_manager_t, checkout_by_name, ike_sa_t*,
ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa));
break;
}
+ /* other threads might be waiting for this entry */
+ entry->condvar->signal(entry->condvar);
}
}
enumerator->destroy(enumerator);
@@ -1628,8 +1651,27 @@ METHOD(ike_sa_manager_t, checkin, void,
* delete any existing IKE_SAs with that peer. */
if (ike_sa->has_condition(ike_sa, COND_INIT_CONTACT_SEEN))
{
+ /* We can't hold the segment locked while checking the
+ * uniqueness as this could lead to deadlocks. We mark the
+ * entry as checked out while we release the lock so no other
+ * thread can acquire it. Since it is not yet in the list of
+ * connected peers that will not cause a deadlock as no other
+ * caller of check_unqiueness() will try to check out this SA */
+ entry->checked_out = TRUE;
+ unlock_single_segment(this, segment);
+
this->public.check_uniqueness(&this->public, ike_sa, TRUE);
ike_sa->set_condition(ike_sa, COND_INIT_CONTACT_SEEN, FALSE);
+
+ /* The entry could have been modified in the mean time, e.g.
+ * because another SA was added/removed next to it or another
+ * thread is waiting, but it should still exist, so there is no
+ * need for a lookup via get_entry_by... */
+ lock_single_segment(this, segment);
+ entry->checked_out = FALSE;
+ /* We already signaled waiting threads above, we have to do that
+ * again after checking the SA out and back in again. */
+ entry->condvar->signal(entry->condvar);
}
}
@@ -2010,6 +2052,15 @@ METHOD(ike_sa_manager_t, get_half_open_count, u_int,
return count;
}
+METHOD(ike_sa_manager_t, set_spi_cb, void,
+ private_ike_sa_manager_t *this, spi_cb_t callback, void *data)
+{
+ this->spi_lock->write_lock(this->spi_lock);
+ this->spi_cb.cb = callback;
+ this->spi_cb.data = data;
+ this->spi_lock->unlock(this->spi_lock);
+}
+
METHOD(ike_sa_manager_t, flush, void,
private_ike_sa_manager_t *this)
{
@@ -2092,10 +2143,12 @@ METHOD(ike_sa_manager_t, flush, void,
charon->bus->set_sa(charon->bus, NULL);
unlock_all_segments(this);
- this->rng_lock->write_lock(this->rng_lock);
+ this->spi_lock->write_lock(this->spi_lock);
this->rng->destroy(this->rng);
this->rng = NULL;
- this->rng_lock->unlock(this->rng_lock);
+ this->spi_cb.cb = NULL;
+ this->spi_cb.data = NULL;
+ this->spi_lock->unlock(this->spi_lock);
}
METHOD(ike_sa_manager_t, destroy, void,
@@ -2120,7 +2173,7 @@ METHOD(ike_sa_manager_t, destroy, void,
free(this->connected_peers_segments);
free(this->init_hashes_segments);
- this->rng_lock->destroy(this->rng_lock);
+ this->spi_lock->destroy(this->spi_lock);
free(this);
}
@@ -2167,6 +2220,7 @@ ike_sa_manager_t *ike_sa_manager_create()
.get_count = _get_count,
.get_half_open_count = _get_half_open_count,
.flush = _flush,
+ .set_spi_cb = _set_spi_cb,
.destroy = _destroy,
},
);
@@ -2178,7 +2232,7 @@ ike_sa_manager_t *ike_sa_manager_create()
free(this);
return NULL;
}
- this->rng_lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
+ this->spi_lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
this->ikesa_limit = lib->settings->get_int(lib->settings,
"%s.ikesa_limit", 0, lib->ns);
diff --git a/src/libcharon/sa/ike_sa_manager.h b/src/libcharon/sa/ike_sa_manager.h
index 3ea928ea5..f1b7c2579 100644
--- a/src/libcharon/sa/ike_sa_manager.h
+++ b/src/libcharon/sa/ike_sa_manager.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Tobias Brunner
+ * Copyright (C) 2008-2015 Tobias Brunner
* Copyright (C) 2005-2008 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -31,6 +31,16 @@ typedef struct ike_sa_manager_t ike_sa_manager_t;
#include <config/peer_cfg.h>
/**
+ * Callback called to generate an IKE SPI.
+ *
+ * This may be called from multiple threads concurrently.
+ *
+ * @param data data supplied during registration of the callback
+ * @return allocated SPI, 0 on failure
+ */
+typedef u_int64_t (*spi_cb_t)(void *data);
+
+/**
* Manages and synchronizes access to all IKE_SAs.
*
* To synchronize access to thread-unsave IKE_SAs, they are checked out for
@@ -227,6 +237,15 @@ struct ike_sa_manager_t {
bool responder_only);
/**
+ * Set the callback to generate IKE SPIs
+ *
+ * @param callback callback to register
+ * @param data data provided to callback
+ */
+ void (*set_spi_cb)(ike_sa_manager_t *this, spi_cb_t callback,
+ void *data);
+
+ /**
* Delete all existing IKE_SAs and destroy them immediately.
*
* Threads will be driven out, so all SAs can be deleted cleanly.
diff --git a/src/libcharon/sa/ikev1/keymat_v1.c b/src/libcharon/sa/ikev1/keymat_v1.c
index f5a91dbeb..e428966ad 100644
--- a/src/libcharon/sa/ikev1/keymat_v1.c
+++ b/src/libcharon/sa/ikev1/keymat_v1.c
@@ -23,14 +23,9 @@
typedef struct private_keymat_v1_t private_keymat_v1_t;
/**
- * Max. number of IVs to track.
+ * Max. number of IVs/QMs to track.
*/
-#define MAX_IV 3
-
-/**
- * Max. number of Quick Modes to track.
- */
-#define MAX_QM 2
+#define MAX_EXCHANGES_DEFAULT 3
/**
* Data stored for IVs
@@ -110,6 +105,11 @@ struct private_keymat_v1_t {
* of QMs are tracked at the same time. Stores qm_data_t objects.
*/
linked_list_t *qms;
+
+ /**
+ * Max. number of IVs/Quick Modes to track.
+ */
+ int max_exchanges;
};
@@ -874,7 +874,7 @@ static qm_data_t *lookup_quick_mode(private_keymat_v1_t *this, u_int32_t mid)
}
this->qms->insert_first(this->qms, found);
/* remove least recently used state if maximum reached */
- if (this->qms->get_count(this->qms) > MAX_QM &&
+ if (this->qms->get_count(this->qms) > this->max_exchanges &&
this->qms->remove_last(this->qms, (void**)&qm) == SUCCESS)
{
qm_data_destroy(qm);
@@ -1048,7 +1048,7 @@ static iv_data_t *lookup_iv(private_keymat_v1_t *this, u_int32_t mid)
}
this->ivs->insert_first(this->ivs, found);
/* remove least recently used IV if maximum reached */
- if (this->ivs->get_count(this->ivs) > MAX_IV &&
+ if (this->ivs->get_count(this->ivs) > this->max_exchanges &&
this->ivs->remove_last(this->ivs, (void**)&iv) == SUCCESS)
{
iv_data_destroy(iv);
@@ -1163,6 +1163,8 @@ keymat_v1_t *keymat_v1_create(bool initiator)
.ivs = linked_list_create(),
.qms = linked_list_create(),
.initiator = initiator,
+ .max_exchanges = lib->settings->get_int(lib->settings,
+ "%s.max_ikev1_exchanges", MAX_EXCHANGES_DEFAULT, lib->ns),
);
return &this->public;
diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c
index 678f99df1..3c601a4fa 100644
--- a/src/libcharon/sa/ikev1/task_manager_v1.c
+++ b/src/libcharon/sa/ikev1/task_manager_v1.c
@@ -752,6 +752,12 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
case ALREADY_DONE:
cancelled = TRUE;
break;
+ case INVALID_ARG:
+ if (task->get_type(task) == TASK_QUICK_MODE)
+ { /* not responsible for this exchange */
+ continue;
+ }
+ /* FALL */
case FAILED:
default:
charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
@@ -929,6 +935,28 @@ static bool have_quick_mode_task(private_task_manager_t *this, u_int32_t mid)
}
/**
+ * Check if we still have an aggressive mode task queued
+ */
+static bool have_aggressive_mode_task(private_task_manager_t *this)
+{
+ enumerator_t *enumerator;
+ task_t *task;
+ bool found = FALSE;
+
+ enumerator = this->passive_tasks->create_enumerator(this->passive_tasks);
+ while (enumerator->enumerate(enumerator, &task))
+ {
+ if (task->get_type(task) == TASK_AGGRESSIVE_MODE)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return found;
+}
+
+/**
* handle an incoming request message
*/
static status_t process_request(private_task_manager_t *this,
@@ -1034,6 +1062,12 @@ static status_t process_request(private_task_manager_t *this,
case ALREADY_DONE:
send_response = FALSE;
break;
+ case INVALID_ARG:
+ if (task->get_type(task) == TASK_QUICK_MODE)
+ { /* not responsible for this exchange */
+ continue;
+ }
+ /* FALL */
case FAILED:
default:
charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
@@ -1061,6 +1095,22 @@ static status_t process_request(private_task_manager_t *this,
* the same message again. */
clear_packets(this->responding.packets);
}
+ if (this->queued &&
+ this->queued->get_exchange_type(this->queued) == INFORMATIONAL_V1)
+ {
+ message_t *queued;
+ status_t status;
+
+ queued = this->queued;
+ this->queued = NULL;
+ status = this->public.task_manager.process_message(
+ &this->public.task_manager, queued);
+ queued->destroy(queued);
+ if (status == DESTROY_ME)
+ {
+ return status;
+ }
+ }
if (this->passive_tasks->get_count(this->passive_tasks) == 0 &&
this->queued_tasks->get_count(this->queued_tasks) > 0)
{
@@ -1133,7 +1183,8 @@ static status_t process_response(private_task_manager_t *this,
this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
clear_packets(this->initiating.packets);
- if (this->queued && this->active_tasks->get_count(this->active_tasks) == 0)
+ if (this->queued && !this->active_tasks->get_count(this->active_tasks) &&
+ this->queued->get_exchange_type(this->queued) == TRANSACTION)
{
queued = this->queued;
this->queued = NULL;
@@ -1228,6 +1279,29 @@ static status_t parse_message(private_task_manager_t *this, message_t *msg)
return status;
}
+/**
+ * Queue the given message if possible
+ */
+static status_t queue_message(private_task_manager_t *this, message_t *msg)
+{
+ if (this->queued)
+ {
+ DBG1(DBG_IKE, "ignoring %N request, queue full",
+ exchange_type_names, msg->get_exchange_type(msg));
+ return FAILED;
+ }
+ this->queued = message_create_from_packet(msg->get_packet(msg));
+ if (this->queued->parse_header(this->queued) != SUCCESS)
+ {
+ this->queued->destroy(this->queued);
+ this->queued = NULL;
+ return FAILED;
+ }
+ DBG1(DBG_IKE, "queueing %N request as tasks still active",
+ exchange_type_names, msg->get_exchange_type(msg));
+ return SUCCESS;
+}
+
METHOD(task_manager_t, process_message, status_t,
private_task_manager_t *this, message_t *msg)
{
@@ -1328,25 +1402,29 @@ METHOD(task_manager_t, process_message, status_t,
}
}
- if (msg->get_exchange_type(msg) == TRANSACTION &&
- this->active_tasks->get_count(this->active_tasks))
- { /* main mode not yet complete, queue XAuth/Mode config tasks */
- if (this->queued)
+ /* drop XAuth/Mode Config/Quick Mode messages until we received the last
+ * Aggressive Mode message. since Informational messages are not
+ * retransmitted we queue them. */
+ if (have_aggressive_mode_task(this))
+ {
+ if (msg->get_exchange_type(msg) == INFORMATIONAL_V1)
{
- DBG1(DBG_IKE, "ignoring additional %N request, queue full",
- exchange_type_names, TRANSACTION);
- return SUCCESS;
+ return queue_message(this, msg);
}
- this->queued = message_create_from_packet(msg->get_packet(msg));
- if (this->queued->parse_header(this->queued) != SUCCESS)
+ else if (msg->get_exchange_type(msg) != AGGRESSIVE)
{
- this->queued->destroy(this->queued);
- this->queued = NULL;
+ DBG1(DBG_IKE, "ignoring %N request while phase 1 is incomplete",
+ exchange_type_names, msg->get_exchange_type(msg));
return FAILED;
}
- DBG1(DBG_IKE, "queueing %N request as tasks still active",
- exchange_type_names, TRANSACTION);
- return SUCCESS;
+ }
+
+ /* queue XAuth/Mode Config messages unless the Main Mode exchange we
+ * initiated is complete */
+ if (msg->get_exchange_type(msg) == TRANSACTION &&
+ this->active_tasks->get_count(this->active_tasks))
+ {
+ return queue_message(this, msg);
}
msg->set_request(msg, TRUE);
@@ -1724,6 +1802,8 @@ METHOD(task_manager_t, queue_dpd, void,
pow(this->retransmit_base, retransmit));
}
}
+ /* compensate for the already elapsed dpd delay */
+ t -= 1000 * peer_cfg->get_dpd(peer_cfg);
/* schedule DPD timeout job */
lib->scheduler->schedule_job_ms(lib->scheduler,
diff --git a/src/libcharon/sa/ikev1/tasks/mode_config.c b/src/libcharon/sa/ikev1/tasks/mode_config.c
index d0994a961..a03477e18 100644
--- a/src/libcharon/sa/ikev1/tasks/mode_config.c
+++ b/src/libcharon/sa/ikev1/tasks/mode_config.c
@@ -482,7 +482,9 @@ static host_t *assign_migrated_vip(linked_list_t *migrated, host_t *requested)
enumerator = migrated->create_enumerator(migrated);
while (enumerator->enumerate(enumerator, &vip))
{
- if (vip->ip_equals(vip, requested))
+ if (vip->ip_equals(vip, requested) ||
+ (requested->is_anyaddr(requested) &&
+ requested->get_family(requested) == vip->get_family(vip)))
{
migrated->remove_at(migrated, enumerator);
found = vip;
diff --git a/src/libcharon/sa/ikev1/tasks/quick_delete.c b/src/libcharon/sa/ikev1/tasks/quick_delete.c
index 1b95a8b11..ade59a2dd 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_delete.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_delete.c
@@ -115,7 +115,7 @@ static bool delete_child(private_quick_delete_t *this, protocol_id_t protocol,
if (this->expired)
{
DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} "
- "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
+ "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
ntohl(child_sa->get_spi(child_sa, TRUE)),
ntohl(child_sa->get_spi(child_sa, FALSE)), my_ts, other_ts);
@@ -126,7 +126,7 @@ static bool delete_child(private_quick_delete_t *this, protocol_id_t protocol,
child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out, NULL);
DBG0(DBG_IKE, "closing CHILD_SA %s{%d} with SPIs "
- "%.8x_i (%llu bytes) %.8x_o (%llu bytes) and TS %#R=== %#R",
+ "%.8x_i (%llu bytes) %.8x_o (%llu bytes) and TS %#R === %#R",
child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c
index d6a3f2cd1..e7d26443b 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c
@@ -388,7 +388,7 @@ static bool install(private_quick_mode_t *this)
this->child_sa->create_ts_enumerator(this->child_sa, FALSE));
DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
- "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
+ "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
this->child_sa->get_name(this->child_sa),
this->child_sa->get_unique_id(this->child_sa),
ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
@@ -1026,7 +1026,7 @@ METHOD(task_t, process_r, status_t,
{
if (this->mid && this->mid != message->get_message_id(message))
{ /* not responsible for this quick mode exchange */
- return NEED_MORE;
+ return INVALID_ARG;
}
switch (this->state)
@@ -1200,7 +1200,7 @@ METHOD(task_t, build_r, status_t,
{
if (this->mid && this->mid != message->get_message_id(message))
{ /* not responsible for this quick mode exchange */
- return NEED_MORE;
+ return INVALID_ARG;
}
switch (this->state)
diff --git a/src/libcharon/sa/ikev1/tasks/xauth.c b/src/libcharon/sa/ikev1/tasks/xauth.c
index a770e90ff..c0c91574c 100644
--- a/src/libcharon/sa/ikev1/tasks/xauth.c
+++ b/src/libcharon/sa/ikev1/tasks/xauth.c
@@ -271,7 +271,10 @@ static bool add_auth_cfg(private_xauth_t *this, identification_t *id, bool local
auth = auth_cfg_create();
auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH);
- auth->add(auth, AUTH_RULE_XAUTH_IDENTITY, id->clone(id));
+ if (id)
+ {
+ auth->add(auth, AUTH_RULE_XAUTH_IDENTITY, id->clone(id));
+ }
auth->merge(auth, this->ike_sa->get_auth_cfg(this->ike_sa, local), FALSE);
this->ike_sa->add_auth_cfg(this->ike_sa, local, auth);
@@ -342,7 +345,10 @@ METHOD(task_t, build_i, status_t,
break;
case SUCCESS:
DESTROY_IF(cp);
- this->status = XAUTH_OK;
+ if (add_auth_cfg(this, NULL, FALSE) && allowed(this))
+ {
+ this->status = XAUTH_OK;
+ }
this->public.task.process = _process_i_status;
return build_i_status(this, message);
default:
diff --git a/src/libcharon/sa/ikev2/keymat_v2.c b/src/libcharon/sa/ikev2/keymat_v2.c
index fce0840e3..55cb5dd9c 100644
--- a/src/libcharon/sa/ikev2/keymat_v2.c
+++ b/src/libcharon/sa/ikev2/keymat_v2.c
@@ -527,6 +527,7 @@ METHOD(keymat_v2_t, derive_child_keys, bool,
case ENCR_AES_GCM_ICV12:
case ENCR_AES_GCM_ICV16:
case ENCR_AES_CTR:
+ case ENCR_CAMELLIA_CTR:
case ENCR_NULL_AUTH_AES_GMAC:
case ENCR_CHACHA20_POLY1305:
enc_size += 4;
diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c
index e08f3dab1..97f73d851 100644
--- a/src/libcharon/sa/ikev2/tasks/child_create.c
+++ b/src/libcharon/sa/ikev2/tasks/child_create.c
@@ -712,7 +712,7 @@ static status_t select_and_install(private_child_create_t *this,
this->child_sa->create_ts_enumerator(this->child_sa, FALSE));
DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
- "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
+ "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
this->child_sa->get_name(this->child_sa),
this->child_sa->get_unique_id(this->child_sa),
ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
@@ -1245,7 +1245,7 @@ METHOD(task_t, build_r, status_t,
}
if (this->config == NULL)
{
- DBG1(DBG_IKE, "traffic selectors %#R=== %#R inacceptable",
+ DBG1(DBG_IKE, "traffic selectors %#R === %#R inacceptable",
this->tsr, this->tsi);
charon->bus->alert(charon->bus, ALERT_TS_MISMATCH, this->tsi, this->tsr);
message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
diff --git a/src/libcharon/sa/ikev2/tasks/child_delete.c b/src/libcharon/sa/ikev2/tasks/child_delete.c
index f0b11e291..877ae0531 100644
--- a/src/libcharon/sa/ikev2/tasks/child_delete.c
+++ b/src/libcharon/sa/ikev2/tasks/child_delete.c
@@ -266,7 +266,7 @@ static void log_children(private_child_delete_t *this)
if (this->expired)
{
DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} "
- "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
+ "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
ntohl(child_sa->get_spi(child_sa, TRUE)),
ntohl(child_sa->get_spi(child_sa, FALSE)), my_ts, other_ts);
@@ -277,7 +277,7 @@ static void log_children(private_child_delete_t *this)
child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out, NULL);
DBG0(DBG_IKE, "closing CHILD_SA %s{%d} with SPIs %.8x_i "
- "(%llu bytes) %.8x_o (%llu bytes) and TS %#R=== %#R",
+ "(%llu bytes) %.8x_o (%llu bytes) and TS %#R === %#R",
child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
diff --git a/src/libcharon/sa/ikev2/tasks/ike_mobike.c b/src/libcharon/sa/ikev2/tasks/ike_mobike.c
index 11b0bb281..cbdc5e797 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_mobike.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_mobike.c
@@ -339,7 +339,11 @@ METHOD(ike_mobike_t, transmit, bool,
{
if (me->ip_equals(me, me_old))
{
- charon->sender->send(charon->sender, packet->clone(packet));
+ copy = packet->clone(packet);
+ /* hosts might have been updated by a peer's MOBIKE exchange */
+ copy->set_source(copy, me_old->clone(me_old));
+ copy->set_destination(copy, other_old->clone(other_old));
+ charon->sender->send(charon->sender, copy);
me->destroy(me);
return TRUE;
}
diff --git a/src/libcharon/sa/ikev2/tasks/ike_natd.c b/src/libcharon/sa/ikev2/tasks/ike_natd.c
index 9e0eb68ce..dd34c1234 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_natd.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_natd.c
@@ -129,25 +129,6 @@ static chunk_t generate_natd_hash(private_ike_natd_t *this,
}
/**
- * build a faked NATD payload to enforce UDP encap
- */
-static chunk_t generate_natd_hash_faked(private_ike_natd_t *this)
-{
- rng_t *rng;
- chunk_t chunk;
-
- rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
- if (!rng || !rng->allocate_bytes(rng, HASH_SIZE_SHA1, &chunk))
- {
- DBG1(DBG_IKE, "unable to get random bytes for NATD fake");
- DESTROY_IF(rng);
- return chunk_empty;
- }
- rng->destroy(rng);
- return chunk;
-}
-
-/**
* Build a NAT detection notify payload.
*/
static notify_payload_t *build_natd_payload(private_ike_natd_t *this,
@@ -162,7 +143,14 @@ static notify_payload_t *build_natd_payload(private_ike_natd_t *this,
config = this->ike_sa->get_ike_cfg(this->ike_sa);
if (force_encap(config) && type == NAT_DETECTION_SOURCE_IP)
{
- hash = generate_natd_hash_faked(this);
+ u_int32_t addr;
+
+ /* chunk_hash() is randomly keyed so this produces a random IPv4 address
+ * that changes with every restart but otherwise stays the same */
+ addr = chunk_hash(chunk_from_chars(0x00, 0x00, 0x00, 0x00));
+ host = host_create_from_chunk(AF_INET, chunk_from_thing(addr), 0);
+ hash = generate_natd_hash(this, ike_sa_id, host);
+ host->destroy(host);
}
else
{
diff --git a/src/libcharon/sa/shunt_manager.c b/src/libcharon/sa/shunt_manager.c
index 1a984435c..5231994c8 100644
--- a/src/libcharon/sa/shunt_manager.c
+++ b/src/libcharon/sa/shunt_manager.c
@@ -63,9 +63,9 @@ struct private_shunt_manager_t {
static bool install_shunt_policy(child_cfg_t *child)
{
enumerator_t *e_my_ts, *e_other_ts;
- linked_list_t *my_ts_list, *other_ts_list;
+ linked_list_t *my_ts_list, *other_ts_list, *hosts;
traffic_selector_t *my_ts, *other_ts;
- host_t *host_any;
+ host_t *host_any, *host_any6;
policy_type_t policy_type;
policy_priority_t policy_prio;
status_t status = SUCCESS;
@@ -85,9 +85,13 @@ static bool install_shunt_policy(child_cfg_t *child)
return FALSE;
}
- my_ts_list = child->get_traffic_selectors(child, TRUE, NULL, NULL);
- other_ts_list = child->get_traffic_selectors(child, FALSE, NULL, NULL);
host_any = host_create_any(AF_INET);
+ host_any6 = host_create_any(AF_INET6);
+
+ hosts = linked_list_create_with_items(host_any, host_any6, NULL);
+ my_ts_list = child->get_traffic_selectors(child, TRUE, NULL, hosts);
+ other_ts_list = child->get_traffic_selectors(child, FALSE, NULL, hosts);
+ hosts->destroy(hosts);
/* enumerate pairs of traffic selectors */
e_my_ts = my_ts_list->create_enumerator(my_ts_list);
@@ -96,6 +100,16 @@ static bool install_shunt_policy(child_cfg_t *child)
e_other_ts = other_ts_list->create_enumerator(other_ts_list);
while (e_other_ts->enumerate(e_other_ts, &other_ts))
{
+ if (my_ts->get_type(my_ts) != other_ts->get_type(other_ts))
+ {
+ continue;
+ }
+ if (my_ts->get_protocol(my_ts) &&
+ other_ts->get_protocol(other_ts) &&
+ my_ts->get_protocol(my_ts) != other_ts->get_protocol(other_ts))
+ {
+ continue;
+ }
/* install out policy */
status |= hydra->kernel_interface->add_policy(
hydra->kernel_interface, host_any, host_any,
@@ -125,6 +139,7 @@ static bool install_shunt_policy(child_cfg_t *child)
offsetof(traffic_selector_t, destroy));
other_ts_list->destroy_offset(other_ts_list,
offsetof(traffic_selector_t, destroy));
+ host_any6->destroy(host_any6);
host_any->destroy(host_any);
return status == SUCCESS;
@@ -185,25 +200,35 @@ METHOD(shunt_manager_t, install, bool,
static void uninstall_shunt_policy(child_cfg_t *child)
{
enumerator_t *e_my_ts, *e_other_ts;
- linked_list_t *my_ts_list, *other_ts_list;
+ linked_list_t *my_ts_list, *other_ts_list, *hosts;
traffic_selector_t *my_ts, *other_ts;
+ host_t *host_any, *host_any6;
+ policy_type_t policy_type;
policy_priority_t policy_prio;
status_t status = SUCCESS;
+ ipsec_sa_cfg_t sa = { .mode = MODE_TRANSPORT };
switch (child->get_mode(child))
{
case MODE_PASS:
+ policy_type = POLICY_PASS;
policy_prio = POLICY_PRIORITY_PASS;
break;
case MODE_DROP:
+ policy_type = POLICY_DROP;
policy_prio = POLICY_PRIORITY_FALLBACK;
break;
default:
return;
}
- my_ts_list = child->get_traffic_selectors(child, TRUE, NULL, NULL);
- other_ts_list = child->get_traffic_selectors(child, FALSE, NULL, NULL);
+ host_any = host_create_any(AF_INET);
+ host_any6 = host_create_any(AF_INET6);
+
+ hosts = linked_list_create_with_items(host_any, host_any6, NULL);
+ my_ts_list = child->get_traffic_selectors(child, TRUE, NULL, hosts);
+ other_ts_list = child->get_traffic_selectors(child, FALSE, NULL, hosts);
+ hosts->destroy(hosts);
/* enumerate pairs of traffic selectors */
e_my_ts = my_ts_list->create_enumerator(my_ts_list);
@@ -212,22 +237,35 @@ static void uninstall_shunt_policy(child_cfg_t *child)
e_other_ts = other_ts_list->create_enumerator(other_ts_list);
while (e_other_ts->enumerate(e_other_ts, &other_ts))
{
+ if (my_ts->get_type(my_ts) != other_ts->get_type(other_ts))
+ {
+ continue;
+ }
+ if (my_ts->get_protocol(my_ts) &&
+ other_ts->get_protocol(other_ts) &&
+ my_ts->get_protocol(my_ts) != other_ts->get_protocol(other_ts))
+ {
+ continue;
+ }
/* uninstall out policy */
status |= hydra->kernel_interface->del_policy(
- hydra->kernel_interface, my_ts, other_ts,
- POLICY_OUT, 0, child->get_mark(child, FALSE),
+ hydra->kernel_interface, host_any, host_any,
+ my_ts, other_ts, POLICY_OUT, policy_type,
+ &sa, child->get_mark(child, FALSE),
policy_prio);
/* uninstall in policy */
status |= hydra->kernel_interface->del_policy(
- hydra->kernel_interface, other_ts, my_ts,
- POLICY_IN, 0, child->get_mark(child, TRUE),
+ hydra->kernel_interface, host_any, host_any,
+ other_ts, my_ts, POLICY_IN, policy_type,
+ &sa, child->get_mark(child, TRUE),
policy_prio);
/* uninstall forward policy */
status |= hydra->kernel_interface->del_policy(
- hydra->kernel_interface, other_ts, my_ts,
- POLICY_FWD, 0, child->get_mark(child, TRUE),
+ hydra->kernel_interface, host_any, host_any,
+ other_ts, my_ts, POLICY_FWD, policy_type,
+ &sa, child->get_mark(child, TRUE),
policy_prio);
}
e_other_ts->destroy(e_other_ts);
@@ -238,6 +276,8 @@ static void uninstall_shunt_policy(child_cfg_t *child)
offsetof(traffic_selector_t, destroy));
other_ts_list->destroy_offset(other_ts_list,
offsetof(traffic_selector_t, destroy));
+ host_any6->destroy(host_any6);
+ host_any->destroy(host_any);
if (status != SUCCESS)
{
diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c
index 63505c960..90ad7e40e 100644
--- a/src/libcharon/sa/trap_manager.c
+++ b/src/libcharon/sa/trap_manager.c
@@ -211,6 +211,7 @@ METHOD(trap_manager_t, install, u_int32_t,
if (this->installing == INSTALL_DISABLED)
{ /* flush() has been called */
this->lock->unlock(this->lock);
+ other->destroy(other);
me->destroy(me);
return 0;
}
@@ -235,6 +236,7 @@ METHOD(trap_manager_t, install, u_int32_t,
{
DBG1(DBG_CFG, "CHILD_SA '%s' is already being routed", found->name);
this->lock->unlock(this->lock);
+ other->destroy(other);
me->destroy(me);
return 0;
}