|
8 | 8 | #include "sd-id128.h" |
9 | 9 |
|
10 | 10 | #include "dhcp-identifier.h" |
11 | | -#include "dhcp6-protocol.h" |
12 | 11 | #include "netif-util.h" |
13 | 12 | #include "siphash24.h" |
14 | 13 | #include "sparse-endian.h" |
15 | 14 | #include "stat-util.h" |
16 | | -#include "stdio-util.h" |
| 15 | +#include "string-table.h" |
17 | 16 | #include "udev-util.h" |
18 | | -#include "virt.h" |
19 | 17 |
|
20 | 18 | #define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) |
21 | 19 | #define APPLICATION_ID SD_ID128_MAKE(a5,0a,d1,12,bf,60,45,77,a2,fb,74,1a,b1,95,5b,03) |
22 | 20 | #define USEC_2000 ((usec_t) 946684800000000) /* 2000-01-01 00:00:00 UTC */ |
23 | 21 |
|
24 | | -int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len, bool strict) { |
| 22 | +static const char * const duid_type_table[_DUID_TYPE_MAX] = { |
| 23 | + [DUID_TYPE_LLT] = "DUID-LLT", |
| 24 | + [DUID_TYPE_EN] = "DUID-EN/Vendor", |
| 25 | + [DUID_TYPE_LL] = "DUID-LL", |
| 26 | + [DUID_TYPE_UUID] = "UUID", |
| 27 | +}; |
| 28 | + |
| 29 | +DEFINE_STRING_TABLE_LOOKUP_TO_STRING(duid_type, DUIDType); |
| 30 | + |
| 31 | +int dhcp_validate_duid_len(DUIDType duid_type, size_t duid_len, bool strict) { |
25 | 32 | struct duid d; |
26 | 33 |
|
27 | 34 | assert_cc(sizeof(d.raw) >= MAX_DUID_LEN); |
@@ -57,110 +64,146 @@ int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len, bool strict) { |
57 | 64 | return 0; |
58 | 65 | } |
59 | 66 |
|
60 | | -int 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) { |
| 67 | +static int dhcp_identifier_set_duid_llt(const uint8_t *addr, size_t addr_len, uint16_t arp_type, usec_t t, struct duid *ret_duid, size_t *ret_len) { |
61 | 68 | uint16_t time_from_2000y; |
62 | 69 |
|
63 | | - assert(duid); |
64 | | - assert(len); |
65 | 70 | assert(addr); |
| 71 | + assert(ret_duid); |
| 72 | + assert(ret_len); |
| 73 | + |
| 74 | + if (addr_len == 0) |
| 75 | + return -EOPNOTSUPP; |
66 | 76 |
|
67 | 77 | if (arp_type == ARPHRD_ETHER) |
68 | 78 | assert_return(addr_len == ETH_ALEN, -EINVAL); |
69 | 79 | else if (arp_type == ARPHRD_INFINIBAND) |
70 | 80 | assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); |
71 | 81 | else |
72 | | - return -EINVAL; |
| 82 | + return -EOPNOTSUPP; |
73 | 83 |
|
74 | 84 | if (t < USEC_2000) |
75 | 85 | time_from_2000y = 0; |
76 | 86 | else |
77 | 87 | time_from_2000y = (uint16_t) (((t - USEC_2000) / USEC_PER_SEC) & 0xffffffff); |
78 | 88 |
|
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); |
| 89 | + unaligned_write_be16(&ret_duid->type, DUID_TYPE_LLT); |
| 90 | + unaligned_write_be16(&ret_duid->llt.htype, arp_type); |
| 91 | + unaligned_write_be32(&ret_duid->llt.time, time_from_2000y); |
| 92 | + memcpy(ret_duid->llt.haddr, addr, addr_len); |
83 | 93 |
|
84 | | - *len = sizeof(duid->type) + sizeof(duid->llt.htype) + sizeof(duid->llt.time) + addr_len; |
| 94 | + *ret_len = sizeof(ret_duid->type) + sizeof(ret_duid->llt.htype) + sizeof(ret_duid->llt.time) + addr_len; |
85 | 95 |
|
86 | 96 | return 0; |
87 | 97 | } |
88 | 98 |
|
89 | | -int 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); |
| 99 | +static int dhcp_identifier_set_duid_ll(const uint8_t *addr, size_t addr_len, uint16_t arp_type, struct duid *ret_duid, size_t *ret_len) { |
92 | 100 | assert(addr); |
| 101 | + assert(ret_duid); |
| 102 | + assert(ret_len); |
| 103 | + |
| 104 | + if (addr_len == 0) |
| 105 | + return -EOPNOTSUPP; |
93 | 106 |
|
94 | 107 | if (arp_type == ARPHRD_ETHER) |
95 | 108 | assert_return(addr_len == ETH_ALEN, -EINVAL); |
96 | 109 | else if (arp_type == ARPHRD_INFINIBAND) |
97 | 110 | assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); |
98 | 111 | else |
99 | | - return -EINVAL; |
| 112 | + return -EOPNOTSUPP; |
100 | 113 |
|
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); |
| 114 | + unaligned_write_be16(&ret_duid->type, DUID_TYPE_LL); |
| 115 | + unaligned_write_be16(&ret_duid->ll.htype, arp_type); |
| 116 | + memcpy(ret_duid->ll.haddr, addr, addr_len); |
104 | 117 |
|
105 | | - *len = sizeof(duid->type) + sizeof(duid->ll.htype) + addr_len; |
| 118 | + *ret_len = sizeof(ret_duid->type) + sizeof(ret_duid->ll.htype) + addr_len; |
106 | 119 |
|
107 | 120 | return 0; |
108 | 121 | } |
109 | 122 |
|
110 | | -int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { |
| 123 | +int dhcp_identifier_set_duid_en(bool test_mode, struct duid *ret_duid, size_t *ret_len) { |
111 | 124 | sd_id128_t machine_id; |
112 | 125 | uint64_t hash; |
| 126 | + int r; |
113 | 127 |
|
114 | | - assert(duid); |
115 | | - assert(len); |
116 | | - |
117 | | -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
118 | | - int r = sd_id128_get_machine(&machine_id); |
119 | | - if (r < 0) |
120 | | - return r; |
121 | | -#else |
122 | | - machine_id = SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10); |
123 | | -#endif |
| 128 | + assert(ret_duid); |
| 129 | + assert(ret_len); |
124 | 130 |
|
125 | | - unaligned_write_be16(&duid->type, DUID_TYPE_EN); |
126 | | - unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN); |
| 131 | + if (!test_mode) { |
| 132 | + r = sd_id128_get_machine(&machine_id); |
| 133 | + if (r < 0) |
| 134 | + return r; |
| 135 | + } else |
| 136 | + /* For tests, especially for fuzzers, reproducibility is important. |
| 137 | + * Hence, use a static and constant machine ID. |
| 138 | + * See 9216fddc5a8ac2742e6cfa7660f95c20ca4f2193. */ |
| 139 | + machine_id = SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10); |
127 | 140 |
|
128 | | - *len = sizeof(duid->type) + sizeof(duid->en); |
| 141 | + unaligned_write_be16(&ret_duid->type, DUID_TYPE_EN); |
| 142 | + unaligned_write_be32(&ret_duid->en.pen, SYSTEMD_PEN); |
129 | 143 |
|
130 | 144 | /* a bit of snake-oil perhaps, but no need to expose the machine-id |
131 | 145 | * directly; duid->en.id might not be aligned, so we need to copy */ |
132 | 146 | hash = htole64(siphash24(&machine_id, sizeof(machine_id), HASH_KEY.bytes)); |
133 | | - memcpy(duid->en.id, &hash, sizeof(duid->en.id)); |
| 147 | + memcpy(ret_duid->en.id, &hash, sizeof(ret_duid->en.id)); |
| 148 | + |
| 149 | + *ret_len = sizeof(ret_duid->type) + sizeof(ret_duid->en); |
| 150 | + |
| 151 | + if (test_mode) |
| 152 | + assert_se(memcmp(ret_duid, (const uint8_t[]) { 0x00, 0x02, 0x00, 0x00, 0xab, 0x11, 0x61, 0x77, 0x40, 0xde, 0x13, 0x42, 0xc3, 0xa2 }, *ret_len) == 0); |
134 | 153 |
|
135 | 154 | return 0; |
136 | 155 | } |
137 | 156 |
|
138 | | -int dhcp_identifier_set_duid_uuid(struct duid *duid, size_t *len) { |
| 157 | +static int dhcp_identifier_set_duid_uuid(struct duid *ret_duid, size_t *ret_len) { |
139 | 158 | sd_id128_t machine_id; |
140 | 159 | int r; |
141 | 160 |
|
142 | | - assert(duid); |
143 | | - assert(len); |
| 161 | + assert(ret_duid); |
| 162 | + assert(ret_len); |
144 | 163 |
|
145 | 164 | r = sd_id128_get_machine_app_specific(APPLICATION_ID, &machine_id); |
146 | 165 | if (r < 0) |
147 | 166 | return r; |
148 | 167 |
|
149 | | - unaligned_write_be16(&duid->type, DUID_TYPE_UUID); |
150 | | - memcpy(&duid->raw.data, &machine_id, sizeof(machine_id)); |
| 168 | + unaligned_write_be16(&ret_duid->type, DUID_TYPE_UUID); |
| 169 | + memcpy(ret_duid->raw.data, &machine_id, sizeof(machine_id)); |
151 | 170 |
|
152 | | - *len = sizeof(duid->type) + sizeof(machine_id); |
| 171 | + *ret_len = sizeof(ret_duid->type) + sizeof(machine_id); |
153 | 172 |
|
154 | 173 | return 0; |
155 | 174 | } |
156 | 175 |
|
| 176 | +int dhcp_identifier_set_duid( |
| 177 | + DUIDType duid_type, |
| 178 | + const uint8_t *addr, |
| 179 | + size_t addr_len, |
| 180 | + uint16_t arp_type, |
| 181 | + usec_t llt_time, |
| 182 | + bool test_mode, |
| 183 | + struct duid *ret_duid, |
| 184 | + size_t *ret_len) { |
| 185 | + |
| 186 | + switch (duid_type) { |
| 187 | + case DUID_TYPE_LLT: |
| 188 | + return dhcp_identifier_set_duid_llt(addr, addr_len, arp_type, llt_time, ret_duid, ret_len); |
| 189 | + case DUID_TYPE_EN: |
| 190 | + return dhcp_identifier_set_duid_en(test_mode, ret_duid, ret_len); |
| 191 | + case DUID_TYPE_LL: |
| 192 | + return dhcp_identifier_set_duid_ll(addr, addr_len, arp_type, ret_duid, ret_len); |
| 193 | + case DUID_TYPE_UUID: |
| 194 | + return dhcp_identifier_set_duid_uuid(ret_duid, ret_len); |
| 195 | + default: |
| 196 | + return -EINVAL; |
| 197 | + } |
| 198 | +} |
| 199 | + |
157 | 200 | int dhcp_identifier_set_iaid( |
158 | 201 | int ifindex, |
159 | 202 | const uint8_t *mac, |
160 | 203 | size_t mac_len, |
161 | 204 | bool legacy_unstable_byteorder, |
162 | 205 | bool use_mac, |
163 | | - void *_id) { |
| 206 | + void *ret) { |
164 | 207 |
|
165 | 208 | /* name is a pointer to memory in the sd_device struct, so must |
166 | 209 | * have the same scope */ |
@@ -212,6 +255,6 @@ int dhcp_identifier_set_iaid( |
212 | 255 | * behavior. */ |
213 | 256 | id32 = be32toh(id32); |
214 | 257 |
|
215 | | - unaligned_write_ne32(_id, id32); |
| 258 | + unaligned_write_ne32(ret, id32); |
216 | 259 | return 0; |
217 | 260 | } |
0 commit comments