]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libcharon/attributes/mem_pool.c
Spelling fixes
[thirdparty/strongswan.git] / src / libcharon / attributes / mem_pool.c
CommitLineData
ac5fb545
TB
1/*
2 * Copyright (C) 2010 Tobias Brunner
e82186fb 3 * Copyright (C) 2008-2010 Martin Willi
1b671669 4 * HSR Hochschule fuer Technik Rapperswil
ac5fb545
TB
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17#include "mem_pool.h"
18
7612a6e4 19#include <library.h>
f05b4272 20#include <utils/debug.h>
12642a68 21#include <collections/hashtable.h>
c5d2d867 22#include <collections/array.h>
e82186fb 23#include <threading/mutex.h>
ac5fb545 24
292ee515 25#define POOL_LIMIT (sizeof(u_int)*8 - 1)
ac5fb545
TB
26
27typedef struct private_mem_pool_t private_mem_pool_t;
28
29/**
30 * private data of mem_pool_t
31 */
32struct private_mem_pool_t {
33 /**
34 * public interface
35 */
36 mem_pool_t public;
37
38 /**
39 * name of the pool
40 */
41 char *name;
42
43 /**
44 * base address of the pool
45 */
46 host_t *base;
47
9d2a3554
TB
48 /**
49 * whether base is the network id of the subnet on which the pool is based
50 */
51 bool base_is_network_id;
52
ac5fb545
TB
53 /**
54 * size of the pool
55 */
56 u_int size;
57
58 /**
59 * next unused address
60 */
61 u_int unused;
62
63 /**
e82186fb 64 * lease hashtable [identity => entry]
ac5fb545 65 */
e82186fb 66 hashtable_t *leases;
fb111e55
TB
67
68 /**
69 * lock to safely access the pool
70 */
e82186fb 71 mutex_t *mutex;
ac5fb545
TB
72};
73
22e6a06b
MW
74/**
75 * A unique lease address offset, with a hash of the peer host address
76 */
77typedef struct {
78 /** lease, as offset */
79 u_int offset;
80 /** hash of remote address, to allow duplicates */
81 u_int hash;
82} unique_lease_t;
83
e82186fb
MW
84/**
85 * Lease entry.
86 */
87typedef struct {
b3ab7a48 88 /* identity reference */
e82186fb 89 identification_t *id;
22e6a06b 90 /* array of online leases, as unique_lease_t */
c5d2d867
MW
91 array_t *online;
92 /* array of offline leases, as u_int offset */
93 array_t *offline;
e82186fb
MW
94} entry_t;
95
c5d2d867
MW
96/**
97 * Create a new entry
98 */
99static entry_t* entry_create(identification_t *id)
100{
101 entry_t *entry;
102
103 INIT(entry,
104 .id = id->clone(id),
22e6a06b 105 .online = array_create(sizeof(unique_lease_t), 0),
c5d2d867
MW
106 .offline = array_create(sizeof(u_int), 0),
107 );
108 return entry;
109}
110
7d02f8db
TB
111/**
112 * Destroy an entry
113 */
114static void entry_destroy(entry_t *this)
115{
116 this->id->destroy(this->id);
117 array_destroy(this->online);
118 array_destroy(this->offline);
119 free(this);
120}
121
ac5fb545
TB
122/**
123 * hashtable hash function for identities
124 */
125static u_int id_hash(identification_t *id)
126{
127 return chunk_hash(id->get_encoding(id));
128}
129
130/**
131 * hashtable equals function for identities
132 */
133static bool id_equals(identification_t *a, identification_t *b)
134{
135 return a->equals(a, b);
136}
137
138/**
139 * convert a pool offset to an address
140 */
141static host_t* offset2host(private_mem_pool_t *pool, int offset)
142{
143 chunk_t addr;
144 host_t *host;
b12c53ce 145 uint32_t *pos;
ac5fb545
TB
146
147 offset--;
148 if (offset > pool->size)
149 {
150 return NULL;
151 }
152
153 addr = chunk_clone(pool->base->get_address(pool->base));
154 if (pool->base->get_family(pool->base) == AF_INET6)
155 {
b12c53ce 156 pos = (uint32_t*)(addr.ptr + 12);
ac5fb545
TB
157 }
158 else
159 {
b12c53ce 160 pos = (uint32_t*)addr.ptr;
ac5fb545
TB
161 }
162 *pos = htonl(offset + ntohl(*pos));
163 host = host_create_from_chunk(pool->base->get_family(pool->base), addr, 0);
164 free(addr.ptr);
165 return host;
166}
167
168/**
169 * convert a host to a pool offset
170 */
171static int host2offset(private_mem_pool_t *pool, host_t *addr)
172{
173 chunk_t host, base;
b12c53ce 174 uint32_t hosti, basei;
ac5fb545
TB
175
176 if (addr->get_family(addr) != pool->base->get_family(pool->base))
177 {
178 return -1;
179 }
180 host = addr->get_address(addr);
181 base = pool->base->get_address(pool->base);
182 if (addr->get_family(addr) == AF_INET6)
183 {
184 /* only look at last /32 block */
185 if (!memeq(host.ptr, base.ptr, 12))
186 {
187 return -1;
188 }
189 host = chunk_skip(host, 12);
190 base = chunk_skip(base, 12);
191 }
b12c53ce
AS
192 hosti = ntohl(*(uint32_t*)(host.ptr));
193 basei = ntohl(*(uint32_t*)(base.ptr));
ac5fb545
TB
194 if (hosti > basei + pool->size)
195 {
196 return -1;
197 }
198 return hosti - basei + 1;
199}
200
201METHOD(mem_pool_t, get_name, const char*,
e82186fb 202 private_mem_pool_t *this)
ac5fb545
TB
203{
204 return this->name;
205}
206
d8eec395
MW
207METHOD(mem_pool_t, get_base, host_t*,
208 private_mem_pool_t *this)
209{
210 return this->base;
211}
212
ac5fb545 213METHOD(mem_pool_t, get_size, u_int,
e82186fb 214 private_mem_pool_t *this)
ac5fb545
TB
215{
216 return this->size;
217}
218
219METHOD(mem_pool_t, get_online, u_int,
e82186fb 220 private_mem_pool_t *this)
ac5fb545 221{
e82186fb
MW
222 enumerator_t *enumerator;
223 entry_t *entry;
224 u_int count = 0;
225
226 this->mutex->lock(this->mutex);
227 enumerator = this->leases->create_enumerator(this->leases);
228 while (enumerator->enumerate(enumerator, NULL, &entry))
229 {
c5d2d867 230 count += array_count(entry->online);
e82186fb
MW
231 }
232 enumerator->destroy(enumerator);
233 this->mutex->unlock(this->mutex);
234
fb111e55 235 return count;
ac5fb545
TB
236}
237
238METHOD(mem_pool_t, get_offline, u_int,
e82186fb 239 private_mem_pool_t *this)
ac5fb545 240{
e82186fb
MW
241 enumerator_t *enumerator;
242 entry_t *entry;
243 u_int count = 0;
244
245 this->mutex->lock(this->mutex);
246 enumerator = this->leases->create_enumerator(this->leases);
247 while (enumerator->enumerate(enumerator, NULL, &entry))
248 {
c5d2d867 249 count += array_count(entry->offline);
e82186fb
MW
250 }
251 enumerator->destroy(enumerator);
252 this->mutex->unlock(this->mutex);
253
fb111e55 254 return count;
ac5fb545
TB
255}
256
22e6a06b
MW
257/**
258 * Create a unique hash for a remote address
259 */
260static u_int hash_addr(host_t *addr)
261{
262 if (addr)
263 {
264 return chunk_hash_inc(addr->get_address(addr), addr->get_port(addr));
265 }
266 return 0;
267}
268
1e04488f
MW
269/**
270 * Get an existing lease for id
271 */
272static int get_existing(private_mem_pool_t *this, identification_t *id,
22e6a06b 273 host_t *requested, host_t *peer)
ac5fb545 274{
ac5fb545 275 enumerator_t *enumerator;
22e6a06b 276 unique_lease_t *lease, reassign;
c5d2d867 277 u_int *current;
1e04488f
MW
278 entry_t *entry;
279 int offset = 0;
280
281 entry = this->leases->get(this->leases, id);
282 if (!entry)
283 {
284 return 0;
285 }
286
287 /* check for a valid offline lease, refresh */
c5d2d867 288 enumerator = array_create_enumerator(entry->offline);
1e04488f
MW
289 if (enumerator->enumerate(enumerator, &current))
290 {
22e6a06b
MW
291 reassign.offset = offset = *current;
292 reassign.hash = hash_addr(peer);
293 array_insert(entry->online, ARRAY_TAIL, &reassign);
c5d2d867 294 array_remove_at(entry->offline, enumerator);
1e04488f
MW
295 }
296 enumerator->destroy(enumerator);
297 if (offset)
298 {
299 DBG1(DBG_CFG, "reassigning offline lease to '%Y'", id);
300 return offset;
301 }
22e6a06b 302 if (!peer)
7612a6e4
MW
303 {
304 return 0;
305 }
1e04488f 306 /* check for a valid online lease to reassign */
c5d2d867 307 enumerator = array_create_enumerator(entry->online);
22e6a06b 308 while (enumerator->enumerate(enumerator, &lease))
1e04488f 309 {
22e6a06b
MW
310 if (lease->offset == host2offset(this, requested) &&
311 lease->hash == hash_addr(peer))
1e04488f 312 {
22e6a06b 313 offset = lease->offset;
d882880e 314 /* add an additional "online" entry */
22e6a06b 315 array_insert(entry->online, ARRAY_TAIL, lease);
1e04488f
MW
316 break;
317 }
318 }
319 enumerator->destroy(enumerator);
320 if (offset)
321 {
322 DBG1(DBG_CFG, "reassigning online lease to '%Y'", id);
323 }
324 return offset;
325}
326
327/**
328 * Get a new lease for id
329 */
22e6a06b 330static int get_new(private_mem_pool_t *this, identification_t *id, host_t *peer)
1e04488f
MW
331{
332 entry_t *entry;
22e6a06b 333 unique_lease_t lease = {};
1e04488f
MW
334
335 if (this->unused < this->size)
336 {
f0a2fef8
MW
337 entry = this->leases->get(this->leases, id);
338 if (!entry)
339 {
c5d2d867 340 entry = entry_create(id);
f0a2fef8
MW
341 this->leases->put(this->leases, entry->id, entry);
342 }
1e04488f 343 /* assigning offset, starting by 1 */
22e6a06b
MW
344 lease.offset = ++this->unused + (this->base_is_network_id ? 1 : 0);
345 lease.hash = hash_addr(peer);
346 array_insert(entry->online, ARRAY_TAIL, &lease);
1e04488f
MW
347 DBG1(DBG_CFG, "assigning new lease to '%Y'", id);
348 }
22e6a06b 349 return lease.offset;
1e04488f
MW
350}
351
352/**
353 * Get a reassigned lease for id in case the pool is full
354 */
22e6a06b
MW
355static int get_reassigned(private_mem_pool_t *this, identification_t *id,
356 host_t *peer)
1e04488f
MW
357{
358 enumerator_t *enumerator;
359 entry_t *entry;
22e6a06b
MW
360 u_int current;
361 unique_lease_t lease = {};
1e04488f
MW
362
363 enumerator = this->leases->create_enumerator(this->leases);
364 while (enumerator->enumerate(enumerator, NULL, &entry))
365 {
c5d2d867 366 if (array_remove(entry->offline, ARRAY_HEAD, &current))
1e04488f 367 {
22e6a06b 368 lease.offset = current;
7d02f8db
TB
369 DBG1(DBG_CFG, "reassigning existing offline lease by '%Y' "
370 "to '%Y'", entry->id, id);
371 }
372 if (!array_count(entry->online) && !array_count(entry->offline))
373 {
374 this->leases->remove_at(this->leases, enumerator);
375 entry_destroy(entry);
376 }
377 if (lease.offset)
378 {
1e04488f
MW
379 break;
380 }
381 }
382 enumerator->destroy(enumerator);
383
22e6a06b 384 if (lease.offset)
1e04488f 385 {
8ab1b29d
TB
386 entry = this->leases->get(this->leases, id);
387 if (!entry)
388 {
389 entry = entry_create(id);
390 this->leases->put(this->leases, entry->id, entry);
391 }
22e6a06b
MW
392 lease.hash = hash_addr(peer);
393 array_insert(entry->online, ARRAY_TAIL, &lease);
1e04488f 394 }
22e6a06b 395 return lease.offset;
1e04488f
MW
396}
397
398METHOD(mem_pool_t, acquire_address, host_t*,
399 private_mem_pool_t *this, identification_t *id, host_t *requested,
22e6a06b 400 mem_pool_op_t operation, host_t *peer)
1e04488f
MW
401{
402 int offset = 0;
ac5fb545
TB
403
404 /* if the pool is empty (e.g. in the %config case) we simply return the
405 * requested address */
406 if (this->size == 0)
407 {
408 return requested->clone(requested);
409 }
410
40e90898 411 if (requested->get_family(requested) !=
fb111e55 412 this->base->get_family(this->base))
ac5fb545 413 {
fb111e55
TB
414 return NULL;
415 }
ac5fb545 416
e82186fb 417 this->mutex->lock(this->mutex);
1e04488f 418 switch (operation)
fb111e55 419 {
1e04488f 420 case MEM_POOL_EXISTING:
22e6a06b 421 offset = get_existing(this, id, requested, peer);
ac5fb545 422 break;
1e04488f 423 case MEM_POOL_NEW:
22e6a06b 424 offset = get_new(this, id, peer);
1e04488f
MW
425 break;
426 case MEM_POOL_REASSIGN:
22e6a06b 427 offset = get_reassigned(this, id, peer);
1e04488f 428 if (!offset)
ac5fb545 429 {
1e04488f
MW
430 DBG1(DBG_CFG, "pool '%s' is full, unable to assign address",
431 this->name);
ac5fb545 432 }
1e04488f
MW
433 break;
434 default:
435 break;
ac5fb545 436 }
e82186fb 437 this->mutex->unlock(this->mutex);
ac5fb545
TB
438
439 if (offset)
440 {
441 return offset2host(this, offset);
442 }
443 return NULL;
444}
445
446METHOD(mem_pool_t, release_address, bool,
e82186fb 447 private_mem_pool_t *this, host_t *address, identification_t *id)
ac5fb545 448{
d882880e
MW
449 enumerator_t *enumerator;
450 bool found = FALSE, more = FALSE;
e82186fb 451 entry_t *entry;
22e6a06b
MW
452 u_int offset;
453 unique_lease_t *current;
e82186fb 454
ac5fb545
TB
455 if (this->size != 0)
456 {
e82186fb
MW
457 this->mutex->lock(this->mutex);
458 entry = this->leases->get(this->leases, id);
459 if (entry)
ac5fb545 460 {
e82186fb 461 offset = host2offset(this, address);
d882880e 462
c5d2d867 463 enumerator = array_create_enumerator(entry->online);
d882880e 464 while (enumerator->enumerate(enumerator, &current))
ac5fb545 465 {
22e6a06b 466 if (current->offset == offset)
d882880e
MW
467 {
468 if (!found)
469 { /* remove the first entry only */
c5d2d867 470 array_remove_at(entry->online, enumerator);
d882880e
MW
471 found = TRUE;
472 }
473 else
474 { /* but check for more entries */
475 more = TRUE;
476 break;
477 }
478 }
479 }
480 enumerator->destroy(enumerator);
481
482 if (found && !more)
483 {
484 /* no tunnels are online anymore for this lease, make offline */
c5d2d867 485 array_insert(entry->offline, ARRAY_TAIL, &offset);
d882880e 486 DBG1(DBG_CFG, "lease %H by '%Y' went offline", address, id);
ac5fb545
TB
487 }
488 }
e82186fb 489 this->mutex->unlock(this->mutex);
ac5fb545 490 }
fb111e55 491 return found;
ac5fb545
TB
492}
493
494/**
495 * lease enumerator
496 */
497typedef struct {
498 /** implemented enumerator interface */
499 enumerator_t public;
e82186fb
MW
500 /** hash-table enumerator */
501 enumerator_t *entries;
502 /** online enumerator */
503 enumerator_t *online;
504 /** offline enumerator */
505 enumerator_t *offline;
ac5fb545
TB
506 /** enumerated pool */
507 private_mem_pool_t *pool;
e82186fb
MW
508 /** currently enumerated entry */
509 entry_t *entry;
ac5fb545 510 /** currently enumerated lease address */
e82186fb 511 host_t *addr;
ac5fb545
TB
512} lease_enumerator_t;
513
514METHOD(enumerator_t, lease_enumerate, bool,
95a63bf2 515 lease_enumerator_t *this, va_list args)
ac5fb545 516{
95a63bf2 517 identification_t **id;
22e6a06b 518 unique_lease_t *lease;
95a63bf2
TB
519 host_t **addr;
520 u_int *offset;
521 bool *online;
522
523 VA_ARGS_VGET(args, id, addr, online);
ac5fb545 524
e82186fb
MW
525 DESTROY_IF(this->addr);
526 this->addr = NULL;
ac5fb545 527
e82186fb 528 while (TRUE)
ac5fb545 529 {
e82186fb 530 if (this->entry)
ac5fb545 531 {
22e6a06b 532 if (this->online->enumerate(this->online, &lease))
e82186fb
MW
533 {
534 *id = this->entry->id;
22e6a06b 535 *addr = this->addr = offset2host(this->pool, lease->offset);
e82186fb
MW
536 *online = TRUE;
537 return TRUE;
538 }
c5d2d867 539 if (this->offline->enumerate(this->offline, &offset))
e82186fb
MW
540 {
541 *id = this->entry->id;
c5d2d867 542 *addr = this->addr = offset2host(this->pool, *offset);
e82186fb
MW
543 *online = FALSE;
544 return TRUE;
545 }
546 this->online->destroy(this->online);
547 this->offline->destroy(this->offline);
548 this->online = this->offline = NULL;
ac5fb545 549 }
e82186fb 550 if (!this->entries->enumerate(this->entries, NULL, &this->entry))
ac5fb545 551 {
e82186fb 552 return FALSE;
ac5fb545 553 }
c5d2d867
MW
554 this->online = array_create_enumerator(this->entry->online);
555 this->offline = array_create_enumerator(this->entry->offline);
ac5fb545 556 }
ac5fb545
TB
557}
558
559METHOD(enumerator_t, lease_enumerator_destroy, void,
e82186fb 560 lease_enumerator_t *this)
ac5fb545 561{
e82186fb
MW
562 DESTROY_IF(this->addr);
563 DESTROY_IF(this->online);
564 DESTROY_IF(this->offline);
565 this->entries->destroy(this->entries);
566 this->pool->mutex->unlock(this->pool->mutex);
ac5fb545
TB
567 free(this);
568}
569
570METHOD(mem_pool_t, create_lease_enumerator, enumerator_t*,
571 private_mem_pool_t *this)
572{
573 lease_enumerator_t *enumerator;
e82186fb
MW
574
575 this->mutex->lock(this->mutex);
ac5fb545
TB
576 INIT(enumerator,
577 .public = {
95a63bf2
TB
578 .enumerate = enumerator_enumerate_default,
579 .venumerate = _lease_enumerate,
e82186fb 580 .destroy = _lease_enumerator_destroy,
ac5fb545
TB
581 },
582 .pool = this,
e82186fb 583 .entries = this->leases->create_enumerator(this->leases),
ac5fb545 584 );
ac5fb545
TB
585 return &enumerator->public;
586}
587
588METHOD(mem_pool_t, destroy, void,
e82186fb 589 private_mem_pool_t *this)
ac5fb545
TB
590{
591 enumerator_t *enumerator;
e82186fb 592 entry_t *entry;
ac5fb545 593
e82186fb
MW
594 enumerator = this->leases->create_enumerator(this->leases);
595 while (enumerator->enumerate(enumerator, NULL, &entry))
ac5fb545 596 {
7d02f8db 597 entry_destroy(entry);
ac5fb545
TB
598 }
599 enumerator->destroy(enumerator);
600
e82186fb
MW
601 this->leases->destroy(this->leases);
602 this->mutex->destroy(this->mutex);
ac5fb545
TB
603 DESTROY_IF(this->base);
604 free(this->name);
605 free(this);
606}
607
608/**
0897cda3 609 * Generic constructor
ac5fb545 610 */
0897cda3 611static private_mem_pool_t *create_generic(char *name)
ac5fb545
TB
612{
613 private_mem_pool_t *this;
614
615 INIT(this,
616 .public = {
617 .get_name = _get_name,
d8eec395 618 .get_base = _get_base,
ac5fb545
TB
619 .get_size = _get_size,
620 .get_online = _get_online,
621 .get_offline = _get_offline,
622 .acquire_address = _acquire_address,
623 .release_address = _release_address,
624 .create_lease_enumerator = _create_lease_enumerator,
625 .destroy = _destroy,
626 },
627 .name = strdup(name),
e82186fb 628 .leases = hashtable_create((hashtable_hash_t)id_hash,
ac5fb545 629 (hashtable_equals_t)id_equals, 16),
e82186fb 630 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
ac5fb545
TB
631 );
632
0897cda3
MW
633 return this;
634}
635
9d2a3554
TB
636/**
637 * Check if the given host is the network ID of a subnet, that is, if hostbits
638 * are zero. Since we limit pools to 2^31 addresses we only have to check the
639 * last 4 bytes.
640 */
641static u_int network_id_diff(host_t *host, int hostbits)
642{
b12c53ce 643 uint32_t last;
9d2a3554
TB
644 chunk_t addr;
645
646 if (!hostbits)
647 {
648 return 0;
649 }
650 addr = host->get_address(host);
651 last = untoh32(addr.ptr + addr.len - sizeof(last));
652 hostbits = sizeof(last) * 8 - hostbits;
653 return (last << hostbits) >> hostbits;
654}
655
0897cda3
MW
656/**
657 * Described in header
658 */
659mem_pool_t *mem_pool_create(char *name, host_t *base, int bits)
660{
661 private_mem_pool_t *this;
9d2a3554 662 u_int diff;
0897cda3
MW
663 int addr_bits;
664
665 this = create_generic(name);
ac5fb545
TB
666 if (base)
667 {
e82186fb 668 addr_bits = base->get_family(base) == AF_INET ? 32 : 128;
9d2a3554 669 bits = max(0, min(bits, addr_bits));
ac5fb545
TB
670 /* net bits -> host bits */
671 bits = addr_bits - bits;
672 if (bits > POOL_LIMIT)
673 {
674 bits = POOL_LIMIT;
894936ce 675 DBG1(DBG_CFG, "virtual IP pool too large, limiting to %H/%d",
ac5fb545
TB
676 base, addr_bits - bits);
677 }
292ee515 678 this->size = 1 << bits;
9d2a3554 679 this->base = base->clone(base);
ac5fb545
TB
680
681 if (this->size > 2)
9d2a3554
TB
682 {
683 /* if base is the network id we later skip the first address,
684 * otherwise adjust the size to represent the actual number
685 * of assignable addresses */
686 diff = network_id_diff(base, bits);
687 if (!diff)
688 {
689 this->base_is_network_id = TRUE;
690 this->size--;
691 }
692 else
693 {
694 this->size -= diff;
695 }
696 /* skip the last address (broadcast) of the subnet */
697 this->size--;
698 }
699 else if (network_id_diff(base, bits))
700 { /* only serve the second address of the subnet */
701 this->size--;
ac5fb545 702 }
ac5fb545 703 }
ac5fb545
TB
704 return &this->public;
705}
706
0897cda3
MW
707/**
708 * Described in header
709 */
710mem_pool_t *mem_pool_create_range(char *name, host_t *from, host_t *to)
711{
712 private_mem_pool_t *this;
713 chunk_t fromaddr, toaddr;
b12c53ce 714 uint32_t diff;
0897cda3
MW
715
716 fromaddr = from->get_address(from);
717 toaddr = to->get_address(to);
718
719 if (from->get_family(from) != to->get_family(to) ||
720 fromaddr.len != toaddr.len || fromaddr.len < sizeof(diff) ||
721 memcmp(fromaddr.ptr, toaddr.ptr, toaddr.len) > 0)
722 {
723 DBG1(DBG_CFG, "invalid IP address range: %H-%H", from, to);
724 return NULL;
725 }
726 if (fromaddr.len > sizeof(diff) &&
727 !chunk_equals(chunk_create(fromaddr.ptr, fromaddr.len - sizeof(diff)),
728 chunk_create(toaddr.ptr, toaddr.len - sizeof(diff))))
729 {
730 DBG1(DBG_CFG, "IP address range too large: %H-%H", from, to);
731 return NULL;
732 }
733 this = create_generic(name);
734 this->base = from->clone(from);
735 diff = untoh32(toaddr.ptr + toaddr.len - sizeof(diff)) -
736 untoh32(fromaddr.ptr + fromaddr.len - sizeof(diff));
737 this->size = diff + 1;
738
739 return &this->public;
740}