]> git.proxmox.com Git - systemd.git/blame - src/libsystemd-network/dhcp-identifier.c
New upstream version 242
[systemd.git] / src / libsystemd-network / dhcp-identifier.c
CommitLineData
52ad194e 1/* SPDX-License-Identifier: LGPL-2.1+ */
e735f4d4 2
6e866b33
MB
3#include <linux/if_infiniband.h>
4#include <net/if_arp.h>
5
6#include "sd-device.h"
db2df898 7#include "sd-id128.h"
e735f4d4 8
e735f4d4 9#include "dhcp-identifier.h"
db2df898 10#include "dhcp6-protocol.h"
e735f4d4 11#include "network-internal.h"
db2df898
MP
12#include "siphash24.h"
13#include "sparse-endian.h"
7c20daf6 14#include "stdio-util.h"
bb4f798a 15#include "udev-util.h"
db2df898 16#include "virt.h"
e735f4d4 17
6e866b33
MB
18#define SYSTEMD_PEN 43793
19#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
20#define APPLICATION_ID SD_ID128_MAKE(a5,0a,d1,12,bf,60,45,77,a2,fb,74,1a,b1,95,5b,03)
21#define USEC_2000 ((usec_t) 946684800000000) /* 2000-01-01 00:00:00 UTC */
e735f4d4 22
6e866b33 23int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len, bool strict) {
aa27b158
MP
24 struct duid d;
25
26 assert_cc(sizeof(d.raw) >= MAX_DUID_LEN);
27 if (duid_len > MAX_DUID_LEN)
28 return -EINVAL;
29
6e866b33
MB
30 if (!strict) {
31 /* Strict validation is not requested. We only ensure that the
32 * DUID is not too long. */
33 return 0;
34 }
35
aa27b158
MP
36 switch (duid_type) {
37 case DUID_TYPE_LLT:
38 if (duid_len <= sizeof(d.llt))
39 return -EINVAL;
40 break;
41 case DUID_TYPE_EN:
42 if (duid_len != sizeof(d.en))
43 return -EINVAL;
44 break;
45 case DUID_TYPE_LL:
46 if (duid_len <= sizeof(d.ll))
47 return -EINVAL;
48 break;
49 case DUID_TYPE_UUID:
50 if (duid_len != sizeof(d.uuid))
51 return -EINVAL;
52 break;
53 default:
54 /* accept unknown type in order to be forward compatible */
55 break;
56 }
57 return 0;
58}
59
6e866b33
MB
60int dhcp_identifier_set_duid_llt(struct duid *duid, usec_t t, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len) {
61 uint16_t time_from_2000y;
62
63 assert(duid);
64 assert(len);
65 assert(addr);
66
67 if (arp_type == ARPHRD_ETHER)
68 assert_return(addr_len == ETH_ALEN, -EINVAL);
69 else if (arp_type == ARPHRD_INFINIBAND)
70 assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
71 else
72 return -EINVAL;
73
74 if (t < USEC_2000)
75 time_from_2000y = 0;
76 else
77 time_from_2000y = (uint16_t) (((t - USEC_2000) / USEC_PER_SEC) & 0xffffffff);
78
79 unaligned_write_be16(&duid->type, DUID_TYPE_LLT);
80 unaligned_write_be16(&duid->llt.htype, arp_type);
81 unaligned_write_be32(&duid->llt.time, time_from_2000y);
82 memcpy(duid->llt.haddr, addr, addr_len);
83
84 *len = sizeof(duid->type) + sizeof(duid->llt.htype) + sizeof(duid->llt.time) + addr_len;
85
86 return 0;
87}
88
89int dhcp_identifier_set_duid_ll(struct duid *duid, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len) {
90 assert(duid);
91 assert(len);
92 assert(addr);
93
94 if (arp_type == ARPHRD_ETHER)
95 assert_return(addr_len == ETH_ALEN, -EINVAL);
96 else if (arp_type == ARPHRD_INFINIBAND)
97 assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
98 else
99 return -EINVAL;
100
101 unaligned_write_be16(&duid->type, DUID_TYPE_LL);
102 unaligned_write_be16(&duid->ll.htype, arp_type);
103 memcpy(duid->ll.haddr, addr, addr_len);
104
105 *len = sizeof(duid->type) + sizeof(duid->ll.htype) + addr_len;
106
107 return 0;
108}
109
e735f4d4
MP
110int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
111 sd_id128_t machine_id;
db2df898 112 uint64_t hash;
e735f4d4
MP
113 int r;
114
115 assert(duid);
116 assert(len);
117
118 r = sd_id128_get_machine(&machine_id);
6e866b33
MB
119 if (r < 0) {
120#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
121 machine_id = SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10);
122#else
e735f4d4 123 return r;
6e866b33
MB
124#endif
125 }
e735f4d4 126
aa27b158 127 unaligned_write_be16(&duid->type, DUID_TYPE_EN);
e3bff60a
MP
128 unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN);
129
e735f4d4
MP
130 *len = sizeof(duid->type) + sizeof(duid->en);
131
132 /* a bit of snake-oil perhaps, but no need to expose the machine-id
6e866b33 133 * directly; duid->en.id might not be aligned, so we need to copy */
db2df898
MP
134 hash = htole64(siphash24(&machine_id, sizeof(machine_id), HASH_KEY.bytes));
135 memcpy(duid->en.id, &hash, sizeof(duid->en.id));
e735f4d4
MP
136
137 return 0;
138}
139
6e866b33
MB
140int dhcp_identifier_set_duid_uuid(struct duid *duid, size_t *len) {
141 sd_id128_t machine_id;
142 int r;
143
144 assert(duid);
145 assert(len);
146
147 r = sd_id128_get_machine_app_specific(APPLICATION_ID, &machine_id);
148 if (r < 0)
149 return r;
150
151 unaligned_write_be16(&duid->type, DUID_TYPE_UUID);
152 memcpy(&duid->raw.data, &machine_id, sizeof(machine_id));
153
154 *len = sizeof(duid->type) + sizeof(machine_id);
155
156 return 0;
157}
158
159int dhcp_identifier_set_iaid(
160 int ifindex,
161 const uint8_t *mac,
162 size_t mac_len,
163 bool legacy_unstable_byteorder,
164 void *_id) {
165 /* name is a pointer to memory in the sd_device struct, so must
166 * have the same scope */
167 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
e735f4d4
MP
168 const char *name = NULL;
169 uint64_t id;
6e866b33 170 uint32_t id32;
e735f4d4 171
6300502b 172 if (detect_container() <= 0) {
e735f4d4 173 /* not in a container, udev will be around */
7c20daf6 174 char ifindex_str[1 + DECIMAL_STR_MAX(int)];
6e866b33 175 int r;
e735f4d4 176
7c20daf6 177 xsprintf(ifindex_str, "n%d", ifindex);
6e866b33
MB
178 if (sd_device_new_from_device_id(&device, ifindex_str) >= 0) {
179 r = sd_device_get_is_initialized(device);
180 if (r < 0)
181 return r;
182 if (r == 0)
e735f4d4
MP
183 /* not yet ready */
184 return -EBUSY;
185
bb4f798a
MB
186 r = device_is_renaming(device);
187 if (r < 0)
188 return r;
189 if (r > 0)
190 /* device is under renaming */
191 return -EBUSY;
192
e735f4d4
MP
193 name = net_get_name(device);
194 }
195 }
196
197 if (name)
db2df898 198 id = siphash24(name, strlen(name), HASH_KEY.bytes);
e735f4d4
MP
199 else
200 /* fall back to MAC address if no predictable name available */
db2df898
MP
201 id = siphash24(mac, mac_len, HASH_KEY.bytes);
202
6e866b33 203 id32 = (id & 0xffffffff) ^ (id >> 32);
e735f4d4 204
6e866b33
MB
205 if (legacy_unstable_byteorder)
206 /* for historical reasons (a bug), the bits were swapped and thus
7c20daf6 207 * the result was endianness dependent. Preserve that behavior. */
6e866b33
MB
208 id32 = __bswap_32(id32);
209 else
210 /* the fixed behavior returns a stable byte order. Since LE is expected
211 * to be more common, swap the bytes on LE to give the same as legacy
212 * behavior. */
213 id32 = be32toh(id32);
e735f4d4 214
6e866b33 215 unaligned_write_ne32(_id, id32);
e735f4d4
MP
216 return 0;
217}