]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp6-lease.c
dhcp6: parse the FQDN option
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp6-lease.c
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 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 &lease->dns_allocated);
208 if (r < 0)
209 return log_dhcp6_client_errno(client, r, "Invalid DNS server option: %m");
210
211 lease->dns_count = r;
212
213 return 0;
214 }
215
216 int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, const struct in6_addr **addrs) {
217 assert_return(lease, -EINVAL);
218 assert_return(addrs, -EINVAL);
219
220 if (lease->dns_count) {
221 *addrs = lease->dns;
222 return lease->dns_count;
223 }
224
225 return -ENOENT;
226 }
227
228 int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval,
229 size_t optlen) {
230 int r;
231 char **domains;
232
233 assert_return(lease, -EINVAL);
234 assert_return(optval, -EINVAL);
235
236 if (!optlen)
237 return 0;
238
239 r = dhcp6_option_parse_domainname_list(optval, optlen, &domains);
240 if (r < 0)
241 return 0;
242
243 strv_free_and_replace(lease->domains, domains);
244 lease->domains_count = r;
245
246 return r;
247 }
248
249 int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***domains) {
250 assert_return(lease, -EINVAL);
251 assert_return(domains, -EINVAL);
252
253 if (lease->domains_count) {
254 *domains = lease->domains;
255 return lease->domains_count;
256 }
257
258 return -ENOENT;
259 }
260
261 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 assert_return(lease, -EINVAL);
268 assert_return(optval, -EINVAL);
269
270 lease->ntp = mfree(lease->ntp);
271 lease->ntp_count = 0;
272 lease->ntp_allocated = 0;
273
274 while ((r = dhcp6_option_parse(&optval, &optlen, &subopt, &sublen,
275 &subval)) >= 0) {
276 int s;
277 char **servers;
278
279 switch(subopt) {
280 case DHCP6_NTP_SUBOPTION_SRV_ADDR:
281 case DHCP6_NTP_SUBOPTION_MC_ADDR:
282 if (sublen != 16)
283 return 0;
284
285 s = dhcp6_option_parse_ip6addrs(subval, sublen,
286 &lease->ntp,
287 lease->ntp_count,
288 &lease->ntp_allocated);
289 if (s < 0)
290 return s;
291
292 lease->ntp_count = s;
293
294 break;
295
296 case DHCP6_NTP_SUBOPTION_SRV_FQDN:
297 r = dhcp6_option_parse_domainname_list(subval, sublen,
298 &servers);
299 if (r < 0)
300 return 0;
301
302 strv_free_and_replace(lease->ntp_fqdn, servers);
303 lease->ntp_fqdn_count = r;
304
305 break;
306 }
307 }
308
309 if (r != -ENOMSG)
310 return r;
311
312 return 0;
313 }
314
315 int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
316 int r;
317
318 assert_return(lease, -EINVAL);
319 assert_return(optval, -EINVAL);
320
321 if (!optlen)
322 return 0;
323
324 if (lease->ntp || lease->ntp_fqdn) {
325 log_dhcp6_client(client, "NTP information already provided");
326
327 return 0;
328 }
329
330 log_dhcp6_client(client, "Using deprecated SNTP information");
331
332 r = dhcp6_option_parse_ip6addrs(optval, optlen, &lease->ntp,
333 lease->ntp_count,
334 &lease->ntp_allocated);
335 if (r < 0)
336 return log_dhcp6_client_errno(client, r, "Invalid SNTP server option: %m");
337
338 lease->ntp_count = r;
339
340 return 0;
341 }
342
343 int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease,
344 const struct in6_addr **addrs) {
345 assert_return(lease, -EINVAL);
346 assert_return(addrs, -EINVAL);
347
348 if (lease->ntp_count) {
349 *addrs = lease->ntp;
350 return lease->ntp_count;
351 }
352
353 return -ENOENT;
354 }
355
356 int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn) {
357 assert_return(lease, -EINVAL);
358 assert_return(ntp_fqdn, -EINVAL);
359
360 if (lease->ntp_fqdn_count) {
361 *ntp_fqdn = lease->ntp_fqdn;
362 return lease->ntp_fqdn_count;
363 }
364
365 return -ENOENT;
366 }
367
368 int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval,
369 size_t optlen) {
370 int r;
371 char *fqdn;
372
373 assert_return(lease, -EINVAL);
374 assert_return(optval, -EINVAL);
375
376 if (optlen < 2)
377 return -ENODATA;
378
379 /* Ignore the flags field, it doesn't carry any useful
380 information for clients. */
381 r = dhcp6_option_parse_domainname(optval + 1, optlen - 1, &fqdn);
382 if (r < 0)
383 return r;
384
385 return free_and_replace(lease->fqdn, fqdn);
386 }
387
388 int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease *lease, const char **fqdn) {
389 assert_return(lease, -EINVAL);
390 assert_return(fqdn, -EINVAL);
391
392 if (lease->fqdn) {
393 *fqdn = lease->fqdn;
394 return 0;
395 }
396
397 return -ENOENT;
398 }
399
400 static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) {
401 assert(lease);
402
403 free(lease->serverid);
404 dhcp6_lease_free_ia(&lease->ia);
405 dhcp6_lease_free_ia(&lease->pd);
406
407 free(lease->dns);
408 free(lease->fqdn);
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 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_lease, sd_dhcp6_lease, dhcp6_lease_free);
419
420 int dhcp6_lease_new(sd_dhcp6_lease **ret) {
421 sd_dhcp6_lease *lease;
422
423 lease = new0(sd_dhcp6_lease, 1);
424 if (!lease)
425 return -ENOMEM;
426
427 lease->n_ref = 1;
428
429 LIST_HEAD_INIT(lease->ia.addresses);
430
431 *ret = lease;
432 return 0;
433 }