]>
Commit | Line | Data |
---|---|---|
98bd7ca0 DH |
1 | /* |
2 | * Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC") | |
3 | * | |
4 | * Permission to use, copy, modify, and distribute this software for any | |
5 | * purpose with or without fee is hereby granted, provided that the above | |
6 | * copyright notice and this permission notice appear in all copies. | |
7 | * | |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH | |
9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | |
10 | * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, | |
11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | |
12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE | |
13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | |
14 | * PERFORMANCE OF THIS SOFTWARE. | |
15 | */ | |
16 | ||
17 | /* TODO: assert() */ | |
18 | /* TODO: simplify functions, as pool is now in iaaddr */ | |
19 | ||
99fe695e | 20 | #include <sys/types.h> |
98bd7ca0 DH |
21 | #include <time.h> |
22 | #include <netinet/in.h> | |
23 | ||
24 | #include "isc-dhcp/result.h" | |
25 | ||
26 | #include <stdarg.h> | |
98bd7ca0 | 27 | #include "dhcpd.h" |
6705543f | 28 | #include "omapip/omapip.h" |
98bd7ca0 DH |
29 | #include "omapip/hash.h" |
30 | #include "dst/md5.h" | |
31 | ||
32 | HASH_FUNCTIONS(ia_na, unsigned char *, struct ia_na, ia_na_hash_t, | |
33 | ia_na_reference, ia_na_dereference, do_string_hash); | |
34 | ||
35 | ia_na_hash_t *ia_active; | |
36 | ||
37 | HASH_FUNCTIONS(iaaddr, struct in6_addr *, struct iaaddr, iaaddr_hash_t, | |
38 | ia_na_reference, ia_na_dereference, do_string_hash); | |
39 | ||
40 | struct ipv6_pool **pools; | |
41 | int num_pools; | |
42 | ||
43 | /* | |
44 | * Create a new IAADDR structure. | |
45 | * | |
46 | * - iaaddr must be a pointer to a (struct iaaddr *) pointer previously | |
47 | * initialized to NULL | |
48 | */ | |
49 | isc_result_t | |
50 | iaaddr_allocate(struct iaaddr **iaaddr, const char *file, int line) { | |
51 | struct iaaddr *tmp; | |
52 | ||
53 | if (iaaddr == NULL) { | |
54 | log_error("%s(%d): NULL pointer reference", file, line); | |
55 | return ISC_R_INVALIDARG; | |
56 | } | |
57 | if (*iaaddr != NULL) { | |
58 | log_error("%s(%d): non-NULL pointer", file, line); | |
59 | return ISC_R_INVALIDARG; | |
60 | } | |
61 | ||
62 | tmp = dmalloc(sizeof(*tmp), file, line); | |
63 | if (tmp == NULL) { | |
64 | return ISC_R_NOMEMORY; | |
65 | } | |
66 | ||
67 | tmp->refcnt = 1; | |
68 | tmp->state = FTS_FREE; | |
69 | tmp->heap_index = -1; | |
70 | ||
71 | *iaaddr = tmp; | |
72 | return ISC_R_SUCCESS; | |
73 | } | |
74 | ||
75 | /* | |
76 | * Reference an IAADDR structure. | |
77 | * | |
78 | * - iaaddr must be a pointer to a (struct iaaddr *) pointer previously | |
79 | * initialized to NULL | |
80 | */ | |
81 | isc_result_t | |
82 | iaaddr_reference(struct iaaddr **iaaddr, struct iaaddr *src, | |
83 | const char *file, int line) { | |
84 | if (iaaddr == NULL) { | |
85 | log_error("%s(%d): NULL pointer reference", file, line); | |
86 | return ISC_R_INVALIDARG; | |
87 | } | |
88 | if (*iaaddr != NULL) { | |
89 | log_error("%s(%d): non-NULL pointer", file, line); | |
90 | return ISC_R_INVALIDARG; | |
91 | } | |
92 | if (src == NULL) { | |
93 | log_error("%s(%d): NULL pointer reference", file, line); | |
94 | return ISC_R_INVALIDARG; | |
95 | } | |
96 | *iaaddr = src; | |
97 | src->refcnt++; | |
98 | return ISC_R_SUCCESS; | |
99 | } | |
100 | ||
101 | ||
102 | /* | |
103 | * Dereference an IAADDR structure. | |
104 | * | |
105 | * If it is the last reference, then the memory for the | |
106 | * structure is freed. | |
107 | */ | |
108 | isc_result_t | |
109 | iaaddr_dereference(struct iaaddr **iaaddr, const char *file, int line) { | |
110 | struct iaaddr *tmp; | |
111 | ||
112 | if ((iaaddr == NULL) || (*iaaddr == NULL)) { | |
113 | log_error("%s(%d): NULL pointer", file, line); | |
114 | return ISC_R_INVALIDARG; | |
115 | } | |
116 | ||
117 | tmp = *iaaddr; | |
118 | *iaaddr = NULL; | |
119 | ||
120 | tmp->refcnt--; | |
121 | if (tmp->refcnt < 0) { | |
122 | log_error("%s(%d): negative refcnt", file, line); | |
123 | tmp->refcnt = 0; | |
124 | } | |
125 | if (tmp->refcnt == 0) { | |
126 | if (tmp->ia_na != NULL) { | |
127 | ia_na_dereference(&(tmp->ia_na), file, line); | |
128 | } | |
129 | if (tmp->ipv6_pool != NULL) { | |
130 | ipv6_pool_dereference(&(tmp->ipv6_pool), file, line); | |
131 | } | |
132 | if (tmp->scope != NULL) { | |
133 | binding_scope_dereference(&tmp->scope, file, line); | |
134 | } | |
135 | dfree(tmp, file, line); | |
136 | } | |
137 | ||
138 | return ISC_R_SUCCESS; | |
139 | } | |
140 | ||
141 | /* | |
142 | * Make the key that we use for IA_NA. | |
143 | */ | |
144 | isc_result_t | |
145 | ia_na_make_key(struct data_string *key, u_int32_t iaid, | |
146 | const char *duid, unsigned int duid_len, | |
147 | const char *file, int line) { | |
148 | ||
149 | memset(key, 0, sizeof(*key)); | |
150 | key->len = duid_len + sizeof(iaid); | |
151 | if (!buffer_allocate(&(key->buffer), key->len, file, line)) { | |
152 | return ISC_R_NOMEMORY; | |
153 | } | |
154 | key->data = key->buffer->data; | |
155 | memcpy((char *)key->data, &iaid, sizeof(iaid)); | |
156 | memcpy((char *)key->data + sizeof(iaid), duid, duid_len); | |
157 | ||
158 | return ISC_R_SUCCESS; | |
159 | } | |
160 | ||
161 | /* | |
162 | * Create a new IA_NA structure. | |
163 | * | |
164 | * - ia_na must be a pointer to a (struct ia_na *) pointer previously | |
165 | * initialized to NULL | |
166 | * - iaid and duid are values from the client | |
167 | * | |
168 | * XXXsk: we don't concern ourself with the byte order of the IAID, | |
169 | * which might be a problem if we transfer this structure | |
170 | * between machines of different byte order | |
171 | */ | |
172 | isc_result_t | |
173 | ia_na_allocate(struct ia_na **ia_na, u_int32_t iaid, | |
174 | const char *duid, unsigned int duid_len, | |
175 | const char *file, int line) { | |
176 | struct ia_na *tmp; | |
177 | ||
178 | if (ia_na == NULL) { | |
179 | log_error("%s(%d): NULL pointer reference", file, line); | |
180 | return ISC_R_INVALIDARG; | |
181 | } | |
182 | if (*ia_na != NULL) { | |
183 | log_error("%s(%d): non-NULL pointer", file, line); | |
184 | return ISC_R_INVALIDARG; | |
185 | } | |
186 | ||
187 | tmp = dmalloc(sizeof(*tmp), file, line); | |
188 | if (tmp == NULL) { | |
189 | return ISC_R_NOMEMORY; | |
190 | } | |
191 | ||
192 | if (ia_na_make_key(&tmp->iaid_duid, iaid, | |
193 | duid, duid_len, file, line) != ISC_R_SUCCESS) { | |
194 | dfree(tmp, file, line); | |
195 | return ISC_R_NOMEMORY; | |
196 | } | |
197 | ||
198 | tmp->refcnt = 1; | |
199 | ||
200 | *ia_na = tmp; | |
201 | return ISC_R_SUCCESS; | |
202 | } | |
203 | ||
204 | /* | |
205 | * Reference an IA_NA structure. | |
206 | * | |
207 | * - ia_na must be a pointer to a (struct ia_na *) pointer previously | |
208 | * initialized to NULL | |
209 | */ | |
210 | isc_result_t | |
211 | ia_na_reference(struct ia_na **ia_na, struct ia_na *src, | |
212 | const char *file, int line) { | |
213 | if (ia_na == NULL) { | |
214 | log_error("%s(%d): NULL pointer reference", file, line); | |
215 | return ISC_R_INVALIDARG; | |
216 | } | |
217 | if (*ia_na != NULL) { | |
218 | log_error("%s(%d): non-NULL pointer", file, line); | |
219 | return ISC_R_INVALIDARG; | |
220 | } | |
221 | if (src == NULL) { | |
222 | log_error("%s(%d): NULL pointer reference", file, line); | |
223 | return ISC_R_INVALIDARG; | |
224 | } | |
225 | *ia_na = src; | |
226 | src->refcnt++; | |
227 | return ISC_R_SUCCESS; | |
228 | } | |
229 | ||
230 | /* | |
231 | * Dereference an IA_NA structure. | |
232 | * | |
233 | * If it is the last reference, then the memory for the | |
234 | * structure is freed. | |
235 | */ | |
236 | isc_result_t | |
237 | ia_na_dereference(struct ia_na **ia_na, const char *file, int line) { | |
238 | struct ia_na *tmp; | |
239 | int i; | |
240 | ||
241 | if ((ia_na == NULL) || (*ia_na == NULL)) { | |
242 | log_error("%s(%d): NULL pointer", file, line); | |
243 | return ISC_R_INVALIDARG; | |
244 | } | |
245 | ||
246 | tmp = *ia_na; | |
247 | *ia_na = NULL; | |
248 | ||
249 | tmp->refcnt--; | |
250 | if (tmp->refcnt < 0) { | |
251 | log_error("%s(%d): negative refcnt", file, line); | |
252 | tmp->refcnt = 0; | |
253 | } | |
254 | if (tmp->refcnt == 0) { | |
255 | if (tmp->iaaddr != NULL) { | |
256 | for (i=0; i<tmp->num_iaaddr; i++) { | |
257 | iaaddr_dereference(&(tmp->iaaddr[i]), | |
258 | file, line); | |
259 | } | |
260 | dfree(tmp->iaaddr, file, line); | |
261 | } | |
262 | data_string_forget(&(tmp->iaid_duid), file, line); | |
263 | dfree(tmp, file, line); | |
264 | } | |
265 | return ISC_R_SUCCESS; | |
266 | } | |
267 | ||
268 | ||
269 | /* | |
270 | * Add an IAADDR entry to an IA_NA structure. | |
271 | */ | |
272 | isc_result_t | |
273 | ia_na_add_iaaddr(struct ia_na *ia_na, struct iaaddr *iaaddr, | |
274 | const char *file, int line) { | |
275 | int max; | |
276 | struct iaaddr **new; | |
277 | ||
278 | /* | |
279 | * Grow our array if we need to. | |
280 | * | |
281 | * Note: we pick 4 as the increment, as that seems a reasonable | |
282 | * guess as to how many addresses we might expect on an | |
283 | * interface. | |
284 | */ | |
285 | if (ia_na->max_iaaddr <= ia_na->num_iaaddr) { | |
286 | max = ia_na->max_iaaddr + 4; | |
287 | new = dmalloc(max * sizeof(struct iaaddr *), file, line); | |
288 | if (new == NULL) { | |
289 | return ISC_R_NOMEMORY; | |
290 | } | |
291 | memcpy(new, ia_na->iaaddr, | |
292 | ia_na->num_iaaddr * sizeof(struct iaaddr *)); | |
293 | ia_na->iaaddr = new; | |
294 | ia_na->max_iaaddr = max; | |
295 | } | |
296 | ||
297 | iaaddr_reference(&(ia_na->iaaddr[ia_na->num_iaaddr]), iaaddr, | |
298 | file, line); | |
299 | ia_na->num_iaaddr++; | |
300 | ia_na_reference(&iaaddr->ia_na, ia_na, file, line); | |
301 | ||
302 | return ISC_R_SUCCESS; | |
303 | } | |
304 | ||
305 | /* | |
306 | * Remove an IAADDR entry to an IA_NA structure. | |
307 | * | |
308 | * Note: if an IAADDR appears more than once, then only ONE will be removed. | |
309 | */ | |
310 | void | |
311 | ia_na_remove_iaaddr(struct ia_na *ia_na, struct iaaddr *iaaddr, | |
312 | const char *file, int line) { | |
313 | int i, j; | |
314 | ||
315 | for (i=0; i<ia_na->num_iaaddr; i++) { | |
316 | if (ia_na->iaaddr[i] == iaaddr) { | |
317 | /* remove this IAADDR */ | |
318 | iaaddr_dereference(&(ia_na->iaaddr[i]), file, line); | |
319 | /* move remaining IAADDR pointers down one */ | |
320 | for (j=i+1; j < ia_na->num_iaaddr; j++) { | |
321 | ia_na->iaaddr[j-1] = ia_na->iaaddr[j]; | |
322 | } | |
323 | /* decrease our total count */ | |
d9b43370 SK |
324 | /* remove the back-reference in the IAADDR itself */ |
325 | ia_na_dereference(&iaaddr->ia_na, file, line); | |
98bd7ca0 DH |
326 | ia_na->num_iaaddr--; |
327 | return; | |
328 | } | |
329 | } | |
330 | log_error("%s(%d): IAADDR not in IA_NA", file, line); | |
331 | } | |
332 | ||
727cae26 | 333 | /* |
d9b43370 SK |
334 | * Remove all addresses from an IA_NA. |
335 | */ | |
336 | void | |
337 | ia_na_remove_all_iaaddr(struct ia_na *ia_na, const char *file, int line) { | |
338 | int i, j; | |
339 | ||
340 | for (i=0; i<ia_na->num_iaaddr; i++) { | |
341 | iaaddr_dereference(&(ia_na->iaaddr[i]), file, line); | |
342 | } | |
343 | ia_na->num_iaaddr = 0; | |
344 | } | |
345 | ||
98bd7ca0 DH |
346 | /* |
347 | * Helper function for lease heaps. | |
348 | * Makes the top of the heap the oldest lease. | |
349 | */ | |
350 | static isc_boolean_t | |
351 | lease_older(void *a, void *b) { | |
352 | struct iaaddr *ia = (struct iaaddr *)a; | |
353 | struct iaaddr *ib = (struct iaaddr *)b; | |
354 | ||
355 | return difftime(ia->valid_lifetime_end_time, | |
356 | ib->valid_lifetime_end_time) < 0; | |
357 | } | |
358 | ||
359 | /* | |
360 | * Helper function for lease heaps. | |
361 | * Callback when an address's position in the heap changes. | |
362 | */ | |
363 | static void | |
364 | lease_address_index_changed(void *iaaddr, unsigned int new_heap_index) { | |
365 | ((struct iaaddr *)iaaddr)-> heap_index = new_heap_index; | |
366 | } | |
367 | ||
368 | ||
369 | /* | |
370 | * Create a new IPv6 lease pool structure. | |
371 | * | |
372 | * - pool must be a pointer to a (struct ipv6_pool *) pointer previously | |
373 | * initialized to NULL | |
374 | */ | |
375 | isc_result_t | |
376 | ipv6_pool_allocate(struct ipv6_pool **pool, | |
377 | const struct in6_addr *start_addr, int bits, | |
378 | const char *file, int line) { | |
379 | struct ipv6_pool *tmp; | |
380 | ||
381 | if (pool == NULL) { | |
382 | log_error("%s(%d): NULL pointer reference", file, line); | |
383 | return ISC_R_INVALIDARG; | |
384 | } | |
385 | if (*pool != NULL) { | |
386 | log_error("%s(%d): non-NULL pointer", file, line); | |
387 | return ISC_R_INVALIDARG; | |
388 | } | |
389 | ||
390 | tmp = dmalloc(sizeof(*tmp), file, line); | |
391 | if (tmp == NULL) { | |
392 | return ISC_R_NOMEMORY; | |
393 | } | |
394 | ||
395 | tmp->refcnt = 1; | |
396 | tmp->start_addr = *start_addr; | |
397 | tmp->bits = bits; | |
398 | if (!iaaddr_new_hash(&tmp->addrs, DEFAULT_HASH_SIZE, file, line)) { | |
399 | dfree(tmp, file, line); | |
400 | return ISC_R_NOMEMORY; | |
401 | } | |
402 | if (isc_heap_create(lease_older, lease_address_index_changed, | |
403 | 0, &(tmp->active_timeouts)) != ISC_R_SUCCESS) { | |
404 | iaaddr_free_hash_table(&(tmp->addrs), file, line); | |
405 | dfree(tmp, file, line); | |
406 | return ISC_R_NOMEMORY; | |
407 | } | |
408 | if (isc_heap_create(lease_older, lease_address_index_changed, | |
409 | 0, &(tmp->inactive_timeouts)) != ISC_R_SUCCESS) { | |
410 | isc_heap_destroy(&(tmp->active_timeouts)); | |
411 | iaaddr_free_hash_table(&(tmp->addrs), file, line); | |
412 | dfree(tmp, file, line); | |
413 | return ISC_R_NOMEMORY; | |
414 | } | |
415 | ||
416 | *pool = tmp; | |
417 | return ISC_R_SUCCESS; | |
418 | } | |
419 | ||
420 | /* | |
421 | * Reference an IPv6 pool structure. | |
422 | * | |
423 | * - pool must be a pointer to a (struct pool *) pointer previously | |
424 | * initialized to NULL | |
425 | */ | |
426 | isc_result_t | |
427 | ipv6_pool_reference(struct ipv6_pool **pool, struct ipv6_pool *src, | |
428 | const char *file, int line) { | |
429 | if (pool == NULL) { | |
430 | log_error("%s(%d): NULL pointer reference", file, line); | |
431 | return ISC_R_INVALIDARG; | |
432 | } | |
433 | if (*pool != NULL) { | |
434 | log_error("%s(%d): non-NULL pointer", file, line); | |
435 | return ISC_R_INVALIDARG; | |
436 | } | |
437 | if (src == NULL) { | |
438 | log_error("%s(%d): NULL pointer reference", file, line); | |
439 | return ISC_R_INVALIDARG; | |
440 | } | |
441 | *pool = src; | |
442 | src->refcnt++; | |
443 | return ISC_R_SUCCESS; | |
444 | } | |
445 | ||
446 | /* | |
447 | * Note: Each IAADDR in a pool is referenced by the pool. This is needed | |
448 | * to prevent the IAADDR from being garbage collected out from under the | |
449 | * pool. | |
450 | * | |
451 | * The references are made from the hash and from the heap. The following | |
452 | * helper functions dereference these when a pool is destroyed. | |
453 | */ | |
454 | ||
455 | /* | |
456 | * Helper function for pool cleanup. | |
457 | * Dereference each of the hash entries in a pool. | |
458 | */ | |
459 | static isc_result_t | |
460 | dereference_hash_entry(const void *name, unsigned len, void *value) { | |
461 | struct iaaddr *iaaddr = (struct iaaddr *)value; | |
462 | ||
463 | iaaddr_dereference(&iaaddr, MDL); | |
464 | return ISC_R_SUCCESS; | |
465 | } | |
466 | ||
467 | /* | |
468 | * Helper function for pool cleanup. | |
469 | * Dereference each of the heap entries in a pool. | |
470 | */ | |
471 | static void | |
472 | dereference_heap_entry(void *value, void *dummy) { | |
473 | struct iaaddr *iaaddr = (struct iaaddr *)value; | |
474 | ||
475 | iaaddr_dereference(&iaaddr, MDL); | |
476 | } | |
477 | ||
478 | ||
479 | /* | |
480 | * Dereference an IPv6 pool structure. | |
481 | * | |
482 | * If it is the last reference, then the memory for the | |
483 | * structure is freed. | |
484 | */ | |
485 | isc_result_t | |
486 | ipv6_pool_dereference(struct ipv6_pool **pool, const char *file, int line) { | |
487 | struct ipv6_pool *tmp; | |
488 | ||
489 | if ((pool == NULL) || (*pool == NULL)) { | |
490 | log_error("%s(%d): NULL pointer", file, line); | |
491 | return ISC_R_INVALIDARG; | |
492 | } | |
493 | ||
494 | tmp = *pool; | |
495 | *pool = NULL; | |
496 | ||
497 | tmp->refcnt--; | |
498 | if (tmp->refcnt < 0) { | |
499 | log_error("%s(%d): negative refcnt", file, line); | |
500 | tmp->refcnt = 0; | |
501 | } | |
502 | if (tmp->refcnt == 0) { | |
503 | iaaddr_hash_foreach(tmp->addrs, dereference_hash_entry); | |
504 | iaaddr_free_hash_table(&(tmp->addrs), file, line); | |
505 | isc_heap_foreach(tmp->active_timeouts, | |
506 | dereference_heap_entry, NULL); | |
507 | isc_heap_destroy(&(tmp->active_timeouts)); | |
508 | isc_heap_foreach(tmp->inactive_timeouts, | |
509 | dereference_heap_entry, NULL); | |
510 | isc_heap_destroy(&(tmp->inactive_timeouts)); | |
511 | dfree(tmp, file, line); | |
512 | } | |
513 | ||
514 | return ISC_R_SUCCESS; | |
515 | } | |
516 | ||
517 | /* | |
518 | * Create an address by hashing the input, and using that for | |
519 | * the non-network part. | |
520 | */ | |
521 | static void | |
522 | create_address(struct in6_addr *addr, | |
523 | const struct in6_addr *net_start_addr, int net_bits, | |
524 | const struct data_string *input) { | |
525 | MD5_CTX ctx; | |
526 | int net_bytes; | |
527 | int i; | |
528 | char *str; | |
529 | const char *net_str; | |
530 | ||
531 | /* | |
532 | * Use MD5 to get a nice 128 bit hash of the input. | |
533 | * Yes, we know MD5 isn't cryptographically sound. | |
534 | * No, we don't care. | |
535 | */ | |
536 | MD5_Init(&ctx); | |
537 | MD5_Update(&ctx, input->data, input->len); | |
538 | MD5_Final((unsigned char *)addr, &ctx); | |
539 | ||
540 | /* | |
541 | * Copy the network bits over. | |
542 | */ | |
543 | str = (char *)addr; | |
544 | net_str = (const char *)net_start_addr; | |
545 | net_bytes = net_bits / 8; | |
546 | for (i=0; i<net_bytes; i++) { | |
547 | str[i] = net_str[i]; | |
548 | } | |
549 | switch (net_bits % 8) { | |
550 | case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break; | |
551 | case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break; | |
552 | case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break; | |
553 | case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break; | |
554 | case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break; | |
555 | case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break; | |
556 | case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break; | |
557 | } | |
558 | } | |
559 | ||
560 | /* | |
561 | * Create a lease for the given address and client duid. | |
562 | * | |
563 | * - pool must be a pointer to a (struct pool *) pointer previously | |
564 | * initialized to NULL | |
565 | * | |
566 | * Right now we simply hash the DUID, and if we get a collision, we hash | |
567 | * again until we find a free address. We try this a fixed number of times, | |
568 | * to avoid getting stuck in a loop (this is important on small pools | |
569 | * where we can run out of space). | |
570 | * | |
571 | * We return the number of attempts that it took to find an available | |
572 | * lease. This tells callers when a pool is are filling up, as | |
573 | * well as an indication of how full the pool is; statistically the | |
574 | * more full a pool is the more attempts must be made before finding | |
575 | * a free lease. Realistically this will only happen in very full | |
576 | * pools. | |
577 | * | |
578 | * We probably want different algorithms depending on the network size, in | |
579 | * the long term. | |
580 | */ | |
581 | isc_result_t | |
582 | activate_lease6(struct ipv6_pool *pool, struct iaaddr **addr, | |
583 | unsigned int *attempts, | |
584 | const struct data_string *uid, time_t valid_lifetime_end_time) { | |
585 | struct data_string ds; | |
586 | struct in6_addr tmp; | |
587 | struct iaaddr *test_iaaddr; | |
588 | struct data_string new_ds; | |
589 | struct iaaddr *iaaddr; | |
d9b43370 | 590 | isc_result_t result; |
98bd7ca0 DH |
591 | |
592 | /* | |
593 | * Use the UID as our initial seed for the hash | |
594 | */ | |
595 | memset(&ds, 0, sizeof(ds)); | |
596 | data_string_copy(&ds, (struct data_string *)uid, MDL); | |
597 | ||
598 | *attempts = 0; | |
599 | for (;;) { | |
600 | /* | |
601 | * Give up at some point. | |
602 | */ | |
603 | if (++(*attempts) > 100) { | |
604 | data_string_forget(&ds, MDL); | |
605 | return ISC_R_NORESOURCES; | |
606 | } | |
607 | ||
608 | /* | |
609 | * Create an address | |
610 | */ | |
611 | create_address(&tmp, &pool->start_addr, pool->bits, &ds); | |
612 | ||
613 | /* | |
614 | * If this address is not in use, we're happy with it | |
615 | */ | |
616 | test_iaaddr = NULL; | |
617 | if (iaaddr_hash_lookup(&test_iaaddr, pool->addrs, | |
618 | &tmp, sizeof(tmp), MDL) == 0) { | |
619 | break; | |
620 | } | |
621 | iaaddr_dereference(&test_iaaddr, MDL); | |
622 | ||
623 | /* | |
624 | * Otherwise, we create a new input, adding the address | |
625 | */ | |
626 | memset(&new_ds, 0, sizeof(new_ds)); | |
627 | new_ds.len = ds.len + sizeof(tmp); | |
628 | if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) { | |
629 | data_string_forget(&ds, MDL); | |
630 | return ISC_R_NOMEMORY; | |
631 | } | |
632 | new_ds.data = new_ds.buffer->data; | |
d9b43370 SK |
633 | memcpy(new_ds.buffer->data, ds.data, ds.len); |
634 | memcpy(new_ds.buffer->data + ds.len, &tmp, sizeof(tmp)); | |
98bd7ca0 DH |
635 | data_string_forget(&ds, MDL); |
636 | data_string_copy(&ds, &new_ds, MDL); | |
637 | data_string_forget(&new_ds, MDL); | |
638 | } | |
639 | ||
640 | data_string_forget(&ds, MDL); | |
641 | ||
642 | /* | |
643 | * We're happy with the address, create an IAADDR | |
644 | * to hold it. | |
645 | */ | |
646 | iaaddr = NULL; | |
d9b43370 SK |
647 | result = iaaddr_allocate(&iaaddr, MDL); |
648 | if (result != ISC_R_SUCCESS) { | |
649 | return result; | |
98bd7ca0 DH |
650 | } |
651 | memcpy(&iaaddr->addr, &tmp, sizeof(iaaddr->addr)); | |
652 | ||
d9b43370 SK |
653 | /* |
654 | * Add the lease to the pool. | |
655 | */ | |
656 | result = add_lease6(pool, iaaddr, valid_lifetime_end_time); | |
657 | if (result == ISC_R_SUCCESS) { | |
658 | iaaddr_reference(addr, iaaddr, MDL); | |
659 | } | |
660 | iaaddr_dereference(&iaaddr, MDL); | |
661 | return result; | |
98bd7ca0 DH |
662 | } |
663 | ||
664 | /* | |
665 | * Put a lease in the pool directly. This is intended to be used when | |
666 | * loading leases from the file. | |
667 | */ | |
668 | isc_result_t | |
669 | add_lease6(struct ipv6_pool *pool, struct iaaddr *iaaddr, | |
670 | time_t valid_lifetime_end_time) { | |
671 | isc_result_t insert_result; | |
d9b43370 SK |
672 | struct iaaddr *test_iaaddr; |
673 | struct iaaddr *tmp_iaaddr; | |
98bd7ca0 DH |
674 | |
675 | iaaddr->state = FTS_ACTIVE; | |
676 | iaaddr->valid_lifetime_end_time = valid_lifetime_end_time; | |
677 | ipv6_pool_reference(&iaaddr->ipv6_pool, pool, MDL); | |
678 | ||
d9b43370 SK |
679 | /* |
680 | * If this IAADDR is already in our structures, remove the | |
681 | * old one. | |
682 | */ | |
683 | test_iaaddr = NULL; | |
684 | if (iaaddr_hash_lookup(&test_iaaddr, pool->addrs, | |
685 | &iaaddr->addr, sizeof(iaaddr->addr), MDL)) { | |
686 | isc_heap_delete(pool->active_timeouts, test_iaaddr->heap_index); | |
687 | iaaddr_hash_delete(pool->addrs, &test_iaaddr->addr, | |
688 | sizeof(test_iaaddr->addr), MDL); | |
689 | pool->num_active--; | |
690 | ||
691 | /* | |
692 | * We're going to do a bit of evil trickery here. | |
693 | * | |
694 | * We need to dereference the entry once to remove our | |
695 | * current reference (in test_iaaddr), and then one | |
696 | * more time to remove the reference left when the | |
697 | * address was added to the pool before. | |
698 | */ | |
699 | tmp_iaaddr = test_iaaddr; | |
700 | iaaddr_dereference(&test_iaaddr, MDL); | |
701 | iaaddr_dereference(&tmp_iaaddr, MDL); | |
702 | } | |
703 | ||
98bd7ca0 DH |
704 | /* |
705 | * Add IAADDR to our structures. | |
706 | */ | |
d9b43370 SK |
707 | tmp_iaaddr = NULL; |
708 | iaaddr_reference(&tmp_iaaddr, iaaddr, MDL); | |
709 | iaaddr_hash_add(pool->addrs, &tmp_iaaddr->addr, | |
710 | sizeof(tmp_iaaddr->addr), iaaddr, MDL); | |
711 | insert_result = isc_heap_insert(pool->active_timeouts, tmp_iaaddr); | |
98bd7ca0 DH |
712 | if (insert_result != ISC_R_SUCCESS) { |
713 | iaaddr_hash_delete(pool->addrs, &iaaddr->addr, | |
714 | sizeof(iaaddr->addr), MDL); | |
d9b43370 | 715 | iaaddr_dereference(&tmp_iaaddr, MDL); |
98bd7ca0 DH |
716 | return insert_result; |
717 | } | |
718 | ||
d9b43370 SK |
719 | /* |
720 | * Note: we intentionally leave tmp_iaaddr referenced; there | |
721 | * is a reference in the heap/hash, after all. | |
722 | */ | |
723 | ||
98bd7ca0 DH |
724 | /* |
725 | * And we're done. | |
726 | */ | |
727 | pool->num_active++; | |
728 | return ISC_R_SUCCESS; | |
729 | } | |
730 | ||
d9b43370 SK |
731 | /* |
732 | * Determine if an address is present in a pool or not. | |
733 | */ | |
98bd7ca0 DH |
734 | isc_boolean_t |
735 | lease6_exists(const struct ipv6_pool *pool, const struct in6_addr *addr) { | |
736 | struct iaaddr *test_iaaddr; | |
737 | ||
738 | test_iaaddr = NULL; | |
739 | if (iaaddr_hash_lookup(&test_iaaddr, pool->addrs, | |
740 | (void *)addr, sizeof(*addr), MDL)) { | |
741 | iaaddr_dereference(&test_iaaddr, MDL); | |
742 | return ISC_TRUE; | |
743 | } else { | |
744 | return ISC_FALSE; | |
745 | } | |
746 | } | |
747 | ||
d9b43370 SK |
748 | /* |
749 | * Put the lease on our active pool. | |
750 | */ | |
751 | static isc_result_t | |
752 | move_lease_to_active(struct ipv6_pool *pool, struct iaaddr *addr) { | |
753 | isc_result_t insert_result; | |
754 | int old_heap_index; | |
755 | ||
756 | old_heap_index = addr->heap_index; | |
757 | insert_result = isc_heap_insert(pool->active_timeouts, addr); | |
758 | if (insert_result == ISC_R_SUCCESS) { | |
759 | iaaddr_hash_add(pool->addrs, &addr->addr, | |
760 | sizeof(addr->addr), addr, MDL); | |
761 | isc_heap_delete(pool->inactive_timeouts, old_heap_index); | |
762 | pool->num_active++; | |
763 | pool->num_inactive--; | |
764 | addr->state = FTS_ACTIVE; | |
765 | } | |
766 | return insert_result; | |
767 | } | |
768 | ||
98bd7ca0 DH |
769 | /* |
770 | * Renew an lease in the pool. | |
771 | * | |
772 | * To do this, first set the new valid_lifetime_end_time for the address, | |
773 | * and then invoke renew_lease() on the address. | |
774 | * | |
775 | * WARNING: lease times must only be extended, never reduced!!! | |
98bd7ca0 DH |
776 | */ |
777 | isc_result_t | |
778 | renew_lease6(struct ipv6_pool *pool, struct iaaddr *addr) { | |
d9b43370 SK |
779 | /* |
780 | * If we're already active, then we can just move our expiration | |
781 | * time down the heap. | |
782 | * | |
783 | * Otherwise, we have to move from the inactive heap to the | |
784 | * active heap. | |
785 | */ | |
786 | if (addr->state == FTS_ACTIVE) { | |
787 | isc_heap_decreased(pool->active_timeouts, addr->heap_index); | |
788 | return ISC_R_SUCCESS; | |
789 | } else { | |
790 | return move_lease_to_active(pool, addr); | |
791 | } | |
792 | } | |
793 | ||
794 | /* | |
795 | * Put the lease on our inactive pool, with the specified state. | |
796 | */ | |
797 | static isc_result_t | |
798 | move_lease_to_inactive(struct ipv6_pool *pool, struct iaaddr *addr, | |
799 | binding_state_t state) { | |
800 | isc_result_t insert_result; | |
801 | int old_heap_index; | |
802 | ||
803 | old_heap_index = addr->heap_index; | |
804 | insert_result = isc_heap_insert(pool->inactive_timeouts, addr); | |
805 | if (insert_result == ISC_R_SUCCESS) { | |
806 | iaaddr_hash_delete(pool->addrs, | |
807 | &addr->addr, sizeof(addr->addr), MDL); | |
808 | isc_heap_delete(pool->active_timeouts, old_heap_index); | |
809 | addr->state = state; | |
810 | pool->num_active--; | |
811 | pool->num_inactive++; | |
812 | } | |
813 | return insert_result; | |
98bd7ca0 DH |
814 | } |
815 | ||
816 | /* | |
817 | * Expire the oldest lease if it's lifetime_end_time is | |
818 | * older than the given time. | |
819 | * | |
820 | * - iaaddr must be a pointer to a (struct iaaddr *) pointer previously | |
821 | * initialized to NULL | |
822 | * | |
823 | * On return iaaddr has a reference to the removed entry. It is left | |
824 | * pointing to NULL if the oldest lease has not expired. | |
825 | */ | |
826 | isc_result_t | |
827 | expire_lease6(struct iaaddr **addr, struct ipv6_pool *pool, time_t now) { | |
828 | struct iaaddr *tmp; | |
d9b43370 | 829 | isc_result_t result; |
98bd7ca0 DH |
830 | |
831 | if (addr == NULL) { | |
832 | log_error("%s(%d): NULL pointer reference", MDL); | |
833 | return ISC_R_INVALIDARG; | |
834 | } | |
835 | if (*addr != NULL) { | |
836 | log_error("%s(%d): non-NULL pointer", MDL); | |
837 | return ISC_R_INVALIDARG; | |
838 | } | |
839 | ||
840 | if (pool->num_active > 0) { | |
841 | tmp = (struct iaaddr *)isc_heap_element(pool->active_timeouts, | |
842 | 1); | |
843 | if (now > tmp->valid_lifetime_end_time) { | |
d9b43370 SK |
844 | result = move_lease_to_inactive(pool, tmp, FTS_EXPIRED); |
845 | if (result == ISC_R_SUCCESS) { | |
846 | iaaddr_reference(addr, tmp, MDL); | |
98bd7ca0 | 847 | } |
d9b43370 | 848 | return result; |
98bd7ca0 DH |
849 | } |
850 | } | |
851 | return ISC_R_SUCCESS; | |
852 | } | |
853 | ||
98bd7ca0 DH |
854 | |
855 | /* | |
856 | * For a declined lease, leave it on the "active" pool, but mark | |
857 | * it as declined. Give it an infinite (well, really long) life. | |
858 | */ | |
859 | isc_result_t | |
860 | decline_lease6(struct ipv6_pool *pool, struct iaaddr *addr) { | |
d9b43370 SK |
861 | isc_result_t result; |
862 | ||
863 | if (addr->state != FTS_ACTIVE) { | |
864 | result = move_lease_to_active(pool, addr); | |
865 | if (result != ISC_R_SUCCESS) { | |
866 | return result; | |
867 | } | |
868 | } | |
98bd7ca0 DH |
869 | addr->state = FTS_ABANDONED; |
870 | addr->valid_lifetime_end_time = MAX_TIME; | |
871 | isc_heap_decreased(pool->active_timeouts, addr->heap_index); | |
872 | return ISC_R_SUCCESS; | |
873 | } | |
874 | ||
875 | /* | |
876 | * Put the returned lease on our inactive pool. | |
877 | */ | |
878 | isc_result_t | |
879 | release_lease6(struct ipv6_pool *pool, struct iaaddr *addr) { | |
d9b43370 SK |
880 | if (addr->state == FTS_ACTIVE) { |
881 | return move_lease_to_inactive(pool, addr, FTS_RELEASED); | |
882 | } else { | |
883 | return ISC_R_SUCCESS; | |
884 | } | |
98bd7ca0 DH |
885 | } |
886 | ||
887 | /* | |
888 | * Mark an IPv6 address as unavailable from a pool. | |
889 | * | |
890 | * This is used for host entries and the addresses of the server itself. | |
891 | */ | |
892 | isc_result_t | |
893 | mark_address_unavailable(struct ipv6_pool *pool, const struct in6_addr *addr) { | |
894 | struct iaaddr *dummy_iaaddr; | |
895 | isc_result_t result; | |
896 | ||
897 | dummy_iaaddr = NULL; | |
898 | result = iaaddr_allocate(&dummy_iaaddr, MDL); | |
899 | if (result == ISC_R_SUCCESS) { | |
900 | dummy_iaaddr->addr = *addr; | |
901 | iaaddr_hash_add(pool->addrs, &dummy_iaaddr->addr, | |
902 | sizeof(*addr), dummy_iaaddr, MDL); | |
903 | } | |
904 | return result; | |
905 | } | |
906 | ||
907 | /* | |
908 | * Add a pool. | |
909 | */ | |
910 | isc_result_t | |
911 | add_ipv6_pool(struct ipv6_pool *pool) { | |
912 | struct ipv6_pool **new_pools; | |
913 | ||
914 | new_pools = dmalloc(sizeof(struct ipv6_pool *) * (num_pools+1), MDL); | |
915 | if (new_pools == NULL) { | |
916 | return ISC_R_NOMEMORY; | |
917 | } | |
918 | ||
919 | if (num_pools > 0) { | |
920 | memcpy(new_pools, pools, | |
921 | sizeof(struct ipv6_pool *) * num_pools); | |
922 | dfree(pools, MDL); | |
923 | } | |
924 | pools = new_pools; | |
925 | ||
926 | pools[num_pools] = NULL; | |
927 | ipv6_pool_reference(&pools[num_pools], pool, MDL); | |
928 | num_pools++; | |
929 | return ISC_R_SUCCESS; | |
930 | } | |
931 | ||
932 | ||
d9b43370 SK |
933 | static void |
934 | cleanup_old_expired(struct ipv6_pool *pool) { | |
935 | struct iaaddr *tmp; | |
936 | struct ia_na *ia_na; | |
937 | ||
938 | while (pool->num_inactive > 0) { | |
939 | tmp = (struct iaaddr *)isc_heap_element(pool->inactive_timeouts, | |
940 | 1); | |
941 | if (cur_time < | |
942 | tmp->valid_lifetime_end_time + EXPIRED_IPV6_CLEANUP_TIME) { | |
943 | break; | |
944 | } | |
945 | ||
946 | isc_heap_delete(pool->inactive_timeouts, tmp->heap_index); | |
947 | pool->num_inactive--; | |
948 | ||
949 | ia_na = NULL; | |
950 | ia_na_reference(&ia_na, tmp->ia_na, MDL); | |
951 | ia_na_remove_iaaddr(ia_na, tmp, MDL); | |
952 | iaaddr_dereference(&tmp, MDL); | |
953 | if (ia_na->num_iaaddr <= 0) { | |
954 | ia_na_hash_delete(ia_active, | |
955 | (char *)ia_na->iaid_duid.data, | |
956 | ia_na->iaid_duid.len, MDL); | |
957 | } | |
958 | ia_na_dereference(&ia_na, MDL); | |
959 | } | |
960 | } | |
961 | ||
962 | static void | |
963 | lease_timeout_support(void *vpool) { | |
964 | struct ipv6_pool *pool; | |
965 | struct iaaddr *addr; | |
966 | ||
967 | pool = (struct ipv6_pool *)vpool; | |
968 | for (;;) { | |
969 | /* | |
970 | * Get the next lease scheduled to expire. | |
971 | * | |
972 | * Note that if there are no leases in the pool, | |
973 | * expire_lease6() will return ISC_R_SUCCESS with | |
974 | * a NULL lease. | |
975 | */ | |
976 | addr = NULL; | |
977 | if (expire_lease6(&addr, pool, cur_time) != ISC_R_SUCCESS) { | |
978 | break; | |
979 | } | |
980 | if (addr == NULL) { | |
981 | break; | |
982 | } | |
983 | ||
984 | /* Look to see if there were ddns updates, and if | |
985 | * so, drop them. | |
986 | * | |
987 | * DH: Do we want to do this on a special 'depref' | |
988 | * timer rather than expiration timer? | |
989 | */ | |
990 | ddns_removals(NULL, addr); | |
991 | ||
992 | write_ia_na(addr->ia_na); | |
993 | ||
994 | iaaddr_dereference(&addr, MDL); | |
995 | } | |
996 | ||
997 | /* | |
998 | * Do some cleanup of our expired leases. | |
999 | */ | |
1000 | cleanup_old_expired(pool); | |
1001 | ||
1002 | /* | |
1003 | * Schedule next round of expirations. | |
1004 | */ | |
1005 | schedule_lease_timeout(pool); | |
1006 | } | |
1007 | ||
98bd7ca0 | 1008 | /* |
d9b43370 SK |
1009 | * For a given pool, add a timer that will remove the next |
1010 | * lease to expire. | |
98bd7ca0 DH |
1011 | */ |
1012 | void | |
d9b43370 SK |
1013 | schedule_lease_timeout(struct ipv6_pool *pool) { |
1014 | struct iaaddr *tmp; | |
1015 | time_t timeout; | |
1016 | time_t next_timeout; | |
1017 | ||
1018 | next_timeout = MAX_TIME; | |
1019 | ||
1020 | if (pool->num_active > 0) { | |
1021 | tmp = (struct iaaddr *)isc_heap_element(pool->active_timeouts, | |
1022 | 1); | |
1023 | if (tmp->valid_lifetime_end_time < next_timeout) { | |
1024 | next_timeout = tmp->valid_lifetime_end_time; | |
1025 | } | |
1026 | } | |
1027 | ||
1028 | if (pool->num_inactive > 0) { | |
1029 | tmp = (struct iaaddr *)isc_heap_element(pool->inactive_timeouts, | |
1030 | 1); | |
1031 | timeout = tmp->valid_lifetime_end_time + | |
1032 | EXPIRED_IPV6_CLEANUP_TIME; | |
1033 | if (timeout < next_timeout) { | |
1034 | next_timeout = timeout; | |
1035 | } | |
1036 | } | |
1037 | ||
1038 | if (next_timeout < MAX_TIME) { | |
1039 | add_timeout(next_timeout, lease_timeout_support, pool, | |
1040 | (tvref_t)ipv6_pool_reference, | |
1041 | (tvunref_t)ipv6_pool_dereference); | |
1042 | } | |
1043 | } | |
1044 | ||
1045 | /* | |
1046 | * Schedule timeouts across all pools. | |
1047 | */ | |
1048 | void | |
1049 | schedule_all_ipv6_lease_timeouts(void) { | |
98bd7ca0 | 1050 | int i; |
98bd7ca0 DH |
1051 | |
1052 | for (i=0; i<num_pools; i++) { | |
d9b43370 | 1053 | schedule_lease_timeout(pools[i]); |
98bd7ca0 DH |
1054 | } |
1055 | } | |
1056 | ||
1057 | /* | |
1058 | * Given an address and the length of the network mask, return | |
1059 | * only the network portion. | |
1060 | * | |
1061 | * Examples: | |
1062 | * | |
1063 | * "fe80::216:6fff:fe49:7d9b", length 64 = "fe80::" | |
1064 | * "2001:888:1936:2:216:6fff:fe49:7d9b", length 48 = "2001:888:1936::" | |
1065 | */ | |
1066 | static void | |
1067 | ipv6_network_portion(struct in6_addr *result, | |
1068 | const struct in6_addr *addr, int bits) { | |
1069 | unsigned char *addrp; | |
1070 | int mask_bits; | |
1071 | int bytes; | |
1072 | int extra_bits; | |
1073 | int i; | |
1074 | ||
1075 | static const unsigned char bitmasks[] = { | |
1076 | 0x00, 0xFE, 0xFC, 0xF8, | |
1077 | 0xF0, 0xE0, 0xC0, 0x80, | |
1078 | }; | |
1079 | ||
1080 | /* | |
1081 | * Sanity check our bits. ;) | |
1082 | */ | |
1083 | if ((bits < 0) || (bits > 128)) { | |
1084 | log_fatal("ipv6_network_portion: bits %d not between 0 and 128", | |
1085 | bits); | |
1086 | } | |
1087 | ||
1088 | /* | |
1089 | * Copy our address portion. | |
1090 | */ | |
1091 | *result = *addr; | |
1092 | addrp = ((unsigned char *)result) + 15; | |
1093 | ||
1094 | /* | |
1095 | * Zero out masked portion. | |
1096 | */ | |
1097 | mask_bits = 128 - bits; | |
1098 | bytes = mask_bits / 8; | |
1099 | extra_bits = mask_bits % 8; | |
1100 | ||
1101 | for (i=0; i<bytes; i++) { | |
1102 | *addrp = 0; | |
1103 | addrp--; | |
1104 | } | |
1105 | if (extra_bits) { | |
1106 | *addrp &= bitmasks[extra_bits]; | |
1107 | } | |
1108 | } | |
1109 | ||
1110 | /* | |
1111 | * Determine if the given address is in the pool. | |
1112 | */ | |
1113 | isc_boolean_t | |
1114 | ipv6_addr_in_pool(const struct in6_addr *addr, const struct ipv6_pool *pool) { | |
1115 | struct in6_addr tmp; | |
1116 | ||
1117 | ipv6_network_portion(&tmp, addr, pool->bits); | |
1118 | if (memcmp(&tmp, &pool->start_addr, sizeof(tmp)) == 0) { | |
1119 | return ISC_TRUE; | |
1120 | } else { | |
1121 | return ISC_FALSE; | |
1122 | } | |
1123 | } | |
1124 | ||
1125 | /* | |
1126 | * Find the pool that contains the given address. | |
1127 | * | |
1128 | * - pool must be a pointer to a (struct ipv6_pool *) pointer previously | |
1129 | * initialized to NULL | |
1130 | */ | |
1131 | isc_result_t | |
1132 | find_ipv6_pool(struct ipv6_pool **pool, const struct in6_addr *addr) { | |
1133 | int i; | |
1134 | ||
1135 | if (pool == NULL) { | |
1136 | log_error("%s(%d): NULL pointer reference", MDL); | |
1137 | return ISC_R_INVALIDARG; | |
1138 | } | |
1139 | if (*pool != NULL) { | |
1140 | log_error("%s(%d): non-NULL pointer", MDL); | |
1141 | return ISC_R_INVALIDARG; | |
1142 | } | |
1143 | ||
1144 | for (i=0; i<num_pools; i++) { | |
1145 | if (ipv6_addr_in_pool(addr, pools[i])) { | |
1146 | ipv6_pool_reference(pool, pools[i], MDL); | |
1147 | return ISC_R_SUCCESS; | |
1148 | } | |
1149 | } | |
1150 | return ISC_R_NOTFOUND; | |
1151 | } | |
1152 | ||
1153 | /* | |
1154 | * Helper function for the various functions that act across all | |
1155 | * pools. | |
1156 | */ | |
1157 | static isc_result_t | |
1158 | change_leases(struct ia_na *ia_na, | |
1159 | isc_result_t (*change_func)(struct ipv6_pool *, struct iaaddr*)) { | |
1160 | isc_result_t retval; | |
1161 | isc_result_t renew_retval; | |
1162 | struct ipv6_pool *pool; | |
1163 | struct in6_addr *addr; | |
1164 | int i; | |
1165 | ||
1166 | retval = ISC_R_SUCCESS; | |
1167 | for (i=0; i<ia_na->num_iaaddr; i++) { | |
1168 | pool = NULL; | |
1169 | addr = &ia_na->iaaddr[i]->addr; | |
1170 | if (find_ipv6_pool(&pool, addr) == ISC_R_SUCCESS) { | |
1171 | renew_retval = change_func(pool, ia_na->iaaddr[i]); | |
1172 | if (renew_retval != ISC_R_SUCCESS) { | |
1173 | retval = renew_retval; | |
1174 | } | |
1175 | } | |
1176 | /* XXXsk: should we warn if we don't find a pool? */ | |
1177 | } | |
1178 | return retval; | |
1179 | } | |
1180 | ||
1181 | /* | |
1182 | * Renew all leases in an IA_NA from all pools. | |
1183 | * | |
1184 | * The new valid_lifetime_end_time should be updated for the addresses. | |
1185 | * | |
1186 | * WARNING: lease times must only be extended, never reduced!!! | |
1187 | */ | |
1188 | isc_result_t | |
1189 | renew_leases(struct ia_na *ia_na) { | |
1190 | return change_leases(ia_na, renew_lease6); | |
1191 | } | |
1192 | ||
1193 | /* | |
1194 | * Release all leases in an IA_NA from all pools. | |
1195 | */ | |
1196 | isc_result_t | |
1197 | release_leases(struct ia_na *ia_na) { | |
1198 | return change_leases(ia_na, release_lease6); | |
1199 | } | |
1200 | ||
1201 | /* | |
1202 | * Decline all leases in an IA_NA from all pools. | |
1203 | */ | |
1204 | isc_result_t | |
1205 | decline_leases(struct ia_na *ia_na) { | |
1206 | return change_leases(ia_na, decline_lease6); | |
1207 | } | |
1208 | ||
1209 | /* | |
1210 | * Helper function to output leases. | |
1211 | */ | |
1212 | static int write_error; | |
1213 | ||
1214 | static isc_result_t | |
1215 | write_ia_na_leases(const void *name, unsigned len, void *value) { | |
1216 | struct ia_na *ia_na = (struct ia_na *)value; | |
1217 | ||
1218 | if (!write_error) { | |
1219 | if (!write_ia_na(ia_na)) { | |
1220 | write_error = 1; | |
1221 | } | |
1222 | } | |
1223 | return ISC_R_SUCCESS; | |
1224 | } | |
1225 | ||
fe5b0fdd | 1226 | #ifdef DHCPv6 |
98bd7ca0 DH |
1227 | /* |
1228 | * Write all DHCPv6 information. | |
1229 | */ | |
1230 | int | |
1231 | write_leases6(void) { | |
1232 | write_error = 0; | |
1233 | write_server_duid(); | |
1234 | iaaddr_hash_foreach(ia_active, write_ia_na_leases); | |
1235 | if (write_error) { | |
1236 | return 0; | |
1237 | } | |
1238 | return 1; | |
1239 | } | |
fe5b0fdd | 1240 | #endif /* DHCPv6 */ |
98bd7ca0 DH |
1241 | |
1242 | static isc_result_t | |
1243 | mark_hosts_unavailable_support(const void *name, unsigned len, void *value) { | |
1244 | struct host_decl *h; | |
1245 | struct data_string fixed_addr; | |
1246 | struct in6_addr addr; | |
1247 | struct ipv6_pool *p; | |
1248 | ||
1249 | h = (struct host_decl *)value; | |
1250 | ||
1251 | /* | |
1252 | * If the host has no address, we don't need to mark anything. | |
1253 | */ | |
1254 | if (h->fixed_addr == NULL) { | |
1255 | return ISC_R_SUCCESS; | |
1256 | } | |
1257 | ||
1258 | /* | |
1259 | * Evaluate the fixed address. | |
1260 | */ | |
1261 | memset(&fixed_addr, 0, sizeof(fixed_addr)); | |
1262 | if (!evaluate_option_cache(&fixed_addr, NULL, NULL, NULL, NULL, NULL, | |
1263 | &global_scope, h->fixed_addr, MDL)) { | |
1264 | log_error("mark_hosts_unavailable: " | |
1265 | "error evaluating host address."); | |
1266 | return ISC_R_SUCCESS; | |
1267 | } | |
1268 | if (fixed_addr.len != 16) { | |
1269 | log_error("mark_hosts_unavailable: " | |
1270 | "host address is not 128 bits."); | |
1271 | return ISC_R_SUCCESS; | |
1272 | } | |
1273 | memcpy(&addr, fixed_addr.data, 16); | |
1274 | data_string_forget(&fixed_addr, MDL); | |
1275 | ||
1276 | /* | |
1277 | * Find the pool holding this host, and mark the address. | |
1278 | * (I suppose it is arguably valid to have a host that does not | |
1279 | * sit in any pool.) | |
1280 | */ | |
1281 | p = NULL; | |
1282 | if (find_ipv6_pool(&p, &addr) == ISC_R_SUCCESS) { | |
1283 | mark_address_unavailable(p, &addr); | |
1284 | ipv6_pool_dereference(&p, MDL); | |
1285 | } | |
1286 | ||
1287 | return ISC_R_SUCCESS; | |
1288 | } | |
1289 | ||
1290 | void | |
1291 | mark_hosts_unavailable(void) { | |
1292 | hash_foreach(host_name_hash, mark_hosts_unavailable_support); | |
1293 | } | |
1294 | ||
1295 | void | |
1296 | mark_interfaces_unavailable(void) { | |
1297 | struct interface_info *ip; | |
1298 | int i; | |
1299 | struct ipv6_pool *p; | |
1300 | ||
1301 | ip = interfaces; | |
1302 | while (ip != NULL) { | |
1303 | for (i=0; i<ip->v6address_count; i++) { | |
1304 | p = NULL; | |
1305 | if (find_ipv6_pool(&p, &ip->v6addresses[i]) | |
1306 | == ISC_R_SUCCESS) { | |
1307 | mark_address_unavailable(p, | |
1308 | &ip->v6addresses[i]); | |
1309 | ipv6_pool_dereference(&p, MDL); | |
1310 | } | |
1311 | } | |
1312 | ip = ip->next; | |
1313 | } | |
1314 | } | |
1315 | ||
1316 | ||
1317 | #ifdef UNIT_TEST | |
1318 | #include <stdlib.h> | |
1319 | ||
1320 | int | |
1321 | main(int argc, char *argv[]) { | |
1322 | struct iaaddr *iaaddr; | |
1323 | struct iaaddr *iaaddr_copy; | |
1324 | u_int32_t iaid; | |
1325 | struct ia_na *ia_na; | |
1326 | struct ia_na *ia_na_copy; | |
1327 | int i; | |
1328 | struct in6_addr addr; | |
1329 | struct ipv6_pool *pool; | |
1330 | struct ipv6_pool *pool_copy; | |
1331 | char addr_buf[INET6_ADDRSTRLEN]; | |
1332 | char *uid; | |
1333 | struct data_string ds; | |
1334 | struct iaaddr *expired_iaaddr; | |
1335 | unsigned int attempts; | |
1336 | ||
1337 | /* | |
1338 | * Test 0: Basic iaaddr manipulation. | |
1339 | */ | |
1340 | iaaddr = NULL; | |
1341 | if (iaaddr_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
1342 | printf("ERROR: iaaddr_allocate() %s:%d\n", MDL); | |
1343 | return 1; | |
1344 | } | |
1345 | if (iaaddr->state != FTS_FREE) { | |
1346 | printf("ERROR: bad state %s:%d\n", MDL); | |
1347 | return 1; | |
1348 | } | |
1349 | if (iaaddr->heap_index != -1) { | |
1350 | printf("ERROR: bad heap_index %s:%d\n", MDL); | |
1351 | return 1; | |
1352 | } | |
1353 | iaaddr_copy = NULL; | |
1354 | if (iaaddr_reference(&iaaddr_copy, iaaddr, MDL) != ISC_R_SUCCESS) { | |
1355 | printf("ERROR: iaaddr_reference() %s:%d\n", MDL); | |
1356 | return 1; | |
1357 | } | |
1358 | if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
1359 | printf("ERROR: iaaddr_reference() %s:%d\n", MDL); | |
1360 | return 1; | |
1361 | } | |
1362 | if (iaaddr_dereference(&iaaddr_copy, MDL) != ISC_R_SUCCESS) { | |
1363 | printf("ERROR: iaaddr_reference() %s:%d\n", MDL); | |
1364 | return 1; | |
1365 | } | |
1366 | ||
1367 | /* | |
1368 | * Test 1: Error iaaddr manipulation. | |
1369 | */ | |
1370 | /* bogus allocate arguments */ | |
1371 | if (iaaddr_allocate(NULL, MDL) != ISC_R_INVALIDARG) { | |
1372 | printf("ERROR: iaaddr_allocate() %s:%d\n", MDL); | |
1373 | return 1; | |
1374 | } | |
1375 | iaaddr = (struct iaaddr *)1; | |
1376 | if (iaaddr_allocate(&iaaddr, MDL) != ISC_R_INVALIDARG) { | |
1377 | printf("ERROR: iaaddr_allocate() %s:%d\n", MDL); | |
1378 | return 1; | |
1379 | } | |
1380 | ||
1381 | /* bogus reference arguments */ | |
1382 | iaaddr = NULL; | |
1383 | if (iaaddr_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
1384 | printf("ERROR: iaaddr_allocate() %s:%d\n", MDL); | |
1385 | return 1; | |
1386 | } | |
1387 | if (iaaddr_reference(NULL, iaaddr, MDL) != ISC_R_INVALIDARG) { | |
1388 | printf("ERROR: iaaddr_reference() %s:%d\n", MDL); | |
1389 | return 1; | |
1390 | } | |
1391 | iaaddr_copy = (struct iaaddr *)1; | |
1392 | if (iaaddr_reference(&iaaddr_copy, iaaddr, MDL) != ISC_R_INVALIDARG) { | |
1393 | printf("ERROR: iaaddr_reference() %s:%d\n", MDL); | |
1394 | return 1; | |
1395 | } | |
1396 | iaaddr_copy = NULL; | |
1397 | if (iaaddr_reference(&iaaddr_copy, NULL, MDL) != ISC_R_INVALIDARG) { | |
1398 | printf("ERROR: iaaddr_reference() %s:%d\n", MDL); | |
1399 | return 1; | |
1400 | } | |
1401 | if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
1402 | printf("ERROR: iaaddr_reference() %s:%d\n", MDL); | |
1403 | return 1; | |
1404 | } | |
1405 | ||
1406 | /* bogus dereference arguments */ | |
1407 | if (iaaddr_dereference(NULL, MDL) != ISC_R_INVALIDARG) { | |
1408 | printf("ERROR: iaaddr_dereference() %s:%d\n", MDL); | |
1409 | return 1; | |
1410 | } | |
1411 | iaaddr = NULL; | |
1412 | if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_INVALIDARG) { | |
1413 | printf("ERROR: iaaddr_dereference() %s:%d\n", MDL); | |
1414 | return 1; | |
1415 | } | |
1416 | ||
1417 | /* | |
1418 | * Test 2: Basic ia_na manipulation. | |
1419 | */ | |
1420 | iaid = 666; | |
1421 | ia_na = NULL; | |
1422 | if (ia_na_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { | |
1423 | printf("ERROR: ia_na_allocate() %s:%d\n", MDL); | |
1424 | return 1; | |
1425 | } | |
1426 | if (memcmp(ia_na->iaid_duid.data, &iaid, sizeof(iaid)) != 0) { | |
1427 | printf("ERROR: bad IAID_DUID %s:%d\n", MDL); | |
1428 | return 1; | |
1429 | } | |
1430 | if (memcmp(ia_na->iaid_duid.data+sizeof(iaid), "TestDUID", 8) != 0) { | |
1431 | printf("ERROR: bad IAID_DUID %s:%d\n", MDL); | |
1432 | return 1; | |
1433 | } | |
1434 | if (ia_na->num_iaaddr != 0) { | |
1435 | printf("ERROR: bad num_iaaddr %s:%d\n", MDL); | |
1436 | return 1; | |
1437 | } | |
1438 | ia_na_copy = NULL; | |
1439 | if (ia_na_reference(&ia_na_copy, ia_na, MDL) != ISC_R_SUCCESS) { | |
1440 | printf("ERROR: ia_na_reference() %s:%d\n", MDL); | |
1441 | return 1; | |
1442 | } | |
1443 | iaaddr = NULL; | |
1444 | if (iaaddr_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
1445 | printf("ERROR: iaaddr_allocate() %s:%d\n", MDL); | |
1446 | return 1; | |
1447 | } | |
1448 | if (ia_na_add_iaaddr(ia_na, iaaddr, MDL) != ISC_R_SUCCESS) { | |
1449 | printf("ERROR: ia_na_add_iaaddr() %s:%d\n", MDL); | |
1450 | return 1; | |
1451 | } | |
1452 | ia_na_remove_iaaddr(ia_na, iaaddr, MDL); | |
1453 | if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
1454 | printf("ERROR: iaaddr_reference() %s:%d\n", MDL); | |
1455 | return 1; | |
1456 | } | |
1457 | if (ia_na_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { | |
1458 | printf("ERROR: ia_na_dereference() %s:%d\n", MDL); | |
1459 | return 1; | |
1460 | } | |
1461 | if (ia_na_dereference(&ia_na_copy, MDL) != ISC_R_SUCCESS) { | |
1462 | printf("ERROR: ia_na_dereference() %s:%d\n", MDL); | |
1463 | return 1; | |
1464 | } | |
1465 | ||
1466 | /* | |
1467 | * Test 3: lots of iaaddr in our ia_na | |
1468 | */ | |
1469 | ||
1470 | /* lots of iaaddr that we delete */ | |
1471 | iaid = 666; | |
1472 | ia_na = NULL; | |
1473 | if (ia_na_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { | |
1474 | printf("ERROR: ia_na_allocate() %s:%d\n", MDL); | |
1475 | return 1; | |
1476 | } | |
1477 | for (i=0; i<100; i++) { | |
1478 | iaaddr = NULL; | |
1479 | if (iaaddr_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
1480 | printf("ERROR: iaaddr_allocate() %s:%d\n", MDL); | |
1481 | return 1; | |
1482 | } | |
1483 | if (ia_na_add_iaaddr(ia_na, iaaddr, MDL) != ISC_R_SUCCESS) { | |
1484 | printf("ERROR: ia_na_add_iaaddr() %s:%d\n", MDL); | |
1485 | return 1; | |
1486 | } | |
1487 | if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
1488 | printf("ERROR: iaaddr_reference() %s:%d\n", MDL); | |
1489 | return 1; | |
1490 | } | |
1491 | } | |
1492 | for (i=0; i<100; i++) { | |
1493 | iaaddr = ia_na->iaaddr[random() % ia_na->num_iaaddr]; | |
1494 | ia_na_remove_iaaddr(ia_na, iaaddr, MDL); | |
1495 | } | |
1496 | if (ia_na_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { | |
1497 | printf("ERROR: ia_na_dereference() %s:%d\n", MDL); | |
1498 | return 1; | |
1499 | } | |
1500 | ||
1501 | /* lots of iaaddr, let dereference cleanup */ | |
1502 | iaid = 666; | |
1503 | ia_na = NULL; | |
1504 | if (ia_na_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { | |
1505 | printf("ERROR: ia_na_allocate() %s:%d\n", MDL); | |
1506 | return 1; | |
1507 | } | |
1508 | for (i=0; i<100; i++) { | |
1509 | iaaddr = NULL; | |
1510 | if (iaaddr_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
1511 | printf("ERROR: iaaddr_allocate() %s:%d\n", MDL); | |
1512 | return 1; | |
1513 | } | |
1514 | if (ia_na_add_iaaddr(ia_na, iaaddr, MDL) != ISC_R_SUCCESS) { | |
1515 | printf("ERROR: ia_na_add_iaaddr() %s:%d\n", MDL); | |
1516 | return 1; | |
1517 | } | |
1518 | if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
1519 | printf("ERROR: iaaddr_reference() %s:%d\n", MDL); | |
1520 | return 1; | |
1521 | } | |
1522 | } | |
1523 | if (ia_na_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { | |
1524 | printf("ERROR: ia_na_dereference() %s:%d\n", MDL); | |
1525 | return 1; | |
1526 | } | |
1527 | ||
1528 | /* | |
1529 | * Test 4: Errors in ia_na. | |
1530 | */ | |
1531 | /* bogus allocate arguments */ | |
1532 | if (ia_na_allocate(NULL, 123, "", 0, MDL) != ISC_R_INVALIDARG) { | |
1533 | printf("ERROR: ia_na_allocate() %s:%d\n", MDL); | |
1534 | return 1; | |
1535 | } | |
1536 | ia_na = (struct ia_na *)1; | |
1537 | if (ia_na_allocate(&ia_na, 456, "", 0, MDL) != ISC_R_INVALIDARG) { | |
1538 | printf("ERROR: ia_na_allocate() %s:%d\n", MDL); | |
1539 | return 1; | |
1540 | } | |
1541 | ||
1542 | /* bogus reference arguments */ | |
1543 | iaid = 666; | |
1544 | ia_na = NULL; | |
1545 | if (ia_na_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { | |
1546 | printf("ERROR: ia_na_allocate() %s:%d\n", MDL); | |
1547 | return 1; | |
1548 | } | |
1549 | if (ia_na_reference(NULL, ia_na, MDL) != ISC_R_INVALIDARG) { | |
1550 | printf("ERROR: ia_na_reference() %s:%d\n", MDL); | |
1551 | return 1; | |
1552 | } | |
1553 | ia_na_copy = (struct ia_na *)1; | |
1554 | if (ia_na_reference(&ia_na_copy, ia_na, MDL) != ISC_R_INVALIDARG) { | |
1555 | printf("ERROR: ia_na_reference() %s:%d\n", MDL); | |
1556 | return 1; | |
1557 | } | |
1558 | ia_na_copy = NULL; | |
1559 | if (ia_na_reference(&ia_na_copy, NULL, MDL) != ISC_R_INVALIDARG) { | |
1560 | printf("ERROR: ia_na_reference() %s:%d\n", MDL); | |
1561 | return 1; | |
1562 | } | |
1563 | if (ia_na_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { | |
1564 | printf("ERROR: ia_na_dereference() %s:%d\n", MDL); | |
1565 | return 1; | |
1566 | } | |
1567 | ||
1568 | /* bogus dereference arguments */ | |
1569 | if (ia_na_dereference(NULL, MDL) != ISC_R_INVALIDARG) { | |
1570 | printf("ERROR: ia_na_dereference() %s:%d\n", MDL); | |
1571 | return 1; | |
1572 | } | |
1573 | ||
1574 | /* bogus remove */ | |
1575 | iaid = 666; | |
1576 | ia_na = NULL; | |
1577 | if (ia_na_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { | |
1578 | printf("ERROR: ia_na_allocate() %s:%d\n", MDL); | |
1579 | return 1; | |
1580 | } | |
1581 | ia_na_remove_iaaddr(ia_na, NULL, MDL); | |
1582 | if (ia_na_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { | |
1583 | printf("ERROR: ia_na_dereference() %s:%d\n", MDL); | |
1584 | return 1; | |
1585 | } | |
1586 | ||
1587 | /* | |
1588 | * Test 5: Basic ipv6_pool manipulation. | |
1589 | */ | |
1590 | ||
1591 | /* allocate, reference */ | |
1592 | inet_pton(AF_INET6, "1:2:3:4::", &addr); | |
1593 | pool = NULL; | |
1594 | if (ipv6_pool_allocate(&pool, &addr, 64, MDL) != ISC_R_SUCCESS) { | |
1595 | printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); | |
1596 | return 1; | |
1597 | } | |
1598 | if (pool->num_active != 0) { | |
1599 | printf("ERROR: bad num_active %s:%d\n", MDL); | |
1600 | return 1; | |
1601 | } | |
1602 | if (pool->bits != 64) { | |
1603 | printf("ERROR: bad bits %s:%d\n", MDL); | |
1604 | return 1; | |
1605 | } | |
1606 | inet_ntop(AF_INET6, &pool->start_addr, addr_buf, sizeof(addr_buf)); | |
1607 | if (strcmp(inet_ntop(AF_INET6, &pool->start_addr, addr_buf, | |
1608 | sizeof(addr_buf)), "1:2:3:4::") != 0) { | |
1609 | printf("ERROR: bad start_addr %s:%d\n", MDL); | |
1610 | return 1; | |
1611 | } | |
1612 | pool_copy = NULL; | |
1613 | if (ipv6_pool_reference(&pool_copy, pool, MDL) != ISC_R_SUCCESS) { | |
1614 | printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); | |
1615 | return 1; | |
1616 | } | |
1617 | ||
1618 | /* activate_lease6, renew_lease6, expire_lease6 */ | |
1619 | uid = "client0"; | |
1620 | memset(&ds, 0, sizeof(ds)); | |
1621 | ds.len = strlen(uid); | |
1622 | if (!buffer_allocate(&ds.buffer, ds.len, MDL)) { | |
1623 | printf("Out of memory\n"); | |
1624 | return 1; | |
1625 | } | |
1626 | ds.data = ds.buffer->data; | |
1627 | memcpy((char *)ds.data, uid, ds.len); | |
1628 | if (activate_lease6(pool, &iaaddr, | |
1629 | &attempts, &ds, 1) != ISC_R_SUCCESS) { | |
1630 | printf("ERROR: activate_lease6() %s:%d\n", MDL); | |
1631 | return 1; | |
1632 | } | |
1633 | if (pool->num_active != 1) { | |
1634 | printf("ERROR: bad num_active %s:%d\n", MDL); | |
1635 | return 1; | |
1636 | } | |
1637 | if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { | |
1638 | printf("ERROR: renew_lease6() %s:%d\n", MDL); | |
1639 | return 1; | |
1640 | } | |
1641 | if (pool->num_active != 1) { | |
1642 | printf("ERROR: bad num_active %s:%d\n", MDL); | |
1643 | return 1; | |
1644 | } | |
1645 | expired_iaaddr = NULL; | |
1646 | if (expire_lease6(&expired_iaaddr, pool, 0) != ISC_R_SUCCESS) { | |
1647 | printf("ERROR: expire_lease6() %s:%d\n", MDL); | |
1648 | return 1; | |
1649 | } | |
1650 | if (expired_iaaddr != NULL) { | |
1651 | printf("ERROR: should not have expired a lease %s:%d\n", MDL); | |
1652 | return 1; | |
1653 | } | |
1654 | if (pool->num_active != 1) { | |
1655 | printf("ERROR: bad num_active %s:%d\n", MDL); | |
1656 | return 1; | |
1657 | } | |
1658 | if (expire_lease6(&expired_iaaddr, pool, 1000) != ISC_R_SUCCESS) { | |
1659 | printf("ERROR: expire_lease6() %s:%d\n", MDL); | |
1660 | return 1; | |
1661 | } | |
1662 | if (expired_iaaddr == NULL) { | |
1663 | printf("ERROR: should have expired a lease %s:%d\n", MDL); | |
1664 | return 1; | |
1665 | } | |
1666 | if (iaaddr_dereference(&expired_iaaddr, MDL) != ISC_R_SUCCESS) { | |
1667 | printf("ERROR: iaaddr_dereference() %s:%d\n", MDL); | |
1668 | return 1; | |
1669 | } | |
1670 | if (pool->num_active != 0) { | |
1671 | printf("ERROR: bad num_active %s:%d\n", MDL); | |
1672 | return 1; | |
1673 | } | |
1674 | if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
1675 | printf("ERROR: iaaddr_dereference() %s:%d\n", MDL); | |
1676 | return 1; | |
1677 | } | |
1678 | ||
1679 | /* release_lease6, decline_lease6 */ | |
1680 | if (activate_lease6(pool, &iaaddr, &attempts, | |
1681 | &ds, 1) != ISC_R_SUCCESS) { | |
1682 | printf("ERROR: activate_lease6() %s:%d\n", MDL); | |
1683 | return 1; | |
1684 | } | |
1685 | if (pool->num_active != 1) { | |
1686 | printf("ERROR: bad num_active %s:%d\n", MDL); | |
1687 | return 1; | |
1688 | } | |
1689 | if (release_lease6(pool, iaaddr) != ISC_R_SUCCESS) { | |
1690 | printf("ERROR: decline_lease6() %s:%d\n", MDL); | |
1691 | return 1; | |
1692 | } | |
1693 | if (pool->num_active != 0) { | |
1694 | printf("ERROR: bad num_active %s:%d\n", MDL); | |
1695 | return 1; | |
1696 | } | |
1697 | if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
1698 | printf("ERROR: iaaddr_dereference() %s:%d\n", MDL); | |
1699 | return 1; | |
1700 | } | |
1701 | if (activate_lease6(pool, &iaaddr, &attempts, | |
1702 | &ds, 1) != ISC_R_SUCCESS) { | |
1703 | printf("ERROR: activate_lease6() %s:%d\n", MDL); | |
1704 | return 1; | |
1705 | } | |
1706 | if (pool->num_active != 1) { | |
1707 | printf("ERROR: bad num_active %s:%d\n", MDL); | |
1708 | return 1; | |
1709 | } | |
1710 | if (decline_lease6(pool, iaaddr) != ISC_R_SUCCESS) { | |
1711 | printf("ERROR: decline_lease6() %s:%d\n", MDL); | |
1712 | return 1; | |
1713 | } | |
1714 | if (pool->num_active != 1) { | |
1715 | printf("ERROR: bad num_active %s:%d\n", MDL); | |
1716 | return 1; | |
1717 | } | |
1718 | if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
1719 | printf("ERROR: iaaddr_dereference() %s:%d\n", MDL); | |
1720 | return 1; | |
1721 | } | |
1722 | ||
1723 | /* dereference */ | |
1724 | if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { | |
1725 | printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); | |
1726 | return 1; | |
1727 | } | |
1728 | if (ipv6_pool_dereference(&pool_copy, MDL) != ISC_R_SUCCESS) { | |
1729 | printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); | |
1730 | return 1; | |
1731 | } | |
1732 | ||
1733 | /* | |
1734 | * Test 6: Error ipv6_pool manipulation | |
1735 | */ | |
1736 | if (ipv6_pool_allocate(NULL, &addr, 64, MDL) != ISC_R_INVALIDARG) { | |
1737 | printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); | |
1738 | return 1; | |
1739 | } | |
1740 | pool = (struct ipv6_pool *)1; | |
1741 | if (ipv6_pool_allocate(&pool, &addr, 64, MDL) != ISC_R_INVALIDARG) { | |
1742 | printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); | |
1743 | return 1; | |
1744 | } | |
1745 | if (ipv6_pool_reference(NULL, pool, MDL) != ISC_R_INVALIDARG) { | |
1746 | printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); | |
1747 | return 1; | |
1748 | } | |
1749 | pool_copy = (struct ipv6_pool *)1; | |
1750 | if (ipv6_pool_reference(&pool_copy, pool, MDL) != ISC_R_INVALIDARG) { | |
1751 | printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); | |
1752 | return 1; | |
1753 | } | |
1754 | pool_copy = NULL; | |
1755 | if (ipv6_pool_reference(&pool_copy, NULL, MDL) != ISC_R_INVALIDARG) { | |
1756 | printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); | |
1757 | return 1; | |
1758 | } | |
1759 | if (ipv6_pool_dereference(NULL, MDL) != ISC_R_INVALIDARG) { | |
1760 | printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); | |
1761 | return 1; | |
1762 | } | |
1763 | if (ipv6_pool_dereference(&pool_copy, MDL) != ISC_R_INVALIDARG) { | |
1764 | printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); | |
1765 | return 1; | |
1766 | } | |
1767 | ||
1768 | /* | |
1769 | * Test 7: order of expiration | |
1770 | */ | |
1771 | pool = NULL; | |
1772 | if (ipv6_pool_allocate(&pool, &addr, 64, MDL) != ISC_R_SUCCESS) { | |
1773 | printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); | |
1774 | return 1; | |
1775 | } | |
1776 | for (i=10; i<100; i+=10) { | |
1777 | if (activate_lease6(pool, &iaaddr, &attempts, | |
1778 | &ds, i) != ISC_R_SUCCESS) { | |
1779 | printf("ERROR: activate_lease6() %s:%d\n", MDL); | |
1780 | return 1; | |
1781 | } | |
1782 | if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
1783 | printf("ERROR: iaaddr_dereference() %s:%d\n", MDL); | |
1784 | return 1; | |
1785 | } | |
1786 | if (pool->num_active != (i / 10)) { | |
1787 | printf("ERROR: bad num_active %s:%d\n", MDL); | |
1788 | return 1; | |
1789 | } | |
1790 | } | |
1791 | if (pool->num_active != 9) { | |
1792 | printf("ERROR: bad num_active %s:%d\n", MDL); | |
1793 | return 1; | |
1794 | } | |
1795 | for (i=10; i<100; i+=10) { | |
1796 | if (expire_lease6(&expired_iaaddr, | |
1797 | pool, 1000) != ISC_R_SUCCESS) { | |
1798 | printf("ERROR: expire_lease6() %s:%d\n", MDL); | |
1799 | return 1; | |
1800 | } | |
1801 | if (expired_iaaddr == NULL) { | |
1802 | printf("ERROR: should have expired a lease %s:%d\n", | |
1803 | MDL); | |
1804 | return 1; | |
1805 | } | |
1806 | if (pool->num_active != (9 - (i / 10))) { | |
1807 | printf("ERROR: bad num_active %s:%d\n", MDL); | |
1808 | return 1; | |
1809 | } | |
1810 | if (expired_iaaddr->valid_lifetime_end_time != i) { | |
1811 | printf("ERROR: bad valid_lifetime_end_time %s:%d\n", | |
1812 | MDL); | |
1813 | return 1; | |
1814 | } | |
1815 | if (iaaddr_dereference(&expired_iaaddr, MDL) != ISC_R_SUCCESS) { | |
1816 | printf("ERROR: iaaddr_dereference() %s:%d\n", MDL); | |
1817 | return 1; | |
1818 | } | |
1819 | } | |
1820 | if (pool->num_active != 0) { | |
1821 | printf("ERROR: bad num_active %s:%d\n", MDL); | |
1822 | return 1; | |
1823 | } | |
1824 | expired_iaaddr = NULL; | |
1825 | if (expire_lease6(&expired_iaaddr, pool, 1000) != ISC_R_SUCCESS) { | |
1826 | printf("ERROR: expire_lease6() %s:%d\n", MDL); | |
1827 | return 1; | |
1828 | } | |
1829 | if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { | |
1830 | printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); | |
1831 | return 1; | |
1832 | } | |
1833 | ||
1834 | /* | |
1835 | * Test 8: small pool | |
1836 | */ | |
1837 | pool = NULL; | |
1838 | if (ipv6_pool_allocate(&pool, &addr, 127, MDL) != ISC_R_SUCCESS) { | |
1839 | printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); | |
1840 | return 1; | |
1841 | } | |
1842 | if (activate_lease6(pool, &iaaddr, &attempts, | |
1843 | &ds, 42) != ISC_R_SUCCESS) { | |
1844 | printf("ERROR: activate_lease6() %s:%d\n", MDL); | |
1845 | return 1; | |
1846 | } | |
1847 | if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
1848 | printf("ERROR: iaaddr_dereference() %s:%d\n", MDL); | |
1849 | return 1; | |
1850 | } | |
1851 | if (activate_lease6(pool, &iaaddr, &attempts, | |
1852 | &ds, 11) != ISC_R_SUCCESS) { | |
1853 | printf("ERROR: activate_lease6() %s:%d\n", MDL); | |
1854 | return 1; | |
1855 | } | |
1856 | if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { | |
1857 | printf("ERROR: iaaddr_dereference() %s:%d\n", MDL); | |
1858 | return 1; | |
1859 | } | |
1860 | if (activate_lease6(pool, &iaaddr, &attempts, | |
1861 | &ds, 11) != ISC_R_NORESOURCES) { | |
1862 | printf("ERROR: activate_lease6() %s:%d\n", MDL); | |
1863 | return 1; | |
1864 | } | |
1865 | if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { | |
1866 | printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); | |
1867 | return 1; | |
1868 | } | |
1869 | ||
1870 | /* | |
1871 | * Test 9: functions across all pools | |
1872 | */ | |
1873 | pool = NULL; | |
1874 | if (ipv6_pool_allocate(&pool, &addr, 64, MDL) != ISC_R_SUCCESS) { | |
1875 | printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); | |
1876 | return 1; | |
1877 | } | |
1878 | if (add_ipv6_pool(pool) != ISC_R_SUCCESS) { | |
1879 | printf("ERROR: add_ipv6_pool() %s:%d\n", MDL); | |
1880 | return 1; | |
1881 | } | |
1882 | if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { | |
1883 | printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); | |
1884 | return 1; | |
1885 | } | |
1886 | pool = NULL; | |
1887 | if (find_ipv6_pool(&pool, &addr) != ISC_R_SUCCESS) { | |
1888 | printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); | |
1889 | return 1; | |
1890 | } | |
1891 | if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { | |
1892 | printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); | |
1893 | return 1; | |
1894 | } | |
1895 | inet_pton(AF_INET6, "1:2:3:4:ffff:ffff:ffff:ffff", &addr); | |
1896 | pool = NULL; | |
1897 | if (find_ipv6_pool(&pool, &addr) != ISC_R_SUCCESS) { | |
1898 | printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); | |
1899 | return 1; | |
1900 | } | |
1901 | if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { | |
1902 | printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); | |
1903 | return 1; | |
1904 | } | |
1905 | inet_pton(AF_INET6, "1:2:3:5::", &addr); | |
1906 | pool = NULL; | |
1907 | if (find_ipv6_pool(&pool, &addr) != ISC_R_NOTFOUND) { | |
1908 | printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); | |
1909 | return 1; | |
1910 | } | |
1911 | inet_pton(AF_INET6, "1:2:3:3:ffff:ffff:ffff:ffff", &addr); | |
1912 | pool = NULL; | |
1913 | if (find_ipv6_pool(&pool, &addr) != ISC_R_NOTFOUND) { | |
1914 | printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); | |
1915 | return 1; | |
1916 | } | |
1917 | ||
1918 | /* iaid = 666; | |
1919 | ia_na = NULL; | |
1920 | if (ia_na_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { | |
1921 | printf("ERROR: ia_na_allocate() %s:%d\n", MDL); | |
1922 | return 1; | |
1923 | }*/ | |
1924 | ||
1925 | printf("SUCCESS: all tests passed (ignore any warning messages)\n"); | |
1926 | return 0; | |
1927 | } | |
1928 | #endif |