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