]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-dhcp6-lease.c
Merge pull request #9017 from keszybz/man-coredump
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp6-lease.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
3fb2c570
PF
2/***
3 This file is part of systemd.
4
5 Copyright (C) 2014 Tom Gundersen
5da1b97f 6 Copyright (C) 2014-2015 Intel Corporation. All rights reserved.
3fb2c570
PF
7***/
8
9#include <errno.h>
10
b5efdb8a 11#include "alloc-util.h"
3fb2c570 12#include "dhcp6-lease-internal.h"
6599680e 13#include "dhcp6-protocol.h"
b5efdb8a
LP
14#include "strv.h"
15#include "util.h"
3fb2c570
PF
16
17int dhcp6_lease_clear_timers(DHCP6IA *ia) {
18 assert_return(ia, -EINVAL);
19
20 ia->timeout_t1 = sd_event_source_unref(ia->timeout_t1);
21 ia->timeout_t2 = sd_event_source_unref(ia->timeout_t2);
22
23 return 0;
24}
25
709d6710
PF
26int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) {
27 DHCP6Address *addr;
28 uint32_t valid = 0, t;
29
30 assert_return(ia, -EINVAL);
31 assert_return(expire, -EINVAL);
32
33 LIST_FOREACH(addresses, addr, ia->addresses) {
ee3a5027 34 t = be32toh(addr->iaaddr.lifetime_valid);
709d6710
PF
35 if (valid < t)
36 valid = t;
37 }
38
e0026dcb 39 t = be32toh(ia->ia_na.lifetime_t2);
709d6710
PF
40 if (t > valid)
41 return -EINVAL;
42
43 *expire = valid - t;
44
45 return 0;
46}
47
3fb2c570
PF
48DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia) {
49 DHCP6Address *address;
50
51 if (!ia)
52 return NULL;
53
54 dhcp6_lease_clear_timers(ia);
55
56 while (ia->addresses) {
57 address = ia->addresses;
58
59 LIST_REMOVE(addresses, ia->addresses, address);
60
61 free(address);
62 }
63
64 return NULL;
65}
66
67int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id,
68 size_t len) {
69 assert_return(lease, -EINVAL);
70 assert_return(id, -EINVAL);
71
72 free(lease->serverid);
73
74 lease->serverid = memdup(id, len);
75 if (!lease->serverid)
76 return -EINVAL;
77
78 lease->serverid_len = len;
79
80 return 0;
81}
82
83int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **id, size_t *len) {
84 assert_return(lease, -EINVAL);
3fb2c570 85
99f1d3fc
ZJS
86 if (!lease->serverid)
87 return -ENOMSG;
88
89 if (id)
90 *id = lease->serverid;
91 if (len)
92 *len = lease->serverid_len;
3fb2c570
PF
93
94 return 0;
95}
96
97int dhcp6_lease_set_preference(sd_dhcp6_lease *lease, uint8_t preference) {
98 assert_return(lease, -EINVAL);
99
100 lease->preference = preference;
101
102 return 0;
103}
104
105int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *preference) {
3fb2c570
PF
106 assert_return(preference, -EINVAL);
107
fab15fec
PF
108 if (!lease)
109 return -EINVAL;
110
3fb2c570
PF
111 *preference = lease->preference;
112
113 return 0;
114}
115
ed6ee219
PF
116int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease) {
117 assert_return(lease, -EINVAL);
118
119 lease->rapid_commit = true;
120
121 return 0;
122}
123
124int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit) {
125 assert_return(lease, -EINVAL);
126 assert_return(rapid_commit, -EINVAL);
127
128 *rapid_commit = lease->rapid_commit;
129
130 return 0;
131}
132
3fb2c570
PF
133int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
134 assert_return(lease, -EINVAL);
135 assert_return(iaid, -EINVAL);
136
e0026dcb 137 *iaid = lease->ia.ia_na.id;
3fb2c570
PF
138
139 return 0;
140}
141
e7504d95
PF
142int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr,
143 uint32_t *lifetime_preferred,
144 uint32_t *lifetime_valid) {
ea3b3a75
PF
145 assert_return(lease, -EINVAL);
146 assert_return(addr, -EINVAL);
147 assert_return(lifetime_preferred, -EINVAL);
148 assert_return(lifetime_valid, -EINVAL);
149
150 if (!lease->addr_iter)
151 return -ENOMSG;
152
ee3a5027
PF
153 memcpy(addr, &lease->addr_iter->iaaddr.address,
154 sizeof(struct in6_addr));
155 *lifetime_preferred =
156 be32toh(lease->addr_iter->iaaddr.lifetime_preferred);
157 *lifetime_valid = be32toh(lease->addr_iter->iaaddr.lifetime_valid);
ea3b3a75
PF
158
159 lease->addr_iter = lease->addr_iter->addresses_next;
160
161 return 0;
162}
163
e7504d95
PF
164void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease) {
165 if (lease)
166 lease->addr_iter = lease->ia.addresses;
ea3b3a75
PF
167}
168
652bf042
PF
169int sd_dhcp6_lease_get_pd(sd_dhcp6_lease *lease, struct in6_addr *prefix,
170 uint8_t *prefix_len,
171 uint32_t *lifetime_preferred,
172 uint32_t *lifetime_valid) {
173 assert_return(lease, -EINVAL);
174 assert_return(prefix, -EINVAL);
175 assert_return(prefix_len, -EINVAL);
176 assert_return(lifetime_preferred, -EINVAL);
177 assert_return(lifetime_valid, -EINVAL);
178
179 if (!lease->prefix_iter)
180 return -ENOMSG;
181
182 memcpy(prefix, &lease->prefix_iter->iapdprefix.address,
183 sizeof(struct in6_addr));
184 *prefix_len = lease->prefix_iter->iapdprefix.prefixlen;
185 *lifetime_preferred =
186 be32toh(lease->prefix_iter->iapdprefix.lifetime_preferred);
187 *lifetime_valid =
188 be32toh(lease->prefix_iter->iapdprefix.lifetime_valid);
189
190 lease->prefix_iter = lease->prefix_iter->addresses_next;
191
192 return 0;
193}
194
195void sd_dhcp6_lease_reset_pd_prefix_iter(sd_dhcp6_lease *lease) {
196 if (lease)
197 lease->prefix_iter = lease->pd.addresses;
198}
199
7bd8e95d
PF
200int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
201 int r;
202
203 assert_return(lease, -EINVAL);
204 assert_return(optval, -EINVAL);
205
206 if (!optlen)
207 return 0;
208
209 r = dhcp6_option_parse_ip6addrs(optval, optlen, &lease->dns,
210 lease->dns_count,
211 &lease->dns_allocated);
212 if (r < 0) {
213 log_dhcp6_client(client, "Invalid DNS server option: %s",
214 strerror(-r));
215
216 return r;
217 }
218
219 lease->dns_count = r;
220
221 return 0;
222}
223
224int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, struct in6_addr **addrs) {
225 assert_return(lease, -EINVAL);
226 assert_return(addrs, -EINVAL);
227
228 if (lease->dns_count) {
229 *addrs = lease->dns;
230 return lease->dns_count;
231 }
232
233 return -ENOENT;
234}
235
5da1b97f
PF
236int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval,
237 size_t optlen) {
238 int r;
239 char **domains;
240
241 assert_return(lease, -EINVAL);
242 assert_return(optval, -EINVAL);
243
244 if (!optlen)
245 return 0;
246
247 r = dhcp6_option_parse_domainname(optval, optlen, &domains);
248 if (r < 0)
249 return 0;
250
130d3d22 251 strv_free_and_replace(lease->domains, domains);
5da1b97f
PF
252 lease->domains_count = r;
253
254 return r;
255}
256
257int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***domains) {
258 assert_return(lease, -EINVAL);
259 assert_return(domains, -EINVAL);
260
261 if (lease->domains_count) {
262 *domains = lease->domains;
263 return lease->domains_count;
264 }
265
266 return -ENOENT;
267}
268
52efd56a 269int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
6599680e
PF
270 int r;
271 uint16_t subopt;
272 size_t sublen;
273 uint8_t *subval;
274
275 assert_return(lease, -EINVAL);
276 assert_return(optval, -EINVAL);
277
63a54aa1 278 lease->ntp = mfree(lease->ntp);
41e4615d
PF
279 lease->ntp_count = 0;
280 lease->ntp_allocated = 0;
281
6599680e
PF
282 while ((r = dhcp6_option_parse(&optval, &optlen, &subopt, &sublen,
283 &subval)) >= 0) {
284 int s;
285 char **servers;
286
287 switch(subopt) {
288 case DHCP6_NTP_SUBOPTION_SRV_ADDR:
289 case DHCP6_NTP_SUBOPTION_MC_ADDR:
290 if (sublen != 16)
291 return 0;
292
293 s = dhcp6_option_parse_ip6addrs(subval, sublen,
294 &lease->ntp,
295 lease->ntp_count,
296 &lease->ntp_allocated);
297 if (s < 0)
298 return s;
299
300 lease->ntp_count = s;
301
302 break;
303
304 case DHCP6_NTP_SUBOPTION_SRV_FQDN:
305 r = dhcp6_option_parse_domainname(subval, sublen,
306 &servers);
307 if (r < 0)
308 return 0;
309
130d3d22 310 strv_free_and_replace(lease->ntp_fqdn, servers);
6599680e
PF
311 lease->ntp_fqdn_count = r;
312
313 break;
314 }
315 }
316
317 if (r != -ENOMSG)
318 return r;
319
320 return 0;
321}
322
41e4615d
PF
323int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
324 int r;
325
326 assert_return(lease, -EINVAL);
327 assert_return(optval, -EINVAL);
328
329 if (!optlen)
330 return 0;
331
332 if (lease->ntp || lease->ntp_fqdn) {
333 log_dhcp6_client(client, "NTP information already provided");
334
335 return 0;
336 }
337
338 log_dhcp6_client(client, "Using deprecated SNTP information");
339
340 r = dhcp6_option_parse_ip6addrs(optval, optlen, &lease->ntp,
341 lease->ntp_count,
342 &lease->ntp_allocated);
343 if (r < 0) {
344 log_dhcp6_client(client, "Invalid SNTP server option: %s",
345 strerror(-r));
346
347 return r;
348 }
349
350 lease->ntp_count = r;
351
352 return 0;
353}
354
6599680e
PF
355int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease,
356 struct in6_addr **addrs) {
357 assert_return(lease, -EINVAL);
358 assert_return(addrs, -EINVAL);
359
360 if (lease->ntp_count) {
361 *addrs = lease->ntp;
362 return lease->ntp_count;
363 }
364
365 return -ENOENT;
366}
367
368int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn) {
369 assert_return(lease, -EINVAL);
370 assert_return(ntp_fqdn, -EINVAL);
371
372 if (lease->ntp_fqdn_count) {
373 *ntp_fqdn = lease->ntp_fqdn;
374 return lease->ntp_fqdn_count;
375 }
376
377 return -ENOENT;
378}
379
3fb2c570 380sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease) {
3733eec3
LP
381
382 if (!lease)
383 return NULL;
384
385 assert(lease->n_ref >= 1);
386 lease->n_ref++;
3fb2c570
PF
387
388 return lease;
389}
390
391sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease) {
3fb2c570 392
3733eec3
LP
393 if (!lease)
394 return NULL;
5da1b97f 395
3733eec3
LP
396 assert(lease->n_ref >= 1);
397 lease->n_ref--;
5da1b97f 398
3733eec3
LP
399 if (lease->n_ref > 0)
400 return NULL;
6599680e 401
3733eec3
LP
402 free(lease->serverid);
403 dhcp6_lease_free_ia(&lease->ia);
dce6563f 404 dhcp6_lease_free_ia(&lease->pd);
3733eec3
LP
405
406 free(lease->dns);
407
408 lease->domains = strv_free(lease->domains);
409
410 free(lease->ntp);
411
412 lease->ntp_fqdn = strv_free(lease->ntp_fqdn);
6b430fdb 413 return mfree(lease);
3fb2c570
PF
414}
415
416int dhcp6_lease_new(sd_dhcp6_lease **ret) {
417 sd_dhcp6_lease *lease;
418
419 lease = new0(sd_dhcp6_lease, 1);
420 if (!lease)
421 return -ENOMEM;
422
3733eec3 423 lease->n_ref = 1;
3fb2c570
PF
424
425 LIST_HEAD_INIT(lease->ia.addresses);
426
427 *ret = lease;
428 return 0;
429}