diff options
author | Tobias Brunner <tobias@strongswan.org> | 2014-10-24 15:40:09 +0200 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2014-10-30 12:32:44 +0100 |
commit | 9d2a3554e5ca88b190f95a0616ae2fe05bb4062b (patch) | |
tree | fd267ce7c764e56a2f7daa5d5636158cf6bb4e49 | |
parent | 1201ddcbc5dda4849524f08a0923071d1b15b387 (diff) | |
download | strongswan-9d2a3554e5ca88b190f95a0616ae2fe05bb4062b.tar.bz2 strongswan-9d2a3554e5ca88b190f95a0616ae2fe05bb4062b.tar.xz |
mem-pool: Correctly ignore first and last addresses of subnets and adjust size
Previously one more than the first and last address was ignored.
And if the base address is not the network ID of the subnet we
should not skip it. But we should adjust the size as it does not
represent the actual number of IP addresses assignable.
-rw-r--r-- | src/libhydra/attributes/mem_pool.c | 56 |
1 files changed, 49 insertions, 7 deletions
diff --git a/src/libhydra/attributes/mem_pool.c b/src/libhydra/attributes/mem_pool.c index cc45e5629..225abe383 100644 --- a/src/libhydra/attributes/mem_pool.c +++ b/src/libhydra/attributes/mem_pool.c @@ -47,6 +47,11 @@ struct private_mem_pool_t { host_t *base; /** + * whether base is the network id of the subnet on which the pool is based + */ + bool base_is_network_id; + + /** * size of the pool */ u_int size; @@ -306,7 +311,7 @@ static int get_new(private_mem_pool_t *this, identification_t *id) this->leases->put(this->leases, entry->id, entry); } /* assigning offset, starting by 1 */ - offset = ++this->unused; + offset = ++this->unused + (this->base_is_network_id ? 1 : 0); array_insert(entry->online, ARRAY_TAIL, &offset); DBG1(DBG_CFG, "assigning new lease to '%Y'", id); } @@ -580,18 +585,39 @@ static private_mem_pool_t *create_generic(char *name) } /** + * Check if the given host is the network ID of a subnet, that is, if hostbits + * are zero. Since we limit pools to 2^31 addresses we only have to check the + * last 4 bytes. + */ +static u_int network_id_diff(host_t *host, int hostbits) +{ + u_int32_t last; + chunk_t addr; + + if (!hostbits) + { + return 0; + } + addr = host->get_address(host); + last = untoh32(addr.ptr + addr.len - sizeof(last)); + hostbits = sizeof(last) * 8 - hostbits; + return (last << hostbits) >> hostbits; +} + +/** * Described in header */ mem_pool_t *mem_pool_create(char *name, host_t *base, int bits) { private_mem_pool_t *this; + u_int diff; int addr_bits; this = create_generic(name); if (base) { addr_bits = base->get_family(base) == AF_INET ? 32 : 128; - bits = max(0, min(bits, base->get_family(base) == AF_INET ? 32 : 128)); + bits = max(0, min(bits, addr_bits)); /* net bits -> host bits */ bits = addr_bits - bits; if (bits > POOL_LIMIT) @@ -601,15 +627,31 @@ mem_pool_t *mem_pool_create(char *name, host_t *base, int bits) base, addr_bits - bits); } this->size = 1 << bits; + this->base = base->clone(base); if (this->size > 2) - { /* do not use first and last addresses of a block */ - this->unused++; - this->size -= 2; + { + /* if base is the network id we later skip the first address, + * otherwise adjust the size to represent the actual number + * of assignable addresses */ + diff = network_id_diff(base, bits); + if (!diff) + { + this->base_is_network_id = TRUE; + this->size--; + } + else + { + this->size -= diff; + } + /* skip the last address (broadcast) of the subnet */ + this->size--; + } + else if (network_id_diff(base, bits)) + { /* only serve the second address of the subnet */ + this->size--; } - this->base = base->clone(base); } - return &this->public; } |