version 1.1, 2012/02/21 22:30:18
|
version 1.1.1.1, 2012/10/09 09:06:55
|
Line 1
|
Line 1
|
/* |
/* |
* Copyright (C) 2010-2011 by Internet Systems Consortium, Inc. ("ISC") | * Copyright (C) 2010-2012 by Internet Systems Consortium, Inc. ("ISC") |
* Copyright (C) 2007-2008 by Internet Systems Consortium, Inc. ("ISC") |
* Copyright (C) 2007-2008 by Internet Systems Consortium, Inc. ("ISC") |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
Line 15
|
Line 15
|
* PERFORMANCE OF THIS SOFTWARE. |
* PERFORMANCE OF THIS SOFTWARE. |
*/ |
*/ |
|
|
/* TODO: assert() */ | /*! |
/* TODO: simplify functions, as pool is now in iaaddr */ | * \todo assert() |
| * \todo simplify functions, as pool is now in iaaddr |
| */ |
|
|
|
/*! \file server/mdb6.c |
|
* |
|
* \page ipv6structures IPv6 Structures Overview |
|
* |
|
* A brief description of the IPv6 structures as reverse engineered. |
|
* |
|
* There are three major data strucutes involved in the database: |
|
* |
|
* - ipv6_pool - this contains information about a pool of addresses or prefixes |
|
* that the server is using. This includes a hash table that |
|
* tracks the active items and a pair of heap tables one for |
|
* active items and one for non-active items. The heap tables |
|
* are used to determine the next items to be modified due to |
|
* timing events (expire mostly). |
|
* - ia_xx - this contains information about a single IA from a request |
|
* normally it will contain one pointer to a lease for the client |
|
* but it may contain more in some circumstances. There are 3 |
|
* hash tables to aid in accessing these one each for NA, TA and PD. |
|
* - iasubopt- the v6 lease structure. These are created dynamically when |
|
* a client asks for something and will eventually be destroyed |
|
* if the client doesn't re-ask for that item. A lease has space |
|
* for backpointers to the IA and to the pool to which it belongs. |
|
* The pool backpointer is always filled, the IA pointer may not be. |
|
* |
|
* In normal use we then have something like this: |
|
* |
|
* \verbatim |
|
* ia hash tables |
|
* ia_na_active +----------------+ |
|
* ia_ta_active +------------+ | pool | |
|
* ia_pd_active | iasubopt |<--| active hash | |
|
* +-----------------+ | aka lease |<--| active heap | |
|
* | ia_xx | | pool ptr |-->| | |
|
* | iasubopt array |<---| iaptr |<--| inactive heap | |
|
* | lease ptr |--->| | | | |
|
* +-----------------+ +------------+ +----------------+ |
|
* \endverbatim |
|
* |
|
* For the pool either the inactive heap will have a pointer |
|
* or both the active heap and the active hash will have pointers. |
|
* |
|
* I think there are several major items to notice. The first is |
|
* that as a lease moves around it will be added to and removed |
|
* from the address hash table in the pool and between the active |
|
* and inactive hash tables. The hash table and the active heap |
|
* are used when the lease is either active or abandoned. The |
|
* inactive heap is used for all other states. In particular a |
|
* lease that has expired or been released will be cleaned |
|
* (DDNS removal etc) and then moved to the inactive heap. After |
|
* some time period (currently 1 hour) it will be freed. |
|
* |
|
* The second is that when a client requests specific addresses, |
|
* either because it previously owned them or if the server supplied |
|
* them as part of a solicit, the server will try to lookup the ia_xx |
|
* associated with the client and find the addresses there. If it |
|
* does find appropriate leases it moves them from the old IA to |
|
* a new IA and eventually replaces the old IA with the new IA |
|
* in the IA hash tables. |
|
* |
|
*/ |
#include "config.h" |
#include "config.h" |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
Line 316 void
|
Line 378 void
|
ia_remove_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt, |
ia_remove_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt, |
const char *file, int line) { |
const char *file, int line) { |
int i, j; |
int i, j; |
|
if (ia == NULL || iasubopt == NULL) |
|
return; |
|
|
for (i=0; i<ia->num_iasubopt; i++) { |
for (i=0; i<ia->num_iasubopt; i++) { |
if (ia->iasubopt[i] == iasubopt) { |
if (ia->iasubopt[i] == iasubopt) { |
Line 807 create_lease6(struct ipv6_pool *pool, struct iasubopt
|
Line 871 create_lease6(struct ipv6_pool *pool, struct iasubopt
|
} |
} |
|
|
/* |
/* |
* Avoid reserved interface IDs. | * Avoid reserved interface IDs. (cf. RFC 5453) |
* (cf. draft-krishnan-ipv6-reserved-iids-02.txt) | |
*/ |
*/ |
reserved_iid = ISC_FALSE; |
reserved_iid = ISC_FALSE; |
if (memcmp(&tmp.s6_addr[8], &rtany, 8) == 0) { | if (memcmp(&tmp.s6_addr[8], &rtany.s6_addr[8], 8) == 0) { |
reserved_iid = ISC_TRUE; |
reserved_iid = ISC_TRUE; |
} |
} |
if (!reserved_iid && |
if (!reserved_iid && |
(memcmp(&tmp.s6_addr[8], &resany, 7) == 0) && | (memcmp(&tmp.s6_addr[8], &resany.s6_addr[8], 7) == 0) && |
((tmp.s6_addr[15] & 0x80) == 0x80)) { |
((tmp.s6_addr[15] & 0x80) == 0x80)) { |
reserved_iid = ISC_TRUE; |
reserved_iid = ISC_TRUE; |
} |
} |
Line 874 create_lease6(struct ipv6_pool *pool, struct iasubopt
|
Line 937 create_lease6(struct ipv6_pool *pool, struct iasubopt
|
return result; |
return result; |
} |
} |
|
|
|
|
|
/*! |
|
* |
|
* \brief Cleans up leases when reading from a lease file |
|
* |
|
* This function is only expected to be run when reading leases in from a file. |
|
* It checks to see if a lease already exists for the new leases's address. |
|
* We don't add expired leases to the structures when reading a lease file |
|
* which limits what can happen. We have two variables the owners of the leases |
|
* being the same or different and the new lease being active or non-active: |
|
* Owners active |
|
* same no remove old lease and its connections |
|
* same yes nothing to do, other code will update the structures. |
|
* diff no nothing to do |
|
* diff yes this combination shouldn't happen, we should only have a |
|
* single active lease per address at a time and that lease |
|
* should move to non-active before any other lease can |
|
* become active for that address. |
|
* Currently we delete the previous lease and pass an error |
|
* to the caller who should log an error. |
|
* |
|
* When we remove a lease we remove it from the hash table and active heap |
|
* (remember only active leases are in the structures at this time) for the |
|
* pool, and from the IA's array. If, after we've removed the pointer from |
|
* IA's array to the lease, the IA has no more pointers we remove it from |
|
* the appropriate hash table as well. |
|
* |
|
* \param[in] ia_table = the hash table for the IA |
|
* \param[in] pool = the pool to update |
|
* \param[in] lease = the new lease we want to add |
|
* \param[in] ia = the new ia we are building |
|
* |
|
* \return |
|
* ISC_R_SUCCESS = the incoming lease and any previous lease were in |
|
* an expected state - one of the first 3 options above. |
|
* If necessary the old lease was removed. |
|
* ISC_R_FAILURE = there is already an active lease for the address in |
|
* the incoming lease. This shouldn't happen if it does |
|
* flag an error for the caller to log. |
|
*/ |
|
|
|
isc_result_t |
|
cleanup_lease6(ia_hash_t *ia_table, |
|
struct ipv6_pool *pool, |
|
struct iasubopt *lease, |
|
struct ia_xx *ia) { |
|
|
|
struct iasubopt *test_iasubopt, *tmp_iasubopt; |
|
struct ia_xx *old_ia; |
|
isc_result_t status = ISC_R_SUCCESS; |
|
|
|
test_iasubopt = NULL; |
|
old_ia = NULL; |
|
|
|
/* |
|
* Look up the address - if we don't find a lease |
|
* we don't need to do anything. |
|
*/ |
|
if (iasubopt_hash_lookup(&test_iasubopt, pool->leases, |
|
&lease->addr, sizeof(lease->addr), |
|
MDL) == 0) { |
|
return (ISC_R_SUCCESS); |
|
} |
|
|
|
if (test_iasubopt->ia == NULL) { |
|
/* no old ia, no work to do */ |
|
iasubopt_dereference(&test_iasubopt, MDL); |
|
return (status); |
|
} |
|
|
|
ia_reference(&old_ia, test_iasubopt->ia, MDL); |
|
|
|
if ((old_ia->iaid_duid.len == ia->iaid_duid.len) && |
|
(memcmp((unsigned char *)ia->iaid_duid.data, |
|
(unsigned char *)old_ia->iaid_duid.data, |
|
ia->iaid_duid.len) == 0)) { |
|
/* same IA */ |
|
if ((lease->state == FTS_ACTIVE) || |
|
(lease->state == FTS_ABANDONED)) { |
|
/* still active, no need to delete */ |
|
goto cleanup; |
|
} |
|
} else { |
|
/* different IA */ |
|
if ((lease->state != FTS_ACTIVE) && |
|
(lease->state != FTS_ABANDONED)) { |
|
/* new lease isn't active, no work */ |
|
goto cleanup; |
|
} |
|
|
|
/* |
|
* We appear to have two active leases, this shouldn't happen. |
|
* Before a second lease can be set to active the first lease |
|
* should be set to inactive (released, expired etc). For now |
|
* delete the previous lease and indicate a failure to the |
|
* caller so it can generate a warning. |
|
* In the future we may try and determine which is the better |
|
* lease to keep. |
|
*/ |
|
|
|
status = ISC_R_FAILURE; |
|
} |
|
|
|
/* |
|
* Remove the old lease from the active heap and from the hash table |
|
* then remove the lease from the IA and clean up the IA if necessary. |
|
*/ |
|
isc_heap_delete(pool->active_timeouts, test_iasubopt->heap_index); |
|
pool->num_active--; |
|
|
|
iasubopt_hash_delete(pool->leases, &test_iasubopt->addr, |
|
sizeof(test_iasubopt->addr), MDL); |
|
ia_remove_iasubopt(old_ia, test_iasubopt, MDL); |
|
if (old_ia->num_iasubopt <= 0) { |
|
ia_hash_delete(ia_table, |
|
(unsigned char *)old_ia->iaid_duid.data, |
|
old_ia->iaid_duid.len, MDL); |
|
} |
|
|
|
/* |
|
* We derefenrece the subopt here as we've just removed it from |
|
* the hash table in the pool. We need to make a copy as we |
|
* need to derefernece it again later. |
|
*/ |
|
tmp_iasubopt = test_iasubopt; |
|
iasubopt_dereference(&tmp_iasubopt, MDL); |
|
|
|
cleanup: |
|
ia_dereference(&old_ia, MDL); |
|
|
|
/* |
|
* Clean up the reference, this is in addition to the deference |
|
* above after removing the entry from the hash table |
|
*/ |
|
iasubopt_dereference(&test_iasubopt, MDL); |
|
|
|
return (status); |
|
} |
|
|
/* |
/* |
* Put a lease in the pool directly. This is intended to be used when |
* Put a lease in the pool directly. This is intended to be used when |
* loading leases from the file. |
* loading leases from the file. |
Line 984 lease6_exists(const struct ipv6_pool *pool, const stru
|
Line 1186 lease6_exists(const struct ipv6_pool *pool, const stru
|
} |
} |
} |
} |
|
|
|
/*! |
|
* |
|
* \brief Check if address is available to a lease |
|
* |
|
* Determine if the address in the lease is available to that |
|
* lease. Either the address isn't in use or it is in use |
|
* but by that lease. |
|
* |
|
* \param[in] lease = lease to check |
|
* |
|
* \return |
|
* ISC_TRUE = The lease is allowed to use that address |
|
* ISC_FALSE = The lease isn't allowed to use that address |
|
*/ |
|
isc_boolean_t |
|
lease6_usable(struct iasubopt *lease) { |
|
struct iasubopt *test_iaaddr; |
|
isc_boolean_t status = ISC_TRUE; |
|
|
|
test_iaaddr = NULL; |
|
if (iasubopt_hash_lookup(&test_iaaddr, lease->ipv6_pool->leases, |
|
(void *)&lease->addr, |
|
sizeof(lease->addr), MDL)) { |
|
if (test_iaaddr != lease) { |
|
status = ISC_FALSE; |
|
} |
|
iasubopt_dereference(&test_iaaddr, MDL); |
|
} |
|
|
|
return (status); |
|
} |
|
|
/* |
/* |
* Put the lease on our active pool. |
* Put the lease on our active pool. |
*/ |
*/ |
Line 1005 move_lease_to_active(struct ipv6_pool *pool, struct ia
|
Line 1239 move_lease_to_active(struct ipv6_pool *pool, struct ia
|
return insert_result; |
return insert_result; |
} |
} |
|
|
/* | /*! |
* Renew an lease in the pool. | * \brief Renew a lease in the pool. |
* |
* |
* To do this, first set the new hard_lifetime_end_time for the resource, | * The hard_lifetime_end_time of the lease should be set to |
* and then invoke renew_lease6() on it. | * the current expiration time. |
| * The soft_lifetime_end_time of the lease should be set to |
| * the desired expiration time. |
* |
* |
* WARNING: lease times must only be extended, never reduced!!! | * This routine will compare the two and call the correct |
| * heap routine to move the lease. If the lease is active |
| * and the new expiration time is greater (the normal case) |
| * then we call isc_heap_decreased() as a larger time is a |
| * lower priority. If the new expiration time is less then |
| * we call isc_heap_increased(). |
| * |
| * If the lease is abandoned then it will be on the active list |
| * and we will always call isc_heap_increased() as the previous |
| * expiration would have been all 1s (as close as we can get |
| * to infinite). |
| * |
| * If the lease is moving to active we call that routine |
| * which will move it from the inactive list to the active list. |
| * |
| * \param pool a pool the lease belongs to |
| * \param lease the lease to be renewed |
| * |
| * \return result of the renew operation (ISC_R_SUCCESS if successful, |
| ISC_R_NOMEMORY when run out of memory) |
*/ |
*/ |
isc_result_t |
isc_result_t |
renew_lease6(struct ipv6_pool *pool, struct iasubopt *lease) { |
renew_lease6(struct ipv6_pool *pool, struct iasubopt *lease) { |
/* | time_t old_end_time = lease->hard_lifetime_end_time; |
* If we're already active, then we can just move our expiration | lease->hard_lifetime_end_time = lease->soft_lifetime_end_time; |
* time down the heap. | lease->soft_lifetime_end_time = 0; |
* | |
* If we're abandoned then we are already on the active list | |
* but we need to retag the lease and move our expiration | |
* from infinite to the current value | |
* | |
* Otherwise, we have to move from the inactive heap to the | |
* active heap. | |
*/ | |
if (lease->state == FTS_ACTIVE) { |
if (lease->state == FTS_ACTIVE) { |
isc_heap_decreased(pool->active_timeouts, lease->heap_index); | if (old_end_time <= lease->hard_lifetime_end_time) { |
| isc_heap_decreased(pool->active_timeouts, |
| lease->heap_index); |
| } else { |
| isc_heap_increased(pool->active_timeouts, |
| lease->heap_index); |
| } |
return ISC_R_SUCCESS; |
return ISC_R_SUCCESS; |
} else if (lease->state == FTS_ABANDONED) { |
} else if (lease->state == FTS_ABANDONED) { |
char tmp_addr[INET6_ADDRSTRLEN]; |
char tmp_addr[INET6_ADDRSTRLEN]; |
Line 1153 release_lease6(struct ipv6_pool *pool, struct iasubopt
|
Line 1407 release_lease6(struct ipv6_pool *pool, struct iasubopt
|
* Create a prefix by hashing the input, and using that for |
* Create a prefix by hashing the input, and using that for |
* the part subject to allocation. |
* the part subject to allocation. |
*/ |
*/ |
static void | void |
build_prefix6(struct in6_addr *pref, |
build_prefix6(struct in6_addr *pref, |
const struct in6_addr *net_start_pref, |
const struct in6_addr *net_start_pref, |
int pool_bits, int pref_bits, |
int pool_bits, int pref_bits, |
Line 1488 lease_timeout_support(void *vpool) {
|
Line 1742 lease_timeout_support(void *vpool) {
|
} |
} |
|
|
/* |
/* |
|
* If appropriate commit and rotate the lease file |
|
* As commit_leases_timed() checks to see if we've done any writes |
|
* we don't bother tracking if this function called write _ia |
|
*/ |
|
(void) commit_leases_timed(); |
|
|
|
/* |
* Do some cleanup of our expired leases. |
* Do some cleanup of our expired leases. |
*/ |
*/ |
cleanup_old_expired(pool); |
cleanup_old_expired(pool); |
Line 1686 change_leases(struct ia_xx *ia,
|
Line 1947 change_leases(struct ia_xx *ia,
|
/* |
/* |
* Renew all leases in an IA from all pools. |
* Renew all leases in an IA from all pools. |
* |
* |
* The new hard_lifetime_end_time should be updated for the addresses/prefixes. | * The new lifetime should be in the soft_lifetime_end_time |
* | * and will be moved to hard_lifetime_end_time by renew_lease6. |
* WARNING: lease times must only be extended, never reduced!!! | |
*/ |
*/ |
isc_result_t |
isc_result_t |
renew_leases(struct ia_xx *ia) { |
renew_leases(struct ia_xx *ia) { |
Line 1886 mark_interfaces_unavailable(void) {
|
Line 2146 mark_interfaces_unavailable(void) {
|
} |
} |
} |
} |
|
|
| /* unittest moved to server/tests/mdb6_unittest.c */ |
#ifdef UNIT_TEST | |
#include <stdlib.h> | |
| |
int | |
main(int argc, char *argv[]) { | |
struct iasubopt *iaaddr; | |
struct iasubopt *iaaddr_copy; | |
u_int32_t iaid; | |
struct ia_xx *ia_na; | |
struct ia_xx *ia_na_copy; | |
int i; | |
struct in6_addr addr; | |
struct ipv6_pool *pool; | |
struct ipv6_pool *pool_copy; | |
char addr_buf[INET6_ADDRSTRLEN]; | |
char *uid; | |
struct data_string ds; | |
struct iasubopt *expired_iaaddr; | |
unsigned int attempts; | |
| |
/* | |
* Test 0: Basic iaaddr manipulation. | |
*/ | |
iaaddr = NULL; | |
if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
if (iaaddr->state != FTS_FREE) { | |
printf("ERROR: bad state %s:%d\n", MDL); | |
return 1; | |
} | |
if (iaaddr->heap_index != -1) { | |
printf("ERROR: bad heap_index %s:%d\n", MDL); | |
return 1; | |
} | |
iaaddr_copy = NULL; | |
if (iasubopt_reference(&iaaddr_copy, iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
if (iasubopt_dereference(&iaaddr_copy, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
| |
/* | |
* Test 1: Error iaaddr manipulation. | |
*/ | |
/* bogus allocate arguments */ | |
if (iasubopt_allocate(NULL, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
iaaddr = (struct iasubopt *)1; | |
if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
| |
/* bogus reference arguments */ | |
iaaddr = NULL; | |
if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
if (iasubopt_reference(NULL, iaaddr, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: iasubopt_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
iaaddr_copy = (struct iasubopt *)1; | |
if (iasubopt_reference(&iaaddr_copy, iaaddr, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: iasubopt_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
iaaddr_copy = NULL; | |
if (iasubopt_reference(&iaaddr_copy, NULL, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: iasubopt_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
| |
/* bogus dereference arguments */ | |
if (iasubopt_dereference(NULL, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
iaaddr = NULL; | |
if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
| |
/* | |
* Test 2: Basic ia_na manipulation. | |
*/ | |
iaid = 666; | |
ia_na = NULL; | |
if (ia_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ia_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
if (memcmp(ia_na->iaid_duid.data, &iaid, sizeof(iaid)) != 0) { | |
printf("ERROR: bad IAID_DUID %s:%d\n", MDL); | |
return 1; | |
} | |
if (memcmp(ia_na->iaid_duid.data+sizeof(iaid), "TestDUID", 8) != 0) { | |
printf("ERROR: bad IAID_DUID %s:%d\n", MDL); | |
return 1; | |
} | |
if (ia_na->num_iasubopt != 0) { | |
printf("ERROR: bad num_iasubopt %s:%d\n", MDL); | |
return 1; | |
} | |
ia_na_copy = NULL; | |
if (ia_reference(&ia_na_copy, ia_na, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ia_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
iaaddr = NULL; | |
if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
if (ia_add_iasubopt(ia_na, iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ia_add_iasubopt() %s:%d\n", MDL); | |
return 1; | |
} | |
ia_remove_iasubopt(ia_na, iaaddr, MDL); | |
if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
if (ia_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ia_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
if (ia_dereference(&ia_na_copy, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ia_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
| |
/* | |
* Test 3: lots of iaaddr in our ia_na | |
*/ | |
| |
/* lots of iaaddr that we delete */ | |
iaid = 666; | |
ia_na = NULL; | |
if (ia_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ia_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
for (i=0; i<100; i++) { | |
iaaddr = NULL; | |
if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
if (ia_add_iasubopt(ia_na, iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ia_add_iasubopt() %s:%d\n", MDL); | |
return 1; | |
} | |
if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
} | |
for (i=0; i<100; i++) { | |
iaaddr = ia_na->iasubopt[random() % ia_na->num_iasubopt]; | |
ia_remove_iasubopt(ia_na, iaaddr, MDL); | |
} | |
if (ia_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ia_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
| |
/* lots of iaaddr, let dereference cleanup */ | |
iaid = 666; | |
ia_na = NULL; | |
if (ia_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ia_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
for (i=0; i<100; i++) { | |
iaaddr = NULL; | |
if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
if (ia_add_iasubopt(ia_na, iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ia_add_iasubopt() %s:%d\n", MDL); | |
return 1; | |
} | |
if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
} | |
if (ia_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ia_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
| |
/* | |
* Test 4: Errors in ia_na. | |
*/ | |
/* bogus allocate arguments */ | |
if (ia_allocate(NULL, 123, "", 0, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: ia_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
ia_na = (struct ia_na *)1; | |
if (ia_allocate(&ia_na, 456, "", 0, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: ia_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
| |
/* bogus reference arguments */ | |
iaid = 666; | |
ia_na = NULL; | |
if (ia_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ia_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
if (ia_reference(NULL, ia_na, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: ia_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
ia_na_copy = (struct ia_na *)1; | |
if (ia_reference(&ia_na_copy, ia_na, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: ia_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
ia_na_copy = NULL; | |
if (ia_reference(&ia_na_copy, NULL, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: ia_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
if (ia_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ia_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
| |
/* bogus dereference arguments */ | |
if (ia_dereference(NULL, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: ia_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
| |
/* bogus remove */ | |
iaid = 666; | |
ia_na = NULL; | |
if (ia_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ia_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
ia_remove_iasubopt(ia_na, NULL, MDL); | |
if (ia_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ia_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
| |
/* | |
* Test 5: Basic ipv6_pool manipulation. | |
*/ | |
| |
/* allocate, reference */ | |
inet_pton(AF_INET6, "1:2:3:4::", &addr); | |
pool = NULL; | |
if (ipv6_pool_allocate(&pool, 0, &addr, 64, 128, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
if (pool->num_active != 0) { | |
printf("ERROR: bad num_active %s:%d\n", MDL); | |
return 1; | |
} | |
if (pool->bits != 64) { | |
printf("ERROR: bad bits %s:%d\n", MDL); | |
return 1; | |
} | |
inet_ntop(AF_INET6, &pool->start_addr, addr_buf, sizeof(addr_buf)); | |
if (strcmp(inet_ntop(AF_INET6, &pool->start_addr, addr_buf, | |
sizeof(addr_buf)), "1:2:3:4::") != 0) { | |
printf("ERROR: bad start_addr %s:%d\n", MDL); | |
return 1; | |
} | |
pool_copy = NULL; | |
if (ipv6_pool_reference(&pool_copy, pool, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
| |
/* create_lease6, renew_lease6, expire_lease6 */ | |
uid = "client0"; | |
memset(&ds, 0, sizeof(ds)); | |
ds.len = strlen(uid); | |
if (!buffer_allocate(&ds.buffer, ds.len, MDL)) { | |
printf("Out of memory\n"); | |
return 1; | |
} | |
ds.data = ds.buffer->data; | |
memcpy((char *)ds.data, uid, ds.len); | |
if (create_lease6(pool, &iaaddr, | |
&attempts, &ds, 1) != ISC_R_SUCCESS) { | |
printf("ERROR: create_lease6() %s:%d\n", MDL); | |
return 1; | |
} | |
if (pool->num_inactive != 1) { | |
printf("ERROR: bad num_inactive %s:%d\n", MDL); | |
return 1; | |
} | |
if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { | |
printf("ERROR: renew_lease6() %s:%d\n", MDL); | |
return 1; | |
} | |
if (pool->num_active != 1) { | |
printf("ERROR: bad num_active %s:%d\n", MDL); | |
return 1; | |
} | |
expired_iaaddr = NULL; | |
if (expire_lease6(&expired_iaaddr, pool, 0) != ISC_R_SUCCESS) { | |
printf("ERROR: expire_lease6() %s:%d\n", MDL); | |
return 1; | |
} | |
if (expired_iaaddr != NULL) { | |
printf("ERROR: should not have expired a lease %s:%d\n", MDL); | |
return 1; | |
} | |
if (pool->num_active != 1) { | |
printf("ERROR: bad num_active %s:%d\n", MDL); | |
return 1; | |
} | |
if (expire_lease6(&expired_iaaddr, pool, 1000) != ISC_R_SUCCESS) { | |
printf("ERROR: expire_lease6() %s:%d\n", MDL); | |
return 1; | |
} | |
if (expired_iaaddr == NULL) { | |
printf("ERROR: should have expired a lease %s:%d\n", MDL); | |
return 1; | |
} | |
if (iasubopt_dereference(&expired_iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
if (pool->num_active != 0) { | |
printf("ERROR: bad num_active %s:%d\n", MDL); | |
return 1; | |
} | |
if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
| |
/* release_lease6, decline_lease6 */ | |
if (create_lease6(pool, &iaaddr, &attempts, | |
&ds, 1) != ISC_R_SUCCESS) { | |
printf("ERROR: create_lease6() %s:%d\n", MDL); | |
return 1; | |
} | |
if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { | |
printf("ERROR: renew_lease6() %s:%d\n", MDL); | |
return 1; | |
} | |
if (pool->num_active != 1) { | |
printf("ERROR: bad num_active %s:%d\n", MDL); | |
return 1; | |
} | |
if (release_lease6(pool, iaaddr) != ISC_R_SUCCESS) { | |
printf("ERROR: decline_lease6() %s:%d\n", MDL); | |
return 1; | |
} | |
if (pool->num_active != 0) { | |
printf("ERROR: bad num_active %s:%d\n", MDL); | |
return 1; | |
} | |
if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
if (create_lease6(pool, &iaaddr, &attempts, | |
&ds, 1) != ISC_R_SUCCESS) { | |
printf("ERROR: create_lease6() %s:%d\n", MDL); | |
return 1; | |
} | |
if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { | |
printf("ERROR: renew_lease6() %s:%d\n", MDL); | |
return 1; | |
} | |
if (pool->num_active != 1) { | |
printf("ERROR: bad num_active %s:%d\n", MDL); | |
return 1; | |
} | |
if (decline_lease6(pool, iaaddr) != ISC_R_SUCCESS) { | |
printf("ERROR: decline_lease6() %s:%d\n", MDL); | |
return 1; | |
} | |
if (pool->num_active != 1) { | |
printf("ERROR: bad num_active %s:%d\n", MDL); | |
return 1; | |
} | |
if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
| |
/* dereference */ | |
if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
if (ipv6_pool_dereference(&pool_copy, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
| |
/* | |
* Test 6: Error ipv6_pool manipulation | |
*/ | |
if (ipv6_pool_allocate(NULL, 0, &addr, 64, 128, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
pool = (struct ipv6_pool *)1; | |
if (ipv6_pool_allocate(&pool, 0, &addr, 64, 128, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
if (ipv6_pool_reference(NULL, pool, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
pool_copy = (struct ipv6_pool *)1; | |
if (ipv6_pool_reference(&pool_copy, pool, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
pool_copy = NULL; | |
if (ipv6_pool_reference(&pool_copy, NULL, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); | |
return 1; | |
} | |
if (ipv6_pool_dereference(NULL, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
if (ipv6_pool_dereference(&pool_copy, MDL) != ISC_R_INVALIDARG) { | |
printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
| |
/* | |
* Test 7: order of expiration | |
*/ | |
pool = NULL; | |
if (ipv6_pool_allocate(&pool, 0, &addr, 64, 128, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
for (i=10; i<100; i+=10) { | |
if (create_lease6(pool, &iaaddr, &attempts, | |
&ds, i) != ISC_R_SUCCESS) { | |
printf("ERROR: create_lease6() %s:%d\n", MDL); | |
return 1; | |
} | |
if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { | |
printf("ERROR: renew_lease6() %s:%d\n", MDL); | |
return 1; | |
} | |
if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
if (pool->num_active != (i / 10)) { | |
printf("ERROR: bad num_active %s:%d\n", MDL); | |
return 1; | |
} | |
} | |
if (pool->num_active != 9) { | |
printf("ERROR: bad num_active %s:%d\n", MDL); | |
return 1; | |
} | |
for (i=10; i<100; i+=10) { | |
if (expire_lease6(&expired_iaaddr, | |
pool, 1000) != ISC_R_SUCCESS) { | |
printf("ERROR: expire_lease6() %s:%d\n", MDL); | |
return 1; | |
} | |
if (expired_iaaddr == NULL) { | |
printf("ERROR: should have expired a lease %s:%d\n", | |
MDL); | |
return 1; | |
} | |
if (pool->num_active != (9 - (i / 10))) { | |
printf("ERROR: bad num_active %s:%d\n", MDL); | |
return 1; | |
} | |
if (expired_iaaddr->hard_lifetime_end_time != i) { | |
printf("ERROR: bad hard_lifetime_end_time %s:%d\n", | |
MDL); | |
return 1; | |
} | |
if (iasubopt_dereference(&expired_iaaddr, MDL) != | |
ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
} | |
if (pool->num_active != 0) { | |
printf("ERROR: bad num_active %s:%d\n", MDL); | |
return 1; | |
} | |
expired_iaaddr = NULL; | |
if (expire_lease6(&expired_iaaddr, pool, 1000) != ISC_R_SUCCESS) { | |
printf("ERROR: expire_lease6() %s:%d\n", MDL); | |
return 1; | |
} | |
if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
| |
/* | |
* Test 8: small pool | |
*/ | |
pool = NULL; | |
addr.s6_addr[14] = 0x81; | |
if (ipv6_pool_allocate(&pool, 0, &addr, 127, 128, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
if (create_lease6(pool, &iaaddr, &attempts, | |
&ds, 42) != ISC_R_SUCCESS) { | |
printf("ERROR: create_lease6() %s:%d\n", MDL); | |
return 1; | |
} | |
if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { | |
printf("ERROR: renew_lease6() %s:%d\n", MDL); | |
return 1; | |
} | |
if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
if (create_lease6(pool, &iaaddr, &attempts, | |
&ds, 11) != ISC_R_SUCCESS) { | |
printf("ERROR: create_lease6() %s:%d\n", MDL); | |
return 1; | |
} | |
if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { | |
printf("ERROR: renew_lease6() %s:%d\n", MDL); | |
return 1; | |
} | |
if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
if (create_lease6(pool, &iaaddr, &attempts, | |
&ds, 11) != ISC_R_NORESOURCES) { | |
printf("ERROR: create_lease6() %s:%d\n", MDL); | |
return 1; | |
} | |
if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
addr.s6_addr[14] = 0; | |
| |
/* | |
* Test 9: functions across all pools | |
*/ | |
pool = NULL; | |
if (ipv6_pool_allocate(&pool, 0, &addr, 64, 128, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); | |
return 1; | |
} | |
if (add_ipv6_pool(pool) != ISC_R_SUCCESS) { | |
printf("ERROR: add_ipv6_pool() %s:%d\n", MDL); | |
return 1; | |
} | |
if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
pool = NULL; | |
if (find_ipv6_pool(&pool, 0, &addr) != ISC_R_SUCCESS) { | |
printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); | |
return 1; | |
} | |
if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
inet_pton(AF_INET6, "1:2:3:4:ffff:ffff:ffff:ffff", &addr); | |
pool = NULL; | |
if (find_ipv6_pool(&pool, 0, &addr) != ISC_R_SUCCESS) { | |
printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); | |
return 1; | |
} | |
if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); | |
return 1; | |
} | |
inet_pton(AF_INET6, "1:2:3:5::", &addr); | |
pool = NULL; | |
if (find_ipv6_pool(&pool, 0, &addr) != ISC_R_NOTFOUND) { | |
printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); | |
return 1; | |
} | |
inet_pton(AF_INET6, "1:2:3:3:ffff:ffff:ffff:ffff", &addr); | |
pool = NULL; | |
if (find_ipv6_pool(&pool, 0, &addr) != ISC_R_NOTFOUND) { | |
printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); | |
return 1; | |
} | |
| |
/* iaid = 666; | |
ia_na = NULL; | |
if (ia_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { | |
printf("ERROR: ia_allocate() %s:%d\n", MDL); | |
return 1; | |
}*/ | |
| |
{ | |
struct in6_addr r; | |
struct data_string ds; | |
u_char data[16]; | |
char buf[64]; | |
int i, j; | |
| |
memset(&ds, 0, sizeof(ds)); | |
memset(data, 0xaa, sizeof(data)); | |
ds.len = 16; | |
ds.data = data; | |
| |
inet_pton(AF_INET6, "3ffe:501:ffff:100::", &addr); | |
for (i = 32; i < 42; i++) | |
for (j = i + 1; j < 49; j++) { | |
memset(&r, 0, sizeof(r)); | |
memset(buf, 0, 64); | |
build_prefix6(&r, &addr, i, j, &ds); | |
inet_ntop(AF_INET6, &r, buf, 64); | |
printf("%d,%d-> %s/%d\n", i, j, buf, j); | |
} | |
} | |
| |
printf("SUCCESS: all tests passed (ignore any warning messages)\n"); | |
return 0; | |
} | |
#endif | |