]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-dhcp6-lease.c
man: fix markup and grammar for FOU{Source,Destination}Port=
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp6-lease.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
3fb2c570 2/***
810adae9 3 Copyright © 2014-2015 Intel Corporation. All rights reserved.
3fb2c570
PF
4***/
5
6#include <errno.h>
7
b5efdb8a 8#include "alloc-util.h"
3fb2c570 9#include "dhcp6-lease-internal.h"
6599680e 10#include "dhcp6-protocol.h"
b5efdb8a
LP
11#include "strv.h"
12#include "util.h"
3fb2c570 13
709d6710
PF
14int 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) {
ee3a5027 22 t = be32toh(addr->iaaddr.lifetime_valid);
709d6710
PF
23 if (valid < t)
24 valid = t;
25 }
26
e0026dcb 27 t = be32toh(ia->ia_na.lifetime_t2);
709d6710
PF
28 if (t > valid)
29 return -EINVAL;
30
31 *expire = valid - t;
32
33 return 0;
34}
35
3fb2c570
PF
36DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia) {
37 DHCP6Address *address;
38
39 if (!ia)
40 return NULL;
41
3fb2c570
PF
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
53int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id,
54 size_t len) {
33d36758
YW
55 uint8_t *serverid;
56
3fb2c570
PF
57 assert_return(lease, -EINVAL);
58 assert_return(id, -EINVAL);
59
33d36758
YW
60 serverid = memdup(id, len);
61 if (!serverid)
62 return -ENOMEM;
3fb2c570 63
33d36758 64 free_and_replace(lease->serverid, serverid);
3fb2c570
PF
65 lease->serverid_len = len;
66
67 return 0;
68}
69
70int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **id, size_t *len) {
71 assert_return(lease, -EINVAL);
3fb2c570 72
99f1d3fc
ZJS
73 if (!lease->serverid)
74 return -ENOMSG;
75
76 if (id)
77 *id = lease->serverid;
78 if (len)
79 *len = lease->serverid_len;
3fb2c570
PF
80
81 return 0;
82}
83
84int 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
92int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *preference) {
3fb2c570
PF
93 assert_return(preference, -EINVAL);
94
fab15fec
PF
95 if (!lease)
96 return -EINVAL;
97
3fb2c570
PF
98 *preference = lease->preference;
99
100 return 0;
101}
102
ed6ee219
PF
103int 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
111int 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
3fb2c570
PF
120int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
121 assert_return(lease, -EINVAL);
122 assert_return(iaid, -EINVAL);
123
e0026dcb 124 *iaid = lease->ia.ia_na.id;
3fb2c570
PF
125
126 return 0;
127}
128
49228c75
PF
129int 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
e7504d95
PF
138int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr,
139 uint32_t *lifetime_preferred,
140 uint32_t *lifetime_valid) {
ea3b3a75
PF
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
ee3a5027
PF
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);
ea3b3a75
PF
154
155 lease->addr_iter = lease->addr_iter->addresses_next;
156
157 return 0;
158}
159
e7504d95
PF
160void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease) {
161 if (lease)
162 lease->addr_iter = lease->ia.addresses;
ea3b3a75
PF
163}
164
652bf042
PF
165int 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
191void sd_dhcp6_lease_reset_pd_prefix_iter(sd_dhcp6_lease *lease) {
192 if (lease)
193 lease->prefix_iter = lease->pd.addresses;
194}
195
7bd8e95d
PF
196int 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 &lease->dns_allocated);
208 if (r < 0) {
209 log_dhcp6_client(client, "Invalid DNS server option: %s",
210 strerror(-r));
211
212 return r;
213 }
214
215 lease->dns_count = r;
216
217 return 0;
218}
219
220int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, struct in6_addr **addrs) {
221 assert_return(lease, -EINVAL);
222 assert_return(addrs, -EINVAL);
223
224 if (lease->dns_count) {
225 *addrs = lease->dns;
226 return lease->dns_count;
227 }
228
229 return -ENOENT;
230}
231
5da1b97f
PF
232int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval,
233 size_t optlen) {
234 int r;
235 char **domains;
236
237 assert_return(lease, -EINVAL);
238 assert_return(optval, -EINVAL);
239
240 if (!optlen)
241 return 0;
242
243 r = dhcp6_option_parse_domainname(optval, optlen, &domains);
244 if (r < 0)
245 return 0;
246
130d3d22 247 strv_free_and_replace(lease->domains, domains);
5da1b97f
PF
248 lease->domains_count = r;
249
250 return r;
251}
252
253int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***domains) {
254 assert_return(lease, -EINVAL);
255 assert_return(domains, -EINVAL);
256
257 if (lease->domains_count) {
258 *domains = lease->domains;
259 return lease->domains_count;
260 }
261
262 return -ENOENT;
263}
264
52efd56a 265int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
6599680e
PF
266 int r;
267 uint16_t subopt;
268 size_t sublen;
269 uint8_t *subval;
270
271 assert_return(lease, -EINVAL);
272 assert_return(optval, -EINVAL);
273
63a54aa1 274 lease->ntp = mfree(lease->ntp);
41e4615d
PF
275 lease->ntp_count = 0;
276 lease->ntp_allocated = 0;
277
6599680e
PF
278 while ((r = dhcp6_option_parse(&optval, &optlen, &subopt, &sublen,
279 &subval)) >= 0) {
280 int s;
281 char **servers;
282
283 switch(subopt) {
284 case DHCP6_NTP_SUBOPTION_SRV_ADDR:
285 case DHCP6_NTP_SUBOPTION_MC_ADDR:
286 if (sublen != 16)
287 return 0;
288
289 s = dhcp6_option_parse_ip6addrs(subval, sublen,
290 &lease->ntp,
291 lease->ntp_count,
292 &lease->ntp_allocated);
293 if (s < 0)
294 return s;
295
296 lease->ntp_count = s;
297
298 break;
299
300 case DHCP6_NTP_SUBOPTION_SRV_FQDN:
301 r = dhcp6_option_parse_domainname(subval, sublen,
302 &servers);
303 if (r < 0)
304 return 0;
305
130d3d22 306 strv_free_and_replace(lease->ntp_fqdn, servers);
6599680e
PF
307 lease->ntp_fqdn_count = r;
308
309 break;
310 }
311 }
312
313 if (r != -ENOMSG)
314 return r;
315
316 return 0;
317}
318
41e4615d
PF
319int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
320 int r;
321
322 assert_return(lease, -EINVAL);
323 assert_return(optval, -EINVAL);
324
325 if (!optlen)
326 return 0;
327
328 if (lease->ntp || lease->ntp_fqdn) {
329 log_dhcp6_client(client, "NTP information already provided");
330
331 return 0;
332 }
333
334 log_dhcp6_client(client, "Using deprecated SNTP information");
335
336 r = dhcp6_option_parse_ip6addrs(optval, optlen, &lease->ntp,
337 lease->ntp_count,
338 &lease->ntp_allocated);
339 if (r < 0) {
340 log_dhcp6_client(client, "Invalid SNTP server option: %s",
341 strerror(-r));
342
343 return r;
344 }
345
346 lease->ntp_count = r;
347
348 return 0;
349}
350
6599680e
PF
351int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease,
352 struct in6_addr **addrs) {
353 assert_return(lease, -EINVAL);
354 assert_return(addrs, -EINVAL);
355
356 if (lease->ntp_count) {
357 *addrs = lease->ntp;
358 return lease->ntp_count;
359 }
360
361 return -ENOENT;
362}
363
364int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn) {
365 assert_return(lease, -EINVAL);
366 assert_return(ntp_fqdn, -EINVAL);
367
368 if (lease->ntp_fqdn_count) {
369 *ntp_fqdn = lease->ntp_fqdn;
370 return lease->ntp_fqdn_count;
371 }
372
373 return -ENOENT;
374}
375
8301aa0b
YW
376static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) {
377 assert(lease);
6599680e 378
3733eec3
LP
379 free(lease->serverid);
380 dhcp6_lease_free_ia(&lease->ia);
dce6563f 381 dhcp6_lease_free_ia(&lease->pd);
3733eec3
LP
382
383 free(lease->dns);
384
385 lease->domains = strv_free(lease->domains);
386
387 free(lease->ntp);
388
389 lease->ntp_fqdn = strv_free(lease->ntp_fqdn);
6b430fdb 390 return mfree(lease);
3fb2c570
PF
391}
392
8301aa0b
YW
393DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_lease, sd_dhcp6_lease, dhcp6_lease_free);
394
3fb2c570
PF
395int dhcp6_lease_new(sd_dhcp6_lease **ret) {
396 sd_dhcp6_lease *lease;
397
398 lease = new0(sd_dhcp6_lease, 1);
399 if (!lease)
400 return -ENOMEM;
401
3733eec3 402 lease->n_ref = 1;
3fb2c570
PF
403
404 LIST_HEAD_INIT(lease->ia.addresses);
405
406 *ret = lease;
407 return 0;
408}