2014-03-19 10:12:32 +05:30
|
|
|
/* duiaid.c - DUID/IAID storage and generation for clientids
|
|
|
|
*
|
2017-01-12 17:00:44 +05:30
|
|
|
* Copyright (c) 2014-2017 Nicholas J. Kain <njkain at gmail dot com>
|
2014-03-19 10:12:32 +05:30
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are met:
|
|
|
|
*
|
|
|
|
* - Redistributions of source code must retain the above copyright notice,
|
|
|
|
* this list of conditions and the following disclaimer.
|
|
|
|
*
|
|
|
|
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
|
|
* and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <errno.h>
|
2014-03-31 02:32:48 +05:30
|
|
|
#include "nk/log.h"
|
|
|
|
#include "nk/random.h"
|
|
|
|
#include "nk/io.h"
|
2014-03-19 10:12:32 +05:30
|
|
|
#include "duiaid.h"
|
|
|
|
#include "ndhc.h"
|
|
|
|
|
2015-02-14 09:44:08 +05:30
|
|
|
static void get_duid_path(char duidfile[static 1], size_t dlen)
|
2014-03-19 10:12:32 +05:30
|
|
|
{
|
2014-03-21 08:56:19 +05:30
|
|
|
int splen = snprintf(duidfile, dlen, "%s/DUID", state_dir);
|
2014-03-31 02:51:27 +05:30
|
|
|
if (splen < 0)
|
|
|
|
suicide("%s: snprintf failed; return=%d", __func__, splen);
|
|
|
|
if ((size_t)splen >= dlen)
|
|
|
|
suicide("%s: snprintf dest buffer too small %d >= %u",
|
|
|
|
__func__, splen, sizeof dlen);
|
2014-03-19 10:12:32 +05:30
|
|
|
}
|
|
|
|
|
2015-02-14 09:44:08 +05:30
|
|
|
static void get_iaid_path(char iaidfile[static 1], size_t ilen,
|
|
|
|
const uint8_t hwaddr[static 6], size_t hwaddrlen)
|
2014-03-19 10:12:32 +05:30
|
|
|
{
|
2014-03-31 02:51:27 +05:30
|
|
|
if (hwaddrlen != 6)
|
|
|
|
suicide("%s: Hardware address length=%u != 6 bytes",
|
|
|
|
__func__, hwaddrlen);
|
2014-03-19 10:12:32 +05:30
|
|
|
int splen = snprintf
|
2014-03-21 08:56:19 +05:30
|
|
|
(iaidfile, ilen,
|
2014-03-25 14:57:47 +05:30
|
|
|
"%s/IAID-%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
|
2014-03-19 13:42:24 +05:30
|
|
|
state_dir, hwaddr[0], hwaddr[1], hwaddr[2],
|
2014-03-19 10:12:32 +05:30
|
|
|
hwaddr[3], hwaddr[4], hwaddr[5]);
|
2014-03-31 02:51:27 +05:30
|
|
|
if (splen < 0)
|
|
|
|
suicide("%s: snprintf failed; return=%d", __func__, splen);
|
|
|
|
if ((size_t)splen >= ilen)
|
|
|
|
suicide("%s: snprintf dest buffer too small %d >= %u",
|
|
|
|
__func__, splen, sizeof ilen);
|
2014-03-19 10:12:32 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
static int open_duidfile_read(void)
|
|
|
|
{
|
2014-03-31 02:32:48 +05:30
|
|
|
char duidfile[PATH_MAX];
|
2014-03-19 10:12:32 +05:30
|
|
|
get_duid_path(duidfile, sizeof duidfile);
|
2014-03-19 15:28:29 +05:30
|
|
|
int fd = open(duidfile, O_RDONLY, 0);
|
2014-03-19 10:12:32 +05:30
|
|
|
if (fd < 0) {
|
|
|
|
log_line("Failed to open duidfile '%s' for reading: %s",
|
|
|
|
duidfile, strerror(errno));
|
|
|
|
}
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int open_duidfile_write(void)
|
|
|
|
{
|
2014-03-31 02:32:48 +05:30
|
|
|
char duidfile[PATH_MAX];
|
2014-03-19 10:12:32 +05:30
|
|
|
get_duid_path(duidfile, sizeof duidfile);
|
2014-03-19 15:28:29 +05:30
|
|
|
int fd = open(duidfile, O_WRONLY|O_TRUNC|O_CREAT, 0644);
|
2014-03-31 02:51:27 +05:30
|
|
|
if (fd < 0)
|
|
|
|
suicide("Failed to open duidfile '%s' for writing: %s",
|
|
|
|
duidfile, strerror(errno));
|
2014-03-19 10:12:32 +05:30
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2015-02-14 09:44:08 +05:30
|
|
|
static int open_iaidfile_read(const uint8_t hwaddr[static 6], size_t hwaddrlen)
|
2014-03-19 10:12:32 +05:30
|
|
|
{
|
2014-03-31 02:32:48 +05:30
|
|
|
char iaidfile[PATH_MAX];
|
2014-03-19 10:12:32 +05:30
|
|
|
get_iaid_path(iaidfile, sizeof iaidfile, hwaddr, hwaddrlen);
|
2014-03-19 15:28:29 +05:30
|
|
|
int fd = open(iaidfile, O_RDONLY, 0);
|
2014-03-19 10:12:32 +05:30
|
|
|
if (fd < 0) {
|
|
|
|
log_line("Failed to open iaidfile '%s' for reading: %s",
|
|
|
|
iaidfile, strerror(errno));
|
|
|
|
}
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2015-02-14 09:44:08 +05:30
|
|
|
static int open_iaidfile_write(const uint8_t hwaddr[static 6],
|
|
|
|
size_t hwaddrlen)
|
2014-03-19 10:12:32 +05:30
|
|
|
{
|
2014-03-31 02:32:48 +05:30
|
|
|
char iaidfile[PATH_MAX];
|
2014-03-19 10:12:32 +05:30
|
|
|
get_iaid_path(iaidfile, sizeof iaidfile, hwaddr, hwaddrlen);
|
2014-03-19 15:28:29 +05:30
|
|
|
int fd = open(iaidfile, O_WRONLY|O_TRUNC|O_CREAT, 0644);
|
2014-03-31 02:51:27 +05:30
|
|
|
if (fd < 0)
|
|
|
|
suicide("Failed to open iaidfile '%s' for writing: %s",
|
|
|
|
iaidfile, strerror(errno));
|
2014-03-19 10:12:32 +05:30
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We use DUID-UUID (RFC6355)
|
|
|
|
// It is a 16-bit type=4 in network byte order followed by a 128-byte UUID.
|
|
|
|
// RFC6355 specifies a RFC4122 UUID, but I simply use a 128-byte random
|
|
|
|
// value, as the complexity of RFC4122 UUID generation is completely
|
|
|
|
// unwarranted for DHCPv4.
|
2015-02-14 09:44:08 +05:30
|
|
|
static size_t generate_duid(struct nk_random_state_u32 s[static 1],
|
|
|
|
char dest[static 1], size_t dlen)
|
2014-03-19 10:12:32 +05:30
|
|
|
{
|
|
|
|
const size_t tlen = sizeof(uint16_t) + 4 * sizeof(uint32_t);
|
2014-03-31 02:51:27 +05:30
|
|
|
if (dlen < tlen)
|
|
|
|
suicide("%s: dlen < %u", __func__, tlen);
|
2014-03-19 10:12:32 +05:30
|
|
|
size_t off = 0;
|
|
|
|
|
|
|
|
uint16_t typefield = htons(4);
|
|
|
|
memcpy(dest+off, &typefield, sizeof typefield);
|
|
|
|
off += sizeof typefield;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < 4; ++i) {
|
|
|
|
uint32_t r32 = nk_random_u32(s);
|
|
|
|
memcpy(dest+off, &r32, sizeof r32);
|
|
|
|
off += sizeof r32;
|
|
|
|
}
|
2014-03-21 08:56:19 +05:30
|
|
|
return off;
|
2014-03-19 10:12:32 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
// RFC6355 specifies the IAID as a 32-bit value that uniquely identifies
|
|
|
|
// a hardware link for a given host.
|
2015-02-14 09:44:08 +05:30
|
|
|
static size_t generate_iaid(struct nk_random_state_u32 s[static 1],
|
|
|
|
char dest[static 1], size_t dlen)
|
2014-03-19 10:12:32 +05:30
|
|
|
{
|
2014-03-31 02:51:27 +05:30
|
|
|
if (dlen < sizeof(uint32_t))
|
|
|
|
suicide("%s: dlen < %u", __func__, sizeof(uint32_t));
|
2014-03-19 10:12:32 +05:30
|
|
|
size_t off = 0;
|
|
|
|
|
|
|
|
uint32_t r32 = nk_random_u32(s);
|
|
|
|
memcpy(dest+off, &r32, sizeof r32);
|
|
|
|
off += sizeof r32;
|
2014-03-21 08:56:19 +05:30
|
|
|
return off;
|
2014-03-19 10:12:32 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
// Failures are all fatal.
|
2015-02-14 09:44:08 +05:30
|
|
|
void get_clientid(struct client_state_t cs[static 1],
|
|
|
|
struct client_config_t cc[static 1])
|
2014-03-19 10:12:32 +05:30
|
|
|
{
|
|
|
|
if (cc->clientid_len > 0)
|
|
|
|
return;
|
|
|
|
char iaid[sizeof cc->clientid];
|
|
|
|
char duid[sizeof cc->clientid];
|
|
|
|
size_t iaid_len;
|
|
|
|
size_t duid_len;
|
2014-03-21 08:56:19 +05:30
|
|
|
|
2014-03-19 10:12:32 +05:30
|
|
|
int fd = open_iaidfile_read(cc->arp, sizeof cc->arp);
|
|
|
|
if (fd < 0) {
|
|
|
|
iaid_len = generate_iaid(&cs->rnd32_state, iaid, sizeof iaid);
|
|
|
|
fd = open_iaidfile_write(cc->arp, sizeof cc->arp);
|
2014-04-06 15:54:13 +05:30
|
|
|
ssize_t r = safe_write(fd, iaid, iaid_len);
|
2014-03-31 02:51:27 +05:30
|
|
|
if (r < 0 || (size_t)r != iaid_len)
|
|
|
|
suicide("%s: (%s) failed to write generated IAID.",
|
|
|
|
cc->interface, __func__);
|
2014-03-19 10:12:32 +05:30
|
|
|
} else {
|
2014-04-06 15:54:13 +05:30
|
|
|
ssize_t r = safe_read(fd, iaid, sizeof iaid);
|
|
|
|
if (r < 0)
|
2014-04-06 15:36:53 +05:30
|
|
|
suicide("%s: (%s) failed to read IAID from file",
|
|
|
|
cc->interface, __func__);
|
2014-04-06 15:54:13 +05:30
|
|
|
iaid_len = (size_t)r;
|
2014-03-19 10:12:32 +05:30
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
fd = open_duidfile_read();
|
|
|
|
if (fd < 0) {
|
|
|
|
duid_len = generate_duid(&cs->rnd32_state, duid, sizeof duid);
|
|
|
|
fd = open_duidfile_write();
|
2014-04-06 15:54:13 +05:30
|
|
|
ssize_t r = safe_write(fd, duid, duid_len);
|
2014-03-31 02:51:27 +05:30
|
|
|
if (r < 0 || (size_t)r != duid_len)
|
|
|
|
suicide("%s: (%s) failed to write generated DUID.",
|
|
|
|
cc->interface, __func__);
|
2014-03-19 10:12:32 +05:30
|
|
|
} else {
|
2014-04-06 15:54:13 +05:30
|
|
|
ssize_t r = safe_read(fd, duid, sizeof duid);
|
|
|
|
if (r < 0)
|
2014-04-06 15:36:53 +05:30
|
|
|
suicide("%s: (%s) failed to read DUID from file",
|
|
|
|
cc->interface, __func__);
|
2014-04-06 15:54:13 +05:30
|
|
|
duid_len = (size_t)r;
|
2014-03-19 10:12:32 +05:30
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
const uint8_t cid_type = 255;
|
2014-03-21 08:56:19 +05:30
|
|
|
size_t cdl = sizeof cid_type + iaid_len + duid_len;
|
2014-03-31 02:51:27 +05:30
|
|
|
if (cdl > sizeof cc->clientid)
|
|
|
|
suicide("%s: (%s) clientid length %u > %u",
|
|
|
|
cc->interface, __func__, cdl, sizeof cc->clientid);
|
2014-03-19 10:12:32 +05:30
|
|
|
|
|
|
|
uint8_t cid_len = 0;
|
2014-03-21 08:56:19 +05:30
|
|
|
memcpy(cc->clientid + cid_len, &cid_type, sizeof cid_type);
|
2014-03-19 10:12:32 +05:30
|
|
|
cid_len += sizeof cid_type;
|
2014-03-21 08:56:19 +05:30
|
|
|
memcpy(cc->clientid + cid_len, iaid, iaid_len);
|
2014-03-19 10:12:32 +05:30
|
|
|
cid_len += iaid_len;
|
2014-03-21 08:56:19 +05:30
|
|
|
memcpy(cc->clientid + cid_len, duid, duid_len);
|
2014-03-19 10:12:32 +05:30
|
|
|
cid_len += duid_len;
|
|
|
|
cc->clientid_len = cid_len;
|
|
|
|
}
|
2014-03-21 08:56:19 +05:30
|
|
|
|