diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/config.c | 7 | ||||
-rw-r--r-- | src/dhcpv6-ia.c | 47 | ||||
-rw-r--r-- | src/odhcpd.h | 1 | ||||
-rw-r--r-- | src/prng.h | 27 | ||||
-rw-r--r-- | src/prng_md5.c | 63 |
5 files changed, 121 insertions, 24 deletions
diff --git a/src/config.c b/src/config.c index 71b786c..bbac334 100644 --- a/src/config.c +++ b/src/config.c @@ -172,6 +172,7 @@ enum { ODHCPD_ATTR_LEASEFILE, ODHCPD_ATTR_LEASETRIGGER, ODHCPD_ATTR_LOGLEVEL, + ODHCPD_ATTR_SECRETKEY, ODHCPD_ATTR_MAX }; @@ -181,6 +182,7 @@ static const struct blobmsg_policy odhcpd_attrs[ODHCPD_ATTR_MAX] = { [ODHCPD_ATTR_LEASEFILE] = { .name = "leasefile", .type = BLOBMSG_TYPE_STRING }, [ODHCPD_ATTR_LEASETRIGGER] = { .name = "leasetrigger", .type = BLOBMSG_TYPE_STRING }, [ODHCPD_ATTR_LOGLEVEL] = { .name = "loglevel", .type = BLOBMSG_TYPE_INT32 }, + [ODHCPD_ATTR_SECRETKEY] = { .name = "secretkey", .type = BLOBMSG_TYPE_STRING }, }; const struct uci_blob_param_list odhcpd_attr_list = { @@ -326,6 +328,11 @@ static void set_config(struct uci_section *s) setlogmask(LOG_UPTO(config.log_level)); } } + + if ((c = tb[ODHCPD_ATTR_SECRETKEY])) { + free(config.secret_key); + config.secret_key = strdup(blobmsg_get_string(c)); + } } static double parse_leasetime(struct blob_attr *c) { diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c index e8255b5..bd4b6e1 100644 --- a/src/dhcpv6-ia.c +++ b/src/dhcpv6-ia.c @@ -16,6 +16,7 @@ #include "odhcpd.h" #include "dhcpv6.h" #include "dhcpv4.h" +#include "prng.h" #include <time.h> #include <errno.h> @@ -51,12 +52,15 @@ static struct netevent_handler dhcpv6_netevent_handler = { .cb = dhcpv6_netevent static struct uloop_timeout valid_until_timeout = {.cb = valid_until_cb}; static uint32_t serial = 0; static uint8_t statemd5[16]; +static prng_context_t *prng; int dhcpv6_ia_init(void) { uloop_timeout_set(&valid_until_timeout, 1000); netlink_add_netevent_handler(&dhcpv6_netevent_handler); + prng = prng_alloc(); + prng_setup(prng); return 0; } @@ -700,7 +704,6 @@ static bool is_reserved_ipv6_iid(uint64_t iid) static bool assign_na(struct interface *iface, struct dhcp_assignment *a) { struct dhcp_assignment *c; - uint32_t seed = 0; /* Preconfigured assignment by static lease */ if (a->assigned_host_id) { @@ -713,36 +716,32 @@ static bool assign_na(struct interface *iface, struct dhcp_assignment *a) } } - /* Seed RNG with checksum of DUID */ - for (size_t i = 0; i < a->clid_len; ++i) - seed += a->clid_data[i]; - srandom(seed); + uint8_t counter = 0; + uint64_t mask; + + if (iface->dhcpv6_hostid_len < 64) + mask = ((uint64_t)1 << (uint64_t)iface->dhcpv6_hostid_len) - 1; + else + mask = UINT64_MAX; /* Try to assign up to 100x */ for (size_t i = 0; i < 100; ++i) { - uint64_t try; + uint64_t try = 0; + uint32_t counter_be = htonl(counter); - if (iface->dhcpv6_hostid_len > 32) { - uint32_t mask_high; + prng_starts(prng); + prng_update(prng, a->clid_data, a->clid_len); + prng_update(prng, (const uint8_t*)&a->iaid, sizeof(a->iaid)); + prng_update(prng, (const uint8_t*)&counter_be, sizeof(counter_be)); + prng_update(prng, (const uint8_t*)&config.secret_key, sizeof(config.secret_key)); + prng_finish(prng, (uint8_t*)&try); - if (iface->dhcpv6_hostid_len >= 64) - mask_high = UINT32_MAX; - else - mask_high = (1 << (iface->dhcpv6_hostid_len - 32)) - 1; + try &= mask; - do { - try = (uint32_t)random(); - try |= (uint64_t)((uint32_t)random() & mask_high) << 32; - } while (try < 0x100); - } else { - uint32_t mask_low; + counter++; - if (iface->dhcpv6_hostid_len == 32) - mask_low = UINT32_MAX; - else - mask_low = (1 << iface->dhcpv6_hostid_len) - 1; - do try = ((uint32_t)random()) & mask_low; while (try < 0x100); - } + if (try < 0x100) + continue; if (is_reserved_ipv6_iid(try)) continue; diff --git a/src/odhcpd.h b/src/odhcpd.h index ff7e105..fff28d5 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -149,6 +149,7 @@ struct config { char *dhcp_cb; char *dhcp_statefile; int log_level; + char *secret_key; }; diff --git a/src/prng.h b/src/prng.h new file mode 100644 index 0000000..5a3da02 --- /dev/null +++ b/src/prng.h @@ -0,0 +1,27 @@ +/** + * Copyright (C) 2021 Mikael Magnusson <mikma@users.sourceforge.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2 for more details. + * + */ +#pragma once + +#include "prng.h" + +#include <stddef.h> +#include <stdint.h> + +typedef struct prng_context_s prng_context_t; + +prng_context_t *prng_alloc(); +void prng_setup(prng_context_t *ctx); +void prng_starts(prng_context_t *ctx); +void prng_update(prng_context_t *ctx, const uint8_t *input, size_t ilen); +void prng_finish(prng_context_t *ctx, uint8_t *output); diff --git a/src/prng_md5.c b/src/prng_md5.c new file mode 100644 index 0000000..77682a2 --- /dev/null +++ b/src/prng_md5.c @@ -0,0 +1,63 @@ +/** + * Copyright (C) 2021 Mikael Magnusson <mikma@user.sourceforge.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "prng.h" + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include <libubox/md5.h> + + +/* PRNG using MD5 from libubox. */ +struct prng_context_s +{ + md5_ctx_t md5; +}; + + +prng_context_t *prng_alloc() +{ + prng_context_t *ctx = calloc(1, sizeof(prng_context_t)); + return ctx; +} + +void prng_setup(prng_context_t *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); +} + +void prng_starts(prng_context_t *ctx) +{ + md5_begin(&ctx->md5); +} + +void prng_update(prng_context_t *ctx, const uint8_t *input, size_t ilen) +{ + md5_hash(input, ilen, &ctx->md5); +} + +void prng_finish(prng_context_t *ctx, uint8_t *output) +{ + uint8_t tmp[16]; + md5_end(tmp, &ctx->md5); + memcpy(output, tmp, 8); +} + +#if 0 +void prng_free() +{ +} +#endif |