]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp6-lease.c
Merge pull request #21264 from medhefgo/boot-lto
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp6-lease.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /***
3 Copyright © 2014-2015 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <errno.h>
7
8 #include "alloc-util.h"
9 #include "dhcp6-lease-internal.h"
10 #include "dhcp6-protocol.h"
11 #include "strv.h"
12 #include "util.h"
13
14 int sd_dhcp6_lease_get_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_t *ret) {
15 assert_return(lease, -EINVAL);
16 assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP);
17 assert_return(clock_supported(clock), -EOPNOTSUPP);
18 assert_return(ret, -EINVAL);
19
20 if (!triple_timestamp_is_set(&lease->timestamp))
21 return -ENODATA;
22
23 *ret = triple_timestamp_by_clock(&lease->timestamp, clock);
24 return 0;
25 }
26
27 int sd_dhcp6_lease_get_server_address(sd_dhcp6_lease *lease, struct in6_addr *ret) {
28 assert_return(lease, -EINVAL);
29 assert_return(ret, -EINVAL);
30
31 *ret = lease->server_address;
32 return 0;
33 }
34
35 int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) {
36 DHCP6Address *addr;
37 uint32_t valid = 0, t;
38
39 assert_return(ia, -EINVAL);
40 assert_return(expire, -EINVAL);
41
42 LIST_FOREACH(addresses, addr, ia->addresses) {
43 t = be32toh(addr->iaaddr.lifetime_valid);
44 if (valid < t)
45 valid = t;
46 }
47
48 t = be32toh(ia->ia_na.lifetime_t2);
49 if (t > valid)
50 return -EINVAL;
51
52 *expire = valid - t;
53
54 return 0;
55 }
56
57 DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia) {
58 DHCP6Address *address;
59
60 if (!ia)
61 return NULL;
62
63 while (ia->addresses) {
64 address = ia->addresses;
65
66 LIST_REMOVE(addresses, ia->addresses, address);
67
68 free(address);
69 }
70
71 return NULL;
72 }
73
74 int dhcp6_lease_set_clientid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len) {
75 uint8_t *clientid;
76
77 assert_return(lease, -EINVAL);
78 assert_return(id, -EINVAL);
79 assert_return(len > 0, -EINVAL);
80
81 clientid = memdup(id, len);
82 if (!clientid)
83 return -ENOMEM;
84
85 free_and_replace(lease->clientid, clientid);
86 lease->clientid_len = len;
87
88 return 0;
89 }
90
91 int dhcp6_lease_get_clientid(sd_dhcp6_lease *lease, uint8_t **ret_id, size_t *ret_len) {
92 assert_return(lease, -EINVAL);
93
94 if (!lease->clientid)
95 return -ENODATA;
96
97 if (ret_id)
98 *ret_id = lease->clientid;
99 if (ret_len)
100 *ret_len = lease->clientid_len;
101
102 return 0;
103 }
104
105 int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len) {
106 uint8_t *serverid;
107
108 assert_return(lease, -EINVAL);
109 assert_return(id, -EINVAL);
110 assert_return(len > 0, -EINVAL);
111
112 serverid = memdup(id, len);
113 if (!serverid)
114 return -ENOMEM;
115
116 free_and_replace(lease->serverid, serverid);
117 lease->serverid_len = len;
118
119 return 0;
120 }
121
122 int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **ret_id, size_t *ret_len) {
123 assert_return(lease, -EINVAL);
124
125 if (!lease->serverid)
126 return -ENODATA;
127
128 if (ret_id)
129 *ret_id = lease->serverid;
130 if (ret_len)
131 *ret_len = lease->serverid_len;
132
133 return 0;
134 }
135
136 int dhcp6_lease_set_preference(sd_dhcp6_lease *lease, uint8_t preference) {
137 assert_return(lease, -EINVAL);
138
139 lease->preference = preference;
140
141 return 0;
142 }
143
144 int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *preference) {
145 assert_return(preference, -EINVAL);
146
147 if (!lease)
148 return -EINVAL;
149
150 *preference = lease->preference;
151
152 return 0;
153 }
154
155 int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease) {
156 assert_return(lease, -EINVAL);
157
158 lease->rapid_commit = true;
159
160 return 0;
161 }
162
163 int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit) {
164 assert_return(lease, -EINVAL);
165 assert_return(rapid_commit, -EINVAL);
166
167 *rapid_commit = lease->rapid_commit;
168
169 return 0;
170 }
171
172 int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr,
173 uint32_t *lifetime_preferred,
174 uint32_t *lifetime_valid) {
175 assert_return(lease, -EINVAL);
176 assert_return(addr, -EINVAL);
177 assert_return(lifetime_preferred, -EINVAL);
178 assert_return(lifetime_valid, -EINVAL);
179
180 if (!lease->addr_iter)
181 return -ENOMSG;
182
183 memcpy(addr, &lease->addr_iter->iaaddr.address,
184 sizeof(struct in6_addr));
185 *lifetime_preferred =
186 be32toh(lease->addr_iter->iaaddr.lifetime_preferred);
187 *lifetime_valid = be32toh(lease->addr_iter->iaaddr.lifetime_valid);
188
189 lease->addr_iter = lease->addr_iter->addresses_next;
190
191 return 0;
192 }
193
194 void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease) {
195 if (lease)
196 lease->addr_iter = lease->ia.addresses;
197 }
198
199 int sd_dhcp6_lease_get_pd(sd_dhcp6_lease *lease, struct in6_addr *prefix,
200 uint8_t *prefix_len,
201 uint32_t *lifetime_preferred,
202 uint32_t *lifetime_valid) {
203 assert_return(lease, -EINVAL);
204 assert_return(prefix, -EINVAL);
205 assert_return(prefix_len, -EINVAL);
206 assert_return(lifetime_preferred, -EINVAL);
207 assert_return(lifetime_valid, -EINVAL);
208
209 if (!lease->prefix_iter)
210 return -ENOMSG;
211
212 memcpy(prefix, &lease->prefix_iter->iapdprefix.address,
213 sizeof(struct in6_addr));
214 *prefix_len = lease->prefix_iter->iapdprefix.prefixlen;
215 *lifetime_preferred =
216 be32toh(lease->prefix_iter->iapdprefix.lifetime_preferred);
217 *lifetime_valid =
218 be32toh(lease->prefix_iter->iapdprefix.lifetime_valid);
219
220 lease->prefix_iter = lease->prefix_iter->addresses_next;
221
222 return 0;
223 }
224
225 void sd_dhcp6_lease_reset_pd_prefix_iter(sd_dhcp6_lease *lease) {
226 if (lease)
227 lease->prefix_iter = lease->pd.addresses;
228 }
229
230 int dhcp6_lease_add_dns(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
231 assert_return(lease, -EINVAL);
232 assert_return(optval, -EINVAL);
233
234 if (optlen == 0)
235 return 0;
236
237 return dhcp6_option_parse_addresses(optval, optlen, &lease->dns, &lease->dns_count);
238 }
239
240 int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, const struct in6_addr **ret) {
241 assert_return(lease, -EINVAL);
242
243 if (!lease->dns)
244 return -ENOENT;
245
246 if (ret)
247 *ret = lease->dns;
248
249 return lease->dns_count;
250 }
251
252 int dhcp6_lease_add_domains(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
253 _cleanup_strv_free_ char **domains = NULL;
254 int r;
255
256 assert_return(lease, -EINVAL);
257 assert_return(optval, -EINVAL);
258
259 if (optlen == 0)
260 return 0;
261
262 r = dhcp6_option_parse_domainname_list(optval, optlen, &domains);
263 if (r < 0)
264 return r;
265
266 return strv_extend_strv(&lease->domains, domains, true);
267 }
268
269 int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***ret) {
270 assert_return(lease, -EINVAL);
271 assert_return(ret, -EINVAL);
272
273 if (!lease->domains)
274 return -ENOENT;
275
276 *ret = lease->domains;
277 return strv_length(lease->domains);
278 }
279
280 int dhcp6_lease_add_ntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
281 int r;
282
283 assert_return(lease, -EINVAL);
284 assert_return(optval, -EINVAL);
285
286 for (size_t offset = 0; offset < optlen;) {
287 const uint8_t *subval;
288 size_t sublen;
289 uint16_t subopt;
290
291 r = dhcp6_option_parse(optval, optlen, &offset, &subopt, &sublen, &subval);
292 if (r < 0)
293 return r;
294
295 switch(subopt) {
296 case DHCP6_NTP_SUBOPTION_SRV_ADDR:
297 case DHCP6_NTP_SUBOPTION_MC_ADDR:
298 if (sublen != 16)
299 return 0;
300
301 r = dhcp6_option_parse_addresses(subval, sublen, &lease->ntp, &lease->ntp_count);
302 if (r < 0)
303 return r;
304
305 break;
306
307 case DHCP6_NTP_SUBOPTION_SRV_FQDN: {
308 _cleanup_free_ char *server = NULL;
309
310 r = dhcp6_option_parse_domainname(subval, sublen, &server);
311 if (r < 0)
312 return r;
313
314 if (strv_contains(lease->ntp_fqdn, server))
315 continue;
316
317 r = strv_consume(&lease->ntp_fqdn, TAKE_PTR(server));
318 if (r < 0)
319 return r;
320
321 break;
322 }}
323 }
324
325 return 0;
326 }
327
328 int dhcp6_lease_add_sntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
329 assert_return(lease, -EINVAL);
330 assert_return(optval, -EINVAL);
331
332 if (optlen == 0)
333 return 0;
334
335 /* SNTP option is defined in RFC4075, and deprecated by RFC5908. */
336 return dhcp6_option_parse_addresses(optval, optlen, &lease->sntp, &lease->sntp_count);
337 }
338
339 int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, const struct in6_addr **ret) {
340 assert_return(lease, -EINVAL);
341
342 if (lease->ntp) {
343 if (ret)
344 *ret = lease->ntp;
345 return lease->ntp_count;
346 }
347
348 if (lease->sntp && !lease->ntp_fqdn) {
349 /* Fallback to the deprecated SNTP option. */
350 if (ret)
351 *ret = lease->sntp;
352 return lease->sntp_count;
353 }
354
355 return -ENOENT;
356 }
357
358 int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ret) {
359 assert_return(lease, -EINVAL);
360
361 if (!lease->ntp_fqdn)
362 return -ENOENT;
363
364 if (ret)
365 *ret = lease->ntp_fqdn;
366 return strv_length(lease->ntp_fqdn);
367 }
368
369 int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
370 int r;
371 char *fqdn;
372
373 assert_return(lease, -EINVAL);
374 assert_return(optval, -EINVAL);
375
376 if (optlen < 2)
377 return -ENODATA;
378
379 /* Ignore the flags field, it doesn't carry any useful
380 information for clients. */
381 r = dhcp6_option_parse_domainname(optval + 1, optlen - 1, &fqdn);
382 if (r < 0)
383 return r;
384
385 return free_and_replace(lease->fqdn, fqdn);
386 }
387
388 int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease *lease, const char **ret) {
389 assert_return(lease, -EINVAL);
390 assert_return(ret, -EINVAL);
391
392 if (!lease->fqdn)
393 return -ENOENT;
394
395 *ret = lease->fqdn;
396 return 0;
397 }
398
399 static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) {
400 if (!lease)
401 return NULL;
402
403 free(lease->clientid);
404 free(lease->serverid);
405 dhcp6_lease_free_ia(&lease->ia);
406 dhcp6_lease_free_ia(&lease->pd);
407 free(lease->dns);
408 free(lease->fqdn);
409 strv_free(lease->domains);
410 free(lease->ntp);
411 strv_free(lease->ntp_fqdn);
412 free(lease->sntp);
413
414 return mfree(lease);
415 }
416
417 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_lease, sd_dhcp6_lease, dhcp6_lease_free);
418
419 int dhcp6_lease_new(sd_dhcp6_lease **ret) {
420 sd_dhcp6_lease *lease;
421
422 lease = new0(sd_dhcp6_lease, 1);
423 if (!lease)
424 return -ENOMEM;
425
426 lease->n_ref = 1;
427
428 LIST_HEAD_INIT(lease->ia.addresses);
429
430 *ret = lease;
431 return 0;
432 }