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