]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/dhcp-identifier.c
tree-wide: sort includes
[thirdparty/systemd.git] / src / libsystemd-network / dhcp-identifier.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright (C) 2015 Tom Gundersen <teg@jklmen>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "sd-id128.h"
23
24 #include "dhcp-identifier.h"
25 #include "dhcp6-protocol.h"
26 #include "libudev.h"
27 #include "network-internal.h"
28 #include "siphash24.h"
29 #include "sparse-endian.h"
30 #include "udev-util.h"
31 #include "virt.h"
32
33 #define SYSTEMD_PEN 43793
34 #define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
35
36 int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
37 sd_id128_t machine_id;
38 uint64_t hash;
39 int r;
40
41 assert(duid);
42 assert(len);
43
44 r = sd_id128_get_machine(&machine_id);
45 if (r < 0)
46 return r;
47
48 unaligned_write_be16(&duid->type, DHCP6_DUID_EN);
49 unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN);
50
51 *len = sizeof(duid->type) + sizeof(duid->en);
52
53 /* a bit of snake-oil perhaps, but no need to expose the machine-id
54 directly; duid->en.id might not be aligned, so we need to copy */
55 siphash24(&hash, &machine_id, sizeof(machine_id), HASH_KEY.bytes);
56 memcpy(duid->en.id, &hash, sizeof(duid->en.id));
57
58 return 0;
59 }
60
61 int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id) {
62 /* name is a pointer to memory in the udev_device struct, so must
63 have the same scope */
64 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
65 const char *name = NULL;
66 uint64_t id;
67
68 if (detect_container() <= 0) {
69 /* not in a container, udev will be around */
70 _cleanup_udev_unref_ struct udev *udev;
71 char ifindex_str[2 + DECIMAL_STR_MAX(int)];
72
73 udev = udev_new();
74 if (!udev)
75 return -ENOMEM;
76
77 sprintf(ifindex_str, "n%d", ifindex);
78 device = udev_device_new_from_device_id(udev, ifindex_str);
79 if (device) {
80 if (udev_device_get_is_initialized(device) <= 0)
81 /* not yet ready */
82 return -EBUSY;
83
84 name = net_get_name(device);
85 }
86 }
87
88 if (name)
89 siphash24(&id, name, strlen(name), HASH_KEY.bytes);
90 else
91 /* fall back to MAC address if no predictable name available */
92 siphash24(&id, mac, mac_len, HASH_KEY.bytes);
93
94 /* fold into 32 bits */
95 unaligned_write_be32(_id, (id & 0xffffffff) ^ (id >> 32));
96
97 return 0;
98 }