1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright (C) 2013 Intel Corporation. All rights reserved.
6 Copyright (C) 2014 Tom Gundersen
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <arpa/inet.h>
25 #include <stdio_ext.h>
29 #include "sd-dhcp-lease.h"
31 #include "alloc-util.h"
32 #include "dhcp-lease-internal.h"
33 #include "dhcp-protocol.h"
34 #include "dns-domain.h"
37 #include "hexdecoct.h"
38 #include "hostname-util.h"
39 #include "in-addr-util.h"
40 #include "network-internal.h"
41 #include "parse-util.h"
42 #include "stdio-util.h"
43 #include "string-util.h"
44 #include "unaligned.h"
46 int sd_dhcp_lease_get_address(sd_dhcp_lease
*lease
, struct in_addr
*addr
) {
47 assert_return(lease
, -EINVAL
);
48 assert_return(addr
, -EINVAL
);
50 if (lease
->address
== 0)
53 addr
->s_addr
= lease
->address
;
57 int sd_dhcp_lease_get_broadcast(sd_dhcp_lease
*lease
, struct in_addr
*addr
) {
58 assert_return(lease
, -EINVAL
);
59 assert_return(addr
, -EINVAL
);
61 if (!lease
->have_broadcast
)
64 addr
->s_addr
= lease
->broadcast
;
68 int sd_dhcp_lease_get_lifetime(sd_dhcp_lease
*lease
, uint32_t *lifetime
) {
69 assert_return(lease
, -EINVAL
);
70 assert_return(lifetime
, -EINVAL
);
72 if (lease
->lifetime
<= 0)
75 *lifetime
= lease
->lifetime
;
79 int sd_dhcp_lease_get_t1(sd_dhcp_lease
*lease
, uint32_t *t1
) {
80 assert_return(lease
, -EINVAL
);
81 assert_return(t1
, -EINVAL
);
90 int sd_dhcp_lease_get_t2(sd_dhcp_lease
*lease
, uint32_t *t2
) {
91 assert_return(lease
, -EINVAL
);
92 assert_return(t2
, -EINVAL
);
101 int sd_dhcp_lease_get_mtu(sd_dhcp_lease
*lease
, uint16_t *mtu
) {
102 assert_return(lease
, -EINVAL
);
103 assert_return(mtu
, -EINVAL
);
112 int sd_dhcp_lease_get_dns(sd_dhcp_lease
*lease
, const struct in_addr
**addr
) {
113 assert_return(lease
, -EINVAL
);
114 assert_return(addr
, -EINVAL
);
116 if (lease
->dns_size
<= 0)
120 return (int) lease
->dns_size
;
123 int sd_dhcp_lease_get_ntp(sd_dhcp_lease
*lease
, const struct in_addr
**addr
) {
124 assert_return(lease
, -EINVAL
);
125 assert_return(addr
, -EINVAL
);
127 if (lease
->ntp_size
<= 0)
131 return (int) lease
->ntp_size
;
134 int sd_dhcp_lease_get_domainname(sd_dhcp_lease
*lease
, const char **domainname
) {
135 assert_return(lease
, -EINVAL
);
136 assert_return(domainname
, -EINVAL
);
138 if (!lease
->domainname
)
141 *domainname
= lease
->domainname
;
145 int sd_dhcp_lease_get_hostname(sd_dhcp_lease
*lease
, const char **hostname
) {
146 assert_return(lease
, -EINVAL
);
147 assert_return(hostname
, -EINVAL
);
149 if (!lease
->hostname
)
152 *hostname
= lease
->hostname
;
156 int sd_dhcp_lease_get_root_path(sd_dhcp_lease
*lease
, const char **root_path
) {
157 assert_return(lease
, -EINVAL
);
158 assert_return(root_path
, -EINVAL
);
160 if (!lease
->root_path
)
163 *root_path
= lease
->root_path
;
167 int sd_dhcp_lease_get_router(sd_dhcp_lease
*lease
, struct in_addr
*addr
) {
168 assert_return(lease
, -EINVAL
);
169 assert_return(addr
, -EINVAL
);
171 if (lease
->router
== 0)
174 addr
->s_addr
= lease
->router
;
178 int sd_dhcp_lease_get_netmask(sd_dhcp_lease
*lease
, struct in_addr
*addr
) {
179 assert_return(lease
, -EINVAL
);
180 assert_return(addr
, -EINVAL
);
182 if (!lease
->have_subnet_mask
)
185 addr
->s_addr
= lease
->subnet_mask
;
189 int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease
*lease
, struct in_addr
*addr
) {
190 assert_return(lease
, -EINVAL
);
191 assert_return(addr
, -EINVAL
);
193 if (lease
->server_address
== 0)
196 addr
->s_addr
= lease
->server_address
;
200 int sd_dhcp_lease_get_next_server(sd_dhcp_lease
*lease
, struct in_addr
*addr
) {
201 assert_return(lease
, -EINVAL
);
202 assert_return(addr
, -EINVAL
);
204 if (lease
->next_server
== 0)
207 addr
->s_addr
= lease
->next_server
;
212 * The returned routes array must be freed by the caller.
213 * Route objects have the same lifetime of the lease and must not be freed.
215 int sd_dhcp_lease_get_routes(sd_dhcp_lease
*lease
, sd_dhcp_route
***routes
) {
219 assert_return(lease
, -EINVAL
);
220 assert_return(routes
, -EINVAL
);
222 if (lease
->static_route_size
<= 0)
225 ret
= new(sd_dhcp_route
*, lease
->static_route_size
);
229 for (i
= 0; i
< lease
->static_route_size
; i
++)
230 ret
[i
] = &lease
->static_route
[i
];
233 return (int) lease
->static_route_size
;
236 int sd_dhcp_lease_get_search_domains(sd_dhcp_lease
*lease
, char ***domains
) {
239 assert_return(lease
, -EINVAL
);
240 assert_return(domains
, -EINVAL
);
242 r
= strv_length(lease
->search_domains
);
244 *domains
= lease
->search_domains
;
251 int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease
*lease
, const void **data
, size_t *data_len
) {
252 assert_return(lease
, -EINVAL
);
253 assert_return(data
, -EINVAL
);
254 assert_return(data_len
, -EINVAL
);
256 if (lease
->vendor_specific_len
<= 0)
259 *data
= lease
->vendor_specific
;
260 *data_len
= lease
->vendor_specific_len
;
264 sd_dhcp_lease
*sd_dhcp_lease_ref(sd_dhcp_lease
*lease
) {
269 assert(lease
->n_ref
>= 1);
275 sd_dhcp_lease
*sd_dhcp_lease_unref(sd_dhcp_lease
*lease
) {
280 assert(lease
->n_ref
>= 1);
283 if (lease
->n_ref
> 0)
286 while (lease
->private_options
) {
287 struct sd_dhcp_raw_option
*option
= lease
->private_options
;
289 LIST_REMOVE(options
, lease
->private_options
, option
);
295 free(lease
->hostname
);
296 free(lease
->domainname
);
299 free(lease
->static_route
);
300 free(lease
->client_id
);
301 free(lease
->vendor_specific
);
302 strv_free(lease
->search_domains
);
306 static int lease_parse_u32(const uint8_t *option
, size_t len
, uint32_t *ret
, uint32_t min
) {
313 *ret
= unaligned_read_be32((be32_t
*) option
);
320 static int lease_parse_u16(const uint8_t *option
, size_t len
, uint16_t *ret
, uint16_t min
) {
327 *ret
= unaligned_read_be16((be16_t
*) option
);
334 static int lease_parse_be32(const uint8_t *option
, size_t len
, be32_t
*ret
) {
341 memcpy(ret
, option
, 4);
345 static int lease_parse_string(const uint8_t *option
, size_t len
, char **ret
) {
355 * One trailing NUL byte is OK, we don't mind. See:
356 * https://github.com/systemd/systemd/issues/1337
358 if (memchr(option
, 0, len
- 1))
361 string
= strndup((const char *) option
, len
);
372 static int lease_parse_domain(const uint8_t *option
, size_t len
, char **ret
) {
373 _cleanup_free_
char *name
= NULL
, *normalized
= NULL
;
379 r
= lease_parse_string(option
, len
, &name
);
387 r
= dns_name_normalize(name
, &normalized
);
391 if (is_localhost(normalized
))
394 if (dns_name_is_root(normalized
))
397 free_and_replace(*ret
, normalized
);
402 static void filter_bogus_addresses(struct in_addr
*addresses
, size_t *n
) {
405 /* Silently filter DNS/NTP servers supplied to us that do not make outside of the local scope. */
407 for (i
= 0, j
= 0; i
< *n
; i
++) {
409 if (in4_addr_is_null(addresses
+i
) ||
410 in4_addr_is_localhost(addresses
+i
))
413 addresses
[j
++] = addresses
[i
];
419 static int lease_parse_in_addrs(const uint8_t *option
, size_t len
, struct in_addr
**ret
, size_t *n_ret
) {
429 struct in_addr
*addresses
;
434 n_addresses
= len
/ 4;
436 addresses
= newdup(struct in_addr
, option
, n_addresses
);
440 filter_bogus_addresses(addresses
, &n_addresses
);
444 *n_ret
= n_addresses
;
450 static int lease_parse_routes(
451 const uint8_t *option
, size_t len
,
452 struct sd_dhcp_route
**routes
, size_t *routes_size
, size_t *routes_allocated
) {
456 assert(option
|| len
<= 0);
459 assert(routes_allocated
);
467 if (!GREEDY_REALLOC(*routes
, *routes_allocated
, *routes_size
+ (len
/ 8)))
471 struct sd_dhcp_route
*route
= *routes
+ *routes_size
;
474 route
->option
= SD_DHCP_OPTION_STATIC_ROUTE
;
475 r
= in4_addr_default_prefixlen((struct in_addr
*) option
, &route
->dst_prefixlen
);
477 log_debug("Failed to determine destination prefix length from class based IP, ignoring");
481 assert_se(lease_parse_be32(option
, 4, &addr
.s_addr
) >= 0);
482 route
->dst_addr
= inet_makeaddr(inet_netof(addr
), 0);
485 assert_se(lease_parse_be32(option
, 4, &route
->gw_addr
.s_addr
) >= 0);
495 /* parses RFC3442 Classless Static Route Option */
496 static int lease_parse_classless_routes(
497 const uint8_t *option
, size_t len
,
498 struct sd_dhcp_route
**routes
, size_t *routes_size
, size_t *routes_allocated
) {
500 assert(option
|| len
<= 0);
503 assert(routes_allocated
);
508 /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */
512 struct sd_dhcp_route
*route
;
514 if (!GREEDY_REALLOC(*routes
, *routes_allocated
, *routes_size
+ 1))
517 route
= *routes
+ *routes_size
;
518 route
->option
= SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE
;
520 dst_octets
= (*option
== 0 ? 0 : ((*option
- 1) / 8) + 1);
521 route
->dst_prefixlen
= *option
;
525 /* can't have more than 4 octets in IPv4 */
526 if (dst_octets
> 4 || len
< dst_octets
)
529 route
->dst_addr
.s_addr
= 0;
530 memcpy(&route
->dst_addr
.s_addr
, option
, dst_octets
);
531 option
+= dst_octets
;
537 assert_se(lease_parse_be32(option
, 4, &route
->gw_addr
.s_addr
) >= 0);
547 int dhcp_lease_parse_options(uint8_t code
, uint8_t len
, const void *option
, void *userdata
) {
548 sd_dhcp_lease
*lease
= userdata
;
555 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME
:
556 r
= lease_parse_u32(option
, len
, &lease
->lifetime
, 1);
558 log_debug_errno(r
, "Failed to parse lease time, ignoring: %m");
562 case SD_DHCP_OPTION_SERVER_IDENTIFIER
:
563 r
= lease_parse_be32(option
, len
, &lease
->server_address
);
565 log_debug_errno(r
, "Failed to parse server identifier, ignoring: %m");
569 case SD_DHCP_OPTION_SUBNET_MASK
:
570 r
= lease_parse_be32(option
, len
, &lease
->subnet_mask
);
572 log_debug_errno(r
, "Failed to parse subnet mask, ignoring: %m");
574 lease
->have_subnet_mask
= true;
577 case SD_DHCP_OPTION_BROADCAST
:
578 r
= lease_parse_be32(option
, len
, &lease
->broadcast
);
580 log_debug_errno(r
, "Failed to parse broadcast address, ignoring: %m");
582 lease
->have_broadcast
= true;
585 case SD_DHCP_OPTION_ROUTER
:
587 r
= lease_parse_be32(option
, 4, &lease
->router
);
589 log_debug_errno(r
, "Failed to parse router address, ignoring: %m");
593 case SD_DHCP_OPTION_DOMAIN_NAME_SERVER
:
594 r
= lease_parse_in_addrs(option
, len
, &lease
->dns
, &lease
->dns_size
);
596 log_debug_errno(r
, "Failed to parse DNS server, ignoring: %m");
599 case SD_DHCP_OPTION_NTP_SERVER
:
600 r
= lease_parse_in_addrs(option
, len
, &lease
->ntp
, &lease
->ntp_size
);
602 log_debug_errno(r
, "Failed to parse NTP server, ignoring: %m");
605 case SD_DHCP_OPTION_STATIC_ROUTE
:
606 r
= lease_parse_routes(option
, len
, &lease
->static_route
, &lease
->static_route_size
, &lease
->static_route_allocated
);
608 log_debug_errno(r
, "Failed to parse static routes, ignoring: %m");
611 case SD_DHCP_OPTION_INTERFACE_MTU
:
612 r
= lease_parse_u16(option
, len
, &lease
->mtu
, 68);
614 log_debug_errno(r
, "Failed to parse MTU, ignoring: %m");
615 if (lease
->mtu
< DHCP_DEFAULT_MIN_SIZE
) {
616 log_debug("MTU value of %" PRIu16
" too small. Using default MTU value of %d instead.", lease
->mtu
, DHCP_DEFAULT_MIN_SIZE
);
617 lease
->mtu
= DHCP_DEFAULT_MIN_SIZE
;
622 case SD_DHCP_OPTION_DOMAIN_NAME
:
623 r
= lease_parse_domain(option
, len
, &lease
->domainname
);
625 log_debug_errno(r
, "Failed to parse domain name, ignoring: %m");
631 case SD_DHCP_OPTION_DOMAIN_SEARCH_LIST
:
632 r
= dhcp_lease_parse_search_domains(option
, len
, &lease
->search_domains
);
634 log_debug_errno(r
, "Failed to parse Domain Search List, ignoring: %m");
637 case SD_DHCP_OPTION_HOST_NAME
:
638 r
= lease_parse_domain(option
, len
, &lease
->hostname
);
640 log_debug_errno(r
, "Failed to parse host name, ignoring: %m");
646 case SD_DHCP_OPTION_ROOT_PATH
:
647 r
= lease_parse_string(option
, len
, &lease
->root_path
);
649 log_debug_errno(r
, "Failed to parse root path, ignoring: %m");
652 case SD_DHCP_OPTION_RENEWAL_T1_TIME
:
653 r
= lease_parse_u32(option
, len
, &lease
->t1
, 1);
655 log_debug_errno(r
, "Failed to parse T1 time, ignoring: %m");
658 case SD_DHCP_OPTION_REBINDING_T2_TIME
:
659 r
= lease_parse_u32(option
, len
, &lease
->t2
, 1);
661 log_debug_errno(r
, "Failed to parse T2 time, ignoring: %m");
664 case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE
:
665 r
= lease_parse_classless_routes(
667 &lease
->static_route
,
668 &lease
->static_route_size
,
669 &lease
->static_route_allocated
);
671 log_debug_errno(r
, "Failed to parse classless routes, ignoring: %m");
674 case SD_DHCP_OPTION_NEW_TZDB_TIMEZONE
: {
675 _cleanup_free_
char *tz
= NULL
;
677 r
= lease_parse_string(option
, len
, &tz
);
679 log_debug_errno(r
, "Failed to parse timezone option, ignoring: %m");
683 if (!timezone_is_valid(tz
)) {
684 log_debug_errno(r
, "Timezone is not valid, ignoring: %m");
688 free_and_replace(lease
->timezone
, tz
);
693 case SD_DHCP_OPTION_VENDOR_SPECIFIC
:
696 lease
->vendor_specific
= mfree(lease
->vendor_specific
);
700 p
= memdup(option
, len
);
704 free(lease
->vendor_specific
);
705 lease
->vendor_specific
= p
;
708 lease
->vendor_specific_len
= len
;
711 case SD_DHCP_OPTION_PRIVATE_BASE
... SD_DHCP_OPTION_PRIVATE_LAST
:
712 r
= dhcp_lease_insert_private_option(lease
, code
, option
, len
);
719 log_debug("Ignoring option DHCP option %"PRIu8
" while parsing.", code
);
726 /* Parses compressed domain names. */
727 int dhcp_lease_parse_search_domains(const uint8_t *option
, size_t len
, char ***domains
) {
728 _cleanup_strv_free_
char **names
= NULL
;
729 size_t pos
= 0, cnt
= 0;
733 assert_return(option
&& len
> 0, -ENODATA
);
736 _cleanup_free_
char *name
= NULL
;
737 size_t n
= 0, allocated
= 0;
738 size_t jump_barrier
= pos
, next_chunk
= 0;
748 } else if (c
<= 63) {
752 label
= (const char*) (option
+ pos
);
757 if (!GREEDY_REALLOC(name
, allocated
, n
+ !first
+ DNS_LABEL_ESCAPED_MAX
))
765 r
= dns_label_escape(label
, c
, name
+ n
, DNS_LABEL_ESCAPED_MAX
);
770 } else if ((c
& 0xc0) == 0xc0) {
780 ptr
= (uint16_t) (c
& ~0xc0) << 8 | (uint16_t) d
;
782 /* Jumps are limited to a "prior occurrence" (RFC-1035 4.1.4) */
783 if (ptr
>= jump_barrier
)
787 /* Save current location so we don't end up re-parsing what's parsed so far. */
796 if (!GREEDY_REALLOC(name
, allocated
, n
+ 1))
800 r
= strv_extend(&names
, name
);
816 int dhcp_lease_insert_private_option(sd_dhcp_lease
*lease
, uint8_t tag
, const void *data
, uint8_t len
) {
817 struct sd_dhcp_raw_option
*cur
, *option
;
821 LIST_FOREACH(options
, cur
, lease
->private_options
) {
824 if (tag
== cur
->tag
) {
825 log_debug("Ignoring duplicate option, tagged %i.", tag
);
830 option
= new(struct sd_dhcp_raw_option
, 1);
835 option
->length
= len
;
836 option
->data
= memdup(data
, len
);
842 LIST_INSERT_BEFORE(options
, lease
->private_options
, cur
, option
);
846 int dhcp_lease_new(sd_dhcp_lease
**ret
) {
847 sd_dhcp_lease
*lease
;
849 lease
= new0(sd_dhcp_lease
, 1);
853 lease
->router
= INADDR_ANY
;
860 int dhcp_lease_save(sd_dhcp_lease
*lease
, const char *lease_file
) {
861 _cleanup_free_
char *temp_path
= NULL
;
862 _cleanup_fclose_
FILE *f
= NULL
;
863 struct sd_dhcp_raw_option
*option
;
864 struct in_addr address
;
865 const struct in_addr
*addresses
;
866 const void *client_id
, *data
;
867 size_t client_id_len
, data_len
;
870 _cleanup_free_ sd_dhcp_route
**routes
= NULL
;
871 char **search_domains
= NULL
;
872 uint32_t t1
, t2
, lifetime
;
878 r
= fopen_temporary(lease_file
, &f
, &temp_path
);
882 (void) __fsetlocking(f
, FSETLOCKING_BYCALLER
);
883 (void) fchmod(fileno(f
), 0644);
886 "# This is private data. Do not parse.\n");
888 r
= sd_dhcp_lease_get_address(lease
, &address
);
890 fprintf(f
, "ADDRESS=%s\n", inet_ntoa(address
));
892 r
= sd_dhcp_lease_get_netmask(lease
, &address
);
894 fprintf(f
, "NETMASK=%s\n", inet_ntoa(address
));
896 r
= sd_dhcp_lease_get_router(lease
, &address
);
898 fprintf(f
, "ROUTER=%s\n", inet_ntoa(address
));
900 r
= sd_dhcp_lease_get_server_identifier(lease
, &address
);
902 fprintf(f
, "SERVER_ADDRESS=%s\n", inet_ntoa(address
));
904 r
= sd_dhcp_lease_get_next_server(lease
, &address
);
906 fprintf(f
, "NEXT_SERVER=%s\n", inet_ntoa(address
));
908 r
= sd_dhcp_lease_get_broadcast(lease
, &address
);
910 fprintf(f
, "BROADCAST=%s\n", inet_ntoa(address
));
912 r
= sd_dhcp_lease_get_mtu(lease
, &mtu
);
914 fprintf(f
, "MTU=%" PRIu16
"\n", mtu
);
916 r
= sd_dhcp_lease_get_t1(lease
, &t1
);
918 fprintf(f
, "T1=%" PRIu32
"\n", t1
);
920 r
= sd_dhcp_lease_get_t2(lease
, &t2
);
922 fprintf(f
, "T2=%" PRIu32
"\n", t2
);
924 r
= sd_dhcp_lease_get_lifetime(lease
, &lifetime
);
926 fprintf(f
, "LIFETIME=%" PRIu32
"\n", lifetime
);
928 r
= sd_dhcp_lease_get_dns(lease
, &addresses
);
931 serialize_in_addrs(f
, addresses
, r
);
935 r
= sd_dhcp_lease_get_ntp(lease
, &addresses
);
938 serialize_in_addrs(f
, addresses
, r
);
942 r
= sd_dhcp_lease_get_domainname(lease
, &string
);
944 fprintf(f
, "DOMAINNAME=%s\n", string
);
946 r
= sd_dhcp_lease_get_search_domains(lease
, &search_domains
);
948 fputs("DOMAIN_SEARCH_LIST=", f
);
949 fputstrv(f
, search_domains
, NULL
, NULL
);
953 r
= sd_dhcp_lease_get_hostname(lease
, &string
);
955 fprintf(f
, "HOSTNAME=%s\n", string
);
957 r
= sd_dhcp_lease_get_root_path(lease
, &string
);
959 fprintf(f
, "ROOT_PATH=%s\n", string
);
961 r
= sd_dhcp_lease_get_routes(lease
, &routes
);
963 serialize_dhcp_routes(f
, "ROUTES", routes
, r
);
965 r
= sd_dhcp_lease_get_timezone(lease
, &string
);
967 fprintf(f
, "TIMEZONE=%s\n", string
);
969 r
= sd_dhcp_lease_get_client_id(lease
, &client_id
, &client_id_len
);
971 _cleanup_free_
char *client_id_hex
= NULL
;
973 client_id_hex
= hexmem(client_id
, client_id_len
);
974 if (!client_id_hex
) {
978 fprintf(f
, "CLIENTID=%s\n", client_id_hex
);
981 r
= sd_dhcp_lease_get_vendor_specific(lease
, &data
, &data_len
);
983 _cleanup_free_
char *option_hex
= NULL
;
985 option_hex
= hexmem(data
, data_len
);
990 fprintf(f
, "VENDOR_SPECIFIC=%s\n", option_hex
);
993 LIST_FOREACH(options
, option
, lease
->private_options
) {
994 char key
[STRLEN("OPTION_000")+1];
996 xsprintf(key
, "OPTION_%" PRIu8
, option
->tag
);
997 r
= serialize_dhcp_option(f
, key
, option
->data
, option
->length
);
1002 r
= fflush_and_check(f
);
1006 if (rename(temp_path
, lease_file
) < 0) {
1015 (void) unlink(temp_path
);
1017 return log_error_errno(r
, "Failed to save lease data %s: %m", lease_file
);
1020 int dhcp_lease_load(sd_dhcp_lease
**ret
, const char *lease_file
) {
1022 _cleanup_(sd_dhcp_lease_unrefp
) sd_dhcp_lease
*lease
= NULL
;
1027 *server_address
= NULL
,
1028 *next_server
= NULL
,
1035 *client_id_hex
= NULL
,
1036 *vendor_specific_hex
= NULL
,
1040 *options
[SD_DHCP_OPTION_PRIVATE_LAST
- SD_DHCP_OPTION_PRIVATE_BASE
+ 1] = {};
1047 r
= dhcp_lease_new(&lease
);
1051 r
= parse_env_file(lease_file
, NEWLINE
,
1052 "ADDRESS", &address
,
1054 "NETMASK", &netmask
,
1055 "SERVER_IDENTIFIER", &server_address
,
1056 "NEXT_SERVER", &next_server
,
1057 "BROADCAST", &broadcast
,
1061 "DOMAINNAME", &lease
->domainname
,
1062 "HOSTNAME", &lease
->hostname
,
1063 "DOMAIN_SEARCH_LIST", &domains
,
1064 "ROOT_PATH", &lease
->root_path
,
1066 "CLIENTID", &client_id_hex
,
1067 "TIMEZONE", &lease
->timezone
,
1068 "VENDOR_SPECIFIC", &vendor_specific_hex
,
1069 "LIFETIME", &lifetime
,
1072 "OPTION_224", &options
[0],
1073 "OPTION_225", &options
[1],
1074 "OPTION_226", &options
[2],
1075 "OPTION_227", &options
[3],
1076 "OPTION_228", &options
[4],
1077 "OPTION_229", &options
[5],
1078 "OPTION_230", &options
[6],
1079 "OPTION_231", &options
[7],
1080 "OPTION_232", &options
[8],
1081 "OPTION_233", &options
[9],
1082 "OPTION_234", &options
[10],
1083 "OPTION_235", &options
[11],
1084 "OPTION_236", &options
[12],
1085 "OPTION_237", &options
[13],
1086 "OPTION_238", &options
[14],
1087 "OPTION_239", &options
[15],
1088 "OPTION_240", &options
[16],
1089 "OPTION_241", &options
[17],
1090 "OPTION_242", &options
[18],
1091 "OPTION_243", &options
[19],
1092 "OPTION_244", &options
[20],
1093 "OPTION_245", &options
[21],
1094 "OPTION_246", &options
[22],
1095 "OPTION_247", &options
[23],
1096 "OPTION_248", &options
[24],
1097 "OPTION_249", &options
[25],
1098 "OPTION_250", &options
[26],
1099 "OPTION_251", &options
[27],
1100 "OPTION_252", &options
[28],
1101 "OPTION_253", &options
[29],
1102 "OPTION_254", &options
[30],
1108 r
= inet_pton(AF_INET
, address
, &lease
->address
);
1110 log_debug("Failed to parse address %s, ignoring.", address
);
1114 r
= inet_pton(AF_INET
, router
, &lease
->router
);
1116 log_debug("Failed to parse router %s, ignoring.", router
);
1120 r
= inet_pton(AF_INET
, netmask
, &lease
->subnet_mask
);
1122 log_debug("Failed to parse netmask %s, ignoring.", netmask
);
1124 lease
->have_subnet_mask
= true;
1127 if (server_address
) {
1128 r
= inet_pton(AF_INET
, server_address
, &lease
->server_address
);
1130 log_debug("Failed to parse server address %s, ignoring.", server_address
);
1134 r
= inet_pton(AF_INET
, next_server
, &lease
->next_server
);
1136 log_debug("Failed to parse next server %s, ignoring.", next_server
);
1140 r
= inet_pton(AF_INET
, broadcast
, &lease
->broadcast
);
1142 log_debug("Failed to parse broadcast address %s, ignoring.", broadcast
);
1144 lease
->have_broadcast
= true;
1148 r
= deserialize_in_addrs(&lease
->dns
, dns
);
1150 log_debug_errno(r
, "Failed to deserialize DNS servers %s, ignoring: %m", dns
);
1152 lease
->dns_size
= r
;
1156 r
= deserialize_in_addrs(&lease
->ntp
, ntp
);
1158 log_debug_errno(r
, "Failed to deserialize NTP servers %s, ignoring: %m", ntp
);
1160 lease
->ntp_size
= r
;
1164 r
= safe_atou16(mtu
, &lease
->mtu
);
1166 log_debug_errno(r
, "Failed to parse MTU %s, ignoring: %m", mtu
);
1170 _cleanup_strv_free_
char **a
= NULL
;
1171 a
= strv_split(domains
, " ");
1175 if (!strv_isempty(a
)) {
1176 lease
->search_domains
= a
;
1182 r
= deserialize_dhcp_routes(
1183 &lease
->static_route
,
1184 &lease
->static_route_size
,
1185 &lease
->static_route_allocated
,
1188 log_debug_errno(r
, "Failed to parse DHCP routes %s, ignoring: %m", routes
);
1192 r
= safe_atou32(lifetime
, &lease
->lifetime
);
1194 log_debug_errno(r
, "Failed to parse lifetime %s, ignoring: %m", lifetime
);
1198 r
= safe_atou32(t1
, &lease
->t1
);
1200 log_debug_errno(r
, "Failed to parse T1 %s, ignoring: %m", t1
);
1204 r
= safe_atou32(t2
, &lease
->t2
);
1206 log_debug_errno(r
, "Failed to parse T2 %s, ignoring: %m", t2
);
1209 if (client_id_hex
) {
1210 r
= deserialize_dhcp_option(&lease
->client_id
, &lease
->client_id_len
, client_id_hex
);
1212 log_debug_errno(r
, "Failed to parse client ID %s, ignoring: %m", client_id_hex
);
1215 if (vendor_specific_hex
) {
1216 r
= deserialize_dhcp_option(&lease
->vendor_specific
, &lease
->vendor_specific_len
, vendor_specific_hex
);
1218 log_debug_errno(r
, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex
);
1221 for (i
= 0; i
<= SD_DHCP_OPTION_PRIVATE_LAST
- SD_DHCP_OPTION_PRIVATE_BASE
; i
++) {
1222 _cleanup_free_
void *data
= NULL
;
1228 r
= deserialize_dhcp_option(&data
, &len
, options
[i
]);
1230 log_debug_errno(r
, "Failed to parse private DHCP option %s, ignoring: %m", options
[i
]);
1234 r
= dhcp_lease_insert_private_option(lease
, SD_DHCP_OPTION_PRIVATE_BASE
+ i
, data
, len
);
1245 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease
*lease
) {
1246 struct in_addr address
, mask
;
1251 if (lease
->address
== 0)
1254 address
.s_addr
= lease
->address
;
1256 /* fall back to the default subnet masks based on address class */
1257 r
= in4_addr_default_subnet_mask(&address
, &mask
);
1261 lease
->subnet_mask
= mask
.s_addr
;
1262 lease
->have_subnet_mask
= true;
1267 int sd_dhcp_lease_get_client_id(sd_dhcp_lease
*lease
, const void **client_id
, size_t *client_id_len
) {
1268 assert_return(lease
, -EINVAL
);
1269 assert_return(client_id
, -EINVAL
);
1270 assert_return(client_id_len
, -EINVAL
);
1272 if (!lease
->client_id
)
1275 *client_id
= lease
->client_id
;
1276 *client_id_len
= lease
->client_id_len
;
1281 int dhcp_lease_set_client_id(sd_dhcp_lease
*lease
, const void *client_id
, size_t client_id_len
) {
1282 assert_return(lease
, -EINVAL
);
1283 assert_return(client_id
|| client_id_len
<= 0, -EINVAL
);
1285 if (client_id_len
<= 0)
1286 lease
->client_id
= mfree(lease
->client_id
);
1290 p
= memdup(client_id
, client_id_len
);
1294 free(lease
->client_id
);
1295 lease
->client_id
= p
;
1296 lease
->client_id_len
= client_id_len
;
1302 int sd_dhcp_lease_get_timezone(sd_dhcp_lease
*lease
, const char **tz
) {
1303 assert_return(lease
, -EINVAL
);
1304 assert_return(tz
, -EINVAL
);
1306 if (!lease
->timezone
)
1309 *tz
= lease
->timezone
;
1313 int sd_dhcp_route_get_destination(sd_dhcp_route
*route
, struct in_addr
*destination
) {
1314 assert_return(route
, -EINVAL
);
1315 assert_return(destination
, -EINVAL
);
1317 *destination
= route
->dst_addr
;
1321 int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route
*route
, uint8_t *length
) {
1322 assert_return(route
, -EINVAL
);
1323 assert_return(length
, -EINVAL
);
1325 *length
= route
->dst_prefixlen
;
1329 int sd_dhcp_route_get_gateway(sd_dhcp_route
*route
, struct in_addr
*gateway
) {
1330 assert_return(route
, -EINVAL
);
1331 assert_return(gateway
, -EINVAL
);
1333 *gateway
= route
->gw_addr
;