dhcp-identifier.c revision dbe81cbd2a93088236a2e4e41eeb33378940f7b9
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/***
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin This file is part of systemd.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner Copyright (C) 2015 Tom Gundersen <teg@jklmen>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin systemd is free software; you can redistribute it and/or modify it
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin under the terms of the GNU Lesser General Public License as published by
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin the Free Software Foundation; either version 2.1 of the License, or
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (at your option) any later version.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin systemd is distributed in the hope that it will be useful, but
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin WITHOUT ANY WARRANTY; without even the implied warranty of
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Lesser General Public License for more details.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin You should have received a copy of the GNU Lesser General Public License
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin along with systemd; If not, see <http://www.gnu.org/licenses/>.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin***/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "libudev.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "sd-id128.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "dhcp-identifier.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "dhcp6-protocol.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "network-internal.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "siphash24.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "sparse-endian.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "udev-util.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "virt.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define SYSTEMD_PEN 43793
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sd_id128_t machine_id;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin uint64_t hash;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int r;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin assert(duid);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin assert(len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin r = sd_id128_get_machine(&machine_id);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (r < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return r;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin unaligned_write_be16(&duid->type, DHCP6_DUID_EN);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *len = sizeof(duid->type) + sizeof(duid->en);
/* a bit of snake-oil perhaps, but no need to expose the machine-id
directly; duid->en.id might not be aligned, so we need to copy */
siphash24(&hash, &machine_id, sizeof(machine_id), HASH_KEY.bytes);
memcpy(duid->en.id, &hash, sizeof(duid->en.id));
return 0;
}
int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id) {
/* name is a pointer to memory in the udev_device struct, so must
have the same scope */
_cleanup_udev_device_unref_ struct udev_device *device = NULL;
const char *name = NULL;
uint64_t id;
if (detect_container() <= 0) {
/* not in a container, udev will be around */
_cleanup_udev_unref_ struct udev *udev;
char ifindex_str[2 + DECIMAL_STR_MAX(int)];
udev = udev_new();
if (!udev)
return -ENOMEM;
sprintf(ifindex_str, "n%d", ifindex);
device = udev_device_new_from_device_id(udev, ifindex_str);
if (device) {
if (udev_device_get_is_initialized(device) <= 0)
/* not yet ready */
return -EBUSY;
name = net_get_name(device);
}
}
if (name)
siphash24(&id, name, strlen(name), HASH_KEY.bytes);
else
/* fall back to MAC address if no predictable name available */
siphash24(&id, mac, mac_len, HASH_KEY.bytes);
/* fold into 32 bits */
unaligned_write_be32(_id, (id & 0xffffffff) ^ (id >> 32));
return 0;
}