2 * Copyright (C) 2007-2017 by Internet Systems Consortium, Inc. ("ISC")
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
19 * \todo simplify functions, as pool is now in iaaddr
22 /*! \file server/mdb6.c
24 * \page ipv6structures IPv6 Structures Overview
26 * A brief description of the IPv6 structures as reverse engineered.
28 * There are four major data structures in the lease configuraion.
30 * - shared_network - The shared network is the outer enclosing scope for a
31 * network region that shares a broadcast domain. It is
32 * composed of one or more subnets all of which are valid
33 * in the given region. The share network may be
34 * explicitly defined or implicitly created if there is
35 * only a subnet statement. This structrure is shared
36 * with v4. Each shared network statment or naked subnet
37 * will map to one of these structures
39 * - subnet - The subnet structure mostly specifies the address range
40 * that could be valid in a given region. This structute
41 * doesn't include the addresses that the server can delegate
42 * those are in the ipv6_pool. This structure is also shared
43 * with v4. Each subnet statement will map to one of these
46 * - ipv6_pond - The pond structure is a grouping of the address and prefix
47 * information via the pointers to the ipv6_pool and the
48 * allowability of this pool for given clinets via the permit
49 * lists and the valid TIMEs. This is equivilent to the v4
50 * pool structure and would have been named ip6_pool except
51 * that the name was already in use. Generally each pool6
52 * statement will map to one of these structures. In addition
53 * there may be one or for each group of naked range6 and
54 * prefix6 statements within a shared network that share
55 * the same group of statements.
57 * - ipv6_pool - this contains information about a pool of addresses or prefixes
58 * that the server is using. This includes a hash table that
59 * tracks the active items and a pair of heap tables one for
60 * active items and one for non-active items. The heap tables
61 * are used to determine the next items to be modified due to
62 * timing events (expire mostly).
64 * The linkages then look like this:
66 *+--------------+ +-------------+
67 *|Shared Network| | ipv6_pond |
73 *| Subnets | | pools |
74 *+-----|--------+ +------|------+
90 * | +---------- shared |
95 * The shared network contains a list of all the subnets that are on a broadcast
96 * doamin. These can be used to determine if an address makes sense in a given
97 * domain, but the subnets do not contain the addresses the server can delegate.
98 * Those are stored in the ponds and pools.
100 * In the simple case to find an acceptable address the server would first find
101 * the shared network the client is on based on either the interface used to
102 * receive the request or the relay agent's information. From the shared
103 * network the server will walk through it's list of ponds. For each pond it
104 * will evaluate the permit information against the (already done) classification.
105 * If it finds an acceptable pond it will then walk through the pools for that
106 * pond. The server first checks the type of the pool (NA, TA and PD) agaisnt the
107 * request and if they match it attemps to find an address within that pool. On
108 * success the address is used, on failure the server steps to the next pool and
109 * if necessary to the next pond.
111 * When the server is successful in finding an address it will execute any
112 * statements assocaited with the pond, then the subnet, then the shared
113 * network the group field is for in the above picture).
115 * In configurations that don't include either a shared network or a pool6
116 * statement (or both) the missing pieces are created.
119 * There are three major data structuress involved in the lease database:
121 * - ipv6_pool - see above
122 * - ia_xx - this contains information about a single IA from a request
123 * normally it will contain one pointer to a lease for the client
124 * but it may contain more in some circumstances. There are 3
125 * hash tables to aid in accessing these one each for NA, TA and PD.
126 * - iasubopt - the v6 lease structure. These are created dynamically when
127 * a client asks for something and will eventually be destroyed
128 * if the client doesn't re-ask for that item. A lease has space
129 * for backpointers to the IA and to the pool to which it belongs.
130 * The pool backpointer is always filled, the IA pointer may not be.
132 * In normal use we then have something like this:
136 * ia_na_active +----------------+
137 * ia_ta_active +------------+ | pool |
138 * ia_pd_active | iasubopt |<--| active hash |
139 * +-----------------+ | aka lease |<--| active heap |
140 * | ia_xx | | pool ptr |-->| |
141 * | iasubopt array |<---| iaptr |<--| inactive heap |
142 * | lease ptr |--->| | | |
143 * +-----------------+ +------------+ +----------------+
146 * For the pool either the inactive heap will have a pointer
147 * or both the active heap and the active hash will have pointers.
149 * I think there are several major items to notice. The first is
150 * that as a lease moves around it will be added to and removed
151 * from the address hash table in the pool and between the active
152 * and inactive hash tables. The hash table and the active heap
153 * are used when the lease is either active or abandoned. The
154 * inactive heap is used for all other states. In particular a
155 * lease that has expired or been released will be cleaned
156 * (DDNS removal etc) and then moved to the inactive heap. After
157 * some time period (currently 1 hour) it will be freed.
159 * The second is that when a client requests specific addresses,
160 * either because it previously owned them or if the server supplied
161 * them as part of a solicit, the server will try to lookup the ia_xx
162 * associated with the client and find the addresses there. If it
163 * does find appropriate leases it moves them from the old IA to
164 * a new IA and eventually replaces the old IA with the new IA
165 * in the IA hash tables.
170 #include <sys/types.h>
172 #include <netinet/in.h>
176 #include "omapip/omapip.h"
177 #include "omapip/hash.h"
180 HASH_FUNCTIONS(ia
, unsigned char *, struct ia_xx
, ia_hash_t
,
181 ia_reference
, ia_dereference
, do_string_hash
)
183 ia_hash_t
*ia_na_active
;
184 ia_hash_t
*ia_ta_active
;
185 ia_hash_t
*ia_pd_active
;
187 HASH_FUNCTIONS(iasubopt
, struct in6_addr
*, struct iasubopt
, iasubopt_hash_t
,
188 iasubopt_reference
, iasubopt_dereference
, do_string_hash
)
190 struct ipv6_pool
**pools
;
194 * Create a new IAADDR/PREFIX structure.
196 * - iasubopt must be a pointer to a (struct iasubopt *) pointer previously
197 * initialized to NULL
200 iasubopt_allocate(struct iasubopt
**iasubopt
, const char *file
, int line
) {
201 struct iasubopt
*tmp
;
203 if (iasubopt
== NULL
) {
204 log_error("%s(%d): NULL pointer reference", file
, line
);
205 return DHCP_R_INVALIDARG
;
207 if (*iasubopt
!= NULL
) {
208 log_error("%s(%d): non-NULL pointer", file
, line
);
209 return DHCP_R_INVALIDARG
;
212 tmp
= dmalloc(sizeof(*tmp
), file
, line
);
214 return ISC_R_NOMEMORY
;
218 tmp
->state
= FTS_FREE
;
219 tmp
->heap_index
= -1;
223 return ISC_R_SUCCESS
;
227 * Reference an IAADDR/PREFIX structure.
229 * - iasubopt must be a pointer to a (struct iasubopt *) pointer previously
230 * initialized to NULL
233 iasubopt_reference(struct iasubopt
**iasubopt
, struct iasubopt
*src
,
234 const char *file
, int line
) {
235 if (iasubopt
== NULL
) {
236 log_error("%s(%d): NULL pointer reference", file
, line
);
237 return DHCP_R_INVALIDARG
;
239 if (*iasubopt
!= NULL
) {
240 log_error("%s(%d): non-NULL pointer", file
, line
);
241 return DHCP_R_INVALIDARG
;
244 log_error("%s(%d): NULL pointer reference", file
, line
);
245 return DHCP_R_INVALIDARG
;
249 return ISC_R_SUCCESS
;
254 * Dereference an IAADDR/PREFIX structure.
256 * If it is the last reference, then the memory for the
257 * structure is freed.
260 iasubopt_dereference(struct iasubopt
**iasubopt
, const char *file
, int line
) {
261 struct iasubopt
*tmp
;
263 if ((iasubopt
== NULL
) || (*iasubopt
== NULL
)) {
264 log_error("%s(%d): NULL pointer", file
, line
);
265 return DHCP_R_INVALIDARG
;
272 if (tmp
->refcnt
< 0) {
273 log_error("%s(%d): negative refcnt", file
, line
);
276 if (tmp
->refcnt
== 0) {
277 if (tmp
->ia
!= NULL
) {
278 ia_dereference(&(tmp
->ia
), file
, line
);
280 if (tmp
->ipv6_pool
!= NULL
) {
281 ipv6_pool_dereference(&(tmp
->ipv6_pool
), file
, line
);
283 if (tmp
->scope
!= NULL
) {
284 binding_scope_dereference(&tmp
->scope
, file
, line
);
287 if (tmp
->on_star
.on_expiry
!= NULL
) {
288 executable_statement_dereference
289 (&tmp
->on_star
.on_expiry
, MDL
);
291 if (tmp
->on_star
.on_commit
!= NULL
) {
292 executable_statement_dereference
293 (&tmp
->on_star
.on_commit
, MDL
);
295 if (tmp
->on_star
.on_release
!= NULL
) {
296 executable_statement_dereference
297 (&tmp
->on_star
.on_release
, MDL
);
300 dfree(tmp
, file
, line
);
303 return ISC_R_SUCCESS
;
307 * Make the key that we use for IA.
310 ia_make_key(struct data_string
*key
, u_int32_t iaid
,
311 const char *duid
, unsigned int duid_len
,
312 const char *file
, int line
) {
314 memset(key
, 0, sizeof(*key
));
315 key
->len
= duid_len
+ sizeof(iaid
);
316 if (!buffer_allocate(&(key
->buffer
), key
->len
, file
, line
)) {
317 return ISC_R_NOMEMORY
;
319 key
->data
= key
->buffer
->data
;
320 memcpy((char *)key
->data
, &iaid
, sizeof(iaid
));
321 memcpy((char *)key
->data
+ sizeof(iaid
), duid
, duid_len
);
323 return ISC_R_SUCCESS
;
327 * Create a new IA structure.
329 * - ia must be a pointer to a (struct ia_xx *) pointer previously
330 * initialized to NULL
331 * - iaid and duid are values from the client
333 * XXXsk: we don't concern ourself with the byte order of the IAID,
334 * which might be a problem if we transfer this structure
335 * between machines of different byte order
338 ia_allocate(struct ia_xx
**ia
, u_int32_t iaid
,
339 const char *duid
, unsigned int duid_len
,
340 const char *file
, int line
) {
344 log_error("%s(%d): NULL pointer reference", file
, line
);
345 return DHCP_R_INVALIDARG
;
348 log_error("%s(%d): non-NULL pointer", file
, line
);
349 return DHCP_R_INVALIDARG
;
352 tmp
= dmalloc(sizeof(*tmp
), file
, line
);
354 return ISC_R_NOMEMORY
;
357 if (ia_make_key(&tmp
->iaid_duid
, iaid
,
358 duid
, duid_len
, file
, line
) != ISC_R_SUCCESS
) {
359 dfree(tmp
, file
, line
);
360 return ISC_R_NOMEMORY
;
366 return ISC_R_SUCCESS
;
370 * Reference an IA structure.
372 * - ia must be a pointer to a (struct ia_xx *) pointer previously
373 * initialized to NULL
376 ia_reference(struct ia_xx
**ia
, struct ia_xx
*src
,
377 const char *file
, int line
) {
379 log_error("%s(%d): NULL pointer reference", file
, line
);
380 return DHCP_R_INVALIDARG
;
383 log_error("%s(%d): non-NULL pointer", file
, line
);
384 return DHCP_R_INVALIDARG
;
387 log_error("%s(%d): NULL pointer reference", file
, line
);
388 return DHCP_R_INVALIDARG
;
392 return ISC_R_SUCCESS
;
396 * Dereference an IA structure.
398 * If it is the last reference, then the memory for the
399 * structure is freed.
402 ia_dereference(struct ia_xx
**ia
, const char *file
, int line
) {
406 if ((ia
== NULL
) || (*ia
== NULL
)) {
407 log_error("%s(%d): NULL pointer", file
, line
);
408 return DHCP_R_INVALIDARG
;
415 if (tmp
->refcnt
< 0) {
416 log_error("%s(%d): negative refcnt", file
, line
);
419 if (tmp
->refcnt
== 0) {
420 if (tmp
->iasubopt
!= NULL
) {
421 for (i
=0; i
<tmp
->num_iasubopt
; i
++) {
422 iasubopt_dereference(&(tmp
->iasubopt
[i
]),
425 dfree(tmp
->iasubopt
, file
, line
);
427 data_string_forget(&(tmp
->iaid_duid
), file
, line
);
428 dfree(tmp
, file
, line
);
430 return ISC_R_SUCCESS
;
435 * Add an IAADDR/PREFIX entry to an IA structure.
438 ia_add_iasubopt(struct ia_xx
*ia
, struct iasubopt
*iasubopt
,
439 const char *file
, int line
) {
441 struct iasubopt
**new;
444 * Grow our array if we need to.
446 * Note: we pick 4 as the increment, as that seems a reasonable
447 * guess as to how many addresses/prefixes we might expect
450 if (ia
->max_iasubopt
<= ia
->num_iasubopt
) {
451 max
= ia
->max_iasubopt
+ 4;
452 new = dmalloc(max
* sizeof(struct iasubopt
*), file
, line
);
454 return ISC_R_NOMEMORY
;
456 memcpy(new, ia
->iasubopt
,
457 ia
->num_iasubopt
* sizeof(struct iasubopt
*));
459 ia
->max_iasubopt
= max
;
462 iasubopt_reference(&(ia
->iasubopt
[ia
->num_iasubopt
]), iasubopt
,
466 return ISC_R_SUCCESS
;
470 * Remove an IAADDR/PREFIX entry to an IA structure.
472 * Note: if a suboption appears more than once, then only ONE will be removed.
475 ia_remove_iasubopt(struct ia_xx
*ia
, struct iasubopt
*iasubopt
,
476 const char *file
, int line
) {
478 if (ia
== NULL
|| iasubopt
== NULL
)
481 for (i
=0; i
<ia
->num_iasubopt
; i
++) {
482 if (ia
->iasubopt
[i
] == iasubopt
) {
483 /* remove this sub option */
484 iasubopt_dereference(&(ia
->iasubopt
[i
]), file
, line
);
485 /* move remaining suboption pointers down one */
486 for (j
=i
+1; j
< ia
->num_iasubopt
; j
++) {
487 ia
->iasubopt
[j
-1] = ia
->iasubopt
[j
];
489 /* decrease our total count */
490 /* remove the back-reference in the suboption itself */
491 ia_dereference(&iasubopt
->ia
, file
, line
);
496 log_error("%s(%d): IAADDR/PREFIX not in IA", file
, line
);
500 * Remove all addresses/prefixes from an IA.
503 ia_remove_all_lease(struct ia_xx
*ia
, const char *file
, int line
) {
506 for (i
=0; i
<ia
->num_iasubopt
; i
++) {
507 ia_dereference(&(ia
->iasubopt
[i
]->ia
), file
, line
);
508 iasubopt_dereference(&(ia
->iasubopt
[i
]), file
, line
);
510 ia
->num_iasubopt
= 0;
517 ia_equal(const struct ia_xx
*a
, const struct ia_xx
*b
)
523 * Handle cases where one or both of the inputs is NULL.
534 * Check the type is the same.
536 if (a
->ia_type
!= b
->ia_type
) {
541 * Check the DUID is the same.
543 if (a
->iaid_duid
.len
!= b
->iaid_duid
.len
) {
546 if (memcmp(a
->iaid_duid
.data
,
547 b
->iaid_duid
.data
, a
->iaid_duid
.len
) != 0) {
552 * Make sure we have the same number of addresses/prefixes in each.
554 if (a
->num_iasubopt
!= b
->num_iasubopt
) {
559 * Check that each address/prefix is present in both.
561 for (i
=0; i
<a
->num_iasubopt
; i
++) {
563 for (j
=0; j
<a
->num_iasubopt
; j
++) {
564 if (a
->iasubopt
[i
]->plen
!= b
->iasubopt
[i
]->plen
)
566 if (memcmp(&(a
->iasubopt
[i
]->addr
),
567 &(b
->iasubopt
[j
]->addr
),
568 sizeof(struct in6_addr
)) == 0) {
579 * These are the same in every way we care about.
585 * Helper function for lease heaps.
586 * Makes the top of the heap the oldest lease.
589 lease_older(void *a
, void *b
) {
590 struct iasubopt
*la
= (struct iasubopt
*)a
;
591 struct iasubopt
*lb
= (struct iasubopt
*)b
;
593 if (la
->hard_lifetime_end_time
== lb
->hard_lifetime_end_time
) {
594 return difftime(la
->soft_lifetime_end_time
,
595 lb
->soft_lifetime_end_time
) < 0;
597 return difftime(la
->hard_lifetime_end_time
,
598 lb
->hard_lifetime_end_time
) < 0;
603 * Helper function for lease address/prefix heaps.
604 * Callback when an address's position in the heap changes.
607 lease_index_changed(void *iasubopt
, unsigned int new_heap_index
) {
608 ((struct iasubopt
*)iasubopt
)-> heap_index
= new_heap_index
;
614 * \brief Create a new IPv6 lease pool structure
616 * Allocate space for a new ipv6_pool structure and return a reference
617 * to it, includes setting the reference count to 1.
619 * \param pool = space for returning a referenced pointer to the pool.
620 * This must point to a space that has been initialzied
621 * to NULL by the caller.
622 * \param[in] type = The type of the pool NA, TA or PD
623 * \param[in] start_addr = The first address in the range for the pool
624 * \param[in] bits = The contiguous bits of the pool
628 * ISC_R_SUCCESS = The pool was successfully created, pool points to it.
629 * DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been
631 * ISC_R_NOMEMORY = The system wasn't able to allocate memory, pool has
635 ipv6_pool_allocate(struct ipv6_pool
**pool
, u_int16_t type
,
636 const struct in6_addr
*start_addr
, int bits
,
637 int units
, const char *file
, int line
) {
638 struct ipv6_pool
*tmp
;
641 log_error("%s(%d): NULL pointer reference", file
, line
);
642 return DHCP_R_INVALIDARG
;
645 log_error("%s(%d): non-NULL pointer", file
, line
);
646 return DHCP_R_INVALIDARG
;
649 tmp
= dmalloc(sizeof(*tmp
), file
, line
);
651 return ISC_R_NOMEMORY
;
655 tmp
->pool_type
= type
;
656 tmp
->start_addr
= *start_addr
;
659 if (!iasubopt_new_hash(&tmp
->leases
, DEFAULT_HASH_SIZE
, file
, line
)) {
660 dfree(tmp
, file
, line
);
661 return ISC_R_NOMEMORY
;
663 if (isc_heap_create(dhcp_gbl_ctx
.mctx
, lease_older
, lease_index_changed
,
664 0, &(tmp
->active_timeouts
)) != ISC_R_SUCCESS
) {
665 iasubopt_free_hash_table(&(tmp
->leases
), file
, line
);
666 dfree(tmp
, file
, line
);
667 return ISC_R_NOMEMORY
;
669 if (isc_heap_create(dhcp_gbl_ctx
.mctx
, lease_older
, lease_index_changed
,
670 0, &(tmp
->inactive_timeouts
)) != ISC_R_SUCCESS
) {
671 isc_heap_destroy(&(tmp
->active_timeouts
));
672 iasubopt_free_hash_table(&(tmp
->leases
), file
, line
);
673 dfree(tmp
, file
, line
);
674 return ISC_R_NOMEMORY
;
678 return ISC_R_SUCCESS
;
683 * \brief reference an IPv6 pool structure.
685 * This function genreates a reference to an ipv6_pool structure
686 * and increments the reference count on the structure.
688 * \param[out] pool = space for returning a referenced pointer to the pool.
689 * This must point to a space that has been initialzied
690 * to NULL by the caller.
691 * \param[in] src = A pointer to the pool to reference. This must not be
695 * ISC_R_SUCCESS = The pool was successfully referenced, pool now points
697 * DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been
701 ipv6_pool_reference(struct ipv6_pool
**pool
, struct ipv6_pool
*src
,
702 const char *file
, int line
) {
704 log_error("%s(%d): NULL pointer reference", file
, line
);
705 return DHCP_R_INVALIDARG
;
708 log_error("%s(%d): non-NULL pointer", file
, line
);
709 return DHCP_R_INVALIDARG
;
712 log_error("%s(%d): NULL pointer reference", file
, line
);
713 return DHCP_R_INVALIDARG
;
717 return ISC_R_SUCCESS
;
721 * Note: Each IAADDR/PREFIX in a pool is referenced by the pool. This is needed
722 * to prevent the lease from being garbage collected out from under the
725 * The references are made from the hash and from the heap. The following
726 * helper functions dereference these when a pool is destroyed.
730 * Helper function for pool cleanup.
731 * Dereference each of the hash entries in a pool.
734 dereference_hash_entry(const void *name
, unsigned len
, void *value
) {
735 struct iasubopt
*iasubopt
= (struct iasubopt
*)value
;
737 iasubopt_dereference(&iasubopt
, MDL
);
738 return ISC_R_SUCCESS
;
742 * Helper function for pool cleanup.
743 * Dereference each of the heap entries in a pool.
746 dereference_heap_entry(void *value
, void *dummy
) {
747 struct iasubopt
*iasubopt
= (struct iasubopt
*)value
;
749 iasubopt_dereference(&iasubopt
, MDL
);
754 * \brief de-reference an IPv6 pool structure.
756 * This function decrements the reference count in an ipv6_pool structure.
757 * If this was the last reference then the memory for the structure is
760 * \param[in] pool = A pointer to the pointer to the pool that should be
761 * de-referenced. On success the pointer to the pool
762 * is cleared. It must not be NULL and must not point
766 * ISC_R_SUCCESS = The pool was successfully de-referenced, pool now points
768 * DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been
772 ipv6_pool_dereference(struct ipv6_pool
**pool
, const char *file
, int line
) {
773 struct ipv6_pool
*tmp
;
775 if ((pool
== NULL
) || (*pool
== NULL
)) {
776 log_error("%s(%d): NULL pointer", file
, line
);
777 return DHCP_R_INVALIDARG
;
784 if (tmp
->refcnt
< 0) {
785 log_error("%s(%d): negative refcnt", file
, line
);
788 if (tmp
->refcnt
== 0) {
789 iasubopt_hash_foreach(tmp
->leases
, dereference_hash_entry
);
790 iasubopt_free_hash_table(&(tmp
->leases
), file
, line
);
791 isc_heap_foreach(tmp
->active_timeouts
,
792 dereference_heap_entry
, NULL
);
793 isc_heap_destroy(&(tmp
->active_timeouts
));
794 isc_heap_foreach(tmp
->inactive_timeouts
,
795 dereference_heap_entry
, NULL
);
796 isc_heap_destroy(&(tmp
->inactive_timeouts
));
797 dfree(tmp
, file
, line
);
800 return ISC_R_SUCCESS
;
804 * Create an address by hashing the input, and using that for
805 * the non-network part.
808 build_address6(struct in6_addr
*addr
,
809 const struct in6_addr
*net_start_addr
, int net_bits
,
810 const struct data_string
*input
) {
818 * Use MD5 to get a nice 128 bit hash of the input.
819 * Yes, we know MD5 isn't cryptographically sound.
823 isc_md5_update(&ctx
, input
->data
, input
->len
);
824 isc_md5_final(&ctx
, (unsigned char *)addr
);
827 * Copy the [0..128] network bits over.
830 net_str
= (const char *)net_start_addr
;
831 net_bytes
= net_bits
/ 8;
832 for (i
= 0; i
< net_bytes
; i
++) {
835 switch (net_bits
% 8) {
836 case 1: str
[i
] = (str
[i
] & 0x7F) | (net_str
[i
] & 0x80); break;
837 case 2: str
[i
] = (str
[i
] & 0x3F) | (net_str
[i
] & 0xC0); break;
838 case 3: str
[i
] = (str
[i
] & 0x1F) | (net_str
[i
] & 0xE0); break;
839 case 4: str
[i
] = (str
[i
] & 0x0F) | (net_str
[i
] & 0xF0); break;
840 case 5: str
[i
] = (str
[i
] & 0x07) | (net_str
[i
] & 0xF8); break;
841 case 6: str
[i
] = (str
[i
] & 0x03) | (net_str
[i
] & 0xFC); break;
842 case 7: str
[i
] = (str
[i
] & 0x01) | (net_str
[i
] & 0xFE); break;
846 * Set the universal/local bit ("u bit") to zero for /64s. The
847 * individual/group bit ("g bit") is unchanged, because the g-bit
848 * has no meaning when the u-bit is cleared.
856 valid_eui_64_duid(const struct data_string
* uid
, int offset
) {
857 if (uid
->len
== (offset
+ EUI_64_ID_LEN
)) {
858 const unsigned char* duid
= uid
->data
+ offset
;
859 return (((duid
[0] == 0x00 && duid
[1] == 0x03) &&
860 (duid
[2] == 0x00 && duid
[3] == 0x1b)));
868 * Create an EUI-64 address
871 build_address6_eui_64(struct in6_addr
*addr
,
872 const struct in6_addr
*net_start_addr
, int net_bits
,
873 const struct data_string
*iaid_duid
, int duid_beg
) {
875 if (net_bits
!= 64) {
876 log_error("build_address_eui_64: network is not 64 bits");
877 return (ISC_R_FAILURE
);
880 if (valid_eui_64_duid(iaid_duid
, duid_beg
)) {
881 const unsigned char *duid
= iaid_duid
->data
+ duid_beg
;
883 /* copy network prefix to the high 64 bits */
884 memcpy(addr
->s6_addr
, net_start_addr
->s6_addr
, 8);
886 /* copy Link-layer address to low 64 bits */
887 memcpy(addr
->s6_addr
+ 8, duid
+ 4, 8);
889 /* RFC-3315 Any address assigned by a server that is based
890 * on an EUI-64 identifier MUST include an interface identifier
891 * with the "u" (universal/local) and "g" (individual/group)
892 * bits of the interface identifier set appropriately, as
893 * indicated in section 2.5.1 of RFC 2373 [5]. */
894 addr
->s6_addr
[8] |= 0x02;
895 return (ISC_R_SUCCESS
);
898 log_error("build_address_eui_64: iaid_duid not a valid EUI-64: %s",
899 print_hex_1(iaid_duid
->len
, iaid_duid
->data
, 60));
900 return (ISC_R_FAILURE
);
904 valid_for_eui_64_pool(struct ipv6_pool
* pool
, struct data_string
* uid
,
905 int duid_beg
, struct in6_addr
* ia_addr
) {
906 struct in6_addr test_addr
;
907 /* If it's not an EUI-64 pool bail */
908 if (!pool
->ipv6_pond
->use_eui_64
) {
912 if (!valid_eui_64_duid(uid
, duid_beg
)) {
913 /* Dynamic lease in a now eui_64 pond, toss it*/
917 /* Call build_address6_eui_64() and compare it's result to
918 * this lease and see if they match. */
919 memset (&test_addr
, 0, sizeof(test_addr
));
920 build_address6_eui_64(&test_addr
, &pool
->start_addr
, pool
->bits
,
923 return (!memcmp(ia_addr
, &test_addr
, sizeof(test_addr
)));
929 * Create a temporary address by a variant of RFC 4941 algo.
930 * Note: this should not be used for prefixes shorter than 64 bits.
933 build_temporary6(struct in6_addr
*addr
,
934 const struct in6_addr
*net_start_addr
, int net_bits
,
935 const struct data_string
*input
) {
936 static u_int32_t history
[2];
937 static u_int32_t counter
= 0;
939 unsigned char md
[16];
942 * First time/time to reseed.
943 * Please use a good pseudo-random generator here!
946 isc_random_get(&history
[0]);
947 isc_random_get(&history
[1]);
951 * Use MD5 as recommended by RFC 4941.
954 isc_md5_update(&ctx
, (unsigned char *)&history
[0], 8UL);
955 isc_md5_update(&ctx
, input
->data
, input
->len
);
956 isc_md5_final(&ctx
, md
);
961 if (net_bits
== 64) {
962 memcpy(&addr
->s6_addr
[0], &net_start_addr
->s6_addr
[0], 8);
963 memcpy(&addr
->s6_addr
[8], md
, 8);
964 addr
->s6_addr
[8] &= ~0x02;
972 * Copy the [0..128] network bits over.
975 net_str
= (const char *)net_start_addr
;
976 net_bytes
= net_bits
/ 8;
977 for (i
= 0; i
< net_bytes
; i
++) {
980 memcpy(str
+ net_bytes
, md
, 16 - net_bytes
);
981 switch (net_bits
% 8) {
982 case 1: str
[i
] = (str
[i
] & 0x7F) | (net_str
[i
] & 0x80); break;
983 case 2: str
[i
] = (str
[i
] & 0x3F) | (net_str
[i
] & 0xC0); break;
984 case 3: str
[i
] = (str
[i
] & 0x1F) | (net_str
[i
] & 0xE0); break;
985 case 4: str
[i
] = (str
[i
] & 0x0F) | (net_str
[i
] & 0xF0); break;
986 case 5: str
[i
] = (str
[i
] & 0x07) | (net_str
[i
] & 0xF8); break;
987 case 6: str
[i
] = (str
[i
] & 0x03) | (net_str
[i
] & 0xFC); break;
988 case 7: str
[i
] = (str
[i
] & 0x01) | (net_str
[i
] & 0xFE); break;
994 * Save history for the next call.
996 memcpy((unsigned char *)&history
[0], md
+ 8, 8);
1000 /* Reserved Subnet Router Anycast ::0:0:0:0. */
1001 static struct in6_addr rtany
;
1002 /* Reserved Subnet Anycasts ::fdff:ffff:ffff:ff80-::fdff:ffff:ffff:ffff. */
1003 static struct in6_addr resany
;
1006 * Create a lease for the given address and client duid.
1008 * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
1009 * initialized to NULL
1011 * Right now we simply hash the DUID, and if we get a collision, we hash
1012 * again until we find a free address. We try this a fixed number of times,
1013 * to avoid getting stuck in a loop (this is important on small pools
1014 * where we can run out of space).
1016 * We return the number of attempts that it took to find an available
1017 * lease. This tells callers when a pool is are filling up, as
1018 * well as an indication of how full the pool is; statistically the
1019 * more full a pool is the more attempts must be made before finding
1020 * a free lease. Realistically this will only happen in very full
1023 * We probably want different algorithms depending on the network size, in
1027 create_lease6(struct ipv6_pool
*pool
, struct iasubopt
**addr
,
1028 unsigned int *attempts
,
1029 const struct data_string
*uid
, time_t soft_lifetime_end_time
) {
1030 struct data_string ds
;
1031 struct in6_addr tmp
;
1032 struct iasubopt
*test_iaaddr
;
1033 struct data_string new_ds
;
1034 struct iasubopt
*iaaddr
;
1035 isc_result_t result
;
1036 isc_boolean_t reserved_iid
;
1037 static isc_boolean_t init_resiid
= ISC_FALSE
;
1040 * Fill the reserved IIDs.
1043 memset(&rtany
, 0, 16);
1044 memset(&resany
, 0, 8);
1045 resany
.s6_addr
[8] = 0xfd;
1046 memset(&resany
.s6_addr
[9], 0xff, 6);
1047 init_resiid
= ISC_TRUE
;
1051 * Use the UID as our initial seed for the hash
1053 memset(&ds
, 0, sizeof(ds
));
1054 data_string_copy(&ds
, (struct data_string
*)uid
, MDL
);
1059 * Give up at some point.
1061 if (++(*attempts
) > 100) {
1062 data_string_forget(&ds
, MDL
);
1063 return ISC_R_NORESOURCES
;
1069 switch (pool
->pool_type
) {
1072 build_address6(&tmp
, &pool
->start_addr
,
1076 /* temporary address */
1077 build_temporary6(&tmp
, &pool
->start_addr
,
1082 log_error("create_lease6: prefix pool.");
1083 return DHCP_R_INVALIDARG
;
1085 log_error("create_lease6: untyped pool.");
1086 return DHCP_R_INVALIDARG
;
1090 * Avoid reserved interface IDs. (cf. RFC 5453)
1092 reserved_iid
= ISC_FALSE
;
1093 if (memcmp(&tmp
.s6_addr
[8], &rtany
.s6_addr
[8], 8) == 0) {
1094 reserved_iid
= ISC_TRUE
;
1096 if (!reserved_iid
&&
1097 (memcmp(&tmp
.s6_addr
[8], &resany
.s6_addr
[8], 7) == 0) &&
1098 ((tmp
.s6_addr
[15] & 0x80) == 0x80)) {
1099 reserved_iid
= ISC_TRUE
;
1103 * If this address is not in use, we're happy with it
1106 if (!reserved_iid
&&
1107 (iasubopt_hash_lookup(&test_iaaddr
, pool
->leases
,
1108 &tmp
, sizeof(tmp
), MDL
) == 0)) {
1111 if (test_iaaddr
!= NULL
)
1112 iasubopt_dereference(&test_iaaddr
, MDL
);
1115 * Otherwise, we create a new input, adding the address
1117 memset(&new_ds
, 0, sizeof(new_ds
));
1118 new_ds
.len
= ds
.len
+ sizeof(tmp
);
1119 if (!buffer_allocate(&new_ds
.buffer
, new_ds
.len
, MDL
)) {
1120 data_string_forget(&ds
, MDL
);
1121 return ISC_R_NOMEMORY
;
1123 new_ds
.data
= new_ds
.buffer
->data
;
1124 memcpy(new_ds
.buffer
->data
, ds
.data
, ds
.len
);
1125 memcpy(new_ds
.buffer
->data
+ ds
.len
, &tmp
, sizeof(tmp
));
1126 data_string_forget(&ds
, MDL
);
1127 data_string_copy(&ds
, &new_ds
, MDL
);
1128 data_string_forget(&new_ds
, MDL
);
1131 data_string_forget(&ds
, MDL
);
1134 * We're happy with the address, create an IAADDR
1138 result
= iasubopt_allocate(&iaaddr
, MDL
);
1139 if (result
!= ISC_R_SUCCESS
) {
1143 memcpy(&iaaddr
->addr
, &tmp
, sizeof(iaaddr
->addr
));
1146 * Add the lease to the pool (note state is free, not active?!).
1148 result
= add_lease6(pool
, iaaddr
, soft_lifetime_end_time
);
1149 if (result
== ISC_R_SUCCESS
) {
1150 iasubopt_reference(addr
, iaaddr
, MDL
);
1152 iasubopt_dereference(&iaaddr
, MDL
);
1158 * \brief Assign an EUI-64 address from a pool for a given iaid-duid
1160 * \param pool - pool from which the address is assigned
1161 * \param iaddr - pointer to the iasubopt to contain the assigned address is
1162 * \param uid - data_string containing the iaid-duid tuple
1163 * \param soft_lifetime_end_time - lifetime of the lease for a solicit?
1165 * \return status indicating success or nature of the failure
1168 create_lease6_eui_64(struct ipv6_pool
*pool
, struct iasubopt
**addr
,
1169 const struct data_string
*uid
,
1170 time_t soft_lifetime_end_time
) {
1171 struct in6_addr tmp
;
1172 struct iasubopt
*test_iaaddr
;
1173 struct iasubopt
*iaaddr
;
1174 isc_result_t result
;
1175 static isc_boolean_t init_resiid
= ISC_FALSE
;
1177 /* Fill the reserved IIDs. */
1179 memset(&rtany
, 0, 16);
1180 memset(&resany
, 0, 8);
1181 resany
.s6_addr
[8] = 0xfd;
1182 memset(&resany
.s6_addr
[9], 0xff, 6);
1183 init_resiid
= ISC_TRUE
;
1186 /* Pool must be IA_NA */
1187 if (pool
->pool_type
!= D6O_IA_NA
) {
1188 log_error("create_lease6_eui_64: pool type is not IA_NA.");
1189 return (DHCP_R_INVALIDARG
);
1192 /* Attempt to build the address */
1193 if (build_address6_eui_64 (&tmp
, &pool
->start_addr
, pool
->bits
,
1194 uid
, IAID_LEN
) != ISC_R_SUCCESS
) {
1195 log_error("create_lease6_eui_64: build_address6_eui_64 failed");
1196 return (ISC_R_FAILURE
);
1199 /* Avoid reserved interface IDs. (cf. RFC 5453) */
1200 if ((memcmp(&tmp
.s6_addr
[8], &rtany
.s6_addr
[8], 8) == 0) ||
1201 ((memcmp(&tmp
.s6_addr
[8], &resany
.s6_addr
[8], 7) == 0) &&
1202 ((tmp
.s6_addr
[15] & 0x80) == 0x80))) {
1203 log_error("create_lease6_eui_64: "
1204 "address conflicts with reserved IID");
1205 return (ISC_R_FAILURE
);
1208 /* If this address is not in use, we're happy with it */
1210 if (iasubopt_hash_lookup(&test_iaaddr
, pool
->leases
,
1211 &tmp
, sizeof(tmp
), MDL
) != 0) {
1213 /* See if it's ours. Static leases won't have an ia */
1215 if (!test_iaaddr
->ia
) {
1216 log_error("create_lease6_eui_64: "
1217 "address %s is assigned to static lease",
1218 pin6_addr(&test_iaaddr
->addr
));
1220 /* Not sure if this can actually happen */
1221 struct data_string
* found
= &test_iaaddr
->ia
->iaid_duid
;
1222 ours
= ((found
->len
== uid
->len
) &&
1223 (!memcmp(found
->data
, uid
->data
, uid
->len
)));
1224 log_error("create_lease6_eui_64: "
1225 "address %s belongs to %s",
1226 pin6_addr(&test_iaaddr
->addr
),
1227 print_hex_1(found
->len
, found
->data
, 60));
1230 iasubopt_dereference(&test_iaaddr
, MDL
);
1233 return (ISC_R_FAILURE
);
1237 /* We're happy with the address, create an IAADDR to hold it. */
1239 result
= iasubopt_allocate(&iaaddr
, MDL
);
1240 if (result
!= ISC_R_SUCCESS
) {
1241 log_error("create_lease6_eui_64: could not allocate iasubop");
1245 memcpy(&iaaddr
->addr
, &tmp
, sizeof(iaaddr
->addr
));
1247 /* Add the lease to the pool and the reply */
1248 result
= add_lease6(pool
, iaaddr
, soft_lifetime_end_time
);
1249 if (result
== ISC_R_SUCCESS
) {
1250 iasubopt_reference(addr
, iaaddr
, MDL
);
1253 iasubopt_dereference(&iaaddr
, MDL
);
1260 * \brief Cleans up leases when reading from a lease file
1262 * This function is only expected to be run when reading leases in from a file.
1263 * It checks to see if a lease already exists for the new leases's address.
1264 * We don't add expired leases to the structures when reading a lease file
1265 * which limits what can happen. We have two variables the owners of the leases
1266 * being the same or different and the new lease being active or non-active:
1268 * same no remove old lease and its connections
1269 * same yes nothing to do, other code will update the structures.
1270 * diff no nothing to do
1271 * diff yes this combination shouldn't happen, we should only have a
1272 * single active lease per address at a time and that lease
1273 * should move to non-active before any other lease can
1274 * become active for that address.
1275 * Currently we delete the previous lease and pass an error
1276 * to the caller who should log an error.
1278 * When we remove a lease we remove it from the hash table and active heap
1279 * (remember only active leases are in the structures at this time) for the
1280 * pool, and from the IA's array. If, after we've removed the pointer from
1281 * IA's array to the lease, the IA has no more pointers we remove it from
1282 * the appropriate hash table as well.
1284 * \param[in] ia_table = the hash table for the IA
1285 * \param[in] pool = the pool to update
1286 * \param[in] lease = the new lease we want to add
1287 * \param[in] ia = the new ia we are building
1290 * ISC_R_SUCCESS = the incoming lease and any previous lease were in
1291 * an expected state - one of the first 3 options above.
1292 * If necessary the old lease was removed.
1293 * ISC_R_FAILURE = there is already an active lease for the address in
1294 * the incoming lease. This shouldn't happen if it does
1295 * flag an error for the caller to log.
1299 cleanup_lease6(ia_hash_t
*ia_table
,
1300 struct ipv6_pool
*pool
,
1301 struct iasubopt
*lease
,
1304 struct iasubopt
*test_iasubopt
, *tmp_iasubopt
;
1305 struct ia_xx
*old_ia
;
1306 isc_result_t status
= ISC_R_SUCCESS
;
1308 test_iasubopt
= NULL
;
1312 * Look up the address - if we don't find a lease
1313 * we don't need to do anything.
1315 if (iasubopt_hash_lookup(&test_iasubopt
, pool
->leases
,
1316 &lease
->addr
, sizeof(lease
->addr
),
1318 return (ISC_R_SUCCESS
);
1321 if (test_iasubopt
->ia
== NULL
) {
1322 /* no old ia, no work to do */
1323 iasubopt_dereference(&test_iasubopt
, MDL
);
1327 ia_reference(&old_ia
, test_iasubopt
->ia
, MDL
);
1329 if ((old_ia
->iaid_duid
.len
== ia
->iaid_duid
.len
) &&
1330 (memcmp((unsigned char *)ia
->iaid_duid
.data
,
1331 (unsigned char *)old_ia
->iaid_duid
.data
,
1332 ia
->iaid_duid
.len
) == 0)) {
1334 if ((lease
->state
== FTS_ACTIVE
) ||
1335 (lease
->state
== FTS_ABANDONED
)) {
1336 /* still active, no need to delete */
1341 if ((lease
->state
!= FTS_ACTIVE
) &&
1342 (lease
->state
!= FTS_ABANDONED
)) {
1343 /* new lease isn't active, no work */
1348 * We appear to have two active leases, this shouldn't happen.
1349 * Before a second lease can be set to active the first lease
1350 * should be set to inactive (released, expired etc). For now
1351 * delete the previous lease and indicate a failure to the
1352 * caller so it can generate a warning.
1353 * In the future we may try and determine which is the better
1357 status
= ISC_R_FAILURE
;
1361 * Remove the old lease from the active heap and from the hash table
1362 * then remove the lease from the IA and clean up the IA if necessary.
1364 isc_heap_delete(pool
->active_timeouts
, test_iasubopt
->heap_index
);
1366 if (pool
->ipv6_pond
)
1367 pool
->ipv6_pond
->num_active
--;
1369 if (lease
->state
== FTS_ABANDONED
) {
1370 pool
->num_abandoned
--;
1371 if (pool
->ipv6_pond
)
1372 pool
->ipv6_pond
->num_abandoned
--;
1375 iasubopt_hash_delete(pool
->leases
, &test_iasubopt
->addr
,
1376 sizeof(test_iasubopt
->addr
), MDL
);
1377 ia_remove_iasubopt(old_ia
, test_iasubopt
, MDL
);
1378 if (old_ia
->num_iasubopt
<= 0) {
1379 ia_hash_delete(ia_table
,
1380 (unsigned char *)old_ia
->iaid_duid
.data
,
1381 old_ia
->iaid_duid
.len
, MDL
);
1385 * We derefenrece the subopt here as we've just removed it from
1386 * the hash table in the pool. We need to make a copy as we
1387 * need to derefernece it again later.
1389 tmp_iasubopt
= test_iasubopt
;
1390 iasubopt_dereference(&tmp_iasubopt
, MDL
);
1393 ia_dereference(&old_ia
, MDL
);
1396 * Clean up the reference, this is in addition to the deference
1397 * above after removing the entry from the hash table
1399 iasubopt_dereference(&test_iasubopt
, MDL
);
1405 * Put a lease in the pool directly. This is intended to be used when
1406 * loading leases from the file.
1409 add_lease6(struct ipv6_pool
*pool
, struct iasubopt
*lease
,
1410 time_t valid_lifetime_end_time
) {
1411 isc_result_t insert_result
;
1412 struct iasubopt
*test_iasubopt
;
1413 struct iasubopt
*tmp_iasubopt
;
1415 /* If a state was not assigned by the caller, assume active. */
1416 if (lease
->state
== 0)
1417 lease
->state
= FTS_ACTIVE
;
1419 ipv6_pool_reference(&lease
->ipv6_pool
, pool
, MDL
);
1422 * If this IAADDR/PREFIX is already in our structures, remove the
1425 test_iasubopt
= NULL
;
1426 if (iasubopt_hash_lookup(&test_iasubopt
, pool
->leases
,
1427 &lease
->addr
, sizeof(lease
->addr
), MDL
)) {
1428 /* XXX: we should probably ask the lease what heap it is on
1429 * (as a consistency check).
1430 * XXX: we should probably have one function to "put this lease
1431 * on its heap" rather than doing these if's everywhere. If
1432 * you add more states to this list, don't.
1434 if ((test_iasubopt
->state
== FTS_ACTIVE
) ||
1435 (test_iasubopt
->state
== FTS_ABANDONED
)) {
1436 isc_heap_delete(pool
->active_timeouts
,
1437 test_iasubopt
->heap_index
);
1439 if (pool
->ipv6_pond
)
1440 pool
->ipv6_pond
->num_active
--;
1442 if (test_iasubopt
->state
== FTS_ABANDONED
) {
1443 pool
->num_abandoned
--;
1444 if (pool
->ipv6_pond
)
1445 pool
->ipv6_pond
->num_abandoned
--;
1448 isc_heap_delete(pool
->inactive_timeouts
,
1449 test_iasubopt
->heap_index
);
1450 pool
->num_inactive
--;
1453 iasubopt_hash_delete(pool
->leases
, &test_iasubopt
->addr
,
1454 sizeof(test_iasubopt
->addr
), MDL
);
1457 * We're going to do a bit of evil trickery here.
1459 * We need to dereference the entry once to remove our
1460 * current reference (in test_iasubopt), and then one
1461 * more time to remove the reference left when the
1462 * address was added to the pool before.
1464 tmp_iasubopt
= test_iasubopt
;
1465 iasubopt_dereference(&test_iasubopt
, MDL
);
1466 iasubopt_dereference(&tmp_iasubopt
, MDL
);
1470 * Add IAADDR/PREFIX to our structures.
1472 tmp_iasubopt
= NULL
;
1473 iasubopt_reference(&tmp_iasubopt
, lease
, MDL
);
1474 if ((tmp_iasubopt
->state
== FTS_ACTIVE
) ||
1475 (tmp_iasubopt
->state
== FTS_ABANDONED
)) {
1476 tmp_iasubopt
->hard_lifetime_end_time
= valid_lifetime_end_time
;
1477 iasubopt_hash_add(pool
->leases
, &tmp_iasubopt
->addr
,
1478 sizeof(tmp_iasubopt
->addr
), lease
, MDL
);
1479 insert_result
= isc_heap_insert(pool
->active_timeouts
,
1481 if (insert_result
== ISC_R_SUCCESS
) {
1483 if (pool
->ipv6_pond
)
1484 pool
->ipv6_pond
->num_active
++;
1486 if (tmp_iasubopt
->state
== FTS_ABANDONED
) {
1487 pool
->num_abandoned
++;
1488 if (pool
->ipv6_pond
)
1489 pool
->ipv6_pond
->num_abandoned
++;
1494 tmp_iasubopt
->soft_lifetime_end_time
= valid_lifetime_end_time
;
1495 insert_result
= isc_heap_insert(pool
->inactive_timeouts
,
1497 if (insert_result
== ISC_R_SUCCESS
)
1498 pool
->num_inactive
++;
1500 if (insert_result
!= ISC_R_SUCCESS
) {
1501 iasubopt_hash_delete(pool
->leases
, &lease
->addr
,
1502 sizeof(lease
->addr
), MDL
);
1503 iasubopt_dereference(&tmp_iasubopt
, MDL
);
1504 return insert_result
;
1508 * Note: we intentionally leave tmp_iasubopt referenced; there
1509 * is a reference in the heap/hash, after all.
1512 return ISC_R_SUCCESS
;
1516 * Determine if an address is present in a pool or not.
1519 lease6_exists(const struct ipv6_pool
*pool
, const struct in6_addr
*addr
) {
1520 struct iasubopt
*test_iaaddr
;
1523 if (iasubopt_hash_lookup(&test_iaaddr
, pool
->leases
,
1524 (void *)addr
, sizeof(*addr
), MDL
)) {
1525 iasubopt_dereference(&test_iaaddr
, MDL
);
1534 * \brief Check if address is available to a lease
1536 * Determine if the address in the lease is available to that
1537 * lease. Either the address isn't in use or it is in use
1538 * but by that lease.
1540 * \param[in] lease = lease to check
1543 * ISC_TRUE = The lease is allowed to use that address
1544 * ISC_FALSE = The lease isn't allowed to use that address
1547 lease6_usable(struct iasubopt
*lease
) {
1548 struct iasubopt
*test_iaaddr
;
1549 isc_boolean_t status
= ISC_TRUE
;
1552 if (iasubopt_hash_lookup(&test_iaaddr
, lease
->ipv6_pool
->leases
,
1553 (void *)&lease
->addr
,
1554 sizeof(lease
->addr
), MDL
)) {
1555 if (test_iaaddr
!= lease
) {
1558 iasubopt_dereference(&test_iaaddr
, MDL
);
1565 * Put the lease on our active pool.
1568 move_lease_to_active(struct ipv6_pool
*pool
, struct iasubopt
*lease
) {
1569 isc_result_t insert_result
;
1572 old_heap_index
= lease
->heap_index
;
1573 insert_result
= isc_heap_insert(pool
->active_timeouts
, lease
);
1574 if (insert_result
== ISC_R_SUCCESS
) {
1575 iasubopt_hash_add(pool
->leases
, &lease
->addr
,
1576 sizeof(lease
->addr
), lease
, MDL
);
1577 isc_heap_delete(pool
->inactive_timeouts
, old_heap_index
);
1579 pool
->num_inactive
--;
1580 lease
->state
= FTS_ACTIVE
;
1581 if (pool
->ipv6_pond
)
1582 pool
->ipv6_pond
->num_active
++;
1585 return insert_result
;
1590 * \brief Renew a lease in the pool.
1592 * The hard_lifetime_end_time of the lease should be set to
1593 * the current expiration time.
1594 * The soft_lifetime_end_time of the lease should be set to
1595 * the desired expiration time.
1597 * This routine will compare the two and call the correct
1598 * heap routine to move the lease. If the lease is active
1599 * and the new expiration time is greater (the normal case)
1600 * then we call isc_heap_decreased() as a larger time is a
1601 * lower priority. If the new expiration time is less then
1602 * we call isc_heap_increased().
1604 * If the lease is abandoned then it will be on the active list
1605 * and we will always call isc_heap_increased() as the previous
1606 * expiration would have been all 1s (as close as we can get
1609 * If the lease is moving to active we call that routine
1610 * which will move it from the inactive list to the active list.
1612 * \param pool = a pool the lease belongs to
1613 * \param lease = the lease to be renewed
1615 * \return result of the renew operation (ISC_R_SUCCESS if successful,
1616 ISC_R_NOMEMORY when run out of memory)
1619 renew_lease6(struct ipv6_pool
*pool
, struct iasubopt
*lease
) {
1620 time_t old_end_time
= lease
->hard_lifetime_end_time
;
1621 lease
->hard_lifetime_end_time
= lease
->soft_lifetime_end_time
;
1622 lease
->soft_lifetime_end_time
= 0;
1624 if (lease
->state
== FTS_ACTIVE
) {
1625 if (old_end_time
<= lease
->hard_lifetime_end_time
) {
1626 isc_heap_decreased(pool
->active_timeouts
,
1629 isc_heap_increased(pool
->active_timeouts
,
1632 return ISC_R_SUCCESS
;
1633 } else if (lease
->state
== FTS_ABANDONED
) {
1634 char tmp_addr
[INET6_ADDRSTRLEN
];
1635 lease
->state
= FTS_ACTIVE
;
1636 isc_heap_increased(pool
->active_timeouts
, lease
->heap_index
);
1637 log_info("Reclaiming previously abandoned address %s",
1638 inet_ntop(AF_INET6
, &(lease
->addr
), tmp_addr
,
1641 pool
->num_abandoned
--;
1642 if (pool
->ipv6_pond
)
1643 pool
->ipv6_pond
->num_abandoned
--;
1645 return ISC_R_SUCCESS
;
1647 return move_lease_to_active(pool
, lease
);
1652 * Put the lease on our inactive pool, with the specified state.
1655 move_lease_to_inactive(struct ipv6_pool
*pool
, struct iasubopt
*lease
,
1656 binding_state_t state
) {
1657 isc_result_t insert_result
;
1660 old_heap_index
= lease
->heap_index
;
1661 insert_result
= isc_heap_insert(pool
->inactive_timeouts
, lease
);
1662 if (insert_result
== ISC_R_SUCCESS
) {
1664 * Handle expire and release statements
1665 * To get here we must be active and have done a commit so
1666 * we should run the proper statements if they exist, though
1667 * that will change when we remove the inactive heap.
1668 * In addition we get rid of the references for both as we
1669 * can only do one (expire or release) on a lease
1671 if (lease
->on_star
.on_expiry
!= NULL
) {
1672 if (state
== FTS_EXPIRED
) {
1673 execute_statements(NULL
, NULL
, NULL
,
1676 lease
->on_star
.on_expiry
,
1679 executable_statement_dereference
1680 (&lease
->on_star
.on_expiry
, MDL
);
1683 if (lease
->on_star
.on_release
!= NULL
) {
1684 if (state
== FTS_RELEASED
) {
1685 execute_statements(NULL
, NULL
, NULL
,
1688 lease
->on_star
.on_release
,
1691 executable_statement_dereference
1692 (&lease
->on_star
.on_release
, MDL
);
1695 #if defined (NSUPDATE)
1696 /* Process events upon expiration. */
1697 if (pool
->pool_type
!= D6O_IA_PD
) {
1698 (void) ddns_removals(NULL
, lease
, NULL
, ISC_FALSE
);
1702 /* Binding scopes are no longer valid after expiry or
1705 if (lease
->scope
!= NULL
) {
1706 binding_scope_dereference(&lease
->scope
, MDL
);
1709 iasubopt_hash_delete(pool
->leases
,
1710 &lease
->addr
, sizeof(lease
->addr
), MDL
);
1711 isc_heap_delete(pool
->active_timeouts
, old_heap_index
);
1712 lease
->state
= state
;
1714 pool
->num_inactive
++;
1715 if (pool
->ipv6_pond
)
1716 pool
->ipv6_pond
->num_active
--;
1718 if (lease
->state
== FTS_ABANDONED
) {
1719 pool
->num_abandoned
--;
1720 if (pool
->ipv6_pond
)
1721 pool
->ipv6_pond
->num_abandoned
--;
1724 return insert_result
;
1728 * Expire the oldest lease if it's lifetime_end_time is
1729 * older than the given time.
1731 * - leasep must be a pointer to a (struct iasubopt *) pointer previously
1732 * initialized to NULL
1734 * On return leasep has a reference to the removed entry. It is left
1735 * pointing to NULL if the oldest lease has not expired.
1738 expire_lease6(struct iasubopt
**leasep
, struct ipv6_pool
*pool
, time_t now
) {
1739 struct iasubopt
*tmp
;
1740 isc_result_t result
;
1742 if (leasep
== NULL
) {
1743 log_error("%s(%d): NULL pointer reference", MDL
);
1744 return DHCP_R_INVALIDARG
;
1746 if (*leasep
!= NULL
) {
1747 log_error("%s(%d): non-NULL pointer", MDL
);
1748 return DHCP_R_INVALIDARG
;
1751 if (pool
->num_active
> 0) {
1752 tmp
= (struct iasubopt
*)
1753 isc_heap_element(pool
->active_timeouts
, 1);
1754 if (now
> tmp
->hard_lifetime_end_time
) {
1755 result
= move_lease_to_inactive(pool
, tmp
,
1757 if (result
== ISC_R_SUCCESS
) {
1758 iasubopt_reference(leasep
, tmp
, MDL
);
1763 return ISC_R_SUCCESS
;
1768 * For a declined lease, leave it on the "active" pool, but mark
1769 * it as declined. Give it an infinite (well, really long) life.
1772 decline_lease6(struct ipv6_pool
*pool
, struct iasubopt
*lease
) {
1773 isc_result_t result
;
1775 if ((lease
->state
!= FTS_ACTIVE
) &&
1776 (lease
->state
!= FTS_ABANDONED
)) {
1777 result
= move_lease_to_active(pool
, lease
);
1778 if (result
!= ISC_R_SUCCESS
) {
1782 lease
->state
= FTS_ABANDONED
;
1784 pool
->num_abandoned
++;
1785 if (pool
->ipv6_pond
)
1786 pool
->ipv6_pond
->num_abandoned
++;
1788 lease
->hard_lifetime_end_time
= MAX_TIME
;
1789 isc_heap_decreased(pool
->active_timeouts
, lease
->heap_index
);
1790 return ISC_R_SUCCESS
;
1794 * Put the returned lease on our inactive pool.
1797 release_lease6(struct ipv6_pool
*pool
, struct iasubopt
*lease
) {
1798 if (lease
->state
== FTS_ACTIVE
) {
1799 return move_lease_to_inactive(pool
, lease
, FTS_RELEASED
);
1801 return ISC_R_SUCCESS
;
1806 * Create a prefix by hashing the input, and using that for
1807 * the part subject to allocation.
1810 build_prefix6(struct in6_addr
*pref
,
1811 const struct in6_addr
*net_start_pref
,
1812 int pool_bits
, int pref_bits
,
1813 const struct data_string
*input
) {
1818 const char *net_str
;
1821 * Use MD5 to get a nice 128 bit hash of the input.
1822 * Yes, we know MD5 isn't cryptographically sound.
1823 * No, we don't care.
1826 isc_md5_update(&ctx
, input
->data
, input
->len
);
1827 isc_md5_final(&ctx
, (unsigned char *)pref
);
1830 * Copy the network bits over.
1833 net_str
= (const char *)net_start_pref
;
1834 net_bytes
= pool_bits
/ 8;
1835 for (i
= 0; i
< net_bytes
; i
++) {
1836 str
[i
] = net_str
[i
];
1839 switch (pool_bits
% 8) {
1840 case 1: str
[i
] = (str
[i
] & 0x7F) | (net_str
[i
] & 0x80); break;
1841 case 2: str
[i
] = (str
[i
] & 0x3F) | (net_str
[i
] & 0xC0); break;
1842 case 3: str
[i
] = (str
[i
] & 0x1F) | (net_str
[i
] & 0xE0); break;
1843 case 4: str
[i
] = (str
[i
] & 0x0F) | (net_str
[i
] & 0xF0); break;
1844 case 5: str
[i
] = (str
[i
] & 0x07) | (net_str
[i
] & 0xF8); break;
1845 case 6: str
[i
] = (str
[i
] & 0x03) | (net_str
[i
] & 0xFC); break;
1846 case 7: str
[i
] = (str
[i
] & 0x01) | (net_str
[i
] & 0xFE); break;
1849 * Zero the remaining bits.
1851 net_bytes
= pref_bits
/ 8;
1852 for (i
=net_bytes
+1; i
<16; i
++) {
1856 switch (pref_bits
% 8) {
1857 case 0: str
[i
] &= 0; break;
1858 case 1: str
[i
] &= 0x80; break;
1859 case 2: str
[i
] &= 0xC0; break;
1860 case 3: str
[i
] &= 0xE0; break;
1861 case 4: str
[i
] &= 0xF0; break;
1862 case 5: str
[i
] &= 0xF8; break;
1863 case 6: str
[i
] &= 0xFC; break;
1864 case 7: str
[i
] &= 0xFE; break;
1869 * Create a lease for the given prefix and client duid.
1871 * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
1872 * initialized to NULL
1874 * Right now we simply hash the DUID, and if we get a collision, we hash
1875 * again until we find a free prefix. We try this a fixed number of times,
1876 * to avoid getting stuck in a loop (this is important on small pools
1877 * where we can run out of space).
1879 * We return the number of attempts that it took to find an available
1880 * prefix. This tells callers when a pool is are filling up, as
1881 * well as an indication of how full the pool is; statistically the
1882 * more full a pool is the more attempts must be made before finding
1883 * a free prefix. Realistically this will only happen in very full
1886 * We probably want different algorithms depending on the network size, in
1890 create_prefix6(struct ipv6_pool
*pool
, struct iasubopt
**pref
,
1891 unsigned int *attempts
,
1892 const struct data_string
*uid
,
1893 time_t soft_lifetime_end_time
) {
1894 struct data_string ds
;
1895 struct in6_addr tmp
;
1896 struct iasubopt
*test_iapref
;
1897 struct data_string new_ds
;
1898 struct iasubopt
*iapref
;
1899 isc_result_t result
;
1902 * Use the UID as our initial seed for the hash
1904 memset(&ds
, 0, sizeof(ds
));
1905 data_string_copy(&ds
, (struct data_string
*)uid
, MDL
);
1910 * Give up at some point.
1912 if (++(*attempts
) > 10) {
1913 data_string_forget(&ds
, MDL
);
1914 return ISC_R_NORESOURCES
;
1920 build_prefix6(&tmp
, &pool
->start_addr
,
1921 pool
->bits
, pool
->units
, &ds
);
1924 * If this prefix is not in use, we're happy with it
1927 if (iasubopt_hash_lookup(&test_iapref
, pool
->leases
,
1928 &tmp
, sizeof(tmp
), MDL
) == 0) {
1931 iasubopt_dereference(&test_iapref
, MDL
);
1934 * Otherwise, we create a new input, adding the prefix
1936 memset(&new_ds
, 0, sizeof(new_ds
));
1937 new_ds
.len
= ds
.len
+ sizeof(tmp
);
1938 if (!buffer_allocate(&new_ds
.buffer
, new_ds
.len
, MDL
)) {
1939 data_string_forget(&ds
, MDL
);
1940 return ISC_R_NOMEMORY
;
1942 new_ds
.data
= new_ds
.buffer
->data
;
1943 memcpy(new_ds
.buffer
->data
, ds
.data
, ds
.len
);
1944 memcpy(new_ds
.buffer
->data
+ ds
.len
, &tmp
, sizeof(tmp
));
1945 data_string_forget(&ds
, MDL
);
1946 data_string_copy(&ds
, &new_ds
, MDL
);
1947 data_string_forget(&new_ds
, MDL
);
1950 data_string_forget(&ds
, MDL
);
1953 * We're happy with the prefix, create an IAPREFIX
1957 result
= iasubopt_allocate(&iapref
, MDL
);
1958 if (result
!= ISC_R_SUCCESS
) {
1961 iapref
->plen
= (u_int8_t
)pool
->units
;
1962 memcpy(&iapref
->addr
, &tmp
, sizeof(iapref
->addr
));
1965 * Add the prefix to the pool (note state is free, not active?!).
1967 result
= add_lease6(pool
, iapref
, soft_lifetime_end_time
);
1968 if (result
== ISC_R_SUCCESS
) {
1969 iasubopt_reference(pref
, iapref
, MDL
);
1971 iasubopt_dereference(&iapref
, MDL
);
1976 * Determine if a prefix is present in a pool or not.
1979 prefix6_exists(const struct ipv6_pool
*pool
,
1980 const struct in6_addr
*pref
, u_int8_t plen
) {
1981 struct iasubopt
*test_iapref
;
1983 if ((int)plen
!= pool
->units
)
1987 if (iasubopt_hash_lookup(&test_iapref
, pool
->leases
,
1988 (void *)pref
, sizeof(*pref
), MDL
)) {
1989 iasubopt_dereference(&test_iapref
, MDL
);
1997 * Mark an IPv6 address/prefix as unavailable from a pool.
1999 * This is used for host entries and the addresses of the server itself.
2002 mark_lease_unavailable(struct ipv6_pool
*pool
, const struct in6_addr
*addr
) {
2003 struct iasubopt
*dummy_iasubopt
;
2004 isc_result_t result
;
2006 dummy_iasubopt
= NULL
;
2007 result
= iasubopt_allocate(&dummy_iasubopt
, MDL
);
2008 if (result
== ISC_R_SUCCESS
) {
2009 dummy_iasubopt
->addr
= *addr
;
2010 iasubopt_hash_add(pool
->leases
, &dummy_iasubopt
->addr
,
2011 sizeof(*addr
), dummy_iasubopt
, MDL
);
2020 add_ipv6_pool(struct ipv6_pool
*pool
) {
2021 struct ipv6_pool
**new_pools
;
2023 new_pools
= dmalloc(sizeof(struct ipv6_pool
*) * (num_pools
+1), MDL
);
2024 if (new_pools
== NULL
) {
2025 return ISC_R_NOMEMORY
;
2028 if (num_pools
> 0) {
2029 memcpy(new_pools
, pools
,
2030 sizeof(struct ipv6_pool
*) * num_pools
);
2035 pools
[num_pools
] = NULL
;
2036 ipv6_pool_reference(&pools
[num_pools
], pool
, MDL
);
2038 return ISC_R_SUCCESS
;
2042 cleanup_old_expired(struct ipv6_pool
*pool
) {
2043 struct iasubopt
*tmp
;
2045 struct ia_xx
*ia_active
;
2046 unsigned char *tmpd
;
2049 while (pool
->num_inactive
> 0) {
2050 tmp
= (struct iasubopt
*)
2051 isc_heap_element(pool
->inactive_timeouts
, 1);
2052 if (tmp
->hard_lifetime_end_time
!= 0) {
2053 timeout
= tmp
->hard_lifetime_end_time
;
2054 timeout
+= EXPIRED_IPV6_CLEANUP_TIME
;
2056 timeout
= tmp
->soft_lifetime_end_time
;
2058 if (cur_time
< timeout
) {
2062 isc_heap_delete(pool
->inactive_timeouts
, tmp
->heap_index
);
2063 pool
->num_inactive
--;
2065 if (tmp
->ia
!= NULL
) {
2067 * Check to see if this IA is in an active list,
2068 * but has no remaining resources. If so, remove it
2069 * from the active list.
2072 ia_reference(&ia
, tmp
->ia
, MDL
);
2073 ia_remove_iasubopt(ia
, tmp
, MDL
);
2075 tmpd
= (unsigned char *)ia
->iaid_duid
.data
;
2076 if ((ia
->ia_type
== D6O_IA_NA
) &&
2077 (ia
->num_iasubopt
<= 0) &&
2078 (ia_hash_lookup(&ia_active
, ia_na_active
, tmpd
,
2079 ia
->iaid_duid
.len
, MDL
) == 0) &&
2080 (ia_active
== ia
)) {
2081 ia_hash_delete(ia_na_active
, tmpd
,
2082 ia
->iaid_duid
.len
, MDL
);
2084 if ((ia
->ia_type
== D6O_IA_TA
) &&
2085 (ia
->num_iasubopt
<= 0) &&
2086 (ia_hash_lookup(&ia_active
, ia_ta_active
, tmpd
,
2087 ia
->iaid_duid
.len
, MDL
) == 0) &&
2088 (ia_active
== ia
)) {
2089 ia_hash_delete(ia_ta_active
, tmpd
,
2090 ia
->iaid_duid
.len
, MDL
);
2092 if ((ia
->ia_type
== D6O_IA_PD
) &&
2093 (ia
->num_iasubopt
<= 0) &&
2094 (ia_hash_lookup(&ia_active
, ia_pd_active
, tmpd
,
2095 ia
->iaid_duid
.len
, MDL
) == 0) &&
2096 (ia_active
== ia
)) {
2097 ia_hash_delete(ia_pd_active
, tmpd
,
2098 ia
->iaid_duid
.len
, MDL
);
2100 ia_dereference(&ia
, MDL
);
2102 iasubopt_dereference(&tmp
, MDL
);
2107 lease_timeout_support(void *vpool
) {
2108 struct ipv6_pool
*pool
;
2109 struct iasubopt
*lease
;
2111 pool
= (struct ipv6_pool
*)vpool
;
2114 * Get the next lease scheduled to expire.
2116 * Note that if there are no leases in the pool,
2117 * expire_lease6() will return ISC_R_SUCCESS with
2120 * expire_lease6() will call move_lease_to_inactive() which
2121 * calls ddns_removals() do we want that on the standard
2122 * expiration timer or a special 'depref' timer? Original
2123 * query from DH, moved here by SAR.
2126 if (expire_lease6(&lease
, pool
, cur_time
) != ISC_R_SUCCESS
) {
2129 if (lease
== NULL
) {
2133 write_ia(lease
->ia
);
2135 iasubopt_dereference(&lease
, MDL
);
2139 * If appropriate commit and rotate the lease file
2140 * As commit_leases_timed() checks to see if we've done any writes
2141 * we don't bother tracking if this function called write _ia
2143 (void) commit_leases_timed();
2146 * Do some cleanup of our expired leases.
2148 cleanup_old_expired(pool
);
2151 * Schedule next round of expirations.
2153 schedule_lease_timeout(pool
);
2157 * For a given pool, add a timer that will remove the next
2161 schedule_lease_timeout(struct ipv6_pool
*pool
) {
2162 struct iasubopt
*tmp
;
2164 time_t next_timeout
;
2167 next_timeout
= MAX_TIME
;
2169 if (pool
->num_active
> 0) {
2170 tmp
= (struct iasubopt
*)
2171 isc_heap_element(pool
->active_timeouts
, 1);
2172 if (tmp
->hard_lifetime_end_time
< next_timeout
) {
2173 next_timeout
= tmp
->hard_lifetime_end_time
+ 1;
2177 if (pool
->num_inactive
> 0) {
2178 tmp
= (struct iasubopt
*)
2179 isc_heap_element(pool
->inactive_timeouts
, 1);
2180 if (tmp
->hard_lifetime_end_time
!= 0) {
2181 timeout
= tmp
->hard_lifetime_end_time
;
2182 timeout
+= EXPIRED_IPV6_CLEANUP_TIME
;
2184 timeout
= tmp
->soft_lifetime_end_time
+ 1;
2186 if (timeout
< next_timeout
) {
2187 next_timeout
= timeout
;
2191 if (next_timeout
< MAX_TIME
) {
2192 tv
.tv_sec
= next_timeout
;
2194 add_timeout(&tv
, lease_timeout_support
, pool
,
2195 (tvref_t
)ipv6_pool_reference
,
2196 (tvunref_t
)ipv6_pool_dereference
);
2201 * Schedule timeouts across all pools.
2204 schedule_all_ipv6_lease_timeouts(void) {
2207 for (i
=0; i
<num_pools
; i
++) {
2208 schedule_lease_timeout(pools
[i
]);
2213 * Given an address and the length of the network mask, return
2214 * only the network portion.
2218 * "fe80::216:6fff:fe49:7d9b", length 64 = "fe80::"
2219 * "2001:888:1936:2:216:6fff:fe49:7d9b", length 48 = "2001:888:1936::"
2222 ipv6_network_portion(struct in6_addr
*result
,
2223 const struct in6_addr
*addr
, int bits
) {
2224 unsigned char *addrp
;
2230 static const unsigned char bitmasks
[] = {
2231 0x00, 0xFE, 0xFC, 0xF8,
2232 0xF0, 0xE0, 0xC0, 0x80,
2236 * Sanity check our bits. ;)
2238 if ((bits
< 0) || (bits
> 128)) {
2239 log_fatal("ipv6_network_portion: bits %d not between 0 and 128",
2244 * Copy our address portion.
2247 addrp
= ((unsigned char *)result
) + 15;
2250 * Zero out masked portion.
2252 mask_bits
= 128 - bits
;
2253 bytes
= mask_bits
/ 8;
2254 extra_bits
= mask_bits
% 8;
2256 for (i
=0; i
<bytes
; i
++) {
2261 *addrp
&= bitmasks
[extra_bits
];
2266 * Determine if the given address/prefix is in the pool.
2269 ipv6_in_pool(const struct in6_addr
*addr
, const struct ipv6_pool
*pool
) {
2270 struct in6_addr tmp
;
2272 ipv6_network_portion(&tmp
, addr
, pool
->bits
);
2273 if (memcmp(&tmp
, &pool
->start_addr
, sizeof(tmp
)) == 0) {
2281 * Find the pool that contains the given address.
2283 * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
2284 * initialized to NULL
2287 find_ipv6_pool(struct ipv6_pool
**pool
, u_int16_t type
,
2288 const struct in6_addr
*addr
) {
2292 log_error("%s(%d): NULL pointer reference", MDL
);
2293 return DHCP_R_INVALIDARG
;
2295 if (*pool
!= NULL
) {
2296 log_error("%s(%d): non-NULL pointer", MDL
);
2297 return DHCP_R_INVALIDARG
;
2300 for (i
=0; i
<num_pools
; i
++) {
2301 if (pools
[i
]->pool_type
!= type
)
2303 if (ipv6_in_pool(addr
, pools
[i
])) {
2304 ipv6_pool_reference(pool
, pools
[i
], MDL
);
2305 return ISC_R_SUCCESS
;
2308 return ISC_R_NOTFOUND
;
2312 * Helper function for the various functions that act across all
2316 change_leases(struct ia_xx
*ia
,
2317 isc_result_t (*change_func
)(struct ipv6_pool
*,
2318 struct iasubopt
*)) {
2319 isc_result_t retval
;
2320 isc_result_t renew_retval
;
2321 struct ipv6_pool
*pool
;
2322 struct in6_addr
*addr
;
2325 retval
= ISC_R_SUCCESS
;
2326 for (i
=0; i
<ia
->num_iasubopt
; i
++) {
2328 addr
= &ia
->iasubopt
[i
]->addr
;
2329 if (find_ipv6_pool(&pool
, ia
->ia_type
,
2330 addr
) == ISC_R_SUCCESS
) {
2331 renew_retval
= change_func(pool
, ia
->iasubopt
[i
]);
2332 if (renew_retval
!= ISC_R_SUCCESS
) {
2333 retval
= renew_retval
;
2336 /* XXXsk: should we warn if we don't find a pool? */
2342 * Renew all leases in an IA from all pools.
2344 * The new lifetime should be in the soft_lifetime_end_time
2345 * and will be moved to hard_lifetime_end_time by renew_lease6.
2348 renew_leases(struct ia_xx
*ia
) {
2349 return change_leases(ia
, renew_lease6
);
2353 * Release all leases in an IA from all pools.
2356 release_leases(struct ia_xx
*ia
) {
2357 return change_leases(ia
, release_lease6
);
2361 * Decline all leases in an IA from all pools.
2364 decline_leases(struct ia_xx
*ia
) {
2365 return change_leases(ia
, decline_lease6
);
2370 * Helper function to output leases.
2372 static int write_error
;
2375 write_ia_leases(const void *name
, unsigned len
, void *value
) {
2376 struct ia_xx
*ia
= (struct ia_xx
*)value
;
2379 if (!write_ia(ia
)) {
2383 return ISC_R_SUCCESS
;
2387 * Write all DHCPv6 information.
2390 write_leases6(void) {
2394 write_server_duid();
2395 nas
= ia_hash_foreach(ia_na_active
, write_ia_leases
);
2399 tas
= ia_hash_foreach(ia_ta_active
, write_ia_leases
);
2403 pds
= ia_hash_foreach(ia_pd_active
, write_ia_leases
);
2408 log_info("Wrote %d NA, %d TA, %d PD leases to lease file.",
2415 mark_hosts_unavailable_support(const void *name
, unsigned len
, void *value
) {
2416 struct host_decl
*h
;
2417 struct data_string fixed_addr
;
2418 struct in6_addr addr
;
2419 struct ipv6_pool
*p
;
2421 h
= (struct host_decl
*)value
;
2424 * If the host has no address, we don't need to mark anything.
2426 if (h
->fixed_addr
== NULL
) {
2427 return ISC_R_SUCCESS
;
2431 * Evaluate the fixed address.
2433 memset(&fixed_addr
, 0, sizeof(fixed_addr
));
2434 if (!evaluate_option_cache(&fixed_addr
, NULL
, NULL
, NULL
, NULL
, NULL
,
2435 &global_scope
, h
->fixed_addr
, MDL
)) {
2436 log_error("mark_hosts_unavailable: "
2437 "error evaluating host address.");
2438 return ISC_R_SUCCESS
;
2440 if (fixed_addr
.len
!= 16) {
2441 log_error("mark_hosts_unavailable: "
2442 "host address is not 128 bits.");
2443 return ISC_R_SUCCESS
;
2445 memcpy(&addr
, fixed_addr
.data
, 16);
2446 data_string_forget(&fixed_addr
, MDL
);
2449 * Find the pool holding this host, and mark the address.
2450 * (I suppose it is arguably valid to have a host that does not
2454 if (find_ipv6_pool(&p
, D6O_IA_NA
, &addr
) == ISC_R_SUCCESS
) {
2455 mark_lease_unavailable(p
, &addr
);
2456 ipv6_pool_dereference(&p
, MDL
);
2458 if (find_ipv6_pool(&p
, D6O_IA_TA
, &addr
) == ISC_R_SUCCESS
) {
2459 mark_lease_unavailable(p
, &addr
);
2460 ipv6_pool_dereference(&p
, MDL
);
2463 return ISC_R_SUCCESS
;
2467 mark_hosts_unavailable(void) {
2468 hash_foreach(host_name_hash
, mark_hosts_unavailable_support
);
2472 mark_phosts_unavailable_support(const void *name
, unsigned len
, void *value
) {
2473 struct host_decl
*h
;
2474 struct iaddrcidrnetlist
*l
;
2475 struct in6_addr pref
;
2476 struct ipv6_pool
*p
;
2478 h
= (struct host_decl
*)value
;
2481 * If the host has no prefix, we don't need to mark anything.
2483 if (h
->fixed_prefix
== NULL
) {
2484 return ISC_R_SUCCESS
;
2488 * Get the fixed prefixes.
2490 for (l
= h
->fixed_prefix
; l
!= NULL
; l
= l
->next
) {
2491 if (l
->cidrnet
.lo_addr
.len
!= 16) {
2494 memcpy(&pref
, l
->cidrnet
.lo_addr
.iabuf
, 16);
2497 * Find the pool holding this host, and mark the prefix.
2498 * (I suppose it is arguably valid to have a host that does not
2502 if (find_ipv6_pool(&p
, D6O_IA_PD
, &pref
) != ISC_R_SUCCESS
) {
2505 if (l
->cidrnet
.bits
!= p
->units
) {
2506 ipv6_pool_dereference(&p
, MDL
);
2509 mark_lease_unavailable(p
, &pref
);
2510 ipv6_pool_dereference(&p
, MDL
);
2513 return ISC_R_SUCCESS
;
2517 mark_phosts_unavailable(void) {
2518 hash_foreach(host_name_hash
, mark_phosts_unavailable_support
);
2522 mark_interfaces_unavailable(void) {
2523 struct interface_info
*ip
;
2525 struct ipv6_pool
*p
;
2528 while (ip
!= NULL
) {
2529 for (i
=0; i
<ip
->v6address_count
; i
++) {
2531 if (find_ipv6_pool(&p
, D6O_IA_NA
, &ip
->v6addresses
[i
])
2533 mark_lease_unavailable(p
,
2534 &ip
->v6addresses
[i
]);
2535 ipv6_pool_dereference(&p
, MDL
);
2537 if (find_ipv6_pool(&p
, D6O_IA_TA
, &ip
->v6addresses
[i
])
2539 mark_lease_unavailable(p
,
2540 &ip
->v6addresses
[i
]);
2541 ipv6_pool_dereference(&p
, MDL
);
2549 * \brief Create a new IPv6 pond structure.
2551 * Allocate space for a new ipv6_pond structure and return a reference
2552 * to it, includes setting the reference count to 1.
2554 * \param pond = space for returning a referenced pointer to the pond.
2555 * This must point to a space that has been initialzied
2556 * to NULL by the caller.
2559 * ISC_R_SUCCESS = The pond was successfully created, pond points to it.
2560 * DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been
2562 * ISC_R_NOMEMORY = The system wasn't able to allocate memory, pond has
2563 * not been modified.
2566 ipv6_pond_allocate(struct ipv6_pond
**pond
, const char *file
, int line
) {
2567 struct ipv6_pond
*tmp
;
2570 log_error("%s(%d): NULL pointer reference", file
, line
);
2571 return DHCP_R_INVALIDARG
;
2573 if (*pond
!= NULL
) {
2574 log_error("%s(%d): non-NULL pointer", file
, line
);
2575 return DHCP_R_INVALIDARG
;
2578 tmp
= dmalloc(sizeof(*tmp
), file
, line
);
2580 return ISC_R_NOMEMORY
;
2586 return ISC_R_SUCCESS
;
2591 * \brief reference an IPv6 pond structure.
2593 * This function genreates a reference to an ipv6_pond structure
2594 * and increments the reference count on the structure.
2596 * \param[out] pond = space for returning a referenced pointer to the pond.
2597 * This must point to a space that has been initialzied
2598 * to NULL by the caller.
2599 * \param[in] src = A pointer to the pond to reference. This must not be
2603 * ISC_R_SUCCESS = The pond was successfully referenced, pond now points
2605 * DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been
2609 ipv6_pond_reference(struct ipv6_pond
**pond
, struct ipv6_pond
*src
,
2610 const char *file
, int line
) {
2612 log_error("%s(%d): NULL pointer reference", file
, line
);
2613 return DHCP_R_INVALIDARG
;
2615 if (*pond
!= NULL
) {
2616 log_error("%s(%d): non-NULL pointer", file
, line
);
2617 return DHCP_R_INVALIDARG
;
2620 log_error("%s(%d): NULL pointer reference", file
, line
);
2621 return DHCP_R_INVALIDARG
;
2625 return ISC_R_SUCCESS
;
2630 * \brief de-reference an IPv6 pond structure.
2632 * This function decrements the reference count in an ipv6_pond structure.
2633 * If this was the last reference then the memory for the structure is
2636 * \param[in] pond = A pointer to the pointer to the pond that should be
2637 * de-referenced. On success the pointer to the pond
2638 * is cleared. It must not be NULL and must not point
2642 * ISC_R_SUCCESS = The pond was successfully de-referenced, pond now points
2644 * DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been
2649 ipv6_pond_dereference(struct ipv6_pond
**pond
, const char *file
, int line
) {
2650 struct ipv6_pond
*tmp
;
2652 if ((pond
== NULL
) || (*pond
== NULL
)) {
2653 log_error("%s(%d): NULL pointer", file
, line
);
2654 return DHCP_R_INVALIDARG
;
2661 if (tmp
->refcnt
< 0) {
2662 log_error("%s(%d): negative refcnt", file
, line
);
2665 if (tmp
->refcnt
== 0) {
2666 dfree(tmp
, file
, line
);
2669 return ISC_R_SUCCESS
;
2674 * Enables/disables EUI-64 address assignment for a pond
2676 * Excecutes statements down to the pond's scope and sets the pond's
2677 * use_eui_64 flag accordingly. In addition it iterates over the
2678 * pond's pools ensuring they are all /64. Anything else is deemed
2679 * invalid for EUI-64. It returns the number of invalid pools
2680 * detected. This is done post-parsing as use-eui-64 can be set
2681 * down to the pool scope and we can't reliably do it until the
2682 * entire configuration has been parsed.
2685 set_eui_64(struct ipv6_pond
*pond
) {
2686 int invalid_cnt
= 0;
2687 struct option_state
* options
= NULL
;
2688 struct option_cache
*oc
= NULL
;
2689 option_state_allocate(&options
, MDL
);
2690 execute_statements_in_scope(NULL
, NULL
, NULL
, NULL
, NULL
, options
,
2691 &global_scope
, pond
->group
, NULL
, NULL
);
2694 ((oc
= lookup_option(&server_universe
, options
, SV_USE_EUI_64
))
2696 (evaluate_boolean_option_cache (NULL
, NULL
, NULL
, NULL
,
2697 options
, NULL
, &global_scope
,
2699 if (pond
->use_eui_64
) {
2700 // Check all pools are valid
2702 struct ipv6_pool
* p
;
2703 while((p
= pond
->ipv6_pools
[i
++]) != NULL
) {
2704 if (p
->bits
!= 64) {
2705 log_error("Pool %s/%d cannot use EUI-64,"
2707 pin6_addr(&p
->start_addr
), p
->bits
);
2710 log_debug("Pool: %s/%d - will use EUI-64",
2711 pin6_addr(&p
->start_addr
), p
->bits
);
2716 /* Don't need the options anymore. */
2717 option_state_dereference(&options
, MDL
);
2718 return (invalid_cnt
);
2723 * Emits a log for each pond that has been flagged as being a "jumbo range"
2724 * A pond is considered a "jumbo range" when the total number of elements
2725 * exceeds the maximum value of POND_TRACK_MAX (currently maximum value
2726 * that can be stored by ipv6_pond.num_total). Since we disable threshold
2727 * logging for jumbo ranges, we need to report this to the user. This
2728 * function allows us to report jumbo ponds after config parsing, so the
2729 * logs can be seen both on the console (-T) and the log facility (i.e syslog).
2731 * Note, threshold logging is done at the pond level, so we need emit a list
2732 * of the addresses ranges of the pools in the pond affected.
2735 report_jumbo_ranges() {
2736 struct shared_network
* s
;
2739 int invalid_cnt
= 0;
2742 /* Loop thru all the networks looking for jumbo range ponds */
2743 for (s
= shared_networks
; s
; s
= s
-> next
) {
2744 struct ipv6_pond
* pond
= s
->ipv6_pond
;
2747 /* while we're here, set the pond's use_eui_64 flag */
2748 invalid_cnt
+= set_eui_64(pond
);
2750 /* if its a jumbo and has pools(sanity check) */
2751 if (pond
->jumbo_range
== 1 && (pond
->ipv6_pools
)) {
2752 struct ipv6_pool
* pool
;
2753 char *bufptr
= log_buf
;
2754 size_t space_left
= sizeof(log_buf
) - 1;
2758 /* Build list containing the start-address/CIDR
2761 while ((pool
= pond
->ipv6_pools
[i
++]) &&
2762 (space_left
> (INET6_ADDRSTRLEN
+ 6))) {
2763 /* more than one so add a comma */
2771 /* add the address */
2772 inet_ntop(AF_INET6
, &pool
->start_addr
,
2773 bufptr
, INET6_ADDRSTRLEN
);
2775 used
= strlen(bufptr
);
2780 sprintf (bufptr
, "/%d",pool
->bits
);
2781 used
= strlen(bufptr
);
2787 log_info("Threshold logging disabled for shared"
2788 " subnet of ranges: %s", log_buf
);
2797 log_fatal ("%d pool(s) are invalid for EUI-64 use",
2805 * \brief Tests that 16-bit hardware type is less than 256
2807 * XXX: DHCPv6 gives a 16-bit field for the htype. DHCPv4 gives an
2808 * 8-bit field. To change the semantics of the generic 'hardware'
2809 * structure, we would have to adjust many DHCPv4 sources (from
2810 * interface to DHCPv4 lease code), and we would have to update the
2811 * 'hardware' config directive (probably being reverse compatible and
2812 * providing a new upgrade/replacement primitive). This is a little
2813 * too much to change for now. Hopefully we will revisit this before
2814 * hardware types exceeding 8 bits are assigned.
2816 * Uses a static variable to limit log occurence to once per startup
2818 * \param htype hardware type value to test
2820 * \return returns 0 if the value is too large
2823 int htype_bounds_check(uint16_t htype
) {
2824 static int log_once
= 0;
2826 if (htype
& 0xFF00) {
2828 log_error("Attention: At least one client advertises a "
2829 "hardware type of %d, which exceeds the software "
2830 "limitation of 255.", htype
);
2841 * \brief Look for hosts by MAC address if it's available
2843 * Checks the inbound packet against host declarations which specified:
2845 * "hardware ethernet <MAC>;"
2847 * For directly connected clients, the function will use the MAC address
2848 * contained in packet:haddr if it's populated. \TODO - While the logic is in
2849 * place for this search, the socket layer does not yet populate packet:haddr,
2850 * this is to be done under rt41523.
2852 * For relayed clients, the function will use the MAC address from the
2853 * client-linklayer-address option if it has been supplied by the relay
2854 * directly connected to the client.
2856 * \param hp[out] - pointer to storage for the host delcaration if found
2857 * \param packet - received packet
2858 * \param opt_state - option state to search
2859 * \param file - source file
2860 * \param line - line number
2862 * \return non-zero if a matching host was found, zero otherwise
2864 int find_hosts_by_haddr6(struct host_decl
**hp
,
2865 struct packet
*packet
,
2866 struct option_state
*opt_state
,
2867 const char *file
, int line
) {
2872 /* For directly connected clients, use packet:haddr if populated */
2873 if (packet
->dhcpv6_container_packet
== NULL
) {
2874 if (packet
->haddr
) {
2875 htype
= packet
->haddr
->hbuf
[0];
2876 hlen
= packet
->haddr
->hlen
- 1,
2877 log_debug("find_hosts_by_haddr6: using packet->haddr,"
2878 " type: %d, len: %d", htype
, hlen
);
2879 found
= find_hosts_by_haddr (hp
, htype
,
2880 &packet
->haddr
->hbuf
[1],
2884 /* The first container packet is the from the relay directly
2885 * connected to the client. Per RFC 6939, that is only relay
2886 * that may supply the client linklayer address option. */
2887 struct packet
*relay_packet
= packet
->dhcpv6_container_packet
;
2888 struct option_state
*relay_state
= relay_packet
->options
;
2889 struct data_string rel_addr
;
2890 struct option_cache
*oc
;
2892 /* Look for the option in the first relay packet */
2893 oc
= lookup_option(&dhcpv6_universe
, relay_state
,
2894 D6O_CLIENT_LINKLAYER_ADDR
);
2896 /* Not there, so bail */
2900 /* The option is present, fetch the address data */
2901 memset(&rel_addr
, 0, sizeof(rel_addr
));
2902 if (!evaluate_option_cache(&rel_addr
, relay_packet
, NULL
, NULL
,
2903 relay_state
, NULL
, &global_scope
,
2905 log_error("find_hosts_by_add6:"
2906 "Error evaluating option cache");
2910 /* The relay address data should be:
2911 * byte 0 - 1 = hardware type
2912 * bytes 2 - hlen = hardware address
2913 * where hlen ( hardware address len) is option data len - 2 */
2914 hlen
= rel_addr
.len
- 2;
2915 if (hlen
> 0 && hlen
<= HARDWARE_ADDR_LEN
) {
2916 htype
= getUShort(rel_addr
.data
);
2917 if (htype_bounds_check(htype
)) {
2918 /* Looks valid, let's search with it */
2919 log_debug("find_hosts_by_haddr6:"
2920 "using relayed haddr"
2921 " type: %d, len: %d", htype
, hlen
);
2922 found
= find_hosts_by_haddr (hp
, htype
,
2928 data_string_forget(&rel_addr
, MDL
);
2935 * find_host_by_duid_chaddr() synthesizes a DHCPv4-like 'hardware'
2936 * parameter from a DHCPv6 supplied DUID (client-identifier option),
2937 * and may seek to use client or relay supplied hardware addresses.
2940 find_hosts_by_duid_chaddr(struct host_decl
**host
,
2941 const struct data_string
*client_id
) {
2943 const unsigned char *chaddr
;
2946 * The DUID-LL and DUID-LLT must have a 2-byte DUID type and 2-byte
2949 if (client_id
->len
< 4)
2953 * The third and fourth octets of the DUID-LL and DUID-LLT
2954 * is the hardware type, but in 16 bits.
2956 htype
= getUShort(client_id
->data
+ 2);
2960 /* The first two octets of the DUID identify the type. */
2961 switch(getUShort(client_id
->data
)) {
2963 if (client_id
->len
> 8) {
2964 hlen
= client_id
->len
- 8;
2965 chaddr
= client_id
->data
+ 8;
2971 * Note that client_id->len must be greater than or equal
2972 * to four to get to this point in the function.
2974 hlen
= client_id
->len
- 4;
2975 chaddr
= client_id
->data
+ 4;
2982 if ((hlen
== 0) || (hlen
> HARDWARE_ADDR_LEN
) ||
2983 !htype_bounds_check(htype
)) {
2987 return find_hosts_by_haddr(host
, htype
, chaddr
, hlen
, MDL
);
2991 * \brief Finds a host record that matches the packet, if any
2993 * This function centralizes the logic for matching v6 client
2994 * packets to host declarations. We check in the following order
2997 * 1. client_id if specified
2998 * 2. MAC address when explicitly available
3000 * 4. synthesized hardware address - this is done last as some
3001 * synthesis methods are not consided to be reliable
3003 * \param[out] host - pointer to storage for the located host
3004 * \param packet - inbound client packet
3005 * \param client_id - client identifier (if one)
3006 * \param file - source file
3007 * \param line - source file line number
3008 * \return non-zero if a host is found, zero otherwise
3011 find_hosts6(struct host_decl
** host
, struct packet
* packet
,
3012 const struct data_string
* client_id
, char* file
, int line
) {
3013 return (find_hosts_by_uid(host
, client_id
->data
, client_id
->len
, MDL
)
3014 || find_hosts_by_haddr6(host
, packet
, packet
->options
, MDL
)
3015 || find_hosts_by_option(host
, packet
, packet
->options
, MDL
)
3016 || find_hosts_by_duid_chaddr(host
, client_id
));
3019 /* unittest moved to server/tests/mdb6_unittest.c */