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