From 80c9fdb0e739898bb28cae633e3aa6f6cd0ecd4d Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Wed, 20 Feb 2008 12:45:53 +0000 Subject: Add IA_TA and IA_PD support in server --- server/mdb6.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 202 insertions(+), 29 deletions(-) (limited to 'server/mdb6.c') diff --git a/server/mdb6.c b/server/mdb6.c index 383facef..3cd3b2b7 100644 --- a/server/mdb6.c +++ b/server/mdb6.c @@ -1149,6 +1149,50 @@ create_address(struct in6_addr *addr, str[8] &= ~0x02; } +/* + * Create a temporary address by a variant of RFC 4941 algo. + */ +static void +create_temporary(struct in6_addr *addr, + const struct in6_addr *net_start_addr, + const struct data_string *input) { + static u_int8_t history[8]; + static u_int32_t counter = 0; + MD5_CTX ctx; + unsigned char md[16]; + extern int dst_s_random(u_int8_t *, unsigned); + + /* + * First time/time to reseed. + * Please use a good pseudo-random generator here! + */ + if (counter == 0) { + if (dst_s_random(history, 8) != 8) + log_fatal("Random failed."); + } + + /* + * Use MD5 as recommended by RFC 4941. + */ + MD5_Init(&ctx); + MD5_Update(&ctx, history, 8UL); + MD5_Update(&ctx, input->data, input->len); + MD5_Final(md, &ctx); + + /* + * Build the address. + */ + memcpy(&addr->s6_addr[0], &net_start_addr->s6_addr[0], 8); + memcpy(&addr->s6_addr[8], md, 8); + addr->s6_addr[8] &= ~0x02; + + /* + * Save history for the next call. + */ + memcpy(history, md + 8, 8); + counter++; +} + /* Reserved Subnet Router Anycast ::0:0:0:0. */ static struct in6_addr rtany; /* Reserved Subnet Anycasts ::fdff:ffff:ffff:ff80-::fdff:ffff:ffff:ffff. */ @@ -1216,9 +1260,14 @@ activate_lease6(struct ipv6_pool *pool, struct iaaddr **addr, } /* - * Create an address + * Create an address or a temporary address. */ - create_address(&tmp, &pool->start_addr, pool->bits, &ds); + if ((pool->bits & POOL_IS_FOR_TEMP) == 0) { + create_address(&tmp, &pool->start_addr, + pool->bits, &ds); + } else { + create_temporary(&tmp, &pool->start_addr, &ds); + } /* * Avoid reserved interface IDs. @@ -1277,7 +1326,7 @@ activate_lease6(struct ipv6_pool *pool, struct iaaddr **addr, memcpy(&iaaddr->addr, &tmp, sizeof(iaaddr->addr)); /* - * Add the lease to the pool. + * Add the lease to the pool (note state is free, not active?!). */ result = add_lease6(pool, iaaddr, valid_lifetime_end_time); if (result == ISC_R_SUCCESS) { @@ -1578,6 +1627,7 @@ create_prefix(struct in6_addr *pref, for (i=0; iplen = ppool->alloc_plen; memcpy(&iapref->pref, &tmp, sizeof(iapref->pref)); /* - * Add the prefix to the pool. + * Add the prefix to the pool (note state is free, not active?!). */ result = add_prefix6(ppool, iapref, valid_lifetime_end_time); if (result == ISC_R_SUCCESS) { @@ -1976,6 +2028,27 @@ mark_address_unavailable(struct ipv6_pool *pool, const struct in6_addr *addr) { return result; } +/* + * Mark an IPv6 prefix as unavailable from a prefix pool. + * + * This is used for host entries. + */ +isc_result_t +mark_prefix_unavailable(struct ipv6_ppool *ppool, + const struct in6_addr *pref) { + struct iaprefix *dummy_iapref; + isc_result_t result; + + dummy_iapref = NULL; + result = iaprefix_allocate(&dummy_iapref, MDL); + if (result == ISC_R_SUCCESS) { + dummy_iapref->pref = *pref; + iaprefix_hash_add(ppool->prefs, &dummy_iapref->pref, + sizeof(*pref), dummy_iapref, MDL); + } + return result; +} + /* * Add a pool. */ @@ -2374,7 +2447,7 @@ isc_boolean_t ipv6_addr_in_pool(const struct in6_addr *addr, const struct ipv6_pool *pool) { struct in6_addr tmp; - ipv6_network_portion(&tmp, addr, pool->bits); + ipv6_network_portion(&tmp, addr, pool->bits & ~POOL_IS_FOR_TEMP); if (memcmp(&tmp, &pool->start_addr, sizeof(tmp)) == 0) { return ISC_TRUE; } else { @@ -2389,7 +2462,8 @@ ipv6_addr_in_pool(const struct in6_addr *addr, const struct ipv6_pool *pool) { * initialized to NULL */ isc_result_t -find_ipv6_pool(struct ipv6_pool **pool, const struct in6_addr *addr) { +find_ipv6_pool(struct ipv6_pool **pool, int temp, + const struct in6_addr *addr) { int i; if (pool == NULL) { @@ -2402,6 +2476,12 @@ find_ipv6_pool(struct ipv6_pool **pool, const struct in6_addr *addr) { } for (i=0; ibits & POOL_IS_FOR_TEMP) == 0)) { + continue; + } + if (!temp && ((pools[i]->bits & POOL_IS_FOR_TEMP) != 0)) { + continue; + } if (ipv6_addr_in_pool(addr, pools[i])) { ipv6_pool_reference(pool, pools[i], MDL); return ISC_R_SUCCESS; @@ -2421,13 +2501,21 @@ change_leases(struct ia_na *ia, isc_result_t renew_retval; struct ipv6_pool *pool; struct in6_addr *addr; - int i; + int temp, i; retval = ISC_R_SUCCESS; + if (ia->ia_type == D6O_IA_NA) { + temp = 0; + } else if (ia->ia_type == D6O_IA_TA) { + temp = 1; + } else { + log_error("IA without type."); + return ISC_R_INVALIDARG; + } for (i=0; inum_iaaddr; i++) { pool = NULL; addr = &ia->iaaddr[i]->addr; - if (find_ipv6_pool(&pool, addr) == ISC_R_SUCCESS) { + if (find_ipv6_pool(&pool, temp, addr) == ISC_R_SUCCESS) { renew_retval = change_func(pool, ia->iaaddr[i]); if (renew_retval != ISC_R_SUCCESS) { retval = renew_retval; @@ -2655,7 +2743,11 @@ mark_hosts_unavailable_support(const void *name, unsigned len, void *value) { * sit in any pool.) */ p = NULL; - if (find_ipv6_pool(&p, &addr) == ISC_R_SUCCESS) { + if (find_ipv6_pool(&p, 0, &addr) == ISC_R_SUCCESS) { + mark_address_unavailable(p, &addr); + ipv6_pool_dereference(&p, MDL); + } + if (find_ipv6_pool(&p, 1, &addr) == ISC_R_SUCCESS) { mark_address_unavailable(p, &addr); ipv6_pool_dereference(&p, MDL); } @@ -2668,6 +2760,56 @@ mark_hosts_unavailable(void) { hash_foreach(host_name_hash, mark_hosts_unavailable_support); } +static isc_result_t +mark_phosts_unavailable_support(const void *name, unsigned len, void *value) { + struct host_decl *h; + struct iaddrcidrnetlist *l; + struct in6_addr pref; + struct ipv6_ppool *p; + + h = (struct host_decl *)value; + + /* + * If the host has no prefix, we don't need to mark anything. + */ + if (h->fixed_prefix == NULL) { + return ISC_R_SUCCESS; + } + + /* + * Get the fixed prefixes. + */ + for (l = h->fixed_prefix; l != NULL; l = l->next) { + if (l->cidrnet.lo_addr.len != 16) { + continue; + } + memcpy(&pref, l->cidrnet.lo_addr.iabuf, 16); + + /* + * Find the pool holding this host, and mark the prefix. + * (I suppose it is arguably valid to have a host that does not + * sit in any pool.) + */ + p = NULL; + if (find_ipv6_ppool(&p, &pref) != ISC_R_SUCCESS) { + continue; + } + if (l->cidrnet.bits != (int) p->alloc_plen) { + ipv6_ppool_dereference(&p, MDL); + continue; + } + mark_prefix_unavailable(p, &pref); + ipv6_ppool_dereference(&p, MDL); + } + + return ISC_R_SUCCESS; +} + +void +mark_phosts_unavailable(void) { + hash_foreach(host_name_hash, mark_phosts_unavailable_support); +} + void mark_interfaces_unavailable(void) { struct interface_info *ip; @@ -2678,7 +2820,13 @@ mark_interfaces_unavailable(void) { while (ip != NULL) { for (i=0; iv6address_count; i++) { p = NULL; - if (find_ipv6_pool(&p, &ip->v6addresses[i]) + if (find_ipv6_pool(&p, 0, &ip->v6addresses[i]) + == ISC_R_SUCCESS) { + mark_address_unavailable(p, + &ip->v6addresses[i]); + ipv6_pool_dereference(&p, MDL); + } + if (find_ipv6_pool(&p, 1, &ip->v6addresses[i]) == ISC_R_SUCCESS) { mark_address_unavailable(p, &ip->v6addresses[i]); @@ -3006,8 +3154,8 @@ main(int argc, char *argv[]) { printf("ERROR: activate_lease6() %s:%d\n", MDL); return 1; } - if (pool->num_active != 1) { - printf("ERROR: bad num_active %s:%d\n", MDL); + if (pool->num_inactive != 1) { + printf("ERROR: bad num_inactive %s:%d\n", MDL); return 1; } if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { @@ -3058,6 +3206,10 @@ main(int argc, char *argv[]) { printf("ERROR: activate_lease6() %s:%d\n", MDL); return 1; } + if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { + printf("ERROR: renew_lease6() %s:%d\n", MDL); + return 1; + } if (pool->num_active != 1) { printf("ERROR: bad num_active %s:%d\n", MDL); return 1; @@ -3079,6 +3231,10 @@ main(int argc, char *argv[]) { printf("ERROR: activate_lease6() %s:%d\n", MDL); return 1; } + if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { + printf("ERROR: renew_lease6() %s:%d\n", MDL); + return 1; + } if (pool->num_active != 1) { printf("ERROR: bad num_active %s:%d\n", MDL); return 1; @@ -3155,6 +3311,10 @@ main(int argc, char *argv[]) { printf("ERROR: activate_lease6() %s:%d\n", MDL); return 1; } + if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { + printf("ERROR: renew_lease6() %s:%d\n", MDL); + return 1; + } if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iaaddr_dereference() %s:%d\n", MDL); return 1; @@ -3211,6 +3371,7 @@ main(int argc, char *argv[]) { * Test 8: small pool */ pool = NULL; + addr.s6_addr[14] = 0x81; if (ipv6_pool_allocate(&pool, &addr, 127, MDL) != ISC_R_SUCCESS) { printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); return 1; @@ -3220,6 +3381,10 @@ main(int argc, char *argv[]) { printf("ERROR: activate_lease6() %s:%d\n", MDL); return 1; } + if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { + printf("ERROR: renew_lease6() %s:%d\n", MDL); + return 1; + } if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iaaddr_dereference() %s:%d\n", MDL); return 1; @@ -3229,6 +3394,10 @@ main(int argc, char *argv[]) { printf("ERROR: activate_lease6() %s:%d\n", MDL); return 1; } + if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { + printf("ERROR: renew_lease6() %s:%d\n", MDL); + return 1; + } if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iaaddr_dereference() %s:%d\n", MDL); return 1; @@ -3242,6 +3411,7 @@ main(int argc, char *argv[]) { printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); return 1; } + addr.s6_addr[14] = 0; /* * Test 9: functions across all pools @@ -3260,7 +3430,7 @@ main(int argc, char *argv[]) { return 1; } pool = NULL; - if (find_ipv6_pool(&pool, &addr) != ISC_R_SUCCESS) { + if (find_ipv6_pool(&pool, 0, &addr) != ISC_R_SUCCESS) { printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); return 1; } @@ -3270,7 +3440,7 @@ main(int argc, char *argv[]) { } inet_pton(AF_INET6, "1:2:3:4:ffff:ffff:ffff:ffff", &addr); pool = NULL; - if (find_ipv6_pool(&pool, &addr) != ISC_R_SUCCESS) { + if (find_ipv6_pool(&pool, 0, &addr) != ISC_R_SUCCESS) { printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); return 1; } @@ -3280,13 +3450,13 @@ main(int argc, char *argv[]) { } inet_pton(AF_INET6, "1:2:3:5::", &addr); pool = NULL; - if (find_ipv6_pool(&pool, &addr) != ISC_R_NOTFOUND) { + if (find_ipv6_pool(&pool, 0, &addr) != ISC_R_NOTFOUND) { printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); return 1; } inet_pton(AF_INET6, "1:2:3:3:ffff:ffff:ffff:ffff", &addr); pool = NULL; - if (find_ipv6_pool(&pool, &addr) != ISC_R_NOTFOUND) { + if (find_ipv6_pool(&pool, 0, &addr) != ISC_R_NOTFOUND) { printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); return 1; } @@ -3301,11 +3471,14 @@ main(int argc, char *argv[]) { { struct in6_addr r; struct data_string ds; + u_char data[16]; char buf[64]; int i, j; + memset(&ds, 0, sizeof(ds)); + memset(data, 0xaa, sizeof(data)); ds.len = 16; - ds.data = &addr; + ds.data = data; inet_pton(AF_INET6, "3ffe:501:ffff:100::", &addr); for (i = 32; i < 42; i++) -- cgit v1.2.1