xref: /netbsd/external/mpl/dhcp/dist/server/mdb6.c (revision f139e6fe)
1 /*	$NetBSD: mdb6.c,v 1.7 2022/09/23 12:30:52 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2007-2017 by Internet Systems Consortium, Inc. ("ISC")
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/cdefs.h>
20 __RCSID("$NetBSD: mdb6.c,v 1.7 2022/09/23 12:30:52 christos Exp $");
21 
22 
23 /*!
24  * \todo assert()
25  * \todo simplify functions, as pool is now in iaaddr
26  */
27 
28 /*! \file server/mdb6.c
29  *
30  * \page ipv6structures IPv6 Structures Overview
31  *
32  * A brief description of the IPv6 structures as reverse engineered.
33  *
34  * There are four major data structures in the lease configuraion.
35  *
36  * - shared_network - The shared network is the outer enclosing scope for a
37  *                    network region that shares a broadcast domain.  It is
38  *                    composed of one or more subnets all of which are valid
39  *                    in the given region.  The share network may be
40  *                    explicitly defined or implicitly created if there is
41  *                    only a subnet statement.  This structrure is shared
42  *                    with v4.  Each shared network statment or naked subnet
43  *                    will map to one of these structures
44  *
45  * - subnet     - The subnet structure mostly specifies the address range
46  *                that could be valid in a given region.  This structute
47  *                doesn't include the addresses that the server can delegate
48  *                those are in the ipv6_pool.  This structure is also shared
49  *                with v4.  Each subnet statement will map to one of these
50  *                structures.
51  *
52  * - ipv6_pond  - The pond structure is a grouping of the address and prefix
53  *                information via the pointers to the ipv6_pool and the
54  *                allowability of this pool for given clinets via the permit
55  *                lists and the valid TIMEs.  This is equivilent to the v4
56  *                pool structure and would have been named ip6_pool except
57  *                that the name was already in use.  Generally each pool6
58  *                statement will map to one of these structures. In addition
59  *                there may be one or for each group of naked range6 and
60  *                prefix6 statements within a shared network that share
61  *                the same group of statements.
62  *
63  * - ipv6_pool - this contains information about a pool of addresses or prefixes
64  *               that the server is using.  This includes a hash table that
65  *               tracks the active items and a pair of heap tables one for
66  *               active items and one for non-active items.  The heap tables
67  *               are used to determine the next items to be modified due to
68  *               timing events (expire mostly).
69  *
70  * The linkages then look like this:
71  * \verbatim
72  *+--------------+   +-------------+
73  *|Shared Network|   | ipv6_pond   |
74  *|   group      |   |   group     |
75  *|              |   | permit info |
76  *|              |   |    next    ---->
77  *|    ponds    ---->|             |
78  *|              |<----  shared    |
79  *|   Subnets    |   |    pools    |
80  *+-----|--------+   +------|------+
81  *      |  ^                |    ^
82  *      |  |                v    |
83  *      |  |         +-----------|-+
84  *      |  |         | ipv6_pool | |
85  *      |  |         |    type   | |
86  *      |  |         |   ipv6_pond |
87  *      |  |         |             |
88  *      |  |         |    next    ---->
89  *      |  |         |             |
90  *      |  |         |   subnet    |
91  *      |  |         +-----|-------+
92  *      |  |               |
93  *      |  |               v
94  *      |  |         +-------------+
95  *      |  |         |   subnet    |
96  *      |  +----------   shared    |
97  *      +----------->|             |
98  *                   |   group     |
99  *                   +-------------+
100  *
101  * The shared network contains a list of all the subnets that are on a broadcast
102  * doamin.  These can be used to determine if an address makes sense in a given
103  * domain, but the subnets do not contain the addresses the server can delegate.
104  * Those are stored in the ponds and pools.
105  *
106  * In the simple case to find an acceptable address the server would first find
107  * the shared network the client is on based on either the interface used to
108  * receive the request or the relay agent's information.  From the shared
109  * network the server will walk through it's list of ponds.  For each pond it
110  * will evaluate the permit information against the (already done) classification.
111  * If it finds an acceptable pond it will then walk through the pools for that
112  * pond.  The server first checks the type of the pool (NA, TA and PD) agaisnt the
113  * request and if they match it attemps to find an address within that pool.  On
114  * success the address is used, on failure the server steps to the next pool and
115  * if necessary to the next pond.
116  *
117  * When the server is successful in finding an address it will execute any
118  * statements assocaited with the pond, then the subnet, then the shared
119  * network the group field is for in the above picture).
120  *
121  * In configurations that don't include either a shared network or a pool6
122  * statement (or both) the missing pieces are created.
123  *
124  *
125  * There are three major data structuress involved in the lease database:
126  *
127  * - ipv6_pool - see above
128  * - ia_xx   - this contains information about a single IA from a request
129  *             normally it will contain one pointer to a lease for the client
130  *             but it may contain more in some circumstances.  There are 3
131  *             hash tables to aid in accessing these one each for NA, TA and PD.
132  * - iasubopt - the v6 lease structure.  These are created dynamically when
133  *              a client asks for something and will eventually be destroyed
134  *              if the client doesn't re-ask for that item.  A lease has space
135  *              for backpointers to the IA and to the pool to which it belongs.
136  *              The pool backpointer is always filled, the IA pointer may not be.
137  *
138  * In normal use we then have something like this:
139  *
140  * \verbatim
141  * ia hash tables
142  *  ia_na_active                           +----------------+
143  *  ia_ta_active          +------------+   | pool           |
144  *  ia_pd_active          | iasubopt   |<--|  active hash   |
145  * +-----------------+    | aka lease  |<--|  active heap   |
146  * | ia_xx           |    |  pool ptr  |-->|                |
147  * |  iasubopt array |<---|  iaptr     |<--|  inactive heap |
148  * |   lease ptr     |--->|            |   |                |
149  * +-----------------+    +------------+   +----------------+
150  * \endverbatim
151  *
152  * For the pool either the inactive heap will have a pointer
153  * or both the active heap and the active hash will have pointers.
154  *
155  * I think there are several major items to notice.   The first is
156  * that as a lease moves around it will be added to and removed
157  * from the address hash table in the pool and between the active
158  * and inactive hash tables.  The hash table and the active heap
159  * are used when the lease is either active or abandoned.  The
160  * inactive heap is used for all other states.  In particular a
161  * lease that has expired or been released will be cleaned
162  * (DDNS removal etc) and then moved to the inactive heap.  After
163  * some time period (currently 1 hour) it will be freed.
164  *
165  * The second is that when a client requests specific addresses,
166  * either because it previously owned them or if the server supplied
167  * them as part of a solicit, the server will try to lookup the ia_xx
168  * associated with the client and find the addresses there.  If it
169  * does find appropriate leases it moves them from the old IA to
170  * a new IA and eventually replaces the old IA with the new IA
171  * in the IA hash tables.
172  *
173  */
174 #include "config.h"
175 
176 #include <sys/types.h>
177 #include <time.h>
178 #include <netinet/in.h>
179 
180 #include <stdarg.h>
181 #include "dhcpd.h"
182 #include "omapip/omapip.h"
183 #include "omapip/hash.h"
184 #include <isc/md.h>
185 
186 HASH_FUNCTIONS(ia, unsigned char *, struct ia_xx, ia_hash_t,
187 	       ia_reference, ia_dereference, do_string_hash)
188 
189 ia_hash_t *ia_na_active;
190 ia_hash_t *ia_ta_active;
191 ia_hash_t *ia_pd_active;
192 
193 HASH_FUNCTIONS(iasubopt, struct in6_addr *, struct iasubopt, iasubopt_hash_t,
194 	       iasubopt_reference, iasubopt_dereference, do_string_hash)
195 
196 struct ipv6_pool **pools;
197 int num_pools;
198 
199 /*
200  * Create a new IAADDR/PREFIX structure.
201  *
202  * - iasubopt must be a pointer to a (struct iasubopt *) pointer previously
203  *   initialized to NULL
204  */
205 isc_result_t
iasubopt_allocate(struct iasubopt ** iasubopt,const char * file,int line)206 iasubopt_allocate(struct iasubopt **iasubopt, const char *file, int line) {
207 	struct iasubopt *tmp;
208 
209 	if (iasubopt == NULL) {
210 		log_error("%s(%d): NULL pointer reference", file, line);
211 		return DHCP_R_INVALIDARG;
212 	}
213 	if (*iasubopt != NULL) {
214 		log_error("%s(%d): non-NULL pointer", file, line);
215 		return DHCP_R_INVALIDARG;
216 	}
217 
218 	tmp = dmalloc(sizeof(*tmp), file, line);
219 	if (tmp == NULL) {
220 		return ISC_R_NOMEMORY;
221 	}
222 
223 	tmp->refcnt = 1;
224 	tmp->state = FTS_FREE;
225 	tmp->active_index = 0;
226 	tmp->inactive_index = 0;
227 	tmp->plen = 255;
228 
229 	*iasubopt = tmp;
230 	return ISC_R_SUCCESS;
231 }
232 
233 /*
234  * Reference an IAADDR/PREFIX structure.
235  *
236  * - iasubopt must be a pointer to a (struct iasubopt *) pointer previously
237  *   initialized to NULL
238  */
239 isc_result_t
iasubopt_reference(struct iasubopt ** iasubopt,struct iasubopt * src,const char * file,int line)240 iasubopt_reference(struct iasubopt **iasubopt, struct iasubopt *src,
241 		 const char *file, int line) {
242 	if (iasubopt == NULL) {
243 		log_error("%s(%d): NULL pointer reference", file, line);
244 		return DHCP_R_INVALIDARG;
245 	}
246 	if (*iasubopt != NULL) {
247 		log_error("%s(%d): non-NULL pointer", file, line);
248 		return DHCP_R_INVALIDARG;
249 	}
250 	if (src == NULL) {
251 		log_error("%s(%d): NULL pointer reference", file, line);
252 		return DHCP_R_INVALIDARG;
253 	}
254 	*iasubopt = src;
255 	src->refcnt++;
256 	return ISC_R_SUCCESS;
257 }
258 
259 
260 /*
261  * Dereference an IAADDR/PREFIX structure.
262  *
263  * If it is the last reference, then the memory for the
264  * structure is freed.
265  */
266 isc_result_t
iasubopt_dereference(struct iasubopt ** iasubopt,const char * file,int line)267 iasubopt_dereference(struct iasubopt **iasubopt, const char *file, int line) {
268 	struct iasubopt *tmp;
269 
270 	if ((iasubopt == NULL) || (*iasubopt == NULL)) {
271 		log_error("%s(%d): NULL pointer", file, line);
272 		return DHCP_R_INVALIDARG;
273 	}
274 
275 	tmp = *iasubopt;
276 	*iasubopt = NULL;
277 
278 	tmp->refcnt--;
279 	if (tmp->refcnt < 0) {
280 		log_error("%s(%d): negative refcnt", file, line);
281 		tmp->refcnt = 0;
282 	}
283 	if (tmp->refcnt == 0) {
284 		if (tmp->ia != NULL) {
285 			ia_dereference(&(tmp->ia), file, line);
286 		}
287 		if (tmp->ipv6_pool != NULL) {
288 			ipv6_pool_dereference(&(tmp->ipv6_pool), file, line);
289 		}
290 		if (tmp->scope != NULL) {
291 			binding_scope_dereference(&tmp->scope, file, line);
292 		}
293 
294 		if (tmp->on_star.on_expiry != NULL) {
295 			executable_statement_dereference
296 				(&tmp->on_star.on_expiry, MDL);
297 		}
298 		if (tmp->on_star.on_commit != NULL) {
299 			executable_statement_dereference
300 				(&tmp->on_star.on_commit, MDL);
301 		}
302 		if (tmp->on_star.on_release != NULL) {
303 			executable_statement_dereference
304 				(&tmp->on_star.on_release, MDL);
305 		}
306 
307 		dfree(tmp, file, line);
308 	}
309 
310 	return ISC_R_SUCCESS;
311 }
312 
313 /*
314  * Make the key that we use for IA.
315  */
316 isc_result_t
ia_make_key(struct data_string * key,u_int32_t iaid,const char * duid,unsigned int duid_len,const char * file,int line)317 ia_make_key(struct data_string *key, u_int32_t iaid,
318 	    const char *duid, unsigned int duid_len,
319 	    const char *file, int line) {
320 
321 	memset(key, 0, sizeof(*key));
322 	key->len = duid_len + sizeof(iaid);
323 	if (!buffer_allocate(&(key->buffer), key->len, file, line)) {
324 		return ISC_R_NOMEMORY;
325 	}
326 	key->data = key->buffer->data;
327 	memcpy((char *)key->data, &iaid, sizeof(iaid));
328 	memcpy((char *)key->data + sizeof(iaid), duid, duid_len);
329 
330 	return ISC_R_SUCCESS;
331 }
332 
333 /*
334  * Create a new IA structure.
335  *
336  * - ia must be a pointer to a (struct ia_xx *) pointer previously
337  *   initialized to NULL
338  * - iaid and duid are values from the client
339  *
340  * XXXsk: we don't concern ourself with the byte order of the IAID,
341  *        which might be a problem if we transfer this structure
342  *        between machines of different byte order
343  */
344 isc_result_t
ia_allocate(struct ia_xx ** ia,u_int32_t iaid,const char * duid,unsigned int duid_len,const char * file,int line)345 ia_allocate(struct ia_xx **ia, u_int32_t iaid,
346 	    const char *duid, unsigned int duid_len,
347 	    const char *file, int line) {
348 	struct ia_xx *tmp;
349 
350 	if (ia == NULL) {
351 		log_error("%s(%d): NULL pointer reference", file, line);
352 		return DHCP_R_INVALIDARG;
353 	}
354 	if (*ia != NULL) {
355 		log_error("%s(%d): non-NULL pointer", file, line);
356 		return DHCP_R_INVALIDARG;
357 	}
358 
359 	tmp = dmalloc(sizeof(*tmp), file, line);
360 	if (tmp == NULL) {
361 		return ISC_R_NOMEMORY;
362 	}
363 
364 	if (ia_make_key(&tmp->iaid_duid, iaid,
365 			duid, duid_len, file, line) != ISC_R_SUCCESS) {
366 		dfree(tmp, file, line);
367 		return ISC_R_NOMEMORY;
368 	}
369 
370 	tmp->refcnt = 1;
371 
372 	*ia = tmp;
373 	return ISC_R_SUCCESS;
374 }
375 
376 /*
377  * Reference an IA structure.
378  *
379  * - ia must be a pointer to a (struct ia_xx *) pointer previously
380  *   initialized to NULL
381  */
382 isc_result_t
ia_reference(struct ia_xx ** ia,struct ia_xx * src,const char * file,int line)383 ia_reference(struct ia_xx **ia, struct ia_xx *src,
384 	     const char *file, int line) {
385 	if (ia == NULL) {
386 		log_error("%s(%d): NULL pointer reference", file, line);
387 		return DHCP_R_INVALIDARG;
388 	}
389 	if (*ia != NULL) {
390 		log_error("%s(%d): non-NULL pointer", file, line);
391 		return DHCP_R_INVALIDARG;
392 	}
393 	if (src == NULL) {
394 		log_error("%s(%d): NULL pointer reference", file, line);
395 		return DHCP_R_INVALIDARG;
396 	}
397 	*ia = src;
398 	src->refcnt++;
399 	return ISC_R_SUCCESS;
400 }
401 
402 /*
403  * Dereference an IA structure.
404  *
405  * If it is the last reference, then the memory for the
406  * structure is freed.
407  */
408 isc_result_t
ia_dereference(struct ia_xx ** ia,const char * file,int line)409 ia_dereference(struct ia_xx **ia, const char *file, int line) {
410 	struct ia_xx *tmp;
411 	int i;
412 
413 	if ((ia == NULL) || (*ia == NULL)) {
414 		log_error("%s(%d): NULL pointer", file, line);
415 		return DHCP_R_INVALIDARG;
416 	}
417 
418 	tmp = *ia;
419 	*ia = NULL;
420 
421 	tmp->refcnt--;
422 	if (tmp->refcnt < 0) {
423 		log_error("%s(%d): negative refcnt", file, line);
424 		tmp->refcnt = 0;
425 	}
426 	if (tmp->refcnt == 0) {
427 		if (tmp->iasubopt != NULL) {
428 			for (i=0; i<tmp->num_iasubopt; i++) {
429 				iasubopt_dereference(&(tmp->iasubopt[i]),
430 						     file, line);
431 			}
432 			dfree(tmp->iasubopt, file, line);
433 		}
434 		data_string_forget(&(tmp->iaid_duid), file, line);
435 		dfree(tmp, file, line);
436 	}
437 	return ISC_R_SUCCESS;
438 }
439 
440 
441 /*
442  * Add an IAADDR/PREFIX entry to an IA structure.
443  */
444 isc_result_t
ia_add_iasubopt(struct ia_xx * ia,struct iasubopt * iasubopt,const char * file,int line)445 ia_add_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt,
446 		const char *file, int line) {
447 	int max;
448 	struct iasubopt **new;
449 
450 	/*
451 	 * Grow our array if we need to.
452 	 *
453 	 * Note: we pick 4 as the increment, as that seems a reasonable
454 	 *       guess as to how many addresses/prefixes we might expect
455 	 *       on an interface.
456 	 */
457 	if (ia->max_iasubopt <= ia->num_iasubopt) {
458 		max = ia->max_iasubopt + 4;
459 		new = dmalloc(max * sizeof(struct iasubopt *), file, line);
460 		if (new == NULL) {
461 			return ISC_R_NOMEMORY;
462 		}
463 		memcpy(new, ia->iasubopt,
464 		       ia->num_iasubopt * sizeof(struct iasubopt *));
465 		ia->iasubopt = new;
466 		ia->max_iasubopt = max;
467 	}
468 
469 	iasubopt_reference(&(ia->iasubopt[ia->num_iasubopt]), iasubopt,
470 			   file, line);
471 	ia->num_iasubopt++;
472 
473 	return ISC_R_SUCCESS;
474 }
475 
476 /*
477  * Remove an IAADDR/PREFIX entry to an IA structure.
478  *
479  * Note: if a suboption appears more than once, then only ONE will be removed.
480  */
481 void
ia_remove_iasubopt(struct ia_xx * ia,struct iasubopt * iasubopt,const char * file,int line)482 ia_remove_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt,
483 		   const char *file, int line) {
484 	int i, j;
485         if (ia == NULL || iasubopt == NULL)
486             return;
487 
488 	for (i=0; i<ia->num_iasubopt; i++) {
489 		if (ia->iasubopt[i] == iasubopt) {
490 			/* remove this sub option */
491 			iasubopt_dereference(&(ia->iasubopt[i]), file, line);
492 			/* move remaining suboption pointers down one */
493 			for (j=i+1; j < ia->num_iasubopt; j++) {
494 				ia->iasubopt[j-1] = ia->iasubopt[j];
495 			}
496 			/* decrease our total count */
497 			/* remove the back-reference in the suboption itself */
498 			ia_dereference(&iasubopt->ia, file, line);
499 			ia->num_iasubopt--;
500 			return;
501 		}
502 	}
503 	log_error("%s(%d): IAADDR/PREFIX not in IA", file, line);
504 }
505 
506 /*
507  * Remove all addresses/prefixes from an IA.
508  */
509 void
ia_remove_all_lease(struct ia_xx * ia,const char * file,int line)510 ia_remove_all_lease(struct ia_xx *ia, const char *file, int line) {
511 	int i;
512 
513 	for (i=0; i<ia->num_iasubopt; i++) {
514 		ia_dereference(&(ia->iasubopt[i]->ia), file, line);
515 		iasubopt_dereference(&(ia->iasubopt[i]), file, line);
516 	}
517 	ia->num_iasubopt = 0;
518 }
519 
520 /*
521  * Compare two IA.
522  */
523 isc_boolean_t
ia_equal(const struct ia_xx * a,const struct ia_xx * b)524 ia_equal(const struct ia_xx *a, const struct ia_xx *b)
525 {
526 	isc_boolean_t found;
527 	int i, j;
528 
529 	/*
530 	 * Handle cases where one or both of the inputs is NULL.
531 	 */
532 	if (a == NULL) {
533 		if (b == NULL) {
534 			return ISC_TRUE;
535 		} else {
536 			return ISC_FALSE;
537 		}
538 	}
539 
540 	/*
541 	 * Check the type is the same.
542 	 */
543 	if (a->ia_type != b->ia_type) {
544 		return ISC_FALSE;
545 	}
546 
547 	/*
548 	 * Check the DUID is the same.
549 	 */
550 	if (a->iaid_duid.len != b->iaid_duid.len) {
551 		return ISC_FALSE;
552 	}
553 	if (memcmp(a->iaid_duid.data,
554 		   b->iaid_duid.data, a->iaid_duid.len) != 0) {
555 		return ISC_FALSE;
556 	}
557 
558 	/*
559 	 * Make sure we have the same number of addresses/prefixes in each.
560 	 */
561 	if (a->num_iasubopt != b->num_iasubopt) {
562 		return ISC_FALSE;
563 	}
564 
565 	/*
566 	 * Check that each address/prefix is present in both.
567 	 */
568 	for (i=0; i<a->num_iasubopt; i++) {
569 		found = ISC_FALSE;
570 		for (j=0; j<a->num_iasubopt; j++) {
571 			if (a->iasubopt[i]->plen != b->iasubopt[i]->plen)
572 				continue;
573 			if (memcmp(&(a->iasubopt[i]->addr),
574 			           &(b->iasubopt[j]->addr),
575 				   sizeof(struct in6_addr)) == 0) {
576 				found = ISC_TRUE;
577 				break;
578 			}
579 		}
580 		if (!found) {
581 			return ISC_FALSE;
582 		}
583 	}
584 
585 	/*
586 	 * These are the same in every way we care about.
587 	 */
588 	return ISC_TRUE;
589 }
590 
591 /*
592  * Helper function for lease heaps.
593  * Makes the top of the heap the oldest lease.
594  */
595 static isc_boolean_t
lease_older(void * a,void * b)596 lease_older(void *a, void *b) {
597 	struct iasubopt *la = (struct iasubopt *)a;
598 	struct iasubopt *lb = (struct iasubopt *)b;
599 
600 	if (la->hard_lifetime_end_time == lb->hard_lifetime_end_time) {
601 		return difftime(la->soft_lifetime_end_time,
602 				lb->soft_lifetime_end_time) < 0;
603 	} else {
604 		return difftime(la->hard_lifetime_end_time,
605 				lb->hard_lifetime_end_time) < 0;
606 	}
607 }
608 
609 /*
610  * Helper functions for lease address/prefix heaps.
611  * Callback when an address's position in the heap changes.
612  */
613 static void
active_changed(void * iasubopt,unsigned int new_heap_index)614 active_changed(void *iasubopt, unsigned int new_heap_index) {
615 	((struct iasubopt *)iasubopt)->active_index = new_heap_index;
616 }
617 
618 static void
inactive_changed(void * iasubopt,unsigned int new_heap_index)619 inactive_changed(void *iasubopt, unsigned int new_heap_index) {
620 	((struct iasubopt *)iasubopt)->inactive_index = new_heap_index;
621 }
622 
623 /*!
624  *
625  * \brief Create a new IPv6 lease pool structure
626  *
627  * Allocate space for a new ipv6_pool structure and return a reference
628  * to it, includes setting the reference count to 1.
629  *
630  * \param     pool       = space for returning a referenced pointer to the pool.
631  *			   This must point to a space that has been initialzied
632  *			   to NULL by the caller.
633  * \param[in] type       = The type of the pool NA, TA or PD
634  * \param[in] start_addr = The first address in the range for the pool
635  * \param[in] bits       = The contiguous bits of the pool
636 
637  *
638  * \return
639  * ISC_R_SUCCESS     = The pool was successfully created, pool points to it.
640  * DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been
641  *		       modified
642  * ISC_R_NOMEMORY    = The system wasn't able to allocate memory, pool has
643  *		       not been modified.
644  */
645 isc_result_t
ipv6_pool_allocate(struct ipv6_pool ** pool,u_int16_t type,const struct in6_addr * start_addr,int bits,int units,const char * file,int line)646 ipv6_pool_allocate(struct ipv6_pool **pool, u_int16_t type,
647 		   const struct in6_addr *start_addr, int bits,
648 		   int units, const char *file, int line) {
649 	struct ipv6_pool *tmp;
650 
651 	if (pool == NULL) {
652 		log_error("%s(%d): NULL pointer reference", file, line);
653 		return DHCP_R_INVALIDARG;
654 	}
655 	if (*pool != NULL) {
656 		log_error("%s(%d): non-NULL pointer", file, line);
657 		return DHCP_R_INVALIDARG;
658 	}
659 
660 	tmp = dmalloc(sizeof(*tmp), file, line);
661 	if (tmp == NULL) {
662 		return ISC_R_NOMEMORY;
663 	}
664 
665 	tmp->refcnt = 1;
666 	tmp->pool_type = type;
667 	tmp->start_addr = *start_addr;
668 	tmp->bits = bits;
669 	tmp->units = units;
670 	if (!iasubopt_new_hash(&tmp->leases, DEFAULT_HASH_SIZE, file, line)) {
671 		dfree(tmp, file, line);
672 		return ISC_R_NOMEMORY;
673 	}
674 	isc_heap_create(dhcp_gbl_ctx.mctx, lease_older, active_changed,
675 			0, &(tmp->active_timeouts));
676 	isc_heap_create(dhcp_gbl_ctx.mctx, lease_older, inactive_changed,
677 			0, &(tmp->inactive_timeouts));
678 
679 	*pool = tmp;
680 	return ISC_R_SUCCESS;
681 }
682 
683 /*!
684  *
685  * \brief reference an IPv6 pool structure.
686  *
687  * This function genreates a reference to an ipv6_pool structure
688  * and increments the reference count on the structure.
689  *
690  * \param[out] pool = space for returning a referenced pointer to the pool.
691  *		      This must point to a space that has been initialzied
692  *		      to NULL by the caller.
693  * \param[in]  src  = A pointer to the pool to reference.  This must not be
694  *		      NULL.
695  *
696  * \return
697  * ISC_R_SUCCESS     = The pool was successfully referenced, pool now points
698  *		       to src.
699  * DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been
700  *		       modified.
701  */
702 isc_result_t
ipv6_pool_reference(struct ipv6_pool ** pool,struct ipv6_pool * src,const char * file,int line)703 ipv6_pool_reference(struct ipv6_pool **pool, struct ipv6_pool *src,
704 		    const char *file, int line) {
705 	if (pool == NULL) {
706 		log_error("%s(%d): NULL pointer reference", file, line);
707 		return DHCP_R_INVALIDARG;
708 	}
709 	if (*pool != NULL) {
710 		log_error("%s(%d): non-NULL pointer", file, line);
711 		return DHCP_R_INVALIDARG;
712 	}
713 	if (src == NULL) {
714 		log_error("%s(%d): NULL pointer reference", file, line);
715 		return DHCP_R_INVALIDARG;
716 	}
717 	*pool = src;
718 	src->refcnt++;
719 	return ISC_R_SUCCESS;
720 }
721 
722 /*
723  * Note: Each IAADDR/PREFIX in a pool is referenced by the pool. This is needed
724  * to prevent the lease from being garbage collected out from under the
725  * pool.
726  *
727  * The references are made from the hash and from the heap. The following
728  * helper functions dereference these when a pool is destroyed.
729  */
730 
731 /*
732  * Helper function for pool cleanup.
733  * Dereference each of the hash entries in a pool.
734  */
735 static isc_result_t
dereference_hash_entry(const void * name,unsigned len,void * value)736 dereference_hash_entry(const void *name, unsigned len, void *value) {
737 	struct iasubopt *iasubopt = (struct iasubopt *)value;
738 
739 	iasubopt_dereference(&iasubopt, MDL);
740 	return ISC_R_SUCCESS;
741 }
742 
743 /*
744  * Helper function for pool cleanup.
745  * Dereference each of the heap entries in a pool.
746  */
747 static void
dereference_heap_entry(void * value,void * dummy)748 dereference_heap_entry(void *value, void *dummy) {
749 	struct iasubopt *iasubopt = (struct iasubopt *)value;
750 
751 	iasubopt_dereference(&iasubopt, MDL);
752 }
753 
754 /*!
755  *
756  * \brief de-reference an IPv6 pool structure.
757  *
758  * This function decrements the reference count in an ipv6_pool structure.
759  * If this was the last reference then the memory for the structure is
760  * freed.
761  *
762  * \param[in] pool = A pointer to the pointer to the pool that should be
763  *		     de-referenced.  On success the pointer to the pool
764  *		     is cleared.  It must not be NULL and must not point
765  *		     to NULL.
766  *
767  * \return
768  * ISC_R_SUCCESS     = The pool was successfully de-referenced, pool now points
769  *		       to NULL
770  * DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been
771  *		       modified.
772  */
773 isc_result_t
ipv6_pool_dereference(struct ipv6_pool ** pool,const char * file,int line)774 ipv6_pool_dereference(struct ipv6_pool **pool, const char *file, int line) {
775 	struct ipv6_pool *tmp;
776 
777 	if ((pool == NULL) || (*pool == NULL)) {
778 		log_error("%s(%d): NULL pointer", file, line);
779 		return DHCP_R_INVALIDARG;
780 	}
781 
782 	tmp = *pool;
783 	*pool = NULL;
784 
785 	tmp->refcnt--;
786 	if (tmp->refcnt < 0) {
787 		log_error("%s(%d): negative refcnt", file, line);
788 		tmp->refcnt = 0;
789 	}
790 	if (tmp->refcnt == 0) {
791 		iasubopt_hash_foreach(tmp->leases, dereference_hash_entry);
792 		iasubopt_free_hash_table(&(tmp->leases), file, line);
793 		isc_heap_foreach(tmp->active_timeouts,
794 				 dereference_heap_entry, NULL);
795 		isc_heap_destroy(&(tmp->active_timeouts));
796 		isc_heap_foreach(tmp->inactive_timeouts,
797 				 dereference_heap_entry, NULL);
798 		isc_heap_destroy(&(tmp->inactive_timeouts));
799 		dfree(tmp, file, line);
800 	}
801 
802 	return ISC_R_SUCCESS;
803 }
804 
805 /*
806  * Create an address by hashing the input, and using that for
807  * the non-network part.
808  */
809 static void
build_address6(struct in6_addr * addr,const struct in6_addr * net_start_addr,int net_bits,const struct data_string * input)810 build_address6(struct in6_addr *addr,
811 	       const struct in6_addr *net_start_addr, int net_bits,
812 	       const struct data_string *input) {
813 	int net_bytes;
814 	int i;
815 	unsigned int len;
816 	char *str;
817 	const char *net_str;
818 
819 	isc_md(ISC_MD_MD5, input->data, input->len, (void *)addr, &len);
820 
821 	/*
822 	 * Copy the [0..128] network bits over.
823 	 */
824 	str = (char *)addr;
825 	net_str = (const char *)net_start_addr;
826 	net_bytes = net_bits / 8;
827 	for (i = 0; i < net_bytes; i++) {
828 		str[i] = net_str[i];
829 	}
830 	switch (net_bits % 8) {
831 		case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
832 		case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
833 		case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break;
834 		case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break;
835 		case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break;
836 		case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break;
837 		case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break;
838 	}
839 
840 	/*
841 	 * Set the universal/local bit ("u bit") to zero for /64s.  The
842 	 * individual/group bit ("g bit") is unchanged, because the g-bit
843 	 * has no meaning when the u-bit is cleared.
844 	 */
845 	if (net_bits == 64)
846 		str[8] &= ~0x02;
847 }
848 
849 #ifdef EUI_64
850 int
valid_eui_64_duid(const struct data_string * uid,int offset)851 valid_eui_64_duid(const struct data_string* uid, int offset) {
852 	if (uid->len == (offset + EUI_64_ID_LEN)) {
853 		const unsigned char* duid = uid->data + offset;
854 		return (((duid[0] == 0x00 && duid[1] == 0x03)  &&
855 			(duid[2] == 0x00 && duid[3] == 0x1b)));
856 	}
857 
858     return(0);
859 }
860 
861 
862 /*
863  * Create an EUI-64 address
864  */
865 static isc_result_t
build_address6_eui_64(struct in6_addr * addr,const struct in6_addr * net_start_addr,int net_bits,const struct data_string * iaid_duid,int duid_beg)866 build_address6_eui_64(struct in6_addr *addr,
867 		      const struct in6_addr *net_start_addr, int net_bits,
868 		      const struct data_string *iaid_duid, int duid_beg) {
869 
870 	if (net_bits != 64) {
871 		log_error("build_address_eui_64: network is not 64 bits");
872 		return (ISC_R_FAILURE);
873 	}
874 
875 	if (valid_eui_64_duid(iaid_duid, duid_beg)) {
876 		const unsigned char *duid = iaid_duid->data + duid_beg;
877 
878 		/* copy network prefix to the high 64 bits */
879 		memcpy(addr->s6_addr, net_start_addr->s6_addr, 8);
880 
881 		/* copy Link-layer address to low 64 bits */
882 		memcpy(addr->s6_addr + 8, duid + 4, 8);
883 
884 		/* RFC-3315 Any address assigned by a server that is based
885 		 * on an EUI-64 identifier MUST include an interface identifier
886 		 * with the "u" (universal/local) and "g" (individual/group)
887 		 * bits of the interface identifier set appropriately, as
888 		 * indicated in section 2.5.1 of RFC 2373 [5]. */
889 		addr->s6_addr[8] |= 0x02;
890 		return (ISC_R_SUCCESS);
891 	}
892 
893 	log_error("build_address_eui_64: iaid_duid not a valid EUI-64: %s",
894 		  print_hex_1(iaid_duid->len, iaid_duid->data, 60));
895 	return (ISC_R_FAILURE);
896 }
897 
898 int
valid_for_eui_64_pool(struct ipv6_pool * pool,struct data_string * uid,int duid_beg,struct in6_addr * ia_addr)899 valid_for_eui_64_pool(struct ipv6_pool* pool, struct data_string* uid,
900 		      int duid_beg, struct in6_addr* ia_addr) {
901         struct in6_addr test_addr;
902 	/* If it's not an EUI-64 pool bail */
903         if (!pool->ipv6_pond->use_eui_64) {
904                 return (0);
905         }
906 
907         if (!valid_eui_64_duid(uid, duid_beg)) {
908                 /* Dynamic lease in a now eui_64 pond, toss it*/
909                 return (0);
910         }
911 
912         /*  Call build_address6_eui_64() and compare it's result to
913 	 *  this lease and see if they match. */
914         memset (&test_addr, 0, sizeof(test_addr));
915         build_address6_eui_64(&test_addr, &pool->start_addr, pool->bits,
916                               uid, duid_beg);
917 
918         return (!memcmp(ia_addr, &test_addr, sizeof(test_addr)));
919 }
920 #endif
921 
922 
923 /*
924  * Create a temporary address by a variant of RFC 4941 algo.
925  * Note: this should not be used for prefixes shorter than 64 bits.
926  */
927 static void
build_temporary6(struct in6_addr * addr,const struct in6_addr * net_start_addr,int net_bits,const struct data_string * input)928 build_temporary6(struct in6_addr *addr,
929 		 const struct in6_addr *net_start_addr, int net_bits,
930 		 const struct data_string *input) {
931 	static u_int32_t history[2];
932 	static u_int32_t counter = 0;
933 	unsigned char md[16] = {0};
934 	unsigned int len;
935 
936 	/*
937 	 * First time/time to reseed.
938 	 * Please use a good pseudo-random generator here!
939 	 */
940 	if (counter == 0) {
941 		history[0] = arc4random();
942 		history[1] = arc4random();
943 	}
944 
945 	/*
946 	 * Use MD5 as recommended by RFC 4941.
947 	 */
948 	isc_md(ISC_MD_MD5, input->data, input->len, (void *)&history[0], &len);
949 
950 	/*
951 	 * Build the address.
952 	 */
953 	if (net_bits == 64) {
954 		memcpy(&addr->s6_addr[0], &net_start_addr->s6_addr[0], 8);
955 		memcpy(&addr->s6_addr[8], md, 8);
956 		addr->s6_addr[8] &= ~0x02;
957 	} else {
958 		int net_bytes;
959 		int i;
960 		char *str;
961 		const char *net_str;
962 
963 		/*
964 		 * Copy the [0..128] network bits over.
965 		 */
966 		str = (char *)addr;
967 		net_str = (const char *)net_start_addr;
968 		net_bytes = net_bits / 8;
969 		for (i = 0; i < net_bytes; i++) {
970 			str[i] = net_str[i];
971 		}
972 		memcpy(str + net_bytes, md, 16 - net_bytes);
973 		switch (net_bits % 8) {
974 		case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
975 		case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
976 		case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break;
977 		case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break;
978 		case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break;
979 		case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break;
980 		case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break;
981 		}
982 	}
983 
984 
985 	/*
986 	 * Save history for the next call.
987 	 */
988 	memcpy((unsigned char *)&history[0], md + 8, 8);
989 	counter++;
990 }
991 
992 /* Reserved Subnet Router Anycast ::0:0:0:0. */
993 static struct in6_addr rtany;
994 /* Reserved Subnet Anycasts ::fdff:ffff:ffff:ff80-::fdff:ffff:ffff:ffff. */
995 static struct in6_addr resany;
996 
997 /*
998  * Create a lease for the given address and client duid.
999  *
1000  * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
1001  *   initialized to NULL
1002  *
1003  * Right now we simply hash the DUID, and if we get a collision, we hash
1004  * again until we find a free address. We try this a fixed number of times,
1005  * to avoid getting stuck in a loop (this is important on small pools
1006  * where we can run out of space).
1007  *
1008  * We return the number of attempts that it took to find an available
1009  * lease. This tells callers when a pool is are filling up, as
1010  * well as an indication of how full the pool is; statistically the
1011  * more full a pool is the more attempts must be made before finding
1012  * a free lease. Realistically this will only happen in very full
1013  * pools.
1014  *
1015  * We probably want different algorithms depending on the network size, in
1016  * the long term.
1017  */
1018 isc_result_t
create_lease6(struct ipv6_pool * pool,struct iasubopt ** addr,unsigned int * attempts,const struct data_string * uid,time_t soft_lifetime_end_time)1019 create_lease6(struct ipv6_pool *pool, struct iasubopt **addr,
1020 	      unsigned int *attempts,
1021 	      const struct data_string *uid, time_t soft_lifetime_end_time) {
1022 	struct data_string ds;
1023 	struct in6_addr tmp;
1024 	struct iasubopt *test_iaaddr;
1025 	struct data_string new_ds;
1026 	struct iasubopt *iaaddr;
1027 	isc_result_t result;
1028 	isc_boolean_t reserved_iid;
1029 	static isc_boolean_t init_resiid = ISC_FALSE;
1030 
1031 	/*
1032 	 * Fill the reserved IIDs.
1033 	 */
1034 	if (!init_resiid) {
1035 		memset(&rtany, 0, 16);
1036 		memset(&resany, 0, 8);
1037 		resany.s6_addr[8] = 0xfd;
1038 		memset(&resany.s6_addr[9], 0xff, 6);
1039 		init_resiid = ISC_TRUE;
1040 	}
1041 
1042 	/*
1043 	 * Use the UID as our initial seed for the hash
1044 	 */
1045 	memset(&ds, 0, sizeof(ds));
1046 	data_string_copy(&ds, (struct data_string *)uid, MDL);
1047 
1048 	*attempts = 0;
1049 	for (;;) {
1050 		/*
1051 		 * Give up at some point.
1052 		 */
1053 		if (++(*attempts) > 100) {
1054 			data_string_forget(&ds, MDL);
1055 			return ISC_R_NORESOURCES;
1056 		}
1057 
1058 		/*
1059 		 * Build a resource.
1060 		 */
1061 		switch (pool->pool_type) {
1062 		case D6O_IA_NA:
1063 			/* address */
1064 			build_address6(&tmp, &pool->start_addr,
1065 				       pool->bits, &ds);
1066 			break;
1067 		case D6O_IA_TA:
1068 			/* temporary address */
1069 			build_temporary6(&tmp, &pool->start_addr,
1070 					 pool->bits, &ds);
1071 			break;
1072 		case D6O_IA_PD:
1073 			/* prefix */
1074 			log_error("create_lease6: prefix pool.");
1075 			data_string_forget(&ds, MDL);
1076 			return DHCP_R_INVALIDARG;
1077 		default:
1078 			log_error("create_lease6: untyped pool.");
1079 			data_string_forget(&ds, MDL);
1080 			return DHCP_R_INVALIDARG;
1081 		}
1082 
1083 		/*
1084 		 * Avoid reserved interface IDs. (cf. RFC 5453)
1085 		 */
1086 		reserved_iid = ISC_FALSE;
1087 		if (memcmp(&tmp.s6_addr[8], &rtany.s6_addr[8], 8) == 0) {
1088 			reserved_iid = ISC_TRUE;
1089 		}
1090 		if (!reserved_iid &&
1091 		    (memcmp(&tmp.s6_addr[8], &resany.s6_addr[8], 7) == 0) &&
1092 		    ((tmp.s6_addr[15] & 0x80) == 0x80)) {
1093 			reserved_iid = ISC_TRUE;
1094 		}
1095 
1096 		/*
1097 		 * If this address is not in use, we're happy with it
1098 		 */
1099 		test_iaaddr = NULL;
1100 		if (!reserved_iid &&
1101 		    (iasubopt_hash_lookup(&test_iaaddr, pool->leases,
1102 					  &tmp, sizeof(tmp), MDL) == 0)) {
1103 			break;
1104 		}
1105 		if (test_iaaddr != NULL)
1106 			iasubopt_dereference(&test_iaaddr, MDL);
1107 
1108 		/*
1109 		 * Otherwise, we create a new input, adding the address
1110 		 */
1111 		memset(&new_ds, 0, sizeof(new_ds));
1112 		new_ds.len = ds.len + sizeof(tmp);
1113 		if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) {
1114 			data_string_forget(&ds, MDL);
1115 			return ISC_R_NOMEMORY;
1116 		}
1117 		new_ds.data = new_ds.buffer->data;
1118 		memcpy(new_ds.buffer->data, ds.data, ds.len);
1119 		memcpy(new_ds.buffer->data + ds.len, &tmp, sizeof(tmp));
1120 		data_string_forget(&ds, MDL);
1121 		data_string_copy(&ds, &new_ds, MDL);
1122 		data_string_forget(&new_ds, MDL);
1123 	}
1124 
1125 	data_string_forget(&ds, MDL);
1126 
1127 	/*
1128 	 * We're happy with the address, create an IAADDR
1129 	 * to hold it.
1130 	 */
1131 	iaaddr = NULL;
1132 	result = iasubopt_allocate(&iaaddr, MDL);
1133 	if (result != ISC_R_SUCCESS) {
1134 		return result;
1135 	}
1136 	iaaddr->plen = 0;
1137 	memcpy(&iaaddr->addr, &tmp, sizeof(iaaddr->addr));
1138 
1139 	/*
1140 	 * Add the lease to the pool (note state is free, not active?!).
1141 	 */
1142 	result = add_lease6(pool, iaaddr, soft_lifetime_end_time);
1143 	if (result == ISC_R_SUCCESS) {
1144 		iasubopt_reference(addr, iaaddr, MDL);
1145 	}
1146 	iasubopt_dereference(&iaaddr, MDL);
1147 	return result;
1148 }
1149 
1150 #ifdef EUI_64
1151 /*!
1152  * \brief Assign an EUI-64 address from a pool for a given iaid-duid
1153  *
1154  *  \param pool - pool from which the address is assigned
1155  *  \param iaddr - pointer to the iasubopt to contain the assigned address is
1156  *  \param uid - data_string containing the iaid-duid tuple
1157  *  \param soft_lifetime_end_time - lifetime of the lease for a solicit?
1158  *
1159  *  \return status indicating success or nature of the failure
1160 */
1161 isc_result_t
create_lease6_eui_64(struct ipv6_pool * pool,struct iasubopt ** addr,const struct data_string * uid,time_t soft_lifetime_end_time)1162 create_lease6_eui_64(struct ipv6_pool *pool, struct iasubopt **addr,
1163 	      const struct data_string *uid,
1164 	      time_t soft_lifetime_end_time) {
1165 	struct in6_addr tmp;
1166 	struct iasubopt *test_iaaddr;
1167 	struct iasubopt *iaaddr;
1168 	isc_result_t result;
1169 	static isc_boolean_t init_resiid = ISC_FALSE;
1170 
1171 	/*  Fill the reserved IIDs.  */
1172 	if (!init_resiid) {
1173 		memset(&rtany, 0, 16);
1174 		memset(&resany, 0, 8);
1175 		resany.s6_addr[8] = 0xfd;
1176 		memset(&resany.s6_addr[9], 0xff, 6);
1177 		init_resiid = ISC_TRUE;
1178 	}
1179 
1180 	/* Pool must be IA_NA */
1181 	if (pool->pool_type != D6O_IA_NA) {
1182 		log_error("create_lease6_eui_64: pool type is not IA_NA.");
1183 		return (DHCP_R_INVALIDARG);
1184 	}
1185 
1186 	/* Attempt to build the address */
1187 	if (build_address6_eui_64 (&tmp, &pool->start_addr, pool->bits,
1188 				   uid, IAID_LEN) != ISC_R_SUCCESS) {
1189 		log_error("create_lease6_eui_64: build_address6_eui_64 failed");
1190 		return (ISC_R_FAILURE);
1191 	}
1192 
1193 	/* Avoid reserved interface IDs. (cf. RFC 5453) */
1194 	if ((memcmp(&tmp.s6_addr[8], &rtany.s6_addr[8], 8) == 0)  ||
1195 	    ((memcmp(&tmp.s6_addr[8], &resany.s6_addr[8], 7) == 0) &&
1196 	    ((tmp.s6_addr[15] & 0x80) == 0x80))) {
1197 		log_error("create_lease6_eui_64: "
1198 			  "address conflicts with reserved IID");
1199 		return (ISC_R_FAILURE);
1200 	}
1201 
1202 	/* If this address is not in use, we're happy with it */
1203 	test_iaaddr = NULL;
1204 	if (iasubopt_hash_lookup(&test_iaaddr, pool->leases,
1205 				  &tmp, sizeof(tmp), MDL) != 0) {
1206 
1207 		/* See if it's ours. Static leases won't have an ia */
1208 		int ours = 0;
1209 		if (!test_iaaddr->ia) {
1210 			log_error("create_lease6_eui_64: "
1211 				  "address  %s is assigned to static lease",
1212 				  pin6_addr(&test_iaaddr->addr));
1213 		} else {
1214 			/* Not sure if this can actually happen */
1215 			struct data_string* found = &test_iaaddr->ia->iaid_duid;
1216 			ours = ((found->len == uid->len) &&
1217 				(!memcmp(found->data, uid->data, uid->len)));
1218 			log_error("create_lease6_eui_64: "
1219 				  "address  %s belongs to %s",
1220 				  pin6_addr(&test_iaaddr->addr),
1221 				  print_hex_1(found->len, found->data, 60));
1222 		}
1223 
1224 		iasubopt_dereference(&test_iaaddr, MDL);
1225 		if (!ours) {
1226 			/* Cant' use it */
1227 			return (ISC_R_FAILURE);
1228 		}
1229 	}
1230 
1231 	/* We're happy with the address, create an IAADDR to hold it. */
1232 	iaaddr = NULL;
1233 	result = iasubopt_allocate(&iaaddr, MDL);
1234 	if (result != ISC_R_SUCCESS) {
1235 		log_error("create_lease6_eui_64: could not allocate iasubop");
1236 		return result;
1237 	}
1238 	iaaddr->plen = 0;
1239 	memcpy(&iaaddr->addr, &tmp, sizeof(iaaddr->addr));
1240 
1241 	/* Add the lease to the pool and the reply */
1242 	result = add_lease6(pool, iaaddr, soft_lifetime_end_time);
1243 	if (result == ISC_R_SUCCESS) {
1244 		iasubopt_reference(addr, iaaddr, MDL);
1245 	}
1246 
1247 	iasubopt_dereference(&iaaddr, MDL);
1248 	return result;
1249 }
1250 #endif
1251 
1252 /*!
1253  *
1254  * \brief Cleans up leases when reading from a lease file
1255  *
1256  * This function is only expected to be run when reading leases in from a file.
1257  * It checks to see if a lease already exists for the new leases's address.
1258  * We don't add expired leases to the structures when reading a lease file
1259  * which limits what can happen.  We have two variables the owners of the leases
1260  * being the same or different and the new lease being active or non-active:
1261  * Owners active
1262  * same   no     remove old lease and its connections
1263  * same   yes    nothing to do, other code will update the structures.
1264  * diff   no     nothing to do
1265  * diff   yes    this combination shouldn't happen, we should only have a
1266  *               single active lease per address at a time and that lease
1267  *               should move to non-active before any other lease can
1268  *               become active for that address.
1269  *               Currently we delete the previous lease and pass an error
1270  *               to the caller who should log an error.
1271  *
1272  * When we remove a lease we remove it from the hash table and active heap
1273  * (remember only active leases are in the structures at this time) for the
1274  * pool, and from the IA's array.  If, after we've removed the pointer from
1275  * IA's array to the lease, the IA has no more pointers we remove it from
1276  * the appropriate hash table as well.
1277  *
1278  * \param[in] ia_table = the hash table for the IA
1279  * \param[in] pool     = the pool to update
1280  * \param[in] lease    = the new lease we want to add
1281  * \param[in] ia       = the new ia we are building
1282  *
1283  * \return
1284  * ISC_R_SUCCESS = the incoming lease and any previous lease were in
1285  *                 an expected state - one of the first 3 options above.
1286  *                 If necessary the old lease was removed.
1287  * ISC_R_FAILURE = there is already an active lease for the address in
1288  *                 the incoming lease.  This shouldn't happen if it does
1289  *                 flag an error for the caller to log.
1290  */
1291 
1292 isc_result_t
cleanup_lease6(ia_hash_t * ia_table,struct ipv6_pool * pool,struct iasubopt * lease,struct ia_xx * ia)1293 cleanup_lease6(ia_hash_t *ia_table,
1294 	       struct ipv6_pool *pool,
1295 	       struct iasubopt *lease,
1296 	       struct ia_xx *ia) {
1297 
1298 	struct iasubopt *test_iasubopt, *tmp_iasubopt;
1299 	struct ia_xx *old_ia;
1300 	isc_result_t status = ISC_R_SUCCESS;
1301 
1302 	test_iasubopt = NULL;
1303 	old_ia = NULL;
1304 
1305 	/*
1306 	 * Look up the address - if we don't find a lease
1307 	 * we don't need to do anything.
1308 	 */
1309 	if (iasubopt_hash_lookup(&test_iasubopt, pool->leases,
1310 				 &lease->addr, sizeof(lease->addr),
1311 				 MDL) == 0) {
1312 		return (ISC_R_SUCCESS);
1313 	}
1314 
1315 	if (test_iasubopt->ia == NULL) {
1316 		/* no old ia, no work to do */
1317 		iasubopt_dereference(&test_iasubopt, MDL);
1318 		return (status);
1319 	}
1320 
1321 	ia_reference(&old_ia, test_iasubopt->ia, MDL);
1322 
1323 	if ((old_ia->iaid_duid.len == ia->iaid_duid.len) &&
1324 	    (memcmp((unsigned char *)ia->iaid_duid.data,
1325 		    (unsigned char *)old_ia->iaid_duid.data,
1326 		    ia->iaid_duid.len) == 0)) {
1327 		/* same IA */
1328 		if ((lease->state == FTS_ACTIVE) ||
1329 		    (lease->state == FTS_ABANDONED)) {
1330 			/* still active, no need to delete */
1331 			goto cleanup;
1332 		}
1333 	} else {
1334 		/* different IA */
1335 		if ((lease->state != FTS_ACTIVE) &&
1336 		    (lease->state != FTS_ABANDONED)) {
1337 			/* new lease isn't active, no work */
1338 			goto cleanup;
1339 		}
1340 
1341 		/*
1342 		 * We appear to have two active leases, this shouldn't happen.
1343 		 * Before a second lease can be set to active the first lease
1344 		 * should be set to inactive (released, expired etc). For now
1345 		 * delete the previous lease and indicate a failure to the
1346 		 * caller so it can generate a warning.
1347 		 * In the future we may try and determine which is the better
1348 		 * lease to keep.
1349 		 */
1350 
1351 		status = ISC_R_FAILURE;
1352 	}
1353 
1354 	/*
1355 	 * Remove the old lease from the active heap and from the hash table
1356 	 * then remove the lease from the IA and clean up the IA if necessary.
1357 	 */
1358 	isc_heap_delete(pool->active_timeouts, test_iasubopt->active_index);
1359 	pool->num_active--;
1360 	if (pool->ipv6_pond)
1361 		pool->ipv6_pond->num_active--;
1362 
1363 	if (lease->state == FTS_ABANDONED) {
1364 		pool->num_abandoned--;
1365 		if (pool->ipv6_pond)
1366 			pool->ipv6_pond->num_abandoned--;
1367 	}
1368 
1369 	iasubopt_hash_delete(pool->leases, &test_iasubopt->addr,
1370 			     sizeof(test_iasubopt->addr), MDL);
1371 	ia_remove_iasubopt(old_ia, test_iasubopt, MDL);
1372 	if (old_ia->num_iasubopt <= 0) {
1373 		ia_hash_delete(ia_table,
1374 			       (unsigned char *)old_ia->iaid_duid.data,
1375 			       old_ia->iaid_duid.len, MDL);
1376 	}
1377 
1378 	/*
1379 	 * We derefenrece the subopt here as we've just removed it from
1380 	 * the hash table in the pool.  We need to make a copy as we
1381 	 * need to derefernece it again later.
1382 	 */
1383 	tmp_iasubopt = test_iasubopt;
1384 	iasubopt_dereference(&tmp_iasubopt, MDL);
1385 
1386       cleanup:
1387 	ia_dereference(&old_ia, MDL);
1388 
1389 	/*
1390 	 * Clean up the reference, this is in addition to the deference
1391 	 * above after removing the entry from the hash table
1392 	 */
1393 	iasubopt_dereference(&test_iasubopt, MDL);
1394 
1395 	return (status);
1396 }
1397 
1398 /*
1399  * Put a lease in the pool directly. This is intended to be used when
1400  * loading leases from the file.
1401  */
1402 isc_result_t
add_lease6(struct ipv6_pool * pool,struct iasubopt * lease,time_t valid_lifetime_end_time)1403 add_lease6(struct ipv6_pool *pool, struct iasubopt *lease,
1404 	   time_t valid_lifetime_end_time) {
1405 	struct iasubopt *test_iasubopt;
1406 	struct iasubopt *tmp_iasubopt;
1407 
1408 	/* If a state was not assigned by the caller, assume active. */
1409 	if (lease->state == 0)
1410 		lease->state = FTS_ACTIVE;
1411 
1412 	ipv6_pool_reference(&lease->ipv6_pool, pool, MDL);
1413 
1414 	/*
1415 	 * If this IAADDR/PREFIX is already in our structures, remove the
1416 	 * old one.
1417 	 */
1418 	test_iasubopt = NULL;
1419 	if (iasubopt_hash_lookup(&test_iasubopt, pool->leases,
1420 				 &lease->addr, sizeof(lease->addr), MDL)) {
1421 		/* XXX: we should probably ask the lease what heap it is on
1422 		 * (as a consistency check).
1423 		 * XXX: we should probably have one function to "put this lease
1424 		 * on its heap" rather than doing these if's everywhere.  If
1425 		 * you add more states to this list, don't.
1426 		 */
1427 		if ((test_iasubopt->state == FTS_ACTIVE) ||
1428 		    (test_iasubopt->state == FTS_ABANDONED)) {
1429 			isc_heap_delete(pool->active_timeouts,
1430 					test_iasubopt->active_index);
1431 			pool->num_active--;
1432 			if (pool->ipv6_pond)
1433 				pool->ipv6_pond->num_active--;
1434 
1435 			if (test_iasubopt->state == FTS_ABANDONED) {
1436 				pool->num_abandoned--;
1437 				if (pool->ipv6_pond)
1438 					pool->ipv6_pond->num_abandoned--;
1439 			}
1440 		} else {
1441 			isc_heap_delete(pool->inactive_timeouts,
1442 					test_iasubopt->inactive_index);
1443 			pool->num_inactive--;
1444 		}
1445 
1446 		iasubopt_hash_delete(pool->leases, &test_iasubopt->addr,
1447 				     sizeof(test_iasubopt->addr), MDL);
1448 
1449 		/*
1450 		 * We're going to do a bit of evil trickery here.
1451 		 *
1452 		 * We need to dereference the entry once to remove our
1453 		 * current reference (in test_iasubopt), and then one
1454 		 * more time to remove the reference left when the
1455 		 * address was added to the pool before.
1456 		 */
1457 		tmp_iasubopt = test_iasubopt;
1458 		iasubopt_dereference(&test_iasubopt, MDL);
1459 		iasubopt_dereference(&tmp_iasubopt, MDL);
1460 	}
1461 
1462 	/*
1463 	 * Add IAADDR/PREFIX to our structures.
1464 	 */
1465 	tmp_iasubopt = NULL;
1466 	iasubopt_reference(&tmp_iasubopt, lease, MDL);
1467 	if ((tmp_iasubopt->state == FTS_ACTIVE) ||
1468 	    (tmp_iasubopt->state == FTS_ABANDONED)) {
1469 		tmp_iasubopt->hard_lifetime_end_time = valid_lifetime_end_time;
1470 		iasubopt_hash_add(pool->leases, &tmp_iasubopt->addr,
1471 				  sizeof(tmp_iasubopt->addr), lease, MDL);
1472 		isc_heap_insert(pool->active_timeouts, tmp_iasubopt);
1473 		pool->num_active++;
1474 		if (pool->ipv6_pond)
1475 			pool->ipv6_pond->num_active++;
1476 
1477 		if (tmp_iasubopt->state == FTS_ABANDONED) {
1478 			pool->num_abandoned++;
1479 			if (pool->ipv6_pond)
1480 				pool->ipv6_pond->num_abandoned++;
1481 		}
1482 
1483 	} else {
1484 		tmp_iasubopt->soft_lifetime_end_time = valid_lifetime_end_time;
1485 		isc_heap_insert(pool->inactive_timeouts, tmp_iasubopt);
1486 		pool->num_inactive++;
1487 	}
1488 	iasubopt_hash_delete(pool->leases, &lease->addr,
1489 			     sizeof(lease->addr), MDL);
1490 	iasubopt_dereference(&tmp_iasubopt, MDL);
1491 	/*
1492 	 * Note: we intentionally leave tmp_iasubopt referenced; there
1493 	 * is a reference in the heap/hash, after all.
1494 	 */
1495 
1496 	return ISC_R_SUCCESS;
1497 }
1498 
1499 /*
1500  * Determine if an address is present in a pool or not.
1501  */
1502 isc_boolean_t
lease6_exists(const struct ipv6_pool * pool,const struct in6_addr * addr)1503 lease6_exists(const struct ipv6_pool *pool, const struct in6_addr *addr) {
1504 	struct iasubopt *test_iaaddr;
1505 
1506 	test_iaaddr = NULL;
1507 	if (iasubopt_hash_lookup(&test_iaaddr, pool->leases,
1508 				 (void *)addr, sizeof(*addr), MDL)) {
1509 		iasubopt_dereference(&test_iaaddr, MDL);
1510 		return ISC_TRUE;
1511 	} else {
1512 		return ISC_FALSE;
1513 	}
1514 }
1515 
1516 /*!
1517  *
1518  * \brief Check if address is available to a lease
1519  *
1520  * Determine if the address in the lease is available to that
1521  * lease.  Either the address isn't in use or it is in use
1522  * but by that lease.
1523  *
1524  * \param[in] lease = lease to check
1525  *
1526  * \return
1527  * ISC_TRUE  = The lease is allowed to use that address
1528  * ISC_FALSE = The lease isn't allowed to use that address
1529  */
1530 isc_boolean_t
lease6_usable(struct iasubopt * lease)1531 lease6_usable(struct iasubopt *lease) {
1532 	struct iasubopt *test_iaaddr;
1533 	isc_boolean_t status = ISC_TRUE;
1534 
1535 	test_iaaddr = NULL;
1536 	if (iasubopt_hash_lookup(&test_iaaddr, lease->ipv6_pool->leases,
1537 				 (void *)&lease->addr,
1538 				 sizeof(lease->addr), MDL)) {
1539 		if (test_iaaddr != lease) {
1540 			status = ISC_FALSE;
1541 		}
1542 		iasubopt_dereference(&test_iaaddr, MDL);
1543 	}
1544 
1545 	return (status);
1546 }
1547 
1548 /*
1549  * Put the lease on our active pool.
1550  */
1551 static isc_result_t
move_lease_to_active(struct ipv6_pool * pool,struct iasubopt * lease)1552 move_lease_to_active(struct ipv6_pool *pool, struct iasubopt *lease) {
1553 	isc_heap_insert(pool->active_timeouts, lease);
1554 	iasubopt_hash_add(pool->leases, &lease->addr,
1555 			  sizeof(lease->addr), lease, MDL);
1556 	isc_heap_delete(pool->inactive_timeouts,
1557 			lease->inactive_index);
1558 	pool->num_active++;
1559 	pool->num_inactive--;
1560 	lease->state = FTS_ACTIVE;
1561 	if (pool->ipv6_pond)
1562 		pool->ipv6_pond->num_active++;
1563 
1564 	return ISC_R_SUCCESS;
1565 }
1566 
1567 /*!
1568  *
1569  * \brief Renew a lease in the pool.
1570  *
1571  * The hard_lifetime_end_time of the lease should be set to
1572  * the current expiration time.
1573  * The soft_lifetime_end_time of the lease should be set to
1574  * the desired expiration time.
1575  *
1576  * This routine will compare the two and call the correct
1577  * heap routine to move the lease.  If the lease is active
1578  * and the new expiration time is greater (the normal case)
1579  * then we call isc_heap_decreased() as a larger time is a
1580  * lower priority.  If the new expiration time is less then
1581  * we call isc_heap_increased().
1582  *
1583  * If the lease is abandoned then it will be on the active list
1584  * and we will always call isc_heap_increased() as the previous
1585  * expiration would have been all 1s (as close as we can get
1586  * to infinite).
1587  *
1588  * If the lease is moving to active we call that routine
1589  * which will move it from the inactive list to the active list.
1590  *
1591  * \param pool  = a pool the lease belongs to
1592  * \param lease = the lease to be renewed
1593  *
1594  * \return result of the renew operation (ISC_R_SUCCESS if successful,
1595            ISC_R_NOMEMORY when run out of memory)
1596  */
1597 isc_result_t
renew_lease6(struct ipv6_pool * pool,struct iasubopt * lease)1598 renew_lease6(struct ipv6_pool *pool, struct iasubopt *lease) {
1599 	time_t old_end_time = lease->hard_lifetime_end_time;
1600 	lease->hard_lifetime_end_time = lease->soft_lifetime_end_time;
1601 	lease->soft_lifetime_end_time = 0;
1602 
1603 	if (lease->state == FTS_ACTIVE) {
1604 		if (old_end_time <= lease->hard_lifetime_end_time) {
1605 			isc_heap_decreased(pool->active_timeouts,
1606 					   lease->active_index);
1607 		} else {
1608 			isc_heap_increased(pool->active_timeouts,
1609 					   lease->active_index);
1610 		}
1611 		return ISC_R_SUCCESS;
1612 	} else if (lease->state == FTS_ABANDONED) {
1613 		char tmp_addr[INET6_ADDRSTRLEN];
1614                 lease->state = FTS_ACTIVE;
1615                 isc_heap_increased(pool->active_timeouts, lease->active_index);
1616 		log_info("Reclaiming previously abandoned address %s",
1617 			 inet_ntop(AF_INET6, &(lease->addr), tmp_addr,
1618 				   sizeof(tmp_addr)));
1619 
1620 		pool->num_abandoned--;
1621 		if (pool->ipv6_pond)
1622 			pool->ipv6_pond->num_abandoned--;
1623 
1624                 return ISC_R_SUCCESS;
1625 	} else {
1626 		return move_lease_to_active(pool, lease);
1627 	}
1628 }
1629 
1630 /*
1631  * Put the lease on our inactive pool, with the specified state.
1632  */
1633 static isc_result_t
move_lease_to_inactive(struct ipv6_pool * pool,struct iasubopt * lease,binding_state_t state)1634 move_lease_to_inactive(struct ipv6_pool *pool, struct iasubopt *lease,
1635 		       binding_state_t state) {
1636 
1637 	isc_heap_insert(pool->inactive_timeouts, lease);
1638 	/*
1639 	 * Handle expire and release statements
1640 	 * To get here we must be active and have done a commit so
1641 	 * we should run the proper statements if they exist, though
1642 	 * that will change when we remove the inactive heap.
1643 	 * In addition we get rid of the references for both as we
1644 	 * can only do one (expire or release) on a lease
1645 	 */
1646 	if (lease->on_star.on_expiry != NULL) {
1647 		if (state == FTS_EXPIRED) {
1648 			execute_statements(NULL, NULL, NULL,
1649 					   NULL, NULL, NULL,
1650 					   &lease->scope,
1651 					   lease->on_star.on_expiry,
1652 					   &lease->on_star);
1653 		}
1654 		executable_statement_dereference
1655 			(&lease->on_star.on_expiry, MDL);
1656 	}
1657 
1658 	if (lease->on_star.on_release != NULL) {
1659 		if (state == FTS_RELEASED) {
1660 			execute_statements(NULL, NULL, NULL,
1661 					   NULL, NULL, NULL,
1662 					   &lease->scope,
1663 					   lease->on_star.on_release,
1664 					   &lease->on_star);
1665 		}
1666 		executable_statement_dereference
1667 			(&lease->on_star.on_release, MDL);
1668 	}
1669 
1670 #if defined (NSUPDATE)
1671 	/* Process events upon expiration. */
1672 	if (pool->pool_type != D6O_IA_PD) {
1673 		(void) ddns_removals(NULL, lease, NULL, ISC_FALSE);
1674 	}
1675 #endif
1676 
1677 	/* Binding scopes are no longer valid after expiry or
1678 	 * release.
1679 	 */
1680 	if (lease->scope != NULL) {
1681 		binding_scope_dereference(&lease->scope, MDL);
1682 	}
1683 
1684 	iasubopt_hash_delete(pool->leases,
1685 			     &lease->addr, sizeof(lease->addr), MDL);
1686 	isc_heap_delete(pool->active_timeouts, lease->active_index);
1687 	lease->state = state;
1688 	pool->num_active--;
1689 	pool->num_inactive++;
1690 	if (pool->ipv6_pond)
1691 		pool->ipv6_pond->num_active--;
1692 
1693 	if (lease->state == FTS_ABANDONED) {
1694 		pool->num_abandoned--;
1695 		if (pool->ipv6_pond)
1696 			pool->ipv6_pond->num_abandoned--;
1697 	}
1698 	return ISC_R_SUCCESS;
1699 }
1700 
1701 /*
1702  * Expire the oldest lease if it's lifetime_end_time is
1703  * older than the given time.
1704  *
1705  * - leasep must be a pointer to a (struct iasubopt *) pointer previously
1706  *   initialized to NULL
1707  *
1708  * On return leasep has a reference to the removed entry. It is left
1709  * pointing to NULL if the oldest lease has not expired.
1710  */
1711 isc_result_t
expire_lease6(struct iasubopt ** leasep,struct ipv6_pool * pool,time_t now)1712 expire_lease6(struct iasubopt **leasep, struct ipv6_pool *pool, time_t now) {
1713 	struct iasubopt *tmp;
1714 	isc_result_t result;
1715 
1716 	if (leasep == NULL) {
1717 		log_error("%s(%d): NULL pointer reference", MDL);
1718 		return DHCP_R_INVALIDARG;
1719 	}
1720 	if (*leasep != NULL) {
1721 		log_error("%s(%d): non-NULL pointer", MDL);
1722 		return DHCP_R_INVALIDARG;
1723 	}
1724 
1725 	if (pool->num_active > 0) {
1726 		tmp = (struct iasubopt *)
1727 				isc_heap_element(pool->active_timeouts, 1);
1728 		if (now > tmp->hard_lifetime_end_time) {
1729 			result = move_lease_to_inactive(pool, tmp,
1730 							FTS_EXPIRED);
1731 			if (result == ISC_R_SUCCESS) {
1732 				iasubopt_reference(leasep, tmp, MDL);
1733 			}
1734 			return result;
1735 		}
1736 	}
1737 	return ISC_R_SUCCESS;
1738 }
1739 
1740 
1741 /*
1742  * For a declined lease, leave it on the "active" pool, but mark
1743  * it as declined. Give it an infinite (well, really long) life.
1744  */
1745 isc_result_t
decline_lease6(struct ipv6_pool * pool,struct iasubopt * lease)1746 decline_lease6(struct ipv6_pool *pool, struct iasubopt *lease) {
1747 	isc_result_t result;
1748 
1749 	if ((lease->state != FTS_ACTIVE) &&
1750 	    (lease->state != FTS_ABANDONED)) {
1751 		result = move_lease_to_active(pool, lease);
1752 		if (result != ISC_R_SUCCESS) {
1753 			return result;
1754 		}
1755 	}
1756 	lease->state = FTS_ABANDONED;
1757 
1758 	pool->num_abandoned++;
1759 	if (pool->ipv6_pond)
1760 		pool->ipv6_pond->num_abandoned++;
1761 
1762 	lease->hard_lifetime_end_time = MAX_TIME;
1763 	isc_heap_decreased(pool->active_timeouts, lease->active_index);
1764 	return ISC_R_SUCCESS;
1765 }
1766 
1767 /*
1768  * Put the returned lease on our inactive pool.
1769  */
1770 isc_result_t
release_lease6(struct ipv6_pool * pool,struct iasubopt * lease)1771 release_lease6(struct ipv6_pool *pool, struct iasubopt *lease) {
1772 	if (lease->state == FTS_ACTIVE) {
1773 		return move_lease_to_inactive(pool, lease, FTS_RELEASED);
1774 	} else {
1775 		return ISC_R_SUCCESS;
1776 	}
1777 }
1778 
1779 /*
1780  * Create a prefix by hashing the input, and using that for
1781  * the part subject to allocation.
1782  */
1783 static void
build_prefix6(struct in6_addr * pref,const struct in6_addr * net_start_pref,int pool_bits,int pref_bits,const struct data_string * input)1784 build_prefix6(struct in6_addr *pref,
1785 	      const struct in6_addr *net_start_pref,
1786 	      int pool_bits, int pref_bits,
1787 	      const struct data_string *input) {
1788 	int net_bytes;
1789 	int i;
1790 	unsigned int len;
1791 	char *str;
1792 	const char *net_str;
1793 
1794 	/*
1795 	 * Use MD5 to get a nice 128 bit hash of the input.
1796 	 * Yes, we know MD5 isn't cryptographically sound.
1797 	 * No, we don't care.
1798 	 */
1799 	isc_md(ISC_MD_MD5, input->data, input->len, (void *)&pref, &len);
1800 
1801 	/*
1802 	 * Copy the network bits over.
1803 	 */
1804 	str = (char *)pref;
1805 	net_str = (const char *)net_start_pref;
1806 	net_bytes = pool_bits / 8;
1807 	for (i = 0; i < net_bytes; i++) {
1808 		str[i] = net_str[i];
1809 	}
1810 	i = net_bytes;
1811 	switch (pool_bits % 8) {
1812 		case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
1813 		case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
1814 		case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break;
1815 		case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break;
1816 		case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break;
1817 		case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break;
1818 		case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break;
1819 	}
1820 	/*
1821 	 * Zero the remaining bits.
1822 	 */
1823 	net_bytes = pref_bits / 8;
1824 	for (i=net_bytes+1; i<16; i++) {
1825 		str[i] = 0;
1826 	}
1827 	i = net_bytes;
1828 	switch (pref_bits % 8) {
1829 		case 0: str[i] &= 0; break;
1830 		case 1: str[i] &= 0x80; break;
1831 		case 2: str[i] &= 0xC0; break;
1832 		case 3: str[i] &= 0xE0; break;
1833 		case 4: str[i] &= 0xF0; break;
1834 		case 5: str[i] &= 0xF8; break;
1835 		case 6: str[i] &= 0xFC; break;
1836 		case 7: str[i] &= 0xFE; break;
1837 	}
1838 }
1839 
1840 /*
1841  * Create a lease for the given prefix and client duid.
1842  *
1843  * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
1844  *   initialized to NULL
1845  *
1846  * Right now we simply hash the DUID, and if we get a collision, we hash
1847  * again until we find a free prefix. We try this a fixed number of times,
1848  * to avoid getting stuck in a loop (this is important on small pools
1849  * where we can run out of space).
1850  *
1851  * We return the number of attempts that it took to find an available
1852  * prefix. This tells callers when a pool is are filling up, as
1853  * well as an indication of how full the pool is; statistically the
1854  * more full a pool is the more attempts must be made before finding
1855  * a free prefix. Realistically this will only happen in very full
1856  * pools.
1857  *
1858  * We probably want different algorithms depending on the network size, in
1859  * the long term.
1860  */
1861 isc_result_t
create_prefix6(struct ipv6_pool * pool,struct iasubopt ** pref,unsigned int * attempts,const struct data_string * uid,time_t soft_lifetime_end_time)1862 create_prefix6(struct ipv6_pool *pool, struct iasubopt **pref,
1863 	       unsigned int *attempts,
1864 	       const struct data_string *uid,
1865 	       time_t soft_lifetime_end_time) {
1866 	struct data_string ds;
1867 	struct in6_addr tmp;
1868 	struct iasubopt *test_iapref;
1869 	struct data_string new_ds;
1870 	struct iasubopt *iapref;
1871 	isc_result_t result;
1872 
1873 	/*
1874 	 * Use the UID as our initial seed for the hash
1875 	 */
1876 	memset(&ds, 0, sizeof(ds));
1877 	data_string_copy(&ds, (struct data_string *)uid, MDL);
1878 
1879 	*attempts = 0;
1880 	for (;;) {
1881 		/*
1882 		 * Give up at some point.
1883 		 */
1884 		if (++(*attempts) > 10) {
1885 			data_string_forget(&ds, MDL);
1886 			return ISC_R_NORESOURCES;
1887 		}
1888 
1889 		/*
1890 		 * Build a prefix
1891 		 */
1892 		build_prefix6(&tmp, &pool->start_addr,
1893 			      pool->bits, pool->units, &ds);
1894 
1895 		/*
1896 		 * If this prefix is not in use, we're happy with it
1897 		 */
1898 		test_iapref = NULL;
1899 		if (iasubopt_hash_lookup(&test_iapref, pool->leases,
1900 					 &tmp, sizeof(tmp), MDL) == 0) {
1901 			break;
1902 		}
1903 		iasubopt_dereference(&test_iapref, MDL);
1904 
1905 		/*
1906 		 * Otherwise, we create a new input, adding the prefix
1907 		 */
1908 		memset(&new_ds, 0, sizeof(new_ds));
1909 		new_ds.len = ds.len + sizeof(tmp);
1910 		if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) {
1911 			data_string_forget(&ds, MDL);
1912 			return ISC_R_NOMEMORY;
1913 		}
1914 		new_ds.data = new_ds.buffer->data;
1915 		memcpy(new_ds.buffer->data, ds.data, ds.len);
1916 		memcpy(&new_ds.buffer->data[0] + ds.len, &tmp, sizeof(tmp));
1917 		data_string_forget(&ds, MDL);
1918 		data_string_copy(&ds, &new_ds, MDL);
1919 		data_string_forget(&new_ds, MDL);
1920 	}
1921 
1922 	data_string_forget(&ds, MDL);
1923 
1924 	/*
1925 	 * We're happy with the prefix, create an IAPREFIX
1926 	 * to hold it.
1927 	 */
1928 	iapref = NULL;
1929 	result = iasubopt_allocate(&iapref, MDL);
1930 	if (result != ISC_R_SUCCESS) {
1931 		return result;
1932 	}
1933 	iapref->plen = (u_int8_t)pool->units;
1934 	memcpy(&iapref->addr, &tmp, sizeof(iapref->addr));
1935 
1936 	/*
1937 	 * Add the prefix to the pool (note state is free, not active?!).
1938 	 */
1939 	result = add_lease6(pool, iapref, soft_lifetime_end_time);
1940 	if (result == ISC_R_SUCCESS) {
1941 		iasubopt_reference(pref, iapref, MDL);
1942 	}
1943 	iasubopt_dereference(&iapref, MDL);
1944 	return result;
1945 }
1946 
1947 /*
1948  * Determine if a prefix is present in a pool or not.
1949  */
1950 isc_boolean_t
prefix6_exists(const struct ipv6_pool * pool,const struct in6_addr * pref,u_int8_t plen)1951 prefix6_exists(const struct ipv6_pool *pool,
1952 	       const struct in6_addr *pref, u_int8_t plen) {
1953 	struct iasubopt *test_iapref;
1954 
1955 	if ((int)plen != pool->units)
1956 		return ISC_FALSE;
1957 
1958 	test_iapref = NULL;
1959 	if (iasubopt_hash_lookup(&test_iapref, pool->leases,
1960 				 (void *)pref, sizeof(*pref), MDL)) {
1961 		iasubopt_dereference(&test_iapref, MDL);
1962 		return ISC_TRUE;
1963 	} else {
1964 		return ISC_FALSE;
1965 	}
1966 }
1967 
1968 /*
1969  * Mark an IPv6 address/prefix as unavailable from a pool.
1970  *
1971  * This is used for host entries and the addresses of the server itself.
1972  */
1973 static isc_result_t
mark_lease_unavailable(struct ipv6_pool * pool,const struct in6_addr * addr)1974 mark_lease_unavailable(struct ipv6_pool *pool, const struct in6_addr *addr) {
1975 	struct iasubopt *dummy_iasubopt;
1976 	isc_result_t result;
1977 
1978 	dummy_iasubopt = NULL;
1979 	result = iasubopt_allocate(&dummy_iasubopt, MDL);
1980 	if (result == ISC_R_SUCCESS) {
1981 		dummy_iasubopt->addr = *addr;
1982 		iasubopt_hash_add(pool->leases, &dummy_iasubopt->addr,
1983 				  sizeof(*addr), dummy_iasubopt, MDL);
1984 	}
1985 	return result;
1986 }
1987 
1988 /*
1989  * Add a pool.
1990  */
1991 isc_result_t
add_ipv6_pool(struct ipv6_pool * pool)1992 add_ipv6_pool(struct ipv6_pool *pool) {
1993 	struct ipv6_pool **new_pools;
1994 
1995 	new_pools = dmalloc(sizeof(struct ipv6_pool *) * (num_pools+1), MDL);
1996 	if (new_pools == NULL) {
1997 		return ISC_R_NOMEMORY;
1998 	}
1999 
2000 	if (num_pools > 0) {
2001 		memcpy(new_pools, pools,
2002 		       sizeof(struct ipv6_pool *) * num_pools);
2003 		dfree(pools, MDL);
2004 	}
2005 	pools = new_pools;
2006 
2007 	pools[num_pools] = NULL;
2008 	ipv6_pool_reference(&pools[num_pools], pool, MDL);
2009 	num_pools++;
2010 	return ISC_R_SUCCESS;
2011 }
2012 
2013 static void
cleanup_old_expired(struct ipv6_pool * pool)2014 cleanup_old_expired(struct ipv6_pool *pool) {
2015 	struct iasubopt *tmp;
2016 	struct ia_xx *ia;
2017 	struct ia_xx *ia_active;
2018 	unsigned char *tmpd;
2019 	time_t timeout;
2020 
2021 	while (pool->num_inactive > 0) {
2022 		tmp = (struct iasubopt *)
2023 				isc_heap_element(pool->inactive_timeouts, 1);
2024 		if (tmp->hard_lifetime_end_time != 0) {
2025 			timeout = tmp->hard_lifetime_end_time;
2026 			timeout += EXPIRED_IPV6_CLEANUP_TIME;
2027 		} else {
2028 			timeout = tmp->soft_lifetime_end_time;
2029 		}
2030 		if (cur_time < timeout) {
2031 			break;
2032 		}
2033 
2034 		isc_heap_delete(pool->inactive_timeouts, tmp->inactive_index);
2035 		pool->num_inactive--;
2036 
2037 		if (tmp->ia != NULL) {
2038 			/*
2039 			 * Check to see if this IA is in an active list,
2040 			 * but has no remaining resources. If so, remove it
2041 			 * from the active list.
2042 			 */
2043 			ia = NULL;
2044 			ia_reference(&ia, tmp->ia, MDL);
2045 			ia_remove_iasubopt(ia, tmp, MDL);
2046 			ia_active = NULL;
2047 			tmpd = (unsigned char *)ia->iaid_duid.data;
2048 			if ((ia->ia_type == D6O_IA_NA) &&
2049 			    (ia->num_iasubopt <= 0) &&
2050 			    (ia_hash_lookup(&ia_active, ia_na_active, tmpd,
2051 					    ia->iaid_duid.len, MDL) == 0) &&
2052 			    (ia_active == ia)) {
2053 				ia_hash_delete(ia_na_active, tmpd,
2054 					       ia->iaid_duid.len, MDL);
2055 			}
2056 			if ((ia->ia_type == D6O_IA_TA) &&
2057 			    (ia->num_iasubopt <= 0) &&
2058 			    (ia_hash_lookup(&ia_active, ia_ta_active, tmpd,
2059 					    ia->iaid_duid.len, MDL) == 0) &&
2060 			    (ia_active == ia)) {
2061 				ia_hash_delete(ia_ta_active, tmpd,
2062 					       ia->iaid_duid.len, MDL);
2063 			}
2064 			if ((ia->ia_type == D6O_IA_PD) &&
2065 			    (ia->num_iasubopt <= 0) &&
2066 			    (ia_hash_lookup(&ia_active, ia_pd_active, tmpd,
2067 					    ia->iaid_duid.len, MDL) == 0) &&
2068 			    (ia_active == ia)) {
2069 				ia_hash_delete(ia_pd_active, tmpd,
2070 					       ia->iaid_duid.len, MDL);
2071 			}
2072 			ia_dereference(&ia, MDL);
2073 		}
2074 		iasubopt_dereference(&tmp, MDL);
2075 	}
2076 }
2077 
2078 static void
lease_timeout_support(void * vpool)2079 lease_timeout_support(void *vpool) {
2080 	struct ipv6_pool *pool;
2081 	struct iasubopt *lease;
2082 
2083 	pool = (struct ipv6_pool *)vpool;
2084 	for (;;) {
2085 		/*
2086 		 * Get the next lease scheduled to expire.
2087 		 *
2088 		 * Note that if there are no leases in the pool,
2089 		 * expire_lease6() will return ISC_R_SUCCESS with
2090 		 * a NULL lease.
2091 		 *
2092 		 * expire_lease6() will call move_lease_to_inactive() which
2093 		 * calls ddns_removals() do we want that on the standard
2094 		 * expiration timer or a special 'depref' timer?  Original
2095 		 * query from DH, moved here by SAR.
2096 		 */
2097 		lease = NULL;
2098 		if (expire_lease6(&lease, pool, cur_time) != ISC_R_SUCCESS) {
2099 			break;
2100 		}
2101 		if (lease == NULL) {
2102 			break;
2103 		}
2104 
2105 		write_ia(lease->ia);
2106 
2107 		iasubopt_dereference(&lease, MDL);
2108 	}
2109 
2110 	/*
2111 	 * If appropriate commit and rotate the lease file
2112 	 * As commit_leases_timed() checks to see if we've done any writes
2113 	 * we don't bother tracking if this function called write _ia
2114 	 */
2115 	(void) commit_leases_timed();
2116 
2117 	/*
2118 	 * Do some cleanup of our expired leases.
2119 	 */
2120 	cleanup_old_expired(pool);
2121 
2122 	/*
2123 	 * Schedule next round of expirations.
2124 	 */
2125 	schedule_lease_timeout(pool);
2126 }
2127 
2128 /*
2129  * For a given pool, add a timer that will remove the next
2130  * lease to expire.
2131  */
2132 void
schedule_lease_timeout(struct ipv6_pool * pool)2133 schedule_lease_timeout(struct ipv6_pool *pool) {
2134 	struct iasubopt *tmp;
2135 	time_t timeout;
2136 	time_t next_timeout;
2137 	struct timeval tv;
2138 
2139 	next_timeout = MAX_TIME;
2140 
2141 	if (pool->num_active > 0) {
2142 		tmp = (struct iasubopt *)
2143 				isc_heap_element(pool->active_timeouts, 1);
2144 		if (tmp->hard_lifetime_end_time < next_timeout) {
2145 			next_timeout = tmp->hard_lifetime_end_time + 1;
2146 		}
2147 	}
2148 
2149 	if (pool->num_inactive > 0) {
2150 		tmp = (struct iasubopt *)
2151 				isc_heap_element(pool->inactive_timeouts, 1);
2152 		if (tmp->hard_lifetime_end_time != 0) {
2153 			timeout = tmp->hard_lifetime_end_time;
2154 			timeout += EXPIRED_IPV6_CLEANUP_TIME;
2155 		} else {
2156 			timeout = tmp->soft_lifetime_end_time + 1;
2157 		}
2158 		if (timeout < next_timeout) {
2159 			next_timeout = timeout;
2160 		}
2161 	}
2162 
2163 	if (next_timeout < MAX_TIME) {
2164 		tv.tv_sec = next_timeout;
2165 		tv.tv_usec = 0;
2166 		add_timeout(&tv, lease_timeout_support, pool,
2167 			    (tvref_t)ipv6_pool_reference,
2168 			    (tvunref_t)ipv6_pool_dereference);
2169 	}
2170 }
2171 
2172 /*
2173  * Schedule timeouts across all pools.
2174  */
2175 void
schedule_all_ipv6_lease_timeouts(void)2176 schedule_all_ipv6_lease_timeouts(void) {
2177 	int i;
2178 
2179 	for (i=0; i<num_pools; i++) {
2180 		schedule_lease_timeout(pools[i]);
2181 	}
2182 }
2183 
2184 /*
2185  * Given an address and the length of the network mask, return
2186  * only the network portion.
2187  *
2188  * Examples:
2189  *
2190  *   "fe80::216:6fff:fe49:7d9b", length 64 = "fe80::"
2191  *   "2001:888:1936:2:216:6fff:fe49:7d9b", length 48 = "2001:888:1936::"
2192  */
2193 static void
ipv6_network_portion(struct in6_addr * result,const struct in6_addr * addr,int bits)2194 ipv6_network_portion(struct in6_addr *result,
2195 		     const struct in6_addr *addr, int bits) {
2196 	unsigned char *addrp;
2197 	int mask_bits;
2198 	int bytes;
2199 	int extra_bits;
2200 	int i;
2201 
2202 	static const unsigned char bitmasks[] = {
2203 		0x00, 0xFE, 0xFC, 0xF8,
2204 		0xF0, 0xE0, 0xC0, 0x80,
2205 	};
2206 
2207 	/*
2208 	 *  Sanity check our bits. ;)
2209 	 */
2210 	if ((bits < 0) || (bits > 128)) {
2211 		log_fatal("ipv6_network_portion: bits %d not between 0 and 128",
2212 			  bits);
2213 	}
2214 
2215 	/*
2216 	 * Copy our address portion.
2217 	 */
2218 	*result = *addr;
2219 	addrp = ((unsigned char *)result) + 15;
2220 
2221 	/*
2222 	 * Zero out masked portion.
2223 	 */
2224 	mask_bits = 128 - bits;
2225 	bytes = mask_bits / 8;
2226 	extra_bits = mask_bits % 8;
2227 
2228 	for (i=0; i<bytes; i++) {
2229 		*addrp = 0;
2230 		addrp--;
2231 	}
2232 	if (extra_bits) {
2233 		*addrp &= bitmasks[extra_bits];
2234 	}
2235 }
2236 
2237 /*
2238  * Determine if the given address/prefix is in the pool.
2239  */
2240 isc_boolean_t
ipv6_in_pool(const struct in6_addr * addr,const struct ipv6_pool * pool)2241 ipv6_in_pool(const struct in6_addr *addr, const struct ipv6_pool *pool) {
2242 	struct in6_addr tmp;
2243 
2244 	ipv6_network_portion(&tmp, addr, pool->bits);
2245 	if (memcmp(&tmp, &pool->start_addr, sizeof(tmp)) == 0) {
2246 		return ISC_TRUE;
2247 	} else {
2248 		return ISC_FALSE;
2249 	}
2250 }
2251 
2252 /*
2253  * Find the pool that contains the given address.
2254  *
2255  * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
2256  *   initialized to NULL
2257  */
2258 isc_result_t
find_ipv6_pool(struct ipv6_pool ** pool,u_int16_t type,const struct in6_addr * addr)2259 find_ipv6_pool(struct ipv6_pool **pool, u_int16_t type,
2260 	       const struct in6_addr *addr) {
2261 	int i;
2262 
2263 	if (pool == NULL) {
2264 		log_error("%s(%d): NULL pointer reference", MDL);
2265 		return DHCP_R_INVALIDARG;
2266 	}
2267 	if (*pool != NULL) {
2268 		log_error("%s(%d): non-NULL pointer", MDL);
2269 		return DHCP_R_INVALIDARG;
2270 	}
2271 
2272 	for (i=0; i<num_pools; i++) {
2273 		if (pools[i]->pool_type != type)
2274 			continue;
2275 		if (ipv6_in_pool(addr, pools[i])) {
2276 			ipv6_pool_reference(pool, pools[i], MDL);
2277 			return ISC_R_SUCCESS;
2278 		}
2279 	}
2280 	return ISC_R_NOTFOUND;
2281 }
2282 
2283 /*
2284  * Helper function for the various functions that act across all
2285  * pools.
2286  */
2287 static isc_result_t
change_leases(struct ia_xx * ia,isc_result_t (* change_func)(struct ipv6_pool *,struct iasubopt *))2288 change_leases(struct ia_xx *ia,
2289 	      isc_result_t (*change_func)(struct ipv6_pool *,
2290 					  struct iasubopt *)) {
2291 	isc_result_t retval;
2292 	isc_result_t renew_retval;
2293 	struct ipv6_pool *pool;
2294 	struct in6_addr *addr;
2295 	int i;
2296 
2297 	retval = ISC_R_SUCCESS;
2298 	for (i=0; i<ia->num_iasubopt; i++) {
2299 		pool = NULL;
2300 		addr = &ia->iasubopt[i]->addr;
2301 		if (find_ipv6_pool(&pool, ia->ia_type,
2302 				   addr) == ISC_R_SUCCESS) {
2303 			renew_retval = change_func(pool, ia->iasubopt[i]);
2304 			if (renew_retval != ISC_R_SUCCESS) {
2305 				retval = renew_retval;
2306 			}
2307 		}
2308 		/* XXXsk: should we warn if we don't find a pool? */
2309 	}
2310 	return retval;
2311 }
2312 
2313 /*
2314  * Renew all leases in an IA from all pools.
2315  *
2316  * The new lifetime should be in the soft_lifetime_end_time
2317  * and will be moved to hard_lifetime_end_time by renew_lease6.
2318  */
2319 isc_result_t
renew_leases(struct ia_xx * ia)2320 renew_leases(struct ia_xx *ia) {
2321 	return change_leases(ia, renew_lease6);
2322 }
2323 
2324 /*
2325  * Release all leases in an IA from all pools.
2326  */
2327 isc_result_t
release_leases(struct ia_xx * ia)2328 release_leases(struct ia_xx *ia) {
2329 	return change_leases(ia, release_lease6);
2330 }
2331 
2332 /*
2333  * Decline all leases in an IA from all pools.
2334  */
2335 isc_result_t
decline_leases(struct ia_xx * ia)2336 decline_leases(struct ia_xx *ia) {
2337 	return change_leases(ia, decline_lease6);
2338 }
2339 
2340 #ifdef DHCPv6
2341 /*
2342  * Helper function to output leases.
2343  */
2344 static int write_error;
2345 
2346 static isc_result_t
write_ia_leases(const void * name,unsigned len,void * value)2347 write_ia_leases(const void *name, unsigned len, void *value) {
2348 	struct ia_xx *ia = (struct ia_xx *)value;
2349 
2350 	if (!write_error) {
2351 		if (!write_ia(ia)) {
2352 			write_error = 1;
2353 		}
2354 	}
2355 	return ISC_R_SUCCESS;
2356 }
2357 
2358 /*
2359  * Write all DHCPv6 information.
2360  */
2361 int
write_leases6(void)2362 write_leases6(void) {
2363 	int nas, tas, pds;
2364 
2365 	write_error = 0;
2366 	write_server_duid();
2367 	nas = ia_hash_foreach(ia_na_active, write_ia_leases);
2368 	if (write_error) {
2369 		return 0;
2370 	}
2371 	tas = ia_hash_foreach(ia_ta_active, write_ia_leases);
2372 	if (write_error) {
2373 		return 0;
2374 	}
2375 	pds = ia_hash_foreach(ia_pd_active, write_ia_leases);
2376 	if (write_error) {
2377 		return 0;
2378 	}
2379 
2380 	log_info("Wrote %d NA, %d TA, %d PD leases to lease file.",
2381 		 nas, tas, pds);
2382 	return 1;
2383 }
2384 #endif /* DHCPv6 */
2385 
2386 static isc_result_t
mark_hosts_unavailable_support(const void * name,unsigned len,void * value)2387 mark_hosts_unavailable_support(const void *name, unsigned len, void *value) {
2388 	struct host_decl *h;
2389 	struct data_string fixed_addr;
2390 	struct in6_addr addr;
2391 	struct ipv6_pool *p;
2392 
2393 	h = (struct host_decl *)value;
2394 
2395 	/*
2396 	 * If the host has no address, we don't need to mark anything.
2397 	 */
2398 	if (h->fixed_addr == NULL) {
2399 		return ISC_R_SUCCESS;
2400 	}
2401 
2402 	/*
2403 	 * Evaluate the fixed address.
2404 	 */
2405 	memset(&fixed_addr, 0, sizeof(fixed_addr));
2406 	if (!evaluate_option_cache(&fixed_addr, NULL, NULL, NULL, NULL, NULL,
2407 				   &global_scope, h->fixed_addr, MDL)) {
2408 		log_error("mark_hosts_unavailable: "
2409 			  "error evaluating host address.");
2410 		return ISC_R_SUCCESS;
2411 	}
2412 	if (fixed_addr.len != 16) {
2413 		log_error("mark_hosts_unavailable: "
2414 			  "host address is not 128 bits.");
2415 		return ISC_R_SUCCESS;
2416 	}
2417 	memcpy(&addr, fixed_addr.data, 16);
2418 	data_string_forget(&fixed_addr, MDL);
2419 
2420 	/*
2421 	 * Find the pool holding this host, and mark the address.
2422 	 * (I suppose it is arguably valid to have a host that does not
2423 	 * sit in any pool.)
2424 	 */
2425 	p = NULL;
2426 	if (find_ipv6_pool(&p, D6O_IA_NA, &addr) == ISC_R_SUCCESS) {
2427 		mark_lease_unavailable(p, &addr);
2428 		ipv6_pool_dereference(&p, MDL);
2429 	}
2430 	if (find_ipv6_pool(&p, D6O_IA_TA, &addr) == ISC_R_SUCCESS) {
2431 		mark_lease_unavailable(p, &addr);
2432 		ipv6_pool_dereference(&p, MDL);
2433 	}
2434 
2435 	return ISC_R_SUCCESS;
2436 }
2437 
2438 void
mark_hosts_unavailable(void)2439 mark_hosts_unavailable(void) {
2440 	hash_foreach(host_name_hash, mark_hosts_unavailable_support);
2441 }
2442 
2443 static isc_result_t
mark_phosts_unavailable_support(const void * name,unsigned len,void * value)2444 mark_phosts_unavailable_support(const void *name, unsigned len, void *value) {
2445 	struct host_decl *h;
2446 	struct iaddrcidrnetlist *l;
2447 	struct in6_addr pref;
2448 	struct ipv6_pool *p;
2449 
2450 	h = (struct host_decl *)value;
2451 
2452 	/*
2453 	 * If the host has no prefix, we don't need to mark anything.
2454 	 */
2455 	if (h->fixed_prefix == NULL) {
2456 		return ISC_R_SUCCESS;
2457 	}
2458 
2459 	/*
2460 	 * Get the fixed prefixes.
2461 	 */
2462 	for (l = h->fixed_prefix; l != NULL; l = l->next) {
2463 		if (l->cidrnet.lo_addr.len != 16) {
2464 			continue;
2465 		}
2466 		memcpy(&pref, l->cidrnet.lo_addr.iabuf, 16);
2467 
2468 		/*
2469 		 * Find the pool holding this host, and mark the prefix.
2470 		 * (I suppose it is arguably valid to have a host that does not
2471 		 * sit in any pool.)
2472 		 */
2473 		p = NULL;
2474 		if (find_ipv6_pool(&p, D6O_IA_PD, &pref) != ISC_R_SUCCESS) {
2475 			continue;
2476 		}
2477 		if (l->cidrnet.bits != p->units) {
2478 			ipv6_pool_dereference(&p, MDL);
2479 			continue;
2480 		}
2481 		mark_lease_unavailable(p, &pref);
2482 		ipv6_pool_dereference(&p, MDL);
2483 	}
2484 
2485 	return ISC_R_SUCCESS;
2486 }
2487 
2488 void
mark_phosts_unavailable(void)2489 mark_phosts_unavailable(void) {
2490 	hash_foreach(host_name_hash, mark_phosts_unavailable_support);
2491 }
2492 
2493 void
mark_interfaces_unavailable(void)2494 mark_interfaces_unavailable(void) {
2495 	struct interface_info *ip;
2496 	int i;
2497 	struct ipv6_pool *p;
2498 
2499 	ip = interfaces;
2500 	while (ip != NULL) {
2501 		for (i=0; i<ip->v6address_count; i++) {
2502 			p = NULL;
2503 			if (find_ipv6_pool(&p, D6O_IA_NA, &ip->v6addresses[i])
2504 							== ISC_R_SUCCESS) {
2505 				mark_lease_unavailable(p,
2506 						       &ip->v6addresses[i]);
2507 				ipv6_pool_dereference(&p, MDL);
2508 			}
2509 			if (find_ipv6_pool(&p, D6O_IA_TA, &ip->v6addresses[i])
2510 							== ISC_R_SUCCESS) {
2511 				mark_lease_unavailable(p,
2512 						       &ip->v6addresses[i]);
2513 				ipv6_pool_dereference(&p, MDL);
2514 			}
2515 		}
2516 		ip = ip->next;
2517 	}
2518 }
2519 
2520 /*!
2521  * \brief Create a new IPv6 pond structure.
2522  *
2523  * Allocate space for a new ipv6_pond structure and return a reference
2524  * to it, includes setting the reference count to 1.
2525  *
2526  * \param pond = space for returning a referenced pointer to the pond.
2527  *		 This must point to a space that has been initialzied
2528  *		 to NULL by the caller.
2529  *
2530  * \return
2531  * ISC_R_SUCCESS     = The pond was successfully created, pond points to it.
2532  * DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been
2533  *		       modified
2534  * ISC_R_NOMEMORY    = The system wasn't able to allocate memory, pond has
2535  *		       not been modified.
2536  */
2537 isc_result_t
ipv6_pond_allocate(struct ipv6_pond ** pond,const char * file,int line)2538 ipv6_pond_allocate(struct ipv6_pond **pond, const char *file, int line) {
2539 	struct ipv6_pond *tmp;
2540 
2541 	if (pond == NULL) {
2542 		log_error("%s(%d): NULL pointer reference", file, line);
2543 		return DHCP_R_INVALIDARG;
2544 	}
2545 	if (*pond != NULL) {
2546 		log_error("%s(%d): non-NULL pointer", file, line);
2547 		return DHCP_R_INVALIDARG;
2548 	}
2549 
2550 	tmp = dmalloc(sizeof(*tmp), file, line);
2551 	if (tmp == NULL) {
2552 		return ISC_R_NOMEMORY;
2553 	}
2554 
2555 	tmp->refcnt = 1;
2556 
2557 	*pond = tmp;
2558 	return ISC_R_SUCCESS;
2559 }
2560 
2561 /*!
2562  *
2563  * \brief reference an IPv6 pond structure.
2564  *
2565  * This function genreates a reference to an ipv6_pond structure
2566  * and increments the reference count on the structure.
2567  *
2568  * \param[out] pond = space for returning a referenced pointer to the pond.
2569  *		      This must point to a space that has been initialzied
2570  *		      to NULL by the caller.
2571  * \param[in]  src  = A pointer to the pond to reference.  This must not be
2572  *		      NULL.
2573  *
2574  * \return
2575  * ISC_R_SUCCESS     = The pond was successfully referenced, pond now points
2576  *		       to src.
2577  * DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been
2578  *		       modified.
2579  */
2580 isc_result_t
ipv6_pond_reference(struct ipv6_pond ** pond,struct ipv6_pond * src,const char * file,int line)2581 ipv6_pond_reference(struct ipv6_pond **pond, struct ipv6_pond *src,
2582 		    const char *file, int line) {
2583 	if (pond == NULL) {
2584 		log_error("%s(%d): NULL pointer reference", file, line);
2585 		return DHCP_R_INVALIDARG;
2586 	}
2587 	if (*pond != NULL) {
2588 		log_error("%s(%d): non-NULL pointer", file, line);
2589 		return DHCP_R_INVALIDARG;
2590 	}
2591 	if (src == NULL) {
2592 		log_error("%s(%d): NULL pointer reference", file, line);
2593 		return DHCP_R_INVALIDARG;
2594 	}
2595 	*pond = src;
2596 	src->refcnt++;
2597 	return ISC_R_SUCCESS;
2598 }
2599 
2600 /*!
2601  *
2602  * \brief de-reference an IPv6 pond structure.
2603  *
2604  * This function decrements the reference count in an ipv6_pond structure.
2605  * If this was the last reference then the memory for the structure is
2606  * freed.
2607  *
2608  * \param[in] pond = A pointer to the pointer to the pond that should be
2609  *		     de-referenced.  On success the pointer to the pond
2610  *		     is cleared.  It must not be NULL and must not point
2611  *		     to NULL.
2612  *
2613  * \return
2614  * ISC_R_SUCCESS     = The pond was successfully de-referenced, pond now points
2615  *		       to NULL
2616  * DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been
2617  *		       modified.
2618  */
2619 
2620 isc_result_t
ipv6_pond_dereference(struct ipv6_pond ** pond,const char * file,int line)2621 ipv6_pond_dereference(struct ipv6_pond **pond, const char *file, int line) {
2622 	struct ipv6_pond *tmp;
2623 
2624 	if ((pond == NULL) || (*pond == NULL)) {
2625 		log_error("%s(%d): NULL pointer", file, line);
2626 		return DHCP_R_INVALIDARG;
2627 	}
2628 
2629 	tmp = *pond;
2630 	*pond = NULL;
2631 
2632 	tmp->refcnt--;
2633 	if (tmp->refcnt < 0) {
2634 		log_error("%s(%d): negative refcnt", file, line);
2635 		tmp->refcnt = 0;
2636 	}
2637 	if (tmp->refcnt == 0) {
2638 		dfree(tmp, file, line);
2639 	}
2640 
2641 	return ISC_R_SUCCESS;
2642 }
2643 
2644 #ifdef EUI_64
2645 /*
2646  * Enables/disables EUI-64 address assignment for a pond
2647  *
2648  * Excecutes statements down to the pond's scope and sets the pond's
2649  * use_eui_64 flag accordingly. In addition it iterates over the
2650  * pond's pools ensuring they are all /64.  Anything else is deemed
2651  * invalid for EUI-64.  It returns the number of invalid pools
2652  * detected.  This is done post-parsing as use-eui-64 can be set
2653  * down to the pool scope and we can't reliably do it until the
2654  * entire configuration has been parsed.
2655  */
2656 int
set_eui_64(struct ipv6_pond * pond)2657 set_eui_64(struct ipv6_pond *pond) {
2658 	int invalid_cnt = 0;
2659 	struct option_state* options = NULL;
2660 	struct option_cache *oc = NULL;
2661 	option_state_allocate(&options, MDL);
2662 	execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL, options,
2663 				    &global_scope, pond->group, NULL, NULL);
2664 
2665 	pond->use_eui_64 =
2666 		((oc = lookup_option(&server_universe, options, SV_USE_EUI_64))
2667 		 &&
2668 		 (evaluate_boolean_option_cache (NULL, NULL, NULL, NULL,
2669 						 options, NULL, &global_scope,
2670 						 oc, MDL)));
2671 	if (pond->use_eui_64) {
2672 		// Check all pools are valid
2673 		int i = 0;
2674 		struct ipv6_pool* p;
2675 		while((p = pond->ipv6_pools[i++]) != NULL) {
2676 			if (p->bits != 64) {
2677 				log_error("Pool %s/%d cannot use EUI-64,"
2678 					  " prefix must 64",
2679 					  pin6_addr(&p->start_addr), p->bits);
2680 				invalid_cnt++;
2681 			} else {
2682 				log_debug("Pool: %s/%d - will use EUI-64",
2683 					  pin6_addr(&p->start_addr), p->bits);
2684 			}
2685 		}
2686 	}
2687 
2688         /* Don't need the options anymore. */
2689         option_state_dereference(&options, MDL);
2690 	return (invalid_cnt);
2691 }
2692 #endif
2693 
2694 /*
2695  * Emits a log for each pond that has been flagged as being a "jumbo range"
2696  * A pond is considered a "jumbo range" when the total number of elements
2697  * exceeds the maximum value of POND_TRACK_MAX (currently maximum value
2698  * that can be stored by ipv6_pond.num_total).  Since we disable threshold
2699  * logging for jumbo ranges, we need to report this to the user.  This
2700  * function allows us to report jumbo ponds after config parsing, so the
2701  * logs can be seen both on the console (-T) and the log facility (i.e syslog).
2702  *
2703  * Note, threshold logging is done at the pond level, so we need emit a list
2704  * of the addresses ranges of the pools in the pond affected.
2705  */
2706 void
report_jumbo_ranges()2707 report_jumbo_ranges() {
2708 	struct shared_network* s;
2709 	char log_buf[1084];
2710 #ifdef EUI_64
2711 	int invalid_cnt = 0;
2712 #endif
2713 
2714 	/* Loop thru all the networks looking for jumbo range ponds */
2715 	for (s = shared_networks; s; s = s -> next) {
2716 		struct ipv6_pond* pond = s->ipv6_pond;
2717 		while (pond) {
2718 #ifdef EUI_64
2719 			/* while we're here, set the pond's use_eui_64 flag */
2720 			invalid_cnt += set_eui_64(pond);
2721 #endif
2722 			/* if its a jumbo and has pools(sanity check) */
2723 			if (pond->jumbo_range == 1 && (pond->ipv6_pools)) {
2724 				struct ipv6_pool* pool;
2725 				char *bufptr = log_buf;
2726 				size_t space_left = sizeof(log_buf) - 1;
2727 				int i = 0;
2728 				int used = 0;
2729 
2730 				/* Build list containing the start-address/CIDR
2731 				 * of each pool */
2732 				*bufptr = '\0';
2733 				while ((pool = pond->ipv6_pools[i++]) &&
2734 				        (space_left > (INET6_ADDRSTRLEN + 6))) {
2735 					/* more than one so add a comma */
2736 					if (i > 1) {
2737 						*bufptr++ = ',';
2738 						*bufptr++ = ' ';
2739 						*bufptr = '\0';
2740 						space_left -= 2;
2741 					}
2742 
2743 					/* add the address */
2744 					inet_ntop(AF_INET6, &pool->start_addr,
2745 						  bufptr, INET6_ADDRSTRLEN);
2746 
2747 					used = strlen(bufptr);
2748 					bufptr += used;
2749 					space_left -= used;
2750 
2751 					/* add the CIDR */
2752 					sprintf (bufptr, "/%d",pool->bits);
2753 					used = strlen(bufptr);
2754 					bufptr += used;
2755 					space_left -= used;
2756 					*bufptr = '\0';
2757 				}
2758 
2759 				log_info("Threshold logging disabled for shared"
2760 					 " subnet of ranges: %s", log_buf);
2761 			}
2762 			pond = pond->next;
2763 		}
2764 
2765 	}
2766 
2767 #ifdef EUI_64
2768 	if (invalid_cnt) {
2769 		log_fatal ("%d pool(s) are invalid for EUI-64 use",
2770 			   invalid_cnt);
2771 	}
2772 #endif
2773 }
2774 
2775 
2776 /*
2777  * \brief Tests that 16-bit hardware type is less than 256
2778  *
2779  * XXX: DHCPv6 gives a 16-bit field for the htype.  DHCPv4 gives an
2780  * 8-bit field.  To change the semantics of the generic 'hardware'
2781  * structure, we would have to adjust many DHCPv4 sources (from
2782  * interface to DHCPv4 lease code), and we would have to update the
2783  * 'hardware' config directive (probably being reverse compatible and
2784  * providing a new upgrade/replacement primitive).  This is a little
2785  * too much to change for now.  Hopefully we will revisit this before
2786  * hardware types exceeding 8 bits are assigned.
2787  *
2788  * Uses a static variable to limit log occurence to once per startup
2789  *
2790  * \param htype hardware type value to test
2791  *
2792  * \return returns 0 if the value is too large
2793  *
2794 */
2795 static int
htype_bounds_check(uint16_t htype)2796 htype_bounds_check(uint16_t htype) {
2797 	static int log_once = 0;
2798 
2799 	if (htype & 0xFF00) {
2800 		if (!log_once) {
2801 			log_error("Attention: At least one client advertises a "
2802 			  "hardware type of %d, which exceeds the software "
2803 			  "limitation of 255.", htype);
2804 			log_once = 1;
2805 		}
2806 
2807 		return(0);
2808 	}
2809 
2810 	return(1);
2811 }
2812 
2813 /*!
2814  * \brief Look for hosts by MAC address if it's available
2815  *
2816  * Checks the inbound packet against host declarations which specified:
2817  *
2818  *      "hardware ethernet <MAC>;"
2819  *
2820  * For directly connected clients, the function will use the MAC address
2821  * contained in packet:haddr if it's populated.  \TODO - While the logic is in
2822  * place for this search, the socket layer does not yet populate packet:haddr,
2823  * this is to be done under rt41523.
2824  *
2825  * For relayed clients, the function will use the MAC address from the
2826  * client-linklayer-address option if it has been supplied by the relay
2827  * directly connected to the client.
2828  *
2829  * \param hp[out] - pointer to storage for the host delcaration if found
2830  * \param packet - received packet
2831  * \param opt_state - option state to search
2832  * \param file - source file
2833  * \param line - line number
2834  *
2835  * \return non-zero if a matching host was found, zero otherwise
2836 */
2837 static int
find_hosts_by_haddr6(struct host_decl ** hp,struct packet * packet,struct option_state * opt_state,const char * file,int line)2838 find_hosts_by_haddr6(struct host_decl **hp,
2839 			 struct packet *packet,
2840 			 struct option_state *opt_state,
2841 			 const char *file, int line) {
2842 	int found = 0;
2843 	int htype;
2844 	int hlen;
2845 
2846 	/* For directly connected clients, use packet:haddr if populated */
2847 	if (packet->dhcpv6_container_packet == NULL) {
2848 		if (packet->haddr) {
2849 			htype = packet->haddr->hbuf[0];
2850 			hlen = packet->haddr->hlen - 1,
2851 			log_debug("find_hosts_by_haddr6: using packet->haddr,"
2852 				  " type: %d, len: %d", htype, hlen);
2853 			found = find_hosts_by_haddr (hp, htype,
2854 						     &packet->haddr->hbuf[1],
2855 						     hlen, MDL);
2856 		}
2857 	} else {
2858 		/* The first container packet is the from the relay directly
2859 		 * connected to the client. Per RFC 6939, that is only relay
2860 		 * that may supply the client linklayer address option. */
2861 		struct packet *relay_packet = packet->dhcpv6_container_packet;
2862 		struct option_state *relay_state = relay_packet->options;
2863 		struct data_string rel_addr;
2864 		struct option_cache *oc;
2865 
2866 		/* Look for the option in the first relay packet */
2867 		oc = lookup_option(&dhcpv6_universe, relay_state,
2868 				   D6O_CLIENT_LINKLAYER_ADDR);
2869 		if (!oc) {
2870 			/* Not there, so bail */
2871 			return (0);
2872 		}
2873 
2874 		/* The option is present, fetch the address data */
2875 		memset(&rel_addr, 0, sizeof(rel_addr));
2876 		if (!evaluate_option_cache(&rel_addr, relay_packet, NULL, NULL,
2877 					   relay_state, NULL, &global_scope,
2878 					   oc, MDL)) {
2879 			log_error("find_hosts_by_add6:"
2880 				  "Error evaluating option cache");
2881 			return (0);
2882 		}
2883 
2884 		/* The relay address data should be:
2885 		 *   byte 0 - 1 = hardware type
2886 		 *   bytes 2 - hlen = hardware address
2887                  * where  hlen ( hardware address len) is option data len - 2 */
2888 		hlen = rel_addr.len - 2;
2889 		if (hlen > 0 && hlen <= HARDWARE_ADDR_LEN) {
2890 			htype = getUShort(rel_addr.data);
2891 			if (htype_bounds_check(htype)) {
2892 				/* Looks valid, let's search with it */
2893 				log_debug("find_hosts_by_haddr6:"
2894 					  "using relayed haddr"
2895 					  " type: %d, len: %d", htype, hlen);
2896 				found = find_hosts_by_haddr (hp, htype,
2897 							     &rel_addr.data[2],
2898 							     hlen, MDL);
2899 			}
2900 		}
2901 
2902 		data_string_forget(&rel_addr, MDL);
2903         }
2904 
2905 	return (found);
2906 }
2907 
2908 /*
2909  * find_host_by_duid_chaddr() synthesizes a DHCPv4-like 'hardware'
2910  * parameter from a DHCPv6 supplied DUID (client-identifier option),
2911  * and may seek to use client or relay supplied hardware addresses.
2912  */
2913 static int
find_hosts_by_duid_chaddr(struct host_decl ** host,const struct data_string * client_id)2914 find_hosts_by_duid_chaddr(struct host_decl **host,
2915 			  const struct data_string *client_id) {
2916 	int htype, hlen;
2917 	const unsigned char *chaddr;
2918 
2919 	/*
2920 	 * The DUID-LL and DUID-LLT must have a 2-byte DUID type and 2-byte
2921 	 * htype.
2922 	 */
2923 	if (client_id->len < 4)
2924 		return 0;
2925 
2926 	/*
2927 	 * The third and fourth octets of the DUID-LL and DUID-LLT
2928 	 * is the hardware type, but in 16 bits.
2929 	 */
2930 	htype = getUShort(client_id->data + 2);
2931 	hlen = 0;
2932 	chaddr = NULL;
2933 
2934 	/* The first two octets of the DUID identify the type. */
2935 	switch(getUShort(client_id->data)) {
2936 	      case DUID_LLT:
2937 		if (client_id->len > 8) {
2938 			hlen = client_id->len - 8;
2939 			chaddr = client_id->data + 8;
2940 		}
2941 		break;
2942 
2943 	      case DUID_LL:
2944 		/*
2945 		 * Note that client_id->len must be greater than or equal
2946 		 * to four to get to this point in the function.
2947 		 */
2948 		hlen = client_id->len - 4;
2949 		chaddr = client_id->data + 4;
2950 		break;
2951 
2952 	      default:
2953 		break;
2954 	}
2955 
2956 	if ((hlen == 0) || (hlen > HARDWARE_ADDR_LEN) ||
2957 	    !htype_bounds_check(htype)) {
2958 		return (0);
2959 	}
2960 
2961 	return find_hosts_by_haddr(host, htype, chaddr, hlen, MDL);
2962 }
2963 
2964 /*
2965  * \brief Finds a host record that matches the packet, if any
2966  *
2967  * This function centralizes the logic for matching v6 client
2968  * packets to host declarations.  We check in the following order
2969  * for matches with:
2970  *
2971  * 1. client_id if specified
2972  * 2. MAC address when explicitly available
2973  * 3. packet option
2974  * 4. synthesized hardware address - this is done last as some
2975  * synthesis methods are not consided to be reliable
2976  *
2977  * \param[out] host - pointer to storage for the located host
2978  * \param packet - inbound client packet
2979  * \param client_id - client identifier (if one)
2980  * \param file - source file
2981  * \param line - source file line number
2982  * \return non-zero if a host is found, zero otherwise
2983 */
2984 int
find_hosts6(struct host_decl ** host,struct packet * packet,const struct data_string * client_id,char * file,int line)2985 find_hosts6(struct host_decl** host, struct packet* packet,
2986             const struct data_string* client_id, char* file, int line) {
2987         return (find_hosts_by_uid(host, client_id->data, client_id->len, MDL)
2988                 || find_hosts_by_haddr6(host, packet, packet->options, MDL)
2989                 || find_hosts_by_option(host, packet, packet->options, MDL)
2990                 || find_hosts_by_duid_chaddr(host, client_id));
2991 }
2992 
2993 /* unittest moved to server/tests/mdb6_unittest.c */
2994