]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp6-lease.c
tree-wide: drop license boilerplate
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp6-lease.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright (C) 2014 Tom Gundersen
6 Copyright (C) 2014-2015 Intel Corporation. All rights reserved.
7 ***/
8
9 #include <errno.h>
10
11 #include "alloc-util.h"
12 #include "dhcp6-lease-internal.h"
13 #include "dhcp6-protocol.h"
14 #include "strv.h"
15 #include "util.h"
16
17 int 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
26 int 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) {
34 t = be32toh(addr->iaaddr.lifetime_valid);
35 if (valid < t)
36 valid = t;
37 }
38
39 t = be32toh(ia->ia_na.lifetime_t2);
40 if (t > valid)
41 return -EINVAL;
42
43 *expire = valid - t;
44
45 return 0;
46 }
47
48 DHCP6IA *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
67 int 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
83 int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **id, size_t *len) {
84 assert_return(lease, -EINVAL);
85
86 if (!lease->serverid)
87 return -ENOMSG;
88
89 if (id)
90 *id = lease->serverid;
91 if (len)
92 *len = lease->serverid_len;
93
94 return 0;
95 }
96
97 int 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
105 int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *preference) {
106 assert_return(preference, -EINVAL);
107
108 if (!lease)
109 return -EINVAL;
110
111 *preference = lease->preference;
112
113 return 0;
114 }
115
116 int 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
124 int 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
133 int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
134 assert_return(lease, -EINVAL);
135 assert_return(iaid, -EINVAL);
136
137 *iaid = lease->ia.ia_na.id;
138
139 return 0;
140 }
141
142 int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr,
143 uint32_t *lifetime_preferred,
144 uint32_t *lifetime_valid) {
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
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);
158
159 lease->addr_iter = lease->addr_iter->addresses_next;
160
161 return 0;
162 }
163
164 void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease) {
165 if (lease)
166 lease->addr_iter = lease->ia.addresses;
167 }
168
169 int 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
195 void sd_dhcp6_lease_reset_pd_prefix_iter(sd_dhcp6_lease *lease) {
196 if (lease)
197 lease->prefix_iter = lease->pd.addresses;
198 }
199
200 int 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
224 int 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
236 int 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
251 strv_free(lease->domains);
252 lease->domains = domains;
253 lease->domains_count = r;
254
255 return r;
256 }
257
258 int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***domains) {
259 assert_return(lease, -EINVAL);
260 assert_return(domains, -EINVAL);
261
262 if (lease->domains_count) {
263 *domains = lease->domains;
264 return lease->domains_count;
265 }
266
267 return -ENOENT;
268 }
269
270 int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
271 int r;
272 uint16_t subopt;
273 size_t sublen;
274 uint8_t *subval;
275
276 assert_return(lease, -EINVAL);
277 assert_return(optval, -EINVAL);
278
279 lease->ntp = mfree(lease->ntp);
280 lease->ntp_count = 0;
281 lease->ntp_allocated = 0;
282
283 while ((r = dhcp6_option_parse(&optval, &optlen, &subopt, &sublen,
284 &subval)) >= 0) {
285 int s;
286 char **servers;
287
288 switch(subopt) {
289 case DHCP6_NTP_SUBOPTION_SRV_ADDR:
290 case DHCP6_NTP_SUBOPTION_MC_ADDR:
291 if (sublen != 16)
292 return 0;
293
294 s = dhcp6_option_parse_ip6addrs(subval, sublen,
295 &lease->ntp,
296 lease->ntp_count,
297 &lease->ntp_allocated);
298 if (s < 0)
299 return s;
300
301 lease->ntp_count = s;
302
303 break;
304
305 case DHCP6_NTP_SUBOPTION_SRV_FQDN:
306 r = dhcp6_option_parse_domainname(subval, sublen,
307 &servers);
308 if (r < 0)
309 return 0;
310
311 lease->ntp_fqdn = strv_free(lease->ntp_fqdn);
312 lease->ntp_fqdn = servers;
313 lease->ntp_fqdn_count = r;
314
315 break;
316 }
317 }
318
319 if (r != -ENOMSG)
320 return r;
321
322 return 0;
323 }
324
325 int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
326 int r;
327
328 assert_return(lease, -EINVAL);
329 assert_return(optval, -EINVAL);
330
331 if (!optlen)
332 return 0;
333
334 if (lease->ntp || lease->ntp_fqdn) {
335 log_dhcp6_client(client, "NTP information already provided");
336
337 return 0;
338 }
339
340 log_dhcp6_client(client, "Using deprecated SNTP information");
341
342 r = dhcp6_option_parse_ip6addrs(optval, optlen, &lease->ntp,
343 lease->ntp_count,
344 &lease->ntp_allocated);
345 if (r < 0) {
346 log_dhcp6_client(client, "Invalid SNTP server option: %s",
347 strerror(-r));
348
349 return r;
350 }
351
352 lease->ntp_count = r;
353
354 return 0;
355 }
356
357 int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease,
358 struct in6_addr **addrs) {
359 assert_return(lease, -EINVAL);
360 assert_return(addrs, -EINVAL);
361
362 if (lease->ntp_count) {
363 *addrs = lease->ntp;
364 return lease->ntp_count;
365 }
366
367 return -ENOENT;
368 }
369
370 int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn) {
371 assert_return(lease, -EINVAL);
372 assert_return(ntp_fqdn, -EINVAL);
373
374 if (lease->ntp_fqdn_count) {
375 *ntp_fqdn = lease->ntp_fqdn;
376 return lease->ntp_fqdn_count;
377 }
378
379 return -ENOENT;
380 }
381
382 sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease) {
383
384 if (!lease)
385 return NULL;
386
387 assert(lease->n_ref >= 1);
388 lease->n_ref++;
389
390 return lease;
391 }
392
393 sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease) {
394
395 if (!lease)
396 return NULL;
397
398 assert(lease->n_ref >= 1);
399 lease->n_ref--;
400
401 if (lease->n_ref > 0)
402 return NULL;
403
404 free(lease->serverid);
405 dhcp6_lease_free_ia(&lease->ia);
406 dhcp6_lease_free_ia(&lease->pd);
407
408 free(lease->dns);
409
410 lease->domains = strv_free(lease->domains);
411
412 free(lease->ntp);
413
414 lease->ntp_fqdn = strv_free(lease->ntp_fqdn);
415 return mfree(lease);
416 }
417
418 int dhcp6_lease_new(sd_dhcp6_lease **ret) {
419 sd_dhcp6_lease *lease;
420
421 lease = new0(sd_dhcp6_lease, 1);
422 if (!lease)
423 return -ENOMEM;
424
425 lease->n_ref = 1;
426
427 LIST_HEAD_INIT(lease->ia.addresses);
428
429 *ret = lease;
430 return 0;
431 }