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