]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp-lease.c
pkgconfig: define variables relative to ${prefix}/${rootprefix}/${sysconfdir}
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp-lease.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 Copyright © 2013 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <arpa/inet.h>
7 #include <errno.h>
8 #include <stdio.h>
9 #include <stdio_ext.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #include "sd-dhcp-lease.h"
14
15 #include "alloc-util.h"
16 #include "dhcp-lease-internal.h"
17 #include "dhcp-protocol.h"
18 #include "dns-domain.h"
19 #include "fd-util.h"
20 #include "fileio.h"
21 #include "hexdecoct.h"
22 #include "hostname-util.h"
23 #include "in-addr-util.h"
24 #include "network-internal.h"
25 #include "parse-util.h"
26 #include "stdio-util.h"
27 #include "string-util.h"
28 #include "strv.h"
29 #include "unaligned.h"
30
31 int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
32 assert_return(lease, -EINVAL);
33 assert_return(addr, -EINVAL);
34
35 if (lease->address == 0)
36 return -ENODATA;
37
38 addr->s_addr = lease->address;
39 return 0;
40 }
41
42 int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr) {
43 assert_return(lease, -EINVAL);
44 assert_return(addr, -EINVAL);
45
46 if (!lease->have_broadcast)
47 return -ENODATA;
48
49 addr->s_addr = lease->broadcast;
50 return 0;
51 }
52
53 int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
54 assert_return(lease, -EINVAL);
55 assert_return(lifetime, -EINVAL);
56
57 if (lease->lifetime <= 0)
58 return -ENODATA;
59
60 *lifetime = lease->lifetime;
61 return 0;
62 }
63
64 int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1) {
65 assert_return(lease, -EINVAL);
66 assert_return(t1, -EINVAL);
67
68 if (lease->t1 <= 0)
69 return -ENODATA;
70
71 *t1 = lease->t1;
72 return 0;
73 }
74
75 int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2) {
76 assert_return(lease, -EINVAL);
77 assert_return(t2, -EINVAL);
78
79 if (lease->t2 <= 0)
80 return -ENODATA;
81
82 *t2 = lease->t2;
83 return 0;
84 }
85
86 int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
87 assert_return(lease, -EINVAL);
88 assert_return(mtu, -EINVAL);
89
90 if (lease->mtu <= 0)
91 return -ENODATA;
92
93 *mtu = lease->mtu;
94 return 0;
95 }
96
97 int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) {
98 assert_return(lease, -EINVAL);
99 assert_return(addr, -EINVAL);
100
101 if (lease->dns_size <= 0)
102 return -ENODATA;
103
104 *addr = lease->dns;
105 return (int) lease->dns_size;
106 }
107
108 int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) {
109 assert_return(lease, -EINVAL);
110 assert_return(addr, -EINVAL);
111
112 if (lease->ntp_size <= 0)
113 return -ENODATA;
114
115 *addr = lease->ntp;
116 return (int) lease->ntp_size;
117 }
118
119 int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
120 assert_return(lease, -EINVAL);
121 assert_return(domainname, -EINVAL);
122
123 if (!lease->domainname)
124 return -ENODATA;
125
126 *domainname = lease->domainname;
127 return 0;
128 }
129
130 int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
131 assert_return(lease, -EINVAL);
132 assert_return(hostname, -EINVAL);
133
134 if (!lease->hostname)
135 return -ENODATA;
136
137 *hostname = lease->hostname;
138 return 0;
139 }
140
141 int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
142 assert_return(lease, -EINVAL);
143 assert_return(root_path, -EINVAL);
144
145 if (!lease->root_path)
146 return -ENODATA;
147
148 *root_path = lease->root_path;
149 return 0;
150 }
151
152 int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) {
153 assert_return(lease, -EINVAL);
154 assert_return(addr, -EINVAL);
155
156 if (lease->router == 0)
157 return -ENODATA;
158
159 addr->s_addr = lease->router;
160 return 0;
161 }
162
163 int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
164 assert_return(lease, -EINVAL);
165 assert_return(addr, -EINVAL);
166
167 if (!lease->have_subnet_mask)
168 return -ENODATA;
169
170 addr->s_addr = lease->subnet_mask;
171 return 0;
172 }
173
174 int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
175 assert_return(lease, -EINVAL);
176 assert_return(addr, -EINVAL);
177
178 if (lease->server_address == 0)
179 return -ENODATA;
180
181 addr->s_addr = lease->server_address;
182 return 0;
183 }
184
185 int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
186 assert_return(lease, -EINVAL);
187 assert_return(addr, -EINVAL);
188
189 if (lease->next_server == 0)
190 return -ENODATA;
191
192 addr->s_addr = lease->next_server;
193 return 0;
194 }
195
196 /*
197 * The returned routes array must be freed by the caller.
198 * Route objects have the same lifetime of the lease and must not be freed.
199 */
200 int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes) {
201 sd_dhcp_route **ret;
202 unsigned i;
203
204 assert_return(lease, -EINVAL);
205 assert_return(routes, -EINVAL);
206
207 if (lease->static_route_size <= 0)
208 return -ENODATA;
209
210 ret = new(sd_dhcp_route *, lease->static_route_size);
211 if (!ret)
212 return -ENOMEM;
213
214 for (i = 0; i < lease->static_route_size; i++)
215 ret[i] = &lease->static_route[i];
216
217 *routes = ret;
218 return (int) lease->static_route_size;
219 }
220
221 int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) {
222 size_t r;
223
224 assert_return(lease, -EINVAL);
225 assert_return(domains, -EINVAL);
226
227 r = strv_length(lease->search_domains);
228 if (r > 0) {
229 *domains = lease->search_domains;
230 return (int) r;
231 }
232
233 return -ENODATA;
234 }
235
236 int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len) {
237 assert_return(lease, -EINVAL);
238 assert_return(data, -EINVAL);
239 assert_return(data_len, -EINVAL);
240
241 if (lease->vendor_specific_len <= 0)
242 return -ENODATA;
243
244 *data = lease->vendor_specific;
245 *data_len = lease->vendor_specific_len;
246 return 0;
247 }
248
249 static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) {
250 assert(lease);
251
252 while (lease->private_options) {
253 struct sd_dhcp_raw_option *option = lease->private_options;
254
255 LIST_REMOVE(options, lease->private_options, option);
256
257 free(option->data);
258 free(option);
259 }
260
261 free(lease->root_path);
262 free(lease->timezone);
263 free(lease->hostname);
264 free(lease->domainname);
265 free(lease->dns);
266 free(lease->ntp);
267 free(lease->static_route);
268 free(lease->client_id);
269 free(lease->vendor_specific);
270 strv_free(lease->search_domains);
271 return mfree(lease);
272 }
273
274 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_lease, sd_dhcp_lease, dhcp_lease_free);
275
276 static int lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
277 assert(option);
278 assert(ret);
279
280 if (len != 4)
281 return -EINVAL;
282
283 *ret = unaligned_read_be32((be32_t*) option);
284 if (*ret < min)
285 *ret = min;
286
287 return 0;
288 }
289
290 static int lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
291 assert(option);
292 assert(ret);
293
294 if (len != 2)
295 return -EINVAL;
296
297 *ret = unaligned_read_be16((be16_t*) option);
298 if (*ret < min)
299 *ret = min;
300
301 return 0;
302 }
303
304 static int lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
305 assert(option);
306 assert(ret);
307
308 if (len != 4)
309 return -EINVAL;
310
311 memcpy(ret, option, 4);
312 return 0;
313 }
314
315 static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
316 assert(option);
317 assert(ret);
318
319 if (len <= 0)
320 *ret = mfree(*ret);
321 else {
322 char *string;
323
324 /*
325 * One trailing NUL byte is OK, we don't mind. See:
326 * https://github.com/systemd/systemd/issues/1337
327 */
328 if (memchr(option, 0, len - 1))
329 return -EINVAL;
330
331 string = strndup((const char *) option, len);
332 if (!string)
333 return -ENOMEM;
334
335 free_and_replace(*ret, string);
336 }
337
338 return 0;
339 }
340
341 static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) {
342 _cleanup_free_ char *name = NULL, *normalized = NULL;
343 int r;
344
345 assert(option);
346 assert(ret);
347
348 r = lease_parse_string(option, len, &name);
349 if (r < 0)
350 return r;
351 if (!name) {
352 *ret = mfree(*ret);
353 return 0;
354 }
355
356 r = dns_name_normalize(name, &normalized);
357 if (r < 0)
358 return r;
359
360 if (is_localhost(normalized))
361 return -EINVAL;
362
363 if (dns_name_is_root(normalized))
364 return -EINVAL;
365
366 free_and_replace(*ret, normalized);
367
368 return 0;
369 }
370
371 static void filter_bogus_addresses(struct in_addr *addresses, size_t *n) {
372 size_t i, j;
373
374 /* Silently filter DNS/NTP servers supplied to us that do not make outside of the local scope. */
375
376 for (i = 0, j = 0; i < *n; i ++) {
377
378 if (in4_addr_is_null(addresses+i) ||
379 in4_addr_is_localhost(addresses+i))
380 continue;
381
382 addresses[j++] = addresses[i];
383 }
384
385 *n = j;
386 }
387
388 static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) {
389 assert(option);
390 assert(ret);
391 assert(n_ret);
392
393 if (len <= 0) {
394 *ret = mfree(*ret);
395 *n_ret = 0;
396 } else {
397 size_t n_addresses;
398 struct in_addr *addresses;
399
400 if (len % 4 != 0)
401 return -EINVAL;
402
403 n_addresses = len / 4;
404
405 addresses = newdup(struct in_addr, option, n_addresses);
406 if (!addresses)
407 return -ENOMEM;
408
409 filter_bogus_addresses(addresses, &n_addresses);
410
411 free(*ret);
412 *ret = addresses;
413 *n_ret = n_addresses;
414 }
415
416 return 0;
417 }
418
419 static int lease_parse_routes(
420 const uint8_t *option, size_t len,
421 struct sd_dhcp_route **routes, size_t *routes_size, size_t *routes_allocated) {
422
423 struct in_addr addr;
424
425 assert(option || len <= 0);
426 assert(routes);
427 assert(routes_size);
428 assert(routes_allocated);
429
430 if (len <= 0)
431 return 0;
432
433 if (len % 8 != 0)
434 return -EINVAL;
435
436 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + (len / 8)))
437 return -ENOMEM;
438
439 while (len >= 8) {
440 struct sd_dhcp_route *route = *routes + *routes_size;
441 int r;
442
443 route->option = SD_DHCP_OPTION_STATIC_ROUTE;
444 r = in4_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen);
445 if (r < 0) {
446 log_debug("Failed to determine destination prefix length from class based IP, ignoring");
447 continue;
448 }
449
450 assert_se(lease_parse_be32(option, 4, &addr.s_addr) >= 0);
451 route->dst_addr = inet_makeaddr(inet_netof(addr), 0);
452 option += 4;
453
454 assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0);
455 option += 4;
456
457 len -= 8;
458 (*routes_size)++;
459 }
460
461 return 0;
462 }
463
464 /* parses RFC3442 Classless Static Route Option */
465 static int lease_parse_classless_routes(
466 const uint8_t *option, size_t len,
467 struct sd_dhcp_route **routes, size_t *routes_size, size_t *routes_allocated) {
468
469 assert(option || len <= 0);
470 assert(routes);
471 assert(routes_size);
472 assert(routes_allocated);
473
474 if (len <= 0)
475 return 0;
476
477 /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */
478
479 while (len > 0) {
480 uint8_t dst_octets;
481 struct sd_dhcp_route *route;
482
483 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1))
484 return -ENOMEM;
485
486 route = *routes + *routes_size;
487 route->option = SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE;
488
489 dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1);
490 route->dst_prefixlen = *option;
491 option++;
492 len--;
493
494 /* can't have more than 4 octets in IPv4 */
495 if (dst_octets > 4 || len < dst_octets)
496 return -EINVAL;
497
498 route->dst_addr.s_addr = 0;
499 memcpy(&route->dst_addr.s_addr, option, dst_octets);
500 option += dst_octets;
501 len -= dst_octets;
502
503 if (len < 4)
504 return -EINVAL;
505
506 assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0);
507 option += 4;
508 len -= 4;
509
510 (*routes_size)++;
511 }
512
513 return 0;
514 }
515
516 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
517 sd_dhcp_lease *lease = userdata;
518 int r;
519
520 assert(lease);
521
522 switch(code) {
523
524 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
525 r = lease_parse_u32(option, len, &lease->lifetime, 1);
526 if (r < 0)
527 log_debug_errno(r, "Failed to parse lease time, ignoring: %m");
528
529 break;
530
531 case SD_DHCP_OPTION_SERVER_IDENTIFIER:
532 r = lease_parse_be32(option, len, &lease->server_address);
533 if (r < 0)
534 log_debug_errno(r, "Failed to parse server identifier, ignoring: %m");
535
536 break;
537
538 case SD_DHCP_OPTION_SUBNET_MASK:
539 r = lease_parse_be32(option, len, &lease->subnet_mask);
540 if (r < 0)
541 log_debug_errno(r, "Failed to parse subnet mask, ignoring: %m");
542 else
543 lease->have_subnet_mask = true;
544 break;
545
546 case SD_DHCP_OPTION_BROADCAST:
547 r = lease_parse_be32(option, len, &lease->broadcast);
548 if (r < 0)
549 log_debug_errno(r, "Failed to parse broadcast address, ignoring: %m");
550 else
551 lease->have_broadcast = true;
552 break;
553
554 case SD_DHCP_OPTION_ROUTER:
555 if (len >= 4) {
556 r = lease_parse_be32(option, 4, &lease->router);
557 if (r < 0)
558 log_debug_errno(r, "Failed to parse router address, ignoring: %m");
559 }
560 break;
561
562 case SD_DHCP_OPTION_DOMAIN_NAME_SERVER:
563 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
564 if (r < 0)
565 log_debug_errno(r, "Failed to parse DNS server, ignoring: %m");
566 break;
567
568 case SD_DHCP_OPTION_NTP_SERVER:
569 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
570 if (r < 0)
571 log_debug_errno(r, "Failed to parse NTP server, ignoring: %m");
572 break;
573
574 case SD_DHCP_OPTION_STATIC_ROUTE:
575 r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size, &lease->static_route_allocated);
576 if (r < 0)
577 log_debug_errno(r, "Failed to parse static routes, ignoring: %m");
578 break;
579
580 case SD_DHCP_OPTION_INTERFACE_MTU:
581 r = lease_parse_u16(option, len, &lease->mtu, 68);
582 if (r < 0)
583 log_debug_errno(r, "Failed to parse MTU, ignoring: %m");
584 if (lease->mtu < DHCP_DEFAULT_MIN_SIZE) {
585 log_debug("MTU value of %" PRIu16 " too small. Using default MTU value of %d instead.", lease->mtu, DHCP_DEFAULT_MIN_SIZE);
586 lease->mtu = DHCP_DEFAULT_MIN_SIZE;
587 }
588
589 break;
590
591 case SD_DHCP_OPTION_DOMAIN_NAME:
592 r = lease_parse_domain(option, len, &lease->domainname);
593 if (r < 0) {
594 log_debug_errno(r, "Failed to parse domain name, ignoring: %m");
595 return 0;
596 }
597
598 break;
599
600 case SD_DHCP_OPTION_DOMAIN_SEARCH_LIST:
601 r = dhcp_lease_parse_search_domains(option, len, &lease->search_domains);
602 if (r < 0)
603 log_debug_errno(r, "Failed to parse Domain Search List, ignoring: %m");
604 break;
605
606 case SD_DHCP_OPTION_HOST_NAME:
607 r = lease_parse_domain(option, len, &lease->hostname);
608 if (r < 0) {
609 log_debug_errno(r, "Failed to parse host name, ignoring: %m");
610 return 0;
611 }
612
613 break;
614
615 case SD_DHCP_OPTION_ROOT_PATH:
616 r = lease_parse_string(option, len, &lease->root_path);
617 if (r < 0)
618 log_debug_errno(r, "Failed to parse root path, ignoring: %m");
619 break;
620
621 case SD_DHCP_OPTION_RENEWAL_T1_TIME:
622 r = lease_parse_u32(option, len, &lease->t1, 1);
623 if (r < 0)
624 log_debug_errno(r, "Failed to parse T1 time, ignoring: %m");
625 break;
626
627 case SD_DHCP_OPTION_REBINDING_T2_TIME:
628 r = lease_parse_u32(option, len, &lease->t2, 1);
629 if (r < 0)
630 log_debug_errno(r, "Failed to parse T2 time, ignoring: %m");
631 break;
632
633 case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
634 r = lease_parse_classless_routes(
635 option, len,
636 &lease->static_route,
637 &lease->static_route_size,
638 &lease->static_route_allocated);
639 if (r < 0)
640 log_debug_errno(r, "Failed to parse classless routes, ignoring: %m");
641 break;
642
643 case SD_DHCP_OPTION_NEW_TZDB_TIMEZONE: {
644 _cleanup_free_ char *tz = NULL;
645
646 r = lease_parse_string(option, len, &tz);
647 if (r < 0) {
648 log_debug_errno(r, "Failed to parse timezone option, ignoring: %m");
649 return 0;
650 }
651
652 if (!timezone_is_valid(tz, LOG_DEBUG)) {
653 log_debug_errno(r, "Timezone is not valid, ignoring: %m");
654 return 0;
655 }
656
657 free_and_replace(lease->timezone, tz);
658
659 break;
660 }
661
662 case SD_DHCP_OPTION_VENDOR_SPECIFIC:
663
664 if (len <= 0)
665 lease->vendor_specific = mfree(lease->vendor_specific);
666 else {
667 void *p;
668
669 p = memdup(option, len);
670 if (!p)
671 return -ENOMEM;
672
673 free(lease->vendor_specific);
674 lease->vendor_specific = p;
675 }
676
677 lease->vendor_specific_len = len;
678 break;
679
680 case SD_DHCP_OPTION_PRIVATE_BASE ... SD_DHCP_OPTION_PRIVATE_LAST:
681 r = dhcp_lease_insert_private_option(lease, code, option, len);
682 if (r < 0)
683 return r;
684
685 break;
686
687 default:
688 log_debug("Ignoring option DHCP option %"PRIu8" while parsing.", code);
689 break;
690 }
691
692 return 0;
693 }
694
695 /* Parses compressed domain names. */
696 int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***domains) {
697 _cleanup_strv_free_ char **names = NULL;
698 size_t pos = 0, cnt = 0;
699 int r;
700
701 assert(domains);
702 assert_return(option && len > 0, -ENODATA);
703
704 while (pos < len) {
705 _cleanup_free_ char *name = NULL;
706 size_t n = 0, allocated = 0;
707 size_t jump_barrier = pos, next_chunk = 0;
708 bool first = true;
709
710 for (;;) {
711 uint8_t c;
712 c = option[pos++];
713
714 if (c == 0) {
715 /* End of name */
716 break;
717 } else if (c <= 63) {
718 const char *label;
719
720 /* Literal label */
721 label = (const char*) (option + pos);
722 pos += c;
723 if (pos >= len)
724 return -EBADMSG;
725
726 if (!GREEDY_REALLOC(name, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
727 return -ENOMEM;
728
729 if (first)
730 first = false;
731 else
732 name[n++] = '.';
733
734 r = dns_label_escape(label, c, name + n, DNS_LABEL_ESCAPED_MAX);
735 if (r < 0)
736 return r;
737
738 n += r;
739 } else if ((c & 0xc0) == 0xc0) {
740 /* Pointer */
741
742 uint8_t d;
743 uint16_t ptr;
744
745 if (pos >= len)
746 return -EBADMSG;
747
748 d = option[pos++];
749 ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
750
751 /* Jumps are limited to a "prior occurrence" (RFC-1035 4.1.4) */
752 if (ptr >= jump_barrier)
753 return -EBADMSG;
754 jump_barrier = ptr;
755
756 /* Save current location so we don't end up re-parsing what's parsed so far. */
757 if (next_chunk == 0)
758 next_chunk = pos;
759
760 pos = ptr;
761 } else
762 return -EBADMSG;
763 }
764
765 if (!GREEDY_REALLOC(name, allocated, n + 1))
766 return -ENOMEM;
767 name[n] = 0;
768
769 r = strv_extend(&names, name);
770 if (r < 0)
771 return r;
772
773 cnt++;
774
775 if (next_chunk != 0)
776 pos = next_chunk;
777 }
778
779 *domains = TAKE_PTR(names);
780
781 return cnt;
782 }
783
784 int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len) {
785 struct sd_dhcp_raw_option *cur, *option;
786
787 assert(lease);
788
789 LIST_FOREACH(options, cur, lease->private_options) {
790 if (tag < cur->tag)
791 break;
792 if (tag == cur->tag) {
793 log_debug("Ignoring duplicate option, tagged %i.", tag);
794 return 0;
795 }
796 }
797
798 option = new(struct sd_dhcp_raw_option, 1);
799 if (!option)
800 return -ENOMEM;
801
802 option->tag = tag;
803 option->length = len;
804 option->data = memdup(data, len);
805 if (!option->data) {
806 free(option);
807 return -ENOMEM;
808 }
809
810 LIST_INSERT_BEFORE(options, lease->private_options, cur, option);
811 return 0;
812 }
813
814 int dhcp_lease_new(sd_dhcp_lease **ret) {
815 sd_dhcp_lease *lease;
816
817 lease = new0(sd_dhcp_lease, 1);
818 if (!lease)
819 return -ENOMEM;
820
821 lease->router = INADDR_ANY;
822 lease->n_ref = 1;
823
824 *ret = lease;
825 return 0;
826 }
827
828 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
829 _cleanup_free_ char *temp_path = NULL;
830 _cleanup_fclose_ FILE *f = NULL;
831 struct sd_dhcp_raw_option *option;
832 struct in_addr address;
833 const struct in_addr *addresses;
834 const void *client_id, *data;
835 size_t client_id_len, data_len;
836 const char *string;
837 uint16_t mtu;
838 _cleanup_free_ sd_dhcp_route **routes = NULL;
839 char **search_domains = NULL;
840 uint32_t t1, t2, lifetime;
841 int r;
842
843 assert(lease);
844 assert(lease_file);
845
846 r = fopen_temporary(lease_file, &f, &temp_path);
847 if (r < 0)
848 goto fail;
849
850 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
851 (void) fchmod(fileno(f), 0644);
852
853 fprintf(f,
854 "# This is private data. Do not parse.\n");
855
856 r = sd_dhcp_lease_get_address(lease, &address);
857 if (r >= 0)
858 fprintf(f, "ADDRESS=%s\n", inet_ntoa(address));
859
860 r = sd_dhcp_lease_get_netmask(lease, &address);
861 if (r >= 0)
862 fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
863
864 r = sd_dhcp_lease_get_router(lease, &address);
865 if (r >= 0)
866 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
867
868 r = sd_dhcp_lease_get_server_identifier(lease, &address);
869 if (r >= 0)
870 fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntoa(address));
871
872 r = sd_dhcp_lease_get_next_server(lease, &address);
873 if (r >= 0)
874 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
875
876 r = sd_dhcp_lease_get_broadcast(lease, &address);
877 if (r >= 0)
878 fprintf(f, "BROADCAST=%s\n", inet_ntoa(address));
879
880 r = sd_dhcp_lease_get_mtu(lease, &mtu);
881 if (r >= 0)
882 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
883
884 r = sd_dhcp_lease_get_t1(lease, &t1);
885 if (r >= 0)
886 fprintf(f, "T1=%" PRIu32 "\n", t1);
887
888 r = sd_dhcp_lease_get_t2(lease, &t2);
889 if (r >= 0)
890 fprintf(f, "T2=%" PRIu32 "\n", t2);
891
892 r = sd_dhcp_lease_get_lifetime(lease, &lifetime);
893 if (r >= 0)
894 fprintf(f, "LIFETIME=%" PRIu32 "\n", lifetime);
895
896 r = sd_dhcp_lease_get_dns(lease, &addresses);
897 if (r > 0) {
898 fputs("DNS=", f);
899 serialize_in_addrs(f, addresses, r);
900 fputs("\n", f);
901 }
902
903 r = sd_dhcp_lease_get_ntp(lease, &addresses);
904 if (r > 0) {
905 fputs("NTP=", f);
906 serialize_in_addrs(f, addresses, r);
907 fputs("\n", f);
908 }
909
910 r = sd_dhcp_lease_get_domainname(lease, &string);
911 if (r >= 0)
912 fprintf(f, "DOMAINNAME=%s\n", string);
913
914 r = sd_dhcp_lease_get_search_domains(lease, &search_domains);
915 if (r > 0) {
916 fputs("DOMAIN_SEARCH_LIST=", f);
917 fputstrv(f, search_domains, NULL, NULL);
918 fputs("\n", f);
919 }
920
921 r = sd_dhcp_lease_get_hostname(lease, &string);
922 if (r >= 0)
923 fprintf(f, "HOSTNAME=%s\n", string);
924
925 r = sd_dhcp_lease_get_root_path(lease, &string);
926 if (r >= 0)
927 fprintf(f, "ROOT_PATH=%s\n", string);
928
929 r = sd_dhcp_lease_get_routes(lease, &routes);
930 if (r > 0)
931 serialize_dhcp_routes(f, "ROUTES", routes, r);
932
933 r = sd_dhcp_lease_get_timezone(lease, &string);
934 if (r >= 0)
935 fprintf(f, "TIMEZONE=%s\n", string);
936
937 r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
938 if (r >= 0) {
939 _cleanup_free_ char *client_id_hex = NULL;
940
941 client_id_hex = hexmem(client_id, client_id_len);
942 if (!client_id_hex) {
943 r = -ENOMEM;
944 goto fail;
945 }
946 fprintf(f, "CLIENTID=%s\n", client_id_hex);
947 }
948
949 r = sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len);
950 if (r >= 0) {
951 _cleanup_free_ char *option_hex = NULL;
952
953 option_hex = hexmem(data, data_len);
954 if (!option_hex) {
955 r = -ENOMEM;
956 goto fail;
957 }
958 fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
959 }
960
961 LIST_FOREACH(options, option, lease->private_options) {
962 char key[STRLEN("OPTION_000")+1];
963
964 xsprintf(key, "OPTION_%" PRIu8, option->tag);
965 r = serialize_dhcp_option(f, key, option->data, option->length);
966 if (r < 0)
967 goto fail;
968 }
969
970 r = fflush_and_check(f);
971 if (r < 0)
972 goto fail;
973
974 if (rename(temp_path, lease_file) < 0) {
975 r = -errno;
976 goto fail;
977 }
978
979 return 0;
980
981 fail:
982 if (temp_path)
983 (void) unlink(temp_path);
984
985 return log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
986 }
987
988 int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
989
990 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
991 _cleanup_free_ char
992 *address = NULL,
993 *router = NULL,
994 *netmask = NULL,
995 *server_address = NULL,
996 *next_server = NULL,
997 *broadcast = NULL,
998 *dns = NULL,
999 *ntp = NULL,
1000 *mtu = NULL,
1001 *routes = NULL,
1002 *domains = NULL,
1003 *client_id_hex = NULL,
1004 *vendor_specific_hex = NULL,
1005 *lifetime = NULL,
1006 *t1 = NULL,
1007 *t2 = NULL,
1008 *options[SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE + 1] = {};
1009
1010 int r, i;
1011
1012 assert(lease_file);
1013 assert(ret);
1014
1015 r = dhcp_lease_new(&lease);
1016 if (r < 0)
1017 return r;
1018
1019 r = parse_env_file(NULL, lease_file,
1020 "ADDRESS", &address,
1021 "ROUTER", &router,
1022 "NETMASK", &netmask,
1023 "SERVER_IDENTIFIER", &server_address,
1024 "NEXT_SERVER", &next_server,
1025 "BROADCAST", &broadcast,
1026 "DNS", &dns,
1027 "NTP", &ntp,
1028 "MTU", &mtu,
1029 "DOMAINNAME", &lease->domainname,
1030 "HOSTNAME", &lease->hostname,
1031 "DOMAIN_SEARCH_LIST", &domains,
1032 "ROOT_PATH", &lease->root_path,
1033 "ROUTES", &routes,
1034 "CLIENTID", &client_id_hex,
1035 "TIMEZONE", &lease->timezone,
1036 "VENDOR_SPECIFIC", &vendor_specific_hex,
1037 "LIFETIME", &lifetime,
1038 "T1", &t1,
1039 "T2", &t2,
1040 "OPTION_224", &options[0],
1041 "OPTION_225", &options[1],
1042 "OPTION_226", &options[2],
1043 "OPTION_227", &options[3],
1044 "OPTION_228", &options[4],
1045 "OPTION_229", &options[5],
1046 "OPTION_230", &options[6],
1047 "OPTION_231", &options[7],
1048 "OPTION_232", &options[8],
1049 "OPTION_233", &options[9],
1050 "OPTION_234", &options[10],
1051 "OPTION_235", &options[11],
1052 "OPTION_236", &options[12],
1053 "OPTION_237", &options[13],
1054 "OPTION_238", &options[14],
1055 "OPTION_239", &options[15],
1056 "OPTION_240", &options[16],
1057 "OPTION_241", &options[17],
1058 "OPTION_242", &options[18],
1059 "OPTION_243", &options[19],
1060 "OPTION_244", &options[20],
1061 "OPTION_245", &options[21],
1062 "OPTION_246", &options[22],
1063 "OPTION_247", &options[23],
1064 "OPTION_248", &options[24],
1065 "OPTION_249", &options[25],
1066 "OPTION_250", &options[26],
1067 "OPTION_251", &options[27],
1068 "OPTION_252", &options[28],
1069 "OPTION_253", &options[29],
1070 "OPTION_254", &options[30]);
1071 if (r < 0)
1072 return r;
1073
1074 if (address) {
1075 r = inet_pton(AF_INET, address, &lease->address);
1076 if (r <= 0)
1077 log_debug("Failed to parse address %s, ignoring.", address);
1078 }
1079
1080 if (router) {
1081 r = inet_pton(AF_INET, router, &lease->router);
1082 if (r <= 0)
1083 log_debug("Failed to parse router %s, ignoring.", router);
1084 }
1085
1086 if (netmask) {
1087 r = inet_pton(AF_INET, netmask, &lease->subnet_mask);
1088 if (r <= 0)
1089 log_debug("Failed to parse netmask %s, ignoring.", netmask);
1090 else
1091 lease->have_subnet_mask = true;
1092 }
1093
1094 if (server_address) {
1095 r = inet_pton(AF_INET, server_address, &lease->server_address);
1096 if (r <= 0)
1097 log_debug("Failed to parse server address %s, ignoring.", server_address);
1098 }
1099
1100 if (next_server) {
1101 r = inet_pton(AF_INET, next_server, &lease->next_server);
1102 if (r <= 0)
1103 log_debug("Failed to parse next server %s, ignoring.", next_server);
1104 }
1105
1106 if (broadcast) {
1107 r = inet_pton(AF_INET, broadcast, &lease->broadcast);
1108 if (r <= 0)
1109 log_debug("Failed to parse broadcast address %s, ignoring.", broadcast);
1110 else
1111 lease->have_broadcast = true;
1112 }
1113
1114 if (dns) {
1115 r = deserialize_in_addrs(&lease->dns, dns);
1116 if (r < 0)
1117 log_debug_errno(r, "Failed to deserialize DNS servers %s, ignoring: %m", dns);
1118 else
1119 lease->dns_size = r;
1120 }
1121
1122 if (ntp) {
1123 r = deserialize_in_addrs(&lease->ntp, ntp);
1124 if (r < 0)
1125 log_debug_errno(r, "Failed to deserialize NTP servers %s, ignoring: %m", ntp);
1126 else
1127 lease->ntp_size = r;
1128 }
1129
1130 if (mtu) {
1131 r = safe_atou16(mtu, &lease->mtu);
1132 if (r < 0)
1133 log_debug_errno(r, "Failed to parse MTU %s, ignoring: %m", mtu);
1134 }
1135
1136 if (domains) {
1137 _cleanup_strv_free_ char **a = NULL;
1138 a = strv_split(domains, " ");
1139 if (!a)
1140 return -ENOMEM;
1141
1142 if (!strv_isempty(a)) {
1143 lease->search_domains = a;
1144 a = NULL;
1145 }
1146 }
1147
1148 if (routes) {
1149 r = deserialize_dhcp_routes(
1150 &lease->static_route,
1151 &lease->static_route_size,
1152 &lease->static_route_allocated,
1153 routes);
1154 if (r < 0)
1155 log_debug_errno(r, "Failed to parse DHCP routes %s, ignoring: %m", routes);
1156 }
1157
1158 if (lifetime) {
1159 r = safe_atou32(lifetime, &lease->lifetime);
1160 if (r < 0)
1161 log_debug_errno(r, "Failed to parse lifetime %s, ignoring: %m", lifetime);
1162 }
1163
1164 if (t1) {
1165 r = safe_atou32(t1, &lease->t1);
1166 if (r < 0)
1167 log_debug_errno(r, "Failed to parse T1 %s, ignoring: %m", t1);
1168 }
1169
1170 if (t2) {
1171 r = safe_atou32(t2, &lease->t2);
1172 if (r < 0)
1173 log_debug_errno(r, "Failed to parse T2 %s, ignoring: %m", t2);
1174 }
1175
1176 if (client_id_hex) {
1177 r = unhexmem(client_id_hex, (size_t) -1, &lease->client_id, &lease->client_id_len);
1178 if (r < 0)
1179 log_debug_errno(r, "Failed to parse client ID %s, ignoring: %m", client_id_hex);
1180 }
1181
1182 if (vendor_specific_hex) {
1183 r = unhexmem(vendor_specific_hex, (size_t) -1, &lease->vendor_specific, &lease->vendor_specific_len);
1184 if (r < 0)
1185 log_debug_errno(r, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex);
1186 }
1187
1188 for (i = 0; i <= SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE; i++) {
1189 _cleanup_free_ void *data = NULL;
1190 size_t len;
1191
1192 if (!options[i])
1193 continue;
1194
1195 r = unhexmem(options[i], (size_t) -1, &data, &len);
1196 if (r < 0) {
1197 log_debug_errno(r, "Failed to parse private DHCP option %s, ignoring: %m", options[i]);
1198 continue;
1199 }
1200
1201 r = dhcp_lease_insert_private_option(lease, SD_DHCP_OPTION_PRIVATE_BASE + i, data, len);
1202 if (r < 0)
1203 return r;
1204 }
1205
1206 *ret = TAKE_PTR(lease);
1207
1208 return 0;
1209 }
1210
1211 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
1212 struct in_addr address, mask;
1213 int r;
1214
1215 assert(lease);
1216
1217 if (lease->address == 0)
1218 return -ENODATA;
1219
1220 address.s_addr = lease->address;
1221
1222 /* fall back to the default subnet masks based on address class */
1223 r = in4_addr_default_subnet_mask(&address, &mask);
1224 if (r < 0)
1225 return r;
1226
1227 lease->subnet_mask = mask.s_addr;
1228 lease->have_subnet_mask = true;
1229
1230 return 0;
1231 }
1232
1233 int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len) {
1234 assert_return(lease, -EINVAL);
1235 assert_return(client_id, -EINVAL);
1236 assert_return(client_id_len, -EINVAL);
1237
1238 if (!lease->client_id)
1239 return -ENODATA;
1240
1241 *client_id = lease->client_id;
1242 *client_id_len = lease->client_id_len;
1243
1244 return 0;
1245 }
1246
1247 int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len) {
1248 assert_return(lease, -EINVAL);
1249 assert_return(client_id || client_id_len <= 0, -EINVAL);
1250
1251 if (client_id_len <= 0)
1252 lease->client_id = mfree(lease->client_id);
1253 else {
1254 void *p;
1255
1256 p = memdup(client_id, client_id_len);
1257 if (!p)
1258 return -ENOMEM;
1259
1260 free(lease->client_id);
1261 lease->client_id = p;
1262 lease->client_id_len = client_id_len;
1263 }
1264
1265 return 0;
1266 }
1267
1268 int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **tz) {
1269 assert_return(lease, -EINVAL);
1270 assert_return(tz, -EINVAL);
1271
1272 if (!lease->timezone)
1273 return -ENODATA;
1274
1275 *tz = lease->timezone;
1276 return 0;
1277 }
1278
1279 int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination) {
1280 assert_return(route, -EINVAL);
1281 assert_return(destination, -EINVAL);
1282
1283 *destination = route->dst_addr;
1284 return 0;
1285 }
1286
1287 int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length) {
1288 assert_return(route, -EINVAL);
1289 assert_return(length, -EINVAL);
1290
1291 *length = route->dst_prefixlen;
1292 return 0;
1293 }
1294
1295 int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway) {
1296 assert_return(route, -EINVAL);
1297 assert_return(gateway, -EINVAL);
1298
1299 *gateway = route->gw_addr;
1300 return 0;
1301 }