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>