mem-pool: Pass the remote IKE address, to re-acquire() an address during reauth

With make-before-break IKEv2 re-authentication, virtual IP addresses must be
assigned overlapping to the same peer. With the remote IKE address, the backend
can detect re-authentication attempts by comparing the remote host address and
port. This allows proper reassignment of the virtual IP if it is re-requested.

This change removes the mem-pool.reassign_online option, as it is obsolete now.
IPs get automatically reassigned if a peer re-requests the same address, and
additionally connects from the same address and port.
This commit is contained in:
Martin Willi 2014-11-04 16:32:33 +01:00
parent 3676023e54
commit 22e6a06b8c
7 changed files with 87 additions and 55 deletions

View File

@ -206,10 +206,6 @@ charon.make_before_break = no
gaps during reauthentication, but requires support for overlapping SAs by gaps during reauthentication, but requires support for overlapping SAs by
the peer. strongSwan can handle such overlapping SAs since version 5.3.0. the peer. strongSwan can handle such overlapping SAs since version 5.3.0.
charon.mem-pool.reassign_online = no
Reassign an online IP address lease from an in-memory address pool if a
client with the same identity requests it explicitly.
charon.multiple_authentication = yes charon.multiple_authentication = yes
Enable multiple authentication exchanges (RFC 4739). Enable multiple authentication exchanges (RFC 4739).

View File

@ -70,20 +70,25 @@ struct private_mem_pool_t {
* lock to safely access the pool * lock to safely access the pool
*/ */
mutex_t *mutex; mutex_t *mutex;
/**
* Do we reassign online leases to the same identity, if requested?
*/
bool reassign_online;
}; };
/**
* A unique lease address offset, with a hash of the peer host address
*/
typedef struct {
/** lease, as offset */
u_int offset;
/** hash of remote address, to allow duplicates */
u_int hash;
} unique_lease_t;
/** /**
* Lease entry. * Lease entry.
*/ */
typedef struct { typedef struct {
/* identitiy reference */ /* identitiy reference */
identification_t *id; identification_t *id;
/* array of online leases, as u_int offset */ /* array of online leases, as unique_lease_t */
array_t *online; array_t *online;
/* array of offline leases, as u_int offset */ /* array of offline leases, as u_int offset */
array_t *offline; array_t *offline;
@ -98,7 +103,7 @@ static entry_t* entry_create(identification_t *id)
INIT(entry, INIT(entry,
.id = id->clone(id), .id = id->clone(id),
.online = array_create(sizeof(u_int), 0), .online = array_create(sizeof(unique_lease_t), 0),
.offline = array_create(sizeof(u_int), 0), .offline = array_create(sizeof(u_int), 0),
); );
return entry; return entry;
@ -239,13 +244,26 @@ METHOD(mem_pool_t, get_offline, u_int,
return count; return count;
} }
/**
* Create a unique hash for a remote address
*/
static u_int hash_addr(host_t *addr)
{
if (addr)
{
return chunk_hash_inc(addr->get_address(addr), addr->get_port(addr));
}
return 0;
}
/** /**
* Get an existing lease for id * Get an existing lease for id
*/ */
static int get_existing(private_mem_pool_t *this, identification_t *id, static int get_existing(private_mem_pool_t *this, identification_t *id,
host_t *requested) host_t *requested, host_t *peer)
{ {
enumerator_t *enumerator; enumerator_t *enumerator;
unique_lease_t *lease, reassign;
u_int *current; u_int *current;
entry_t *entry; entry_t *entry;
int offset = 0; int offset = 0;
@ -260,8 +278,9 @@ static int get_existing(private_mem_pool_t *this, identification_t *id,
enumerator = array_create_enumerator(entry->offline); enumerator = array_create_enumerator(entry->offline);
if (enumerator->enumerate(enumerator, &current)) if (enumerator->enumerate(enumerator, &current))
{ {
offset = *current; reassign.offset = offset = *current;
array_insert(entry->online, ARRAY_TAIL, current); reassign.hash = hash_addr(peer);
array_insert(entry->online, ARRAY_TAIL, &reassign);
array_remove_at(entry->offline, enumerator); array_remove_at(entry->offline, enumerator);
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
@ -270,19 +289,20 @@ static int get_existing(private_mem_pool_t *this, identification_t *id,
DBG1(DBG_CFG, "reassigning offline lease to '%Y'", id); DBG1(DBG_CFG, "reassigning offline lease to '%Y'", id);
return offset; return offset;
} }
if (!this->reassign_online) if (!peer)
{ {
return 0; return 0;
} }
/* check for a valid online lease to reassign */ /* check for a valid online lease to reassign */
enumerator = array_create_enumerator(entry->online); enumerator = array_create_enumerator(entry->online);
while (enumerator->enumerate(enumerator, &current)) while (enumerator->enumerate(enumerator, &lease))
{ {
if (*current == host2offset(this, requested)) if (lease->offset == host2offset(this, requested) &&
lease->hash == hash_addr(peer))
{ {
offset = *current; offset = lease->offset;
/* add an additional "online" entry */ /* add an additional "online" entry */
array_insert(entry->online, ARRAY_TAIL, current); array_insert(entry->online, ARRAY_TAIL, lease);
break; break;
} }
} }
@ -297,10 +317,10 @@ static int get_existing(private_mem_pool_t *this, identification_t *id,
/** /**
* Get a new lease for id * Get a new lease for id
*/ */
static int get_new(private_mem_pool_t *this, identification_t *id) static int get_new(private_mem_pool_t *this, identification_t *id, host_t *peer)
{ {
entry_t *entry; entry_t *entry;
u_int offset = 0; unique_lease_t lease = {};
if (this->unused < this->size) if (this->unused < this->size)
{ {
@ -311,28 +331,31 @@ static int get_new(private_mem_pool_t *this, identification_t *id)
this->leases->put(this->leases, entry->id, entry); this->leases->put(this->leases, entry->id, entry);
} }
/* assigning offset, starting by 1 */ /* assigning offset, starting by 1 */
offset = ++this->unused + (this->base_is_network_id ? 1 : 0); lease.offset = ++this->unused + (this->base_is_network_id ? 1 : 0);
array_insert(entry->online, ARRAY_TAIL, &offset); lease.hash = hash_addr(peer);
array_insert(entry->online, ARRAY_TAIL, &lease);
DBG1(DBG_CFG, "assigning new lease to '%Y'", id); DBG1(DBG_CFG, "assigning new lease to '%Y'", id);
} }
return offset; return lease.offset;
} }
/** /**
* Get a reassigned lease for id in case the pool is full * Get a reassigned lease for id in case the pool is full
*/ */
static int get_reassigned(private_mem_pool_t *this, identification_t *id) static int get_reassigned(private_mem_pool_t *this, identification_t *id,
host_t *peer)
{ {
enumerator_t *enumerator; enumerator_t *enumerator;
entry_t *entry; entry_t *entry;
u_int current, offset = 0; u_int current;
unique_lease_t lease = {};
enumerator = this->leases->create_enumerator(this->leases); enumerator = this->leases->create_enumerator(this->leases);
while (enumerator->enumerate(enumerator, NULL, &entry)) while (enumerator->enumerate(enumerator, NULL, &entry))
{ {
if (array_remove(entry->offline, ARRAY_HEAD, &current)) if (array_remove(entry->offline, ARRAY_HEAD, &current))
{ {
offset = current; lease.offset = current;
DBG1(DBG_CFG, "reassigning existing offline lease by '%Y'" DBG1(DBG_CFG, "reassigning existing offline lease by '%Y'"
" to '%Y'", entry->id, id); " to '%Y'", entry->id, id);
break; break;
@ -340,7 +363,7 @@ static int get_reassigned(private_mem_pool_t *this, identification_t *id)
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
if (offset) if (lease.offset)
{ {
entry = this->leases->get(this->leases, id); entry = this->leases->get(this->leases, id);
if (!entry) if (!entry)
@ -348,14 +371,15 @@ static int get_reassigned(private_mem_pool_t *this, identification_t *id)
entry = entry_create(id); entry = entry_create(id);
this->leases->put(this->leases, entry->id, entry); this->leases->put(this->leases, entry->id, entry);
} }
array_insert(entry->online, ARRAY_TAIL, &offset); lease.hash = hash_addr(peer);
array_insert(entry->online, ARRAY_TAIL, &lease);
} }
return offset; return lease.offset;
} }
METHOD(mem_pool_t, acquire_address, host_t*, METHOD(mem_pool_t, acquire_address, host_t*,
private_mem_pool_t *this, identification_t *id, host_t *requested, private_mem_pool_t *this, identification_t *id, host_t *requested,
mem_pool_op_t operation) mem_pool_op_t operation, host_t *peer)
{ {
int offset = 0; int offset = 0;
@ -376,13 +400,13 @@ METHOD(mem_pool_t, acquire_address, host_t*,
switch (operation) switch (operation)
{ {
case MEM_POOL_EXISTING: case MEM_POOL_EXISTING:
offset = get_existing(this, id, requested); offset = get_existing(this, id, requested, peer);
break; break;
case MEM_POOL_NEW: case MEM_POOL_NEW:
offset = get_new(this, id); offset = get_new(this, id, peer);
break; break;
case MEM_POOL_REASSIGN: case MEM_POOL_REASSIGN:
offset = get_reassigned(this, id); offset = get_reassigned(this, id, peer);
if (!offset) if (!offset)
{ {
DBG1(DBG_CFG, "pool '%s' is full, unable to assign address", DBG1(DBG_CFG, "pool '%s' is full, unable to assign address",
@ -407,7 +431,8 @@ METHOD(mem_pool_t, release_address, bool,
enumerator_t *enumerator; enumerator_t *enumerator;
bool found = FALSE, more = FALSE; bool found = FALSE, more = FALSE;
entry_t *entry; entry_t *entry;
u_int offset, *current; u_int offset;
unique_lease_t *current;
if (this->size != 0) if (this->size != 0)
{ {
@ -420,7 +445,7 @@ METHOD(mem_pool_t, release_address, bool,
enumerator = array_create_enumerator(entry->online); enumerator = array_create_enumerator(entry->online);
while (enumerator->enumerate(enumerator, &current)) while (enumerator->enumerate(enumerator, &current))
{ {
if (*current == offset) if (current->offset == offset)
{ {
if (!found) if (!found)
{ /* remove the first entry only */ { /* remove the first entry only */
@ -472,6 +497,7 @@ METHOD(enumerator_t, lease_enumerate, bool,
lease_enumerator_t *this, identification_t **id, host_t **addr, bool *online) lease_enumerator_t *this, identification_t **id, host_t **addr, bool *online)
{ {
u_int *offset; u_int *offset;
unique_lease_t *lease;
DESTROY_IF(this->addr); DESTROY_IF(this->addr);
this->addr = NULL; this->addr = NULL;
@ -480,10 +506,10 @@ METHOD(enumerator_t, lease_enumerate, bool,
{ {
if (this->entry) if (this->entry)
{ {
if (this->online->enumerate(this->online, &offset)) if (this->online->enumerate(this->online, &lease))
{ {
*id = this->entry->id; *id = this->entry->id;
*addr = this->addr = offset2host(this->pool, *offset); *addr = this->addr = offset2host(this->pool, lease->offset);
*online = TRUE; *online = TRUE;
return TRUE; return TRUE;
} }
@ -581,8 +607,6 @@ static private_mem_pool_t *create_generic(char *name)
.leases = hashtable_create((hashtable_hash_t)id_hash, .leases = hashtable_create((hashtable_hash_t)id_hash,
(hashtable_equals_t)id_equals, 16), (hashtable_equals_t)id_equals, 16),
.mutex = mutex_create(MUTEX_TYPE_DEFAULT), .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
.reassign_online = lib->settings->get_bool(lib->settings,
"%s.mem-pool.reassign_online", FALSE, lib->ns),
); );
return this; return this;

View File

@ -87,13 +87,21 @@ struct mem_pool_t {
* acquire a new lease (MEM_POOL_NEW), and if the pool is full once again * acquire a new lease (MEM_POOL_NEW), and if the pool is full once again
* to assign an existing offline lease (MEM_POOL_REASSIGN). * to assign an existing offline lease (MEM_POOL_REASSIGN).
* *
* If the same identity requests a virtual IP that is already assigned to
* it, the peer address and port is used to check if it is the same client
* instance that is connecting. If this is true, the request is considered
* a request for a reauthentication attempt, and the same virtual IP gets
* assigned to the peer.
*
* @param id the id to acquire an address for * @param id the id to acquire an address for
* @param requested acquire this address, if possible * @param requested acquire this address, if possible
* @param operation acquire operation to perform, see above * @param operation acquire operation to perform, see above
* @param peer optional remote IKE address and port
* @return the acquired address * @return the acquired address
*/ */
host_t* (*acquire_address)(mem_pool_t *this, identification_t *id, host_t* (*acquire_address)(mem_pool_t *this, identification_t *id,
host_t *requested, mem_pool_op_t operation); host_t *requested, mem_pool_op_t operation,
host_t *peer);
/** /**
* Release a previously acquired address. * Release a previously acquired address.

View File

@ -618,7 +618,7 @@ static host_t *allocate_addr(private_load_tester_config_t *this, uint num)
enumerator = this->pools->create_enumerator(this->pools); enumerator = this->pools->create_enumerator(this->pools);
while (enumerator->enumerate(enumerator, &pool)) while (enumerator->enumerate(enumerator, &pool))
{ {
found = pool->acquire_address(pool, id, requested, MEM_POOL_NEW); found = pool->acquire_address(pool, id, requested, MEM_POOL_NEW, NULL);
if (found) if (found)
{ {
iface = (char*)pool->get_name(pool); iface = (char*)pool->get_name(pool);

View File

@ -94,7 +94,7 @@ static mem_pool_t *find_pool(private_stroke_attribute_t *this, char *name)
*/ */
static host_t *find_addr(private_stroke_attribute_t *this, linked_list_t *pools, static host_t *find_addr(private_stroke_attribute_t *this, linked_list_t *pools,
identification_t *id, host_t *requested, identification_t *id, host_t *requested,
mem_pool_op_t operation) mem_pool_op_t operation, host_t *peer)
{ {
host_t *addr = NULL; host_t *addr = NULL;
enumerator_t *enumerator; enumerator_t *enumerator;
@ -107,7 +107,7 @@ static host_t *find_addr(private_stroke_attribute_t *this, linked_list_t *pools,
pool = find_pool(this, name); pool = find_pool(this, name);
if (pool) if (pool)
{ {
addr = pool->acquire_address(pool, id, requested, operation); addr = pool->acquire_address(pool, id, requested, operation, peer);
if (addr) if (addr)
{ {
break; break;
@ -124,19 +124,20 @@ METHOD(attribute_provider_t, acquire_address, host_t*,
host_t *requested) host_t *requested)
{ {
identification_t *id; identification_t *id;
host_t *addr; host_t *addr, *peer;
id = ike_sa->get_other_eap_id(ike_sa); id = ike_sa->get_other_eap_id(ike_sa);
peer = ike_sa->get_other_host(ike_sa);
this->lock->read_lock(this->lock); this->lock->read_lock(this->lock);
addr = find_addr(this, pools, id, requested, MEM_POOL_EXISTING); addr = find_addr(this, pools, id, requested, MEM_POOL_EXISTING, peer);
if (!addr) if (!addr)
{ {
addr = find_addr(this, pools, id, requested, MEM_POOL_NEW); addr = find_addr(this, pools, id, requested, MEM_POOL_NEW, peer);
if (!addr) if (!addr)
{ {
addr = find_addr(this, pools, id, requested, MEM_POOL_REASSIGN); addr = find_addr(this, pools, id, requested, MEM_POOL_REASSIGN, peer);
} }
} }

View File

@ -96,7 +96,8 @@ static void pool_destroy(pool_t *pool)
* Find an existing or not yet existing lease * Find an existing or not yet existing lease
*/ */
static host_t *find_addr(private_vici_attribute_t *this, linked_list_t *pools, static host_t *find_addr(private_vici_attribute_t *this, linked_list_t *pools,
identification_t *id, host_t *requested, mem_pool_op_t op) identification_t *id, host_t *requested,
mem_pool_op_t op, host_t *peer)
{ {
enumerator_t *enumerator; enumerator_t *enumerator;
host_t *addr = NULL; host_t *addr = NULL;
@ -109,7 +110,8 @@ static host_t *find_addr(private_vici_attribute_t *this, linked_list_t *pools,
pool = this->pools->get(this->pools, name); pool = this->pools->get(this->pools, name);
if (pool) if (pool)
{ {
addr = pool->vips->acquire_address(pool->vips, id, requested, op); addr = pool->vips->acquire_address(pool->vips, id, requested,
op, peer);
if (addr) if (addr)
{ {
break; break;
@ -126,19 +128,20 @@ METHOD(attribute_provider_t, acquire_address, host_t*,
host_t *requested) host_t *requested)
{ {
identification_t *id; identification_t *id;
host_t *addr; host_t *addr, *peer;
id = ike_sa->get_other_eap_id(ike_sa); id = ike_sa->get_other_eap_id(ike_sa);
peer = ike_sa->get_other_host(ike_sa);
this->lock->read_lock(this->lock); this->lock->read_lock(this->lock);
addr = find_addr(this, pools, id, requested, MEM_POOL_EXISTING); addr = find_addr(this, pools, id, requested, MEM_POOL_EXISTING, peer);
if (!addr) if (!addr)
{ {
addr = find_addr(this, pools, id, requested, MEM_POOL_NEW); addr = find_addr(this, pools, id, requested, MEM_POOL_NEW, peer);
if (!addr) if (!addr)
{ {
addr = find_addr(this, pools, id, requested, MEM_POOL_REASSIGN); addr = find_addr(this, pools, id, requested, MEM_POOL_REASSIGN, peer);
} }
} }

View File

@ -43,7 +43,7 @@ static void assert_acquire(mem_pool_t *pool, char *requested, char *expected,
id = identification_create_from_string("tester"); id = identification_create_from_string("tester");
req = host_create_from_string(requested, 0); req = host_create_from_string(requested, 0);
acquired = pool->acquire_address(pool, id, req, operation); acquired = pool->acquire_address(pool, id, req, operation, NULL);
assert_host(expected, acquired); assert_host(expected, acquired);
DESTROY_IF(acquired); DESTROY_IF(acquired);