first merge of NATT code

This commit is contained in:
Martin Willi
2006-06-22 06:36:28 +00:00
parent 6bf1352032
commit 1396815afb
46 changed files with 2973 additions and 772 deletions
+273 -16
View File
@@ -6,6 +6,7 @@
*/
/*
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
* Copyright (C) 2005 Jan Hutter, Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -19,6 +20,8 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <sys/time.h>
#include <string.h>
#include "ike_sa.h"
@@ -32,6 +35,7 @@
#include <crypto/diffie_hellman.h>
#include <crypto/prf_plus.h>
#include <crypto/crypters/crypter.h>
#include <crypto/hashers/hasher.h>
#include <encoding/payloads/sa_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <encoding/payloads/ke_payload.h>
@@ -173,6 +177,31 @@ struct private_ike_sa_t {
* A logger for this IKE_SA.
*/
logger_t *logger;
/**
* NAT hasher.
*/
hasher_t *nat_hasher;
/**
* NAT status of local host.
*/
bool nat_here;
/**
* NAT status of remote host.
*/
bool nat_there;
/**
* Timestamp of last IKE message sent or received on this SA
*/
struct timeval last_msg_tv;
/*
* Message ID of last DPD message
*/
u_int32_t last_dpd_message_id;
};
/**
@@ -320,24 +349,25 @@ static identification_t* get_other_id(private_ike_sa_t *this)
return this->policy->get_other_id(this->policy);;
}
/**
* Implementation of ike_sa_t.retransmit_possible.
*/
static bool retransmit_possible(private_ike_sa_t *this, u_int32_t message_id)
{
return ((this->last_requested_message)
&& (message_id != this->last_replied_message_id)
&& (message_id == this->last_requested_message->get_message_id(
this->last_requested_message)));
}
/**
* Implementation of ike_sa_t.retransmit_request.
*/
status_t retransmit_request (private_ike_sa_t *this, u_int32_t message_id)
static status_t retransmit_request(private_ike_sa_t *this, u_int32_t message_id)
{
packet_t *packet;
if (this->last_requested_message == NULL)
{
return NOT_FOUND;
}
if (message_id == this->last_replied_message_id)
{
return NOT_FOUND;
}
if ((this->last_requested_message->get_message_id(this->last_requested_message)) != message_id)
if (!this->protected.public.retransmit_possible(&this->protected.public, message_id))
{
return NOT_FOUND;
}
@@ -349,7 +379,6 @@ status_t retransmit_request (private_ike_sa_t *this, u_int32_t message_id)
return SUCCESS;
}
/**
* Implementation of protected_ike_sa_t.build_transforms.
*/
@@ -648,6 +677,12 @@ static status_t send_request(private_ike_sa_t *this, message_t *message)
"Increase message counter for outgoing messages from %d",
this->message_id_out);
this->message_id_out++;
/* bump last message sent timestamp */
if (gettimeofday(&this->last_msg_tv, NULL) < 0)
{
this->logger->log(this->logger, ERROR|LEVEL1, "failed to get time of day");
}
return SUCCESS;
}
@@ -869,6 +904,158 @@ static status_t initiate_connection(private_ike_sa_t *this, connection_t *connec
return current_state->initiate_connection(current_state, connection);
}
/**
* Implementation of protected_ike_sa_t.update_connection_hosts.
*
* Quoting RFC 4306:
*
* 2.11. Address and Port Agility
*
* IKE runs over UDP ports 500 and 4500, and implicitly sets up ESP and
* AH associations for the same IP addresses it runs over. The IP
* addresses and ports in the outer header are, however, not themselves
* cryptographically protected, and IKE is designed to work even through
* Network Address Translation (NAT) boxes. An implementation MUST
* accept incoming requests even if the source port is not 500 or 4500,
* and MUST respond to the address and port from which the request was
* received. It MUST specify the address and port at which the request
* was received as the source address and port in the response. IKE
* functions identically over IPv4 or IPv6.
*
* [...]
*
* There are cases where a NAT box decides to remove mappings that
* are still alive (for example, the keepalive interval is too long,
* or the NAT box is rebooted). To recover in these cases, hosts
* that are not behind a NAT SHOULD send all packets (including
* retransmission packets) to the IP address and port from the last
* valid authenticated packet from the other end (i.e., dynamically
* update the address). A host behind a NAT SHOULD NOT do this
* because it opens a DoS attack possibility. Any authenticated IKE
* packet or any authenticated UDP-encapsulated ESP packet can be
* used to detect that the IP address or the port has changed.
*/
static status_t update_connection_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
{
host_t *old_other = NULL;
iterator_t *iterator = NULL;
child_sa_t *child_sa = NULL;
int my_changes, other_changes;
ike_sa_state_t s;
my_changes = me->get_differences(me, this->connection->get_my_host(this->connection));
old_other = this->connection->get_other_host(this->connection);
other_changes = other->get_differences(other, old_other);
if (!my_changes && !other_changes) {
return SUCCESS;
}
if (my_changes)
{
this->connection->update_my_host(this->connection, me->clone(me));
}
s = this->protected.public.get_state(&this->protected.public);
if (s == RESPONDER_INIT || s == IKE_SA_INIT_REQUESTED || !this->nat_here)
{
if (other_changes)
{
this->connection->update_other_host(this->connection, other->clone(other));
}
}
else
{
if (other_changes & HOST_DIFF_ADDR)
{
this->logger->log(this->logger, ERROR|LEVEL1,
"Destination ip changed from %s to %s. As we are NATed this is not allowed!",
old_other->get_address(old_other), other->get_address(other));
return DESTROY_ME;
}
else if (other_changes & HOST_DIFF_PORT)
{
old_other->set_port(old_other, other->get_port(other));
}
}
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
while (iterator->iterate(iterator, (void**)&child_sa))
{
child_sa->update_hosts(child_sa,
this->connection->get_my_host(this->connection),
this->connection->get_other_host(this->connection),
my_changes, other_changes);
/* XXX error handling */
}
iterator->destroy(iterator);
return SUCCESS;
}
/**
* Implementation of protected_ike_sa_t.build_transforms.
* TODO: IPv6 support.
*/
static chunk_t generate_natd_hash(private_ike_sa_t *this, u_int64_t spi_i, u_int64_t spi_r, host_t *host)
{
chunk_t natd_string;
chunk_t natd_hash;
void *p;
struct sockaddr_in* sai;
char buf[512];
natd_hash = chunk_alloc(this->nat_hasher->get_hash_size(this->nat_hasher));
natd_string = chunk_alloc(8 + 8 + 4 + 2);
sai = (struct sockaddr_in*)host->get_sockaddr(host);
p = natd_string.ptr;
*(u_int64_t*)p = spi_i; p += sizeof(spi_i);
*(u_int64_t*)p = spi_r; p += sizeof(spi_r);
*(u_int32_t*)p = sai->sin_addr.s_addr; p += sizeof(sai->sin_addr.s_addr);
*(u_int16_t*)p = sai->sin_port; p += sizeof(sai->sin_port);
this->nat_hasher->get_hash(this->nat_hasher, natd_string, natd_hash.ptr);
this->nat_hasher->reset(this->nat_hasher);
sprintf(buf, "natd_hash(%016llx %016llx %s:%d)\n == SHA1(", spi_i, spi_r,
host->get_address(host), host->get_port(host));
chunk_to_hex(buf + strlen(buf), sizeof(buf) - strlen(buf), natd_string);
strcat(buf, ") == ");
chunk_to_hex(buf + strlen(buf), sizeof(buf) - strlen(buf), natd_hash);
this->logger->log(this->logger, CONTROL|LEVEL3, buf);
chunk_free(&natd_string);
return natd_hash;
}
/**
* Implementation of ike_sa_t.send_dpd_request.
*/
static status_t send_dpd_request(private_ike_sa_t *this)
{
message_t *dpd_msg;
status_t status;
this->protected.build_message(&this->protected, INFORMATIONAL, TRUE, &dpd_msg);
status = this->protected.send_request(&this->protected, dpd_msg);
if (status != SUCCESS)
{
dpd_msg->destroy(dpd_msg);
}
this->last_dpd_message_id = dpd_msg->get_message_id(dpd_msg);
return status;
}
/**
* Implementation of ike_sa_t.get_last_dpd_message_id
*/
static u_int32_t get_last_dpd_message_id(private_ike_sa_t *this)
{
return this->last_dpd_message_id;
}
/**
* Implementation of ike_sa_t.get_child_sa.
*/
@@ -1026,7 +1213,8 @@ static status_t rekey_child_sa(private_ike_sa_t *this, u_int32_t reqid)
this->connection->get_my_host(this->connection),
this->connection->get_other_host(this->connection),
this->policy->get_soft_lifetime(this->policy),
this->policy->get_hard_lifetime(this->policy));
this->policy->get_hard_lifetime(this->policy),
this->nat_here || this->nat_there);
child_sa->alloc(child_sa, proposals);
sa_payload = sa_payload_create_from_proposal_list(proposals);
request->add_payload(request, (payload_t*)sa_payload);
@@ -1183,6 +1371,57 @@ static status_t delete_(private_ike_sa_t *this)
return SUCCESS;
}
/**
* Implementation of ike_sa_t.is_my_host_behind_nat.
*/
static bool is_my_host_behind_nat (private_ike_sa_t *this)
{
return this->nat_here;
}
/**
* Implementation of ike_sa_t.is_other_host_behind_nat.
*/
static bool is_other_host_behind_nat (private_ike_sa_t *this)
{
return this->nat_there;
}
/**
* Implementation of ike_sa_t.is_any_host_behind_nat.
*/
static bool is_any_host_behind_nat (private_ike_sa_t *this)
{
return this->nat_here || this->nat_there;
}
/**
* Implementation of protected_ike_sa_t.set_my_host_behind_nat.
*/
static void set_my_host_behind_nat (private_ike_sa_t *this, bool nat)
{
this->nat_here = nat;
}
/**
* Implementation of protected_ike_sa_t.set_other_host_behind_nat.
*/
static void set_other_host_behind_nat (private_ike_sa_t *this, bool nat)
{
this->nat_there = nat;
}
/**
* Implementation of ike_sa_t.get_last_msg_tv.
*/
static struct timeval get_last_msg_tv (private_ike_sa_t *this)
{
/*
* XXX: query kernel for last activity time
*/
return this->last_msg_tv;
}
/**
* Implementation of protected_ike_sa_t.destroy.
*/
@@ -1269,6 +1508,7 @@ static void destroy(private_ike_sa_t *this)
{
this->last_responded_message->destroy(this->last_responded_message);
}
this->nat_hasher->destroy(this->nat_hasher);
this->ike_sa_id->destroy(this->ike_sa_id);
this->randomizer->destroy(this->randomizer);
this->current_state->destroy(this->current_state);
@@ -1294,11 +1534,17 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->protected.public.get_my_id = (identification_t*(*)(ike_sa_t*)) get_my_id;
this->protected.public.get_other_id = (identification_t*(*)(ike_sa_t*)) get_other_id;
this->protected.public.get_connection = (connection_t*(*)(ike_sa_t*)) get_connection;
this->protected.public.retransmit_possible = (bool (*) (ike_sa_t *, u_int32_t)) retransmit_possible;
this->protected.public.retransmit_request = (status_t (*) (ike_sa_t *, u_int32_t)) retransmit_request;
this->protected.public.get_state = (ike_sa_state_t (*) (ike_sa_t *this)) get_state;
this->protected.public.log_status = (void (*) (ike_sa_t*,logger_t*,char*))log_status;
this->protected.public.delete = (status_t(*)(ike_sa_t*))delete_;
this->protected.public.destroy = (void(*)(ike_sa_t*))destroy;
this->protected.public.is_my_host_behind_nat = (bool(*)(ike_sa_t*)) is_my_host_behind_nat;
this->protected.public.is_other_host_behind_nat = (bool(*)(ike_sa_t*)) is_other_host_behind_nat;
this->protected.public.is_any_host_behind_nat = (bool(*)(ike_sa_t*)) is_any_host_behind_nat;
this->protected.public.get_last_msg_tv = (struct timeval (*)(ike_sa_t*)) get_last_msg_tv;
this->protected.public.send_dpd_request = (status_t (*)(ike_sa_t*)) send_dpd_request;
/* protected functions */
this->protected.build_message = (void (*) (protected_ike_sa_t *, exchange_type_t,bool,message_t**)) build_message;
@@ -1327,6 +1573,11 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->protected.set_last_replied_message_id = (void (*) (protected_ike_sa_t *,u_int32_t)) set_last_replied_message_id;
this->protected.destroy_child_sa = (u_int32_t (*)(protected_ike_sa_t*,u_int32_t))destroy_child_sa;
this->protected.get_child_sa = (child_sa_t* (*)(protected_ike_sa_t*,u_int32_t))get_child_sa_by_spi;
this->protected.set_my_host_behind_nat = (void(*)(protected_ike_sa_t*, bool)) set_my_host_behind_nat;
this->protected.set_other_host_behind_nat = (void(*)(protected_ike_sa_t*, bool)) set_other_host_behind_nat;
this->protected.generate_natd_hash = (chunk_t (*) (protected_ike_sa_t *, u_int64_t, u_int64_t, host_t*)) generate_natd_hash;
this->protected.get_last_dpd_message_id = (u_int32_t (*) (protected_ike_sa_t*)) get_last_dpd_message_id;
this->protected.update_connection_hosts = (status_t (*) (protected_ike_sa_t *, host_t*, host_t*)) update_connection_hosts;
/* initialize private fields */
this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
@@ -1350,7 +1601,13 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->child_prf = NULL;
this->connection = NULL;
this->policy = NULL;
this->nat_hasher = hasher_create(HASH_SHA1);
this->nat_here = FALSE;
this->nat_there = FALSE;
this->last_msg_tv.tv_sec = 0;
this->last_msg_tv.tv_usec = 0;
this->last_dpd_message_id = 0;
/* at creation time, IKE_SA is in a initiator state */
if (ike_sa_id->is_initiator(ike_sa_id))
{