summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/config.c7
-rw-r--r--src/dhcpv6-ia.c47
-rw-r--r--src/odhcpd.h1
-rw-r--r--src/prng.h27
-rw-r--r--src/prng_md5.c63
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