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