summaryrefslogtreecommitdiff
path: root/server/mdb6.c
diff options
context:
space:
mode:
authorFrancis Dupont <fdupont@isc.org>2008-02-20 12:45:53 +0000
committerFrancis Dupont <fdupont@isc.org>2008-02-20 12:45:53 +0000
commit80c9fdb0e739898bb28cae633e3aa6f6cd0ecd4d (patch)
tree00ad89185db10b5e2bbc6e6abcfc7b9cd8e05ae9 /server/mdb6.c
parent892379eca3644f16ba3c5517a9be655e713a55df (diff)
downloadisc-dhcp-80c9fdb0e739898bb28cae633e3aa6f6cd0ecd4d.tar.gz
Add IA_TA and IA_PD support in server
Diffstat (limited to 'server/mdb6.c')
-rw-r--r--server/mdb6.c231
1 files changed, 202 insertions, 29 deletions
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; i<net_bytes; i++) {
str[i] = net_str[i];
}
+ i = net_bytes;
switch (pool_bits % 8) {
case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
@@ -1594,15 +1644,16 @@ create_prefix(struct in6_addr *pref,
for (i=net_bytes+1; i<16; i++) {
str[i] = 0;
}
+ i = net_bytes;
switch (pref_bits % 8) {
- case 0: str[i] &= 0;
- case 1: str[i] &= 0x80;
- case 2: str[i] &= 0xC0;
- case 3: str[i] &= 0xE0;
- case 4: str[i] &= 0xF0;
- case 5: str[i] &= 0xF8;
- case 6: str[i] &= 0xFC;
- case 7: str[i] &= 0xFE;
+ case 0: str[i] &= 0; break;
+ case 1: str[i] &= 0x80; break;
+ case 2: str[i] &= 0xC0; break;
+ case 3: str[i] &= 0xE0; break;
+ case 4: str[i] &= 0xF0; break;
+ case 5: str[i] &= 0xF8; break;
+ case 6: str[i] &= 0xFC; break;
+ case 7: str[i] &= 0xFE; break;
}
}
@@ -1628,10 +1679,10 @@ create_prefix(struct in6_addr *pref,
* the long term.
*/
isc_result_t
-activate_prefix(struct ipv6_ppool *ppool, struct iaprefix **pref,
- unsigned int *attempts,
- const struct data_string *uid,
- time_t valid_lifetime_end_time) {
+activate_prefix6(struct ipv6_ppool *ppool, struct iaprefix **pref,
+ unsigned int *attempts,
+ const struct data_string *uid,
+ time_t valid_lifetime_end_time) {
struct data_string ds;
struct in6_addr tmp;
struct iaprefix *test_iapref;
@@ -1700,10 +1751,11 @@ activate_prefix(struct ipv6_ppool *ppool, struct iaprefix **pref,
if (result != ISC_R_SUCCESS) {
return result;
}
+ iapref->plen = 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; i<num_pools; i++) {
+ if (temp && ((pools[i]->bits & 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; i<ia->num_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; i<ip->v6address_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++)