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