ISC DHCP  4.3.1
A reference DHCPv4 and DHCPv6 implementation
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
mdb6.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-2013 by Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
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->heap_index = -1;
220  tmp->plen = 255;
221 
222  *iasubopt = tmp;
223  return ISC_R_SUCCESS;
224 }
225 
226 /*
227  * Reference an IAADDR/PREFIX structure.
228  *
229  * - iasubopt must be a pointer to a (struct iasubopt *) pointer previously
230  * initialized to NULL
231  */
232 isc_result_t
233 iasubopt_reference(struct iasubopt **iasubopt, struct iasubopt *src,
234  const char *file, int line) {
235  if (iasubopt == NULL) {
236  log_error("%s(%d): NULL pointer reference", file, line);
237  return DHCP_R_INVALIDARG;
238  }
239  if (*iasubopt != NULL) {
240  log_error("%s(%d): non-NULL pointer", file, line);
241  return DHCP_R_INVALIDARG;
242  }
243  if (src == NULL) {
244  log_error("%s(%d): NULL pointer reference", file, line);
245  return DHCP_R_INVALIDARG;
246  }
247  *iasubopt = src;
248  src->refcnt++;
249  return ISC_R_SUCCESS;
250 }
251 
252 
253 /*
254  * Dereference an IAADDR/PREFIX structure.
255  *
256  * If it is the last reference, then the memory for the
257  * structure is freed.
258  */
259 isc_result_t
260 iasubopt_dereference(struct iasubopt **iasubopt, const char *file, int line) {
261  struct iasubopt *tmp;
262 
263  if ((iasubopt == NULL) || (*iasubopt == NULL)) {
264  log_error("%s(%d): NULL pointer", file, line);
265  return DHCP_R_INVALIDARG;
266  }
267 
268  tmp = *iasubopt;
269  *iasubopt = NULL;
270 
271  tmp->refcnt--;
272  if (tmp->refcnt < 0) {
273  log_error("%s(%d): negative refcnt", file, line);
274  tmp->refcnt = 0;
275  }
276  if (tmp->refcnt == 0) {
277  if (tmp->ia != NULL) {
278  ia_dereference(&(tmp->ia), file, line);
279  }
280  if (tmp->ipv6_pool != NULL) {
281  ipv6_pool_dereference(&(tmp->ipv6_pool), file, line);
282  }
283  if (tmp->scope != NULL) {
284  binding_scope_dereference(&tmp->scope, file, line);
285  }
286 
287  if (tmp->on_star.on_expiry != NULL) {
289  (&tmp->on_star.on_expiry, MDL);
290  }
291  if (tmp->on_star.on_commit != NULL) {
293  (&tmp->on_star.on_commit, MDL);
294  }
295  if (tmp->on_star.on_release != NULL) {
297  (&tmp->on_star.on_release, MDL);
298  }
299 
300  dfree(tmp, file, line);
301  }
302 
303  return ISC_R_SUCCESS;
304 }
305 
306 /*
307  * Make the key that we use for IA.
308  */
309 isc_result_t
310 ia_make_key(struct data_string *key, u_int32_t iaid,
311  const char *duid, unsigned int duid_len,
312  const char *file, int line) {
313 
314  memset(key, 0, sizeof(*key));
315  key->len = duid_len + sizeof(iaid);
316  if (!buffer_allocate(&(key->buffer), key->len, file, line)) {
317  return ISC_R_NOMEMORY;
318  }
319  key->data = key->buffer->data;
320  memcpy((char *)key->data, &iaid, sizeof(iaid));
321  memcpy((char *)key->data + sizeof(iaid), duid, duid_len);
322 
323  return ISC_R_SUCCESS;
324 }
325 
326 /*
327  * Create a new IA structure.
328  *
329  * - ia must be a pointer to a (struct ia_xx *) pointer previously
330  * initialized to NULL
331  * - iaid and duid are values from the client
332  *
333  * XXXsk: we don't concern ourself with the byte order of the IAID,
334  * which might be a problem if we transfer this structure
335  * between machines of different byte order
336  */
337 isc_result_t
338 ia_allocate(struct ia_xx **ia, u_int32_t iaid,
339  const char *duid, unsigned int duid_len,
340  const char *file, int line) {
341  struct ia_xx *tmp;
342 
343  if (ia == NULL) {
344  log_error("%s(%d): NULL pointer reference", file, line);
345  return DHCP_R_INVALIDARG;
346  }
347  if (*ia != NULL) {
348  log_error("%s(%d): non-NULL pointer", file, line);
349  return DHCP_R_INVALIDARG;
350  }
351 
352  tmp = dmalloc(sizeof(*tmp), file, line);
353  if (tmp == NULL) {
354  return ISC_R_NOMEMORY;
355  }
356 
357  if (ia_make_key(&tmp->iaid_duid, iaid,
358  duid, duid_len, file, line) != ISC_R_SUCCESS) {
359  dfree(tmp, file, line);
360  return ISC_R_NOMEMORY;
361  }
362 
363  tmp->refcnt = 1;
364 
365  *ia = tmp;
366  return ISC_R_SUCCESS;
367 }
368 
369 /*
370  * Reference an IA structure.
371  *
372  * - ia must be a pointer to a (struct ia_xx *) pointer previously
373  * initialized to NULL
374  */
375 isc_result_t
376 ia_reference(struct ia_xx **ia, struct ia_xx *src,
377  const char *file, int line) {
378  if (ia == NULL) {
379  log_error("%s(%d): NULL pointer reference", file, line);
380  return DHCP_R_INVALIDARG;
381  }
382  if (*ia != NULL) {
383  log_error("%s(%d): non-NULL pointer", file, line);
384  return DHCP_R_INVALIDARG;
385  }
386  if (src == NULL) {
387  log_error("%s(%d): NULL pointer reference", file, line);
388  return DHCP_R_INVALIDARG;
389  }
390  *ia = src;
391  src->refcnt++;
392  return ISC_R_SUCCESS;
393 }
394 
395 /*
396  * Dereference an IA structure.
397  *
398  * If it is the last reference, then the memory for the
399  * structure is freed.
400  */
401 isc_result_t
402 ia_dereference(struct ia_xx **ia, const char *file, int line) {
403  struct ia_xx *tmp;
404  int i;
405 
406  if ((ia == NULL) || (*ia == NULL)) {
407  log_error("%s(%d): NULL pointer", file, line);
408  return DHCP_R_INVALIDARG;
409  }
410 
411  tmp = *ia;
412  *ia = NULL;
413 
414  tmp->refcnt--;
415  if (tmp->refcnt < 0) {
416  log_error("%s(%d): negative refcnt", file, line);
417  tmp->refcnt = 0;
418  }
419  if (tmp->refcnt == 0) {
420  if (tmp->iasubopt != NULL) {
421  for (i=0; i<tmp->num_iasubopt; i++) {
422  iasubopt_dereference(&(tmp->iasubopt[i]),
423  file, line);
424  }
425  dfree(tmp->iasubopt, file, line);
426  }
427  data_string_forget(&(tmp->iaid_duid), file, line);
428  dfree(tmp, file, line);
429  }
430  return ISC_R_SUCCESS;
431 }
432 
433 
434 /*
435  * Add an IAADDR/PREFIX entry to an IA structure.
436  */
437 isc_result_t
438 ia_add_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt,
439  const char *file, int line) {
440  int max;
441  struct iasubopt **new;
442 
443  /*
444  * Grow our array if we need to.
445  *
446  * Note: we pick 4 as the increment, as that seems a reasonable
447  * guess as to how many addresses/prefixes we might expect
448  * on an interface.
449  */
450  if (ia->max_iasubopt <= ia->num_iasubopt) {
451  max = ia->max_iasubopt + 4;
452  new = dmalloc(max * sizeof(struct iasubopt *), file, line);
453  if (new == NULL) {
454  return ISC_R_NOMEMORY;
455  }
456  memcpy(new, ia->iasubopt,
457  ia->num_iasubopt * sizeof(struct iasubopt *));
458  ia->iasubopt = new;
459  ia->max_iasubopt = max;
460  }
461 
462  iasubopt_reference(&(ia->iasubopt[ia->num_iasubopt]), iasubopt,
463  file, line);
464  ia->num_iasubopt++;
465 
466  return ISC_R_SUCCESS;
467 }
468 
469 /*
470  * Remove an IAADDR/PREFIX entry to an IA structure.
471  *
472  * Note: if a suboption appears more than once, then only ONE will be removed.
473  */
474 void
476  const char *file, int line) {
477  int i, j;
478  if (ia == NULL || iasubopt == NULL)
479  return;
480 
481  for (i=0; i<ia->num_iasubopt; i++) {
482  if (ia->iasubopt[i] == iasubopt) {
483  /* remove this sub option */
484  iasubopt_dereference(&(ia->iasubopt[i]), file, line);
485  /* move remaining suboption pointers down one */
486  for (j=i+1; j < ia->num_iasubopt; j++) {
487  ia->iasubopt[j-1] = ia->iasubopt[j];
488  }
489  /* decrease our total count */
490  /* remove the back-reference in the suboption itself */
491  ia_dereference(&iasubopt->ia, file, line);
492  ia->num_iasubopt--;
493  return;
494  }
495  }
496  log_error("%s(%d): IAADDR/PREFIX not in IA", file, line);
497 }
498 
499 /*
500  * Remove all addresses/prefixes from an IA.
501  */
502 void
503 ia_remove_all_lease(struct ia_xx *ia, const char *file, int line) {
504  int i;
505 
506  for (i=0; i<ia->num_iasubopt; i++) {
507  ia_dereference(&(ia->iasubopt[i]->ia), file, line);
508  iasubopt_dereference(&(ia->iasubopt[i]), file, line);
509  }
510  ia->num_iasubopt = 0;
511 }
512 
513 /*
514  * Compare two IA.
515  */
516 isc_boolean_t
517 ia_equal(const struct ia_xx *a, const struct ia_xx *b)
518 {
519  isc_boolean_t found;
520  int i, j;
521 
522  /*
523  * Handle cases where one or both of the inputs is NULL.
524  */
525  if (a == NULL) {
526  if (b == NULL) {
527  return ISC_TRUE;
528  } else {
529  return ISC_FALSE;
530  }
531  }
532 
533  /*
534  * Check the type is the same.
535  */
536  if (a->ia_type != b->ia_type) {
537  return ISC_FALSE;
538  }
539 
540  /*
541  * Check the DUID is the same.
542  */
543  if (a->iaid_duid.len != b->iaid_duid.len) {
544  return ISC_FALSE;
545  }
546  if (memcmp(a->iaid_duid.data,
547  b->iaid_duid.data, a->iaid_duid.len) != 0) {
548  return ISC_FALSE;
549  }
550 
551  /*
552  * Make sure we have the same number of addresses/prefixes in each.
553  */
554  if (a->num_iasubopt != b->num_iasubopt) {
555  return ISC_FALSE;
556  }
557 
558  /*
559  * Check that each address/prefix is present in both.
560  */
561  for (i=0; i<a->num_iasubopt; i++) {
562  found = ISC_FALSE;
563  for (j=0; j<a->num_iasubopt; j++) {
564  if (a->iasubopt[i]->plen != b->iasubopt[i]->plen)
565  continue;
566  if (memcmp(&(a->iasubopt[i]->addr),
567  &(b->iasubopt[j]->addr),
568  sizeof(struct in6_addr)) == 0) {
569  found = ISC_TRUE;
570  break;
571  }
572  }
573  if (!found) {
574  return ISC_FALSE;
575  }
576  }
577 
578  /*
579  * These are the same in every way we care about.
580  */
581  return ISC_TRUE;
582 }
583 
584 /*
585  * Helper function for lease heaps.
586  * Makes the top of the heap the oldest lease.
587  */
588 static isc_boolean_t
589 lease_older(void *a, void *b) {
590  struct iasubopt *la = (struct iasubopt *)a;
591  struct iasubopt *lb = (struct iasubopt *)b;
592 
594  return difftime(la->soft_lifetime_end_time,
595  lb->soft_lifetime_end_time) < 0;
596  } else {
597  return difftime(la->hard_lifetime_end_time,
598  lb->hard_lifetime_end_time) < 0;
599  }
600 }
601 
602 /*
603  * Helper function for lease address/prefix heaps.
604  * Callback when an address's position in the heap changes.
605  */
606 static void
607 lease_index_changed(void *iasubopt, unsigned int new_heap_index) {
608  ((struct iasubopt *)iasubopt)-> heap_index = new_heap_index;
609 }
610 
611 
634 isc_result_t
635 ipv6_pool_allocate(struct ipv6_pool **pool, u_int16_t type,
636  const struct in6_addr *start_addr, int bits,
637  int units, const char *file, int line) {
638  struct ipv6_pool *tmp;
639 
640  if (pool == NULL) {
641  log_error("%s(%d): NULL pointer reference", file, line);
642  return DHCP_R_INVALIDARG;
643  }
644  if (*pool != NULL) {
645  log_error("%s(%d): non-NULL pointer", file, line);
646  return DHCP_R_INVALIDARG;
647  }
648 
649  tmp = dmalloc(sizeof(*tmp), file, line);
650  if (tmp == NULL) {
651  return ISC_R_NOMEMORY;
652  }
653 
654  tmp->refcnt = 1;
655  tmp->pool_type = type;
656  tmp->start_addr = *start_addr;
657  tmp->bits = bits;
658  tmp->units = units;
659  if (!iasubopt_new_hash(&tmp->leases, DEFAULT_HASH_SIZE, file, line)) {
660  dfree(tmp, file, line);
661  return ISC_R_NOMEMORY;
662  }
663  if (isc_heap_create(dhcp_gbl_ctx.mctx, lease_older, lease_index_changed,
664  0, &(tmp->active_timeouts)) != ISC_R_SUCCESS) {
665  iasubopt_free_hash_table(&(tmp->leases), file, line);
666  dfree(tmp, file, line);
667  return ISC_R_NOMEMORY;
668  }
669  if (isc_heap_create(dhcp_gbl_ctx.mctx, lease_older, lease_index_changed,
670  0, &(tmp->inactive_timeouts)) != ISC_R_SUCCESS) {
672  iasubopt_free_hash_table(&(tmp->leases), file, line);
673  dfree(tmp, file, line);
674  return ISC_R_NOMEMORY;
675  }
676 
677  *pool = tmp;
678  return ISC_R_SUCCESS;
679 }
680 
700 isc_result_t
702  const char *file, int line) {
703  if (pool == NULL) {
704  log_error("%s(%d): NULL pointer reference", file, line);
705  return DHCP_R_INVALIDARG;
706  }
707  if (*pool != NULL) {
708  log_error("%s(%d): non-NULL pointer", file, line);
709  return DHCP_R_INVALIDARG;
710  }
711  if (src == NULL) {
712  log_error("%s(%d): NULL pointer reference", file, line);
713  return DHCP_R_INVALIDARG;
714  }
715  *pool = src;
716  src->refcnt++;
717  return ISC_R_SUCCESS;
718 }
719 
720 /*
721  * Note: Each IAADDR/PREFIX in a pool is referenced by the pool. This is needed
722  * to prevent the lease from being garbage collected out from under the
723  * pool.
724  *
725  * The references are made from the hash and from the heap. The following
726  * helper functions dereference these when a pool is destroyed.
727  */
728 
729 /*
730  * Helper function for pool cleanup.
731  * Dereference each of the hash entries in a pool.
732  */
733 static isc_result_t
734 dereference_hash_entry(const void *name, unsigned len, void *value) {
735  struct iasubopt *iasubopt = (struct iasubopt *)value;
736 
737  iasubopt_dereference(&iasubopt, MDL);
738  return ISC_R_SUCCESS;
739 }
740 
741 /*
742  * Helper function for pool cleanup.
743  * Dereference each of the heap entries in a pool.
744  */
745 static void
746 dereference_heap_entry(void *value, void *dummy) {
747  struct iasubopt *iasubopt = (struct iasubopt *)value;
748 
749  iasubopt_dereference(&iasubopt, MDL);
750 }
751 
771 isc_result_t
772 ipv6_pool_dereference(struct ipv6_pool **pool, const char *file, int line) {
773  struct ipv6_pool *tmp;
774 
775  if ((pool == NULL) || (*pool == NULL)) {
776  log_error("%s(%d): NULL pointer", file, line);
777  return DHCP_R_INVALIDARG;
778  }
779 
780  tmp = *pool;
781  *pool = NULL;
782 
783  tmp->refcnt--;
784  if (tmp->refcnt < 0) {
785  log_error("%s(%d): negative refcnt", file, line);
786  tmp->refcnt = 0;
787  }
788  if (tmp->refcnt == 0) {
789  iasubopt_hash_foreach(tmp->leases, dereference_hash_entry);
790  iasubopt_free_hash_table(&(tmp->leases), file, line);
792  dereference_heap_entry, NULL);
795  dereference_heap_entry, NULL);
797  dfree(tmp, file, line);
798  }
799 
800  return ISC_R_SUCCESS;
801 }
802 
803 /*
804  * Create an address by hashing the input, and using that for
805  * the non-network part.
806  */
807 static void
808 build_address6(struct in6_addr *addr,
809  const struct in6_addr *net_start_addr, int net_bits,
810  const struct data_string *input) {
811  isc_md5_t ctx;
812  int net_bytes;
813  int i;
814  char *str;
815  const char *net_str;
816 
817  /*
818  * Use MD5 to get a nice 128 bit hash of the input.
819  * Yes, we know MD5 isn't cryptographically sound.
820  * No, we don't care.
821  */
822  isc_md5_init(&ctx);
823  isc_md5_update(&ctx, input->data, input->len);
824  isc_md5_final(&ctx, (unsigned char *)addr);
825 
826  /*
827  * Copy the [0..128] network bits over.
828  */
829  str = (char *)addr;
830  net_str = (const char *)net_start_addr;
831  net_bytes = net_bits / 8;
832  for (i = 0; i < net_bytes; i++) {
833  str[i] = net_str[i];
834  }
835  switch (net_bits % 8) {
836  case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
837  case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
838  case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break;
839  case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break;
840  case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break;
841  case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break;
842  case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break;
843  }
844 
845  /*
846  * Set the universal/local bit ("u bit") to zero for /64s. The
847  * individual/group bit ("g bit") is unchanged, because the g-bit
848  * has no meaning when the u-bit is cleared.
849  */
850  if (net_bits == 64)
851  str[8] &= ~0x02;
852 }
853 
854 /*
855  * Create a temporary address by a variant of RFC 4941 algo.
856  * Note: this should not be used for prefixes shorter than 64 bits.
857  */
858 static void
859 build_temporary6(struct in6_addr *addr,
860  const struct in6_addr *net_start_addr, int net_bits,
861  const struct data_string *input) {
862  static u_int32_t history[2];
863  static u_int32_t counter = 0;
864  isc_md5_t ctx;
865  unsigned char md[16];
866 
867  /*
868  * First time/time to reseed.
869  * Please use a good pseudo-random generator here!
870  */
871  if (counter == 0) {
872  isc_random_get(&history[0]);
873  isc_random_get(&history[1]);
874  }
875 
876  /*
877  * Use MD5 as recommended by RFC 4941.
878  */
879  isc_md5_init(&ctx);
880  isc_md5_update(&ctx, (unsigned char *)&history[0], 8UL);
881  isc_md5_update(&ctx, input->data, input->len);
882  isc_md5_final(&ctx, md);
883 
884  /*
885  * Build the address.
886  */
887  if (net_bits == 64) {
888  memcpy(&addr->s6_addr[0], &net_start_addr->s6_addr[0], 8);
889  memcpy(&addr->s6_addr[8], md, 8);
890  addr->s6_addr[8] &= ~0x02;
891  } else {
892  int net_bytes;
893  int i;
894  char *str;
895  const char *net_str;
896 
897  /*
898  * Copy the [0..128] network bits over.
899  */
900  str = (char *)addr;
901  net_str = (const char *)net_start_addr;
902  net_bytes = net_bits / 8;
903  for (i = 0; i < net_bytes; i++) {
904  str[i] = net_str[i];
905  }
906  memcpy(str + net_bytes, md, 16 - net_bytes);
907  switch (net_bits % 8) {
908  case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
909  case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
910  case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break;
911  case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break;
912  case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break;
913  case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break;
914  case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break;
915  }
916  }
917 
918 
919  /*
920  * Save history for the next call.
921  */
922  memcpy((unsigned char *)&history[0], md + 8, 8);
923  counter++;
924 }
925 
926 /* Reserved Subnet Router Anycast ::0:0:0:0. */
927 static struct in6_addr rtany;
928 /* Reserved Subnet Anycasts ::fdff:ffff:ffff:ff80-::fdff:ffff:ffff:ffff. */
929 static struct in6_addr resany;
930 
931 /*
932  * Create a lease for the given address and client duid.
933  *
934  * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
935  * initialized to NULL
936  *
937  * Right now we simply hash the DUID, and if we get a collision, we hash
938  * again until we find a free address. We try this a fixed number of times,
939  * to avoid getting stuck in a loop (this is important on small pools
940  * where we can run out of space).
941  *
942  * We return the number of attempts that it took to find an available
943  * lease. This tells callers when a pool is are filling up, as
944  * well as an indication of how full the pool is; statistically the
945  * more full a pool is the more attempts must be made before finding
946  * a free lease. Realistically this will only happen in very full
947  * pools.
948  *
949  * We probably want different algorithms depending on the network size, in
950  * the long term.
951  */
952 isc_result_t
953 create_lease6(struct ipv6_pool *pool, struct iasubopt **addr,
954  unsigned int *attempts,
955  const struct data_string *uid, time_t soft_lifetime_end_time) {
956  struct data_string ds;
957  struct in6_addr tmp;
958  struct iasubopt *test_iaaddr;
959  struct data_string new_ds;
960  struct iasubopt *iaaddr;
961  isc_result_t result;
962  isc_boolean_t reserved_iid;
963  static isc_boolean_t init_resiid = ISC_FALSE;
964 
965  /*
966  * Fill the reserved IIDs.
967  */
968  if (!init_resiid) {
969  memset(&rtany, 0, 16);
970  memset(&resany, 0, 8);
971  resany.s6_addr[8] = 0xfd;
972  memset(&resany.s6_addr[9], 0xff, 6);
973  init_resiid = ISC_TRUE;
974  }
975 
976  /*
977  * Use the UID as our initial seed for the hash
978  */
979  memset(&ds, 0, sizeof(ds));
980  data_string_copy(&ds, (struct data_string *)uid, MDL);
981 
982  *attempts = 0;
983  for (;;) {
984  /*
985  * Give up at some point.
986  */
987  if (++(*attempts) > 100) {
988  data_string_forget(&ds, MDL);
989  return ISC_R_NORESOURCES;
990  }
991 
992  /*
993  * Build a resource.
994  */
995  switch (pool->pool_type) {
996  case D6O_IA_NA:
997  /* address */
998  build_address6(&tmp, &pool->start_addr,
999  pool->bits, &ds);
1000  break;
1001  case D6O_IA_TA:
1002  /* temporary address */
1003  build_temporary6(&tmp, &pool->start_addr,
1004  pool->bits, &ds);
1005  break;
1006  case D6O_IA_PD:
1007  /* prefix */
1008  log_error("create_lease6: prefix pool.");
1009  return DHCP_R_INVALIDARG;
1010  default:
1011  log_error("create_lease6: untyped pool.");
1012  return DHCP_R_INVALIDARG;
1013  }
1014 
1015  /*
1016  * Avoid reserved interface IDs. (cf. RFC 5453)
1017  */
1018  reserved_iid = ISC_FALSE;
1019  if (memcmp(&tmp.s6_addr[8], &rtany.s6_addr[8], 8) == 0) {
1020  reserved_iid = ISC_TRUE;
1021  }
1022  if (!reserved_iid &&
1023  (memcmp(&tmp.s6_addr[8], &resany.s6_addr[8], 7) == 0) &&
1024  ((tmp.s6_addr[15] & 0x80) == 0x80)) {
1025  reserved_iid = ISC_TRUE;
1026  }
1027 
1028  /*
1029  * If this address is not in use, we're happy with it
1030  */
1031  test_iaaddr = NULL;
1032  if (!reserved_iid &&
1033  (iasubopt_hash_lookup(&test_iaaddr, pool->leases,
1034  &tmp, sizeof(tmp), MDL) == 0)) {
1035  break;
1036  }
1037  if (test_iaaddr != NULL)
1038  iasubopt_dereference(&test_iaaddr, MDL);
1039 
1040  /*
1041  * Otherwise, we create a new input, adding the address
1042  */
1043  memset(&new_ds, 0, sizeof(new_ds));
1044  new_ds.len = ds.len + sizeof(tmp);
1045  if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) {
1046  data_string_forget(&ds, MDL);
1047  return ISC_R_NOMEMORY;
1048  }
1049  new_ds.data = new_ds.buffer->data;
1050  memcpy(new_ds.buffer->data, ds.data, ds.len);
1051  memcpy(new_ds.buffer->data + ds.len, &tmp, sizeof(tmp));
1052  data_string_forget(&ds, MDL);
1053  data_string_copy(&ds, &new_ds, MDL);
1054  data_string_forget(&new_ds, MDL);
1055  }
1056 
1057  data_string_forget(&ds, MDL);
1058 
1059  /*
1060  * We're happy with the address, create an IAADDR
1061  * to hold it.
1062  */
1063  iaaddr = NULL;
1064  result = iasubopt_allocate(&iaaddr, MDL);
1065  if (result != ISC_R_SUCCESS) {
1066  return result;
1067  }
1068  iaaddr->plen = 0;
1069  memcpy(&iaaddr->addr, &tmp, sizeof(iaaddr->addr));
1070 
1071  /*
1072  * Add the lease to the pool (note state is free, not active?!).
1073  */
1074  result = add_lease6(pool, iaaddr, soft_lifetime_end_time);
1075  if (result == ISC_R_SUCCESS) {
1076  iasubopt_reference(addr, iaaddr, MDL);
1077  }
1078  iasubopt_dereference(&iaaddr, MDL);
1079  return result;
1080 }
1081 
1082 
1123 isc_result_t
1125  struct ipv6_pool *pool,
1126  struct iasubopt *lease,
1127  struct ia_xx *ia) {
1128 
1129  struct iasubopt *test_iasubopt, *tmp_iasubopt;
1130  struct ia_xx *old_ia;
1131  isc_result_t status = ISC_R_SUCCESS;
1132 
1133  test_iasubopt = NULL;
1134  old_ia = NULL;
1135 
1136  /*
1137  * Look up the address - if we don't find a lease
1138  * we don't need to do anything.
1139  */
1140  if (iasubopt_hash_lookup(&test_iasubopt, pool->leases,
1141  &lease->addr, sizeof(lease->addr),
1142  MDL) == 0) {
1143  return (ISC_R_SUCCESS);
1144  }
1145 
1146  if (test_iasubopt->ia == NULL) {
1147  /* no old ia, no work to do */
1148  iasubopt_dereference(&test_iasubopt, MDL);
1149  return (status);
1150  }
1151 
1152  ia_reference(&old_ia, test_iasubopt->ia, MDL);
1153 
1154  if ((old_ia->iaid_duid.len == ia->iaid_duid.len) &&
1155  (memcmp((unsigned char *)ia->iaid_duid.data,
1156  (unsigned char *)old_ia->iaid_duid.data,
1157  ia->iaid_duid.len) == 0)) {
1158  /* same IA */
1159  if ((lease->state == FTS_ACTIVE) ||
1160  (lease->state == FTS_ABANDONED)) {
1161  /* still active, no need to delete */
1162  goto cleanup;
1163  }
1164  } else {
1165  /* different IA */
1166  if ((lease->state != FTS_ACTIVE) &&
1167  (lease->state != FTS_ABANDONED)) {
1168  /* new lease isn't active, no work */
1169  goto cleanup;
1170  }
1171 
1172  /*
1173  * We appear to have two active leases, this shouldn't happen.
1174  * Before a second lease can be set to active the first lease
1175  * should be set to inactive (released, expired etc). For now
1176  * delete the previous lease and indicate a failure to the
1177  * caller so it can generate a warning.
1178  * In the future we may try and determine which is the better
1179  * lease to keep.
1180  */
1181 
1182  status = ISC_R_FAILURE;
1183  }
1184 
1185  /*
1186  * Remove the old lease from the active heap and from the hash table
1187  * then remove the lease from the IA and clean up the IA if necessary.
1188  */
1189  isc_heap_delete(pool->active_timeouts, test_iasubopt->heap_index);
1190  pool->num_active--;
1191  if (pool->ipv6_pond)
1192  pool->ipv6_pond->num_active--;
1193 
1194  iasubopt_hash_delete(pool->leases, &test_iasubopt->addr,
1195  sizeof(test_iasubopt->addr), MDL);
1196  ia_remove_iasubopt(old_ia, test_iasubopt, MDL);
1197  if (old_ia->num_iasubopt <= 0) {
1198  ia_hash_delete(ia_table,
1199  (unsigned char *)old_ia->iaid_duid.data,
1200  old_ia->iaid_duid.len, MDL);
1201  }
1202 
1203  /*
1204  * We derefenrece the subopt here as we've just removed it from
1205  * the hash table in the pool. We need to make a copy as we
1206  * need to derefernece it again later.
1207  */
1208  tmp_iasubopt = test_iasubopt;
1209  iasubopt_dereference(&tmp_iasubopt, MDL);
1210 
1211  cleanup:
1212  ia_dereference(&old_ia, MDL);
1213 
1214  /*
1215  * Clean up the reference, this is in addition to the deference
1216  * above after removing the entry from the hash table
1217  */
1218  iasubopt_dereference(&test_iasubopt, MDL);
1219 
1220  return (status);
1221 }
1222 
1223 /*
1224  * Put a lease in the pool directly. This is intended to be used when
1225  * loading leases from the file.
1226  */
1227 isc_result_t
1229  time_t valid_lifetime_end_time) {
1230  isc_result_t insert_result;
1231  struct iasubopt *test_iasubopt;
1232  struct iasubopt *tmp_iasubopt;
1233 
1234  /* If a state was not assigned by the caller, assume active. */
1235  if (lease->state == 0)
1236  lease->state = FTS_ACTIVE;
1237 
1238  ipv6_pool_reference(&lease->ipv6_pool, pool, MDL);
1239 
1240  /*
1241  * If this IAADDR/PREFIX is already in our structures, remove the
1242  * old one.
1243  */
1244  test_iasubopt = NULL;
1245  if (iasubopt_hash_lookup(&test_iasubopt, pool->leases,
1246  &lease->addr, sizeof(lease->addr), MDL)) {
1247  /* XXX: we should probably ask the lease what heap it is on
1248  * (as a consistency check).
1249  * XXX: we should probably have one function to "put this lease
1250  * on its heap" rather than doing these if's everywhere. If
1251  * you add more states to this list, don't.
1252  */
1253  if ((test_iasubopt->state == FTS_ACTIVE) ||
1254  (test_iasubopt->state == FTS_ABANDONED)) {
1256  test_iasubopt->heap_index);
1257  pool->num_active--;
1258  if (pool->ipv6_pond)
1259  pool->ipv6_pond->num_active--;
1260  } else {
1262  test_iasubopt->heap_index);
1263  pool->num_inactive--;
1264  }
1265 
1266  iasubopt_hash_delete(pool->leases, &test_iasubopt->addr,
1267  sizeof(test_iasubopt->addr), MDL);
1268 
1269  /*
1270  * We're going to do a bit of evil trickery here.
1271  *
1272  * We need to dereference the entry once to remove our
1273  * current reference (in test_iasubopt), and then one
1274  * more time to remove the reference left when the
1275  * address was added to the pool before.
1276  */
1277  tmp_iasubopt = test_iasubopt;
1278  iasubopt_dereference(&test_iasubopt, MDL);
1279  iasubopt_dereference(&tmp_iasubopt, MDL);
1280  }
1281 
1282  /*
1283  * Add IAADDR/PREFIX to our structures.
1284  */
1285  tmp_iasubopt = NULL;
1286  iasubopt_reference(&tmp_iasubopt, lease, MDL);
1287  if ((tmp_iasubopt->state == FTS_ACTIVE) ||
1288  (tmp_iasubopt->state == FTS_ABANDONED)) {
1289  tmp_iasubopt->hard_lifetime_end_time = valid_lifetime_end_time;
1290  iasubopt_hash_add(pool->leases, &tmp_iasubopt->addr,
1291  sizeof(tmp_iasubopt->addr), lease, MDL);
1292  insert_result = isc_heap_insert(pool->active_timeouts,
1293  tmp_iasubopt);
1294  if (insert_result == ISC_R_SUCCESS) {
1295  pool->num_active++;
1296  if (pool->ipv6_pond)
1297  pool->ipv6_pond->num_active++;
1298  }
1299 
1300  } else {
1301  tmp_iasubopt->soft_lifetime_end_time = valid_lifetime_end_time;
1302  insert_result = isc_heap_insert(pool->inactive_timeouts,
1303  tmp_iasubopt);
1304  if (insert_result == ISC_R_SUCCESS)
1305  pool->num_inactive++;
1306  }
1307  if (insert_result != ISC_R_SUCCESS) {
1308  iasubopt_hash_delete(pool->leases, &lease->addr,
1309  sizeof(lease->addr), MDL);
1310  iasubopt_dereference(&tmp_iasubopt, MDL);
1311  return insert_result;
1312  }
1313 
1314  /*
1315  * Note: we intentionally leave tmp_iasubopt referenced; there
1316  * is a reference in the heap/hash, after all.
1317  */
1318 
1319  return ISC_R_SUCCESS;
1320 }
1321 
1322 /*
1323  * Determine if an address is present in a pool or not.
1324  */
1325 isc_boolean_t
1326 lease6_exists(const struct ipv6_pool *pool, const struct in6_addr *addr) {
1327  struct iasubopt *test_iaaddr;
1328 
1329  test_iaaddr = NULL;
1330  if (iasubopt_hash_lookup(&test_iaaddr, pool->leases,
1331  (void *)addr, sizeof(*addr), MDL)) {
1332  iasubopt_dereference(&test_iaaddr, MDL);
1333  return ISC_TRUE;
1334  } else {
1335  return ISC_FALSE;
1336  }
1337 }
1338 
1353 isc_boolean_t
1355  struct iasubopt *test_iaaddr;
1356  isc_boolean_t status = ISC_TRUE;
1357 
1358  test_iaaddr = NULL;
1359  if (iasubopt_hash_lookup(&test_iaaddr, lease->ipv6_pool->leases,
1360  (void *)&lease->addr,
1361  sizeof(lease->addr), MDL)) {
1362  if (test_iaaddr != lease) {
1363  status = ISC_FALSE;
1364  }
1365  iasubopt_dereference(&test_iaaddr, MDL);
1366  }
1367 
1368  return (status);
1369 }
1370 
1371 /*
1372  * Put the lease on our active pool.
1373  */
1374 static isc_result_t
1375 move_lease_to_active(struct ipv6_pool *pool, struct iasubopt *lease) {
1376  isc_result_t insert_result;
1377  int old_heap_index;
1378 
1379  old_heap_index = lease->heap_index;
1380  insert_result = isc_heap_insert(pool->active_timeouts, lease);
1381  if (insert_result == ISC_R_SUCCESS) {
1382  iasubopt_hash_add(pool->leases, &lease->addr,
1383  sizeof(lease->addr), lease, MDL);
1384  isc_heap_delete(pool->inactive_timeouts, old_heap_index);
1385  pool->num_active++;
1386  pool->num_inactive--;
1387  lease->state = FTS_ACTIVE;
1388  if (pool->ipv6_pond)
1389  pool->ipv6_pond->num_active++;
1390  }
1391  return insert_result;
1392 }
1393 
1424 isc_result_t
1425 renew_lease6(struct ipv6_pool *pool, struct iasubopt *lease) {
1426  time_t old_end_time = lease->hard_lifetime_end_time;
1428  lease->soft_lifetime_end_time = 0;
1429 
1430  if (lease->state == FTS_ACTIVE) {
1431  if (old_end_time <= lease->hard_lifetime_end_time) {
1433  lease->heap_index);
1434  } else {
1436  lease->heap_index);
1437  }
1438  return ISC_R_SUCCESS;
1439  } else if (lease->state == FTS_ABANDONED) {
1440  char tmp_addr[INET6_ADDRSTRLEN];
1441  lease->state = FTS_ACTIVE;
1443  log_info("Reclaiming previously abandoned address %s",
1444  inet_ntop(AF_INET6, &(lease->addr), tmp_addr,
1445  sizeof(tmp_addr)));
1446  return ISC_R_SUCCESS;
1447  } else {
1448  return move_lease_to_active(pool, lease);
1449  }
1450 }
1451 
1452 /*
1453  * Put the lease on our inactive pool, with the specified state.
1454  */
1455 static isc_result_t
1456 move_lease_to_inactive(struct ipv6_pool *pool, struct iasubopt *lease,
1458  isc_result_t insert_result;
1459  int old_heap_index;
1460 
1461  old_heap_index = lease->heap_index;
1462  insert_result = isc_heap_insert(pool->inactive_timeouts, lease);
1463  if (insert_result == ISC_R_SUCCESS) {
1464  /*
1465  * Handle expire and release statements
1466  * To get here we must be active and have done a commit so
1467  * we should run the proper statements if they exist, though
1468  * that will change when we remove the inactive heap.
1469  * In addition we get rid of the references for both as we
1470  * can only do one (expire or release) on a lease
1471  */
1472  if (lease->on_star.on_expiry != NULL) {
1473  if (state == FTS_EXPIRED) {
1474  execute_statements(NULL, NULL, NULL,
1475  NULL, NULL, NULL,
1476  &lease->scope,
1477  lease->on_star.on_expiry,
1478  &lease->on_star);
1479  }
1481  (&lease->on_star.on_expiry, MDL);
1482  }
1483 
1484  if (lease->on_star.on_release != NULL) {
1485  if (state == FTS_RELEASED) {
1486  execute_statements(NULL, NULL, NULL,
1487  NULL, NULL, NULL,
1488  &lease->scope,
1489  lease->on_star.on_release,
1490  &lease->on_star);
1491  }
1493  (&lease->on_star.on_release, MDL);
1494  }
1495 
1496 #if defined (NSUPDATE)
1497  /* Process events upon expiration. */
1498  if (pool->pool_type != D6O_IA_PD) {
1499  (void) ddns_removals(NULL, lease, NULL, ISC_FALSE);
1500  }
1501 #endif
1502 
1503  /* Binding scopes are no longer valid after expiry or
1504  * release.
1505  */
1506  if (lease->scope != NULL) {
1508  }
1509 
1510  iasubopt_hash_delete(pool->leases,
1511  &lease->addr, sizeof(lease->addr), MDL);
1512  isc_heap_delete(pool->active_timeouts, old_heap_index);
1513  lease->state = state;
1514  pool->num_active--;
1515  pool->num_inactive++;
1516  if (pool->ipv6_pond)
1517  pool->ipv6_pond->num_active--;
1518  }
1519  return insert_result;
1520 }
1521 
1522 /*
1523  * Expire the oldest lease if it's lifetime_end_time is
1524  * older than the given time.
1525  *
1526  * - leasep must be a pointer to a (struct iasubopt *) pointer previously
1527  * initialized to NULL
1528  *
1529  * On return leasep has a reference to the removed entry. It is left
1530  * pointing to NULL if the oldest lease has not expired.
1531  */
1532 isc_result_t
1533 expire_lease6(struct iasubopt **leasep, struct ipv6_pool *pool, time_t now) {
1534  struct iasubopt *tmp;
1535  isc_result_t result;
1536 
1537  if (leasep == NULL) {
1538  log_error("%s(%d): NULL pointer reference", MDL);
1539  return DHCP_R_INVALIDARG;
1540  }
1541  if (*leasep != NULL) {
1542  log_error("%s(%d): non-NULL pointer", MDL);
1543  return DHCP_R_INVALIDARG;
1544  }
1545 
1546  if (pool->num_active > 0) {
1547  tmp = (struct iasubopt *)
1549  if (now > tmp->hard_lifetime_end_time) {
1550  result = move_lease_to_inactive(pool, tmp,
1551  FTS_EXPIRED);
1552  if (result == ISC_R_SUCCESS) {
1553  iasubopt_reference(leasep, tmp, MDL);
1554  }
1555  return result;
1556  }
1557  }
1558  return ISC_R_SUCCESS;
1559 }
1560 
1561 
1562 /*
1563  * For a declined lease, leave it on the "active" pool, but mark
1564  * it as declined. Give it an infinite (well, really long) life.
1565  */
1566 isc_result_t
1567 decline_lease6(struct ipv6_pool *pool, struct iasubopt *lease) {
1568  isc_result_t result;
1569 
1570  if ((lease->state != FTS_ACTIVE) &&
1571  (lease->state != FTS_ABANDONED)) {
1572  result = move_lease_to_active(pool, lease);
1573  if (result != ISC_R_SUCCESS) {
1574  return result;
1575  }
1576  }
1577  lease->state = FTS_ABANDONED;
1580  return ISC_R_SUCCESS;
1581 }
1582 
1583 /*
1584  * Put the returned lease on our inactive pool.
1585  */
1586 isc_result_t
1587 release_lease6(struct ipv6_pool *pool, struct iasubopt *lease) {
1588  if (lease->state == FTS_ACTIVE) {
1589  return move_lease_to_inactive(pool, lease, FTS_RELEASED);
1590  } else {
1591  return ISC_R_SUCCESS;
1592  }
1593 }
1594 
1595 /*
1596  * Create a prefix by hashing the input, and using that for
1597  * the part subject to allocation.
1598  */
1599 void
1600 build_prefix6(struct in6_addr *pref,
1601  const struct in6_addr *net_start_pref,
1602  int pool_bits, int pref_bits,
1603  const struct data_string *input) {
1604  isc_md5_t ctx;
1605  int net_bytes;
1606  int i;
1607  char *str;
1608  const char *net_str;
1609 
1610  /*
1611  * Use MD5 to get a nice 128 bit hash of the input.
1612  * Yes, we know MD5 isn't cryptographically sound.
1613  * No, we don't care.
1614  */
1615  isc_md5_init(&ctx);
1616  isc_md5_update(&ctx, input->data, input->len);
1617  isc_md5_final(&ctx, (unsigned char *)pref);
1618 
1619  /*
1620  * Copy the network bits over.
1621  */
1622  str = (char *)pref;
1623  net_str = (const char *)net_start_pref;
1624  net_bytes = pool_bits / 8;
1625  for (i = 0; i < net_bytes; i++) {
1626  str[i] = net_str[i];
1627  }
1628  i = net_bytes;
1629  switch (pool_bits % 8) {
1630  case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
1631  case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
1632  case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break;
1633  case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break;
1634  case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break;
1635  case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break;
1636  case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break;
1637  }
1638  /*
1639  * Zero the remaining bits.
1640  */
1641  net_bytes = pref_bits / 8;
1642  for (i=net_bytes+1; i<16; i++) {
1643  str[i] = 0;
1644  }
1645  i = net_bytes;
1646  switch (pref_bits % 8) {
1647  case 0: str[i] &= 0; break;
1648  case 1: str[i] &= 0x80; break;
1649  case 2: str[i] &= 0xC0; break;
1650  case 3: str[i] &= 0xE0; break;
1651  case 4: str[i] &= 0xF0; break;
1652  case 5: str[i] &= 0xF8; break;
1653  case 6: str[i] &= 0xFC; break;
1654  case 7: str[i] &= 0xFE; break;
1655  }
1656 }
1657 
1658 /*
1659  * Create a lease for the given prefix and client duid.
1660  *
1661  * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
1662  * initialized to NULL
1663  *
1664  * Right now we simply hash the DUID, and if we get a collision, we hash
1665  * again until we find a free prefix. We try this a fixed number of times,
1666  * to avoid getting stuck in a loop (this is important on small pools
1667  * where we can run out of space).
1668  *
1669  * We return the number of attempts that it took to find an available
1670  * prefix. This tells callers when a pool is are filling up, as
1671  * well as an indication of how full the pool is; statistically the
1672  * more full a pool is the more attempts must be made before finding
1673  * a free prefix. Realistically this will only happen in very full
1674  * pools.
1675  *
1676  * We probably want different algorithms depending on the network size, in
1677  * the long term.
1678  */
1679 isc_result_t
1680 create_prefix6(struct ipv6_pool *pool, struct iasubopt **pref,
1681  unsigned int *attempts,
1682  const struct data_string *uid,
1683  time_t soft_lifetime_end_time) {
1684  struct data_string ds;
1685  struct in6_addr tmp;
1686  struct iasubopt *test_iapref;
1687  struct data_string new_ds;
1688  struct iasubopt *iapref;
1689  isc_result_t result;
1690 
1691  /*
1692  * Use the UID as our initial seed for the hash
1693  */
1694  memset(&ds, 0, sizeof(ds));
1695  data_string_copy(&ds, (struct data_string *)uid, MDL);
1696 
1697  *attempts = 0;
1698  for (;;) {
1699  /*
1700  * Give up at some point.
1701  */
1702  if (++(*attempts) > 10) {
1703  data_string_forget(&ds, MDL);
1704  return ISC_R_NORESOURCES;
1705  }
1706 
1707  /*
1708  * Build a prefix
1709  */
1710  build_prefix6(&tmp, &pool->start_addr,
1711  pool->bits, pool->units, &ds);
1712 
1713  /*
1714  * If this prefix is not in use, we're happy with it
1715  */
1716  test_iapref = NULL;
1717  if (iasubopt_hash_lookup(&test_iapref, pool->leases,
1718  &tmp, sizeof(tmp), MDL) == 0) {
1719  break;
1720  }
1721  iasubopt_dereference(&test_iapref, MDL);
1722 
1723  /*
1724  * Otherwise, we create a new input, adding the prefix
1725  */
1726  memset(&new_ds, 0, sizeof(new_ds));
1727  new_ds.len = ds.len + sizeof(tmp);
1728  if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) {
1729  data_string_forget(&ds, MDL);
1730  return ISC_R_NOMEMORY;
1731  }
1732  new_ds.data = new_ds.buffer->data;
1733  memcpy(new_ds.buffer->data, ds.data, ds.len);
1734  memcpy(new_ds.buffer->data + ds.len, &tmp, sizeof(tmp));
1735  data_string_forget(&ds, MDL);
1736  data_string_copy(&ds, &new_ds, MDL);
1737  data_string_forget(&new_ds, MDL);
1738  }
1739 
1740  data_string_forget(&ds, MDL);
1741 
1742  /*
1743  * We're happy with the prefix, create an IAPREFIX
1744  * to hold it.
1745  */
1746  iapref = NULL;
1747  result = iasubopt_allocate(&iapref, MDL);
1748  if (result != ISC_R_SUCCESS) {
1749  return result;
1750  }
1751  iapref->plen = (u_int8_t)pool->units;
1752  memcpy(&iapref->addr, &tmp, sizeof(iapref->addr));
1753 
1754  /*
1755  * Add the prefix to the pool (note state is free, not active?!).
1756  */
1757  result = add_lease6(pool, iapref, soft_lifetime_end_time);
1758  if (result == ISC_R_SUCCESS) {
1759  iasubopt_reference(pref, iapref, MDL);
1760  }
1761  iasubopt_dereference(&iapref, MDL);
1762  return result;
1763 }
1764 
1765 /*
1766  * Determine if a prefix is present in a pool or not.
1767  */
1768 isc_boolean_t
1769 prefix6_exists(const struct ipv6_pool *pool,
1770  const struct in6_addr *pref, u_int8_t plen) {
1771  struct iasubopt *test_iapref;
1772 
1773  if ((int)plen != pool->units)
1774  return ISC_FALSE;
1775 
1776  test_iapref = NULL;
1777  if (iasubopt_hash_lookup(&test_iapref, pool->leases,
1778  (void *)pref, sizeof(*pref), MDL)) {
1779  iasubopt_dereference(&test_iapref, MDL);
1780  return ISC_TRUE;
1781  } else {
1782  return ISC_FALSE;
1783  }
1784 }
1785 
1786 /*
1787  * Mark an IPv6 address/prefix as unavailable from a pool.
1788  *
1789  * This is used for host entries and the addresses of the server itself.
1790  */
1791 isc_result_t
1792 mark_lease_unavailable(struct ipv6_pool *pool, const struct in6_addr *addr) {
1793  struct iasubopt *dummy_iasubopt;
1794  isc_result_t result;
1795 
1796  dummy_iasubopt = NULL;
1797  result = iasubopt_allocate(&dummy_iasubopt, MDL);
1798  if (result == ISC_R_SUCCESS) {
1799  dummy_iasubopt->addr = *addr;
1800  iasubopt_hash_add(pool->leases, &dummy_iasubopt->addr,
1801  sizeof(*addr), dummy_iasubopt, MDL);
1802  }
1803  return result;
1804 }
1805 
1806 /*
1807  * Add a pool.
1808  */
1809 isc_result_t
1810 add_ipv6_pool(struct ipv6_pool *pool) {
1811  struct ipv6_pool **new_pools;
1812 
1813  new_pools = dmalloc(sizeof(struct ipv6_pool *) * (num_pools+1), MDL);
1814  if (new_pools == NULL) {
1815  return ISC_R_NOMEMORY;
1816  }
1817 
1818  if (num_pools > 0) {
1819  memcpy(new_pools, pools,
1820  sizeof(struct ipv6_pool *) * num_pools);
1821  dfree(pools, MDL);
1822  }
1823  pools = new_pools;
1824 
1825  pools[num_pools] = NULL;
1827  num_pools++;
1828  return ISC_R_SUCCESS;
1829 }
1830 
1831 static void
1832 cleanup_old_expired(struct ipv6_pool *pool) {
1833  struct iasubopt *tmp;
1834  struct ia_xx *ia;
1835  struct ia_xx *ia_active;
1836  unsigned char *tmpd;
1837  time_t timeout;
1838 
1839  while (pool->num_inactive > 0) {
1840  tmp = (struct iasubopt *)
1842  if (tmp->hard_lifetime_end_time != 0) {
1843  timeout = tmp->hard_lifetime_end_time;
1844  timeout += EXPIRED_IPV6_CLEANUP_TIME;
1845  } else {
1846  timeout = tmp->soft_lifetime_end_time;
1847  }
1848  if (cur_time < timeout) {
1849  break;
1850  }
1851 
1853  pool->num_inactive--;
1854 
1855  if (tmp->ia != NULL) {
1856  /*
1857  * Check to see if this IA is in an active list,
1858  * but has no remaining resources. If so, remove it
1859  * from the active list.
1860  */
1861  ia = NULL;
1862  ia_reference(&ia, tmp->ia, MDL);
1863  ia_remove_iasubopt(ia, tmp, MDL);
1864  ia_active = NULL;
1865  tmpd = (unsigned char *)ia->iaid_duid.data;
1866  if ((ia->ia_type == D6O_IA_NA) &&
1867  (ia->num_iasubopt <= 0) &&
1868  (ia_hash_lookup(&ia_active, ia_na_active, tmpd,
1869  ia->iaid_duid.len, MDL) == 0) &&
1870  (ia_active == ia)) {
1871  ia_hash_delete(ia_na_active, tmpd,
1872  ia->iaid_duid.len, MDL);
1873  }
1874  if ((ia->ia_type == D6O_IA_TA) &&
1875  (ia->num_iasubopt <= 0) &&
1876  (ia_hash_lookup(&ia_active, ia_ta_active, tmpd,
1877  ia->iaid_duid.len, MDL) == 0) &&
1878  (ia_active == ia)) {
1879  ia_hash_delete(ia_ta_active, tmpd,
1880  ia->iaid_duid.len, MDL);
1881  }
1882  if ((ia->ia_type == D6O_IA_PD) &&
1883  (ia->num_iasubopt <= 0) &&
1884  (ia_hash_lookup(&ia_active, ia_pd_active, tmpd,
1885  ia->iaid_duid.len, MDL) == 0) &&
1886  (ia_active == ia)) {
1887  ia_hash_delete(ia_pd_active, tmpd,
1888  ia->iaid_duid.len, MDL);
1889  }
1890  ia_dereference(&ia, MDL);
1891  }
1892  iasubopt_dereference(&tmp, MDL);
1893  }
1894 }
1895 
1896 static void
1897 lease_timeout_support(void *vpool) {
1898  struct ipv6_pool *pool;
1899  struct iasubopt *lease;
1900 
1901  pool = (struct ipv6_pool *)vpool;
1902  for (;;) {
1903  /*
1904  * Get the next lease scheduled to expire.
1905  *
1906  * Note that if there are no leases in the pool,
1907  * expire_lease6() will return ISC_R_SUCCESS with
1908  * a NULL lease.
1909  *
1910  * expire_lease6() will call move_lease_to_inactive() which
1911  * calls ddns_removals() do we want that on the standard
1912  * expiration timer or a special 'depref' timer? Original
1913  * query from DH, moved here by SAR.
1914  */
1915  lease = NULL;
1916  if (expire_lease6(&lease, pool, cur_time) != ISC_R_SUCCESS) {
1917  break;
1918  }
1919  if (lease == NULL) {
1920  break;
1921  }
1922 
1923  write_ia(lease->ia);
1924 
1925  iasubopt_dereference(&lease, MDL);
1926  }
1927 
1928  /*
1929  * If appropriate commit and rotate the lease file
1930  * As commit_leases_timed() checks to see if we've done any writes
1931  * we don't bother tracking if this function called write _ia
1932  */
1933  (void) commit_leases_timed();
1934 
1935  /*
1936  * Do some cleanup of our expired leases.
1937  */
1938  cleanup_old_expired(pool);
1939 
1940  /*
1941  * Schedule next round of expirations.
1942  */
1943  schedule_lease_timeout(pool);
1944 }
1945 
1946 /*
1947  * For a given pool, add a timer that will remove the next
1948  * lease to expire.
1949  */
1950 void
1952  struct iasubopt *tmp;
1953  time_t timeout;
1954  time_t next_timeout;
1955  struct timeval tv;
1956 
1957  next_timeout = MAX_TIME;
1958 
1959  if (pool->num_active > 0) {
1960  tmp = (struct iasubopt *)
1962  if (tmp->hard_lifetime_end_time < next_timeout) {
1963  next_timeout = tmp->hard_lifetime_end_time + 1;
1964  }
1965  }
1966 
1967  if (pool->num_inactive > 0) {
1968  tmp = (struct iasubopt *)
1970  if (tmp->hard_lifetime_end_time != 0) {
1971  timeout = tmp->hard_lifetime_end_time;
1972  timeout += EXPIRED_IPV6_CLEANUP_TIME;
1973  } else {
1974  timeout = tmp->soft_lifetime_end_time + 1;
1975  }
1976  if (timeout < next_timeout) {
1977  next_timeout = timeout;
1978  }
1979  }
1980 
1981  if (next_timeout < MAX_TIME) {
1982  tv.tv_sec = next_timeout;
1983  tv.tv_usec = 0;
1984  add_timeout(&tv, lease_timeout_support, pool,
1987  }
1988 }
1989 
1990 /*
1991  * Schedule timeouts across all pools.
1992  */
1993 void
1995  int i;
1996 
1997  for (i=0; i<num_pools; i++) {
1999  }
2000 }
2001 
2002 /*
2003  * Given an address and the length of the network mask, return
2004  * only the network portion.
2005  *
2006  * Examples:
2007  *
2008  * "fe80::216:6fff:fe49:7d9b", length 64 = "fe80::"
2009  * "2001:888:1936:2:216:6fff:fe49:7d9b", length 48 = "2001:888:1936::"
2010  */
2011 static void
2012 ipv6_network_portion(struct in6_addr *result,
2013  const struct in6_addr *addr, int bits) {
2014  unsigned char *addrp;
2015  int mask_bits;
2016  int bytes;
2017  int extra_bits;
2018  int i;
2019 
2020  static const unsigned char bitmasks[] = {
2021  0x00, 0xFE, 0xFC, 0xF8,
2022  0xF0, 0xE0, 0xC0, 0x80,
2023  };
2024 
2025  /*
2026  * Sanity check our bits. ;)
2027  */
2028  if ((bits < 0) || (bits > 128)) {
2029  log_fatal("ipv6_network_portion: bits %d not between 0 and 128",
2030  bits);
2031  }
2032 
2033  /*
2034  * Copy our address portion.
2035  */
2036  *result = *addr;
2037  addrp = ((unsigned char *)result) + 15;
2038 
2039  /*
2040  * Zero out masked portion.
2041  */
2042  mask_bits = 128 - bits;
2043  bytes = mask_bits / 8;
2044  extra_bits = mask_bits % 8;
2045 
2046  for (i=0; i<bytes; i++) {
2047  *addrp = 0;
2048  addrp--;
2049  }
2050  if (extra_bits) {
2051  *addrp &= bitmasks[extra_bits];
2052  }
2053 }
2054 
2055 /*
2056  * Determine if the given address/prefix is in the pool.
2057  */
2058 isc_boolean_t
2059 ipv6_in_pool(const struct in6_addr *addr, const struct ipv6_pool *pool) {
2060  struct in6_addr tmp;
2061 
2062  ipv6_network_portion(&tmp, addr, pool->bits);
2063  if (memcmp(&tmp, &pool->start_addr, sizeof(tmp)) == 0) {
2064  return ISC_TRUE;
2065  } else {
2066  return ISC_FALSE;
2067  }
2068 }
2069 
2070 /*
2071  * Find the pool that contains the given address.
2072  *
2073  * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
2074  * initialized to NULL
2075  */
2076 isc_result_t
2077 find_ipv6_pool(struct ipv6_pool **pool, u_int16_t type,
2078  const struct in6_addr *addr) {
2079  int i;
2080 
2081  if (pool == NULL) {
2082  log_error("%s(%d): NULL pointer reference", MDL);
2083  return DHCP_R_INVALIDARG;
2084  }
2085  if (*pool != NULL) {
2086  log_error("%s(%d): non-NULL pointer", MDL);
2087  return DHCP_R_INVALIDARG;
2088  }
2089 
2090  for (i=0; i<num_pools; i++) {
2091  if (pools[i]->pool_type != type)
2092  continue;
2093  if (ipv6_in_pool(addr, pools[i])) {
2094  ipv6_pool_reference(pool, pools[i], MDL);
2095  return ISC_R_SUCCESS;
2096  }
2097  }
2098  return ISC_R_NOTFOUND;
2099 }
2100 
2101 /*
2102  * Helper function for the various functions that act across all
2103  * pools.
2104  */
2105 static isc_result_t
2106 change_leases(struct ia_xx *ia,
2107  isc_result_t (*change_func)(struct ipv6_pool *,
2108  struct iasubopt *)) {
2109  isc_result_t retval;
2110  isc_result_t renew_retval;
2111  struct ipv6_pool *pool;
2112  struct in6_addr *addr;
2113  int i;
2114 
2115  retval = ISC_R_SUCCESS;
2116  for (i=0; i<ia->num_iasubopt; i++) {
2117  pool = NULL;
2118  addr = &ia->iasubopt[i]->addr;
2119  if (find_ipv6_pool(&pool, ia->ia_type,
2120  addr) == ISC_R_SUCCESS) {
2121  renew_retval = change_func(pool, ia->iasubopt[i]);
2122  if (renew_retval != ISC_R_SUCCESS) {
2123  retval = renew_retval;
2124  }
2125  }
2126  /* XXXsk: should we warn if we don't find a pool? */
2127  }
2128  return retval;
2129 }
2130 
2131 /*
2132  * Renew all leases in an IA from all pools.
2133  *
2134  * The new lifetime should be in the soft_lifetime_end_time
2135  * and will be moved to hard_lifetime_end_time by renew_lease6.
2136  */
2137 isc_result_t
2138 renew_leases(struct ia_xx *ia) {
2139  return change_leases(ia, renew_lease6);
2140 }
2141 
2142 /*
2143  * Release all leases in an IA from all pools.
2144  */
2145 isc_result_t
2146 release_leases(struct ia_xx *ia) {
2147  return change_leases(ia, release_lease6);
2148 }
2149 
2150 /*
2151  * Decline all leases in an IA from all pools.
2152  */
2153 isc_result_t
2154 decline_leases(struct ia_xx *ia) {
2155  return change_leases(ia, decline_lease6);
2156 }
2157 
2158 #ifdef DHCPv6
2159 /*
2160  * Helper function to output leases.
2161  */
2162 static int write_error;
2163 
2164 static isc_result_t
2165 write_ia_leases(const void *name, unsigned len, void *value) {
2166  struct ia_xx *ia = (struct ia_xx *)value;
2167 
2168  if (!write_error) {
2169  if (!write_ia(ia)) {
2170  write_error = 1;
2171  }
2172  }
2173  return ISC_R_SUCCESS;
2174 }
2175 
2176 /*
2177  * Write all DHCPv6 information.
2178  */
2179 int
2180 write_leases6(void) {
2181  int nas, tas, pds;
2182 
2183  write_error = 0;
2185  nas = ia_hash_foreach(ia_na_active, write_ia_leases);
2186  if (write_error) {
2187  return 0;
2188  }
2189  tas = ia_hash_foreach(ia_ta_active, write_ia_leases);
2190  if (write_error) {
2191  return 0;
2192  }
2193  pds = ia_hash_foreach(ia_pd_active, write_ia_leases);
2194  if (write_error) {
2195  return 0;
2196  }
2197 
2198  log_info("Wrote %d NA, %d TA, %d PD leases to lease file.",
2199  nas, tas, pds);
2200  return 1;
2201 }
2202 #endif /* DHCPv6 */
2203 
2204 static isc_result_t
2205 mark_hosts_unavailable_support(const void *name, unsigned len, void *value) {
2206  struct host_decl *h;
2207  struct data_string fixed_addr;
2208  struct in6_addr addr;
2209  struct ipv6_pool *p;
2210 
2211  h = (struct host_decl *)value;
2212 
2213  /*
2214  * If the host has no address, we don't need to mark anything.
2215  */
2216  if (h->fixed_addr == NULL) {
2217  return ISC_R_SUCCESS;
2218  }
2219 
2220  /*
2221  * Evaluate the fixed address.
2222  */
2223  memset(&fixed_addr, 0, sizeof(fixed_addr));
2224  if (!evaluate_option_cache(&fixed_addr, NULL, NULL, NULL, NULL, NULL,
2225  &global_scope, h->fixed_addr, MDL)) {
2226  log_error("mark_hosts_unavailable: "
2227  "error evaluating host address.");
2228  return ISC_R_SUCCESS;
2229  }
2230  if (fixed_addr.len != 16) {
2231  log_error("mark_hosts_unavailable: "
2232  "host address is not 128 bits.");
2233  return ISC_R_SUCCESS;
2234  }
2235  memcpy(&addr, fixed_addr.data, 16);
2237 
2238  /*
2239  * Find the pool holding this host, and mark the address.
2240  * (I suppose it is arguably valid to have a host that does not
2241  * sit in any pool.)
2242  */
2243  p = NULL;
2244  if (find_ipv6_pool(&p, D6O_IA_NA, &addr) == ISC_R_SUCCESS) {
2245  mark_lease_unavailable(p, &addr);
2247  }
2248  if (find_ipv6_pool(&p, D6O_IA_TA, &addr) == ISC_R_SUCCESS) {
2249  mark_lease_unavailable(p, &addr);
2251  }
2252 
2253  return ISC_R_SUCCESS;
2254 }
2255 
2256 void
2258  hash_foreach(host_name_hash, mark_hosts_unavailable_support);
2259 }
2260 
2261 static isc_result_t
2262 mark_phosts_unavailable_support(const void *name, unsigned len, void *value) {
2263  struct host_decl *h;
2264  struct iaddrcidrnetlist *l;
2265  struct in6_addr pref;
2266  struct ipv6_pool *p;
2267 
2268  h = (struct host_decl *)value;
2269 
2270  /*
2271  * If the host has no prefix, we don't need to mark anything.
2272  */
2273  if (h->fixed_prefix == NULL) {
2274  return ISC_R_SUCCESS;
2275  }
2276 
2277  /*
2278  * Get the fixed prefixes.
2279  */
2280  for (l = h->fixed_prefix; l != NULL; l = l->next) {
2281  if (l->cidrnet.lo_addr.len != 16) {
2282  continue;
2283  }
2284  memcpy(&pref, l->cidrnet.lo_addr.iabuf, 16);
2285 
2286  /*
2287  * Find the pool holding this host, and mark the prefix.
2288  * (I suppose it is arguably valid to have a host that does not
2289  * sit in any pool.)
2290  */
2291  p = NULL;
2292  if (find_ipv6_pool(&p, D6O_IA_PD, &pref) != ISC_R_SUCCESS) {
2293  continue;
2294  }
2295  if (l->cidrnet.bits != p->units) {
2297  continue;
2298  }
2299  mark_lease_unavailable(p, &pref);
2301  }
2302 
2303  return ISC_R_SUCCESS;
2304 }
2305 
2306 void
2308  hash_foreach(host_name_hash, mark_phosts_unavailable_support);
2309 }
2310 
2311 void
2313  struct interface_info *ip;
2314  int i;
2315  struct ipv6_pool *p;
2316 
2317  ip = interfaces;
2318  while (ip != NULL) {
2319  for (i=0; i<ip->v6address_count; i++) {
2320  p = NULL;
2321  if (find_ipv6_pool(&p, D6O_IA_NA, &ip->v6addresses[i])
2322  == ISC_R_SUCCESS) {
2324  &ip->v6addresses[i]);
2326  }
2327  if (find_ipv6_pool(&p, D6O_IA_TA, &ip->v6addresses[i])
2328  == ISC_R_SUCCESS) {
2330  &ip->v6addresses[i]);
2332  }
2333  }
2334  ip = ip->next;
2335  }
2336 }
2337 
2355 isc_result_t
2356 ipv6_pond_allocate(struct ipv6_pond **pond, const char *file, int line) {
2357  struct ipv6_pond *tmp;
2358 
2359  if (pond == NULL) {
2360  log_error("%s(%d): NULL pointer reference", file, line);
2361  return DHCP_R_INVALIDARG;
2362  }
2363  if (*pond != NULL) {
2364  log_error("%s(%d): non-NULL pointer", file, line);
2365  return DHCP_R_INVALIDARG;
2366  }
2367 
2368  tmp = dmalloc(sizeof(*tmp), file, line);
2369  if (tmp == NULL) {
2370  return ISC_R_NOMEMORY;
2371  }
2372 
2373  tmp->refcnt = 1;
2374 
2375  *pond = tmp;
2376  return ISC_R_SUCCESS;
2377 }
2378 
2398 isc_result_t
2399 ipv6_pond_reference(struct ipv6_pond **pond, struct ipv6_pond *src,
2400  const char *file, int line) {
2401  if (pond == NULL) {
2402  log_error("%s(%d): NULL pointer reference", file, line);
2403  return DHCP_R_INVALIDARG;
2404  }
2405  if (*pond != NULL) {
2406  log_error("%s(%d): non-NULL pointer", file, line);
2407  return DHCP_R_INVALIDARG;
2408  }
2409  if (src == NULL) {
2410  log_error("%s(%d): NULL pointer reference", file, line);
2411  return DHCP_R_INVALIDARG;
2412  }
2413  *pond = src;
2414  src->refcnt++;
2415  return ISC_R_SUCCESS;
2416 }
2417 
2438 isc_result_t
2439 ipv6_pond_dereference(struct ipv6_pond **pond, const char *file, int line) {
2440  struct ipv6_pond *tmp;
2441 
2442  if ((pond == NULL) || (*pond == NULL)) {
2443  log_error("%s(%d): NULL pointer", file, line);
2444  return DHCP_R_INVALIDARG;
2445  }
2446 
2447  tmp = *pond;
2448  *pond = NULL;
2449 
2450  tmp->refcnt--;
2451  if (tmp->refcnt < 0) {
2452  log_error("%s(%d): negative refcnt", file, line);
2453  tmp->refcnt = 0;
2454  }
2455  if (tmp->refcnt == 0) {
2456  dfree(tmp, file, line);
2457  }
2458 
2459  return ISC_R_SUCCESS;
2460 }
2461 
2462 /* unittest moved to server/tests/mdb6_unittest.c */
#define FTS_ABANDONED
Definition: dhcpd.h:488
struct iaddrcidrnet cidrnet
Definition: inet.h:77
void mark_interfaces_unavailable(void)
Definition: mdb6.c:2312
ia_hash_t * ia_ta_active
isc_boolean_t lease6_usable(struct iasubopt *lease)
Check if address is available to a lease.
Definition: mdb6.c:1354
const char int line
Definition: dhcpd.h:3557
isc_result_t mark_lease_unavailable(struct ipv6_pool *pool, const struct in6_addr *addr)
Definition: mdb6.c:1792
struct binding_scope * global_scope
Definition: tree.c:39
isc_boolean_t prefix6_exists(const struct ipv6_pool *pool, const struct in6_addr *pref, u_int8_t plen)
Definition: mdb6.c:1769
Definition: dhcpd.h:507
unsigned len
Definition: tree.h:80
int executable_statement_dereference(struct executable_statement **ptr, const char *file, int line)
Definition: execute.c:615
int bits
Definition: inet.h:72
#define FTS_FREE
Definition: dhcpd.h:484
Definition: dhcpd.h:1541
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:1680
int units
Definition: dhcpd.h:1580
int max_iasubopt
Definition: dhcpd.h:1546
void * dmalloc(unsigned, const char *, int)
Definition: alloc.c:56
isc_result_t renew_lease6(struct ipv6_pool *pool, struct iasubopt *lease)
Renew a lease in the pool.
Definition: mdb6.c:1425
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:310
isc_result_t iasubopt_dereference(struct iasubopt **iasubopt, const char *file, int line)
Definition: mdb6.c:260
#define MDL
Definition: omapip.h:568
int heap_index
Definition: dhcpd.h:1526
unsigned char iabuf[16]
Definition: inet.h:33
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:2077
#define FTS_RELEASED
Definition: dhcpd.h:487
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:1600
struct executable_statement * on_release
Definition: dhcpd.h:503
isc_result_t ia_dereference(struct ia_xx **ia, const char *file, int line)
Definition: mdb6.c:402
void data_string_forget(struct data_string *data, const char *file, int line)
Definition: alloc.c:1276
isc_result_t ia_add_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt, const char *file, int line)
Definition: mdb6.c:438
struct in6_addr start_addr
Definition: dhcpd.h:1578
struct option_cache * fixed_addr
Definition: dhcpd.h:875
int log_error(const char *,...) __attribute__((__format__(__printf__
isc_result_t release_leases(struct ia_xx *ia)
Definition: mdb6.c:2146
#define FTS_EXPIRED
Definition: dhcpd.h:486
int binding_scope_dereference(struct binding_scope **ptr, const char *file, int line)
Definition: tree.c:3722
int num_inactive
Definition: dhcpd.h:1584
struct on_star on_star
Definition: dhcpd.h:1538
struct binding_scope * scope
Definition: dhcpd.h:1513
struct ipv6_pond * ipv6_pond
Definition: dhcpd.h:1590
void add_timeout(struct timeval *when, void(*)(void *) where, void *what, tvref_t ref, tvunref_t unref)
Definition: dispatch.c:198
void ia_remove_all_lease(struct ia_xx *ia, const char *file, int line)
Definition: mdb6.c:503
unsigned len
Definition: inet.h:32
int refcnt
Definition: dhcpd.h:1605
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:635
#define EXPIRED_IPV6_CLEANUP_TIME
Definition: dhcpd.h:1524
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. When the heap elements are deleted space is not freed but will be reused when new elements are inserted.
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:338
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:953
#define D6O_IA_TA
Definition: dhcp6.h:34
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:1326
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...
time_t hard_lifetime_end_time
Definition: dhcpd.h:1514
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:2643
host_hash_t * host_name_hash
Definition: mdb.c:37
Definition: dhcpd.h:906
unsigned do_string_hash(const void *, unsigned, unsigned)
Definition: hash.c:267
ia_hash_t * ia_na_active
struct ipv6_pool * ipv6_pool
Definition: dhcpd.h:1519
int buffer_allocate(struct buffer **ptr, unsigned len, const char *file, int line)
Definition: alloc.c:680
isc_result_t ipv6_pond_allocate(struct ipv6_pond **pond, const char *file, int line)
Create a new IPv6 pond structure.
Definition: mdb6.c:2356
int write_server_duid(void)
struct iaddrcidrnetlist * next
Definition: inet.h:76
isc_boolean_t ia_equal(const struct ia_xx *a, const struct ia_xx *b)
Definition: mdb6.c:517
u_int8_t plen
Definition: dhcpd.h:1511
struct data_string iaid_duid
Definition: dhcpd.h:1543
#define cur_time
Definition: dhcpd.h:1946
Definition: ip.h:47
void(* tvref_t)(void *, void *, const char *, int)
Definition: dhcpd.h:1316
int refcnt
Definition: dhcpd.h:1542
void dfree(void *, const char *, int)
Definition: alloc.c:131
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:1579
isc_result_t renew_leases(struct ia_xx *ia)
Definition: mdb6.c:2138
int refcnt
Definition: dhcpd.h:1509
isc_result_t decline_leases(struct ia_xx *ia)
Definition: mdb6.c:2154
iasubopt_hash_t * leases
Definition: dhcpd.h:1581
int num_iasubopt
Definition: dhcpd.h:1545
int int log_info(const char *,...) __attribute__((__format__(__printf__
u_int16_t ia_type
Definition: dhcpd.h:1544
binding_state_t state
Definition: dhcpd.h:1512
struct interface_info * interfaces
Definition: discover.c:43
int num_active
Definition: dhcpd.h:1619
isc_result_t ipv6_pool_dereference(struct ipv6_pool **pool, const char *file, int line)
de-reference an IPv6 pool structure.
Definition: mdb6.c:772
int v6address_count
Definition: dhcpd.h:1259
void(* tvunref_t)(void *, const char *, int)
Definition: dhcpd.h:1317
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:701
#define DEFAULT_HASH_SIZE
Definition: hash.h:33
ipv6_pool structure
Definition: dhcpd.h:1575
void isc_heap_destroy(isc_heap_t **heapp)
Destroys a heap.
int refcnt
Definition: dhcpd.h:1576
struct iaddrcidrnetlist * fixed_prefix
Definition: dhcpd.h:876
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:1046
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:512
isc_result_t add_lease6(struct ipv6_pool *pool, struct iasubopt *lease, time_t valid_lifetime_end_time)
Definition: mdb6.c:1228
struct interface_info * next
Definition: dhcpd.h:1247
isc_heap_t * inactive_timeouts
Definition: dhcpd.h:1585
#define D6O_IA_NA
Definition: dhcp6.h:33
isc_result_t iasubopt_reference(struct iasubopt **iasubopt, struct iasubopt *src, const char *file, int line)
Definition: mdb6.c:233
HASH_FUNCTIONS(ia, unsigned char *, struct ia_xx, ia_hash_t, ia_reference, ia_dereference, do_string_hash)
Definition: mdb6.c:180
unsigned char data[1]
Definition: tree.h:63
isc_heap_t * active_timeouts
Definition: dhcpd.h:1583
isc_result_t decline_lease6(struct ipv6_pool *pool, struct iasubopt *lease)
Definition: mdb6.c:1567
void schedule_lease_timeout(struct ipv6_pool *pool)
Definition: mdb6.c:1951
time_t soft_lifetime_end_time
Definition: dhcpd.h:1515
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:2439
isc_boolean_t ipv6_in_pool(const struct in6_addr *addr, const struct ipv6_pool *pool)
Definition: mdb6.c:2059
void mark_phosts_unavailable(void)
Definition: mdb6.c:2307
isc_result_t expire_lease6(struct iasubopt **leasep, struct ipv6_pool *pool, time_t now)
Definition: mdb6.c:1533
isc_result_t release_lease6(struct ipv6_pool *pool, struct iasubopt *lease)
Definition: mdb6.c:1587
#define MAX_TIME
Definition: dhcpd.h:1493
struct data_string data
Definition: dhcpd.h:354
ipv6_pond structure
Definition: dhcpd.h:1604
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:55
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:2399
struct ipv6_pool ** pools
struct iasubopt ** iasubopt
Definition: dhcpd.h:1548
int write_ia(const struct ia_xx *)
Definition: db.c:519
struct ia_xx * ia
Definition: dhcpd.h:1518
struct executable_statement * on_expiry
Definition: dhcpd.h:501
const char * file
Definition: dhcpd.h:3557
isc_result_t ia_reference(struct ia_xx **ia, struct ia_xx *src, const char *file, int line)
Definition: mdb6.c:376
struct in6_addr addr
Definition: dhcpd.h:1510
struct executable_statement * on_commit
Definition: dhcpd.h:502
const unsigned char * data
Definition: tree.h:79
isc_result_t add_ipv6_pool(struct ipv6_pool *pool)
Definition: mdb6.c:1810
void data_string_copy(struct data_string *dest, const struct data_string *src, const char *file, int line)
Definition: alloc.c:1260
void mark_hosts_unavailable(void)
Definition: mdb6.c:2257
u_int16_t pool_type
Definition: dhcpd.h:1577
isc_result_t isc_heap_insert(isc_heap_t *heap, void *elt)
Inserts a new element into a heap.
void ia_remove_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt, const char *file, int line)
Definition: mdb6.c:475
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:1124
u_int8_t binding_state_t
Definition: dhcpd.h:491
void schedule_all_ipv6_lease_timeouts(void)
Definition: mdb6.c:1994
struct buffer * buffer
Definition: tree.h:78
int num_active
Definition: dhcpd.h:1582
#define FTS_ACTIVE
Definition: dhcpd.h:485
struct in6_addr * v6addresses
Definition: dhcpd.h:1257
int num_pools