1 /* $NetBSD: mdb6.c,v 1.5 2014/07/12 12:09:38 spz Exp $ */ 2 /* 3 * Copyright (C) 2007-2013 by Internet Systems Consortium, Inc. ("ISC") 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/cdefs.h> 19 __RCSID("$NetBSD: mdb6.c,v 1.5 2014/07/12 12:09:38 spz Exp $"); 20 21 /*! 22 * \todo assert() 23 * \todo simplify functions, as pool is now in iaaddr 24 */ 25 26 /*! \file server/mdb6.c 27 * 28 * \page ipv6structures IPv6 Structures Overview 29 * 30 * A brief description of the IPv6 structures as reverse engineered. 31 * 32 * There are four major data structures in the lease configuraion. 33 * 34 * - shared_network - The shared network is the outer enclosing scope for a 35 * network region that shares a broadcast domain. It is 36 * composed of one or more subnets all of which are valid 37 * in the given region. The share network may be 38 * explicitly defined or implicitly created if there is 39 * only a subnet statement. This structrure is shared 40 * with v4. Each shared network statment or naked subnet 41 * will map to one of these structures 42 * 43 * - subnet - The subnet structure mostly specifies the address range 44 * that could be valid in a given region. This structute 45 * doesn't include the addresses that the server can delegate 46 * those are in the ipv6_pool. This structure is also shared 47 * with v4. Each subnet statement will map to one of these 48 * structures. 49 * 50 * - ipv6_pond - The pond structure is a grouping of the address and prefix 51 * information via the pointers to the ipv6_pool and the 52 * allowability of this pool for given clinets via the permit 53 * lists and the valid TIMEs. This is equivilent to the v4 54 * pool structure and would have been named ip6_pool except 55 * that the name was already in use. Generally each pool6 56 * statement will map to one of these structures. In addition 57 * there may be one or for each group of naked range6 and 58 * prefix6 statements within a shared network that share 59 * the same group of statements. 60 * 61 * - ipv6_pool - this contains information about a pool of addresses or prefixes 62 * that the server is using. This includes a hash table that 63 * tracks the active items and a pair of heap tables one for 64 * active items and one for non-active items. The heap tables 65 * are used to determine the next items to be modified due to 66 * timing events (expire mostly). 67 * 68 * The linkages then look like this: 69 * \verbatim 70 *+--------------+ +-------------+ 71 *|Shared Network| | ipv6_pond | 72 *| group | | group | 73 *| | | permit info | 74 *| | | next ----> 75 *| ponds ---->| | 76 *| |<---- shared | 77 *| Subnets | | pools | 78 *+-----|--------+ +------|------+ 79 * | ^ | ^ 80 * | | v | 81 * | | +-----------|-+ 82 * | | | ipv6_pool | | 83 * | | | type | | 84 * | | | ipv6_pond | 85 * | | | | 86 * | | | next ----> 87 * | | | | 88 * | | | subnet | 89 * | | +-----|-------+ 90 * | | | 91 * | | v 92 * | | +-------------+ 93 * | | | subnet | 94 * | +---------- shared | 95 * +----------->| | 96 * | group | 97 * +-------------+ 98 * 99 * The shared network contains a list of all the subnets that are on a broadcast 100 * doamin. These can be used to determine if an address makes sense in a given 101 * domain, but the subnets do not contain the addresses the server can delegate. 102 * Those are stored in the ponds and pools. 103 * 104 * In the simple case to find an acceptable address the server would first find 105 * the shared network the client is on based on either the interface used to 106 * receive the request or the relay agent's information. From the shared 107 * network the server will walk through it's list of ponds. For each pond it 108 * will evaluate the permit information against the (already done) classification. 109 * If it finds an acceptable pond it will then walk through the pools for that 110 * pond. The server first checks the type of the pool (NA, TA and PD) agaisnt the 111 * request and if they match it attemps to find an address within that pool. On 112 * success the address is used, on failure the server steps to the next pool and 113 * if necessary to the next pond. 114 * 115 * When the server is successful in finding an address it will execute any 116 * statements assocaited with the pond, then the subnet, then the shared 117 * network the group field is for in the above picture). 118 * 119 * In configurations that don't include either a shared network or a pool6 120 * statement (or both) the missing pieces are created. 121 * 122 * 123 * There are three major data structuress involved in the lease database: 124 * 125 * - ipv6_pool - see above 126 * - ia_xx - this contains information about a single IA from a request 127 * normally it will contain one pointer to a lease for the client 128 * but it may contain more in some circumstances. There are 3 129 * hash tables to aid in accessing these one each for NA, TA and PD. 130 * - iasubopt - the v6 lease structure. These are created dynamically when 131 * a client asks for something and will eventually be destroyed 132 * if the client doesn't re-ask for that item. A lease has space 133 * for backpointers to the IA and to the pool to which it belongs. 134 * The pool backpointer is always filled, the IA pointer may not be. 135 * 136 * In normal use we then have something like this: 137 * 138 * \verbatim 139 * ia hash tables 140 * ia_na_active +----------------+ 141 * ia_ta_active +------------+ | pool | 142 * ia_pd_active | iasubopt |<--| active hash | 143 * +-----------------+ | aka lease |<--| active heap | 144 * | ia_xx | | pool ptr |-->| | 145 * | iasubopt array |<---| iaptr |<--| inactive heap | 146 * | lease ptr |--->| | | | 147 * +-----------------+ +------------+ +----------------+ 148 * \endverbatim 149 * 150 * For the pool either the inactive heap will have a pointer 151 * or both the active heap and the active hash will have pointers. 152 * 153 * I think there are several major items to notice. The first is 154 * that as a lease moves around it will be added to and removed 155 * from the address hash table in the pool and between the active 156 * and inactive hash tables. The hash table and the active heap 157 * are used when the lease is either active or abandoned. The 158 * inactive heap is used for all other states. In particular a 159 * lease that has expired or been released will be cleaned 160 * (DDNS removal etc) and then moved to the inactive heap. After 161 * some time period (currently 1 hour) it will be freed. 162 * 163 * The second is that when a client requests specific addresses, 164 * either because it previously owned them or if the server supplied 165 * them as part of a solicit, the server will try to lookup the ia_xx 166 * associated with the client and find the addresses there. If it 167 * does find appropriate leases it moves them from the old IA to 168 * a new IA and eventually replaces the old IA with the new IA 169 * in the IA hash tables. 170 * 171 */ 172 #include "config.h" 173 174 #include <sys/types.h> 175 #include <time.h> 176 #include <netinet/in.h> 177 178 #include <stdarg.h> 179 #include "dhcpd.h" 180 #include "omapip/omapip.h" 181 #include "omapip/hash.h" 182 #include <isc/md5.h> 183 184 HASH_FUNCTIONS(ia, unsigned char *, struct ia_xx, ia_hash_t, 185 ia_reference, ia_dereference, do_string_hash) 186 187 ia_hash_t *ia_na_active; 188 ia_hash_t *ia_ta_active; 189 ia_hash_t *ia_pd_active; 190 191 HASH_FUNCTIONS(iasubopt, struct in6_addr *, struct iasubopt, iasubopt_hash_t, 192 iasubopt_reference, iasubopt_dereference, do_string_hash) 193 194 struct ipv6_pool **pools; 195 int num_pools; 196 197 /* 198 * Create a new IAADDR/PREFIX structure. 199 * 200 * - iasubopt must be a pointer to a (struct iasubopt *) pointer previously 201 * initialized to NULL 202 */ 203 isc_result_t 204 iasubopt_allocate(struct iasubopt **iasubopt, const char *file, int line) { 205 struct iasubopt *tmp; 206 207 if (iasubopt == NULL) { 208 log_error("%s(%d): NULL pointer reference", file, line); 209 return DHCP_R_INVALIDARG; 210 } 211 if (*iasubopt != NULL) { 212 log_error("%s(%d): non-NULL pointer", file, line); 213 return DHCP_R_INVALIDARG; 214 } 215 216 tmp = dmalloc(sizeof(*tmp), file, line); 217 if (tmp == NULL) { 218 return ISC_R_NOMEMORY; 219 } 220 221 tmp->refcnt = 1; 222 tmp->state = FTS_FREE; 223 tmp->heap_index = -1; 224 tmp->plen = 255; 225 226 *iasubopt = tmp; 227 return ISC_R_SUCCESS; 228 } 229 230 /* 231 * Reference an IAADDR/PREFIX structure. 232 * 233 * - iasubopt must be a pointer to a (struct iasubopt *) pointer previously 234 * initialized to NULL 235 */ 236 isc_result_t 237 iasubopt_reference(struct iasubopt **iasubopt, struct iasubopt *src, 238 const char *file, int line) { 239 if (iasubopt == NULL) { 240 log_error("%s(%d): NULL pointer reference", file, line); 241 return DHCP_R_INVALIDARG; 242 } 243 if (*iasubopt != NULL) { 244 log_error("%s(%d): non-NULL pointer", file, line); 245 return DHCP_R_INVALIDARG; 246 } 247 if (src == NULL) { 248 log_error("%s(%d): NULL pointer reference", file, line); 249 return DHCP_R_INVALIDARG; 250 } 251 *iasubopt = src; 252 src->refcnt++; 253 return ISC_R_SUCCESS; 254 } 255 256 257 /* 258 * Dereference an IAADDR/PREFIX structure. 259 * 260 * If it is the last reference, then the memory for the 261 * structure is freed. 262 */ 263 isc_result_t 264 iasubopt_dereference(struct iasubopt **iasubopt, const char *file, int line) { 265 struct iasubopt *tmp; 266 267 if ((iasubopt == NULL) || (*iasubopt == NULL)) { 268 log_error("%s(%d): NULL pointer", file, line); 269 return DHCP_R_INVALIDARG; 270 } 271 272 tmp = *iasubopt; 273 *iasubopt = NULL; 274 275 tmp->refcnt--; 276 if (tmp->refcnt < 0) { 277 log_error("%s(%d): negative refcnt", file, line); 278 tmp->refcnt = 0; 279 } 280 if (tmp->refcnt == 0) { 281 if (tmp->ia != NULL) { 282 ia_dereference(&(tmp->ia), file, line); 283 } 284 if (tmp->ipv6_pool != NULL) { 285 ipv6_pool_dereference(&(tmp->ipv6_pool), file, line); 286 } 287 if (tmp->scope != NULL) { 288 binding_scope_dereference(&tmp->scope, file, line); 289 } 290 291 if (tmp->on_star.on_expiry != NULL) { 292 executable_statement_dereference 293 (&tmp->on_star.on_expiry, MDL); 294 } 295 if (tmp->on_star.on_commit != NULL) { 296 executable_statement_dereference 297 (&tmp->on_star.on_commit, MDL); 298 } 299 if (tmp->on_star.on_release != NULL) { 300 executable_statement_dereference 301 (&tmp->on_star.on_release, MDL); 302 } 303 304 dfree(tmp, file, line); 305 } 306 307 return ISC_R_SUCCESS; 308 } 309 310 /* 311 * Make the key that we use for IA. 312 */ 313 isc_result_t 314 ia_make_key(struct data_string *key, u_int32_t iaid, 315 const char *duid, unsigned int duid_len, 316 const char *file, int line) { 317 318 memset(key, 0, sizeof(*key)); 319 key->len = duid_len + sizeof(iaid); 320 if (!buffer_allocate(&(key->buffer), key->len, file, line)) { 321 return ISC_R_NOMEMORY; 322 } 323 key->data = key->buffer->data; 324 memcpy((char *)key->data, &iaid, sizeof(iaid)); 325 memcpy((char *)key->data + sizeof(iaid), duid, duid_len); 326 327 return ISC_R_SUCCESS; 328 } 329 330 /* 331 * Create a new IA structure. 332 * 333 * - ia must be a pointer to a (struct ia_xx *) pointer previously 334 * initialized to NULL 335 * - iaid and duid are values from the client 336 * 337 * XXXsk: we don't concern ourself with the byte order of the IAID, 338 * which might be a problem if we transfer this structure 339 * between machines of different byte order 340 */ 341 isc_result_t 342 ia_allocate(struct ia_xx **ia, u_int32_t iaid, 343 const char *duid, unsigned int duid_len, 344 const char *file, int line) { 345 struct ia_xx *tmp; 346 347 if (ia == NULL) { 348 log_error("%s(%d): NULL pointer reference", file, line); 349 return DHCP_R_INVALIDARG; 350 } 351 if (*ia != NULL) { 352 log_error("%s(%d): non-NULL pointer", file, line); 353 return DHCP_R_INVALIDARG; 354 } 355 356 tmp = dmalloc(sizeof(*tmp), file, line); 357 if (tmp == NULL) { 358 return ISC_R_NOMEMORY; 359 } 360 361 if (ia_make_key(&tmp->iaid_duid, iaid, 362 duid, duid_len, file, line) != ISC_R_SUCCESS) { 363 dfree(tmp, file, line); 364 return ISC_R_NOMEMORY; 365 } 366 367 tmp->refcnt = 1; 368 369 *ia = tmp; 370 return ISC_R_SUCCESS; 371 } 372 373 /* 374 * Reference an IA structure. 375 * 376 * - ia must be a pointer to a (struct ia_xx *) pointer previously 377 * initialized to NULL 378 */ 379 isc_result_t 380 ia_reference(struct ia_xx **ia, struct ia_xx *src, 381 const char *file, int line) { 382 if (ia == NULL) { 383 log_error("%s(%d): NULL pointer reference", file, line); 384 return DHCP_R_INVALIDARG; 385 } 386 if (*ia != NULL) { 387 log_error("%s(%d): non-NULL pointer", file, line); 388 return DHCP_R_INVALIDARG; 389 } 390 if (src == NULL) { 391 log_error("%s(%d): NULL pointer reference", file, line); 392 return DHCP_R_INVALIDARG; 393 } 394 *ia = src; 395 src->refcnt++; 396 return ISC_R_SUCCESS; 397 } 398 399 /* 400 * Dereference an IA structure. 401 * 402 * If it is the last reference, then the memory for the 403 * structure is freed. 404 */ 405 isc_result_t 406 ia_dereference(struct ia_xx **ia, const char *file, int line) { 407 struct ia_xx *tmp; 408 int i; 409 410 if ((ia == NULL) || (*ia == NULL)) { 411 log_error("%s(%d): NULL pointer", file, line); 412 return DHCP_R_INVALIDARG; 413 } 414 415 tmp = *ia; 416 *ia = NULL; 417 418 tmp->refcnt--; 419 if (tmp->refcnt < 0) { 420 log_error("%s(%d): negative refcnt", file, line); 421 tmp->refcnt = 0; 422 } 423 if (tmp->refcnt == 0) { 424 if (tmp->iasubopt != NULL) { 425 for (i=0; i<tmp->num_iasubopt; i++) { 426 iasubopt_dereference(&(tmp->iasubopt[i]), 427 file, line); 428 } 429 dfree(tmp->iasubopt, file, line); 430 } 431 data_string_forget(&(tmp->iaid_duid), file, line); 432 dfree(tmp, file, line); 433 } 434 return ISC_R_SUCCESS; 435 } 436 437 438 /* 439 * Add an IAADDR/PREFIX entry to an IA structure. 440 */ 441 isc_result_t 442 ia_add_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt, 443 const char *file, int line) { 444 int max; 445 struct iasubopt **new; 446 447 /* 448 * Grow our array if we need to. 449 * 450 * Note: we pick 4 as the increment, as that seems a reasonable 451 * guess as to how many addresses/prefixes we might expect 452 * on an interface. 453 */ 454 if (ia->max_iasubopt <= ia->num_iasubopt) { 455 max = ia->max_iasubopt + 4; 456 new = dmalloc(max * sizeof(struct iasubopt *), file, line); 457 if (new == NULL) { 458 return ISC_R_NOMEMORY; 459 } 460 memcpy(new, ia->iasubopt, 461 ia->num_iasubopt * sizeof(struct iasubopt *)); 462 ia->iasubopt = new; 463 ia->max_iasubopt = max; 464 } 465 466 iasubopt_reference(&(ia->iasubopt[ia->num_iasubopt]), iasubopt, 467 file, line); 468 ia->num_iasubopt++; 469 470 return ISC_R_SUCCESS; 471 } 472 473 /* 474 * Remove an IAADDR/PREFIX entry to an IA structure. 475 * 476 * Note: if a suboption appears more than once, then only ONE will be removed. 477 */ 478 void 479 ia_remove_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt, 480 const char *file, int line) { 481 int i, j; 482 if (ia == NULL || iasubopt == NULL) 483 return; 484 485 for (i=0; i<ia->num_iasubopt; i++) { 486 if (ia->iasubopt[i] == iasubopt) { 487 /* remove this sub option */ 488 iasubopt_dereference(&(ia->iasubopt[i]), file, line); 489 /* move remaining suboption pointers down one */ 490 for (j=i+1; j < ia->num_iasubopt; j++) { 491 ia->iasubopt[j-1] = ia->iasubopt[j]; 492 } 493 /* decrease our total count */ 494 /* remove the back-reference in the suboption itself */ 495 ia_dereference(&iasubopt->ia, file, line); 496 ia->num_iasubopt--; 497 return; 498 } 499 } 500 log_error("%s(%d): IAADDR/PREFIX not in IA", file, line); 501 } 502 503 /* 504 * Remove all addresses/prefixes from an IA. 505 */ 506 void 507 ia_remove_all_lease(struct ia_xx *ia, const char *file, int line) { 508 int i; 509 510 for (i=0; i<ia->num_iasubopt; i++) { 511 ia_dereference(&(ia->iasubopt[i]->ia), file, line); 512 iasubopt_dereference(&(ia->iasubopt[i]), file, line); 513 } 514 ia->num_iasubopt = 0; 515 } 516 517 /* 518 * Compare two IA. 519 */ 520 isc_boolean_t 521 ia_equal(const struct ia_xx *a, const struct ia_xx *b) 522 { 523 isc_boolean_t found; 524 int i, j; 525 526 /* 527 * Handle cases where one or both of the inputs is NULL. 528 */ 529 if (a == NULL) { 530 if (b == NULL) { 531 return ISC_TRUE; 532 } else { 533 return ISC_FALSE; 534 } 535 } 536 537 /* 538 * Check the type is the same. 539 */ 540 if (a->ia_type != b->ia_type) { 541 return ISC_FALSE; 542 } 543 544 /* 545 * Check the DUID is the same. 546 */ 547 if (a->iaid_duid.len != b->iaid_duid.len) { 548 return ISC_FALSE; 549 } 550 if (memcmp(a->iaid_duid.data, 551 b->iaid_duid.data, a->iaid_duid.len) != 0) { 552 return ISC_FALSE; 553 } 554 555 /* 556 * Make sure we have the same number of addresses/prefixes in each. 557 */ 558 if (a->num_iasubopt != b->num_iasubopt) { 559 return ISC_FALSE; 560 } 561 562 /* 563 * Check that each address/prefix is present in both. 564 */ 565 for (i=0; i<a->num_iasubopt; i++) { 566 found = ISC_FALSE; 567 for (j=0; j<a->num_iasubopt; j++) { 568 if (a->iasubopt[i]->plen != b->iasubopt[i]->plen) 569 continue; 570 if (memcmp(&(a->iasubopt[i]->addr), 571 &(b->iasubopt[j]->addr), 572 sizeof(struct in6_addr)) == 0) { 573 found = ISC_TRUE; 574 break; 575 } 576 } 577 if (!found) { 578 return ISC_FALSE; 579 } 580 } 581 582 /* 583 * These are the same in every way we care about. 584 */ 585 return ISC_TRUE; 586 } 587 588 /* 589 * Helper function for lease heaps. 590 * Makes the top of the heap the oldest lease. 591 */ 592 static isc_boolean_t 593 lease_older(void *a, void *b) { 594 struct iasubopt *la = (struct iasubopt *)a; 595 struct iasubopt *lb = (struct iasubopt *)b; 596 597 if (la->hard_lifetime_end_time == lb->hard_lifetime_end_time) { 598 return difftime(la->soft_lifetime_end_time, 599 lb->soft_lifetime_end_time) < 0; 600 } else { 601 return difftime(la->hard_lifetime_end_time, 602 lb->hard_lifetime_end_time) < 0; 603 } 604 } 605 606 /* 607 * Helper function for lease address/prefix heaps. 608 * Callback when an address's position in the heap changes. 609 */ 610 static void 611 lease_index_changed(void *iasubopt, unsigned int new_heap_index) { 612 ((struct iasubopt *)iasubopt)-> heap_index = new_heap_index; 613 } 614 615 616 /*! 617 * 618 * \brief Create a new IPv6 lease pool structure 619 * 620 * Allocate space for a new ipv6_pool structure and return a reference 621 * to it, includes setting the reference count to 1. 622 * 623 * \param pool = space for returning a referenced pointer to the pool. 624 * This must point to a space that has been initialzied 625 * to NULL by the caller. 626 * \param[in] type = The type of the pool NA, TA or PD 627 * \param[in] start_addr = The first address in the range for the pool 628 * \param[in] bits = The contiguous bits of the pool 629 630 * 631 * \return 632 * ISC_R_SUCCESS = The pool was successfully created, pool points to it. 633 * DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been 634 * modified 635 * ISC_R_NOMEMORY = The system wasn't able to allocate memory, pool has 636 * not been modified. 637 */ 638 isc_result_t 639 ipv6_pool_allocate(struct ipv6_pool **pool, u_int16_t type, 640 const struct in6_addr *start_addr, int bits, 641 int units, const char *file, int line) { 642 struct ipv6_pool *tmp; 643 644 if (pool == NULL) { 645 log_error("%s(%d): NULL pointer reference", file, line); 646 return DHCP_R_INVALIDARG; 647 } 648 if (*pool != NULL) { 649 log_error("%s(%d): non-NULL pointer", file, line); 650 return DHCP_R_INVALIDARG; 651 } 652 653 tmp = dmalloc(sizeof(*tmp), file, line); 654 if (tmp == NULL) { 655 return ISC_R_NOMEMORY; 656 } 657 658 tmp->refcnt = 1; 659 tmp->pool_type = type; 660 tmp->start_addr = *start_addr; 661 tmp->bits = bits; 662 tmp->units = units; 663 if (!iasubopt_new_hash(&tmp->leases, DEFAULT_HASH_SIZE, file, line)) { 664 dfree(tmp, file, line); 665 return ISC_R_NOMEMORY; 666 } 667 if (isc_heap_create(dhcp_gbl_ctx.mctx, lease_older, lease_index_changed, 668 0, &(tmp->active_timeouts)) != ISC_R_SUCCESS) { 669 iasubopt_free_hash_table(&(tmp->leases), file, line); 670 dfree(tmp, file, line); 671 return ISC_R_NOMEMORY; 672 } 673 if (isc_heap_create(dhcp_gbl_ctx.mctx, lease_older, lease_index_changed, 674 0, &(tmp->inactive_timeouts)) != ISC_R_SUCCESS) { 675 isc_heap_destroy(&(tmp->active_timeouts)); 676 iasubopt_free_hash_table(&(tmp->leases), file, line); 677 dfree(tmp, file, line); 678 return ISC_R_NOMEMORY; 679 } 680 681 *pool = tmp; 682 return ISC_R_SUCCESS; 683 } 684 685 /*! 686 * 687 * \brief reference an IPv6 pool structure. 688 * 689 * This function genreates a reference to an ipv6_pool structure 690 * and increments the reference count on the structure. 691 * 692 * \param[out] pool = space for returning a referenced pointer to the pool. 693 * This must point to a space that has been initialzied 694 * to NULL by the caller. 695 * \param[in] src = A pointer to the pool to reference. This must not be 696 * NULL. 697 * 698 * \return 699 * ISC_R_SUCCESS = The pool was successfully referenced, pool now points 700 * to src. 701 * DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been 702 * modified. 703 */ 704 isc_result_t 705 ipv6_pool_reference(struct ipv6_pool **pool, struct ipv6_pool *src, 706 const char *file, int line) { 707 if (pool == NULL) { 708 log_error("%s(%d): NULL pointer reference", file, line); 709 return DHCP_R_INVALIDARG; 710 } 711 if (*pool != NULL) { 712 log_error("%s(%d): non-NULL pointer", file, line); 713 return DHCP_R_INVALIDARG; 714 } 715 if (src == NULL) { 716 log_error("%s(%d): NULL pointer reference", file, line); 717 return DHCP_R_INVALIDARG; 718 } 719 *pool = src; 720 src->refcnt++; 721 return ISC_R_SUCCESS; 722 } 723 724 /* 725 * Note: Each IAADDR/PREFIX in a pool is referenced by the pool. This is needed 726 * to prevent the lease from being garbage collected out from under the 727 * pool. 728 * 729 * The references are made from the hash and from the heap. The following 730 * helper functions dereference these when a pool is destroyed. 731 */ 732 733 /* 734 * Helper function for pool cleanup. 735 * Dereference each of the hash entries in a pool. 736 */ 737 static isc_result_t 738 dereference_hash_entry(const void *name, unsigned len, void *value) { 739 struct iasubopt *iasubopt = (struct iasubopt *)value; 740 741 iasubopt_dereference(&iasubopt, MDL); 742 return ISC_R_SUCCESS; 743 } 744 745 /* 746 * Helper function for pool cleanup. 747 * Dereference each of the heap entries in a pool. 748 */ 749 static void 750 dereference_heap_entry(void *value, void *dummy) { 751 struct iasubopt *iasubopt = (struct iasubopt *)value; 752 753 iasubopt_dereference(&iasubopt, MDL); 754 } 755 756 /*! 757 * 758 * \brief de-reference an IPv6 pool structure. 759 * 760 * This function decrements the reference count in an ipv6_pool structure. 761 * If this was the last reference then the memory for the structure is 762 * freed. 763 * 764 * \param[in] pool = A pointer to the pointer to the pool that should be 765 * de-referenced. On success the pointer to the pool 766 * is cleared. It must not be NULL and must not point 767 * to NULL. 768 * 769 * \return 770 * ISC_R_SUCCESS = The pool was successfully de-referenced, pool now points 771 * to NULL 772 * DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been 773 * modified. 774 */ 775 isc_result_t 776 ipv6_pool_dereference(struct ipv6_pool **pool, const char *file, int line) { 777 struct ipv6_pool *tmp; 778 779 if ((pool == NULL) || (*pool == NULL)) { 780 log_error("%s(%d): NULL pointer", file, line); 781 return DHCP_R_INVALIDARG; 782 } 783 784 tmp = *pool; 785 *pool = NULL; 786 787 tmp->refcnt--; 788 if (tmp->refcnt < 0) { 789 log_error("%s(%d): negative refcnt", file, line); 790 tmp->refcnt = 0; 791 } 792 if (tmp->refcnt == 0) { 793 iasubopt_hash_foreach(tmp->leases, dereference_hash_entry); 794 iasubopt_free_hash_table(&(tmp->leases), file, line); 795 isc_heap_foreach(tmp->active_timeouts, 796 dereference_heap_entry, NULL); 797 isc_heap_destroy(&(tmp->active_timeouts)); 798 isc_heap_foreach(tmp->inactive_timeouts, 799 dereference_heap_entry, NULL); 800 isc_heap_destroy(&(tmp->inactive_timeouts)); 801 dfree(tmp, file, line); 802 } 803 804 return ISC_R_SUCCESS; 805 } 806 807 /* 808 * Create an address by hashing the input, and using that for 809 * the non-network part. 810 */ 811 static void 812 build_address6(struct in6_addr *addr, 813 const struct in6_addr *net_start_addr, int net_bits, 814 const struct data_string *input) { 815 isc_md5_t ctx; 816 int net_bytes; 817 int i; 818 char *str; 819 const char *net_str; 820 821 /* 822 * Use MD5 to get a nice 128 bit hash of the input. 823 * Yes, we know MD5 isn't cryptographically sound. 824 * No, we don't care. 825 */ 826 isc_md5_init(&ctx); 827 isc_md5_update(&ctx, input->data, input->len); 828 isc_md5_final(&ctx, (unsigned char *)addr); 829 830 /* 831 * Copy the [0..128] network bits over. 832 */ 833 str = (char *)addr; 834 net_str = (const char *)net_start_addr; 835 net_bytes = net_bits / 8; 836 for (i = 0; i < net_bytes; i++) { 837 str[i] = net_str[i]; 838 } 839 switch (net_bits % 8) { 840 case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break; 841 case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break; 842 case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break; 843 case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break; 844 case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break; 845 case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break; 846 case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break; 847 } 848 849 /* 850 * Set the universal/local bit ("u bit") to zero for /64s. The 851 * individual/group bit ("g bit") is unchanged, because the g-bit 852 * has no meaning when the u-bit is cleared. 853 */ 854 if (net_bits == 64) 855 str[8] &= ~0x02; 856 } 857 858 /* 859 * Create a temporary address by a variant of RFC 4941 algo. 860 * Note: this should not be used for prefixes shorter than 64 bits. 861 */ 862 static void 863 build_temporary6(struct in6_addr *addr, 864 const struct in6_addr *net_start_addr, int net_bits, 865 const struct data_string *input) { 866 static u_int32_t history[2]; 867 static u_int32_t counter = 0; 868 isc_md5_t ctx; 869 unsigned char md[16]; 870 871 /* 872 * First time/time to reseed. 873 * Please use a good pseudo-random generator here! 874 */ 875 if (counter == 0) { 876 isc_random_get(&history[0]); 877 isc_random_get(&history[1]); 878 } 879 880 /* 881 * Use MD5 as recommended by RFC 4941. 882 */ 883 isc_md5_init(&ctx); 884 isc_md5_update(&ctx, (unsigned char *)&history[0], 8UL); 885 isc_md5_update(&ctx, input->data, input->len); 886 isc_md5_final(&ctx, md); 887 888 /* 889 * Build the address. 890 */ 891 if (net_bits == 64) { 892 memcpy(&addr->s6_addr[0], &net_start_addr->s6_addr[0], 8); 893 memcpy(&addr->s6_addr[8], md, 8); 894 addr->s6_addr[8] &= ~0x02; 895 } else { 896 int net_bytes; 897 int i; 898 char *str; 899 const char *net_str; 900 901 /* 902 * Copy the [0..128] network bits over. 903 */ 904 str = (char *)addr; 905 net_str = (const char *)net_start_addr; 906 net_bytes = net_bits / 8; 907 for (i = 0; i < net_bytes; i++) { 908 str[i] = net_str[i]; 909 } 910 memcpy(str + net_bytes, md, 16 - net_bytes); 911 switch (net_bits % 8) { 912 case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break; 913 case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break; 914 case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break; 915 case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break; 916 case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break; 917 case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break; 918 case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break; 919 } 920 } 921 922 923 /* 924 * Save history for the next call. 925 */ 926 memcpy((unsigned char *)&history[0], md + 8, 8); 927 counter++; 928 } 929 930 /* Reserved Subnet Router Anycast ::0:0:0:0. */ 931 static struct in6_addr rtany; 932 /* Reserved Subnet Anycasts ::fdff:ffff:ffff:ff80-::fdff:ffff:ffff:ffff. */ 933 static struct in6_addr resany; 934 935 /* 936 * Create a lease for the given address and client duid. 937 * 938 * - pool must be a pointer to a (struct ipv6_pool *) pointer previously 939 * initialized to NULL 940 * 941 * Right now we simply hash the DUID, and if we get a collision, we hash 942 * again until we find a free address. We try this a fixed number of times, 943 * to avoid getting stuck in a loop (this is important on small pools 944 * where we can run out of space). 945 * 946 * We return the number of attempts that it took to find an available 947 * lease. This tells callers when a pool is are filling up, as 948 * well as an indication of how full the pool is; statistically the 949 * more full a pool is the more attempts must be made before finding 950 * a free lease. Realistically this will only happen in very full 951 * pools. 952 * 953 * We probably want different algorithms depending on the network size, in 954 * the long term. 955 */ 956 isc_result_t 957 create_lease6(struct ipv6_pool *pool, struct iasubopt **addr, 958 unsigned int *attempts, 959 const struct data_string *uid, time_t soft_lifetime_end_time) { 960 struct data_string ds; 961 struct in6_addr tmp; 962 struct iasubopt *test_iaaddr; 963 struct data_string new_ds; 964 struct iasubopt *iaaddr; 965 isc_result_t result; 966 isc_boolean_t reserved_iid; 967 static isc_boolean_t init_resiid = ISC_FALSE; 968 969 /* 970 * Fill the reserved IIDs. 971 */ 972 if (!init_resiid) { 973 memset(&rtany, 0, 16); 974 memset(&resany, 0, 8); 975 resany.s6_addr[8] = 0xfd; 976 memset(&resany.s6_addr[9], 0xff, 6); 977 init_resiid = ISC_TRUE; 978 } 979 980 /* 981 * Use the UID as our initial seed for the hash 982 */ 983 memset(&ds, 0, sizeof(ds)); 984 data_string_copy(&ds, (struct data_string *)uid, MDL); 985 986 *attempts = 0; 987 for (;;) { 988 /* 989 * Give up at some point. 990 */ 991 if (++(*attempts) > 100) { 992 data_string_forget(&ds, MDL); 993 return ISC_R_NORESOURCES; 994 } 995 996 /* 997 * Build a resource. 998 */ 999 switch (pool->pool_type) { 1000 case D6O_IA_NA: 1001 /* address */ 1002 build_address6(&tmp, &pool->start_addr, 1003 pool->bits, &ds); 1004 break; 1005 case D6O_IA_TA: 1006 /* temporary address */ 1007 build_temporary6(&tmp, &pool->start_addr, 1008 pool->bits, &ds); 1009 break; 1010 case D6O_IA_PD: 1011 /* prefix */ 1012 log_error("create_lease6: prefix pool."); 1013 return DHCP_R_INVALIDARG; 1014 default: 1015 log_error("create_lease6: untyped pool."); 1016 return DHCP_R_INVALIDARG; 1017 } 1018 1019 /* 1020 * Avoid reserved interface IDs. (cf. RFC 5453) 1021 */ 1022 reserved_iid = ISC_FALSE; 1023 if (memcmp(&tmp.s6_addr[8], &rtany.s6_addr[8], 8) == 0) { 1024 reserved_iid = ISC_TRUE; 1025 } 1026 if (!reserved_iid && 1027 (memcmp(&tmp.s6_addr[8], &resany.s6_addr[8], 7) == 0) && 1028 ((tmp.s6_addr[15] & 0x80) == 0x80)) { 1029 reserved_iid = ISC_TRUE; 1030 } 1031 1032 /* 1033 * If this address is not in use, we're happy with it 1034 */ 1035 test_iaaddr = NULL; 1036 if (!reserved_iid && 1037 (iasubopt_hash_lookup(&test_iaaddr, pool->leases, 1038 &tmp, sizeof(tmp), MDL) == 0)) { 1039 break; 1040 } 1041 if (test_iaaddr != NULL) 1042 iasubopt_dereference(&test_iaaddr, MDL); 1043 1044 /* 1045 * Otherwise, we create a new input, adding the address 1046 */ 1047 memset(&new_ds, 0, sizeof(new_ds)); 1048 new_ds.len = ds.len + sizeof(tmp); 1049 if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) { 1050 data_string_forget(&ds, MDL); 1051 return ISC_R_NOMEMORY; 1052 } 1053 new_ds.data = new_ds.buffer->data; 1054 memcpy(new_ds.buffer->data, ds.data, ds.len); 1055 memcpy(new_ds.buffer->data + ds.len, &tmp, sizeof(tmp)); 1056 data_string_forget(&ds, MDL); 1057 data_string_copy(&ds, &new_ds, MDL); 1058 data_string_forget(&new_ds, MDL); 1059 } 1060 1061 data_string_forget(&ds, MDL); 1062 1063 /* 1064 * We're happy with the address, create an IAADDR 1065 * to hold it. 1066 */ 1067 iaaddr = NULL; 1068 result = iasubopt_allocate(&iaaddr, MDL); 1069 if (result != ISC_R_SUCCESS) { 1070 return result; 1071 } 1072 iaaddr->plen = 0; 1073 memcpy(&iaaddr->addr, &tmp, sizeof(iaaddr->addr)); 1074 1075 /* 1076 * Add the lease to the pool (note state is free, not active?!). 1077 */ 1078 result = add_lease6(pool, iaaddr, soft_lifetime_end_time); 1079 if (result == ISC_R_SUCCESS) { 1080 iasubopt_reference(addr, iaaddr, MDL); 1081 } 1082 iasubopt_dereference(&iaaddr, MDL); 1083 return result; 1084 } 1085 1086 1087 /*! 1088 * 1089 * \brief Cleans up leases when reading from a lease file 1090 * 1091 * This function is only expected to be run when reading leases in from a file. 1092 * It checks to see if a lease already exists for the new leases's address. 1093 * We don't add expired leases to the structures when reading a lease file 1094 * which limits what can happen. We have two variables the owners of the leases 1095 * being the same or different and the new lease being active or non-active: 1096 * Owners active 1097 * same no remove old lease and its connections 1098 * same yes nothing to do, other code will update the structures. 1099 * diff no nothing to do 1100 * diff yes this combination shouldn't happen, we should only have a 1101 * single active lease per address at a time and that lease 1102 * should move to non-active before any other lease can 1103 * become active for that address. 1104 * Currently we delete the previous lease and pass an error 1105 * to the caller who should log an error. 1106 * 1107 * When we remove a lease we remove it from the hash table and active heap 1108 * (remember only active leases are in the structures at this time) for the 1109 * pool, and from the IA's array. If, after we've removed the pointer from 1110 * IA's array to the lease, the IA has no more pointers we remove it from 1111 * the appropriate hash table as well. 1112 * 1113 * \param[in] ia_table = the hash table for the IA 1114 * \param[in] pool = the pool to update 1115 * \param[in] lease = the new lease we want to add 1116 * \param[in] ia = the new ia we are building 1117 * 1118 * \return 1119 * ISC_R_SUCCESS = the incoming lease and any previous lease were in 1120 * an expected state - one of the first 3 options above. 1121 * If necessary the old lease was removed. 1122 * ISC_R_FAILURE = there is already an active lease for the address in 1123 * the incoming lease. This shouldn't happen if it does 1124 * flag an error for the caller to log. 1125 */ 1126 1127 isc_result_t 1128 cleanup_lease6(ia_hash_t *ia_table, 1129 struct ipv6_pool *pool, 1130 struct iasubopt *lease, 1131 struct ia_xx *ia) { 1132 1133 struct iasubopt *test_iasubopt, *tmp_iasubopt; 1134 struct ia_xx *old_ia; 1135 isc_result_t status = ISC_R_SUCCESS; 1136 1137 test_iasubopt = NULL; 1138 old_ia = NULL; 1139 1140 /* 1141 * Look up the address - if we don't find a lease 1142 * we don't need to do anything. 1143 */ 1144 if (iasubopt_hash_lookup(&test_iasubopt, pool->leases, 1145 &lease->addr, sizeof(lease->addr), 1146 MDL) == 0) { 1147 return (ISC_R_SUCCESS); 1148 } 1149 1150 if (test_iasubopt->ia == NULL) { 1151 /* no old ia, no work to do */ 1152 iasubopt_dereference(&test_iasubopt, MDL); 1153 return (status); 1154 } 1155 1156 ia_reference(&old_ia, test_iasubopt->ia, MDL); 1157 1158 if ((old_ia->iaid_duid.len == ia->iaid_duid.len) && 1159 (memcmp((unsigned char *)ia->iaid_duid.data, 1160 (unsigned char *)old_ia->iaid_duid.data, 1161 ia->iaid_duid.len) == 0)) { 1162 /* same IA */ 1163 if ((lease->state == FTS_ACTIVE) || 1164 (lease->state == FTS_ABANDONED)) { 1165 /* still active, no need to delete */ 1166 goto cleanup; 1167 } 1168 } else { 1169 /* different IA */ 1170 if ((lease->state != FTS_ACTIVE) && 1171 (lease->state != FTS_ABANDONED)) { 1172 /* new lease isn't active, no work */ 1173 goto cleanup; 1174 } 1175 1176 /* 1177 * We appear to have two active leases, this shouldn't happen. 1178 * Before a second lease can be set to active the first lease 1179 * should be set to inactive (released, expired etc). For now 1180 * delete the previous lease and indicate a failure to the 1181 * caller so it can generate a warning. 1182 * In the future we may try and determine which is the better 1183 * lease to keep. 1184 */ 1185 1186 status = ISC_R_FAILURE; 1187 } 1188 1189 /* 1190 * Remove the old lease from the active heap and from the hash table 1191 * then remove the lease from the IA and clean up the IA if necessary. 1192 */ 1193 isc_heap_delete(pool->active_timeouts, test_iasubopt->heap_index); 1194 pool->num_active--; 1195 1196 iasubopt_hash_delete(pool->leases, &test_iasubopt->addr, 1197 sizeof(test_iasubopt->addr), MDL); 1198 ia_remove_iasubopt(old_ia, test_iasubopt, MDL); 1199 if (old_ia->num_iasubopt <= 0) { 1200 ia_hash_delete(ia_table, 1201 (unsigned char *)old_ia->iaid_duid.data, 1202 old_ia->iaid_duid.len, MDL); 1203 } 1204 1205 /* 1206 * We derefenrece the subopt here as we've just removed it from 1207 * the hash table in the pool. We need to make a copy as we 1208 * need to derefernece it again later. 1209 */ 1210 tmp_iasubopt = test_iasubopt; 1211 iasubopt_dereference(&tmp_iasubopt, MDL); 1212 1213 cleanup: 1214 ia_dereference(&old_ia, MDL); 1215 1216 /* 1217 * Clean up the reference, this is in addition to the deference 1218 * above after removing the entry from the hash table 1219 */ 1220 iasubopt_dereference(&test_iasubopt, MDL); 1221 1222 return (status); 1223 } 1224 1225 /* 1226 * Put a lease in the pool directly. This is intended to be used when 1227 * loading leases from the file. 1228 */ 1229 isc_result_t 1230 add_lease6(struct ipv6_pool *pool, struct iasubopt *lease, 1231 time_t valid_lifetime_end_time) { 1232 isc_result_t insert_result; 1233 struct iasubopt *test_iasubopt; 1234 struct iasubopt *tmp_iasubopt; 1235 1236 /* If a state was not assigned by the caller, assume active. */ 1237 if (lease->state == 0) 1238 lease->state = FTS_ACTIVE; 1239 1240 ipv6_pool_reference(&lease->ipv6_pool, pool, MDL); 1241 1242 /* 1243 * If this IAADDR/PREFIX is already in our structures, remove the 1244 * old one. 1245 */ 1246 test_iasubopt = NULL; 1247 if (iasubopt_hash_lookup(&test_iasubopt, pool->leases, 1248 &lease->addr, sizeof(lease->addr), MDL)) { 1249 /* XXX: we should probably ask the lease what heap it is on 1250 * (as a consistency check). 1251 * XXX: we should probably have one function to "put this lease 1252 * on its heap" rather than doing these if's everywhere. If 1253 * you add more states to this list, don't. 1254 */ 1255 if ((test_iasubopt->state == FTS_ACTIVE) || 1256 (test_iasubopt->state == FTS_ABANDONED)) { 1257 isc_heap_delete(pool->active_timeouts, 1258 test_iasubopt->heap_index); 1259 pool->num_active--; 1260 } else { 1261 isc_heap_delete(pool->inactive_timeouts, 1262 test_iasubopt->heap_index); 1263 pool->num_inactive--; 1264 } 1265 1266 iasubopt_hash_delete(pool->leases, &test_iasubopt->addr, 1267 sizeof(test_iasubopt->addr), MDL); 1268 1269 /* 1270 * We're going to do a bit of evil trickery here. 1271 * 1272 * We need to dereference the entry once to remove our 1273 * current reference (in test_iasubopt), and then one 1274 * more time to remove the reference left when the 1275 * address was added to the pool before. 1276 */ 1277 tmp_iasubopt = test_iasubopt; 1278 iasubopt_dereference(&test_iasubopt, MDL); 1279 iasubopt_dereference(&tmp_iasubopt, MDL); 1280 } 1281 1282 /* 1283 * Add IAADDR/PREFIX to our structures. 1284 */ 1285 tmp_iasubopt = NULL; 1286 iasubopt_reference(&tmp_iasubopt, lease, MDL); 1287 if ((tmp_iasubopt->state == FTS_ACTIVE) || 1288 (tmp_iasubopt->state == FTS_ABANDONED)) { 1289 tmp_iasubopt->hard_lifetime_end_time = valid_lifetime_end_time; 1290 iasubopt_hash_add(pool->leases, &tmp_iasubopt->addr, 1291 sizeof(tmp_iasubopt->addr), lease, MDL); 1292 insert_result = isc_heap_insert(pool->active_timeouts, 1293 tmp_iasubopt); 1294 if (insert_result == ISC_R_SUCCESS) 1295 pool->num_active++; 1296 } else { 1297 tmp_iasubopt->soft_lifetime_end_time = valid_lifetime_end_time; 1298 insert_result = isc_heap_insert(pool->inactive_timeouts, 1299 tmp_iasubopt); 1300 if (insert_result == ISC_R_SUCCESS) 1301 pool->num_inactive++; 1302 } 1303 if (insert_result != ISC_R_SUCCESS) { 1304 iasubopt_hash_delete(pool->leases, &lease->addr, 1305 sizeof(lease->addr), MDL); 1306 iasubopt_dereference(&tmp_iasubopt, MDL); 1307 return insert_result; 1308 } 1309 1310 /* 1311 * Note: we intentionally leave tmp_iasubopt referenced; there 1312 * is a reference in the heap/hash, after all. 1313 */ 1314 1315 return ISC_R_SUCCESS; 1316 } 1317 1318 /* 1319 * Determine if an address is present in a pool or not. 1320 */ 1321 isc_boolean_t 1322 lease6_exists(const struct ipv6_pool *pool, const struct in6_addr *addr) { 1323 struct iasubopt *test_iaaddr; 1324 1325 test_iaaddr = NULL; 1326 if (iasubopt_hash_lookup(&test_iaaddr, pool->leases, 1327 (void *)addr, sizeof(*addr), MDL)) { 1328 iasubopt_dereference(&test_iaaddr, MDL); 1329 return ISC_TRUE; 1330 } else { 1331 return ISC_FALSE; 1332 } 1333 } 1334 1335 /*! 1336 * 1337 * \brief Check if address is available to a lease 1338 * 1339 * Determine if the address in the lease is available to that 1340 * lease. Either the address isn't in use or it is in use 1341 * but by that lease. 1342 * 1343 * \param[in] lease = lease to check 1344 * 1345 * \return 1346 * ISC_TRUE = The lease is allowed to use that address 1347 * ISC_FALSE = The lease isn't allowed to use that address 1348 */ 1349 isc_boolean_t 1350 lease6_usable(struct iasubopt *lease) { 1351 struct iasubopt *test_iaaddr; 1352 isc_boolean_t status = ISC_TRUE; 1353 1354 test_iaaddr = NULL; 1355 if (iasubopt_hash_lookup(&test_iaaddr, lease->ipv6_pool->leases, 1356 (void *)&lease->addr, 1357 sizeof(lease->addr), MDL)) { 1358 if (test_iaaddr != lease) { 1359 status = ISC_FALSE; 1360 } 1361 iasubopt_dereference(&test_iaaddr, MDL); 1362 } 1363 1364 return (status); 1365 } 1366 1367 /* 1368 * Put the lease on our active pool. 1369 */ 1370 static isc_result_t 1371 move_lease_to_active(struct ipv6_pool *pool, struct iasubopt *lease) { 1372 isc_result_t insert_result; 1373 int old_heap_index; 1374 1375 old_heap_index = lease->heap_index; 1376 insert_result = isc_heap_insert(pool->active_timeouts, lease); 1377 if (insert_result == ISC_R_SUCCESS) { 1378 iasubopt_hash_add(pool->leases, &lease->addr, 1379 sizeof(lease->addr), lease, MDL); 1380 isc_heap_delete(pool->inactive_timeouts, old_heap_index); 1381 pool->num_active++; 1382 pool->num_inactive--; 1383 lease->state = FTS_ACTIVE; 1384 } 1385 return insert_result; 1386 } 1387 1388 /*! 1389 * 1390 * \brief Renew a lease in the pool. 1391 * 1392 * The hard_lifetime_end_time of the lease should be set to 1393 * the current expiration time. 1394 * The soft_lifetime_end_time of the lease should be set to 1395 * the desired expiration time. 1396 * 1397 * This routine will compare the two and call the correct 1398 * heap routine to move the lease. If the lease is active 1399 * and the new expiration time is greater (the normal case) 1400 * then we call isc_heap_decreased() as a larger time is a 1401 * lower priority. If the new expiration time is less then 1402 * we call isc_heap_increased(). 1403 * 1404 * If the lease is abandoned then it will be on the active list 1405 * and we will always call isc_heap_increased() as the previous 1406 * expiration would have been all 1s (as close as we can get 1407 * to infinite). 1408 * 1409 * If the lease is moving to active we call that routine 1410 * which will move it from the inactive list to the active list. 1411 * 1412 * \param pool = a pool the lease belongs to 1413 * \param lease = the lease to be renewed 1414 * 1415 * \return result of the renew operation (ISC_R_SUCCESS if successful, 1416 ISC_R_NOMEMORY when run out of memory) 1417 */ 1418 isc_result_t 1419 renew_lease6(struct ipv6_pool *pool, struct iasubopt *lease) { 1420 time_t old_end_time = lease->hard_lifetime_end_time; 1421 lease->hard_lifetime_end_time = lease->soft_lifetime_end_time; 1422 lease->soft_lifetime_end_time = 0; 1423 1424 if (lease->state == FTS_ACTIVE) { 1425 if (old_end_time <= lease->hard_lifetime_end_time) { 1426 isc_heap_decreased(pool->active_timeouts, 1427 lease->heap_index); 1428 } else { 1429 isc_heap_increased(pool->active_timeouts, 1430 lease->heap_index); 1431 } 1432 return ISC_R_SUCCESS; 1433 } else if (lease->state == FTS_ABANDONED) { 1434 char tmp_addr[INET6_ADDRSTRLEN]; 1435 lease->state = FTS_ACTIVE; 1436 isc_heap_increased(pool->active_timeouts, lease->heap_index); 1437 log_info("Reclaiming previously abandoned address %s", 1438 inet_ntop(AF_INET6, &(lease->addr), tmp_addr, 1439 sizeof(tmp_addr))); 1440 return ISC_R_SUCCESS; 1441 } else { 1442 return move_lease_to_active(pool, lease); 1443 } 1444 } 1445 1446 /* 1447 * Put the lease on our inactive pool, with the specified state. 1448 */ 1449 static isc_result_t 1450 move_lease_to_inactive(struct ipv6_pool *pool, struct iasubopt *lease, 1451 binding_state_t state) { 1452 isc_result_t insert_result; 1453 int old_heap_index; 1454 1455 old_heap_index = lease->heap_index; 1456 insert_result = isc_heap_insert(pool->inactive_timeouts, lease); 1457 if (insert_result == ISC_R_SUCCESS) { 1458 /* 1459 * Handle expire and release statements 1460 * To get here we must be active and have done a commit so 1461 * we should run the proper statements if they exist, though 1462 * that will change when we remove the inactive heap. 1463 * In addition we get rid of the references for both as we 1464 * can only do one (expire or release) on a lease 1465 */ 1466 if (lease->on_star.on_expiry != NULL) { 1467 if (state == FTS_EXPIRED) { 1468 execute_statements(NULL, NULL, NULL, 1469 NULL, NULL, NULL, 1470 &lease->scope, 1471 lease->on_star.on_expiry, 1472 &lease->on_star); 1473 } 1474 executable_statement_dereference 1475 (&lease->on_star.on_expiry, MDL); 1476 } 1477 1478 if (lease->on_star.on_release != NULL) { 1479 if (state == FTS_RELEASED) { 1480 execute_statements(NULL, NULL, NULL, 1481 NULL, NULL, NULL, 1482 &lease->scope, 1483 lease->on_star.on_release, 1484 &lease->on_star); 1485 } 1486 executable_statement_dereference 1487 (&lease->on_star.on_release, MDL); 1488 } 1489 1490 #if defined (NSUPDATE) 1491 /* Process events upon expiration. */ 1492 if (pool->pool_type != D6O_IA_PD) { 1493 (void) ddns_removals(NULL, lease, NULL, ISC_FALSE); 1494 } 1495 #endif 1496 1497 /* Binding scopes are no longer valid after expiry or 1498 * release. 1499 */ 1500 if (lease->scope != NULL) { 1501 binding_scope_dereference(&lease->scope, MDL); 1502 } 1503 1504 iasubopt_hash_delete(pool->leases, 1505 &lease->addr, sizeof(lease->addr), MDL); 1506 isc_heap_delete(pool->active_timeouts, old_heap_index); 1507 lease->state = state; 1508 pool->num_active--; 1509 pool->num_inactive++; 1510 } 1511 return insert_result; 1512 } 1513 1514 /* 1515 * Expire the oldest lease if it's lifetime_end_time is 1516 * older than the given time. 1517 * 1518 * - leasep must be a pointer to a (struct iasubopt *) pointer previously 1519 * initialized to NULL 1520 * 1521 * On return leasep has a reference to the removed entry. It is left 1522 * pointing to NULL if the oldest lease has not expired. 1523 */ 1524 isc_result_t 1525 expire_lease6(struct iasubopt **leasep, struct ipv6_pool *pool, time_t now) { 1526 struct iasubopt *tmp; 1527 isc_result_t result; 1528 1529 if (leasep == NULL) { 1530 log_error("%s(%d): NULL pointer reference", MDL); 1531 return DHCP_R_INVALIDARG; 1532 } 1533 if (*leasep != NULL) { 1534 log_error("%s(%d): non-NULL pointer", MDL); 1535 return DHCP_R_INVALIDARG; 1536 } 1537 1538 if (pool->num_active > 0) { 1539 tmp = (struct iasubopt *) 1540 isc_heap_element(pool->active_timeouts, 1); 1541 if (now > tmp->hard_lifetime_end_time) { 1542 result = move_lease_to_inactive(pool, tmp, 1543 FTS_EXPIRED); 1544 if (result == ISC_R_SUCCESS) { 1545 iasubopt_reference(leasep, tmp, MDL); 1546 } 1547 return result; 1548 } 1549 } 1550 return ISC_R_SUCCESS; 1551 } 1552 1553 1554 /* 1555 * For a declined lease, leave it on the "active" pool, but mark 1556 * it as declined. Give it an infinite (well, really long) life. 1557 */ 1558 isc_result_t 1559 decline_lease6(struct ipv6_pool *pool, struct iasubopt *lease) { 1560 isc_result_t result; 1561 1562 if ((lease->state != FTS_ACTIVE) && 1563 (lease->state != FTS_ABANDONED)) { 1564 result = move_lease_to_active(pool, lease); 1565 if (result != ISC_R_SUCCESS) { 1566 return result; 1567 } 1568 } 1569 lease->state = FTS_ABANDONED; 1570 lease->hard_lifetime_end_time = MAX_TIME; 1571 isc_heap_decreased(pool->active_timeouts, lease->heap_index); 1572 return ISC_R_SUCCESS; 1573 } 1574 1575 /* 1576 * Put the returned lease on our inactive pool. 1577 */ 1578 isc_result_t 1579 release_lease6(struct ipv6_pool *pool, struct iasubopt *lease) { 1580 if (lease->state == FTS_ACTIVE) { 1581 return move_lease_to_inactive(pool, lease, FTS_RELEASED); 1582 } else { 1583 return ISC_R_SUCCESS; 1584 } 1585 } 1586 1587 /* 1588 * Create a prefix by hashing the input, and using that for 1589 * the part subject to allocation. 1590 */ 1591 static void 1592 build_prefix6(struct in6_addr *pref, 1593 const struct in6_addr *net_start_pref, 1594 int pool_bits, int pref_bits, 1595 const struct data_string *input) { 1596 isc_md5_t ctx; 1597 int net_bytes; 1598 int i; 1599 char *str; 1600 const char *net_str; 1601 1602 /* 1603 * Use MD5 to get a nice 128 bit hash of the input. 1604 * Yes, we know MD5 isn't cryptographically sound. 1605 * No, we don't care. 1606 */ 1607 isc_md5_init(&ctx); 1608 isc_md5_update(&ctx, input->data, input->len); 1609 isc_md5_final(&ctx, (unsigned char *)pref); 1610 1611 /* 1612 * Copy the network bits over. 1613 */ 1614 str = (char *)pref; 1615 net_str = (const char *)net_start_pref; 1616 net_bytes = pool_bits / 8; 1617 for (i = 0; i < net_bytes; i++) { 1618 str[i] = net_str[i]; 1619 } 1620 i = net_bytes; 1621 switch (pool_bits % 8) { 1622 case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break; 1623 case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break; 1624 case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break; 1625 case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break; 1626 case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break; 1627 case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break; 1628 case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break; 1629 } 1630 /* 1631 * Zero the remaining bits. 1632 */ 1633 net_bytes = pref_bits / 8; 1634 for (i=net_bytes+1; i<16; i++) { 1635 str[i] = 0; 1636 } 1637 i = net_bytes; 1638 switch (pref_bits % 8) { 1639 case 0: str[i] &= 0; break; 1640 case 1: str[i] &= 0x80; break; 1641 case 2: str[i] &= 0xC0; break; 1642 case 3: str[i] &= 0xE0; break; 1643 case 4: str[i] &= 0xF0; break; 1644 case 5: str[i] &= 0xF8; break; 1645 case 6: str[i] &= 0xFC; break; 1646 case 7: str[i] &= 0xFE; break; 1647 } 1648 } 1649 1650 /* 1651 * Create a lease for the given prefix and client duid. 1652 * 1653 * - pool must be a pointer to a (struct ipv6_pool *) pointer previously 1654 * initialized to NULL 1655 * 1656 * Right now we simply hash the DUID, and if we get a collision, we hash 1657 * again until we find a free prefix. We try this a fixed number of times, 1658 * to avoid getting stuck in a loop (this is important on small pools 1659 * where we can run out of space). 1660 * 1661 * We return the number of attempts that it took to find an available 1662 * prefix. This tells callers when a pool is are filling up, as 1663 * well as an indication of how full the pool is; statistically the 1664 * more full a pool is the more attempts must be made before finding 1665 * a free prefix. Realistically this will only happen in very full 1666 * pools. 1667 * 1668 * We probably want different algorithms depending on the network size, in 1669 * the long term. 1670 */ 1671 isc_result_t 1672 create_prefix6(struct ipv6_pool *pool, struct iasubopt **pref, 1673 unsigned int *attempts, 1674 const struct data_string *uid, 1675 time_t soft_lifetime_end_time) { 1676 struct data_string ds; 1677 struct in6_addr tmp; 1678 struct iasubopt *test_iapref; 1679 struct data_string new_ds; 1680 struct iasubopt *iapref; 1681 isc_result_t result; 1682 1683 /* 1684 * Use the UID as our initial seed for the hash 1685 */ 1686 memset(&ds, 0, sizeof(ds)); 1687 data_string_copy(&ds, (struct data_string *)uid, MDL); 1688 1689 *attempts = 0; 1690 for (;;) { 1691 /* 1692 * Give up at some point. 1693 */ 1694 if (++(*attempts) > 10) { 1695 data_string_forget(&ds, MDL); 1696 return ISC_R_NORESOURCES; 1697 } 1698 1699 /* 1700 * Build a prefix 1701 */ 1702 build_prefix6(&tmp, &pool->start_addr, 1703 pool->bits, pool->units, &ds); 1704 1705 /* 1706 * If this prefix is not in use, we're happy with it 1707 */ 1708 test_iapref = NULL; 1709 if (iasubopt_hash_lookup(&test_iapref, pool->leases, 1710 &tmp, sizeof(tmp), MDL) == 0) { 1711 break; 1712 } 1713 iasubopt_dereference(&test_iapref, MDL); 1714 1715 /* 1716 * Otherwise, we create a new input, adding the prefix 1717 */ 1718 memset(&new_ds, 0, sizeof(new_ds)); 1719 new_ds.len = ds.len + sizeof(tmp); 1720 if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) { 1721 data_string_forget(&ds, MDL); 1722 return ISC_R_NOMEMORY; 1723 } 1724 new_ds.data = new_ds.buffer->data; 1725 memcpy(new_ds.buffer->data, ds.data, ds.len); 1726 memcpy(new_ds.buffer->data + ds.len, &tmp, sizeof(tmp)); 1727 data_string_forget(&ds, MDL); 1728 data_string_copy(&ds, &new_ds, MDL); 1729 data_string_forget(&new_ds, MDL); 1730 } 1731 1732 data_string_forget(&ds, MDL); 1733 1734 /* 1735 * We're happy with the prefix, create an IAPREFIX 1736 * to hold it. 1737 */ 1738 iapref = NULL; 1739 result = iasubopt_allocate(&iapref, MDL); 1740 if (result != ISC_R_SUCCESS) { 1741 return result; 1742 } 1743 iapref->plen = (u_int8_t)pool->units; 1744 memcpy(&iapref->addr, &tmp, sizeof(iapref->addr)); 1745 1746 /* 1747 * Add the prefix to the pool (note state is free, not active?!). 1748 */ 1749 result = add_lease6(pool, iapref, soft_lifetime_end_time); 1750 if (result == ISC_R_SUCCESS) { 1751 iasubopt_reference(pref, iapref, MDL); 1752 } 1753 iasubopt_dereference(&iapref, MDL); 1754 return result; 1755 } 1756 1757 /* 1758 * Determine if a prefix is present in a pool or not. 1759 */ 1760 isc_boolean_t 1761 prefix6_exists(const struct ipv6_pool *pool, 1762 const struct in6_addr *pref, u_int8_t plen) { 1763 struct iasubopt *test_iapref; 1764 1765 if ((int)plen != pool->units) 1766 return ISC_FALSE; 1767 1768 test_iapref = NULL; 1769 if (iasubopt_hash_lookup(&test_iapref, pool->leases, 1770 (void *)pref, sizeof(*pref), MDL)) { 1771 iasubopt_dereference(&test_iapref, MDL); 1772 return ISC_TRUE; 1773 } else { 1774 return ISC_FALSE; 1775 } 1776 } 1777 1778 /* 1779 * Mark an IPv6 address/prefix as unavailable from a pool. 1780 * 1781 * This is used for host entries and the addresses of the server itself. 1782 */ 1783 static isc_result_t 1784 mark_lease_unavailable(struct ipv6_pool *pool, const struct in6_addr *addr) { 1785 struct iasubopt *dummy_iasubopt; 1786 isc_result_t result; 1787 1788 dummy_iasubopt = NULL; 1789 result = iasubopt_allocate(&dummy_iasubopt, MDL); 1790 if (result == ISC_R_SUCCESS) { 1791 dummy_iasubopt->addr = *addr; 1792 iasubopt_hash_add(pool->leases, &dummy_iasubopt->addr, 1793 sizeof(*addr), dummy_iasubopt, MDL); 1794 } 1795 return result; 1796 } 1797 1798 /* 1799 * Add a pool. 1800 */ 1801 isc_result_t 1802 add_ipv6_pool(struct ipv6_pool *pool) { 1803 struct ipv6_pool **new_pools; 1804 1805 new_pools = dmalloc(sizeof(struct ipv6_pool *) * (num_pools+1), MDL); 1806 if (new_pools == NULL) { 1807 return ISC_R_NOMEMORY; 1808 } 1809 1810 if (num_pools > 0) { 1811 memcpy(new_pools, pools, 1812 sizeof(struct ipv6_pool *) * num_pools); 1813 dfree(pools, MDL); 1814 } 1815 pools = new_pools; 1816 1817 pools[num_pools] = NULL; 1818 ipv6_pool_reference(&pools[num_pools], pool, MDL); 1819 num_pools++; 1820 return ISC_R_SUCCESS; 1821 } 1822 1823 static void 1824 cleanup_old_expired(struct ipv6_pool *pool) { 1825 struct iasubopt *tmp; 1826 struct ia_xx *ia; 1827 struct ia_xx *ia_active; 1828 unsigned char *tmpd; 1829 time_t timeout; 1830 1831 while (pool->num_inactive > 0) { 1832 tmp = (struct iasubopt *) 1833 isc_heap_element(pool->inactive_timeouts, 1); 1834 if (tmp->hard_lifetime_end_time != 0) { 1835 timeout = tmp->hard_lifetime_end_time; 1836 timeout += EXPIRED_IPV6_CLEANUP_TIME; 1837 } else { 1838 timeout = tmp->soft_lifetime_end_time; 1839 } 1840 if (cur_time < timeout) { 1841 break; 1842 } 1843 1844 isc_heap_delete(pool->inactive_timeouts, tmp->heap_index); 1845 pool->num_inactive--; 1846 1847 if (tmp->ia != NULL) { 1848 /* 1849 * Check to see if this IA is in an active list, 1850 * but has no remaining resources. If so, remove it 1851 * from the active list. 1852 */ 1853 ia = NULL; 1854 ia_reference(&ia, tmp->ia, MDL); 1855 ia_remove_iasubopt(ia, tmp, MDL); 1856 ia_active = NULL; 1857 tmpd = (unsigned char *)ia->iaid_duid.data; 1858 if ((ia->ia_type == D6O_IA_NA) && 1859 (ia->num_iasubopt <= 0) && 1860 (ia_hash_lookup(&ia_active, ia_na_active, tmpd, 1861 ia->iaid_duid.len, MDL) == 0) && 1862 (ia_active == ia)) { 1863 ia_hash_delete(ia_na_active, tmpd, 1864 ia->iaid_duid.len, MDL); 1865 } 1866 if ((ia->ia_type == D6O_IA_TA) && 1867 (ia->num_iasubopt <= 0) && 1868 (ia_hash_lookup(&ia_active, ia_ta_active, tmpd, 1869 ia->iaid_duid.len, MDL) == 0) && 1870 (ia_active == ia)) { 1871 ia_hash_delete(ia_ta_active, tmpd, 1872 ia->iaid_duid.len, MDL); 1873 } 1874 if ((ia->ia_type == D6O_IA_PD) && 1875 (ia->num_iasubopt <= 0) && 1876 (ia_hash_lookup(&ia_active, ia_pd_active, tmpd, 1877 ia->iaid_duid.len, MDL) == 0) && 1878 (ia_active == ia)) { 1879 ia_hash_delete(ia_pd_active, tmpd, 1880 ia->iaid_duid.len, MDL); 1881 } 1882 ia_dereference(&ia, MDL); 1883 } 1884 iasubopt_dereference(&tmp, MDL); 1885 } 1886 } 1887 1888 static void 1889 lease_timeout_support(void *vpool) { 1890 struct ipv6_pool *pool; 1891 struct iasubopt *lease; 1892 1893 pool = (struct ipv6_pool *)vpool; 1894 for (;;) { 1895 /* 1896 * Get the next lease scheduled to expire. 1897 * 1898 * Note that if there are no leases in the pool, 1899 * expire_lease6() will return ISC_R_SUCCESS with 1900 * a NULL lease. 1901 * 1902 * expire_lease6() will call move_lease_to_inactive() which 1903 * calls ddns_removals() do we want that on the standard 1904 * expiration timer or a special 'depref' timer? Original 1905 * query from DH, moved here by SAR. 1906 */ 1907 lease = NULL; 1908 if (expire_lease6(&lease, pool, cur_time) != ISC_R_SUCCESS) { 1909 break; 1910 } 1911 if (lease == NULL) { 1912 break; 1913 } 1914 1915 write_ia(lease->ia); 1916 1917 iasubopt_dereference(&lease, MDL); 1918 } 1919 1920 /* 1921 * If appropriate commit and rotate the lease file 1922 * As commit_leases_timed() checks to see if we've done any writes 1923 * we don't bother tracking if this function called write _ia 1924 */ 1925 (void) commit_leases_timed(); 1926 1927 /* 1928 * Do some cleanup of our expired leases. 1929 */ 1930 cleanup_old_expired(pool); 1931 1932 /* 1933 * Schedule next round of expirations. 1934 */ 1935 schedule_lease_timeout(pool); 1936 } 1937 1938 /* 1939 * For a given pool, add a timer that will remove the next 1940 * lease to expire. 1941 */ 1942 void 1943 schedule_lease_timeout(struct ipv6_pool *pool) { 1944 struct iasubopt *tmp; 1945 time_t timeout; 1946 time_t next_timeout; 1947 struct timeval tv; 1948 1949 next_timeout = MAX_TIME; 1950 1951 if (pool->num_active > 0) { 1952 tmp = (struct iasubopt *) 1953 isc_heap_element(pool->active_timeouts, 1); 1954 if (tmp->hard_lifetime_end_time < next_timeout) { 1955 next_timeout = tmp->hard_lifetime_end_time + 1; 1956 } 1957 } 1958 1959 if (pool->num_inactive > 0) { 1960 tmp = (struct iasubopt *) 1961 isc_heap_element(pool->inactive_timeouts, 1); 1962 if (tmp->hard_lifetime_end_time != 0) { 1963 timeout = tmp->hard_lifetime_end_time; 1964 timeout += EXPIRED_IPV6_CLEANUP_TIME; 1965 } else { 1966 timeout = tmp->soft_lifetime_end_time + 1; 1967 } 1968 if (timeout < next_timeout) { 1969 next_timeout = timeout; 1970 } 1971 } 1972 1973 if (next_timeout < MAX_TIME) { 1974 tv.tv_sec = next_timeout; 1975 tv.tv_usec = 0; 1976 add_timeout(&tv, lease_timeout_support, pool, 1977 (tvref_t)ipv6_pool_reference, 1978 (tvunref_t)ipv6_pool_dereference); 1979 } 1980 } 1981 1982 /* 1983 * Schedule timeouts across all pools. 1984 */ 1985 void 1986 schedule_all_ipv6_lease_timeouts(void) { 1987 int i; 1988 1989 for (i=0; i<num_pools; i++) { 1990 schedule_lease_timeout(pools[i]); 1991 } 1992 } 1993 1994 /* 1995 * Given an address and the length of the network mask, return 1996 * only the network portion. 1997 * 1998 * Examples: 1999 * 2000 * "fe80::216:6fff:fe49:7d9b", length 64 = "fe80::" 2001 * "2001:888:1936:2:216:6fff:fe49:7d9b", length 48 = "2001:888:1936::" 2002 */ 2003 static void 2004 ipv6_network_portion(struct in6_addr *result, 2005 const struct in6_addr *addr, int bits) { 2006 unsigned char *addrp; 2007 int mask_bits; 2008 int bytes; 2009 int extra_bits; 2010 int i; 2011 2012 static const unsigned char bitmasks[] = { 2013 0x00, 0xFE, 0xFC, 0xF8, 2014 0xF0, 0xE0, 0xC0, 0x80, 2015 }; 2016 2017 /* 2018 * Sanity check our bits. ;) 2019 */ 2020 if ((bits < 0) || (bits > 128)) { 2021 log_fatal("ipv6_network_portion: bits %d not between 0 and 128", 2022 bits); 2023 } 2024 2025 /* 2026 * Copy our address portion. 2027 */ 2028 *result = *addr; 2029 addrp = ((unsigned char *)result) + 15; 2030 2031 /* 2032 * Zero out masked portion. 2033 */ 2034 mask_bits = 128 - bits; 2035 bytes = mask_bits / 8; 2036 extra_bits = mask_bits % 8; 2037 2038 for (i=0; i<bytes; i++) { 2039 *addrp = 0; 2040 addrp--; 2041 } 2042 if (extra_bits) { 2043 *addrp &= bitmasks[extra_bits]; 2044 } 2045 } 2046 2047 /* 2048 * Determine if the given address/prefix is in the pool. 2049 */ 2050 isc_boolean_t 2051 ipv6_in_pool(const struct in6_addr *addr, const struct ipv6_pool *pool) { 2052 struct in6_addr tmp; 2053 2054 ipv6_network_portion(&tmp, addr, pool->bits); 2055 if (memcmp(&tmp, &pool->start_addr, sizeof(tmp)) == 0) { 2056 return ISC_TRUE; 2057 } else { 2058 return ISC_FALSE; 2059 } 2060 } 2061 2062 /* 2063 * Find the pool that contains the given address. 2064 * 2065 * - pool must be a pointer to a (struct ipv6_pool *) pointer previously 2066 * initialized to NULL 2067 */ 2068 isc_result_t 2069 find_ipv6_pool(struct ipv6_pool **pool, u_int16_t type, 2070 const struct in6_addr *addr) { 2071 int i; 2072 2073 if (pool == NULL) { 2074 log_error("%s(%d): NULL pointer reference", MDL); 2075 return DHCP_R_INVALIDARG; 2076 } 2077 if (*pool != NULL) { 2078 log_error("%s(%d): non-NULL pointer", MDL); 2079 return DHCP_R_INVALIDARG; 2080 } 2081 2082 for (i=0; i<num_pools; i++) { 2083 if (pools[i]->pool_type != type) 2084 continue; 2085 if (ipv6_in_pool(addr, pools[i])) { 2086 ipv6_pool_reference(pool, pools[i], MDL); 2087 return ISC_R_SUCCESS; 2088 } 2089 } 2090 return ISC_R_NOTFOUND; 2091 } 2092 2093 /* 2094 * Helper function for the various functions that act across all 2095 * pools. 2096 */ 2097 static isc_result_t 2098 change_leases(struct ia_xx *ia, 2099 isc_result_t (*change_func)(struct ipv6_pool *, 2100 struct iasubopt *)) { 2101 isc_result_t retval; 2102 isc_result_t renew_retval; 2103 struct ipv6_pool *pool; 2104 struct in6_addr *addr; 2105 int i; 2106 2107 retval = ISC_R_SUCCESS; 2108 for (i=0; i<ia->num_iasubopt; i++) { 2109 pool = NULL; 2110 addr = &ia->iasubopt[i]->addr; 2111 if (find_ipv6_pool(&pool, ia->ia_type, 2112 addr) == ISC_R_SUCCESS) { 2113 renew_retval = change_func(pool, ia->iasubopt[i]); 2114 if (renew_retval != ISC_R_SUCCESS) { 2115 retval = renew_retval; 2116 } 2117 } 2118 /* XXXsk: should we warn if we don't find a pool? */ 2119 } 2120 return retval; 2121 } 2122 2123 /* 2124 * Renew all leases in an IA from all pools. 2125 * 2126 * The new lifetime should be in the soft_lifetime_end_time 2127 * and will be moved to hard_lifetime_end_time by renew_lease6. 2128 */ 2129 isc_result_t 2130 renew_leases(struct ia_xx *ia) { 2131 return change_leases(ia, renew_lease6); 2132 } 2133 2134 /* 2135 * Release all leases in an IA from all pools. 2136 */ 2137 isc_result_t 2138 release_leases(struct ia_xx *ia) { 2139 return change_leases(ia, release_lease6); 2140 } 2141 2142 /* 2143 * Decline all leases in an IA from all pools. 2144 */ 2145 isc_result_t 2146 decline_leases(struct ia_xx *ia) { 2147 return change_leases(ia, decline_lease6); 2148 } 2149 2150 #ifdef DHCPv6 2151 /* 2152 * Helper function to output leases. 2153 */ 2154 static int write_error; 2155 2156 static isc_result_t 2157 write_ia_leases(const void *name, unsigned len, void *value) { 2158 struct ia_xx *ia = (struct ia_xx *)value; 2159 2160 if (!write_error) { 2161 if (!write_ia(ia)) { 2162 write_error = 1; 2163 } 2164 } 2165 return ISC_R_SUCCESS; 2166 } 2167 2168 /* 2169 * Write all DHCPv6 information. 2170 */ 2171 int 2172 write_leases6(void) { 2173 int nas, tas, pds; 2174 2175 write_error = 0; 2176 write_server_duid(); 2177 nas = ia_hash_foreach(ia_na_active, write_ia_leases); 2178 if (write_error) { 2179 return 0; 2180 } 2181 tas = ia_hash_foreach(ia_ta_active, write_ia_leases); 2182 if (write_error) { 2183 return 0; 2184 } 2185 pds = ia_hash_foreach(ia_pd_active, write_ia_leases); 2186 if (write_error) { 2187 return 0; 2188 } 2189 2190 log_info("Wrote %d NA, %d TA, %d PD leases to lease file.", 2191 nas, tas, pds); 2192 return 1; 2193 } 2194 #endif /* DHCPv6 */ 2195 2196 static isc_result_t 2197 mark_hosts_unavailable_support(const void *name, unsigned len, void *value) { 2198 struct host_decl *h; 2199 struct data_string fixed_addr; 2200 struct in6_addr addr; 2201 struct ipv6_pool *p; 2202 2203 h = (struct host_decl *)value; 2204 2205 /* 2206 * If the host has no address, we don't need to mark anything. 2207 */ 2208 if (h->fixed_addr == NULL) { 2209 return ISC_R_SUCCESS; 2210 } 2211 2212 /* 2213 * Evaluate the fixed address. 2214 */ 2215 memset(&fixed_addr, 0, sizeof(fixed_addr)); 2216 if (!evaluate_option_cache(&fixed_addr, NULL, NULL, NULL, NULL, NULL, 2217 &global_scope, h->fixed_addr, MDL)) { 2218 log_error("mark_hosts_unavailable: " 2219 "error evaluating host address."); 2220 return ISC_R_SUCCESS; 2221 } 2222 if (fixed_addr.len != 16) { 2223 log_error("mark_hosts_unavailable: " 2224 "host address is not 128 bits."); 2225 return ISC_R_SUCCESS; 2226 } 2227 memcpy(&addr, fixed_addr.data, 16); 2228 data_string_forget(&fixed_addr, MDL); 2229 2230 /* 2231 * Find the pool holding this host, and mark the address. 2232 * (I suppose it is arguably valid to have a host that does not 2233 * sit in any pool.) 2234 */ 2235 p = NULL; 2236 if (find_ipv6_pool(&p, D6O_IA_NA, &addr) == ISC_R_SUCCESS) { 2237 mark_lease_unavailable(p, &addr); 2238 ipv6_pool_dereference(&p, MDL); 2239 } 2240 if (find_ipv6_pool(&p, D6O_IA_TA, &addr) == ISC_R_SUCCESS) { 2241 mark_lease_unavailable(p, &addr); 2242 ipv6_pool_dereference(&p, MDL); 2243 } 2244 2245 return ISC_R_SUCCESS; 2246 } 2247 2248 void 2249 mark_hosts_unavailable(void) { 2250 hash_foreach(host_name_hash, mark_hosts_unavailable_support); 2251 } 2252 2253 static isc_result_t 2254 mark_phosts_unavailable_support(const void *name, unsigned len, void *value) { 2255 struct host_decl *h; 2256 struct iaddrcidrnetlist *l; 2257 struct in6_addr pref; 2258 struct ipv6_pool *p; 2259 2260 h = (struct host_decl *)value; 2261 2262 /* 2263 * If the host has no prefix, we don't need to mark anything. 2264 */ 2265 if (h->fixed_prefix == NULL) { 2266 return ISC_R_SUCCESS; 2267 } 2268 2269 /* 2270 * Get the fixed prefixes. 2271 */ 2272 for (l = h->fixed_prefix; l != NULL; l = l->next) { 2273 if (l->cidrnet.lo_addr.len != 16) { 2274 continue; 2275 } 2276 memcpy(&pref, l->cidrnet.lo_addr.iabuf, 16); 2277 2278 /* 2279 * Find the pool holding this host, and mark the prefix. 2280 * (I suppose it is arguably valid to have a host that does not 2281 * sit in any pool.) 2282 */ 2283 p = NULL; 2284 if (find_ipv6_pool(&p, D6O_IA_PD, &pref) != ISC_R_SUCCESS) { 2285 continue; 2286 } 2287 if (l->cidrnet.bits != p->units) { 2288 ipv6_pool_dereference(&p, MDL); 2289 continue; 2290 } 2291 mark_lease_unavailable(p, &pref); 2292 ipv6_pool_dereference(&p, MDL); 2293 } 2294 2295 return ISC_R_SUCCESS; 2296 } 2297 2298 void 2299 mark_phosts_unavailable(void) { 2300 hash_foreach(host_name_hash, mark_phosts_unavailable_support); 2301 } 2302 2303 void 2304 mark_interfaces_unavailable(void) { 2305 struct interface_info *ip; 2306 int i; 2307 struct ipv6_pool *p; 2308 2309 ip = interfaces; 2310 while (ip != NULL) { 2311 for (i=0; i<ip->v6address_count; i++) { 2312 p = NULL; 2313 if (find_ipv6_pool(&p, D6O_IA_NA, &ip->v6addresses[i]) 2314 == ISC_R_SUCCESS) { 2315 mark_lease_unavailable(p, 2316 &ip->v6addresses[i]); 2317 ipv6_pool_dereference(&p, MDL); 2318 } 2319 if (find_ipv6_pool(&p, D6O_IA_TA, &ip->v6addresses[i]) 2320 == ISC_R_SUCCESS) { 2321 mark_lease_unavailable(p, 2322 &ip->v6addresses[i]); 2323 ipv6_pool_dereference(&p, MDL); 2324 } 2325 } 2326 ip = ip->next; 2327 } 2328 } 2329 2330 /*! 2331 * \brief Create a new IPv6 pond structure. 2332 * 2333 * Allocate space for a new ipv6_pond structure and return a reference 2334 * to it, includes setting the reference count to 1. 2335 * 2336 * \param pond = space for returning a referenced pointer to the pond. 2337 * This must point to a space that has been initialzied 2338 * to NULL by the caller. 2339 * 2340 * \return 2341 * ISC_R_SUCCESS = The pond was successfully created, pond points to it. 2342 * DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been 2343 * modified 2344 * ISC_R_NOMEMORY = The system wasn't able to allocate memory, pond has 2345 * not been modified. 2346 */ 2347 isc_result_t 2348 ipv6_pond_allocate(struct ipv6_pond **pond, const char *file, int line) { 2349 struct ipv6_pond *tmp; 2350 2351 if (pond == NULL) { 2352 log_error("%s(%d): NULL pointer reference", file, line); 2353 return DHCP_R_INVALIDARG; 2354 } 2355 if (*pond != NULL) { 2356 log_error("%s(%d): non-NULL pointer", file, line); 2357 return DHCP_R_INVALIDARG; 2358 } 2359 2360 tmp = dmalloc(sizeof(*tmp), file, line); 2361 if (tmp == NULL) { 2362 return ISC_R_NOMEMORY; 2363 } 2364 2365 tmp->refcnt = 1; 2366 2367 *pond = tmp; 2368 return ISC_R_SUCCESS; 2369 } 2370 2371 /*! 2372 * 2373 * \brief reference an IPv6 pond structure. 2374 * 2375 * This function genreates a reference to an ipv6_pond structure 2376 * and increments the reference count on the structure. 2377 * 2378 * \param[out] pond = space for returning a referenced pointer to the pond. 2379 * This must point to a space that has been initialzied 2380 * to NULL by the caller. 2381 * \param[in] src = A pointer to the pond to reference. This must not be 2382 * NULL. 2383 * 2384 * \return 2385 * ISC_R_SUCCESS = The pond was successfully referenced, pond now points 2386 * to src. 2387 * DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been 2388 * modified. 2389 */ 2390 isc_result_t 2391 ipv6_pond_reference(struct ipv6_pond **pond, struct ipv6_pond *src, 2392 const char *file, int line) { 2393 if (pond == NULL) { 2394 log_error("%s(%d): NULL pointer reference", file, line); 2395 return DHCP_R_INVALIDARG; 2396 } 2397 if (*pond != NULL) { 2398 log_error("%s(%d): non-NULL pointer", file, line); 2399 return DHCP_R_INVALIDARG; 2400 } 2401 if (src == NULL) { 2402 log_error("%s(%d): NULL pointer reference", file, line); 2403 return DHCP_R_INVALIDARG; 2404 } 2405 *pond = src; 2406 src->refcnt++; 2407 return ISC_R_SUCCESS; 2408 } 2409 2410 /*! 2411 * 2412 * \brief de-reference an IPv6 pond structure. 2413 * 2414 * This function decrements the reference count in an ipv6_pond structure. 2415 * If this was the last reference then the memory for the structure is 2416 * freed. 2417 * 2418 * \param[in] pond = A pointer to the pointer to the pond that should be 2419 * de-referenced. On success the pointer to the pond 2420 * is cleared. It must not be NULL and must not point 2421 * to NULL. 2422 * 2423 * \return 2424 * ISC_R_SUCCESS = The pond was successfully de-referenced, pond now points 2425 * to NULL 2426 * DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been 2427 * modified. 2428 */ 2429 2430 isc_result_t 2431 ipv6_pond_dereference(struct ipv6_pond **pond, const char *file, int line) { 2432 struct ipv6_pond *tmp; 2433 2434 if ((pond == NULL) || (*pond == NULL)) { 2435 log_error("%s(%d): NULL pointer", file, line); 2436 return DHCP_R_INVALIDARG; 2437 } 2438 2439 tmp = *pond; 2440 *pond = NULL; 2441 2442 tmp->refcnt--; 2443 if (tmp->refcnt < 0) { 2444 log_error("%s(%d): negative refcnt", file, line); 2445 tmp->refcnt = 0; 2446 } 2447 if (tmp->refcnt == 0) { 2448 dfree(tmp, file, line); 2449 } 2450 2451 return ISC_R_SUCCESS; 2452 } 2453 2454 /* unittest moved to server/tests/mdb6_unittest.c */ 2455