ISC DHCP  4.3.6
A reference DHCPv4 and DHCPv6 implementation
mdb6.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-2016 by Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16 
168 #include "config.h"
169 
170 #include <sys/types.h>
171 #include <time.h>
172 #include <netinet/in.h>
173 
174 #include <stdarg.h>
175 #include "dhcpd.h"
176 #include "omapip/omapip.h"
177 #include "omapip/hash.h"
178 #include <isc/md5.h>
179 
180 HASH_FUNCTIONS(ia, unsigned char *, struct ia_xx, ia_hash_t,
182 
186 
187 HASH_FUNCTIONS(iasubopt, struct in6_addr *, struct iasubopt, iasubopt_hash_t,
189 
190 struct ipv6_pool **pools;
191 int num_pools;
192 
193 /*
194  * Create a new IAADDR/PREFIX structure.
195  *
196  * - iasubopt must be a pointer to a (struct iasubopt *) pointer previously
197  * initialized to NULL
198  */
199 isc_result_t
200 iasubopt_allocate(struct iasubopt **iasubopt, const char *file, int line) {
201  struct iasubopt *tmp;
202 
203  if (iasubopt == NULL) {
204  log_error("%s(%d): NULL pointer reference", file, line);
205  return DHCP_R_INVALIDARG;
206  }
207  if (*iasubopt != NULL) {
208  log_error("%s(%d): non-NULL pointer", file, line);
209  return DHCP_R_INVALIDARG;
210  }
211 
212  tmp = dmalloc(sizeof(*tmp), file, line);
213  if (tmp == NULL) {
214  return ISC_R_NOMEMORY;
215  }
216 
217  tmp->refcnt = 1;
218  tmp->state = FTS_FREE;
219  tmp->active_index = -1;
220  tmp->inactive_index = -1;
221  tmp->plen = 255;
222 
223  *iasubopt = tmp;
224  return ISC_R_SUCCESS;
225 }
226 
227 /*
228  * Reference an IAADDR/PREFIX structure.
229  *
230  * - iasubopt must be a pointer to a (struct iasubopt *) pointer previously
231  * initialized to NULL
232  */
233 isc_result_t
235  const char *file, int line) {
236  if (iasubopt == NULL) {
237  log_error("%s(%d): NULL pointer reference", file, line);
238  return DHCP_R_INVALIDARG;
239  }
240  if (*iasubopt != NULL) {
241  log_error("%s(%d): non-NULL pointer", file, line);
242  return DHCP_R_INVALIDARG;
243  }
244  if (src == NULL) {
245  log_error("%s(%d): NULL pointer reference", file, line);
246  return DHCP_R_INVALIDARG;
247  }
248  *iasubopt = src;
249  src->refcnt++;
250  return ISC_R_SUCCESS;
251 }
252 
253 
254 /*
255  * Dereference an IAADDR/PREFIX structure.
256  *
257  * If it is the last reference, then the memory for the
258  * structure is freed.
259  */
260 isc_result_t
261 iasubopt_dereference(struct iasubopt **iasubopt, const char *file, int line) {
262  struct iasubopt *tmp;
263 
264  if ((iasubopt == NULL) || (*iasubopt == NULL)) {
265  log_error("%s(%d): NULL pointer", file, line);
266  return DHCP_R_INVALIDARG;
267  }
268 
269  tmp = *iasubopt;
270  *iasubopt = NULL;
271 
272  tmp->refcnt--;
273  if (tmp->refcnt < 0) {
274  log_error("%s(%d): negative refcnt", file, line);
275  tmp->refcnt = 0;
276  }
277  if (tmp->refcnt == 0) {
278  if (tmp->ia != NULL) {
279  ia_dereference(&(tmp->ia), file, line);
280  }
281  if (tmp->ipv6_pool != NULL) {
283  }
284  if (tmp->scope != NULL) {
286  }
287 
288  if (tmp->on_star.on_expiry != NULL) {
290  (&tmp->on_star.on_expiry, MDL);
291  }
292  if (tmp->on_star.on_commit != NULL) {
294  (&tmp->on_star.on_commit, MDL);
295  }
296  if (tmp->on_star.on_release != NULL) {
298  (&tmp->on_star.on_release, MDL);
299  }
300 
301  dfree(tmp, file, line);
302  }
303 
304  return ISC_R_SUCCESS;
305 }
306 
307 /*
308  * Make the key that we use for IA.
309  */
310 isc_result_t
311 ia_make_key(struct data_string *key, u_int32_t iaid,
312  const char *duid, unsigned int duid_len,
313  const char *file, int line) {
314 
315  memset(key, 0, sizeof(*key));
316  key->len = duid_len + sizeof(iaid);
317  if (!buffer_allocate(&(key->buffer), key->len, file, line)) {
318  return ISC_R_NOMEMORY;
319  }
320  key->data = key->buffer->data;
321  memcpy((char *)key->data, &iaid, sizeof(iaid));
322  memcpy((char *)key->data + sizeof(iaid), duid, duid_len);
323 
324  return ISC_R_SUCCESS;
325 }
326 
327 /*
328  * Create a new IA structure.
329  *
330  * - ia must be a pointer to a (struct ia_xx *) pointer previously
331  * initialized to NULL
332  * - iaid and duid are values from the client
333  *
334  * XXXsk: we don't concern ourself with the byte order of the IAID,
335  * which might be a problem if we transfer this structure
336  * between machines of different byte order
337  */
338 isc_result_t
339 ia_allocate(struct ia_xx **ia, u_int32_t iaid,
340  const char *duid, unsigned int duid_len,
341  const char *file, int line) {
342  struct ia_xx *tmp;
343 
344  if (ia == NULL) {
345  log_error("%s(%d): NULL pointer reference", file, line);
346  return DHCP_R_INVALIDARG;
347  }
348  if (*ia != NULL) {
349  log_error("%s(%d): non-NULL pointer", file, line);
350  return DHCP_R_INVALIDARG;
351  }
352 
353  tmp = dmalloc(sizeof(*tmp), file, line);
354  if (tmp == NULL) {
355  return ISC_R_NOMEMORY;
356  }
357 
358  if (ia_make_key(&tmp->iaid_duid, iaid,
359  duid, duid_len, file, line) != ISC_R_SUCCESS) {
360  dfree(tmp, file, line);
361  return ISC_R_NOMEMORY;
362  }
363 
364  tmp->refcnt = 1;
365 
366  *ia = tmp;
367  return ISC_R_SUCCESS;
368 }
369 
370 /*
371  * Reference an IA structure.
372  *
373  * - ia must be a pointer to a (struct ia_xx *) pointer previously
374  * initialized to NULL
375  */
376 isc_result_t
377 ia_reference(struct ia_xx **ia, struct ia_xx *src,
378  const char *file, int line) {
379  if (ia == NULL) {
380  log_error("%s(%d): NULL pointer reference", file, line);
381  return DHCP_R_INVALIDARG;
382  }
383  if (*ia != NULL) {
384  log_error("%s(%d): non-NULL pointer", file, line);
385  return DHCP_R_INVALIDARG;
386  }
387  if (src == NULL) {
388  log_error("%s(%d): NULL pointer reference", file, line);
389  return DHCP_R_INVALIDARG;
390  }
391  *ia = src;
392  src->refcnt++;
393  return ISC_R_SUCCESS;
394 }
395 
396 /*
397  * Dereference an IA structure.
398  *
399  * If it is the last reference, then the memory for the
400  * structure is freed.
401  */
402 isc_result_t
403 ia_dereference(struct ia_xx **ia, const char *file, int line) {
404  struct ia_xx *tmp;
405  int i;
406 
407  if ((ia == NULL) || (*ia == NULL)) {
408  log_error("%s(%d): NULL pointer", file, line);
409  return DHCP_R_INVALIDARG;
410  }
411 
412  tmp = *ia;
413  *ia = NULL;
414 
415  tmp->refcnt--;
416  if (tmp->refcnt < 0) {
417  log_error("%s(%d): negative refcnt", file, line);
418  tmp->refcnt = 0;
419  }
420  if (tmp->refcnt == 0) {
421  if (tmp->iasubopt != NULL) {
422  for (i=0; i<tmp->num_iasubopt; i++) {
423  iasubopt_dereference(&(tmp->iasubopt[i]),
424  file, line);
425  }
426  dfree(tmp->iasubopt, file, line);
427  }
429  dfree(tmp, file, line);
430  }
431  return ISC_R_SUCCESS;
432 }
433 
434 
435 /*
436  * Add an IAADDR/PREFIX entry to an IA structure.
437  */
438 isc_result_t
439 ia_add_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt,
440  const char *file, int line) {
441  int max;
442  struct iasubopt **new;
443 
444  /*
445  * Grow our array if we need to.
446  *
447  * Note: we pick 4 as the increment, as that seems a reasonable
448  * guess as to how many addresses/prefixes we might expect
449  * on an interface.
450  */
451  if (ia->max_iasubopt <= ia->num_iasubopt) {
452  max = ia->max_iasubopt + 4;
453  new = dmalloc(max * sizeof(struct iasubopt *), file, line);
454  if (new == NULL) {
455  return ISC_R_NOMEMORY;
456  }
457  memcpy(new, ia->iasubopt,
458  ia->num_iasubopt * sizeof(struct iasubopt *));
459  ia->iasubopt = new;
460  ia->max_iasubopt = max;
461  }
462 
464  file, line);
465  ia->num_iasubopt++;
466 
467  return ISC_R_SUCCESS;
468 }
469 
470 /*
471  * Remove an IAADDR/PREFIX entry to an IA structure.
472  *
473  * Note: if a suboption appears more than once, then only ONE will be removed.
474  */
475 void
477  const char *file, int line) {
478  int i, j;
479  if (ia == NULL || iasubopt == NULL)
480  return;
481 
482  for (i=0; i<ia->num_iasubopt; i++) {
483  if (ia->iasubopt[i] == iasubopt) {
484  /* remove this sub option */
486  /* move remaining suboption pointers down one */
487  for (j=i+1; j < ia->num_iasubopt; j++) {
488  ia->iasubopt[j-1] = ia->iasubopt[j];
489  }
490  /* decrease our total count */
491  /* remove the back-reference in the suboption itself */
493  ia->num_iasubopt--;
494  return;
495  }
496  }
497  log_error("%s(%d): IAADDR/PREFIX not in IA", file, line);
498 }
499 
500 /*
501  * Remove all addresses/prefixes from an IA.
502  */
503 void
504 ia_remove_all_lease(struct ia_xx *ia, const char *file, int line) {
505  int i;
506 
507  for (i=0; i<ia->num_iasubopt; i++) {
508  ia_dereference(&(ia->iasubopt[i]->ia), file, line);
510  }
511  ia->num_iasubopt = 0;
512 }
513 
514 /*
515  * Compare two IA.
516  */
517 isc_boolean_t
518 ia_equal(const struct ia_xx *a, const struct ia_xx *b)
519 {
520  isc_boolean_t found;
521  int i, j;
522 
523  /*
524  * Handle cases where one or both of the inputs is NULL.
525  */
526  if (a == NULL) {
527  if (b == NULL) {
528  return ISC_TRUE;
529  } else {
530  return ISC_FALSE;
531  }
532  }
533 
534  /*
535  * Check the type is the same.
536  */
537  if (a->ia_type != b->ia_type) {
538  return ISC_FALSE;
539  }
540 
541  /*
542  * Check the DUID is the same.
543  */
544  if (a->iaid_duid.len != b->iaid_duid.len) {
545  return ISC_FALSE;
546  }
547  if (memcmp(a->iaid_duid.data,
548  b->iaid_duid.data, a->iaid_duid.len) != 0) {
549  return ISC_FALSE;
550  }
551 
552  /*
553  * Make sure we have the same number of addresses/prefixes in each.
554  */
555  if (a->num_iasubopt != b->num_iasubopt) {
556  return ISC_FALSE;
557  }
558 
559  /*
560  * Check that each address/prefix is present in both.
561  */
562  for (i=0; i<a->num_iasubopt; i++) {
563  found = ISC_FALSE;
564  for (j=0; j<a->num_iasubopt; j++) {
565  if (a->iasubopt[i]->plen != b->iasubopt[i]->plen)
566  continue;
567  if (memcmp(&(a->iasubopt[i]->addr),
568  &(b->iasubopt[j]->addr),
569  sizeof(struct in6_addr)) == 0) {
570  found = ISC_TRUE;
571  break;
572  }
573  }
574  if (!found) {
575  return ISC_FALSE;
576  }
577  }
578 
579  /*
580  * These are the same in every way we care about.
581  */
582  return ISC_TRUE;
583 }
584 
585 /*
586  * Helper function for lease heaps.
587  * Makes the top of the heap the oldest lease.
588  */
589 static isc_boolean_t
590 lease_older(void *a, void *b) {
591  struct iasubopt *la = (struct iasubopt *)a;
592  struct iasubopt *lb = (struct iasubopt *)b;
593 
595  return difftime(la->soft_lifetime_end_time,
596  lb->soft_lifetime_end_time) < 0;
597  } else {
598  return difftime(la->hard_lifetime_end_time,
599  lb->hard_lifetime_end_time) < 0;
600  }
601 }
602 
603 /*
604  * Helper function 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 /*
860  * Create a temporary address by a variant of RFC 4941 algo.
861  * Note: this should not be used for prefixes shorter than 64 bits.
862  */
863 static void
864 build_temporary6(struct in6_addr *addr,
865  const struct in6_addr *net_start_addr, int net_bits,
866  const struct data_string *input) {
867  static u_int32_t history[2];
868  static u_int32_t counter = 0;
869  isc_md5_t ctx;
870  unsigned char md[16];
871 
872  /*
873  * First time/time to reseed.
874  * Please use a good pseudo-random generator here!
875  */
876  if (counter == 0) {
877  isc_random_get(&history[0]);
878  isc_random_get(&history[1]);
879  }
880 
881  /*
882  * Use MD5 as recommended by RFC 4941.
883  */
884  isc_md5_init(&ctx);
885  isc_md5_update(&ctx, (unsigned char *)&history[0], 8UL);
886  isc_md5_update(&ctx, input->data, input->len);
887  isc_md5_final(&ctx, md);
888 
889  /*
890  * Build the address.
891  */
892  if (net_bits == 64) {
893  memcpy(&addr->s6_addr[0], &net_start_addr->s6_addr[0], 8);
894  memcpy(&addr->s6_addr[8], md, 8);
895  addr->s6_addr[8] &= ~0x02;
896  } else {
897  int net_bytes;
898  int i;
899  char *str;
900  const char *net_str;
901 
902  /*
903  * Copy the [0..128] network bits over.
904  */
905  str = (char *)addr;
906  net_str = (const char *)net_start_addr;
907  net_bytes = net_bits / 8;
908  for (i = 0; i < net_bytes; i++) {
909  str[i] = net_str[i];
910  }
911  memcpy(str + net_bytes, md, 16 - net_bytes);
912  switch (net_bits % 8) {
913  case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
914  case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
915  case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break;
916  case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break;
917  case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break;
918  case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break;
919  case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break;
920  }
921  }
922 
923 
924  /*
925  * Save history for the next call.
926  */
927  memcpy((unsigned char *)&history[0], md + 8, 8);
928  counter++;
929 }
930 
931 /* Reserved Subnet Router Anycast ::0:0:0:0. */
932 static struct in6_addr rtany;
933 /* Reserved Subnet Anycasts ::fdff:ffff:ffff:ff80-::fdff:ffff:ffff:ffff. */
934 static struct in6_addr resany;
935 
936 /*
937  * Create a lease for the given address and client duid.
938  *
939  * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
940  * initialized to NULL
941  *
942  * Right now we simply hash the DUID, and if we get a collision, we hash
943  * again until we find a free address. We try this a fixed number of times,
944  * to avoid getting stuck in a loop (this is important on small pools
945  * where we can run out of space).
946  *
947  * We return the number of attempts that it took to find an available
948  * lease. This tells callers when a pool is are filling up, as
949  * well as an indication of how full the pool is; statistically the
950  * more full a pool is the more attempts must be made before finding
951  * a free lease. Realistically this will only happen in very full
952  * pools.
953  *
954  * We probably want different algorithms depending on the network size, in
955  * the long term.
956  */
957 isc_result_t
958 create_lease6(struct ipv6_pool *pool, struct iasubopt **addr,
959  unsigned int *attempts,
960  const struct data_string *uid, time_t soft_lifetime_end_time) {
961  struct data_string ds;
962  struct in6_addr tmp;
963  struct iasubopt *test_iaaddr;
964  struct data_string new_ds;
965  struct iasubopt *iaaddr;
966  isc_result_t result;
967  isc_boolean_t reserved_iid;
968  static isc_boolean_t init_resiid = ISC_FALSE;
969 
970  /*
971  * Fill the reserved IIDs.
972  */
973  if (!init_resiid) {
974  memset(&rtany, 0, 16);
975  memset(&resany, 0, 8);
976  resany.s6_addr[8] = 0xfd;
977  memset(&resany.s6_addr[9], 0xff, 6);
978  init_resiid = ISC_TRUE;
979  }
980 
981  /*
982  * Use the UID as our initial seed for the hash
983  */
984  memset(&ds, 0, sizeof(ds));
985  data_string_copy(&ds, (struct data_string *)uid, MDL);
986 
987  *attempts = 0;
988  for (;;) {
989  /*
990  * Give up at some point.
991  */
992  if (++(*attempts) > 100) {
993  data_string_forget(&ds, MDL);
994  return ISC_R_NORESOURCES;
995  }
996 
997  /*
998  * Build a resource.
999  */
1000  switch (pool->pool_type) {
1001  case D6O_IA_NA:
1002  /* address */
1003  build_address6(&tmp, &pool->start_addr,
1004  pool->bits, &ds);
1005  break;
1006  case D6O_IA_TA:
1007  /* temporary address */
1008  build_temporary6(&tmp, &pool->start_addr,
1009  pool->bits, &ds);
1010  break;
1011  case D6O_IA_PD:
1012  /* prefix */
1013  log_error("create_lease6: prefix pool.");
1014  return DHCP_R_INVALIDARG;
1015  default:
1016  log_error("create_lease6: untyped pool.");
1017  return DHCP_R_INVALIDARG;
1018  }
1019 
1020  /*
1021  * Avoid reserved interface IDs. (cf. RFC 5453)
1022  */
1023  reserved_iid = ISC_FALSE;
1024  if (memcmp(&tmp.s6_addr[8], &rtany.s6_addr[8], 8) == 0) {
1025  reserved_iid = ISC_TRUE;
1026  }
1027  if (!reserved_iid &&
1028  (memcmp(&tmp.s6_addr[8], &resany.s6_addr[8], 7) == 0) &&
1029  ((tmp.s6_addr[15] & 0x80) == 0x80)) {
1030  reserved_iid = ISC_TRUE;
1031  }
1032 
1033  /*
1034  * If this address is not in use, we're happy with it
1035  */
1036  test_iaaddr = NULL;
1037  if (!reserved_iid &&
1038  (iasubopt_hash_lookup(&test_iaaddr, pool->leases,
1039  &tmp, sizeof(tmp), MDL) == 0)) {
1040  break;
1041  }
1042  if (test_iaaddr != NULL)
1043  iasubopt_dereference(&test_iaaddr, MDL);
1044 
1045  /*
1046  * Otherwise, we create a new input, adding the address
1047  */
1048  memset(&new_ds, 0, sizeof(new_ds));
1049  new_ds.len = ds.len + sizeof(tmp);
1050  if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) {
1051  data_string_forget(&ds, MDL);
1052  return ISC_R_NOMEMORY;
1053  }
1054  new_ds.data = new_ds.buffer->data;
1055  memcpy(new_ds.buffer->data, ds.data, ds.len);
1056  memcpy(new_ds.buffer->data + ds.len, &tmp, sizeof(tmp));
1057  data_string_forget(&ds, MDL);
1058  data_string_copy(&ds, &new_ds, MDL);
1059  data_string_forget(&new_ds, MDL);
1060  }
1061 
1062  data_string_forget(&ds, MDL);
1063 
1064  /*
1065  * We're happy with the address, create an IAADDR
1066  * to hold it.
1067  */
1068  iaaddr = NULL;
1069  result = iasubopt_allocate(&iaaddr, MDL);
1070  if (result != ISC_R_SUCCESS) {
1071  return result;
1072  }
1073  iaaddr->plen = 0;
1074  memcpy(&iaaddr->addr, &tmp, sizeof(iaaddr->addr));
1075 
1076  /*
1077  * Add the lease to the pool (note state is free, not active?!).
1078  */
1079  result = add_lease6(pool, iaaddr, soft_lifetime_end_time);
1080  if (result == ISC_R_SUCCESS) {
1081  iasubopt_reference(addr, iaaddr, MDL);
1082  }
1083  iasubopt_dereference(&iaaddr, MDL);
1084  return result;
1085 }
1086 
1087 
1128 isc_result_t
1130  struct ipv6_pool *pool,
1131  struct iasubopt *lease,
1132  struct ia_xx *ia) {
1133 
1134  struct iasubopt *test_iasubopt, *tmp_iasubopt;
1135  struct ia_xx *old_ia;
1136  isc_result_t status = ISC_R_SUCCESS;
1137 
1138  test_iasubopt = NULL;
1139  old_ia = NULL;
1140 
1141  /*
1142  * Look up the address - if we don't find a lease
1143  * we don't need to do anything.
1144  */
1145  if (iasubopt_hash_lookup(&test_iasubopt, pool->leases,
1146  &lease->addr, sizeof(lease->addr),
1147  MDL) == 0) {
1148  return (ISC_R_SUCCESS);
1149  }
1150 
1151  if (test_iasubopt->ia == NULL) {
1152  /* no old ia, no work to do */
1153  iasubopt_dereference(&test_iasubopt, MDL);
1154  return (status);
1155  }
1156 
1157  ia_reference(&old_ia, test_iasubopt->ia, MDL);
1158 
1159  if ((old_ia->iaid_duid.len == ia->iaid_duid.len) &&
1160  (memcmp((unsigned char *)ia->iaid_duid.data,
1161  (unsigned char *)old_ia->iaid_duid.data,
1162  ia->iaid_duid.len) == 0)) {
1163  /* same IA */
1164  if ((lease->state == FTS_ACTIVE) ||
1165  (lease->state == FTS_ABANDONED)) {
1166  /* still active, no need to delete */
1167  goto cleanup;
1168  }
1169  } else {
1170  /* different IA */
1171  if ((lease->state != FTS_ACTIVE) &&
1172  (lease->state != FTS_ABANDONED)) {
1173  /* new lease isn't active, no work */
1174  goto cleanup;
1175  }
1176 
1177  /*
1178  * We appear to have two active leases, this shouldn't happen.
1179  * Before a second lease can be set to active the first lease
1180  * should be set to inactive (released, expired etc). For now
1181  * delete the previous lease and indicate a failure to the
1182  * caller so it can generate a warning.
1183  * In the future we may try and determine which is the better
1184  * lease to keep.
1185  */
1186 
1187  status = ISC_R_FAILURE;
1188  }
1189 
1190  /*
1191  * Remove the old lease from the active heap and from the hash table
1192  * then remove the lease from the IA and clean up the IA if necessary.
1193  */
1194  isc_heap_delete(pool->active_timeouts, test_iasubopt->active_index);
1195  pool->num_active--;
1196  if (pool->ipv6_pond)
1197  pool->ipv6_pond->num_active--;
1198 
1199  if (lease->state == FTS_ABANDONED) {
1200  pool->num_abandoned--;
1201  if (pool->ipv6_pond)
1202  pool->ipv6_pond->num_abandoned--;
1203  }
1204 
1205  iasubopt_hash_delete(pool->leases, &test_iasubopt->addr,
1206  sizeof(test_iasubopt->addr), MDL);
1207  ia_remove_iasubopt(old_ia, test_iasubopt, MDL);
1208  if (old_ia->num_iasubopt <= 0) {
1209  ia_hash_delete(ia_table,
1210  (unsigned char *)old_ia->iaid_duid.data,
1211  old_ia->iaid_duid.len, MDL);
1212  }
1213 
1214  /*
1215  * We derefenrece the subopt here as we've just removed it from
1216  * the hash table in the pool. We need to make a copy as we
1217  * need to derefernece it again later.
1218  */
1219  tmp_iasubopt = test_iasubopt;
1220  iasubopt_dereference(&tmp_iasubopt, MDL);
1221 
1222  cleanup:
1223  ia_dereference(&old_ia, MDL);
1224 
1225  /*
1226  * Clean up the reference, this is in addition to the deference
1227  * above after removing the entry from the hash table
1228  */
1229  iasubopt_dereference(&test_iasubopt, MDL);
1230 
1231  return (status);
1232 }
1233 
1234 /*
1235  * Put a lease in the pool directly. This is intended to be used when
1236  * loading leases from the file.
1237  */
1238 isc_result_t
1240  time_t valid_lifetime_end_time) {
1241  isc_result_t insert_result;
1242  struct iasubopt *test_iasubopt;
1243  struct iasubopt *tmp_iasubopt;
1244 
1245  /* If a state was not assigned by the caller, assume active. */
1246  if (lease->state == 0)
1247  lease->state = FTS_ACTIVE;
1248 
1249  ipv6_pool_reference(&lease->ipv6_pool, pool, MDL);
1250 
1251  /*
1252  * If this IAADDR/PREFIX is already in our structures, remove the
1253  * old one.
1254  */
1255  test_iasubopt = NULL;
1256  if (iasubopt_hash_lookup(&test_iasubopt, pool->leases,
1257  &lease->addr, sizeof(lease->addr), MDL)) {
1258  /* XXX: we should probably ask the lease what heap it is on
1259  * (as a consistency check).
1260  * XXX: we should probably have one function to "put this lease
1261  * on its heap" rather than doing these if's everywhere. If
1262  * you add more states to this list, don't.
1263  */
1264  if ((test_iasubopt->state == FTS_ACTIVE) ||
1265  (test_iasubopt->state == FTS_ABANDONED)) {
1266  isc_heap_delete(pool->active_timeouts,
1267  test_iasubopt->active_index);
1268  pool->num_active--;
1269  if (pool->ipv6_pond)
1270  pool->ipv6_pond->num_active--;
1271 
1272  if (test_iasubopt->state == FTS_ABANDONED) {
1273  pool->num_abandoned--;
1274  if (pool->ipv6_pond)
1275  pool->ipv6_pond->num_abandoned--;
1276  }
1277  } else {
1278  isc_heap_delete(pool->inactive_timeouts,
1279  test_iasubopt->inactive_index);
1280  pool->num_inactive--;
1281  }
1282 
1283  iasubopt_hash_delete(pool->leases, &test_iasubopt->addr,
1284  sizeof(test_iasubopt->addr), MDL);
1285 
1286  /*
1287  * We're going to do a bit of evil trickery here.
1288  *
1289  * We need to dereference the entry once to remove our
1290  * current reference (in test_iasubopt), and then one
1291  * more time to remove the reference left when the
1292  * address was added to the pool before.
1293  */
1294  tmp_iasubopt = test_iasubopt;
1295  iasubopt_dereference(&test_iasubopt, MDL);
1296  iasubopt_dereference(&tmp_iasubopt, MDL);
1297  }
1298 
1299  /*
1300  * Add IAADDR/PREFIX to our structures.
1301  */
1302  tmp_iasubopt = NULL;
1303  iasubopt_reference(&tmp_iasubopt, lease, MDL);
1304  if ((tmp_iasubopt->state == FTS_ACTIVE) ||
1305  (tmp_iasubopt->state == FTS_ABANDONED)) {
1306  tmp_iasubopt->hard_lifetime_end_time = valid_lifetime_end_time;
1307  iasubopt_hash_add(pool->leases, &tmp_iasubopt->addr,
1308  sizeof(tmp_iasubopt->addr), lease, MDL);
1309  insert_result = isc_heap_insert(pool->active_timeouts,
1310  tmp_iasubopt);
1311  if (insert_result == ISC_R_SUCCESS) {
1312  pool->num_active++;
1313  if (pool->ipv6_pond)
1314  pool->ipv6_pond->num_active++;
1315 
1316  if (tmp_iasubopt->state == FTS_ABANDONED) {
1317  pool->num_abandoned++;
1318  if (pool->ipv6_pond)
1319  pool->ipv6_pond->num_abandoned++;
1320  }
1321  }
1322 
1323  } else {
1324  tmp_iasubopt->soft_lifetime_end_time = valid_lifetime_end_time;
1325  insert_result = isc_heap_insert(pool->inactive_timeouts,
1326  tmp_iasubopt);
1327  if (insert_result == ISC_R_SUCCESS)
1328  pool->num_inactive++;
1329  }
1330  if (insert_result != ISC_R_SUCCESS) {
1331  iasubopt_hash_delete(pool->leases, &lease->addr,
1332  sizeof(lease->addr), MDL);
1333  iasubopt_dereference(&tmp_iasubopt, MDL);
1334  return insert_result;
1335  }
1336 
1337  /*
1338  * Note: we intentionally leave tmp_iasubopt referenced; there
1339  * is a reference in the heap/hash, after all.
1340  */
1341 
1342  return ISC_R_SUCCESS;
1343 }
1344 
1345 /*
1346  * Determine if an address is present in a pool or not.
1347  */
1348 isc_boolean_t
1349 lease6_exists(const struct ipv6_pool *pool, const struct in6_addr *addr) {
1350  struct iasubopt *test_iaaddr;
1351 
1352  test_iaaddr = NULL;
1353  if (iasubopt_hash_lookup(&test_iaaddr, pool->leases,
1354  (void *)addr, sizeof(*addr), MDL)) {
1355  iasubopt_dereference(&test_iaaddr, MDL);
1356  return ISC_TRUE;
1357  } else {
1358  return ISC_FALSE;
1359  }
1360 }
1361 
1376 isc_boolean_t
1378  struct iasubopt *test_iaaddr;
1379  isc_boolean_t status = ISC_TRUE;
1380 
1381  test_iaaddr = NULL;
1382  if (iasubopt_hash_lookup(&test_iaaddr, lease->ipv6_pool->leases,
1383  (void *)&lease->addr,
1384  sizeof(lease->addr), MDL)) {
1385  if (test_iaaddr != lease) {
1386  status = ISC_FALSE;
1387  }
1388  iasubopt_dereference(&test_iaaddr, MDL);
1389  }
1390 
1391  return (status);
1392 }
1393 
1394 /*
1395  * Put the lease on our active pool.
1396  */
1397 static isc_result_t
1398 move_lease_to_active(struct ipv6_pool *pool, struct iasubopt *lease) {
1399  isc_result_t insert_result;
1400 
1401  insert_result = isc_heap_insert(pool->active_timeouts, lease);
1402  if (insert_result == ISC_R_SUCCESS) {
1403  iasubopt_hash_add(pool->leases, &lease->addr,
1404  sizeof(lease->addr), lease, MDL);
1405  isc_heap_delete(pool->inactive_timeouts,
1406  lease->inactive_index);
1407  pool->num_active++;
1408  pool->num_inactive--;
1409  lease->state = FTS_ACTIVE;
1410  if (pool->ipv6_pond)
1411  pool->ipv6_pond->num_active++;
1412 
1413  }
1414  return insert_result;
1415 }
1416 
1447 isc_result_t
1449  time_t old_end_time = lease->hard_lifetime_end_time;
1450  lease->hard_lifetime_end_time = lease->soft_lifetime_end_time;
1451  lease->soft_lifetime_end_time = 0;
1452 
1453  if (lease->state == FTS_ACTIVE) {
1454  if (old_end_time <= lease->hard_lifetime_end_time) {
1455  isc_heap_decreased(pool->active_timeouts,
1456  lease->active_index);
1457  } else {
1458  isc_heap_increased(pool->active_timeouts,
1459  lease->active_index);
1460  }
1461  return ISC_R_SUCCESS;
1462  } else if (lease->state == FTS_ABANDONED) {
1463  char tmp_addr[INET6_ADDRSTRLEN];
1464  lease->state = FTS_ACTIVE;
1465  isc_heap_increased(pool->active_timeouts, lease->active_index);
1466  log_info("Reclaiming previously abandoned address %s",
1467  inet_ntop(AF_INET6, &(lease->addr), tmp_addr,
1468  sizeof(tmp_addr)));
1469 
1470  pool->num_abandoned--;
1471  if (pool->ipv6_pond)
1472  pool->ipv6_pond->num_abandoned--;
1473 
1474  return ISC_R_SUCCESS;
1475  } else {
1476  return move_lease_to_active(pool, lease);
1477  }
1478 }
1479 
1480 /*
1481  * Put the lease on our inactive pool, with the specified state.
1482  */
1483 static isc_result_t
1484 move_lease_to_inactive(struct ipv6_pool *pool, struct iasubopt *lease,
1486  isc_result_t insert_result;
1487 
1488  insert_result = isc_heap_insert(pool->inactive_timeouts, lease);
1489  if (insert_result == ISC_R_SUCCESS) {
1490  /*
1491  * Handle expire and release statements
1492  * To get here we must be active and have done a commit so
1493  * we should run the proper statements if they exist, though
1494  * that will change when we remove the inactive heap.
1495  * In addition we get rid of the references for both as we
1496  * can only do one (expire or release) on a lease
1497  */
1498  if (lease->on_star.on_expiry != NULL) {
1499  if (state == FTS_EXPIRED) {
1500  execute_statements(NULL, NULL, NULL,
1501  NULL, NULL, NULL,
1502  &lease->scope,
1504  &lease->on_star);
1505  }
1507  (&lease->on_star.on_expiry, MDL);
1508  }
1509 
1510  if (lease->on_star.on_release != NULL) {
1511  if (state == FTS_RELEASED) {
1512  execute_statements(NULL, NULL, NULL,
1513  NULL, NULL, NULL,
1514  &lease->scope,
1516  &lease->on_star);
1517  }
1519  (&lease->on_star.on_release, MDL);
1520  }
1521 
1522 #if defined (NSUPDATE)
1523  /* Process events upon expiration. */
1524  if (pool->pool_type != D6O_IA_PD) {
1525  (void) ddns_removals(NULL, lease, NULL, ISC_FALSE);
1526  }
1527 #endif
1528 
1529  /* Binding scopes are no longer valid after expiry or
1530  * release.
1531  */
1532  if (lease->scope != NULL) {
1534  }
1535 
1536  iasubopt_hash_delete(pool->leases,
1537  &lease->addr, sizeof(lease->addr), MDL);
1538  isc_heap_delete(pool->active_timeouts, lease->active_index);
1539  lease->state = state;
1540  pool->num_active--;
1541  pool->num_inactive++;
1542  if (pool->ipv6_pond)
1543  pool->ipv6_pond->num_active--;
1544 
1545  if (lease->state == FTS_ABANDONED) {
1546  pool->num_abandoned--;
1547  if (pool->ipv6_pond)
1548  pool->ipv6_pond->num_abandoned--;
1549  }
1550  }
1551  return insert_result;
1552 }
1553 
1554 /*
1555  * Expire the oldest lease if it's lifetime_end_time is
1556  * older than the given time.
1557  *
1558  * - leasep must be a pointer to a (struct iasubopt *) pointer previously
1559  * initialized to NULL
1560  *
1561  * On return leasep has a reference to the removed entry. It is left
1562  * pointing to NULL if the oldest lease has not expired.
1563  */
1564 isc_result_t
1565 expire_lease6(struct iasubopt **leasep, struct ipv6_pool *pool, time_t now) {
1566  struct iasubopt *tmp;
1567  isc_result_t result;
1568 
1569  if (leasep == NULL) {
1570  log_error("%s(%d): NULL pointer reference", MDL);
1571  return DHCP_R_INVALIDARG;
1572  }
1573  if (*leasep != NULL) {
1574  log_error("%s(%d): non-NULL pointer", MDL);
1575  return DHCP_R_INVALIDARG;
1576  }
1577 
1578  if (pool->num_active > 0) {
1579  tmp = (struct iasubopt *)
1580  isc_heap_element(pool->active_timeouts, 1);
1581  if (now > tmp->hard_lifetime_end_time) {
1582  result = move_lease_to_inactive(pool, tmp,
1583  FTS_EXPIRED);
1584  if (result == ISC_R_SUCCESS) {
1585  iasubopt_reference(leasep, tmp, MDL);
1586  }
1587  return result;
1588  }
1589  }
1590  return ISC_R_SUCCESS;
1591 }
1592 
1593 
1594 /*
1595  * For a declined lease, leave it on the "active" pool, but mark
1596  * it as declined. Give it an infinite (well, really long) life.
1597  */
1598 isc_result_t
1600  isc_result_t result;
1601 
1602  if ((lease->state != FTS_ACTIVE) &&
1603  (lease->state != FTS_ABANDONED)) {
1604  result = move_lease_to_active(pool, lease);
1605  if (result != ISC_R_SUCCESS) {
1606  return result;
1607  }
1608  }
1610 
1611  pool->num_abandoned++;
1612  if (pool->ipv6_pond)
1613  pool->ipv6_pond->num_abandoned++;
1614 
1615  lease->hard_lifetime_end_time = MAX_TIME;
1616  isc_heap_decreased(pool->active_timeouts, lease->active_index);
1617  return ISC_R_SUCCESS;
1618 }
1619 
1620 /*
1621  * Put the returned lease on our inactive pool.
1622  */
1623 isc_result_t
1625  if (lease->state == FTS_ACTIVE) {
1626  return move_lease_to_inactive(pool, lease, FTS_RELEASED);
1627  } else {
1628  return ISC_R_SUCCESS;
1629  }
1630 }
1631 
1632 /*
1633  * Create a prefix by hashing the input, and using that for
1634  * the part subject to allocation.
1635  */
1636 void
1637 build_prefix6(struct in6_addr *pref,
1638  const struct in6_addr *net_start_pref,
1639  int pool_bits, int pref_bits,
1640  const struct data_string *input) {
1641  isc_md5_t ctx;
1642  int net_bytes;
1643  int i;
1644  char *str;
1645  const char *net_str;
1646 
1647  /*
1648  * Use MD5 to get a nice 128 bit hash of the input.
1649  * Yes, we know MD5 isn't cryptographically sound.
1650  * No, we don't care.
1651  */
1652  isc_md5_init(&ctx);
1653  isc_md5_update(&ctx, input->data, input->len);
1654  isc_md5_final(&ctx, (unsigned char *)pref);
1655 
1656  /*
1657  * Copy the network bits over.
1658  */
1659  str = (char *)pref;
1660  net_str = (const char *)net_start_pref;
1661  net_bytes = pool_bits / 8;
1662  for (i = 0; i < net_bytes; i++) {
1663  str[i] = net_str[i];
1664  }
1665  i = net_bytes;
1666  switch (pool_bits % 8) {
1667  case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
1668  case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
1669  case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break;
1670  case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break;
1671  case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break;
1672  case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break;
1673  case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break;
1674  }
1675  /*
1676  * Zero the remaining bits.
1677  */
1678  net_bytes = pref_bits / 8;
1679  for (i=net_bytes+1; i<16; i++) {
1680  str[i] = 0;
1681  }
1682  i = net_bytes;
1683  switch (pref_bits % 8) {
1684  case 0: str[i] &= 0; break;
1685  case 1: str[i] &= 0x80; break;
1686  case 2: str[i] &= 0xC0; break;
1687  case 3: str[i] &= 0xE0; break;
1688  case 4: str[i] &= 0xF0; break;
1689  case 5: str[i] &= 0xF8; break;
1690  case 6: str[i] &= 0xFC; break;
1691  case 7: str[i] &= 0xFE; break;
1692  }
1693 }
1694 
1695 /*
1696  * Create a lease for the given prefix and client duid.
1697  *
1698  * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
1699  * initialized to NULL
1700  *
1701  * Right now we simply hash the DUID, and if we get a collision, we hash
1702  * again until we find a free prefix. We try this a fixed number of times,
1703  * to avoid getting stuck in a loop (this is important on small pools
1704  * where we can run out of space).
1705  *
1706  * We return the number of attempts that it took to find an available
1707  * prefix. This tells callers when a pool is are filling up, as
1708  * well as an indication of how full the pool is; statistically the
1709  * more full a pool is the more attempts must be made before finding
1710  * a free prefix. Realistically this will only happen in very full
1711  * pools.
1712  *
1713  * We probably want different algorithms depending on the network size, in
1714  * the long term.
1715  */
1716 isc_result_t
1717 create_prefix6(struct ipv6_pool *pool, struct iasubopt **pref,
1718  unsigned int *attempts,
1719  const struct data_string *uid,
1720  time_t soft_lifetime_end_time) {
1721  struct data_string ds;
1722  struct in6_addr tmp;
1723  struct iasubopt *test_iapref;
1724  struct data_string new_ds;
1725  struct iasubopt *iapref;
1726  isc_result_t result;
1727 
1728  /*
1729  * Use the UID as our initial seed for the hash
1730  */
1731  memset(&ds, 0, sizeof(ds));
1732  data_string_copy(&ds, (struct data_string *)uid, MDL);
1733 
1734  *attempts = 0;
1735  for (;;) {
1736  /*
1737  * Give up at some point.
1738  */
1739  if (++(*attempts) > 10) {
1740  data_string_forget(&ds, MDL);
1741  return ISC_R_NORESOURCES;
1742  }
1743 
1744  /*
1745  * Build a prefix
1746  */
1747  build_prefix6(&tmp, &pool->start_addr,
1748  pool->bits, pool->units, &ds);
1749 
1750  /*
1751  * If this prefix is not in use, we're happy with it
1752  */
1753  test_iapref = NULL;
1754  if (iasubopt_hash_lookup(&test_iapref, pool->leases,
1755  &tmp, sizeof(tmp), MDL) == 0) {
1756  break;
1757  }
1758  iasubopt_dereference(&test_iapref, MDL);
1759 
1760  /*
1761  * Otherwise, we create a new input, adding the prefix
1762  */
1763  memset(&new_ds, 0, sizeof(new_ds));
1764  new_ds.len = ds.len + sizeof(tmp);
1765  if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) {
1766  data_string_forget(&ds, MDL);
1767  return ISC_R_NOMEMORY;
1768  }
1769  new_ds.data = new_ds.buffer->data;
1770  memcpy(new_ds.buffer->data, ds.data, ds.len);
1771  memcpy(new_ds.buffer->data + ds.len, &tmp, sizeof(tmp));
1772  data_string_forget(&ds, MDL);
1773  data_string_copy(&ds, &new_ds, MDL);
1774  data_string_forget(&new_ds, MDL);
1775  }
1776 
1777  data_string_forget(&ds, MDL);
1778 
1779  /*
1780  * We're happy with the prefix, create an IAPREFIX
1781  * to hold it.
1782  */
1783  iapref = NULL;
1784  result = iasubopt_allocate(&iapref, MDL);
1785  if (result != ISC_R_SUCCESS) {
1786  return result;
1787  }
1788  iapref->plen = (u_int8_t)pool->units;
1789  memcpy(&iapref->addr, &tmp, sizeof(iapref->addr));
1790 
1791  /*
1792  * Add the prefix to the pool (note state is free, not active?!).
1793  */
1794  result = add_lease6(pool, iapref, soft_lifetime_end_time);
1795  if (result == ISC_R_SUCCESS) {
1796  iasubopt_reference(pref, iapref, MDL);
1797  }
1798  iasubopt_dereference(&iapref, MDL);
1799  return result;
1800 }
1801 
1802 /*
1803  * Determine if a prefix is present in a pool or not.
1804  */
1805 isc_boolean_t
1807  const struct in6_addr *pref, u_int8_t plen) {
1808  struct iasubopt *test_iapref;
1809 
1810  if ((int)plen != pool->units)
1811  return ISC_FALSE;
1812 
1813  test_iapref = NULL;
1814  if (iasubopt_hash_lookup(&test_iapref, pool->leases,
1815  (void *)pref, sizeof(*pref), MDL)) {
1816  iasubopt_dereference(&test_iapref, MDL);
1817  return ISC_TRUE;
1818  } else {
1819  return ISC_FALSE;
1820  }
1821 }
1822 
1823 /*
1824  * Mark an IPv6 address/prefix as unavailable from a pool.
1825  *
1826  * This is used for host entries and the addresses of the server itself.
1827  */
1828 isc_result_t
1829 mark_lease_unavailable(struct ipv6_pool *pool, const struct in6_addr *addr) {
1830  struct iasubopt *dummy_iasubopt;
1831  isc_result_t result;
1832 
1833  dummy_iasubopt = NULL;
1834  result = iasubopt_allocate(&dummy_iasubopt, MDL);
1835  if (result == ISC_R_SUCCESS) {
1836  dummy_iasubopt->addr = *addr;
1837  iasubopt_hash_add(pool->leases, &dummy_iasubopt->addr,
1838  sizeof(*addr), dummy_iasubopt, MDL);
1839  }
1840  return result;
1841 }
1842 
1843 /*
1844  * Add a pool.
1845  */
1846 isc_result_t
1848  struct ipv6_pool **new_pools;
1849 
1850  new_pools = dmalloc(sizeof(struct ipv6_pool *) * (num_pools+1), MDL);
1851  if (new_pools == NULL) {
1852  return ISC_R_NOMEMORY;
1853  }
1854 
1855  if (num_pools > 0) {
1856  memcpy(new_pools, pools,
1857  sizeof(struct ipv6_pool *) * num_pools);
1858  dfree(pools, MDL);
1859  }
1860  pools = new_pools;
1861 
1862  pools[num_pools] = NULL;
1864  num_pools++;
1865  return ISC_R_SUCCESS;
1866 }
1867 
1868 static void
1869 cleanup_old_expired(struct ipv6_pool *pool) {
1870  struct iasubopt *tmp;
1871  struct ia_xx *ia;
1872  struct ia_xx *ia_active;
1873  unsigned char *tmpd;
1874  time_t timeout;
1875 
1876  while (pool->num_inactive > 0) {
1877  tmp = (struct iasubopt *)
1878  isc_heap_element(pool->inactive_timeouts, 1);
1879  if (tmp->hard_lifetime_end_time != 0) {
1882  } else {
1884  }
1885  if (cur_time < timeout) {
1886  break;
1887  }
1888 
1889  isc_heap_delete(pool->inactive_timeouts, tmp->inactive_index);
1890  pool->num_inactive--;
1891 
1892  if (tmp->ia != NULL) {
1893  /*
1894  * Check to see if this IA is in an active list,
1895  * but has no remaining resources. If so, remove it
1896  * from the active list.
1897  */
1898  ia = NULL;
1899  ia_reference(&ia, tmp->ia, MDL);
1900  ia_remove_iasubopt(ia, tmp, MDL);
1901  ia_active = NULL;
1902  tmpd = (unsigned char *)ia->iaid_duid.data;
1903  if ((ia->ia_type == D6O_IA_NA) &&
1904  (ia->num_iasubopt <= 0) &&
1905  (ia_hash_lookup(&ia_active, ia_na_active, tmpd,
1906  ia->iaid_duid.len, MDL) == 0) &&
1907  (ia_active == ia)) {
1908  ia_hash_delete(ia_na_active, tmpd,
1909  ia->iaid_duid.len, MDL);
1910  }
1911  if ((ia->ia_type == D6O_IA_TA) &&
1912  (ia->num_iasubopt <= 0) &&
1913  (ia_hash_lookup(&ia_active, ia_ta_active, tmpd,
1914  ia->iaid_duid.len, MDL) == 0) &&
1915  (ia_active == ia)) {
1916  ia_hash_delete(ia_ta_active, tmpd,
1917  ia->iaid_duid.len, MDL);
1918  }
1919  if ((ia->ia_type == D6O_IA_PD) &&
1920  (ia->num_iasubopt <= 0) &&
1921  (ia_hash_lookup(&ia_active, ia_pd_active, tmpd,
1922  ia->iaid_duid.len, MDL) == 0) &&
1923  (ia_active == ia)) {
1924  ia_hash_delete(ia_pd_active, tmpd,
1925  ia->iaid_duid.len, MDL);
1926  }
1927  ia_dereference(&ia, MDL);
1928  }
1929  iasubopt_dereference(&tmp, MDL);
1930  }
1931 }
1932 
1933 static void
1934 lease_timeout_support(void *vpool) {
1935  struct ipv6_pool *pool;
1936  struct iasubopt *lease;
1937 
1938  pool = (struct ipv6_pool *)vpool;
1939  for (;;) {
1940  /*
1941  * Get the next lease scheduled to expire.
1942  *
1943  * Note that if there are no leases in the pool,
1944  * expire_lease6() will return ISC_R_SUCCESS with
1945  * a NULL lease.
1946  *
1947  * expire_lease6() will call move_lease_to_inactive() which
1948  * calls ddns_removals() do we want that on the standard
1949  * expiration timer or a special 'depref' timer? Original
1950  * query from DH, moved here by SAR.
1951  */
1952  lease = NULL;
1953  if (expire_lease6(&lease, pool, cur_time) != ISC_R_SUCCESS) {
1954  break;
1955  }
1956  if (lease == NULL) {
1957  break;
1958  }
1959 
1960  write_ia(lease->ia);
1961 
1963  }
1964 
1965  /*
1966  * If appropriate commit and rotate the lease file
1967  * As commit_leases_timed() checks to see if we've done any writes
1968  * we don't bother tracking if this function called write _ia
1969  */
1970  (void) commit_leases_timed();
1971 
1972  /*
1973  * Do some cleanup of our expired leases.
1974  */
1975  cleanup_old_expired(pool);
1976 
1977  /*
1978  * Schedule next round of expirations.
1979  */
1981 }
1982 
1983 /*
1984  * For a given pool, add a timer that will remove the next
1985  * lease to expire.
1986  */
1987 void
1989  struct iasubopt *tmp;
1990  time_t timeout;
1991  time_t next_timeout;
1992  struct timeval tv;
1993 
1994  next_timeout = MAX_TIME;
1995 
1996  if (pool->num_active > 0) {
1997  tmp = (struct iasubopt *)
1998  isc_heap_element(pool->active_timeouts, 1);
1999  if (tmp->hard_lifetime_end_time < next_timeout) {
2000  next_timeout = tmp->hard_lifetime_end_time + 1;
2001  }
2002  }
2003 
2004  if (pool->num_inactive > 0) {
2005  tmp = (struct iasubopt *)
2006  isc_heap_element(pool->inactive_timeouts, 1);
2007  if (tmp->hard_lifetime_end_time != 0) {
2010  } else {
2011  timeout = tmp->soft_lifetime_end_time + 1;
2012  }
2013  if (timeout < next_timeout) {
2014  next_timeout = timeout;
2015  }
2016  }
2017 
2018  if (next_timeout < MAX_TIME) {
2019  tv.tv_sec = next_timeout;
2020  tv.tv_usec = 0;
2021  add_timeout(&tv, lease_timeout_support, pool,
2024  }
2025 }
2026 
2027 /*
2028  * Schedule timeouts across all pools.
2029  */
2030 void
2032  int i;
2033 
2034  for (i=0; i<num_pools; i++) {
2036  }
2037 }
2038 
2039 /*
2040  * Given an address and the length of the network mask, return
2041  * only the network portion.
2042  *
2043  * Examples:
2044  *
2045  * "fe80::216:6fff:fe49:7d9b", length 64 = "fe80::"
2046  * "2001:888:1936:2:216:6fff:fe49:7d9b", length 48 = "2001:888:1936::"
2047  */
2048 static void
2049 ipv6_network_portion(struct in6_addr *result,
2050  const struct in6_addr *addr, int bits) {
2051  unsigned char *addrp;
2052  int mask_bits;
2053  int bytes;
2054  int extra_bits;
2055  int i;
2056 
2057  static const unsigned char bitmasks[] = {
2058  0x00, 0xFE, 0xFC, 0xF8,
2059  0xF0, 0xE0, 0xC0, 0x80,
2060  };
2061 
2062  /*
2063  * Sanity check our bits. ;)
2064  */
2065  if ((bits < 0) || (bits > 128)) {
2066  log_fatal("ipv6_network_portion: bits %d not between 0 and 128",
2067  bits);
2068  }
2069 
2070  /*
2071  * Copy our address portion.
2072  */
2073  *result = *addr;
2074  addrp = ((unsigned char *)result) + 15;
2075 
2076  /*
2077  * Zero out masked portion.
2078  */
2079  mask_bits = 128 - bits;
2080  bytes = mask_bits / 8;
2081  extra_bits = mask_bits % 8;
2082 
2083  for (i=0; i<bytes; i++) {
2084  *addrp = 0;
2085  addrp--;
2086  }
2087  if (extra_bits) {
2088  *addrp &= bitmasks[extra_bits];
2089  }
2090 }
2091 
2092 /*
2093  * Determine if the given address/prefix is in the pool.
2094  */
2095 isc_boolean_t
2096 ipv6_in_pool(const struct in6_addr *addr, const struct ipv6_pool *pool) {
2097  struct in6_addr tmp;
2098 
2099  ipv6_network_portion(&tmp, addr, pool->bits);
2100  if (memcmp(&tmp, &pool->start_addr, sizeof(tmp)) == 0) {
2101  return ISC_TRUE;
2102  } else {
2103  return ISC_FALSE;
2104  }
2105 }
2106 
2107 /*
2108  * Find the pool that contains the given address.
2109  *
2110  * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
2111  * initialized to NULL
2112  */
2113 isc_result_t
2114 find_ipv6_pool(struct ipv6_pool **pool, u_int16_t type,
2115  const struct in6_addr *addr) {
2116  int i;
2117 
2118  if (pool == NULL) {
2119  log_error("%s(%d): NULL pointer reference", MDL);
2120  return DHCP_R_INVALIDARG;
2121  }
2122  if (*pool != NULL) {
2123  log_error("%s(%d): non-NULL pointer", MDL);
2124  return DHCP_R_INVALIDARG;
2125  }
2126 
2127  for (i=0; i<num_pools; i++) {
2128  if (pools[i]->pool_type != type)
2129  continue;
2130  if (ipv6_in_pool(addr, pools[i])) {
2132  return ISC_R_SUCCESS;
2133  }
2134  }
2135  return ISC_R_NOTFOUND;
2136 }
2137 
2138 /*
2139  * Helper function for the various functions that act across all
2140  * pools.
2141  */
2142 static isc_result_t
2143 change_leases(struct ia_xx *ia,
2144  isc_result_t (*change_func)(struct ipv6_pool *,
2145  struct iasubopt *)) {
2146  isc_result_t retval;
2147  isc_result_t renew_retval;
2148  struct ipv6_pool *pool;
2149  struct in6_addr *addr;
2150  int i;
2151 
2152  retval = ISC_R_SUCCESS;
2153  for (i=0; i<ia->num_iasubopt; i++) {
2154  pool = NULL;
2155  addr = &ia->iasubopt[i]->addr;
2156  if (find_ipv6_pool(&pool, ia->ia_type,
2157  addr) == ISC_R_SUCCESS) {
2158  renew_retval = change_func(pool, ia->iasubopt[i]);
2159  if (renew_retval != ISC_R_SUCCESS) {
2160  retval = renew_retval;
2161  }
2162  }
2163  /* XXXsk: should we warn if we don't find a pool? */
2164  }
2165  return retval;
2166 }
2167 
2168 /*
2169  * Renew all leases in an IA from all pools.
2170  *
2171  * The new lifetime should be in the soft_lifetime_end_time
2172  * and will be moved to hard_lifetime_end_time by renew_lease6.
2173  */
2174 isc_result_t
2175 renew_leases(struct ia_xx *ia) {
2176  return change_leases(ia, renew_lease6);
2177 }
2178 
2179 /*
2180  * Release all leases in an IA from all pools.
2181  */
2182 isc_result_t
2183 release_leases(struct ia_xx *ia) {
2184  return change_leases(ia, release_lease6);
2185 }
2186 
2187 /*
2188  * Decline all leases in an IA from all pools.
2189  */
2190 isc_result_t
2191 decline_leases(struct ia_xx *ia) {
2192  return change_leases(ia, decline_lease6);
2193 }
2194 
2195 #ifdef DHCPv6
2196 /*
2197  * Helper function to output leases.
2198  */
2199 static int write_error;
2200 
2201 static isc_result_t
2202 write_ia_leases(const void *name, unsigned len, void *value) {
2203  struct ia_xx *ia = (struct ia_xx *)value;
2204 
2205  if (!write_error) {
2206  if (!write_ia(ia)) {
2207  write_error = 1;
2208  }
2209  }
2210  return ISC_R_SUCCESS;
2211 }
2212 
2213 /*
2214  * Write all DHCPv6 information.
2215  */
2216 int
2217 write_leases6(void) {
2218  int nas, tas, pds;
2219 
2220  write_error = 0;
2222  nas = ia_hash_foreach(ia_na_active, write_ia_leases);
2223  if (write_error) {
2224  return 0;
2225  }
2226  tas = ia_hash_foreach(ia_ta_active, write_ia_leases);
2227  if (write_error) {
2228  return 0;
2229  }
2230  pds = ia_hash_foreach(ia_pd_active, write_ia_leases);
2231  if (write_error) {
2232  return 0;
2233  }
2234 
2235  log_info("Wrote %d NA, %d TA, %d PD leases to lease file.",
2236  nas, tas, pds);
2237  return 1;
2238 }
2239 #endif /* DHCPv6 */
2240 
2241 static isc_result_t
2242 mark_hosts_unavailable_support(const void *name, unsigned len, void *value) {
2243  struct host_decl *h;
2244  struct data_string fixed_addr;
2245  struct in6_addr addr;
2246  struct ipv6_pool *p;
2247 
2248  h = (struct host_decl *)value;
2249 
2250  /*
2251  * If the host has no address, we don't need to mark anything.
2252  */
2253  if (h->fixed_addr == NULL) {
2254  return ISC_R_SUCCESS;
2255  }
2256 
2257  /*
2258  * Evaluate the fixed address.
2259  */
2260  memset(&fixed_addr, 0, sizeof(fixed_addr));
2261  if (!evaluate_option_cache(&fixed_addr, NULL, NULL, NULL, NULL, NULL,
2262  &global_scope, h->fixed_addr, MDL)) {
2263  log_error("mark_hosts_unavailable: "
2264  "error evaluating host address.");
2265  return ISC_R_SUCCESS;
2266  }
2267  if (fixed_addr.len != 16) {
2268  log_error("mark_hosts_unavailable: "
2269  "host address is not 128 bits.");
2270  return ISC_R_SUCCESS;
2271  }
2272  memcpy(&addr, fixed_addr.data, 16);
2274 
2275  /*
2276  * Find the pool holding this host, and mark the address.
2277  * (I suppose it is arguably valid to have a host that does not
2278  * sit in any pool.)
2279  */
2280  p = NULL;
2281  if (find_ipv6_pool(&p, D6O_IA_NA, &addr) == ISC_R_SUCCESS) {
2282  mark_lease_unavailable(p, &addr);
2284  }
2285  if (find_ipv6_pool(&p, D6O_IA_TA, &addr) == ISC_R_SUCCESS) {
2286  mark_lease_unavailable(p, &addr);
2288  }
2289 
2290  return ISC_R_SUCCESS;
2291 }
2292 
2293 void
2295  hash_foreach(host_name_hash, mark_hosts_unavailable_support);
2296 }
2297 
2298 static isc_result_t
2299 mark_phosts_unavailable_support(const void *name, unsigned len, void *value) {
2300  struct host_decl *h;
2301  struct iaddrcidrnetlist *l;
2302  struct in6_addr pref;
2303  struct ipv6_pool *p;
2304 
2305  h = (struct host_decl *)value;
2306 
2307  /*
2308  * If the host has no prefix, we don't need to mark anything.
2309  */
2310  if (h->fixed_prefix == NULL) {
2311  return ISC_R_SUCCESS;
2312  }
2313 
2314  /*
2315  * Get the fixed prefixes.
2316  */
2317  for (l = h->fixed_prefix; l != NULL; l = l->next) {
2318  if (l->cidrnet.lo_addr.len != 16) {
2319  continue;
2320  }
2321  memcpy(&pref, l->cidrnet.lo_addr.iabuf, 16);
2322 
2323  /*
2324  * Find the pool holding this host, and mark the prefix.
2325  * (I suppose it is arguably valid to have a host that does not
2326  * sit in any pool.)
2327  */
2328  p = NULL;
2329  if (find_ipv6_pool(&p, D6O_IA_PD, &pref) != ISC_R_SUCCESS) {
2330  continue;
2331  }
2332  if (l->cidrnet.bits != p->units) {
2334  continue;
2335  }
2336  mark_lease_unavailable(p, &pref);
2338  }
2339 
2340  return ISC_R_SUCCESS;
2341 }
2342 
2343 void
2345  hash_foreach(host_name_hash, mark_phosts_unavailable_support);
2346 }
2347 
2348 void
2350  struct interface_info *ip;
2351  int i;
2352  struct ipv6_pool *p;
2353 
2354  ip = interfaces;
2355  while (ip != NULL) {
2356  for (i=0; i<ip->v6address_count; i++) {
2357  p = NULL;
2358  if (find_ipv6_pool(&p, D6O_IA_NA, &ip->v6addresses[i])
2359  == ISC_R_SUCCESS) {
2361  &ip->v6addresses[i]);
2363  }
2364  if (find_ipv6_pool(&p, D6O_IA_TA, &ip->v6addresses[i])
2365  == ISC_R_SUCCESS) {
2367  &ip->v6addresses[i]);
2369  }
2370  }
2371  ip = ip->next;
2372  }
2373 }
2374 
2392 isc_result_t
2393 ipv6_pond_allocate(struct ipv6_pond **pond, const char *file, int line) {
2394  struct ipv6_pond *tmp;
2395 
2396  if (pond == NULL) {
2397  log_error("%s(%d): NULL pointer reference", file, line);
2398  return DHCP_R_INVALIDARG;
2399  }
2400  if (*pond != NULL) {
2401  log_error("%s(%d): non-NULL pointer", file, line);
2402  return DHCP_R_INVALIDARG;
2403  }
2404 
2405  tmp = dmalloc(sizeof(*tmp), file, line);
2406  if (tmp == NULL) {
2407  return ISC_R_NOMEMORY;
2408  }
2409 
2410  tmp->refcnt = 1;
2411 
2412  *pond = tmp;
2413  return ISC_R_SUCCESS;
2414 }
2415 
2435 isc_result_t
2436 ipv6_pond_reference(struct ipv6_pond **pond, struct ipv6_pond *src,
2437  const char *file, int line) {
2438  if (pond == NULL) {
2439  log_error("%s(%d): NULL pointer reference", file, line);
2440  return DHCP_R_INVALIDARG;
2441  }
2442  if (*pond != NULL) {
2443  log_error("%s(%d): non-NULL pointer", file, line);
2444  return DHCP_R_INVALIDARG;
2445  }
2446  if (src == NULL) {
2447  log_error("%s(%d): NULL pointer reference", file, line);
2448  return DHCP_R_INVALIDARG;
2449  }
2450  *pond = src;
2451  src->refcnt++;
2452  return ISC_R_SUCCESS;
2453 }
2454 
2475 isc_result_t
2476 ipv6_pond_dereference(struct ipv6_pond **pond, const char *file, int line) {
2477  struct ipv6_pond *tmp;
2478 
2479  if ((pond == NULL) || (*pond == NULL)) {
2480  log_error("%s(%d): NULL pointer", file, line);
2481  return DHCP_R_INVALIDARG;
2482  }
2483 
2484  tmp = *pond;
2485  *pond = NULL;
2486 
2487  tmp->refcnt--;
2488  if (tmp->refcnt < 0) {
2489  log_error("%s(%d): negative refcnt", file, line);
2490  tmp->refcnt = 0;
2491  }
2492  if (tmp->refcnt == 0) {
2493  dfree(tmp, file, line);
2494  }
2495 
2496  return ISC_R_SUCCESS;
2497 }
2498 
2499 /*
2500  * Emits a log for each pond that has been flagged as being a "jumbo range"
2501  * A pond is considered a "jumbo range" when the total number of elements
2502  * exceeds the maximum value of POND_TRACK_MAX (currently maximum value
2503  * that can be stored by ipv6_pond.num_total). Since we disable threshold
2504  * logging for jumbo ranges, we need to report this to the user. This
2505  * function allows us to report jumbo ponds after config parsing, so the
2506  * logs can be seen both on the console (-T) and the log facility (i.e syslog).
2507  *
2508  * Note, threshold logging is done at the pond level, so we need emit a list
2509  * of the addresses ranges of the pools in the pond affected.
2510  */
2511 void
2513  struct shared_network* s;
2514  char log_buf[1084];
2515 
2516  /* Loop thru all the networks looking for jumbo range ponds */
2517  for (s = shared_networks; s; s = s -> next) {
2518  struct ipv6_pond* pond = s->ipv6_pond;
2519  while (pond) {
2520  /* if its a jumbo and has pools(sanity check) */
2521  if (pond->jumbo_range == 1 && (pond->ipv6_pools)) {
2522  struct ipv6_pool* pool;
2523  char *bufptr = log_buf;
2524  size_t space_left = sizeof(log_buf) - 1;
2525  int i = 0;
2526  int used = 0;
2527 
2528  /* Build list containing the start-address/CIDR
2529  * of each pool */
2530  *bufptr = '\0';
2531  while ((pool = pond->ipv6_pools[i++]) &&
2532  (space_left > (INET6_ADDRSTRLEN + 6))) {
2533  /* more than one so add a comma */
2534  if (i > 1) {
2535  *bufptr++ = ',';
2536  *bufptr++ = ' ';
2537  *bufptr = '\0';
2538  space_left -= 2;
2539  }
2540 
2541  /* add the address */
2542  inet_ntop(AF_INET6, &pool->start_addr,
2543  bufptr, INET6_ADDRSTRLEN);
2544 
2545  used = strlen(bufptr);
2546  bufptr += used;
2547  space_left -= used;
2548 
2549  /* add the CIDR */
2550  sprintf (bufptr, "/%d",pool->bits);
2551  used = strlen(bufptr);
2552  bufptr += used;
2553  space_left -= used;
2554  *bufptr = '\0';
2555  }
2556 
2557  log_info("Threshold logging disabled for shared"
2558  " subnet of ranges: %s", log_buf);
2559  }
2560  pond = pond->next;
2561  }
2562  }
2563 }
2564 
2565 
2566 /*
2567  * \brief Tests that 16-bit hardware type is less than 256
2568  *
2569  * XXX: DHCPv6 gives a 16-bit field for the htype. DHCPv4 gives an
2570  * 8-bit field. To change the semantics of the generic 'hardware'
2571  * structure, we would have to adjust many DHCPv4 sources (from
2572  * interface to DHCPv4 lease code), and we would have to update the
2573  * 'hardware' config directive (probably being reverse compatible and
2574  * providing a new upgrade/replacement primitive). This is a little
2575  * too much to change for now. Hopefully we will revisit this before
2576  * hardware types exceeding 8 bits are assigned.
2577  *
2578  * Uses a static variable to limit log occurence to once per startup
2579  *
2580  * \param htype hardware type value to test
2581  *
2582  * \return returns 0 if the value is too large
2583  *
2584 */
2585 int htype_bounds_check(uint16_t htype) {
2586  static int log_once = 0;
2587 
2588  if (htype & 0xFF00) {
2589  if (!log_once) {
2590  log_error("Attention: At least one client advertises a "
2591  "hardware type of %d, which exceeds the software "
2592  "limitation of 255.", htype);
2593  log_once = 1;
2594  }
2595 
2596  return(0);
2597  }
2598 
2599  return(1);
2600 }
2601 
2627  struct packet *packet,
2628  struct option_state *opt_state,
2629  const char *file, int line) {
2630  int found = 0;
2631  int htype;
2632  int hlen;
2633 
2634  /* For directly connected clients, use packet:haddr if populated */
2635  if (packet->dhcpv6_container_packet == NULL) {
2636  if (packet->haddr) {
2637  htype = packet->haddr->hbuf[0];
2638  hlen = packet->haddr->hlen - 1,
2639  log_debug("find_hosts_by_haddr6: using packet->haddr,"
2640  " type: %d, len: %d", htype, hlen);
2641  found = find_hosts_by_haddr (hp, htype,
2642  &packet->haddr->hbuf[1],
2643  hlen, MDL);
2644  }
2645  } else {
2646  /* The first container packet is the from the relay directly
2647  * connected to the client. Per RFC 6939, that is only relay
2648  * that may supply the client linklayer address option. */
2649  struct packet *relay_packet = packet->dhcpv6_container_packet;
2650  struct option_state *relay_state = relay_packet->options;
2651  struct data_string rel_addr;
2652  struct option_cache *oc;
2653 
2654  /* Look for the option in the first relay packet */
2655  oc = lookup_option(&dhcpv6_universe, relay_state,
2657  if (!oc) {
2658  /* Not there, so bail */
2659  return (0);
2660  }
2661 
2662  /* The option is present, fetch the address data */
2663  memset(&rel_addr, 0, sizeof(rel_addr));
2664  if (!evaluate_option_cache(&rel_addr, relay_packet, NULL, NULL,
2665  relay_state, NULL, &global_scope,
2666  oc, MDL)) {
2667  log_error("find_hosts_by_add6:"
2668  "Error evaluating option cache");
2669  return (0);
2670  }
2671 
2672  /* The relay address data should be:
2673  * byte 0 - 1 = hardware type
2674  * bytes 2 - hlen = hardware address
2675  * where hlen ( hardware address len) is option data len - 2 */
2676  hlen = rel_addr.len - 2;
2677  if (hlen > 0 && hlen <= HARDWARE_ADDR_LEN) {
2678  htype = getUShort(rel_addr.data);
2679  if (htype_bounds_check(htype)) {
2680  /* Looks valid, let's search with it */
2681  log_debug("find_hosts_by_haddr6:"
2682  "using relayed haddr"
2683  " type: %d, len: %d", htype, hlen);
2684  found = find_hosts_by_haddr (hp, htype,
2685  &rel_addr.data[2],
2686  hlen, MDL);
2687  }
2688  }
2689 
2690  data_string_forget(&rel_addr, MDL);
2691  }
2692 
2693  return (found);
2694 }
2695 
2696 /*
2697  * find_host_by_duid_chaddr() synthesizes a DHCPv4-like 'hardware'
2698  * parameter from a DHCPv6 supplied DUID (client-identifier option),
2699  * and may seek to use client or relay supplied hardware addresses.
2700  */
2701 int
2703  const struct data_string *client_id) {
2704  int htype, hlen;
2705  const unsigned char *chaddr;
2706 
2707  /*
2708  * The DUID-LL and DUID-LLT must have a 2-byte DUID type and 2-byte
2709  * htype.
2710  */
2711  if (client_id->len < 4)
2712  return 0;
2713 
2714  /*
2715  * The third and fourth octets of the DUID-LL and DUID-LLT
2716  * is the hardware type, but in 16 bits.
2717  */
2718  htype = getUShort(client_id->data + 2);
2719  hlen = 0;
2720  chaddr = NULL;
2721 
2722  /* The first two octets of the DUID identify the type. */
2723  switch(getUShort(client_id->data)) {
2724  case DUID_LLT:
2725  if (client_id->len > 8) {
2726  hlen = client_id->len - 8;
2727  chaddr = client_id->data + 8;
2728  }
2729  break;
2730 
2731  case DUID_LL:
2732  /*
2733  * Note that client_id->len must be greater than or equal
2734  * to four to get to this point in the function.
2735  */
2736  hlen = client_id->len - 4;
2737  chaddr = client_id->data + 4;
2738  break;
2739 
2740  default:
2741  break;
2742  }
2743 
2744  if ((hlen == 0) || (hlen > HARDWARE_ADDR_LEN) ||
2745  !htype_bounds_check(htype)) {
2746  return (0);
2747  }
2748 
2749  return find_hosts_by_haddr(host, htype, chaddr, hlen, MDL);
2750 }
2751 
2752 /*
2753  * \brief Finds a host record that matches the packet, if any
2754  *
2755  * This function centralizes the logic for matching v6 client
2756  * packets to host declarations. We check in the following order
2757  * for matches with:
2758  *
2759  * 1. client_id if specified
2760  * 2. MAC address when explicitly available
2761  * 3. packet option
2762  * 4. synthesized hardware address - this is done last as some
2763  * synthesis methods are not consided to be reliable
2764  *
2765  * \param[out] host - pointer to storage for the located host
2766  * \param packet - inbound client packet
2767  * \param client_id - client identifier (if one)
2768  * \param file - source file
2769  * \param line - source file line number
2770  * \return non-zero if a host is found, zero otherwise
2771 */
2772 int
2773 find_hosts6(struct host_decl** host, struct packet* packet,
2774  const struct data_string* client_id, char* file, int line) {
2775  return (find_hosts_by_uid(host, client_id->data, client_id->len, MDL)
2778  || find_hosts_by_duid_chaddr(host, client_id));
2779 }
2780 
2781 
2782 /* unittest moved to server/tests/mdb6_unittest.c */
#define FTS_ABANDONED
Definition: dhcpd.h:538
struct iaddrcidrnet cidrnet
Definition: inet.h:77
void mark_interfaces_unavailable(void)
Definition: mdb6.c:2349
ia_hash_t * ia_ta_active
int find_hosts_by_haddr6(struct host_decl **hp, struct packet *packet, struct option_state *opt_state, const char *file, int line)
Look for hosts by MAC address if it's available.
Definition: mdb6.c:2626
struct ipv6_pond * next
Definition: dhcpd.h:1713
isc_boolean_t lease6_usable(struct iasubopt *lease)
Check if address is available to a lease.
Definition: mdb6.c:1377
const char int line
Definition: dhcpd.h:3728
isc_result_t mark_lease_unavailable(struct ipv6_pool *pool, const struct in6_addr *addr)
Definition: mdb6.c:1829
struct binding_scope * global_scope
Definition: tree.c:38
isc_boolean_t prefix6_exists(const struct ipv6_pool *pool, const struct in6_addr *pref, u_int8_t plen)
Definition: mdb6.c:1806
void report_jumbo_ranges()
Definition: mdb6.c:2512
struct on_star on_star
Definition: dhcpd.h:580
Definition: dhcpd.h:557
unsigned len
Definition: tree.h:80
int executable_statement_dereference(struct executable_statement **ptr, const char *file, int line)
Definition: execute.c:623
int bits
Definition: inet.h:72
u_int8_t hlen
Definition: dhcpd.h:489
#define FTS_FREE
Definition: dhcpd.h:534
struct shared_network * shared_networks
Definition: mdb.c:33
Definition: dhcpd.h:1647
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:1717
int active_index
Definition: dhcpd.h:1632
int units
Definition: dhcpd.h:1686
int max_iasubopt
Definition: dhcpd.h:1652
struct lease_state * state
Definition: dhcpd.h:625
isc_result_t renew_lease6(struct ipv6_pool *pool, struct iasubopt *lease)
Renew a lease in the pool.
Definition: mdb6.c:1448
int execute_statements(struct binding_value **result, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *out_options, struct binding_scope **scope, struct executable_statement *statements, struct on_star *on_star)
Definition: execute.c:35
isc_result_t ia_make_key(struct data_string *key, u_int32_t iaid, const char *duid, unsigned int duid_len, const char *file, int line)
Definition: mdb6.c:311
struct ipv6_pond * ipv6_pond
Definition: dhcpd.h:1038
isc_result_t iasubopt_dereference(struct iasubopt **iasubopt, const char *file, int line)
Definition: mdb6.c:261
#define MDL
Definition: omapip.h:568
int find_hosts_by_option(struct host_decl **, struct packet *, struct option_state *, const char *, int)
Definition: mdb.c:638
unsigned char iabuf[16]
Definition: inet.h:33
dhcp_context_t dhcp_gbl_ctx
Definition: isclib.c:33
#define DHCP_R_INVALIDARG
Definition: result.h:49
isc_result_t find_ipv6_pool(struct ipv6_pool **pool, u_int16_t type, const struct in6_addr *addr)
Definition: mdb6.c:2114
#define FTS_RELEASED
Definition: dhcpd.h:537
int int int log_debug(const char *,...) __attribute__((__format__(__printf__
void build_prefix6(struct in6_addr *pref, const struct in6_addr *net_start_pref, int pool_bits, int pref_bits, const struct data_string *input)
Definition: mdb6.c:1637
struct executable_statement * on_release
Definition: dhcpd.h:553
isc_result_t ia_dereference(struct ia_xx **ia, const char *file, int line)
Definition: mdb6.c:403
#define D6O_CLIENT_LINKLAYER_ADDR
Definition: dhcp6.h:108
void data_string_forget(struct data_string *data, const char *file, int line)
Definition: alloc.c:1339
isc_result_t ia_add_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt, const char *file, int line)
Definition: mdb6.c:439
struct in6_addr start_addr
Definition: dhcpd.h:1684
struct option_cache * fixed_addr
Definition: dhcpd.h:956
int find_hosts_by_duid_chaddr(struct host_decl **host, const struct data_string *client_id)
Definition: mdb6.c:2702
#define DUID_LL
Definition: dhcp6.h:167
int log_error(const char *,...) __attribute__((__format__(__printf__
isc_result_t release_leases(struct ia_xx *ia)
Definition: mdb6.c:2183
#define FTS_EXPIRED
Definition: dhcpd.h:536
int binding_scope_dereference(struct binding_scope **ptr, const char *file, int line)
Definition: tree.c:3786
struct on_star on_star
Definition: dhcpd.h:1644
struct binding_scope * scope
Definition: dhcpd.h:1618
void add_timeout(struct timeval *when, void(*)(void *) where, void *what, tvref_t ref, tvunref_t unref)
Definition: dispatch.c:206
void(* tvunref_t)(void *, const char *, int)
Definition: dhcpd.h:1421
void ia_remove_all_lease(struct ia_xx *ia, const char *file, int line)
Definition: mdb6.c:504
unsigned len
Definition: inet.h:32
int find_hosts_by_haddr(struct host_decl **, int, const unsigned char *, unsigned, const char *, int)
Definition: mdb.c:610
int refcnt
Definition: dhcpd.h:1712
isc_result_t ipv6_pool_allocate(struct ipv6_pool **pool, u_int16_t type, const struct in6_addr *start_addr, int bits, int units, const char *file, int line)
Create a new IPv6 lease pool structure.
Definition: mdb6.c:640
#define EXPIRED_IPV6_CLEANUP_TIME
Definition: dhcpd.h:1629
isc_result_t isc_heap_create(isc_heapcompare_t compare, isc_heapindex_t index, unsigned int size_increment, isc_heap_t **heapp)
Create a new heap. The heap is implemented using a space-efficient storage method....
void(* tvref_t)(void *, void *, const char *, int)
Definition: dhcpd.h:1420
struct option_state * options
Definition: dhcpd.h:449
isc_result_t ia_allocate(struct ia_xx **ia, u_int32_t iaid, const char *duid, unsigned int duid_len, const char *file, int line)
Definition: mdb6.c:339
int write_leases6(void)
void log_fatal(const char *,...) __attribute__((__format__(__printf__
isc_result_t create_lease6(struct ipv6_pool *pool, struct iasubopt **addr, unsigned int *attempts, const struct data_string *uid, time_t soft_lifetime_end_time)
Definition: mdb6.c:958
#define D6O_IA_TA
Definition: dhcp6.h:33
isc_mem_t * mctx
Definition: isclib.h:95
isc_boolean_t lease6_exists(const struct ipv6_pool *pool, const struct in6_addr *addr)
Definition: mdb6.c:1349
int inactive_index
Definition: dhcpd.h:1633
void isc_heap_decreased(isc_heap_t *heap, unsigned int index)
Indicates to the heap that an element's priority has decreased. This function MUST be called whenever...
time_t hard_lifetime_end_time
Definition: dhcpd.h:1619
int evaluate_option_cache(struct data_string *result, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct option_cache *oc, const char *file, int line)
Definition: tree.c:2699
host_hash_t * host_name_hash
Definition: mdb.c:36
Definition: dhcpd.h:999
unsigned do_string_hash(const void *, unsigned, unsigned)
Definition: hash.c:268
ia_hash_t * ia_na_active
struct ipv6_pool * ipv6_pool
Definition: dhcpd.h:1624
int buffer_allocate(struct buffer **ptr, unsigned len, const char *file, int line)
Definition: alloc.c:679
isc_result_t ipv6_pond_allocate(struct ipv6_pond **pond, const char *file, int line)
Create a new IPv6 pond structure.
Definition: mdb6.c:2393
Definition: dhcpd.h:405
int write_server_duid(void)
struct iaddrcidrnetlist * next
Definition: inet.h:76
char * name
Definition: dhcpd.h:948
isc_boolean_t ia_equal(const struct ia_xx *a, const struct ia_xx *b)
Definition: mdb6.c:518
u_int8_t plen
Definition: dhcpd.h:1616
struct data_string iaid_duid
Definition: dhcpd.h:1649
#define cur_time
Definition: dhcpd.h:2079
Definition: ip.h:47
int refcnt
Definition: dhcpd.h:1648
u_int32_t getUShort(const unsigned char *)
struct hardware * haddr
Definition: dhcpd.h:435
void dfree(void *, const char *, int)
Definition: alloc.c:145
void isc_heap_foreach(isc_heap_t *heap, isc_heapaction_t action, void *uap)
Iterate over the heap, calling an action for each element. The order of iteration is not sorted.
int bits
Definition: dhcpd.h:1685
int jumbo_range
Definition: dhcpd.h:1730
isc_result_t renew_leases(struct ia_xx *ia)
Definition: mdb6.c:2175
int refcnt
Definition: dhcpd.h:1614
isc_result_t decline_leases(struct ia_xx *ia)
Definition: mdb6.c:2191
struct option_cache * lookup_option(struct universe *universe, struct option_state *options, unsigned code)
Definition: options.c:2449
iasubopt_hash_t * leases
Definition: dhcpd.h:1687
int num_iasubopt
Definition: dhcpd.h:1651
int int log_info(const char *,...) __attribute__((__format__(__printf__
struct ipv6_pool ** ipv6_pools
Definition: dhcpd.h:1722
u_int16_t ia_type
Definition: dhcpd.h:1650
binding_state_t state
Definition: dhcpd.h:1617
void * dmalloc(size_t, const char *, int)
Definition: alloc.c:57
struct interface_info * interfaces
Definition: discover.c:42
int find_hosts_by_uid(struct host_decl **, const unsigned char *, unsigned, const char *, int)
Definition: mdb.c:630
isc_result_t ipv6_pool_dereference(struct ipv6_pool **pool, const char *file, int line)
de-reference an IPv6 pool structure.
Definition: mdb6.c:777
void cleanup(void)
isc_result_t ipv6_pool_reference(struct ipv6_pool **pool, struct ipv6_pool *src, const char *file, int line)
reference an IPv6 pool structure.
Definition: mdb6.c:706
#define DEFAULT_HASH_SIZE
Definition: hash.h:33
ipv6_pool structure
Definition: dhcpd.h:1681
void isc_heap_destroy(isc_heap_t **heapp)
Destroys a heap.
int refcnt
Definition: dhcpd.h:1682
struct iaddrcidrnetlist * fixed_prefix
Definition: dhcpd.h:957
ia_hash_t * ia_pd_active
isc_result_t ddns_removals(struct lease *, struct iasubopt *, struct dhcp_ddns_cb *, isc_boolean_t)
int commit_leases_timed(void)
Definition: db.c:1043
void isc_heap_increased(isc_heap_t *heap, unsigned int index)
Indicates to the heap that an element's priority has increased. This function MUST be called whenever...
void isc_heap_delete(isc_heap_t *heap, unsigned int index)
Deletes an element from a heap, by element index.
int hash_foreach(struct hash_table *, hash_foreach_func)
Definition: hash.c:513
isc_result_t add_lease6(struct ipv6_pool *pool, struct iasubopt *lease, time_t valid_lifetime_end_time)
Definition: mdb6.c:1239
struct universe dhcpv6_universe
Definition: tables.c:343
isc_heap_t * inactive_timeouts
Definition: dhcpd.h:1692
#define D6O_IA_NA
Definition: dhcp6.h:32
isc_result_t iasubopt_reference(struct iasubopt **iasubopt, struct iasubopt *src, const char *file, int line)
Definition: mdb6.c:234
HASH_FUNCTIONS(ia, unsigned char *, struct ia_xx, ia_hash_t, ia_reference, ia_dereference, do_string_hash)
Definition: mdb6.c:180
int find_hosts6(struct host_decl **host, struct packet *packet, const struct data_string *client_id, char *file, int line)
Definition: mdb6.c:2773
unsigned char data[1]
Definition: tree.h:63
isc_heap_t * active_timeouts
Definition: dhcpd.h:1690
isc_result_t decline_lease6(struct ipv6_pool *pool, struct iasubopt *lease)
Definition: mdb6.c:1599
void schedule_lease_timeout(struct ipv6_pool *pool)
Definition: mdb6.c:1988
time_t soft_lifetime_end_time
Definition: dhcpd.h:1620
struct iaddr lo_addr
Definition: inet.h:71
isc_result_t ipv6_pond_dereference(struct ipv6_pond **pond, const char *file, int line)
de-reference an IPv6 pond structure.
Definition: mdb6.c:2476
isc_boolean_t ipv6_in_pool(const struct in6_addr *addr, const struct ipv6_pool *pool)
Definition: mdb6.c:2096
void mark_phosts_unavailable(void)
Definition: mdb6.c:2344
isc_result_t expire_lease6(struct iasubopt **leasep, struct ipv6_pool *pool, time_t now)
Definition: mdb6.c:1565
u_int8_t hbuf[HARDWARE_ADDR_LEN+1]
Definition: dhcpd.h:490
isc_result_t release_lease6(struct ipv6_pool *pool, struct iasubopt *lease)
Definition: mdb6.c:1624
#define MAX_TIME
Definition: dhcpd.h:1598
struct data_string data
Definition: dhcpd.h:390
ipv6_pond structure
Definition: dhcpd.h:1711
#define HARDWARE_ADDR_LEN
Definition: dhcpd.h:483
void * isc_heap_element(isc_heap_t *heap, unsigned int index)
Returns the element for a specific element index.
#define D6O_IA_PD
Definition: dhcp6.h:54
isc_result_t ipv6_pond_reference(struct ipv6_pond **pond, struct ipv6_pond *src, const char *file, int line)
reference an IPv6 pond structure.
Definition: mdb6.c:2436
struct ipv6_pool ** pools
#define DUID_LLT
Definition: dhcp6.h:165
struct iasubopt ** iasubopt
Definition: dhcpd.h:1654
int write_ia(const struct ia_xx *)
Definition: db.c:518
struct ia_xx * ia
Definition: dhcpd.h:1623
struct executable_statement * on_expiry
Definition: dhcpd.h:551
struct shared_network * next
Definition: dhcpd.h:1029
const char * file
Definition: dhcpd.h:3728
isc_result_t ia_reference(struct ia_xx **ia, struct ia_xx *src, const char *file, int line)
Definition: mdb6.c:377
struct in6_addr addr
Definition: dhcpd.h:1615
struct executable_statement * on_commit
Definition: dhcpd.h:552
const unsigned char * data
Definition: tree.h:79
isc_result_t add_ipv6_pool(struct ipv6_pool *pool)
Definition: mdb6.c:1847
struct binding_scope * scope
Definition: dhcpd.h:572
void data_string_copy(struct data_string *dest, const struct data_string *src, const char *file, int line)
Definition: alloc.c:1323
void mark_hosts_unavailable(void)
Definition: mdb6.c:2294
u_int16_t pool_type
Definition: dhcpd.h:1683
isc_result_t isc_heap_insert(isc_heap_t *heap, void *elt)
Inserts a new element into a heap.
int htype_bounds_check(uint16_t htype)
Definition: mdb6.c:2585
void ia_remove_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt, const char *file, int line)
Definition: mdb6.c:476
isc_result_t cleanup_lease6(ia_hash_t *ia_table, struct ipv6_pool *pool, struct iasubopt *lease, struct ia_xx *ia)
Cleans up leases when reading from a lease file.
Definition: mdb6.c:1129
u_int8_t binding_state_t
Definition: dhcpd.h:541
void schedule_all_ipv6_lease_timeouts(void)
Definition: mdb6.c:2031
struct buffer * buffer
Definition: tree.h:78
struct packet * dhcpv6_container_packet
Definition: dhcpd.h:422
#define FTS_ACTIVE
Definition: dhcpd.h:535
int num_pools