]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp6-lease.c
Merge pull request #20056 from calestyo/split-up-sysusers.d-systemd.conf.in
[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 assert_return(ret, -EINVAL);
243
244 if (!lease->dns)
245 return -ENOENT;
246
247 *ret = lease->dns;
248 return lease->dns_count;
249 }
250
251 int dhcp6_lease_add_domains(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
252 _cleanup_strv_free_ char **domains = NULL;
253 int r;
254
255 assert_return(lease, -EINVAL);
256 assert_return(optval, -EINVAL);
257
258 if (optlen == 0)
259 return 0;
260
261 r = dhcp6_option_parse_domainname_list(optval, optlen, &domains);
262 if (r < 0)
263 return r;
264
265 return strv_extend_strv(&lease->domains, domains, true);
266 }
267
268 int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***ret) {
269 assert_return(lease, -EINVAL);
270 assert_return(ret, -EINVAL);
271
272 if (!lease->domains)
273 return -ENOENT;
274
275 *ret = lease->domains;
276 return strv_length(lease->domains);
277 }
278
279 int dhcp6_lease_add_ntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
280 int r;
281
282 assert_return(lease, -EINVAL);
283 assert_return(optval, -EINVAL);
284
285 for (size_t offset = 0; offset < optlen;) {
286 const uint8_t *subval;
287 size_t sublen;
288 uint16_t subopt;
289
290 r = dhcp6_option_parse(optval, optlen, &offset, &subopt, &sublen, &subval);
291 if (r < 0)
292 return r;
293
294 switch(subopt) {
295 case DHCP6_NTP_SUBOPTION_SRV_ADDR:
296 case DHCP6_NTP_SUBOPTION_MC_ADDR:
297 if (sublen != 16)
298 return 0;
299
300 r = dhcp6_option_parse_addresses(subval, sublen, &lease->ntp, &lease->ntp_count);
301 if (r < 0)
302 return r;
303
304 break;
305
306 case DHCP6_NTP_SUBOPTION_SRV_FQDN: {
307 _cleanup_free_ char *server = NULL;
308
309 r = dhcp6_option_parse_domainname(subval, sublen, &server);
310 if (r < 0)
311 return r;
312
313 if (strv_contains(lease->ntp_fqdn, server))
314 continue;
315
316 r = strv_consume(&lease->ntp_fqdn, TAKE_PTR(server));
317 if (r < 0)
318 return r;
319
320 break;
321 }}
322 }
323
324 return 0;
325 }
326
327 int dhcp6_lease_add_sntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
328 assert_return(lease, -EINVAL);
329 assert_return(optval, -EINVAL);
330
331 if (optlen == 0)
332 return 0;
333
334 /* SNTP option is defined in RFC4075, and deprecated by RFC5908. */
335 return dhcp6_option_parse_addresses(optval, optlen, &lease->sntp, &lease->sntp_count);
336 }
337
338 int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, const struct in6_addr **ret) {
339 assert_return(lease, -EINVAL);
340 assert_return(ret, -EINVAL);
341
342 if (lease->ntp) {
343 *ret = lease->ntp;
344 return lease->ntp_count;
345 }
346
347 if (lease->sntp && !lease->ntp_fqdn) {
348 /* Fallback to the deprecated SNTP option. */
349 *ret = lease->sntp;
350 return lease->sntp_count;
351 }
352
353 return -ENOENT;
354 }
355
356 int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ret) {
357 assert_return(lease, -EINVAL);
358 assert_return(ret, -EINVAL);
359
360 if (!lease->ntp_fqdn)
361 return -ENOENT;
362
363 *ret = lease->ntp_fqdn;
364 return strv_length(lease->ntp_fqdn);
365 }
366
367 int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
368 int r;
369 char *fqdn;
370
371 assert_return(lease, -EINVAL);
372 assert_return(optval, -EINVAL);
373
374 if (optlen < 2)
375 return -ENODATA;
376
377 /* Ignore the flags field, it doesn't carry any useful
378 information for clients. */
379 r = dhcp6_option_parse_domainname(optval + 1, optlen - 1, &fqdn);
380 if (r < 0)
381 return r;
382
383 return free_and_replace(lease->fqdn, fqdn);
384 }
385
386 int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease *lease, const char **ret) {
387 assert_return(lease, -EINVAL);
388 assert_return(ret, -EINVAL);
389
390 if (!lease->fqdn)
391 return -ENOENT;
392
393 *ret = lease->fqdn;
394 return 0;
395 }
396
397 static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) {
398 if (!lease)
399 return NULL;
400
401 free(lease->clientid);
402 free(lease->serverid);
403 dhcp6_lease_free_ia(&lease->ia);
404 dhcp6_lease_free_ia(&lease->pd);
405 free(lease->dns);
406 free(lease->fqdn);
407 strv_free(lease->domains);
408 free(lease->ntp);
409 strv_free(lease->ntp_fqdn);
410 free(lease->sntp);
411
412 return mfree(lease);
413 }
414
415 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_lease, sd_dhcp6_lease, dhcp6_lease_free);
416
417 int dhcp6_lease_new(sd_dhcp6_lease **ret) {
418 sd_dhcp6_lease *lease;
419
420 lease = new0(sd_dhcp6_lease, 1);
421 if (!lease)
422 return -ENOMEM;
423
424 lease->n_ref = 1;
425
426 LIST_HEAD_INIT(lease->ia.addresses);
427
428 *ret = lease;
429 return 0;
430 }