summaryrefslogtreecommitdiff
path: root/src/conftest/hooks
diff options
context:
space:
mode:
Diffstat (limited to 'src/conftest/hooks')
-rw-r--r--src/conftest/hooks/add_notify.c140
-rw-r--r--src/conftest/hooks/add_payload.c151
-rw-r--r--src/conftest/hooks/custom_proposal.c188
-rw-r--r--src/conftest/hooks/force_cookie.c117
-rw-r--r--src/conftest/hooks/hook.h45
-rw-r--r--src/conftest/hooks/ignore_message.c89
-rw-r--r--src/conftest/hooks/ike_auth_fill.c145
-rw-r--r--src/conftest/hooks/log_id.c89
-rw-r--r--src/conftest/hooks/log_ke.c81
-rw-r--r--src/conftest/hooks/log_proposals.c98
-rw-r--r--src/conftest/hooks/log_ts.c86
-rw-r--r--src/conftest/hooks/pretend_auth.c386
-rw-r--r--src/conftest/hooks/rebuild_auth.c243
-rw-r--r--src/conftest/hooks/reset_seq.c158
-rw-r--r--src/conftest/hooks/set_critical.c123
-rw-r--r--src/conftest/hooks/set_ike_initiator.c87
-rw-r--r--src/conftest/hooks/set_ike_request.c84
-rw-r--r--src/conftest/hooks/set_ike_spi.c104
-rw-r--r--src/conftest/hooks/set_ike_version.c111
-rw-r--r--src/conftest/hooks/set_length.c133
-rw-r--r--src/conftest/hooks/set_proposal_number.c163
-rw-r--r--src/conftest/hooks/set_reserved.c245
-rw-r--r--src/conftest/hooks/unencrypted_notify.c153
-rw-r--r--src/conftest/hooks/unsort_message.c133
24 files changed, 3352 insertions, 0 deletions
diff --git a/src/conftest/hooks/add_notify.c b/src/conftest/hooks/add_notify.c
new file mode 100644
index 000000000..de46ca81f
--- /dev/null
+++ b/src/conftest/hooks/add_notify.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+typedef struct private_add_notify_t private_add_notify_t;
+
+/**
+ * Private data of an add_notify_t object.
+ */
+struct private_add_notify_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+
+ /**
+ * Alter requests or responses?
+ */
+ bool req;
+
+ /**
+ * ID of message to alter.
+ */
+ int id;
+
+ /**
+ * Notify type
+ */
+ char *type;
+
+ /**
+ * Notify data
+ */
+ char *data;
+
+ /**
+ * SPI of notify
+ */
+ int spi;
+
+ /**
+ * TRUE for a ESP protocol notify, FALSE for IKE
+ */
+ bool esp;
+};
+
+METHOD(listener_t, message, bool,
+ private_add_notify_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (!incoming &&
+ message->get_request(message) == this->req &&
+ message->get_message_id(message) == this->id)
+ {
+ notify_type_t type;
+ notify_payload_t *notify;
+ chunk_t data = chunk_empty;
+
+ type = atoi(this->type);
+ if (!type)
+ {
+ type = enum_from_name(notify_type_names, this->type);
+ if (type == -1)
+ {
+ DBG1(DBG_CFG, "unknown notify: '%s', skipped", this->type);
+ return TRUE;
+ }
+ }
+ if (strncaseeq(this->data, "0x", 2))
+ {
+ data = chunk_skip(chunk_create(this->data, strlen(this->data)), 2);
+ data = chunk_from_hex(data, NULL);
+ }
+ else if (this->data && strlen(this->data))
+ {
+ data = chunk_clone(chunk_create(this->data, strlen(this->data)));
+ }
+ notify = notify_payload_create_from_protocol_and_type(
+ this->esp ? PROTO_ESP : PROTO_IKE, type);
+ notify->set_spi(notify, this->spi);
+ if (data.len)
+ {
+ notify->set_notification_data(notify, data);
+ free(data.ptr);
+ }
+ message->add_payload(message, &notify->payload_interface);
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_add_notify_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *add_notify_hook_create(char *name)
+{
+ private_add_notify_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ .req = conftest->test->get_bool(conftest->test,
+ "hooks.%s.request", TRUE, name),
+ .id = conftest->test->get_int(conftest->test,
+ "hooks.%s.id", 0, name),
+ .type = conftest->test->get_str(conftest->test,
+ "hooks.%s.type", "", name),
+ .data = conftest->test->get_str(conftest->test,
+ "hooks.%s.data", "", name),
+ .spi = conftest->test->get_int(conftest->test,
+ "hooks.%s.spi", 0, name),
+ .esp = conftest->test->get_bool(conftest->test,
+ "hooks.%s.esp", FALSE, name),
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/add_payload.c b/src/conftest/hooks/add_payload.c
new file mode 100644
index 000000000..03a47cc23
--- /dev/null
+++ b/src/conftest/hooks/add_payload.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+#include <encoding/payloads/unknown_payload.h>
+
+typedef struct private_add_payload_t private_add_payload_t;
+
+/**
+ * Private data of an add_payload_t object.
+ */
+struct private_add_payload_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+
+ /**
+ * Alter requests or responses?
+ */
+ bool req;
+
+ /**
+ * ID of message to alter.
+ */
+ int id;
+
+ /**
+ * Payload type
+ */
+ char *type;
+
+ /**
+ * Payload data
+ */
+ char *data;
+
+ /**
+ * Set critical bit of the payload
+ */
+ bool critical;
+
+ /**
+ * True to replace existing payload of this type
+ */
+ bool replace;
+};
+
+METHOD(listener_t, message, bool,
+ private_add_payload_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (!incoming &&
+ message->get_request(message) == this->req &&
+ message->get_message_id(message) == this->id)
+ {
+ unknown_payload_t *unknown;
+ payload_t *payload;
+ enumerator_t *enumerator;
+ chunk_t data = chunk_empty;
+ payload_type_t type;
+
+ type = atoi(this->type);
+ if (!type)
+ {
+ type = enum_from_name(payload_type_short_names, this->type);
+ if (type == -1)
+ {
+ DBG1(DBG_CFG, "unknown payload: '%s', skipped", this->type);
+ return TRUE;
+ }
+ }
+ if (this->replace)
+ {
+ enumerator = message->create_payload_enumerator(message);
+ while (enumerator->enumerate(enumerator, &payload))
+ {
+ if (payload->get_type(payload) == type)
+ {
+ message->remove_payload_at(message, enumerator);
+ payload->destroy(payload);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ if (strncaseeq(this->data, "0x", 2))
+ {
+ data = chunk_skip(chunk_create(this->data, strlen(this->data)), 2);
+ data = chunk_from_hex(data, NULL);
+ }
+ else if (this->data && strlen(this->data))
+ {
+ data = chunk_clone(chunk_create(this->data, strlen(this->data)));
+ }
+ unknown = unknown_payload_create_data(type, this->critical, data);
+ message->add_payload(message, &unknown->payload_interface);
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_add_payload_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *add_payload_hook_create(char *name)
+{
+ private_add_payload_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ .req = conftest->test->get_bool(conftest->test,
+ "hooks.%s.request", TRUE, name),
+ .id = conftest->test->get_int(conftest->test,
+ "hooks.%s.id", 0, name),
+ .type = conftest->test->get_str(conftest->test,
+ "hooks.%s.type", "", name),
+ .data = conftest->test->get_str(conftest->test,
+ "hooks.%s.data", "", name),
+ .critical = conftest->test->get_bool(conftest->test,
+ "hooks.%s.critical", FALSE, name),
+ .replace = conftest->test->get_bool(conftest->test,
+ "hooks.%s.replace", FALSE, name),
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/custom_proposal.c b/src/conftest/hooks/custom_proposal.c
new file mode 100644
index 000000000..e4acd841f
--- /dev/null
+++ b/src/conftest/hooks/custom_proposal.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+#include <errno.h>
+
+#include <encoding/payloads/sa_payload.h>
+#include <config/proposal.h>
+#include <crypto/proposal/proposal_keywords.h>
+
+typedef struct private_custom_proposal_t private_custom_proposal_t;
+
+/**
+ * Private data of an custom_proposal_t object.
+ */
+struct private_custom_proposal_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+
+ /**
+ * Alter requests or responses?
+ */
+ bool req;
+
+ /**
+ * ID of message to alter.
+ */
+ int id;
+
+ /**
+ * hook name
+ */
+ char *name;
+};
+
+/**
+ * Load custom proposal configuration to proposal list
+ */
+static linked_list_t* load_proposals(private_custom_proposal_t *this,
+ protocol_id_t proto, u_int64_t spi)
+{
+ enumerator_t *props, *algs;
+ char *number, *key, *value;
+ linked_list_t *list;
+
+ list = linked_list_create();
+ props = conftest->test->create_section_enumerator(conftest->test,
+ "hooks.%s", this->name);
+ while (props->enumerate(props, &number))
+ {
+ const proposal_token_t *token = NULL;
+ proposal_t *proposal;
+ u_int16_t type, alg, keysize = 0;
+ char *end;
+
+ proposal = proposal_create(proto, atoi(number));
+ proposal->set_spi(proposal, spi);
+
+ algs = conftest->test->create_key_value_enumerator(conftest->test,
+ "hooks.%s.%s", this->name, number);
+ while (algs->enumerate(algs, &key, &value))
+ {
+ errno = 0;
+ type = strtoul(key, &end, 10);
+ if (end == key || errno)
+ {
+ type = enum_from_name(transform_type_names, key);
+ if (type == -1)
+ {
+ DBG1(DBG_CFG, "unknown transform: '%s', skipped", key);
+ continue;
+ }
+ }
+ errno = 0;
+ alg = strtoul(value, &end, 10);
+ if (end == value || errno)
+ {
+ token = proposal_get_token(value, strlen(value));
+ if (!token)
+ {
+ DBG1(DBG_CFG, "unknown algorithm: '%s', skipped", value);
+ continue;
+ }
+ keysize = token->keysize;
+ alg = token->algorithm;
+ }
+ proposal->add_algorithm(proposal, type, alg, keysize);
+ }
+ algs->destroy(algs);
+ list->insert_last(list, proposal);
+ }
+ props->destroy(props);
+ return list;
+}
+
+METHOD(listener_t, message, bool,
+ private_custom_proposal_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (!incoming &&
+ message->get_request(message) == this->req &&
+ message->get_message_id(message) == this->id)
+ {
+ enumerator_t *enumerator;
+ payload_t *payload;
+ sa_payload_t *new, *old = NULL;
+ linked_list_t *new_props, *old_props;
+ proposal_t *proposal;
+
+ enumerator = message->create_payload_enumerator(message);
+ while (enumerator->enumerate(enumerator, &payload))
+ {
+ if (payload->get_type(payload) == SECURITY_ASSOCIATION)
+ {
+ old = (sa_payload_t*)payload;
+ message->remove_payload_at(message, enumerator);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (old)
+ {
+ old_props = old->get_proposals(old);
+ old->destroy(old);
+ enumerator = old_props->create_enumerator(old_props);
+ if (enumerator->enumerate(enumerator, &proposal))
+ {
+ new_props = load_proposals(this,
+ proposal->get_protocol(proposal),
+ proposal->get_spi(proposal));
+ DBG1(DBG_CFG, "injecting custom proposal: %#P", new_props);
+ new = sa_payload_create_from_proposal_list(new_props);
+ message->add_payload(message, (payload_t*)new);
+ new_props->destroy_offset(new_props, offsetof(proposal_t, destroy));
+ }
+ enumerator->destroy(enumerator);
+ old_props->destroy_offset(old_props, offsetof(proposal_t, destroy));
+ }
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_custom_proposal_t *this)
+{
+ free(this->name);
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *custom_proposal_hook_create(char *name)
+{
+ private_custom_proposal_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ .req = conftest->test->get_bool(conftest->test,
+ "hooks.%s.request", TRUE, name),
+ .id = conftest->test->get_int(conftest->test,
+ "hooks.%s.id", 0, name),
+ .name = strdup(name),
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/force_cookie.c b/src/conftest/hooks/force_cookie.c
new file mode 100644
index 000000000..e34f82851
--- /dev/null
+++ b/src/conftest/hooks/force_cookie.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+#include <encoding/payloads/unknown_payload.h>
+
+typedef struct private_force_cookie_t private_force_cookie_t;
+
+/**
+ * Private data of an force_cookie_t object.
+ */
+struct private_force_cookie_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+};
+
+METHOD(listener_t, message, bool,
+ private_force_cookie_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (incoming && message->get_request(message) &&
+ message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ enumerator_t *enumerator;
+ bool has_cookie = FALSE;
+ payload_t *payload;
+
+ enumerator = message->create_payload_enumerator(message);
+ while (enumerator->enumerate(enumerator, &payload))
+ {
+ if (payload->get_type(payload) == NOTIFY)
+ {
+ notify_payload_t *notify = (notify_payload_t*)payload;
+ chunk_t data;
+
+ if (notify->get_notify_type(notify) == COOKIE)
+ {
+ data = notify->get_notification_data(notify);
+ DBG1(DBG_CFG, "received COOKIE: %#B", &data);
+ has_cookie = TRUE;
+ break;
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ if (!has_cookie)
+ {
+ message_t *response;
+ host_t *src, *dst;
+ packet_t *packet;
+ ike_sa_id_t *ike_sa_id;
+ chunk_t data = chunk_from_thing("COOKIE test data");
+
+ DBG1(DBG_CFG, "sending COOKIE: %#B", &data);
+ response = message_create();
+ dst = message->get_source(message);
+ src = message->get_destination(message);
+ response->set_source(response, src->clone(src));
+ response->set_destination(response, dst->clone(dst));
+ response->set_exchange_type(response, IKE_SA_INIT);
+ response->set_request(response, FALSE);
+ response->set_message_id(response, 0);
+ ike_sa_id = message->get_ike_sa_id(message);
+ ike_sa_id->switch_initiator(ike_sa_id);
+ response->set_ike_sa_id(response, ike_sa_id);
+ response->add_notify(response, FALSE, COOKIE, data);
+ if (response->generate(response, NULL, &packet) == SUCCESS)
+ {
+ charon->sender->send(charon->sender, packet);
+ response->destroy(response);
+ }
+ message->set_exchange_type(message, EXCHANGE_TYPE_UNDEFINED);
+ }
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_force_cookie_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *force_cookie_hook_create(char *name)
+{
+ private_force_cookie_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/hook.h b/src/conftest/hooks/hook.h
new file mode 100644
index 000000000..39a15f21b
--- /dev/null
+++ b/src/conftest/hooks/hook.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup hook hook
+ * @{ @ingroup hooks
+ */
+
+#ifndef HOOK_H_
+#define HOOK_H_
+
+typedef struct hook_t hook_t;
+
+#include <daemon.h>
+#include <conftest.h>
+
+/**
+ * Hook providing interface.
+ */
+struct hook_t {
+
+ /**
+ * Implements listener_t.
+ */
+ listener_t listener;
+
+ /**
+ * Destroy a hook_t.
+ */
+ void (*destroy)(hook_t *this);
+};
+
+#endif /** HOOK_H_ @}*/
diff --git a/src/conftest/hooks/ignore_message.c b/src/conftest/hooks/ignore_message.c
new file mode 100644
index 000000000..210f3ac50
--- /dev/null
+++ b/src/conftest/hooks/ignore_message.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+typedef struct private_ignore_message_t private_ignore_message_t;
+
+/**
+ * Private data of an ignore_message_t object.
+ */
+struct private_ignore_message_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+
+ /**
+ * Drop incoming or outgoing?
+ */
+ bool in;
+
+ /**
+ * Drop requests or responses?
+ */
+ bool req;
+
+ /**
+ * ID of message to drop.
+ */
+ int id;
+};
+
+METHOD(listener_t, message, bool,
+ private_ignore_message_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (incoming == this->in &&
+ message->get_request(message) == this->req &&
+ message->get_message_id(message) == this->id)
+ {
+ DBG1(DBG_CFG, "ignoring message");
+ message->set_exchange_type(message, EXCHANGE_TYPE_UNDEFINED);
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_ignore_message_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create the ignore_message hook
+ */
+hook_t *ignore_message_hook_create(char *name)
+{
+ private_ignore_message_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ .in = conftest->test->get_bool(conftest->test,
+ "hooks.%s.inbound", TRUE, name),
+ .req = conftest->test->get_bool(conftest->test,
+ "hooks.%s.request", TRUE, name),
+ .id = conftest->test->get_int(conftest->test,
+ "hooks.%s.id", 0, name),
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/ike_auth_fill.c b/src/conftest/hooks/ike_auth_fill.c
new file mode 100644
index 000000000..2843d60c1
--- /dev/null
+++ b/src/conftest/hooks/ike_auth_fill.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+#include <time.h>
+#include <netinet/udp.h>
+
+#include <encoding/payloads/cert_payload.h>
+#include <encoding/payloads/encryption_payload.h>
+
+typedef struct private_ike_auth_fill_t private_ike_auth_fill_t;
+
+/**
+ * Private data of an ike_auth_fill_t object.
+ */
+struct private_ike_auth_fill_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+
+ /**
+ * Alter requests or responses?
+ */
+ bool req;
+
+ /**
+ * ID of message to alter.
+ */
+ int id;
+
+ /**
+ * Number of bytes to fill IKE_AUTH up
+ */
+ int bytes;
+};
+
+/** size of non ESP-Marker */
+#define NON_ESP_MARKER_LEN 4
+
+/**
+ * Calculate packet size on wire (without ethernet/IP header)
+ */
+static size_t calculate_wire_size(message_t *message, ike_sa_t *ike_sa)
+{
+ enumerator_t *enumerator;
+ payload_t *payload;
+ size_t size = 0;
+
+ enumerator = message->create_payload_enumerator(message);
+ while (enumerator->enumerate(enumerator, &payload))
+ {
+ size += payload->get_length(payload);
+ }
+ enumerator->destroy(enumerator);
+
+ if (message->get_exchange_type(message) != IKE_SA_INIT)
+ {
+ keymat_t *keymat;
+ aead_t *aead;
+ size_t bs;
+
+ keymat = ike_sa->get_keymat(ike_sa);
+ aead = keymat->get_aead(keymat, FALSE);
+ if (aead)
+ {
+ bs = aead->get_block_size(aead);
+ size += ENCRYPTION_PAYLOAD_HEADER_LENGTH + NON_ESP_MARKER_LEN +
+ aead->get_icv_size(aead) + aead->get_iv_size(aead) +
+ (bs - (size % bs));
+ }
+ }
+ return sizeof(struct udphdr) + IKE_HEADER_LENGTH + size;
+}
+
+METHOD(listener_t, message, bool,
+ private_ike_auth_fill_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (!incoming &&
+ message->get_request(message) == this->req &&
+ message->get_message_id(message) == this->id)
+ {
+ cert_payload_t *pld;
+ size_t size, diff;
+ chunk_t data;
+
+ size = calculate_wire_size(message, ike_sa);
+ if (size < this->bytes - CERT_PAYLOAD_HEADER_LENGTH)
+ {
+ diff = this->bytes - size - CERT_PAYLOAD_HEADER_LENGTH;
+ data = chunk_alloc(diff);
+ memset(data.ptr, 0x12, data.len);
+ pld = cert_payload_create_custom(201, data);
+ message->add_payload(message, &pld->payload_interface);
+ DBG1(DBG_CFG, "inserting %d dummy bytes certificate payload", diff);
+ }
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_ike_auth_fill_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *ike_auth_fill_hook_create(char *name)
+{
+ private_ike_auth_fill_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ .req = conftest->test->get_bool(conftest->test,
+ "hooks.%s.request", TRUE, name),
+ .id = conftest->test->get_int(conftest->test,
+ "hooks.%s.id", 1, name),
+ .bytes = conftest->test->get_int(conftest->test,
+ "hooks.%s.bytes", 0, name),
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/log_id.c b/src/conftest/hooks/log_id.c
new file mode 100644
index 000000000..ad14cea10
--- /dev/null
+++ b/src/conftest/hooks/log_id.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+#include <encoding/payloads/id_payload.h>
+
+typedef struct private_log_id_t private_log_id_t;
+
+/**
+ * Private data of an log_id_t object.
+ */
+struct private_log_id_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+};
+
+METHOD(listener_t, message, bool,
+ private_log_id_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (incoming)
+ {
+ enumerator_t *enumerator;
+ payload_t *payload;
+ id_payload_t *id_payload;
+ identification_t *id;
+ chunk_t data;
+
+ enumerator = message->create_payload_enumerator(message);
+ while (enumerator->enumerate(enumerator, &payload))
+ {
+ if (payload->get_type(payload) == ID_INITIATOR ||
+ payload->get_type(payload) == ID_RESPONDER)
+ {
+ id_payload = (id_payload_t*)payload;
+ id = id_payload->get_identification(id_payload);
+ data = id->get_encoding(id);
+
+ DBG1(DBG_CFG, "%N: %N %B",
+ payload_type_short_names, payload->get_type(payload),
+ id_type_names, id->get_type(id), &data);
+ id->destroy(id);
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_log_id_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *log_id_hook_create(char *name)
+{
+ private_log_id_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/log_ke.c b/src/conftest/hooks/log_ke.c
new file mode 100644
index 000000000..231c0a8d8
--- /dev/null
+++ b/src/conftest/hooks/log_ke.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+#include <encoding/payloads/ke_payload.h>
+
+typedef struct private_log_ke_t private_log_ke_t;
+
+/**
+ * Private data of an log_ke_t object.
+ */
+struct private_log_ke_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+};
+
+METHOD(listener_t, message, bool,
+ private_log_ke_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (incoming)
+ {
+ enumerator_t *enumerator;
+ payload_t *payload;
+ ke_payload_t *ke;
+
+ enumerator = message->create_payload_enumerator(message);
+ while (enumerator->enumerate(enumerator, &payload))
+ {
+ if (payload->get_type(payload) == KEY_EXCHANGE)
+ {
+ ke = (ke_payload_t*)payload;
+ DBG1(DBG_CFG, "received DH group %N",
+ diffie_hellman_group_names, ke->get_dh_group_number(ke));
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_log_ke_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *log_ke_hook_create(char *name)
+{
+ private_log_ke_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/log_proposals.c b/src/conftest/hooks/log_proposals.c
new file mode 100644
index 000000000..8c330ab3d
--- /dev/null
+++ b/src/conftest/hooks/log_proposals.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+#include <encoding/payloads/sa_payload.h>
+
+typedef struct private_log_proposals_t private_log_proposals_t;
+
+/**
+ * Private data of an log_proposals_t object.
+ */
+struct private_log_proposals_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+};
+
+METHOD(listener_t, message, bool,
+ private_log_proposals_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (incoming)
+ {
+ enumerator_t *enumerator, *proposals;
+ payload_t *payload;
+ linked_list_t *list;
+ sa_payload_t *sa;
+ proposal_t *proposal;
+
+ enumerator = message->create_payload_enumerator(message);
+ while (enumerator->enumerate(enumerator, &payload))
+ {
+ if (payload->get_type(payload) == SECURITY_ASSOCIATION)
+ {
+ sa = (sa_payload_t*)payload;
+ list = sa->get_proposals(sa);
+ DBG1(DBG_CFG, "received %d proposal%s:", list->get_count(list),
+ list->get_count(list) == 1 ? "" : "s");
+ proposals = list->create_enumerator(list);
+ while (proposals->enumerate(proposals, &proposal))
+ {
+ u_int64_t spi = proposal->get_spi(proposal);
+
+ if (proposal->get_protocol(proposal) != PROTO_IKE)
+ {
+ spi = htonl(spi);
+ }
+ DBG1(DBG_CFG, " %d (SPI 0x%llx): %P",
+ proposal->get_number(proposal), spi, proposal);
+ }
+ proposals->destroy(proposals);
+ list->destroy_offset(list, offsetof(proposal_t, destroy));
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_log_proposals_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *log_proposals_hook_create(char *name)
+{
+ private_log_proposals_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/log_ts.c b/src/conftest/hooks/log_ts.c
new file mode 100644
index 000000000..dacc7a58c
--- /dev/null
+++ b/src/conftest/hooks/log_ts.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+#include <encoding/payloads/ts_payload.h>
+
+typedef struct private_log_ts_t private_log_ts_t;
+
+/**
+ * Private data of an log_ts_t object.
+ */
+struct private_log_ts_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+};
+
+METHOD(listener_t, message, bool,
+ private_log_ts_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (incoming)
+ {
+ enumerator_t *enumerator;
+ payload_t *payload;
+ linked_list_t *list;
+ ts_payload_t *ts;
+
+ enumerator = message->create_payload_enumerator(message);
+ while (enumerator->enumerate(enumerator, &payload))
+ {
+ if (payload->get_type(payload) == TRAFFIC_SELECTOR_INITIATOR ||
+ payload->get_type(payload) == TRAFFIC_SELECTOR_RESPONDER)
+ {
+ ts = (ts_payload_t*)payload;
+ list = ts->get_traffic_selectors(ts);
+
+ DBG1(DBG_CFG, "received %N: %#R",
+ payload_type_short_names, payload->get_type(payload), list);
+ list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_log_ts_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *log_ts_hook_create(char *name)
+{
+ private_log_ts_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/pretend_auth.c b/src/conftest/hooks/pretend_auth.c
new file mode 100644
index 000000000..4b7168cac
--- /dev/null
+++ b/src/conftest/hooks/pretend_auth.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+#include <encoding/payloads/nonce_payload.h>
+#include <encoding/payloads/cert_payload.h>
+#include <encoding/payloads/auth_payload.h>
+#include <encoding/payloads/id_payload.h>
+#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/ts_payload.h>
+
+typedef struct private_pretend_auth_t private_pretend_auth_t;
+
+/**
+ * Private data of an pretend_auth_t object.
+ */
+struct private_pretend_auth_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+
+ /**
+ * remote peer identity
+ */
+ identification_t *id;
+
+ /**
+ * reserved bytes of ID payload
+ */
+ char reserved[3];
+
+ /**
+ * IKE_SA_INIT data for signature
+ */
+ chunk_t ike_init;
+
+ /**
+ * Nonce for signature
+ */
+ chunk_t nonce;
+
+ /**
+ * Selected CHILD_SA proposal
+ */
+ proposal_t *proposal;
+
+ /**
+ * List of initiators Traffic Selectors
+ */
+ linked_list_t *tsi;
+
+ /**
+ * List of responders Traffic Selectors
+ */
+ linked_list_t *tsr;
+};
+
+/**
+ * Process IKE_SA_INIT request message, outgoing
+ */
+static void process_init_request(private_pretend_auth_t *this,
+ ike_sa_t *ike_sa, message_t *message)
+{
+ nonce_payload_t *nonce;
+
+ nonce = (nonce_payload_t*)message->get_payload(message, NONCE);
+ if (nonce)
+ {
+ free(this->nonce.ptr);
+ this->nonce = nonce->get_nonce(nonce);
+ }
+}
+
+/**
+ * Process IKE_AUTH request message, outgoing
+ */
+static void process_auth_request(private_pretend_auth_t *this,
+ ike_sa_t *ike_sa, message_t *message)
+{
+ id_payload_t *id;
+ sa_payload_t *sa;
+ ts_payload_t *tsi, *tsr;
+ linked_list_t *proposals;
+
+ id = (id_payload_t*)message->get_payload(message, ID_RESPONDER);
+ if (id)
+ {
+ this->id->destroy(this->id);
+ this->id = id->get_identification(id);
+ }
+ sa = (sa_payload_t*)message->get_payload(message, SECURITY_ASSOCIATION);
+ if (sa)
+ {
+ proposals = sa->get_proposals(sa);
+ proposals->remove_first(proposals, (void**)&this->proposal);
+ if (this->proposal)
+ {
+ this->proposal->set_spi(this->proposal, htonl(0x12345678));
+ }
+ proposals->destroy_offset(proposals, offsetof(proposal_t, destroy));
+ }
+ tsi = (ts_payload_t*)message->get_payload(message,
+ TRAFFIC_SELECTOR_INITIATOR);
+ if (tsi)
+ {
+ this->tsi = tsi->get_traffic_selectors(tsi);
+ }
+ tsr = (ts_payload_t*)message->get_payload(message,
+ TRAFFIC_SELECTOR_RESPONDER);
+ if (tsr)
+ {
+ this->tsr = tsr->get_traffic_selectors(tsr);
+ }
+
+}
+
+/**
+ * Process IKE_SA_INIT response message, incoming
+ */
+static void process_init_response(private_pretend_auth_t *this,
+ ike_sa_t *ike_sa, message_t *message)
+{
+ this->ike_init = message->get_packet_data(message);
+}
+
+/**
+ * Build CERT payloads
+ */
+static void build_certs(private_pretend_auth_t *this,
+ ike_sa_t *ike_sa, message_t *message, auth_cfg_t *auth)
+{
+ enumerator_t *enumerator;
+ cert_payload_t *payload;
+ certificate_t *cert;
+ auth_rule_t type;
+
+ /* get subject cert first, then issuing certificates */
+ cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
+ if (cert)
+ {
+ payload = cert_payload_create_from_cert(cert);
+ if (payload)
+ {
+ DBG1(DBG_IKE, "pretending end entity cert \"%Y\"",
+ cert->get_subject(cert));
+ message->add_payload(message, (payload_t*)payload);
+ }
+ }
+ enumerator = auth->create_enumerator(auth);
+ while (enumerator->enumerate(enumerator, &type, &cert))
+ {
+ if (type == AUTH_RULE_IM_CERT)
+ {
+ payload = cert_payload_create_from_cert(cert);
+ if (payload)
+ {
+ DBG1(DBG_IKE, "pretending issuer cert \"%Y\"",
+ cert->get_subject(cert));
+ message->add_payload(message, (payload_t*)payload);
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * Build faked AUTH payload
+ */
+static bool build_auth(private_pretend_auth_t *this,
+ ike_sa_t *ike_sa, message_t *message)
+{
+ chunk_t octets, auth_data;
+ private_key_t *private;
+ auth_cfg_t *auth;
+ auth_payload_t *auth_payload;
+ auth_method_t auth_method;
+ signature_scheme_t scheme;
+ keymat_t *keymat;
+
+ auth = auth_cfg_create();
+ private = lib->credmgr->get_private(lib->credmgr, KEY_ANY, this->id, auth);
+ build_certs(this, ike_sa, message, auth);
+ auth->destroy(auth);
+ if (private == NULL)
+ {
+ DBG1(DBG_CFG, "no private key found for '%Y' to pretend AUTH", this->id);
+ return FALSE;
+ }
+
+ switch (private->get_type(private))
+ {
+ case KEY_RSA:
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
+ auth_method = AUTH_RSA;
+ break;
+ case KEY_ECDSA:
+ /* we try to deduct the signature scheme from the keysize */
+ switch (private->get_keysize(private))
+ {
+ case 256:
+ scheme = SIGN_ECDSA_256;
+ auth_method = AUTH_ECDSA_256;
+ break;
+ case 384:
+ scheme = SIGN_ECDSA_384;
+ auth_method = AUTH_ECDSA_384;
+ break;
+ case 521:
+ scheme = SIGN_ECDSA_521;
+ auth_method = AUTH_ECDSA_521;
+ break;
+ default:
+ DBG1(DBG_CFG, "%d bit ECDSA private key size not supported",
+ private->get_keysize(private));
+ return FALSE;
+ }
+ break;
+ default:
+ DBG1(DBG_CFG, "private key of type %N not supported",
+ key_type_names, private->get_type(private));
+ return FALSE;
+ }
+ keymat = ike_sa->get_keymat(ike_sa);
+ octets = keymat->get_auth_octets(keymat, TRUE, this->ike_init,
+ this->nonce, this->id, this->reserved);
+ if (!private->sign(private, scheme, octets, &auth_data))
+ {
+ chunk_free(&octets);
+ private->destroy(private);
+ return FALSE;
+ }
+ auth_payload = auth_payload_create();
+ auth_payload->set_auth_method(auth_payload, auth_method);
+ auth_payload->set_data(auth_payload, auth_data);
+ chunk_free(&auth_data);
+ chunk_free(&octets);
+ private->destroy(private);
+ message->add_payload(message, (payload_t*)auth_payload);
+ DBG1(DBG_CFG, "pretending AUTH payload for '%Y' with %N",
+ this->id, auth_method_names, auth_method);
+ return TRUE;
+}
+
+/**
+ * Process IKE_AUTH response message, incoming
+ */
+static void process_auth_response(private_pretend_auth_t *this,
+ ike_sa_t *ike_sa, message_t *message)
+{
+ enumerator_t *enumerator;
+ payload_t *payload;
+
+ /* check for, and remove AUTHENTICATION_FAILED notify */
+ enumerator = message->create_payload_enumerator(message);
+ while (enumerator->enumerate(enumerator, &payload))
+ {
+ notify_payload_t *notify = (notify_payload_t*)payload;
+
+ if (payload->get_type(payload) != NOTIFY ||
+ notify->get_notify_type(notify) != AUTHENTICATION_FAILED)
+ {
+ DBG1(DBG_CFG, "no %N notify found, disabling AUTH pretending",
+ notify_type_names, AUTHENTICATION_FAILED);
+ enumerator->destroy(enumerator);
+ return;
+ }
+ message->remove_payload_at(message, enumerator);
+ payload->destroy(payload);
+ }
+ enumerator->destroy(enumerator);
+
+ if (!build_auth(this, ike_sa, message))
+ {
+ message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
+ return;
+ }
+ message->add_payload(message, (payload_t*)
+ id_payload_create_from_identification(ID_RESPONDER, this->id));
+ if (this->proposal)
+ {
+ message->add_payload(message, (payload_t*)
+ sa_payload_create_from_proposal(this->proposal));
+ }
+ if (this->tsi)
+ {
+ message->add_payload(message, (payload_t*)
+ ts_payload_create_from_traffic_selectors(TRUE, this->tsi));
+ }
+ if (this->tsr)
+ {
+ message->add_payload(message, (payload_t*)
+ ts_payload_create_from_traffic_selectors(FALSE, this->tsr));
+ }
+}
+
+METHOD(listener_t, message, bool,
+ private_pretend_auth_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (incoming)
+ {
+ if (!message->get_request(message))
+ {
+ if (message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ process_init_response(this, ike_sa, message);
+ }
+ if (message->get_exchange_type(message) == IKE_AUTH &&
+ message->get_message_id(message) == 1)
+ {
+ process_auth_response(this, ike_sa, message);
+ }
+ }
+ }
+ else
+ {
+ if (message->get_request(message))
+ {
+ if (message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ process_init_request(this, ike_sa, message);
+ }
+ if (message->get_exchange_type(message) == IKE_AUTH &&
+ message->get_message_id(message) == 1)
+ {
+ process_auth_request(this, ike_sa, message);
+ }
+ }
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_pretend_auth_t *this)
+{
+ if (this->tsi)
+ {
+ this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
+ }
+ if (this->tsr)
+ {
+ this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
+ }
+ DESTROY_IF(this->proposal);
+ this->id->destroy(this->id);
+ free(this->ike_init.ptr);
+ free(this->nonce.ptr);
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *pretend_auth_hook_create(char *name)
+{
+ private_pretend_auth_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ .id = identification_create_from_string(
+ conftest->test->get_str(conftest->test,
+ "hooks.%s.peer", "%any", name)),
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/rebuild_auth.c b/src/conftest/hooks/rebuild_auth.c
new file mode 100644
index 000000000..993c952e0
--- /dev/null
+++ b/src/conftest/hooks/rebuild_auth.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+#include <encoding/generator.h>
+#include <encoding/payloads/nonce_payload.h>
+#include <encoding/payloads/auth_payload.h>
+#include <encoding/payloads/id_payload.h>
+
+typedef struct private_rebuild_auth_t private_rebuild_auth_t;
+
+/**
+ * Private data of an rebuild_auth_t object.
+ */
+struct private_rebuild_auth_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+
+ /**
+ * Our IKE_SA_INIT data, required to rebuild AUTH
+ */
+ chunk_t ike_init;
+
+ /**
+ * Received NONCE, required to rebuild AUTH
+ */
+ chunk_t nonce;
+
+ /**
+ * ID to use for key lookup, if not from IDi
+ */
+ identification_t *id;
+};
+
+/**
+ * Rebuild our AUTH data
+ */
+static bool rebuild_auth(private_rebuild_auth_t *this, ike_sa_t *ike_sa,
+ message_t *message)
+{
+ enumerator_t *enumerator;
+ chunk_t octets, auth_data;
+ private_key_t *private;
+ auth_cfg_t *auth;
+ payload_t *payload;
+ auth_payload_t *auth_payload;
+ auth_method_t auth_method;
+ signature_scheme_t scheme;
+ keymat_t *keymat;
+ identification_t *id;
+ char reserved[3];
+ generator_t *generator;
+ chunk_t data;
+ u_int32_t *lenpos;
+
+ payload = message->get_payload(message,
+ message->get_request(message) ? ID_INITIATOR : ID_RESPONDER);
+ if (!payload)
+ {
+ DBG1(DBG_CFG, "ID payload not found to rebuild AUTH");
+ return FALSE;
+ }
+
+ generator = generator_create();
+ generator->generate_payload(generator, payload);
+ data = generator->get_chunk(generator, &lenpos);
+ if (data.len < 8)
+ {
+ DBG1(DBG_CFG, "ID payload invalid to rebuild AUTH");
+ generator->destroy(generator);
+ return FALSE;
+ }
+ memcpy(reserved, data.ptr + 5, 3);
+ id = identification_create_from_encoding(data.ptr[4], chunk_skip(data, 8));
+ generator->destroy(generator);
+
+ auth = auth_cfg_create();
+ private = lib->credmgr->get_private(lib->credmgr, KEY_ANY,
+ this->id ?: id, auth);
+ auth->destroy(auth);
+ if (private == NULL)
+ {
+ DBG1(DBG_CFG, "no private key found for '%Y' to rebuild AUTH",
+ this->id ?: id);
+ id->destroy(id);
+ return FALSE;
+ }
+
+ switch (private->get_type(private))
+ {
+ case KEY_RSA:
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
+ auth_method = AUTH_RSA;
+ break;
+ case KEY_ECDSA:
+ /* we try to deduct the signature scheme from the keysize */
+ switch (private->get_keysize(private))
+ {
+ case 256:
+ scheme = SIGN_ECDSA_256;
+ auth_method = AUTH_ECDSA_256;
+ break;
+ case 384:
+ scheme = SIGN_ECDSA_384;
+ auth_method = AUTH_ECDSA_384;
+ break;
+ case 521:
+ scheme = SIGN_ECDSA_521;
+ auth_method = AUTH_ECDSA_521;
+ break;
+ default:
+ DBG1(DBG_CFG, "%d bit ECDSA private key size not supported",
+ private->get_keysize(private));
+ id->destroy(id);
+ return FALSE;
+ }
+ break;
+ default:
+ DBG1(DBG_CFG, "private key of type %N not supported",
+ key_type_names, private->get_type(private));
+ id->destroy(id);
+ return FALSE;
+ }
+ keymat = ike_sa->get_keymat(ike_sa);
+ octets = keymat->get_auth_octets(keymat, FALSE, this->ike_init,
+ this->nonce, id, reserved);
+ if (!private->sign(private, scheme, octets, &auth_data))
+ {
+ chunk_free(&octets);
+ private->destroy(private);
+ id->destroy(id);
+ return FALSE;
+ }
+ auth_payload = auth_payload_create();
+ auth_payload->set_auth_method(auth_payload, auth_method);
+ auth_payload->set_data(auth_payload, auth_data);
+ chunk_free(&auth_data);
+ chunk_free(&octets);
+ private->destroy(private);
+
+ enumerator = message->create_payload_enumerator(message);
+ while (enumerator->enumerate(enumerator, &payload))
+ {
+ if (payload->get_type(payload) == AUTHENTICATION)
+ {
+ message->remove_payload_at(message, enumerator);
+ payload->destroy(payload);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ message->add_payload(message, (payload_t*)auth_payload);
+ DBG1(DBG_CFG, "rebuilding AUTH payload for '%Y' with %N",
+ id, auth_method_names, auth_method);
+ id->destroy(id);
+ return TRUE;
+}
+
+METHOD(listener_t, message, bool,
+ private_rebuild_auth_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (!incoming && message->get_message_id(message) == 1)
+ {
+ rebuild_auth(this, ike_sa, message);
+ }
+ if (message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ if (incoming)
+ {
+ nonce_payload_t *nonce;
+
+ nonce = (nonce_payload_t*)message->get_payload(message, NONCE);
+ if (nonce)
+ {
+ free(this->nonce.ptr);
+ this->nonce = nonce->get_nonce(nonce);
+ }
+ }
+ else
+ {
+ packet_t *packet;
+
+ if (message->generate(message, NULL, &packet) == SUCCESS)
+ {
+ free(this->ike_init.ptr);
+ this->ike_init = chunk_clone(packet->get_data(packet));
+ packet->destroy(packet);
+ }
+ }
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_rebuild_auth_t *this)
+{
+ free(this->ike_init.ptr);
+ free(this->nonce.ptr);
+ DESTROY_IF(this->id);
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *rebuild_auth_hook_create(char *name)
+{
+ private_rebuild_auth_t *this;
+ char *id;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ );
+ id = conftest->test->get_str(conftest->test, "hooks.%s.key", NULL, name);
+ if (id)
+ {
+ this->id = identification_create_from_string(id);
+ }
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/reset_seq.c b/src/conftest/hooks/reset_seq.c
new file mode 100644
index 000000000..ccf8e997d
--- /dev/null
+++ b/src/conftest/hooks/reset_seq.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+#include <linux/xfrm.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <processing/jobs/callback_job.h>
+#include <plugins/kernel_netlink/kernel_netlink_shared.h>
+
+#define XFRM_RTA(nlh, x) ((struct rtattr*)(NLMSG_DATA(nlh) + NLMSG_ALIGN(sizeof(x))))
+
+typedef struct private_reset_seq_t private_reset_seq_t;
+
+/**
+ * Private data of an reset_seq_t object.
+ */
+struct private_reset_seq_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+
+ /**
+ * Delay for reset
+ */
+ int delay;
+};
+
+/**
+ * Callback job
+ */
+static job_requeue_t reset_cb(struct xfrm_usersa_id *data)
+{
+ netlink_buf_t request;
+ struct nlmsghdr *hdr;
+ struct xfrm_aevent_id *id;
+ struct rtattr *rthdr;
+ struct xfrm_replay_state *replay;
+ struct sockaddr_nl addr;
+ int s, len;
+
+ DBG1(DBG_CFG, "resetting sequence number of SPI 0x%x", htonl(data->spi));
+
+ memset(&request, 0, sizeof(request));
+
+ hdr = (struct nlmsghdr*)request;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE;
+ hdr->nlmsg_seq = 201;
+ hdr->nlmsg_pid = getpid();
+ hdr->nlmsg_type = XFRM_MSG_NEWAE;
+ hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id));
+
+ id = (struct xfrm_aevent_id*)NLMSG_DATA(hdr);
+ id->sa_id = *data;
+
+ rthdr = XFRM_RTA(hdr, struct xfrm_aevent_id);
+ rthdr->rta_type = XFRMA_REPLAY_VAL;
+ rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state));
+ hdr->nlmsg_len += rthdr->rta_len;
+
+ replay = (struct xfrm_replay_state*)RTA_DATA(rthdr);
+
+ s = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM);
+ if (s == -1)
+ {
+ DBG1(DBG_CFG, "opening XFRM socket failed: %s", strerror(errno));
+ return JOB_REQUEUE_NONE;
+ }
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ len = sendto(s, hdr, hdr->nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+ if (len != hdr->nlmsg_len)
+ {
+ DBG1(DBG_CFG, "sending XFRM aevent failed: %s", strerror(errno));
+ }
+ close(s);
+ return JOB_REQUEUE_NONE;
+}
+
+/**
+ * Schedule sequence number reset job
+ */
+static void schedule_reset_job(private_reset_seq_t *this, host_t *dst,
+ u_int32_t spi)
+{
+ struct xfrm_usersa_id *data;
+ chunk_t chunk;
+
+ INIT(data,
+ .spi = spi,
+ .family = dst->get_family(dst),
+ .proto = IPPROTO_ESP,
+ );
+
+ chunk = dst->get_address(dst);
+ memcpy(&data->daddr, chunk.ptr, min(chunk.len, sizeof(xfrm_address_t)));
+
+ lib->scheduler->schedule_job(lib->scheduler,
+ (job_t*)callback_job_create(
+ (void*)reset_cb, data, (void*)free, NULL),
+ this->delay);
+}
+
+METHOD(listener_t, child_updown, bool,
+ private_reset_seq_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
+ bool up)
+{
+ if (up)
+ {
+ schedule_reset_job(this, ike_sa->get_other_host(ike_sa),
+ child_sa->get_spi(child_sa, FALSE));
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_reset_seq_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *reset_seq_hook_create(char *name)
+{
+ private_reset_seq_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .child_updown = _child_updown,
+ },
+ .destroy = _destroy,
+ },
+ .delay = conftest->test->get_int(conftest->test,
+ "hooks.%s.delay", 10, name),
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/set_critical.c b/src/conftest/hooks/set_critical.c
new file mode 100644
index 000000000..caf2215c3
--- /dev/null
+++ b/src/conftest/hooks/set_critical.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+#include <encoding/payloads/unknown_payload.h>
+
+typedef struct private_set_critical_t private_set_critical_t;
+
+/**
+ * Private data of an set_critical_t object.
+ */
+struct private_set_critical_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+
+ /**
+ * Alter requests or responses?
+ */
+ bool req;
+
+ /**
+ * ID of message to alter.
+ */
+ int id;
+
+ /**
+ * Payload types, space separated
+ */
+ char *payloads;
+};
+
+METHOD(listener_t, message, bool,
+ private_set_critical_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (!incoming &&
+ message->get_request(message) == this->req &&
+ message->get_message_id(message) == this->id)
+ {
+ enumerator_t *msg, *types;
+ payload_t *payload;
+ payload_type_t type;
+ bool *critical;
+ char *name;
+
+ types = enumerator_create_token(this->payloads, " ", "");
+ while (types->enumerate(types, &name))
+ {
+ type = atoi(name);
+ if (!type)
+ {
+ type = enum_from_name(payload_type_short_names, name);
+ if (type == -1)
+ {
+ DBG1(DBG_CFG, "invalid payload name '%s'", name);
+ break;
+ }
+ }
+ msg = message->create_payload_enumerator(message);
+ while (msg->enumerate(msg, &payload))
+ {
+ if (type == payload->get_type(payload))
+ {
+ critical = payload_get_field(payload, FLAG, 0);
+ if (critical)
+ {
+ *critical = TRUE;
+ }
+ }
+ }
+ msg->destroy(msg);
+ }
+ types->destroy(types);
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_set_critical_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *set_critical_hook_create(char *name)
+{
+ private_set_critical_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ .req = conftest->test->get_bool(conftest->test,
+ "hooks.%s.request", TRUE, name),
+ .id = conftest->test->get_int(conftest->test,
+ "hooks.%s.id", 0, name),
+ .payloads = conftest->test->get_str(conftest->test,
+ "hooks.%s.payloads", "", name),
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/set_ike_initiator.c b/src/conftest/hooks/set_ike_initiator.c
new file mode 100644
index 000000000..6ba43eaca
--- /dev/null
+++ b/src/conftest/hooks/set_ike_initiator.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+#include <encoding/payloads/unknown_payload.h>
+
+typedef struct private_set_ike_initiator_t private_set_ike_initiator_t;
+
+/**
+ * Private data of an set_ike_initiator_t object.
+ */
+struct private_set_ike_initiator_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+
+ /**
+ * Alter requests or responses?
+ */
+ bool req;
+
+ /**
+ * ID of message to alter.
+ */
+ int id;
+};
+
+METHOD(listener_t, message, bool,
+ private_set_ike_initiator_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (!incoming &&
+ message->get_request(message) == this->req &&
+ message->get_message_id(message) == this->id)
+ {
+ ike_sa_id_t *id;
+
+ DBG1(DBG_CFG, "toggling IKE message initiator flag");
+ id = message->get_ike_sa_id(message);
+ id->switch_initiator(id);
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_set_ike_initiator_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *set_ike_initiator_hook_create(char *name)
+{
+ private_set_ike_initiator_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ .req = conftest->test->get_bool(conftest->test,
+ "hooks.%s.request", TRUE, name),
+ .id = conftest->test->get_int(conftest->test,
+ "hooks.%s.id", 0, name),
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/set_ike_request.c b/src/conftest/hooks/set_ike_request.c
new file mode 100644
index 000000000..baabea66a
--- /dev/null
+++ b/src/conftest/hooks/set_ike_request.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+#include <encoding/payloads/unknown_payload.h>
+
+typedef struct private_set_ike_request_t private_set_ike_request_t;
+
+/**
+ * Private data of an set_ike_request_t object.
+ */
+struct private_set_ike_request_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+
+ /**
+ * Alter requests or responses?
+ */
+ bool req;
+
+ /**
+ * ID of message to alter.
+ */
+ int id;
+};
+
+METHOD(listener_t, message, bool,
+ private_set_ike_request_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (!incoming &&
+ message->get_request(message) == this->req &&
+ message->get_message_id(message) == this->id)
+ {
+ DBG1(DBG_CFG, "toggling IKE message request flag");
+ message->set_request(message, !this->req);
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_set_ike_request_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *set_ike_request_hook_create(char *name)
+{
+ private_set_ike_request_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ .req = conftest->test->get_bool(conftest->test,
+ "hooks.%s.request", TRUE, name),
+ .id = conftest->test->get_int(conftest->test,
+ "hooks.%s.id", 0, name),
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/set_ike_spi.c b/src/conftest/hooks/set_ike_spi.c
new file mode 100644
index 000000000..14a0da9cd
--- /dev/null
+++ b/src/conftest/hooks/set_ike_spi.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+#include <encoding/payloads/unknown_payload.h>
+
+typedef struct private_set_ike_spi_t private_set_ike_spi_t;
+
+/**
+ * Private data of an set_ike_spi_t object.
+ */
+struct private_set_ike_spi_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+
+ /**
+ * Alter requests or responses?
+ */
+ bool req;
+
+ /**
+ * ID of message to alter.
+ */
+ int id;
+
+ /**
+ * Initiator SPI
+ */
+ u_int64_t spii;
+
+ /**
+ * Responder SPI
+ */
+ u_int64_t spir;
+};
+
+METHOD(listener_t, message, bool,
+ private_set_ike_spi_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (!incoming &&
+ message->get_request(message) == this->req &&
+ message->get_message_id(message) == this->id)
+ {
+ ike_sa_id_t *id;
+
+ DBG1(DBG_CFG, "setting IKE SPIs to: 0x%llx/0x%llx",
+ this->spii, this->spir);
+
+ id = message->get_ike_sa_id(message);
+ id->set_initiator_spi(id, this->spii);
+ id->set_responder_spi(id, this->spir);
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_set_ike_spi_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *set_ike_spi_hook_create(char *name)
+{
+ private_set_ike_spi_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ .req = conftest->test->get_bool(conftest->test,
+ "hooks.%s.request", TRUE, name),
+ .id = conftest->test->get_int(conftest->test,
+ "hooks.%s.id", 0, name),
+ .spii = strtoull(conftest->test->get_str(conftest->test,
+ "hooks.%s.spii", "0", name), NULL, 16),
+ .spir = strtoull(conftest->test->get_str(conftest->test,
+ "hooks.%s.spir", "0", name), NULL, 16),
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/set_ike_version.c b/src/conftest/hooks/set_ike_version.c
new file mode 100644
index 000000000..d2de9dc81
--- /dev/null
+++ b/src/conftest/hooks/set_ike_version.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+#include <encoding/payloads/unknown_payload.h>
+
+typedef struct private_set_ike_version_t private_set_ike_version_t;
+
+/**
+ * Private data of an set_ike_version_t object.
+ */
+struct private_set_ike_version_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+
+ /**
+ * Alter requests or responses?
+ */
+ bool req;
+
+ /**
+ * ID of message to alter.
+ */
+ int id;
+
+ /**
+ * Major version to set
+ */
+ int major;
+
+ /**
+ * Minor version to set
+ */
+ int minor;
+
+ /**
+ * Higher version supported?
+ */
+ bool higher;
+};
+
+METHOD(listener_t, message, bool,
+ private_set_ike_version_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (!incoming &&
+ message->get_request(message) == this->req &&
+ message->get_message_id(message) == this->id)
+ {
+ DBG1(DBG_CFG, "setting IKE version of message ID %d to %d.%d",
+ this->id, this->major, this->minor);
+ message->set_major_version(message, this->major);
+ message->set_minor_version(message, this->minor);
+ if (this->higher)
+ {
+ message->set_version_flag(message);
+ }
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_set_ike_version_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *set_ike_version_hook_create(char *name)
+{
+ private_set_ike_version_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ .req = conftest->test->get_bool(conftest->test,
+ "hooks.%s.request", TRUE, name),
+ .id = conftest->test->get_int(conftest->test,
+ "hooks.%s.id", 0, name),
+ .major = conftest->test->get_int(conftest->test,
+ "hooks.%s.major", 2, name),
+ .minor = conftest->test->get_int(conftest->test,
+ "hooks.%s.minor", 0, name),
+ .higher = conftest->test->get_bool(conftest->test,
+ "hooks.%s.higher", FALSE, name),
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/set_length.c b/src/conftest/hooks/set_length.c
new file mode 100644
index 000000000..0379dcb7c
--- /dev/null
+++ b/src/conftest/hooks/set_length.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+typedef struct private_set_length_t private_set_length_t;
+
+/**
+ * Private data of an set_length_t object.
+ */
+struct private_set_length_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+
+ /**
+ * Alter requests or responses?
+ */
+ bool req;
+
+ /**
+ * ID of message to alter.
+ */
+ int id;
+
+ /**
+ * Payload type
+ */
+ char *type;
+
+ /**
+ * Difference to correct length
+ */
+ int diff;
+};
+
+METHOD(listener_t, message, bool,
+ private_set_length_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (!incoming &&
+ message->get_request(message) == this->req &&
+ message->get_message_id(message) == this->id)
+ {
+ payload_t *payload;
+ enumerator_t *enumerator;
+ payload_type_t type;
+
+ type = atoi(this->type);
+ if (!type)
+ {
+ type = enum_from_name(payload_type_short_names, this->type);
+ if (type == -1)
+ {
+ DBG1(DBG_CFG, "unknown payload: '%s', skipped", this->type);
+ return TRUE;
+ }
+ }
+ enumerator = message->create_payload_enumerator(message);
+ while (enumerator->enumerate(enumerator, &payload))
+ {
+ if (type == payload->get_type(payload))
+ {
+ encoding_rule_t *rules;
+ size_t count;
+ u_int16_t *len;
+ int i;
+
+ payload->get_encoding_rules(payload, &rules, &count);
+ for (i = 0; i < count; i++)
+ {
+ if (rules[i].type == PAYLOAD_LENGTH)
+ {
+ len = (u_int16_t*)(((void*)payload) + rules[i].offset);
+ DBG1(DBG_CFG, "adjusting length of %N payload "
+ "from %d to %d", payload_type_short_names, type,
+ *len, *len + this->diff);
+ *len = *len + this->diff;
+ }
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_set_length_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *set_length_hook_create(char *name)
+{
+ private_set_length_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ .req = conftest->test->get_bool(conftest->test,
+ "hooks.%s.request", TRUE, name),
+ .id = conftest->test->get_int(conftest->test,
+ "hooks.%s.id", 0, name),
+ .type = conftest->test->get_str(conftest->test,
+ "hooks.%s.type", "", name),
+ .diff = conftest->test->get_int(conftest->test,
+ "hooks.%s.diff", 0, name),
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/set_proposal_number.c b/src/conftest/hooks/set_proposal_number.c
new file mode 100644
index 000000000..a59d96b6d
--- /dev/null
+++ b/src/conftest/hooks/set_proposal_number.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+#include <encoding/payloads/sa_payload.h>
+
+typedef struct private_set_proposal_number_t private_set_proposal_number_t;
+
+/**
+ * Private data of an set_proposal_number_t object.
+ */
+struct private_set_proposal_number_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+
+ /**
+ * Alter requests or responses?
+ */
+ bool req;
+
+ /**
+ * ID of message to alter.
+ */
+ int id;
+
+ /**
+ * Proposal number to modify
+ */
+ int from;
+
+ /**
+ * Proposal number to set
+ */
+ int to;
+};
+
+/**
+ * Copy all algs from given type from one proposal to another
+ */
+static void copy_proposal_algs(proposal_t *from, proposal_t *to,
+ transform_type_t type)
+{
+ enumerator_t *enumerator;
+ u_int16_t alg, key_size;
+
+ enumerator = from->create_enumerator(from, type);
+ while (enumerator->enumerate(enumerator, &alg, &key_size))
+ {
+ to->add_algorithm(to, type, alg, key_size);
+ }
+ enumerator->destroy(enumerator);
+}
+
+METHOD(listener_t, message, bool,
+ private_set_proposal_number_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (!incoming &&
+ message->get_request(message) == this->req &&
+ message->get_message_id(message) == this->id)
+ {
+ enumerator_t *enumerator;
+ payload_t *payload;
+ linked_list_t *list = NULL, *updated;
+ sa_payload_t *sa;
+ proposal_t *proposal, *new;
+
+ updated = linked_list_create();
+ enumerator = message->create_payload_enumerator(message);
+ while (enumerator->enumerate(enumerator, &payload))
+ {
+ if (payload->get_type(payload) == SECURITY_ASSOCIATION)
+ {
+ sa = (sa_payload_t*)payload;
+ list = sa->get_proposals(sa);
+ message->remove_payload_at(message, enumerator);
+ sa->destroy(sa);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (list)
+ {
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &proposal))
+ {
+ if (proposal->get_number(proposal) == this->from)
+ {
+ DBG1(DBG_CFG, "setting proposal number from %d to %d",
+ this->from, this->to);
+ new = proposal_create(proposal->get_protocol(proposal),
+ this->to);
+ copy_proposal_algs(proposal, new, ENCRYPTION_ALGORITHM);
+ copy_proposal_algs(proposal, new, INTEGRITY_ALGORITHM);
+ copy_proposal_algs(proposal, new, PSEUDO_RANDOM_FUNCTION);
+ copy_proposal_algs(proposal, new, DIFFIE_HELLMAN_GROUP);
+ copy_proposal_algs(proposal, new, EXTENDED_SEQUENCE_NUMBERS);
+ updated->insert_last(updated, new);
+ }
+ else
+ {
+ list->remove_at(list, enumerator);
+ updated->insert_last(updated, proposal);
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ sa = sa_payload_create_from_proposal_list(updated);
+ list->destroy_offset(list, offsetof(proposal_t, destroy));
+ updated->destroy_offset(updated, offsetof(proposal_t, destroy));
+ message->add_payload(message, (payload_t*)sa);
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_set_proposal_number_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *set_proposal_number_hook_create(char *name)
+{
+ private_set_proposal_number_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ .req = conftest->test->get_bool(conftest->test,
+ "hooks.%s.request", TRUE, name),
+ .id = conftest->test->get_int(conftest->test,
+ "hooks.%s.id", 0, name),
+ .from = conftest->test->get_int(conftest->test,
+ "hooks.%s.from", 0, name),
+ .to = conftest->test->get_int(conftest->test,
+ "hooks.%s.to", 1, name),
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/set_reserved.c b/src/conftest/hooks/set_reserved.c
new file mode 100644
index 000000000..77a605d2a
--- /dev/null
+++ b/src/conftest/hooks/set_reserved.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+#include <encoding/payloads/sa_payload.h>
+
+typedef struct private_set_reserved_t private_set_reserved_t;
+
+/**
+ * Private data of an set_reserved_t object.
+ */
+struct private_set_reserved_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+
+ /**
+ * Alter requests or responses?
+ */
+ bool req;
+
+ /**
+ * ID of message to alter.
+ */
+ int id;
+
+ /**
+ * Hook name
+ */
+ char *name;
+};
+
+/**
+ * Set reserved bit of a payload
+ */
+static void set_bit(private_set_reserved_t *this, message_t *message,
+ payload_type_t type, u_int nr)
+{
+ enumerator_t *payloads;
+ payload_t *payload;
+ bool *bit;
+
+ if (type == HEADER)
+ {
+ message->set_reserved_header_bit(message, nr);
+ DBG1(DBG_CFG, "setting reserved bit %d of %N",
+ nr, payload_type_short_names, type);
+ }
+ else
+ {
+ payloads = message->create_payload_enumerator(message);
+ while (payloads->enumerate(payloads, &payload))
+ {
+ if (payload->get_type(payload) == type)
+ {
+ bit = payload_get_field(payload, RESERVED_BIT, nr);
+ if (bit)
+ {
+ DBG1(DBG_CFG, "setting reserved bit %d of %N",
+ nr, payload_type_short_names, type);
+ *bit = TRUE;
+ }
+ }
+ }
+ payloads->destroy(payloads);
+ }
+}
+
+/**
+ * Set reserved byte of a payload
+ */
+static void set_byte(private_set_reserved_t *this, message_t *message,
+ payload_type_t type, u_int nr, u_int8_t byteval)
+{
+ enumerator_t *payloads;
+ payload_t *payload;
+ u_int8_t *byte;
+
+ if (type == TRANSFORM_SUBSTRUCTURE || type == PROPOSAL_SUBSTRUCTURE)
+ {
+ enumerator_t *transforms, *proposals;
+ transform_substructure_t *transform;
+ proposal_substructure_t *proposal;
+ sa_payload_t *sa;
+
+ payloads = message->create_payload_enumerator(message);
+ while (payloads->enumerate(payloads, &payload))
+ {
+ if (payload->get_type(payload) == SECURITY_ASSOCIATION)
+ {
+ sa = (sa_payload_t*)payload;
+ proposals = sa->create_substructure_enumerator(sa);
+ while (proposals->enumerate(proposals, &proposal))
+ {
+ if (type == PROPOSAL_SUBSTRUCTURE)
+ {
+ byte = payload_get_field(&proposal->payload_interface,
+ RESERVED_BYTE, nr);
+ if (byte)
+ {
+ DBG1(DBG_CFG, "setting reserved byte %d of %N to %d",
+ nr, payload_type_short_names, type, byteval);
+ *byte = byteval;
+ }
+ }
+ else if (type == TRANSFORM_SUBSTRUCTURE)
+ {
+ transforms = proposal->create_substructure_enumerator(
+ proposal);
+ while (transforms->enumerate(transforms, &transform))
+ {
+ byte = payload_get_field(&transform->payload_interface,
+ RESERVED_BYTE, nr);
+ if (byte)
+ {
+ DBG1(DBG_CFG, "setting reserved byte %d of %N to %d",
+ nr, payload_type_short_names, type, byteval);
+ *byte = byteval;
+ }
+ }
+ transforms->destroy(transforms);
+ }
+ }
+ proposals->destroy(proposals);
+ }
+ }
+ payloads->destroy(payloads);
+ }
+ else
+ {
+ payloads = message->create_payload_enumerator(message);
+ while (payloads->enumerate(payloads, &payload))
+ {
+ if (payload->get_type(payload) == type)
+ {
+ byte = payload_get_field(payload, RESERVED_BYTE, nr);
+ if (byte)
+ {
+ DBG1(DBG_CFG, "setting reserved byte %d of %N to %d",
+ nr, payload_type_short_names, type, byteval);
+ *byte = byteval;
+ }
+ }
+ }
+ payloads->destroy(payloads);
+ }
+}
+
+METHOD(listener_t, message, bool,
+ private_set_reserved_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (!incoming &&
+ message->get_request(message) == this->req &&
+ message->get_message_id(message) == this->id)
+ {
+ enumerator_t *bits, *bytes, *types;
+ payload_type_t type;
+ char *nr, *name;
+ u_int8_t byteval;
+
+ types = conftest->test->create_section_enumerator(conftest->test,
+ "hooks.%s", this->name);
+ while (types->enumerate(types, &name))
+ {
+ type = atoi(name);
+ if (!type)
+ {
+ type = enum_from_name(payload_type_short_names, name);
+ if (type == -1)
+ {
+ DBG1(DBG_CFG, "invalid payload name '%s'", name);
+ break;
+ }
+ }
+ nr = conftest->test->get_str(conftest->test,
+ "hooks.%s.%s.bits", "", this->name, name);
+ bits = enumerator_create_token(nr, ",", " ");
+ while (bits->enumerate(bits, &nr))
+ {
+ set_bit(this, message, type, atoi(nr));
+ }
+ bits->destroy(bits);
+
+ nr = conftest->test->get_str(conftest->test,
+ "hooks.%s.%s.bytes", "", this->name, name);
+ byteval = conftest->test->get_int(conftest->test,
+ "hooks.%s.%s.byteval", 255, this->name, name);
+ bytes = enumerator_create_token(nr, ",", " ");
+ while (bytes->enumerate(bytes, &nr))
+ {
+ set_byte(this, message, type, atoi(nr), byteval);
+ }
+ bytes->destroy(bytes);
+ }
+ types->destroy(types);
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_set_reserved_t *this)
+{
+ free(this->name);
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *set_reserved_hook_create(char *name)
+{
+ private_set_reserved_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ .req = conftest->test->get_bool(conftest->test,
+ "hooks.%s.request", TRUE, name),
+ .id = conftest->test->get_int(conftest->test,
+ "hooks.%s.id", 0, name),
+ .name = strdup(name),
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/unencrypted_notify.c b/src/conftest/hooks/unencrypted_notify.c
new file mode 100644
index 000000000..80bdc64b7
--- /dev/null
+++ b/src/conftest/hooks/unencrypted_notify.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+typedef struct private_unencrypted_notify_t private_unencrypted_notify_t;
+
+/**
+ * Private data of an unencrypted_notify_t object.
+ */
+struct private_unencrypted_notify_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+
+ /**
+ * ID of message send.
+ */
+ int id;
+
+ /**
+ * Notify type
+ */
+ char *type;
+
+ /**
+ * Notify data
+ */
+ char *data;
+
+ /**
+ * SPI of notify
+ */
+ int spi;
+
+ /**
+ * TRUE for a ESP protocol notify, FALSE for IKE
+ */
+ bool esp;
+};
+
+METHOD(listener_t, ike_updown, bool,
+ private_unencrypted_notify_t *this, ike_sa_t *ike_sa, bool up)
+{
+ if (up)
+ {
+ message_t *message;
+ host_t *host;
+ notify_type_t type;
+ notify_payload_t *notify;
+ chunk_t data = chunk_empty;
+ packet_t *packet;
+
+ type = atoi(this->type);
+ if (!type)
+ {
+ type = enum_from_name(notify_type_names, this->type);
+ if (type == -1)
+ {
+ DBG1(DBG_CFG, "unknown notify: '%s', skipped", this->type);
+ return TRUE;
+ }
+ }
+ if (strncaseeq(this->data, "0x", 2))
+ {
+ data = chunk_skip(chunk_create(this->data, strlen(this->data)), 2);
+ data = chunk_from_hex(data, NULL);
+ }
+ else if (this->data && strlen(this->data))
+ {
+ data = chunk_clone(chunk_create(this->data, strlen(this->data)));
+ }
+ notify = notify_payload_create_from_protocol_and_type(
+ this->esp ? PROTO_ESP : PROTO_IKE, type);
+ notify->set_spi(notify, this->spi);
+ if (data.len)
+ {
+ notify->set_notification_data(notify, data);
+ free(data.ptr);
+ }
+
+ DBG1(DBG_CFG, "injecting unencrypted INFORMATIONAL message");
+
+ message = message_create();
+ message->set_message_id(message, this->id);
+ message->set_ike_sa_id(message, ike_sa->get_id(ike_sa));
+ message->set_exchange_type(message, INFORMATIONAL);
+ message->set_request(message, TRUE);
+ host = ike_sa->get_my_host(ike_sa);
+ message->set_source(message, host->clone(host));
+ host = ike_sa->get_other_host(ike_sa);
+ message->set_destination(message, host->clone(host));
+ message->add_payload(message, &notify->payload_interface);
+ if (message->generate(message, NULL, &packet) != SUCCESS)
+ {
+ DBG1(DBG_CFG, "generating message failed");
+ message->destroy(message);
+ return TRUE;
+ }
+ message->destroy(message);
+ charon->sender->send(charon->sender, packet);
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_unencrypted_notify_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *unencrypted_notify_hook_create(char *name)
+{
+ private_unencrypted_notify_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .ike_updown = _ike_updown,
+ },
+ .destroy = _destroy,
+ },
+ .id = conftest->test->get_int(conftest->test,
+ "hooks.%s.id", 2, name),
+ .type = conftest->test->get_str(conftest->test,
+ "hooks.%s.type", "", name),
+ .data = conftest->test->get_str(conftest->test,
+ "hooks.%s.data", "", name),
+ .spi = conftest->test->get_int(conftest->test,
+ "hooks.%s.spi", 0, name),
+ .esp = conftest->test->get_bool(conftest->test,
+ "hooks.%s.esp", FALSE, name),
+ );
+
+ return &this->hook;
+}
diff --git a/src/conftest/hooks/unsort_message.c b/src/conftest/hooks/unsort_message.c
new file mode 100644
index 000000000..b37b261a4
--- /dev/null
+++ b/src/conftest/hooks/unsort_message.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "hook.h"
+
+typedef struct private_unsort_message_t private_unsort_message_t;
+
+/**
+ * Private data of an unsort_message_t object.
+ */
+struct private_unsort_message_t {
+
+ /**
+ * Implements the hook_t interface.
+ */
+ hook_t hook;
+
+ /**
+ * Alter requests or responses?
+ */
+ bool req;
+
+ /**
+ * ID of message to alter.
+ */
+ int id;
+
+ /**
+ * Order of payloads we want
+ */
+ char *order;
+};
+
+METHOD(listener_t, message, bool,
+ private_unsort_message_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming)
+{
+ if (!incoming &&
+ message->get_request(message) == this->req &&
+ message->get_message_id(message) == this->id)
+ {
+ enumerator_t *enumerator, *order;
+ linked_list_t *list;
+ payload_type_t type;
+ payload_t *payload;
+ char *name;
+
+ list = linked_list_create();
+ enumerator = message->create_payload_enumerator(message);
+ while (enumerator->enumerate(enumerator, &payload))
+ {
+ message->remove_payload_at(message, enumerator);
+ list->insert_last(list, payload);
+ }
+ enumerator->destroy(enumerator);
+
+ order = enumerator_create_token(this->order, ", ", " ");
+ while (order->enumerate(order, &name))
+ {
+ type = enum_from_name(payload_type_short_names, name);
+ if (type != -1)
+ {
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &payload))
+ {
+ if (payload->get_type(payload) == type)
+ {
+ list->remove_at(list, enumerator);
+ message->add_payload(message, payload);
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "unknown payload to sort: '%s', skipped", name);
+ }
+ }
+ order->destroy(order);
+
+ while (list->remove_first(list, (void**)&payload) == SUCCESS)
+ {
+ message->add_payload(message, payload);
+ }
+ list->destroy(list);
+
+ message->disable_sort(message);
+ }
+ return TRUE;
+}
+
+METHOD(hook_t, destroy, void,
+ private_unsort_message_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create the IKE_AUTH fill hook
+ */
+hook_t *unsort_message_hook_create(char *name)
+{
+ private_unsort_message_t *this;
+
+ INIT(this,
+ .hook = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ .req = conftest->test->get_bool(conftest->test,
+ "hooks.%s.request", TRUE, name),
+ .id = conftest->test->get_int(conftest->test,
+ "hooks.%s.id", 0, name),
+ .order = conftest->test->get_str(conftest->test,
+ "hooks.%s.order", "", name),
+ );
+
+ return &this->hook;
+}