ISC DHCP  4.4.1
A reference DHCPv4 and DHCPv6 implementation
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 
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 
180 HASH_FUNCTIONS(ia, unsigned char *, struct ia_xx, ia_hash_t,
182 
186 
187 HASH_FUNCTIONS(iasubopt, struct in6_addr *, struct iasubopt, iasubopt_hash_t,
189 
190 struct ipv6_pool **pools;
191 int 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  */
199 isc_result_t
200 iasubopt_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  */
233 isc_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  */
260 isc_result_t
261 iasubopt_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  */
310 isc_result_t
311 ia_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  */
338 isc_result_t
339 ia_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  */
376 isc_result_t
377 ia_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  */
402 isc_result_t
403 ia_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  */
438 isc_result_t
439 ia_add_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt,
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  */
475 void
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  */
503 void
504 ia_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++) {
508  ia_dereference(&(ia->iasubopt[i]->ia), file, line);
510  }
511  ia->num_iasubopt = 0;
512 }
513 
514 /*
515  * Compare two IA.
516  */
517 isc_boolean_t
518 ia_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  */
589 static isc_boolean_t
590 lease_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  */
607 static void
608 active_changed(void *iasubopt, unsigned int new_heap_index) {
609  ((struct iasubopt *)iasubopt)->active_index = new_heap_index;
610 }
611 
612 static void
613 inactive_changed(void *iasubopt, unsigned int new_heap_index) {
614  ((struct iasubopt *)iasubopt)->inactive_index = new_heap_index;
615 }
616 
639 isc_result_t
640 ipv6_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 
705 isc_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  */
738 static isc_result_t
739 dereference_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  */
750 static void
751 dereference_heap_entry(void *value, void *dummy) {
752  struct iasubopt *iasubopt = (struct iasubopt *)value;
753 
755 }
756 
776 isc_result_t
777 ipv6_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  */
812 static void
813 build_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
860 int
861 valid_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  */
875 static isc_result_t
876 build_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 
908 int
909 valid_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  */
937 static void
938 build_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. */
1006 static struct in6_addr rtany;
1007 /* Reserved Subnet Anycasts ::fdff:ffff:ffff:ff80-::fdff:ffff:ffff:ffff. */
1008 static 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  */
1031 isc_result_t
1032 create_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  return DHCP_R_INVALIDARG;
1089  default:
1090  log_error("create_lease6: untyped pool.");
1091  return DHCP_R_INVALIDARG;
1092  }
1093 
1094  /*
1095  * Avoid reserved interface IDs. (cf. RFC 5453)
1096  */
1097  reserved_iid = ISC_FALSE;
1098  if (memcmp(&tmp.s6_addr[8], &rtany.s6_addr[8], 8) == 0) {
1099  reserved_iid = ISC_TRUE;
1100  }
1101  if (!reserved_iid &&
1102  (memcmp(&tmp.s6_addr[8], &resany.s6_addr[8], 7) == 0) &&
1103  ((tmp.s6_addr[15] & 0x80) == 0x80)) {
1104  reserved_iid = ISC_TRUE;
1105  }
1106 
1107  /*
1108  * If this address is not in use, we're happy with it
1109  */
1110  test_iaaddr = NULL;
1111  if (!reserved_iid &&
1112  (iasubopt_hash_lookup(&test_iaaddr, pool->leases,
1113  &tmp, sizeof(tmp), MDL) == 0)) {
1114  break;
1115  }
1116  if (test_iaaddr != NULL)
1117  iasubopt_dereference(&test_iaaddr, MDL);
1118 
1119  /*
1120  * Otherwise, we create a new input, adding the address
1121  */
1122  memset(&new_ds, 0, sizeof(new_ds));
1123  new_ds.len = ds.len + sizeof(tmp);
1124  if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) {
1125  data_string_forget(&ds, MDL);
1126  return ISC_R_NOMEMORY;
1127  }
1128  new_ds.data = new_ds.buffer->data;
1129  memcpy(new_ds.buffer->data, ds.data, ds.len);
1130  memcpy(new_ds.buffer->data + ds.len, &tmp, sizeof(tmp));
1131  data_string_forget(&ds, MDL);
1132  data_string_copy(&ds, &new_ds, MDL);
1133  data_string_forget(&new_ds, MDL);
1134  }
1135 
1136  data_string_forget(&ds, MDL);
1137 
1138  /*
1139  * We're happy with the address, create an IAADDR
1140  * to hold it.
1141  */
1142  iaaddr = NULL;
1143  result = iasubopt_allocate(&iaaddr, MDL);
1144  if (result != ISC_R_SUCCESS) {
1145  return result;
1146  }
1147  iaaddr->plen = 0;
1148  memcpy(&iaaddr->addr, &tmp, sizeof(iaaddr->addr));
1149 
1150  /*
1151  * Add the lease to the pool (note state is free, not active?!).
1152  */
1153  result = add_lease6(pool, iaaddr, soft_lifetime_end_time);
1154  if (result == ISC_R_SUCCESS) {
1155  iasubopt_reference(addr, iaaddr, MDL);
1156  }
1157  iasubopt_dereference(&iaaddr, MDL);
1158  return result;
1159 }
1160 
1161 #ifdef EUI_64
1162 
1172 isc_result_t
1173 create_lease6_eui_64(struct ipv6_pool *pool, struct iasubopt **addr,
1174  const struct data_string *uid,
1175  time_t soft_lifetime_end_time) {
1176  struct in6_addr tmp;
1177  struct iasubopt *test_iaaddr;
1178  struct iasubopt *iaaddr;
1179  isc_result_t result;
1180  static isc_boolean_t init_resiid = ISC_FALSE;
1181 
1182  /* Fill the reserved IIDs. */
1183  if (!init_resiid) {
1184  memset(&rtany, 0, 16);
1185  memset(&resany, 0, 8);
1186  resany.s6_addr[8] = 0xfd;
1187  memset(&resany.s6_addr[9], 0xff, 6);
1188  init_resiid = ISC_TRUE;
1189  }
1190 
1191  /* Pool must be IA_NA */
1192  if (pool->pool_type != D6O_IA_NA) {
1193  log_error("create_lease6_eui_64: pool type is not IA_NA.");
1194  return (DHCP_R_INVALIDARG);
1195  }
1196 
1197  /* Attempt to build the address */
1198  if (build_address6_eui_64 (&tmp, &pool->start_addr, pool->bits,
1199  uid, IAID_LEN) != ISC_R_SUCCESS) {
1200  log_error("create_lease6_eui_64: build_address6_eui_64 failed");
1201  return (ISC_R_FAILURE);
1202  }
1203 
1204  /* Avoid reserved interface IDs. (cf. RFC 5453) */
1205  if ((memcmp(&tmp.s6_addr[8], &rtany.s6_addr[8], 8) == 0) ||
1206  ((memcmp(&tmp.s6_addr[8], &resany.s6_addr[8], 7) == 0) &&
1207  ((tmp.s6_addr[15] & 0x80) == 0x80))) {
1208  log_error("create_lease6_eui_64: "
1209  "address conflicts with reserved IID");
1210  return (ISC_R_FAILURE);
1211  }
1212 
1213  /* If this address is not in use, we're happy with it */
1214  test_iaaddr = NULL;
1215  if (iasubopt_hash_lookup(&test_iaaddr, pool->leases,
1216  &tmp, sizeof(tmp), MDL) != 0) {
1217 
1218  /* See if it's ours. Static leases won't have an ia */
1219  int ours = 0;
1220  if (!test_iaaddr->ia) {
1221  log_error("create_lease6_eui_64: "
1222  "address %s is assigned to static lease",
1223  pin6_addr(&test_iaaddr->addr));
1224  } else {
1225  /* Not sure if this can actually happen */
1226  struct data_string* found = &test_iaaddr->ia->iaid_duid;
1227  ours = ((found->len == uid->len) &&
1228  (!memcmp(found->data, uid->data, uid->len)));
1229  log_error("create_lease6_eui_64: "
1230  "address %s belongs to %s",
1231  pin6_addr(&test_iaaddr->addr),
1232  print_hex_1(found->len, found->data, 60));
1233  }
1234 
1235  iasubopt_dereference(&test_iaaddr, MDL);
1236  if (!ours) {
1237  /* Cant' use it */
1238  return (ISC_R_FAILURE);
1239  }
1240  }
1241 
1242  /* We're happy with the address, create an IAADDR to hold it. */
1243  iaaddr = NULL;
1244  result = iasubopt_allocate(&iaaddr, MDL);
1245  if (result != ISC_R_SUCCESS) {
1246  log_error("create_lease6_eui_64: could not allocate iasubop");
1247  return result;
1248  }
1249  iaaddr->plen = 0;
1250  memcpy(&iaaddr->addr, &tmp, sizeof(iaaddr->addr));
1251 
1252  /* Add the lease to the pool and the reply */
1253  result = add_lease6(pool, iaaddr, soft_lifetime_end_time);
1254  if (result == ISC_R_SUCCESS) {
1255  iasubopt_reference(addr, iaaddr, MDL);
1256  }
1257 
1258  iasubopt_dereference(&iaaddr, MDL);
1259  return result;
1260 }
1261 #endif
1262 
1303 isc_result_t
1305  struct ipv6_pool *pool,
1306  struct iasubopt *lease,
1307  struct ia_xx *ia) {
1308 
1309  struct iasubopt *test_iasubopt, *tmp_iasubopt;
1310  struct ia_xx *old_ia;
1311  isc_result_t status = ISC_R_SUCCESS;
1312 
1313  test_iasubopt = NULL;
1314  old_ia = NULL;
1315 
1316  /*
1317  * Look up the address - if we don't find a lease
1318  * we don't need to do anything.
1319  */
1320  if (iasubopt_hash_lookup(&test_iasubopt, pool->leases,
1321  &lease->addr, sizeof(lease->addr),
1322  MDL) == 0) {
1323  return (ISC_R_SUCCESS);
1324  }
1325 
1326  if (test_iasubopt->ia == NULL) {
1327  /* no old ia, no work to do */
1328  iasubopt_dereference(&test_iasubopt, MDL);
1329  return (status);
1330  }
1331 
1332  ia_reference(&old_ia, test_iasubopt->ia, MDL);
1333 
1334  if ((old_ia->iaid_duid.len == ia->iaid_duid.len) &&
1335  (memcmp((unsigned char *)ia->iaid_duid.data,
1336  (unsigned char *)old_ia->iaid_duid.data,
1337  ia->iaid_duid.len) == 0)) {
1338  /* same IA */
1339  if ((lease->state == FTS_ACTIVE) ||
1340  (lease->state == FTS_ABANDONED)) {
1341  /* still active, no need to delete */
1342  goto cleanup;
1343  }
1344  } else {
1345  /* different IA */
1346  if ((lease->state != FTS_ACTIVE) &&
1347  (lease->state != FTS_ABANDONED)) {
1348  /* new lease isn't active, no work */
1349  goto cleanup;
1350  }
1351 
1352  /*
1353  * We appear to have two active leases, this shouldn't happen.
1354  * Before a second lease can be set to active the first lease
1355  * should be set to inactive (released, expired etc). For now
1356  * delete the previous lease and indicate a failure to the
1357  * caller so it can generate a warning.
1358  * In the future we may try and determine which is the better
1359  * lease to keep.
1360  */
1361 
1362  status = ISC_R_FAILURE;
1363  }
1364 
1365  /*
1366  * Remove the old lease from the active heap and from the hash table
1367  * then remove the lease from the IA and clean up the IA if necessary.
1368  */
1369  isc_heap_delete(pool->active_timeouts, test_iasubopt->active_index);
1370  pool->num_active--;
1371  if (pool->ipv6_pond)
1372  pool->ipv6_pond->num_active--;
1373 
1374  if (lease->state == FTS_ABANDONED) {
1375  pool->num_abandoned--;
1376  if (pool->ipv6_pond)
1377  pool->ipv6_pond->num_abandoned--;
1378  }
1379 
1380  iasubopt_hash_delete(pool->leases, &test_iasubopt->addr,
1381  sizeof(test_iasubopt->addr), MDL);
1382  ia_remove_iasubopt(old_ia, test_iasubopt, MDL);
1383  if (old_ia->num_iasubopt <= 0) {
1384  ia_hash_delete(ia_table,
1385  (unsigned char *)old_ia->iaid_duid.data,
1386  old_ia->iaid_duid.len, MDL);
1387  }
1388 
1389  /*
1390  * We derefenrece the subopt here as we've just removed it from
1391  * the hash table in the pool. We need to make a copy as we
1392  * need to derefernece it again later.
1393  */
1394  tmp_iasubopt = test_iasubopt;
1395  iasubopt_dereference(&tmp_iasubopt, MDL);
1396 
1397  cleanup:
1398  ia_dereference(&old_ia, MDL);
1399 
1400  /*
1401  * Clean up the reference, this is in addition to the deference
1402  * above after removing the entry from the hash table
1403  */
1404  iasubopt_dereference(&test_iasubopt, MDL);
1405 
1406  return (status);
1407 }
1408 
1409 /*
1410  * Put a lease in the pool directly. This is intended to be used when
1411  * loading leases from the file.
1412  */
1413 isc_result_t
1415  time_t valid_lifetime_end_time) {
1416  isc_result_t insert_result;
1417  struct iasubopt *test_iasubopt;
1418  struct iasubopt *tmp_iasubopt;
1419 
1420  /* If a state was not assigned by the caller, assume active. */
1421  if (lease->state == 0)
1422  lease->state = FTS_ACTIVE;
1423 
1424  ipv6_pool_reference(&lease->ipv6_pool, pool, MDL);
1425 
1426  /*
1427  * If this IAADDR/PREFIX is already in our structures, remove the
1428  * old one.
1429  */
1430  test_iasubopt = NULL;
1431  if (iasubopt_hash_lookup(&test_iasubopt, pool->leases,
1432  &lease->addr, sizeof(lease->addr), MDL)) {
1433  /* XXX: we should probably ask the lease what heap it is on
1434  * (as a consistency check).
1435  * XXX: we should probably have one function to "put this lease
1436  * on its heap" rather than doing these if's everywhere. If
1437  * you add more states to this list, don't.
1438  */
1439  if ((test_iasubopt->state == FTS_ACTIVE) ||
1440  (test_iasubopt->state == FTS_ABANDONED)) {
1441  isc_heap_delete(pool->active_timeouts,
1442  test_iasubopt->active_index);
1443  pool->num_active--;
1444  if (pool->ipv6_pond)
1445  pool->ipv6_pond->num_active--;
1446 
1447  if (test_iasubopt->state == FTS_ABANDONED) {
1448  pool->num_abandoned--;
1449  if (pool->ipv6_pond)
1450  pool->ipv6_pond->num_abandoned--;
1451  }
1452  } else {
1453  isc_heap_delete(pool->inactive_timeouts,
1454  test_iasubopt->inactive_index);
1455  pool->num_inactive--;
1456  }
1457 
1458  iasubopt_hash_delete(pool->leases, &test_iasubopt->addr,
1459  sizeof(test_iasubopt->addr), MDL);
1460 
1461  /*
1462  * We're going to do a bit of evil trickery here.
1463  *
1464  * We need to dereference the entry once to remove our
1465  * current reference (in test_iasubopt), and then one
1466  * more time to remove the reference left when the
1467  * address was added to the pool before.
1468  */
1469  tmp_iasubopt = test_iasubopt;
1470  iasubopt_dereference(&test_iasubopt, MDL);
1471  iasubopt_dereference(&tmp_iasubopt, MDL);
1472  }
1473 
1474  /*
1475  * Add IAADDR/PREFIX to our structures.
1476  */
1477  tmp_iasubopt = NULL;
1478  iasubopt_reference(&tmp_iasubopt, lease, MDL);
1479  if ((tmp_iasubopt->state == FTS_ACTIVE) ||
1480  (tmp_iasubopt->state == FTS_ABANDONED)) {
1481  tmp_iasubopt->hard_lifetime_end_time = valid_lifetime_end_time;
1482  iasubopt_hash_add(pool->leases, &tmp_iasubopt->addr,
1483  sizeof(tmp_iasubopt->addr), lease, MDL);
1484  insert_result = isc_heap_insert(pool->active_timeouts,
1485  tmp_iasubopt);
1486  if (insert_result == ISC_R_SUCCESS) {
1487  pool->num_active++;
1488  if (pool->ipv6_pond)
1489  pool->ipv6_pond->num_active++;
1490 
1491  if (tmp_iasubopt->state == FTS_ABANDONED) {
1492  pool->num_abandoned++;
1493  if (pool->ipv6_pond)
1494  pool->ipv6_pond->num_abandoned++;
1495  }
1496  }
1497 
1498  } else {
1499  tmp_iasubopt->soft_lifetime_end_time = valid_lifetime_end_time;
1500  insert_result = isc_heap_insert(pool->inactive_timeouts,
1501  tmp_iasubopt);
1502  if (insert_result == ISC_R_SUCCESS)
1503  pool->num_inactive++;
1504  }
1505  if (insert_result != ISC_R_SUCCESS) {
1506  iasubopt_hash_delete(pool->leases, &lease->addr,
1507  sizeof(lease->addr), MDL);
1508  iasubopt_dereference(&tmp_iasubopt, MDL);
1509  return insert_result;
1510  }
1511 
1512  /*
1513  * Note: we intentionally leave tmp_iasubopt referenced; there
1514  * is a reference in the heap/hash, after all.
1515  */
1516 
1517  return ISC_R_SUCCESS;
1518 }
1519 
1520 /*
1521  * Determine if an address is present in a pool or not.
1522  */
1523 isc_boolean_t
1524 lease6_exists(const struct ipv6_pool *pool, const struct in6_addr *addr) {
1525  struct iasubopt *test_iaaddr;
1526 
1527  test_iaaddr = NULL;
1528  if (iasubopt_hash_lookup(&test_iaaddr, pool->leases,
1529  (void *)addr, sizeof(*addr), MDL)) {
1530  iasubopt_dereference(&test_iaaddr, MDL);
1531  return ISC_TRUE;
1532  } else {
1533  return ISC_FALSE;
1534  }
1535 }
1536 
1551 isc_boolean_t
1553  struct iasubopt *test_iaaddr;
1554  isc_boolean_t status = ISC_TRUE;
1555 
1556  test_iaaddr = NULL;
1557  if (iasubopt_hash_lookup(&test_iaaddr, lease->ipv6_pool->leases,
1558  (void *)&lease->addr,
1559  sizeof(lease->addr), MDL)) {
1560  if (test_iaaddr != lease) {
1561  status = ISC_FALSE;
1562  }
1563  iasubopt_dereference(&test_iaaddr, MDL);
1564  }
1565 
1566  return (status);
1567 }
1568 
1569 /*
1570  * Put the lease on our active pool.
1571  */
1572 static isc_result_t
1573 move_lease_to_active(struct ipv6_pool *pool, struct iasubopt *lease) {
1574  isc_result_t insert_result;
1575 
1576  insert_result = isc_heap_insert(pool->active_timeouts, lease);
1577  if (insert_result == ISC_R_SUCCESS) {
1578  iasubopt_hash_add(pool->leases, &lease->addr,
1579  sizeof(lease->addr), lease, MDL);
1580  isc_heap_delete(pool->inactive_timeouts,
1581  lease->inactive_index);
1582  pool->num_active++;
1583  pool->num_inactive--;
1584  lease->state = FTS_ACTIVE;
1585  if (pool->ipv6_pond)
1586  pool->ipv6_pond->num_active++;
1587 
1588  }
1589  return insert_result;
1590 }
1591 
1622 isc_result_t
1624  time_t old_end_time = lease->hard_lifetime_end_time;
1625  lease->hard_lifetime_end_time = lease->soft_lifetime_end_time;
1626  lease->soft_lifetime_end_time = 0;
1627 
1628  if (lease->state == FTS_ACTIVE) {
1629  if (old_end_time <= lease->hard_lifetime_end_time) {
1630  isc_heap_decreased(pool->active_timeouts,
1631  lease->active_index);
1632  } else {
1633  isc_heap_increased(pool->active_timeouts,
1634  lease->active_index);
1635  }
1636  return ISC_R_SUCCESS;
1637  } else if (lease->state == FTS_ABANDONED) {
1638  char tmp_addr[INET6_ADDRSTRLEN];
1639  lease->state = FTS_ACTIVE;
1640  isc_heap_increased(pool->active_timeouts, lease->active_index);
1641  log_info("Reclaiming previously abandoned address %s",
1642  inet_ntop(AF_INET6, &(lease->addr), tmp_addr,
1643  sizeof(tmp_addr)));
1644 
1645  pool->num_abandoned--;
1646  if (pool->ipv6_pond)
1647  pool->ipv6_pond->num_abandoned--;
1648 
1649  return ISC_R_SUCCESS;
1650  } else {
1651  return move_lease_to_active(pool, lease);
1652  }
1653 }
1654 
1655 /*
1656  * Put the lease on our inactive pool, with the specified state.
1657  */
1658 static isc_result_t
1659 move_lease_to_inactive(struct ipv6_pool *pool, struct iasubopt *lease,
1661  isc_result_t insert_result;
1662 
1663  insert_result = isc_heap_insert(pool->inactive_timeouts, lease);
1664  if (insert_result == ISC_R_SUCCESS) {
1665  /*
1666  * Handle expire and release statements
1667  * To get here we must be active and have done a commit so
1668  * we should run the proper statements if they exist, though
1669  * that will change when we remove the inactive heap.
1670  * In addition we get rid of the references for both as we
1671  * can only do one (expire or release) on a lease
1672  */
1673  if (lease->on_star.on_expiry != NULL) {
1674  if (state == FTS_EXPIRED) {
1675  execute_statements(NULL, NULL, NULL,
1676  NULL, NULL, NULL,
1677  &lease->scope,
1679  &lease->on_star);
1680  }
1682  (&lease->on_star.on_expiry, MDL);
1683  }
1684 
1685  if (lease->on_star.on_release != NULL) {
1686  if (state == FTS_RELEASED) {
1687  execute_statements(NULL, NULL, NULL,
1688  NULL, NULL, NULL,
1689  &lease->scope,
1691  &lease->on_star);
1692  }
1694  (&lease->on_star.on_release, MDL);
1695  }
1696 
1697 #if defined (NSUPDATE)
1698  /* Process events upon expiration. */
1699  if (pool->pool_type != D6O_IA_PD) {
1700  (void) ddns_removals(NULL, lease, NULL, ISC_FALSE);
1701  }
1702 #endif
1703 
1704  /* Binding scopes are no longer valid after expiry or
1705  * release.
1706  */
1707  if (lease->scope != NULL) {
1709  }
1710 
1711  iasubopt_hash_delete(pool->leases,
1712  &lease->addr, sizeof(lease->addr), MDL);
1713  isc_heap_delete(pool->active_timeouts, lease->active_index);
1714  lease->state = state;
1715  pool->num_active--;
1716  pool->num_inactive++;
1717  if (pool->ipv6_pond)
1718  pool->ipv6_pond->num_active--;
1719 
1720  if (lease->state == FTS_ABANDONED) {
1721  pool->num_abandoned--;
1722  if (pool->ipv6_pond)
1723  pool->ipv6_pond->num_abandoned--;
1724  }
1725  }
1726  return insert_result;
1727 }
1728 
1729 /*
1730  * Expire the oldest lease if it's lifetime_end_time is
1731  * older than the given time.
1732  *
1733  * - leasep must be a pointer to a (struct iasubopt *) pointer previously
1734  * initialized to NULL
1735  *
1736  * On return leasep has a reference to the removed entry. It is left
1737  * pointing to NULL if the oldest lease has not expired.
1738  */
1739 isc_result_t
1740 expire_lease6(struct iasubopt **leasep, struct ipv6_pool *pool, time_t now) {
1741  struct iasubopt *tmp;
1742  isc_result_t result;
1743 
1744  if (leasep == NULL) {
1745  log_error("%s(%d): NULL pointer reference", MDL);
1746  return DHCP_R_INVALIDARG;
1747  }
1748  if (*leasep != NULL) {
1749  log_error("%s(%d): non-NULL pointer", MDL);
1750  return DHCP_R_INVALIDARG;
1751  }
1752 
1753  if (pool->num_active > 0) {
1754  tmp = (struct iasubopt *)
1755  isc_heap_element(pool->active_timeouts, 1);
1756  if (now > tmp->hard_lifetime_end_time) {
1757  result = move_lease_to_inactive(pool, tmp,
1758  FTS_EXPIRED);
1759  if (result == ISC_R_SUCCESS) {
1760  iasubopt_reference(leasep, tmp, MDL);
1761  }
1762  return result;
1763  }
1764  }
1765  return ISC_R_SUCCESS;
1766 }
1767 
1768 
1769 /*
1770  * For a declined lease, leave it on the "active" pool, but mark
1771  * it as declined. Give it an infinite (well, really long) life.
1772  */
1773 isc_result_t
1775  isc_result_t result;
1776 
1777  if ((lease->state != FTS_ACTIVE) &&
1778  (lease->state != FTS_ABANDONED)) {
1779  result = move_lease_to_active(pool, lease);
1780  if (result != ISC_R_SUCCESS) {
1781  return result;
1782  }
1783  }
1785 
1786  pool->num_abandoned++;
1787  if (pool->ipv6_pond)
1788  pool->ipv6_pond->num_abandoned++;
1789 
1790  lease->hard_lifetime_end_time = MAX_TIME;
1791  isc_heap_decreased(pool->active_timeouts, lease->active_index);
1792  return ISC_R_SUCCESS;
1793 }
1794 
1795 /*
1796  * Put the returned lease on our inactive pool.
1797  */
1798 isc_result_t
1800  if (lease->state == FTS_ACTIVE) {
1801  return move_lease_to_inactive(pool, lease, FTS_RELEASED);
1802  } else {
1803  return ISC_R_SUCCESS;
1804  }
1805 }
1806 
1807 /*
1808  * Create a prefix by hashing the input, and using that for
1809  * the part subject to allocation.
1810  */
1811 void
1812 build_prefix6(struct in6_addr *pref,
1813  const struct in6_addr *net_start_pref,
1814  int pool_bits, int pref_bits,
1815  const struct data_string *input) {
1816  isc_md5_t ctx;
1817  int net_bytes;
1818  int i;
1819  char *str;
1820  const char *net_str;
1821 
1822  /*
1823  * Use MD5 to get a nice 128 bit hash of the input.
1824  * Yes, we know MD5 isn't cryptographically sound.
1825  * No, we don't care.
1826  */
1827  isc_md5_init(&ctx);
1828  isc_md5_update(&ctx, input->data, input->len);
1829  isc_md5_final(&ctx, (unsigned char *)pref);
1830 
1831  /*
1832  * Copy the network bits over.
1833  */
1834  str = (char *)pref;
1835  net_str = (const char *)net_start_pref;
1836  net_bytes = pool_bits / 8;
1837  for (i = 0; i < net_bytes; i++) {
1838  str[i] = net_str[i];
1839  }
1840  i = net_bytes;
1841  switch (pool_bits % 8) {
1842  case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
1843  case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
1844  case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break;
1845  case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break;
1846  case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break;
1847  case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break;
1848  case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break;
1849  }
1850  /*
1851  * Zero the remaining bits.
1852  */
1853  net_bytes = pref_bits / 8;
1854  for (i=net_bytes+1; i<16; i++) {
1855  str[i] = 0;
1856  }
1857  i = net_bytes;
1858  switch (pref_bits % 8) {
1859  case 0: str[i] &= 0; break;
1860  case 1: str[i] &= 0x80; break;
1861  case 2: str[i] &= 0xC0; break;
1862  case 3: str[i] &= 0xE0; break;
1863  case 4: str[i] &= 0xF0; break;
1864  case 5: str[i] &= 0xF8; break;
1865  case 6: str[i] &= 0xFC; break;
1866  case 7: str[i] &= 0xFE; break;
1867  }
1868 }
1869 
1870 /*
1871  * Create a lease for the given prefix and client duid.
1872  *
1873  * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
1874  * initialized to NULL
1875  *
1876  * Right now we simply hash the DUID, and if we get a collision, we hash
1877  * again until we find a free prefix. We try this a fixed number of times,
1878  * to avoid getting stuck in a loop (this is important on small pools
1879  * where we can run out of space).
1880  *
1881  * We return the number of attempts that it took to find an available
1882  * prefix. This tells callers when a pool is are filling up, as
1883  * well as an indication of how full the pool is; statistically the
1884  * more full a pool is the more attempts must be made before finding
1885  * a free prefix. Realistically this will only happen in very full
1886  * pools.
1887  *
1888  * We probably want different algorithms depending on the network size, in
1889  * the long term.
1890  */
1891 isc_result_t
1892 create_prefix6(struct ipv6_pool *pool, struct iasubopt **pref,
1893  unsigned int *attempts,
1894  const struct data_string *uid,
1895  time_t soft_lifetime_end_time) {
1896  struct data_string ds;
1897  struct in6_addr tmp;
1898  struct iasubopt *test_iapref;
1899  struct data_string new_ds;
1900  struct iasubopt *iapref;
1901  isc_result_t result;
1902 
1903  /*
1904  * Use the UID as our initial seed for the hash
1905  */
1906  memset(&ds, 0, sizeof(ds));
1907  data_string_copy(&ds, (struct data_string *)uid, MDL);
1908 
1909  *attempts = 0;
1910  for (;;) {
1911  /*
1912  * Give up at some point.
1913  */
1914  if (++(*attempts) > 10) {
1915  data_string_forget(&ds, MDL);
1916  return ISC_R_NORESOURCES;
1917  }
1918 
1919  /*
1920  * Build a prefix
1921  */
1922  build_prefix6(&tmp, &pool->start_addr,
1923  pool->bits, pool->units, &ds);
1924 
1925  /*
1926  * If this prefix is not in use, we're happy with it
1927  */
1928  test_iapref = NULL;
1929  if (iasubopt_hash_lookup(&test_iapref, pool->leases,
1930  &tmp, sizeof(tmp), MDL) == 0) {
1931  break;
1932  }
1933  iasubopt_dereference(&test_iapref, MDL);
1934 
1935  /*
1936  * Otherwise, we create a new input, adding the prefix
1937  */
1938  memset(&new_ds, 0, sizeof(new_ds));
1939  new_ds.len = ds.len + sizeof(tmp);
1940  if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) {
1941  data_string_forget(&ds, MDL);
1942  return ISC_R_NOMEMORY;
1943  }
1944  new_ds.data = new_ds.buffer->data;
1945  memcpy(new_ds.buffer->data, ds.data, ds.len);
1946  memcpy(new_ds.buffer->data + ds.len, &tmp, sizeof(tmp));
1947  data_string_forget(&ds, MDL);
1948  data_string_copy(&ds, &new_ds, MDL);
1949  data_string_forget(&new_ds, MDL);
1950  }
1951 
1952  data_string_forget(&ds, MDL);
1953 
1954  /*
1955  * We're happy with the prefix, create an IAPREFIX
1956  * to hold it.
1957  */
1958  iapref = NULL;
1959  result = iasubopt_allocate(&iapref, MDL);
1960  if (result != ISC_R_SUCCESS) {
1961  return result;
1962  }
1963  iapref->plen = (u_int8_t)pool->units;
1964  memcpy(&iapref->addr, &tmp, sizeof(iapref->addr));
1965 
1966  /*
1967  * Add the prefix to the pool (note state is free, not active?!).
1968  */
1969  result = add_lease6(pool, iapref, soft_lifetime_end_time);
1970  if (result == ISC_R_SUCCESS) {
1971  iasubopt_reference(pref, iapref, MDL);
1972  }
1973  iasubopt_dereference(&iapref, MDL);
1974  return result;
1975 }
1976 
1977 /*
1978  * Determine if a prefix is present in a pool or not.
1979  */
1980 isc_boolean_t
1982  const struct in6_addr *pref, u_int8_t plen) {
1983  struct iasubopt *test_iapref;
1984 
1985  if ((int)plen != pool->units)
1986  return ISC_FALSE;
1987 
1988  test_iapref = NULL;
1989  if (iasubopt_hash_lookup(&test_iapref, pool->leases,
1990  (void *)pref, sizeof(*pref), MDL)) {
1991  iasubopt_dereference(&test_iapref, MDL);
1992  return ISC_TRUE;
1993  } else {
1994  return ISC_FALSE;
1995  }
1996 }
1997 
1998 /*
1999  * Mark an IPv6 address/prefix as unavailable from a pool.
2000  *
2001  * This is used for host entries and the addresses of the server itself.
2002  */
2003 isc_result_t
2004 mark_lease_unavailable(struct ipv6_pool *pool, const struct in6_addr *addr) {
2005  struct iasubopt *dummy_iasubopt;
2006  isc_result_t result;
2007 
2008  dummy_iasubopt = NULL;
2009  result = iasubopt_allocate(&dummy_iasubopt, MDL);
2010  if (result == ISC_R_SUCCESS) {
2011  dummy_iasubopt->addr = *addr;
2012  iasubopt_hash_add(pool->leases, &dummy_iasubopt->addr,
2013  sizeof(*addr), dummy_iasubopt, MDL);
2014  }
2015  return result;
2016 }
2017 
2018 /*
2019  * Add a pool.
2020  */
2021 isc_result_t
2023  struct ipv6_pool **new_pools;
2024 
2025  new_pools = dmalloc(sizeof(struct ipv6_pool *) * (num_pools+1), MDL);
2026  if (new_pools == NULL) {
2027  return ISC_R_NOMEMORY;
2028  }
2029 
2030  if (num_pools > 0) {
2031  memcpy(new_pools, pools,
2032  sizeof(struct ipv6_pool *) * num_pools);
2033  dfree(pools, MDL);
2034  }
2035  pools = new_pools;
2036 
2037  pools[num_pools] = NULL;
2038  ipv6_pool_reference(&pools[num_pools], pool, MDL);
2039  num_pools++;
2040  return ISC_R_SUCCESS;
2041 }
2042 
2043 static void
2044 cleanup_old_expired(struct ipv6_pool *pool) {
2045  struct iasubopt *tmp;
2046  struct ia_xx *ia;
2047  struct ia_xx *ia_active;
2048  unsigned char *tmpd;
2049  time_t timeout;
2050 
2051  while (pool->num_inactive > 0) {
2052  tmp = (struct iasubopt *)
2053  isc_heap_element(pool->inactive_timeouts, 1);
2054  if (tmp->hard_lifetime_end_time != 0) {
2057  } else {
2059  }
2060  if (cur_time < timeout) {
2061  break;
2062  }
2063 
2064  isc_heap_delete(pool->inactive_timeouts, tmp->inactive_index);
2065  pool->num_inactive--;
2066 
2067  if (tmp->ia != NULL) {
2068  /*
2069  * Check to see if this IA is in an active list,
2070  * but has no remaining resources. If so, remove it
2071  * from the active list.
2072  */
2073  ia = NULL;
2074  ia_reference(&ia, tmp->ia, MDL);
2075  ia_remove_iasubopt(ia, tmp, MDL);
2076  ia_active = NULL;
2077  tmpd = (unsigned char *)ia->iaid_duid.data;
2078  if ((ia->ia_type == D6O_IA_NA) &&
2079  (ia->num_iasubopt <= 0) &&
2080  (ia_hash_lookup(&ia_active, ia_na_active, tmpd,
2081  ia->iaid_duid.len, MDL) == 0) &&
2082  (ia_active == ia)) {
2083  ia_hash_delete(ia_na_active, tmpd,
2084  ia->iaid_duid.len, MDL);
2085  }
2086  if ((ia->ia_type == D6O_IA_TA) &&
2087  (ia->num_iasubopt <= 0) &&
2088  (ia_hash_lookup(&ia_active, ia_ta_active, tmpd,
2089  ia->iaid_duid.len, MDL) == 0) &&
2090  (ia_active == ia)) {
2091  ia_hash_delete(ia_ta_active, tmpd,
2092  ia->iaid_duid.len, MDL);
2093  }
2094  if ((ia->ia_type == D6O_IA_PD) &&
2095  (ia->num_iasubopt <= 0) &&
2096  (ia_hash_lookup(&ia_active, ia_pd_active, tmpd,
2097  ia->iaid_duid.len, MDL) == 0) &&
2098  (ia_active == ia)) {
2099  ia_hash_delete(ia_pd_active, tmpd,
2100  ia->iaid_duid.len, MDL);
2101  }
2102  ia_dereference(&ia, MDL);
2103  }
2104  iasubopt_dereference(&tmp, MDL);
2105  }
2106 }
2107 
2108 static void
2109 lease_timeout_support(void *vpool) {
2110  struct ipv6_pool *pool;
2111  struct iasubopt *lease;
2112 
2113  pool = (struct ipv6_pool *)vpool;
2114  for (;;) {
2115  /*
2116  * Get the next lease scheduled to expire.
2117  *
2118  * Note that if there are no leases in the pool,
2119  * expire_lease6() will return ISC_R_SUCCESS with
2120  * a NULL lease.
2121  *
2122  * expire_lease6() will call move_lease_to_inactive() which
2123  * calls ddns_removals() do we want that on the standard
2124  * expiration timer or a special 'depref' timer? Original
2125  * query from DH, moved here by SAR.
2126  */
2127  lease = NULL;
2128  if (expire_lease6(&lease, pool, cur_time) != ISC_R_SUCCESS) {
2129  break;
2130  }
2131  if (lease == NULL) {
2132  break;
2133  }
2134 
2135  write_ia(lease->ia);
2136 
2138  }
2139 
2140  /*
2141  * If appropriate commit and rotate the lease file
2142  * As commit_leases_timed() checks to see if we've done any writes
2143  * we don't bother tracking if this function called write _ia
2144  */
2145  (void) commit_leases_timed();
2146 
2147  /*
2148  * Do some cleanup of our expired leases.
2149  */
2150  cleanup_old_expired(pool);
2151 
2152  /*
2153  * Schedule next round of expirations.
2154  */
2156 }
2157 
2158 /*
2159  * For a given pool, add a timer that will remove the next
2160  * lease to expire.
2161  */
2162 void
2164  struct iasubopt *tmp;
2165  time_t timeout;
2166  time_t next_timeout;
2167  struct timeval tv;
2168 
2169  next_timeout = MAX_TIME;
2170 
2171  if (pool->num_active > 0) {
2172  tmp = (struct iasubopt *)
2173  isc_heap_element(pool->active_timeouts, 1);
2174  if (tmp->hard_lifetime_end_time < next_timeout) {
2175  next_timeout = tmp->hard_lifetime_end_time + 1;
2176  }
2177  }
2178 
2179  if (pool->num_inactive > 0) {
2180  tmp = (struct iasubopt *)
2181  isc_heap_element(pool->inactive_timeouts, 1);
2182  if (tmp->hard_lifetime_end_time != 0) {
2185  } else {
2186  timeout = tmp->soft_lifetime_end_time + 1;
2187  }
2188  if (timeout < next_timeout) {
2189  next_timeout = timeout;
2190  }
2191  }
2192 
2193  if (next_timeout < MAX_TIME) {
2194  tv.tv_sec = next_timeout;
2195  tv.tv_usec = 0;
2196  add_timeout(&tv, lease_timeout_support, pool,
2199  }
2200 }
2201 
2202 /*
2203  * Schedule timeouts across all pools.
2204  */
2205 void
2207  int i;
2208 
2209  for (i=0; i<num_pools; i++) {
2211  }
2212 }
2213 
2214 /*
2215  * Given an address and the length of the network mask, return
2216  * only the network portion.
2217  *
2218  * Examples:
2219  *
2220  * "fe80::216:6fff:fe49:7d9b", length 64 = "fe80::"
2221  * "2001:888:1936:2:216:6fff:fe49:7d9b", length 48 = "2001:888:1936::"
2222  */
2223 static void
2224 ipv6_network_portion(struct in6_addr *result,
2225  const struct in6_addr *addr, int bits) {
2226  unsigned char *addrp;
2227  int mask_bits;
2228  int bytes;
2229  int extra_bits;
2230  int i;
2231 
2232  static const unsigned char bitmasks[] = {
2233  0x00, 0xFE, 0xFC, 0xF8,
2234  0xF0, 0xE0, 0xC0, 0x80,
2235  };
2236 
2237  /*
2238  * Sanity check our bits. ;)
2239  */
2240  if ((bits < 0) || (bits > 128)) {
2241  log_fatal("ipv6_network_portion: bits %d not between 0 and 128",
2242  bits);
2243  }
2244 
2245  /*
2246  * Copy our address portion.
2247  */
2248  *result = *addr;
2249  addrp = ((unsigned char *)result) + 15;
2250 
2251  /*
2252  * Zero out masked portion.
2253  */
2254  mask_bits = 128 - bits;
2255  bytes = mask_bits / 8;
2256  extra_bits = mask_bits % 8;
2257 
2258  for (i=0; i<bytes; i++) {
2259  *addrp = 0;
2260  addrp--;
2261  }
2262  if (extra_bits) {
2263  *addrp &= bitmasks[extra_bits];
2264  }
2265 }
2266 
2267 /*
2268  * Determine if the given address/prefix is in the pool.
2269  */
2270 isc_boolean_t
2271 ipv6_in_pool(const struct in6_addr *addr, const struct ipv6_pool *pool) {
2272  struct in6_addr tmp;
2273 
2274  ipv6_network_portion(&tmp, addr, pool->bits);
2275  if (memcmp(&tmp, &pool->start_addr, sizeof(tmp)) == 0) {
2276  return ISC_TRUE;
2277  } else {
2278  return ISC_FALSE;
2279  }
2280 }
2281 
2282 /*
2283  * Find the pool that contains the given address.
2284  *
2285  * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
2286  * initialized to NULL
2287  */
2288 isc_result_t
2289 find_ipv6_pool(struct ipv6_pool **pool, u_int16_t type,
2290  const struct in6_addr *addr) {
2291  int i;
2292 
2293  if (pool == NULL) {
2294  log_error("%s(%d): NULL pointer reference", MDL);
2295  return DHCP_R_INVALIDARG;
2296  }
2297  if (*pool != NULL) {
2298  log_error("%s(%d): non-NULL pointer", MDL);
2299  return DHCP_R_INVALIDARG;
2300  }
2301 
2302  for (i=0; i<num_pools; i++) {
2303  if (pools[i]->pool_type != type)
2304  continue;
2305  if (ipv6_in_pool(addr, pools[i])) {
2307  return ISC_R_SUCCESS;
2308  }
2309  }
2310  return ISC_R_NOTFOUND;
2311 }
2312 
2313 /*
2314  * Helper function for the various functions that act across all
2315  * pools.
2316  */
2317 static isc_result_t
2318 change_leases(struct ia_xx *ia,
2319  isc_result_t (*change_func)(struct ipv6_pool *,
2320  struct iasubopt *)) {
2321  isc_result_t retval;
2322  isc_result_t renew_retval;
2323  struct ipv6_pool *pool;
2324  struct in6_addr *addr;
2325  int i;
2326 
2327  retval = ISC_R_SUCCESS;
2328  for (i=0; i<ia->num_iasubopt; i++) {
2329  pool = NULL;
2330  addr = &ia->iasubopt[i]->addr;
2331  if (find_ipv6_pool(&pool, ia->ia_type,
2332  addr) == ISC_R_SUCCESS) {
2333  renew_retval = change_func(pool, ia->iasubopt[i]);
2334  if (renew_retval != ISC_R_SUCCESS) {
2335  retval = renew_retval;
2336  }
2337  }
2338  /* XXXsk: should we warn if we don't find a pool? */
2339  }
2340  return retval;
2341 }
2342 
2343 /*
2344  * Renew all leases in an IA from all pools.
2345  *
2346  * The new lifetime should be in the soft_lifetime_end_time
2347  * and will be moved to hard_lifetime_end_time by renew_lease6.
2348  */
2349 isc_result_t
2350 renew_leases(struct ia_xx *ia) {
2351  return change_leases(ia, renew_lease6);
2352 }
2353 
2354 /*
2355  * Release all leases in an IA from all pools.
2356  */
2357 isc_result_t
2358 release_leases(struct ia_xx *ia) {
2359  return change_leases(ia, release_lease6);
2360 }
2361 
2362 /*
2363  * Decline all leases in an IA from all pools.
2364  */
2365 isc_result_t
2366 decline_leases(struct ia_xx *ia) {
2367  return change_leases(ia, decline_lease6);
2368 }
2369 
2370 #ifdef DHCPv6
2371 /*
2372  * Helper function to output leases.
2373  */
2374 static int write_error;
2375 
2376 static isc_result_t
2377 write_ia_leases(const void *name, unsigned len, void *value) {
2378  struct ia_xx *ia = (struct ia_xx *)value;
2379 
2380  if (!write_error) {
2381  if (!write_ia(ia)) {
2382  write_error = 1;
2383  }
2384  }
2385  return ISC_R_SUCCESS;
2386 }
2387 
2388 /*
2389  * Write all DHCPv6 information.
2390  */
2391 int
2392 write_leases6(void) {
2393  int nas, tas, pds;
2394 
2395  write_error = 0;
2397  nas = ia_hash_foreach(ia_na_active, write_ia_leases);
2398  if (write_error) {
2399  return 0;
2400  }
2401  tas = ia_hash_foreach(ia_ta_active, write_ia_leases);
2402  if (write_error) {
2403  return 0;
2404  }
2405  pds = ia_hash_foreach(ia_pd_active, write_ia_leases);
2406  if (write_error) {
2407  return 0;
2408  }
2409 
2410  log_info("Wrote %d NA, %d TA, %d PD leases to lease file.",
2411  nas, tas, pds);
2412  return 1;
2413 }
2414 #endif /* DHCPv6 */
2415 
2416 static isc_result_t
2417 mark_hosts_unavailable_support(const void *name, unsigned len, void *value) {
2418  struct host_decl *h;
2419  struct data_string fixed_addr;
2420  struct in6_addr addr;
2421  struct ipv6_pool *p;
2422 
2423  h = (struct host_decl *)value;
2424 
2425  /*
2426  * If the host has no address, we don't need to mark anything.
2427  */
2428  if (h->fixed_addr == NULL) {
2429  return ISC_R_SUCCESS;
2430  }
2431 
2432  /*
2433  * Evaluate the fixed address.
2434  */
2435  memset(&fixed_addr, 0, sizeof(fixed_addr));
2436  if (!evaluate_option_cache(&fixed_addr, NULL, NULL, NULL, NULL, NULL,
2437  &global_scope, h->fixed_addr, MDL)) {
2438  log_error("mark_hosts_unavailable: "
2439  "error evaluating host address.");
2440  return ISC_R_SUCCESS;
2441  }
2442  if (fixed_addr.len != 16) {
2443  log_error("mark_hosts_unavailable: "
2444  "host address is not 128 bits.");
2445  return ISC_R_SUCCESS;
2446  }
2447  memcpy(&addr, fixed_addr.data, 16);
2449 
2450  /*
2451  * Find the pool holding this host, and mark the address.
2452  * (I suppose it is arguably valid to have a host that does not
2453  * sit in any pool.)
2454  */
2455  p = NULL;
2456  if (find_ipv6_pool(&p, D6O_IA_NA, &addr) == ISC_R_SUCCESS) {
2457  mark_lease_unavailable(p, &addr);
2459  }
2460  if (find_ipv6_pool(&p, D6O_IA_TA, &addr) == ISC_R_SUCCESS) {
2461  mark_lease_unavailable(p, &addr);
2463  }
2464 
2465  return ISC_R_SUCCESS;
2466 }
2467 
2468 void
2470  hash_foreach(host_name_hash, mark_hosts_unavailable_support);
2471 }
2472 
2473 static isc_result_t
2474 mark_phosts_unavailable_support(const void *name, unsigned len, void *value) {
2475  struct host_decl *h;
2476  struct iaddrcidrnetlist *l;
2477  struct in6_addr pref;
2478  struct ipv6_pool *p;
2479 
2480  h = (struct host_decl *)value;
2481 
2482  /*
2483  * If the host has no prefix, we don't need to mark anything.
2484  */
2485  if (h->fixed_prefix == NULL) {
2486  return ISC_R_SUCCESS;
2487  }
2488 
2489  /*
2490  * Get the fixed prefixes.
2491  */
2492  for (l = h->fixed_prefix; l != NULL; l = l->next) {
2493  if (l->cidrnet.lo_addr.len != 16) {
2494  continue;
2495  }
2496  memcpy(&pref, l->cidrnet.lo_addr.iabuf, 16);
2497 
2498  /*
2499  * Find the pool holding this host, and mark the prefix.
2500  * (I suppose it is arguably valid to have a host that does not
2501  * sit in any pool.)
2502  */
2503  p = NULL;
2504  if (find_ipv6_pool(&p, D6O_IA_PD, &pref) != ISC_R_SUCCESS) {
2505  continue;
2506  }
2507  if (l->cidrnet.bits != p->units) {
2509  continue;
2510  }
2511  mark_lease_unavailable(p, &pref);
2513  }
2514 
2515  return ISC_R_SUCCESS;
2516 }
2517 
2518 void
2520  hash_foreach(host_name_hash, mark_phosts_unavailable_support);
2521 }
2522 
2523 void
2525  struct interface_info *ip;
2526  int i;
2527  struct ipv6_pool *p;
2528 
2529  ip = interfaces;
2530  while (ip != NULL) {
2531  for (i=0; i<ip->v6address_count; i++) {
2532  p = NULL;
2533  if (find_ipv6_pool(&p, D6O_IA_NA, &ip->v6addresses[i])
2534  == ISC_R_SUCCESS) {
2536  &ip->v6addresses[i]);
2538  }
2539  if (find_ipv6_pool(&p, D6O_IA_TA, &ip->v6addresses[i])
2540  == ISC_R_SUCCESS) {
2542  &ip->v6addresses[i]);
2544  }
2545  }
2546  ip = ip->next;
2547  }
2548 }
2549 
2567 isc_result_t
2568 ipv6_pond_allocate(struct ipv6_pond **pond, const char *file, int line) {
2569  struct ipv6_pond *tmp;
2570 
2571  if (pond == NULL) {
2572  log_error("%s(%d): NULL pointer reference", file, line);
2573  return DHCP_R_INVALIDARG;
2574  }
2575  if (*pond != NULL) {
2576  log_error("%s(%d): non-NULL pointer", file, line);
2577  return DHCP_R_INVALIDARG;
2578  }
2579 
2580  tmp = dmalloc(sizeof(*tmp), file, line);
2581  if (tmp == NULL) {
2582  return ISC_R_NOMEMORY;
2583  }
2584 
2585  tmp->refcnt = 1;
2586 
2587  *pond = tmp;
2588  return ISC_R_SUCCESS;
2589 }
2590 
2610 isc_result_t
2611 ipv6_pond_reference(struct ipv6_pond **pond, struct ipv6_pond *src,
2612  const char *file, int line) {
2613  if (pond == NULL) {
2614  log_error("%s(%d): NULL pointer reference", file, line);
2615  return DHCP_R_INVALIDARG;
2616  }
2617  if (*pond != NULL) {
2618  log_error("%s(%d): non-NULL pointer", file, line);
2619  return DHCP_R_INVALIDARG;
2620  }
2621  if (src == NULL) {
2622  log_error("%s(%d): NULL pointer reference", file, line);
2623  return DHCP_R_INVALIDARG;
2624  }
2625  *pond = src;
2626  src->refcnt++;
2627  return ISC_R_SUCCESS;
2628 }
2629 
2650 isc_result_t
2651 ipv6_pond_dereference(struct ipv6_pond **pond, const char *file, int line) {
2652  struct ipv6_pond *tmp;
2653 
2654  if ((pond == NULL) || (*pond == NULL)) {
2655  log_error("%s(%d): NULL pointer", file, line);
2656  return DHCP_R_INVALIDARG;
2657  }
2658 
2659  tmp = *pond;
2660  *pond = NULL;
2661 
2662  tmp->refcnt--;
2663  if (tmp->refcnt < 0) {
2664  log_error("%s(%d): negative refcnt", file, line);
2665  tmp->refcnt = 0;
2666  }
2667  if (tmp->refcnt == 0) {
2668  dfree(tmp, file, line);
2669  }
2670 
2671  return ISC_R_SUCCESS;
2672 }
2673 
2674 #ifdef EUI_64
2675 /*
2676  * Enables/disables EUI-64 address assignment for a pond
2677  *
2678  * Excecutes statements down to the pond's scope and sets the pond's
2679  * use_eui_64 flag accordingly. In addition it iterates over the
2680  * pond's pools ensuring they are all /64. Anything else is deemed
2681  * invalid for EUI-64. It returns the number of invalid pools
2682  * detected. This is done post-parsing as use-eui-64 can be set
2683  * down to the pool scope and we can't reliably do it until the
2684  * entire configuration has been parsed.
2685  */
2686 int
2687 set_eui_64(struct ipv6_pond *pond) {
2688  int invalid_cnt = 0;
2689  struct option_state* options = NULL;
2690  struct option_cache *oc = NULL;
2691  option_state_allocate(&options, MDL);
2692  execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL, options,
2693  &global_scope, pond->group, NULL, NULL);
2694 
2695  pond->use_eui_64 =
2696  ((oc = lookup_option(&server_universe, options, SV_USE_EUI_64))
2697  &&
2698  (evaluate_boolean_option_cache (NULL, NULL, NULL, NULL,
2699  options, NULL, &global_scope,
2700  oc, MDL)));
2701  if (pond->use_eui_64) {
2702  // Check all pools are valid
2703  int i = 0;
2704  struct ipv6_pool* p;
2705  while((p = pond->ipv6_pools[i++]) != NULL) {
2706  if (p->bits != 64) {
2707  log_error("Pool %s/%d cannot use EUI-64,"
2708  " prefix must 64",
2709  pin6_addr(&p->start_addr), p->bits);
2710  invalid_cnt++;
2711  } else {
2712  log_debug("Pool: %s/%d - will use EUI-64",
2713  pin6_addr(&p->start_addr), p->bits);
2714  }
2715  }
2716  }
2717 
2718  /* Don't need the options anymore. */
2719  option_state_dereference(&options, MDL);
2720  return (invalid_cnt);
2721 }
2722 #endif
2723 
2724 /*
2725  * Emits a log for each pond that has been flagged as being a "jumbo range"
2726  * A pond is considered a "jumbo range" when the total number of elements
2727  * exceeds the maximum value of POND_TRACK_MAX (currently maximum value
2728  * that can be stored by ipv6_pond.num_total). Since we disable threshold
2729  * logging for jumbo ranges, we need to report this to the user. This
2730  * function allows us to report jumbo ponds after config parsing, so the
2731  * logs can be seen both on the console (-T) and the log facility (i.e syslog).
2732  *
2733  * Note, threshold logging is done at the pond level, so we need emit a list
2734  * of the addresses ranges of the pools in the pond affected.
2735  */
2736 void
2738  struct shared_network* s;
2739  char log_buf[1084];
2740 #ifdef EUI_64
2741  int invalid_cnt = 0;
2742 #endif
2743 
2744  /* Loop thru all the networks looking for jumbo range ponds */
2745  for (s = shared_networks; s; s = s -> next) {
2746  struct ipv6_pond* pond = s->ipv6_pond;
2747  while (pond) {
2748 #ifdef EUI_64
2749  /* while we're here, set the pond's use_eui_64 flag */
2750  invalid_cnt += set_eui_64(pond);
2751 #endif
2752  /* if its a jumbo and has pools(sanity check) */
2753  if (pond->jumbo_range == 1 && (pond->ipv6_pools)) {
2754  struct ipv6_pool* pool;
2755  char *bufptr = log_buf;
2756  size_t space_left = sizeof(log_buf) - 1;
2757  int i = 0;
2758  int used = 0;
2759 
2760  /* Build list containing the start-address/CIDR
2761  * of each pool */
2762  *bufptr = '\0';
2763  while ((pool = pond->ipv6_pools[i++]) &&
2764  (space_left > (INET6_ADDRSTRLEN + 6))) {
2765  /* more than one so add a comma */
2766  if (i > 1) {
2767  *bufptr++ = ',';
2768  *bufptr++ = ' ';
2769  *bufptr = '\0';
2770  space_left -= 2;
2771  }
2772 
2773  /* add the address */
2774  inet_ntop(AF_INET6, &pool->start_addr,
2775  bufptr, INET6_ADDRSTRLEN);
2776 
2777  used = strlen(bufptr);
2778  bufptr += used;
2779  space_left -= used;
2780 
2781  /* add the CIDR */
2782  sprintf (bufptr, "/%d",pool->bits);
2783  used = strlen(bufptr);
2784  bufptr += used;
2785  space_left -= used;
2786  *bufptr = '\0';
2787  }
2788 
2789  log_info("Threshold logging disabled for shared"
2790  " subnet of ranges: %s", log_buf);
2791  }
2792  pond = pond->next;
2793  }
2794 
2795  }
2796 
2797 #ifdef EUI_64
2798  if (invalid_cnt) {
2799  log_fatal ("%d pool(s) are invalid for EUI-64 use",
2800  invalid_cnt);
2801  }
2802 #endif
2803 }
2804 
2805 
2806 /*
2807  * \brief Tests that 16-bit hardware type is less than 256
2808  *
2809  * XXX: DHCPv6 gives a 16-bit field for the htype. DHCPv4 gives an
2810  * 8-bit field. To change the semantics of the generic 'hardware'
2811  * structure, we would have to adjust many DHCPv4 sources (from
2812  * interface to DHCPv4 lease code), and we would have to update the
2813  * 'hardware' config directive (probably being reverse compatible and
2814  * providing a new upgrade/replacement primitive). This is a little
2815  * too much to change for now. Hopefully we will revisit this before
2816  * hardware types exceeding 8 bits are assigned.
2817  *
2818  * Uses a static variable to limit log occurence to once per startup
2819  *
2820  * \param htype hardware type value to test
2821  *
2822  * \return returns 0 if the value is too large
2823  *
2824 */
2825 int htype_bounds_check(uint16_t htype) {
2826  static int log_once = 0;
2827 
2828  if (htype & 0xFF00) {
2829  if (!log_once) {
2830  log_error("Attention: At least one client advertises a "
2831  "hardware type of %d, which exceeds the software "
2832  "limitation of 255.", htype);
2833  log_once = 1;
2834  }
2835 
2836  return(0);
2837  }
2838 
2839  return(1);
2840 }
2841 
2867  struct packet *packet,
2868  struct option_state *opt_state,
2869  const char *file, int line) {
2870  int found = 0;
2871  int htype;
2872  int hlen;
2873 
2874  /* For directly connected clients, use packet:haddr if populated */
2875  if (packet->dhcpv6_container_packet == NULL) {
2876  if (packet->haddr) {
2877  htype = packet->haddr->hbuf[0];
2878  hlen = packet->haddr->hlen - 1,
2879  log_debug("find_hosts_by_haddr6: using packet->haddr,"
2880  " type: %d, len: %d", htype, hlen);
2881  found = find_hosts_by_haddr (hp, htype,
2882  &packet->haddr->hbuf[1],
2883  hlen, MDL);
2884  }
2885  } else {
2886  /* The first container packet is the from the relay directly
2887  * connected to the client. Per RFC 6939, that is only relay
2888  * that may supply the client linklayer address option. */
2889  struct packet *relay_packet = packet->dhcpv6_container_packet;
2890  struct option_state *relay_state = relay_packet->options;
2891  struct data_string rel_addr;
2892  struct option_cache *oc;
2893 
2894  /* Look for the option in the first relay packet */
2895  oc = lookup_option(&dhcpv6_universe, relay_state,
2897  if (!oc) {
2898  /* Not there, so bail */
2899  return (0);
2900  }
2901 
2902  /* The option is present, fetch the address data */
2903  memset(&rel_addr, 0, sizeof(rel_addr));
2904  if (!evaluate_option_cache(&rel_addr, relay_packet, NULL, NULL,
2905  relay_state, NULL, &global_scope,
2906  oc, MDL)) {
2907  log_error("find_hosts_by_add6:"
2908  "Error evaluating option cache");
2909  return (0);
2910  }
2911 
2912  /* The relay address data should be:
2913  * byte 0 - 1 = hardware type
2914  * bytes 2 - hlen = hardware address
2915  * where hlen ( hardware address len) is option data len - 2 */
2916  hlen = rel_addr.len - 2;
2917  if (hlen > 0 && hlen <= HARDWARE_ADDR_LEN) {
2918  htype = getUShort(rel_addr.data);
2919  if (htype_bounds_check(htype)) {
2920  /* Looks valid, let's search with it */
2921  log_debug("find_hosts_by_haddr6:"
2922  "using relayed haddr"
2923  " type: %d, len: %d", htype, hlen);
2924  found = find_hosts_by_haddr (hp, htype,
2925  &rel_addr.data[2],
2926  hlen, MDL);
2927  }
2928  }
2929 
2930  data_string_forget(&rel_addr, MDL);
2931  }
2932 
2933  return (found);
2934 }
2935 
2936 /*
2937  * find_host_by_duid_chaddr() synthesizes a DHCPv4-like 'hardware'
2938  * parameter from a DHCPv6 supplied DUID (client-identifier option),
2939  * and may seek to use client or relay supplied hardware addresses.
2940  */
2941 int
2943  const struct data_string *client_id) {
2944  int htype, hlen;
2945  const unsigned char *chaddr;
2946 
2947  /*
2948  * The DUID-LL and DUID-LLT must have a 2-byte DUID type and 2-byte
2949  * htype.
2950  */
2951  if (client_id->len < 4)
2952  return 0;
2953 
2954  /*
2955  * The third and fourth octets of the DUID-LL and DUID-LLT
2956  * is the hardware type, but in 16 bits.
2957  */
2958  htype = getUShort(client_id->data + 2);
2959  hlen = 0;
2960  chaddr = NULL;
2961 
2962  /* The first two octets of the DUID identify the type. */
2963  switch(getUShort(client_id->data)) {
2964  case DUID_LLT:
2965  if (client_id->len > 8) {
2966  hlen = client_id->len - 8;
2967  chaddr = client_id->data + 8;
2968  }
2969  break;
2970 
2971  case DUID_LL:
2972  /*
2973  * Note that client_id->len must be greater than or equal
2974  * to four to get to this point in the function.
2975  */
2976  hlen = client_id->len - 4;
2977  chaddr = client_id->data + 4;
2978  break;
2979 
2980  default:
2981  break;
2982  }
2983 
2984  if ((hlen == 0) || (hlen > HARDWARE_ADDR_LEN) ||
2985  !htype_bounds_check(htype)) {
2986  return (0);
2987  }
2988 
2989  return find_hosts_by_haddr(host, htype, chaddr, hlen, MDL);
2990 }
2991 
2992 /*
2993  * \brief Finds a host record that matches the packet, if any
2994  *
2995  * This function centralizes the logic for matching v6 client
2996  * packets to host declarations. We check in the following order
2997  * for matches with:
2998  *
2999  * 1. client_id if specified
3000  * 2. MAC address when explicitly available
3001  * 3. packet option
3002  * 4. synthesized hardware address - this is done last as some
3003  * synthesis methods are not consided to be reliable
3004  *
3005  * \param[out] host - pointer to storage for the located host
3006  * \param packet - inbound client packet
3007  * \param client_id - client identifier (if one)
3008  * \param file - source file
3009  * \param line - source file line number
3010  * \return non-zero if a host is found, zero otherwise
3011 */
3012 int
3013 find_hosts6(struct host_decl** host, struct packet* packet,
3014  const struct data_string* client_id, char* file, int line) {
3015  return (find_hosts_by_uid(host, client_id->data, client_id->len, MDL)
3018  || find_hosts_by_duid_chaddr(host, client_id));
3019 }
3020 
3021 /* unittest moved to server/tests/mdb6_unittest.c */
#define FTS_ABANDONED
Definition: dhcpd.h:541
struct iaddrcidrnet cidrnet
Definition: inet.h:77
void mark_interfaces_unavailable(void)
Definition: mdb6.c:2524
ia_hash_t * ia_ta_active
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:2866
struct ipv6_pond * next
Definition: dhcpd.h:1731
isc_boolean_t lease6_usable(struct iasubopt *lease)
Check if address is available to a lease.
Definition: mdb6.c:1552
const char int line
Definition: dhcpd.h:3782
isc_result_t mark_lease_unavailable(struct ipv6_pool *pool, const struct in6_addr *addr)
Definition: mdb6.c:2004
struct binding_scope * global_scope
Definition: tree.c:38
isc_boolean_t prefix6_exists(const struct ipv6_pool *pool, const struct in6_addr *pref, u_int8_t plen)
Definition: mdb6.c:1981
void report_jumbo_ranges()
Definition: mdb6.c:2737
struct on_star on_star
Definition: dhcpd.h:583
Definition: dhcpd.h:560
unsigned len
Definition: tree.h:79
int executable_statement_dereference(struct executable_statement **ptr, const char *file, int line)
Definition: execute.c:623
int bits
Definition: inet.h:72
u_int8_t hlen
Definition: dhcpd.h:492
#define FTS_FREE
Definition: dhcpd.h:537
struct shared_network * shared_networks
Definition: mdb.c:33
Definition: dhcpd.h:1665
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:1892
int active_index
Definition: dhcpd.h:1649
int units
Definition: dhcpd.h:1704
int max_iasubopt
Definition: dhcpd.h:1670
struct lease_state * state
Definition: dhcpd.h:628
isc_result_t renew_lease6(struct ipv6_pool *pool, struct iasubopt *lease)
Renew a lease in the pool.
Definition: mdb6.c:1623
struct universe server_universe
Definition: stables.c:176
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
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
#define EUI_64_ID_LEN
Definition: dhcp6.h:282
struct ipv6_pond * ipv6_pond
Definition: dhcpd.h:1054
isc_result_t iasubopt_dereference(struct iasubopt **iasubopt, const char *file, int line)
Definition: mdb6.c:261
#define MDL
Definition: omapip.h:567
int find_hosts_by_option(struct host_decl **, struct packet *, struct option_state *, const char *, int)
Definition: mdb.c:637
unsigned char iabuf[16]
Definition: inet.h:33
#define print_hex_1(len, data, limit)
Definition: dhcpd.h:2622
dhcp_context_t dhcp_gbl_ctx
Definition: isclib.c:33
#define DHCP_R_INVALIDARG
Definition: result.h:48
isc_result_t find_ipv6_pool(struct ipv6_pool **pool, u_int16_t type, const struct in6_addr *addr)
Definition: mdb6.c:2289
#define FTS_RELEASED
Definition: dhcpd.h:540
int int int log_debug(const char *,...) __attribute__((__format__(__printf__
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:1812
struct executable_statement * on_release
Definition: dhcpd.h:556
isc_result_t ia_dereference(struct ia_xx **ia, const char *file, int line)
Definition: mdb6.c:403
#define D6O_CLIENT_LINKLAYER_ADDR
Definition: dhcp6.h:108
void data_string_forget(struct data_string *data, const char *file, int line)
Definition: alloc.c:1339
isc_result_t ia_add_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt, const char *file, int line)
Definition: mdb6.c:439
struct in6_addr start_addr
Definition: dhcpd.h:1702
struct option_cache * fixed_addr
Definition: dhcpd.h:972
int find_hosts_by_duid_chaddr(struct host_decl **host, const struct data_string *client_id)
Definition: mdb6.c:2942
#define DUID_LL
Definition: dhcp6.h:169
int log_error(const char *,...) __attribute__((__format__(__printf__
isc_result_t release_leases(struct ia_xx *ia)
Definition: mdb6.c:2358
#define FTS_EXPIRED
Definition: dhcpd.h:539
int binding_scope_dereference(struct binding_scope **ptr, const char *file, int line)
Definition: tree.c:3786
struct on_star on_star
Definition: dhcpd.h:1661
struct binding_scope * scope
Definition: dhcpd.h:1635
void add_timeout(struct timeval *when, void(*)(void *) where, void *what, tvref_t ref, tvunref_t unref)
Definition: dispatch.c:206
void(* tvunref_t)(void *, const char *, int)
Definition: dhcpd.h:1438
void ia_remove_all_lease(struct ia_xx *ia, const char *file, int line)
Definition: mdb6.c:504
unsigned len
Definition: inet.h:32
int find_hosts_by_haddr(struct host_decl **, int, const unsigned char *, unsigned, const char *, int)
Definition: mdb.c:609
int refcnt
Definition: dhcpd.h:1730
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
#define EXPIRED_IPV6_CLEANUP_TIME
Definition: dhcpd.h:1646
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(* tvref_t)(void *, void *, const char *, int)
Definition: dhcpd.h:1437
struct option_state * options
Definition: dhcpd.h:449
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
int write_leases6(void)
void log_fatal(const char *,...) __attribute__((__format__(__printf__
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
#define D6O_IA_TA
Definition: dhcp6.h:33
isc_mem_t * mctx
Definition: isclib.h:92
isc_boolean_t lease6_exists(const struct ipv6_pool *pool, const struct in6_addr *addr)
Definition: mdb6.c:1524
int inactive_index
Definition: dhcpd.h:1650
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 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:563
int option_state_allocate(struct option_state **ptr, const char *file, int line)
Definition: alloc.c:846
time_t hard_lifetime_end_time
Definition: dhcpd.h:1636
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
host_hash_t * host_name_hash
Definition: mdb.c:36
Definition: dhcpd.h:1015
unsigned do_string_hash(const void *, unsigned, unsigned)
Definition: hash.c:266
ia_hash_t * ia_na_active
struct ipv6_pool * ipv6_pool
Definition: dhcpd.h:1641
int buffer_allocate(struct buffer **ptr, unsigned len, const char *file, int line)
Definition: alloc.c:679
isc_result_t ipv6_pond_allocate(struct ipv6_pond **pond, const char *file, int line)
Create a new IPv6 pond structure.
Definition: mdb6.c:2568
Definition: dhcpd.h:405
int write_server_duid(void)
struct iaddrcidrnetlist * next
Definition: inet.h:76
char * name
Definition: dhcpd.h:964
isc_boolean_t ia_equal(const struct ia_xx *a, const struct ia_xx *b)
Definition: mdb6.c:518
u_int8_t plen
Definition: dhcpd.h:1633
struct data_string iaid_duid
Definition: dhcpd.h:1667
#define cur_time
Definition: dhcpd.h:2110
Definition: ip.h:47
int refcnt
Definition: dhcpd.h:1666
u_int32_t getUShort(const unsigned char *)
struct hardware * haddr
Definition: dhcpd.h:435
void dfree(void *, const char *, int)
Definition: alloc.c:145
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.
int bits
Definition: dhcpd.h:1703
int jumbo_range
Definition: dhcpd.h:1748
isc_result_t renew_leases(struct ia_xx *ia)
Definition: mdb6.c:2350
int refcnt
Definition: dhcpd.h:1631
isc_result_t decline_leases(struct ia_xx *ia)
Definition: mdb6.c:2366
struct option_cache * lookup_option(struct universe *universe, struct option_state *options, unsigned code)
Definition: options.c:2465
iasubopt_hash_t * leases
Definition: dhcpd.h:1705
int num_iasubopt
Definition: dhcpd.h:1669
int int log_info(const char *,...) __attribute__((__format__(__printf__
struct ipv6_pool ** ipv6_pools
Definition: dhcpd.h:1740
u_int16_t ia_type
Definition: dhcpd.h:1668
binding_state_t state
Definition: dhcpd.h:1634
const char * pin6_addr(const struct in6_addr *)
void * dmalloc(size_t, const char *, int)
Definition: alloc.c:57
struct interface_info * interfaces
Definition: discover.c:42
int find_hosts_by_uid(struct host_decl **, const unsigned char *, unsigned, const char *, int)
Definition: mdb.c:629
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
void cleanup(void)
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
#define DEFAULT_HASH_SIZE
Definition: hash.h:33
ipv6_pool structure
Definition: dhcpd.h:1699
void isc_heap_destroy(isc_heap_t **heapp)
Destroys a heap.
int refcnt
Definition: dhcpd.h:1700
struct iaddrcidrnetlist * fixed_prefix
Definition: dhcpd.h:973
int option_state_dereference(struct option_state **ptr, const char *file, int line)
Definition: alloc.c:911
ia_hash_t * ia_pd_active
isc_result_t ddns_removals(struct lease *, struct iasubopt *, struct dhcp_ddns_cb *, isc_boolean_t)
int commit_leases_timed(void)
Definition: db.c:1064
#define IAID_LEN
Definition: dhcp6.h:283
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...
void isc_heap_delete(isc_heap_t *heap, unsigned int index)
Deletes an element from a heap, by element index.
int hash_foreach(struct hash_table *, hash_foreach_func)
Definition: hash.c:511
isc_result_t add_lease6(struct ipv6_pool *pool, struct iasubopt *lease, time_t valid_lifetime_end_time)
Definition: mdb6.c:1414
struct universe dhcpv6_universe
Definition: tables.c:343
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
isc_heap_t * inactive_timeouts
Definition: dhcpd.h:1710
#define D6O_IA_NA
Definition: dhcp6.h:32
isc_result_t iasubopt_reference(struct iasubopt **iasubopt, struct iasubopt *src, const char *file, int line)
Definition: mdb6.c:234
HASH_FUNCTIONS(ia, unsigned char *, struct ia_xx, ia_hash_t, ia_reference, ia_dereference, do_string_hash)
Definition: mdb6.c:180
int find_hosts6(struct host_decl **host, struct packet *packet, const struct data_string *client_id, char *file, int line)
Definition: mdb6.c:3013
unsigned char data[1]
Definition: tree.h:62
isc_heap_t * active_timeouts
Definition: dhcpd.h:1708
isc_result_t decline_lease6(struct ipv6_pool *pool, struct iasubopt *lease)
Definition: mdb6.c:1774
void schedule_lease_timeout(struct ipv6_pool *pool)
Definition: mdb6.c:2163
time_t soft_lifetime_end_time
Definition: dhcpd.h:1637
struct iaddr lo_addr
Definition: inet.h:71
isc_result_t ipv6_pond_dereference(struct ipv6_pond **pond, const char *file, int line)
de-reference an IPv6 pond structure.
Definition: mdb6.c:2651
isc_boolean_t ipv6_in_pool(const struct in6_addr *addr, const struct ipv6_pool *pool)
Definition: mdb6.c:2271
void mark_phosts_unavailable(void)
Definition: mdb6.c:2519
isc_result_t expire_lease6(struct iasubopt **leasep, struct ipv6_pool *pool, time_t now)
Definition: mdb6.c:1740
u_int8_t hbuf[HARDWARE_ADDR_LEN+1]
Definition: dhcpd.h:493
isc_result_t release_lease6(struct ipv6_pool *pool, struct iasubopt *lease)
Definition: mdb6.c:1799
#define MAX_TIME
Definition: dhcpd.h:1615
struct data_string data
Definition: dhcpd.h:390
ipv6_pond structure
Definition: dhcpd.h:1729
#define HARDWARE_ADDR_LEN
Definition: dhcpd.h:486
void * isc_heap_element(isc_heap_t *heap, unsigned int index)
Returns the element for a specific element index.
#define D6O_IA_PD
Definition: dhcp6.h:54
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:2611
struct ipv6_pool ** pools
#define DUID_LLT
Definition: dhcp6.h:167
struct iasubopt ** iasubopt
Definition: dhcpd.h:1672
int write_ia(const struct ia_xx *)
Definition: db.c:518
struct ia_xx * ia
Definition: dhcpd.h:1640
struct executable_statement * on_expiry
Definition: dhcpd.h:554
struct shared_network * next
Definition: dhcpd.h:1045
const char * file
Definition: dhcpd.h:3782
isc_result_t ia_reference(struct ia_xx **ia, struct ia_xx *src, const char *file, int line)
Definition: mdb6.c:377
struct in6_addr addr
Definition: dhcpd.h:1632
struct executable_statement * on_commit
Definition: dhcpd.h:555
const unsigned char * data
Definition: tree.h:78
isc_result_t add_ipv6_pool(struct ipv6_pool *pool)
Definition: mdb6.c:2022
struct binding_scope * scope
Definition: dhcpd.h:575
void data_string_copy(struct data_string *dest, const struct data_string *src, const char *file, int line)
Definition: alloc.c:1323
void mark_hosts_unavailable(void)
Definition: mdb6.c:2469
u_int16_t pool_type
Definition: dhcpd.h:1701
isc_result_t isc_heap_insert(isc_heap_t *heap, void *elt)
Inserts a new element into a heap.
int htype_bounds_check(uint16_t htype)
Definition: mdb6.c:2825
void ia_remove_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt, const char *file, int line)
Definition: mdb6.c:476
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:1304
u_int8_t binding_state_t
Definition: dhcpd.h:544
struct group * group
Definition: dhcpd.h:1732
void schedule_all_ipv6_lease_timeouts(void)
Definition: mdb6.c:2206
struct buffer * buffer
Definition: tree.h:77
struct packet * dhcpv6_container_packet
Definition: dhcpd.h:422
#define FTS_ACTIVE
Definition: dhcpd.h:538