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