2 This file is part of systemd.
4 Copyright (C) 2013 Intel Corporation. All rights reserved.
5 Copyright (C) 2014 Tom Gundersen
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include <arpa/inet.h>
28 #include "unaligned.h"
29 #include "in-addr-util.h"
30 #include "hostname-util.h"
31 #include "dhcp-protocol.h"
32 #include "dhcp-lease-internal.h"
33 #include "sd-dhcp-lease.h"
34 #include "network-internal.h"
35 #include "dns-domain.h"
37 int sd_dhcp_lease_get_address(sd_dhcp_lease
*lease
, struct in_addr
*addr
) {
38 assert_return(lease
, -EINVAL
);
39 assert_return(addr
, -EINVAL
);
41 addr
->s_addr
= lease
->address
;
46 int sd_dhcp_lease_get_lifetime(sd_dhcp_lease
*lease
, uint32_t *lifetime
) {
47 assert_return(lease
, -EINVAL
);
48 assert_return(lifetime
, -EINVAL
);
50 *lifetime
= lease
->lifetime
;
55 int sd_dhcp_lease_get_mtu(sd_dhcp_lease
*lease
, uint16_t *mtu
) {
56 assert_return(lease
, -EINVAL
);
57 assert_return(mtu
, -EINVAL
);
67 int sd_dhcp_lease_get_dns(sd_dhcp_lease
*lease
, const struct in_addr
**addr
) {
68 assert_return(lease
, -EINVAL
);
69 assert_return(addr
, -EINVAL
);
71 if (lease
->dns_size
) {
73 return lease
->dns_size
;
80 int sd_dhcp_lease_get_ntp(sd_dhcp_lease
*lease
, const struct in_addr
**addr
) {
81 assert_return(lease
, -EINVAL
);
82 assert_return(addr
, -EINVAL
);
84 if (lease
->ntp_size
) {
86 return lease
->ntp_size
;
93 int sd_dhcp_lease_get_domainname(sd_dhcp_lease
*lease
, const char **domainname
) {
94 assert_return(lease
, -EINVAL
);
95 assert_return(domainname
, -EINVAL
);
97 if (lease
->domainname
)
98 *domainname
= lease
->domainname
;
105 int sd_dhcp_lease_get_hostname(sd_dhcp_lease
*lease
, const char **hostname
) {
106 assert_return(lease
, -EINVAL
);
107 assert_return(hostname
, -EINVAL
);
110 *hostname
= lease
->hostname
;
117 int sd_dhcp_lease_get_root_path(sd_dhcp_lease
*lease
, const char **root_path
) {
118 assert_return(lease
, -EINVAL
);
119 assert_return(root_path
, -EINVAL
);
121 if (lease
->root_path
)
122 *root_path
= lease
->root_path
;
129 int sd_dhcp_lease_get_router(sd_dhcp_lease
*lease
, struct in_addr
*addr
) {
130 assert_return(lease
, -EINVAL
);
131 assert_return(addr
, -EINVAL
);
133 if (lease
->router
!= INADDR_ANY
)
134 addr
->s_addr
= lease
->router
;
141 int sd_dhcp_lease_get_netmask(sd_dhcp_lease
*lease
, struct in_addr
*addr
) {
142 assert_return(lease
, -EINVAL
);
143 assert_return(addr
, -EINVAL
);
145 addr
->s_addr
= lease
->subnet_mask
;
150 int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease
*lease
, struct in_addr
*addr
) {
151 assert_return(lease
, -EINVAL
);
152 assert_return(addr
, -EINVAL
);
154 addr
->s_addr
= lease
->server_address
;
159 int sd_dhcp_lease_get_next_server(sd_dhcp_lease
*lease
, struct in_addr
*addr
) {
160 assert_return(lease
, -EINVAL
);
161 assert_return(addr
, -EINVAL
);
163 addr
->s_addr
= lease
->next_server
;
168 int sd_dhcp_lease_get_routes(sd_dhcp_lease
*lease
, struct sd_dhcp_route
**routes
) {
170 assert_return(lease
, -EINVAL
);
171 assert_return(routes
, -EINVAL
);
173 if (lease
->static_route_size
) {
174 *routes
= lease
->static_route
;
175 return lease
->static_route_size
;
182 int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease
*lease
, const uint8_t **data
,
184 assert_return(lease
, -EINVAL
);
185 assert_return(data
, -EINVAL
);
186 assert_return(data_len
, -EINVAL
);
188 if (!lease
->vendor_specific
)
191 *data
= lease
->vendor_specific
;
192 *data_len
= lease
->vendor_specific_len
;
197 sd_dhcp_lease
*sd_dhcp_lease_ref(sd_dhcp_lease
*lease
) {
199 assert_se(REFCNT_INC(lease
->n_ref
) >= 2);
204 sd_dhcp_lease
*sd_dhcp_lease_unref(sd_dhcp_lease
*lease
) {
205 if (lease
&& REFCNT_DEC(lease
->n_ref
) == 0) {
206 free(lease
->hostname
);
207 free(lease
->domainname
);
210 free(lease
->static_route
);
211 free(lease
->client_id
);
212 free(lease
->vendor_specific
);
219 static void lease_parse_u32(const uint8_t *option
, size_t len
, uint32_t *ret
, uint32_t min
) {
224 *ret
= unaligned_read_be32((be32_t
*) option
);
231 static void lease_parse_s32(const uint8_t *option
, size_t len
, int32_t *ret
) {
232 lease_parse_u32(option
, len
, (uint32_t *)ret
, 0);
235 static void lease_parse_u16(const uint8_t *option
, size_t len
, uint16_t *ret
, uint16_t min
) {
240 *ret
= unaligned_read_be16((be16_t
*) option
);
247 static void lease_parse_be32(const uint8_t *option
, size_t len
, be32_t
*ret
) {
252 memcpy(ret
, option
, 4);
255 static void lease_parse_bool(const uint8_t *option
, size_t len
, bool *ret
) {
263 static void lease_parse_u8(const uint8_t *option
, size_t len
, uint8_t *ret
, uint8_t min
) {
275 static int lease_parse_string(const uint8_t *option
, size_t len
, char **ret
) {
282 string
= strndup((const char *)option
, len
);
293 static int lease_parse_in_addrs_aux(const uint8_t *option
, size_t len
, struct in_addr
**ret
, size_t *ret_size
, size_t mult
) {
298 if (len
&& !(len
% (4 * mult
))) {
300 struct in_addr
*addresses
;
304 addresses
= newdup(struct in_addr
, option
, size
);
316 static int lease_parse_in_addrs(const uint8_t *option
, size_t len
, struct in_addr
**ret
, size_t *ret_size
) {
317 return lease_parse_in_addrs_aux(option
, len
, ret
, ret_size
, 1);
320 static int lease_parse_in_addrs_pairs(const uint8_t *option
, size_t len
, struct in_addr
**ret
, size_t *ret_size
) {
321 return lease_parse_in_addrs_aux(option
, len
, ret
, ret_size
, 2);
324 static int lease_parse_routes(const uint8_t *option
, size_t len
, struct sd_dhcp_route
**routes
,
325 size_t *routes_size
, size_t *routes_allocated
) {
332 assert(routes_allocated
);
340 if (!GREEDY_REALLOC(*routes
, *routes_allocated
, *routes_size
+ (len
/ 8)))
344 struct sd_dhcp_route
*route
= *routes
+ *routes_size
;
347 r
= in_addr_default_prefixlen((struct in_addr
*) option
, &route
->dst_prefixlen
);
349 log_error("Failed to determine destination prefix length from class based IP, ignoring");
353 lease_parse_be32(option
, 4, &addr
.s_addr
);
354 route
->dst_addr
= inet_makeaddr(inet_netof(addr
), 0);
357 lease_parse_be32(option
, 4, &route
->gw_addr
.s_addr
);
367 /* parses RFC3442 Classless Static Route Option */
368 static int lease_parse_classless_routes(const uint8_t *option
, size_t len
, struct sd_dhcp_route
**routes
,
369 size_t *routes_size
, size_t *routes_allocated
) {
374 assert(routes_allocated
);
376 /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */
380 struct sd_dhcp_route
*route
;
382 if (!GREEDY_REALLOC(*routes
, *routes_allocated
, *routes_size
+ 1))
385 route
= *routes
+ *routes_size
;
387 dst_octets
= (*option
== 0 ? 0 : ((*option
- 1) / 8) + 1);
388 route
->dst_prefixlen
= *option
;
392 /* can't have more than 4 octets in IPv4 */
393 if (dst_octets
> 4 || len
< dst_octets
)
396 route
->dst_addr
.s_addr
= 0;
397 memcpy(&route
->dst_addr
.s_addr
, option
, dst_octets
);
398 option
+= dst_octets
;
404 lease_parse_be32(option
, 4, &route
->gw_addr
.s_addr
);
414 int dhcp_lease_parse_options(uint8_t code
, uint8_t len
, const uint8_t *option
,
416 sd_dhcp_lease
*lease
= user_data
;
423 case DHCP_OPTION_TIME_OFFSET
:
424 lease_parse_s32(option
, len
, &lease
->time_offset
);
428 case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT
:
429 lease_parse_u32(option
, len
, &lease
->mtu_aging_timeout
, 0);
433 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME
:
434 lease_parse_u32(option
, len
, &lease
->lifetime
, 1);
438 case DHCP_OPTION_SERVER_IDENTIFIER
:
439 lease_parse_be32(option
, len
, &lease
->server_address
);
443 case DHCP_OPTION_SUBNET_MASK
:
444 lease_parse_be32(option
, len
, &lease
->subnet_mask
);
448 case DHCP_OPTION_BROADCAST
:
449 lease_parse_be32(option
, len
, &lease
->broadcast
);
453 case DHCP_OPTION_ROUTER
:
455 lease_parse_be32(option
, 4, &lease
->router
);
459 case DHCP_OPTION_DOMAIN_NAME_SERVER
:
460 r
= lease_parse_in_addrs(option
, len
, &lease
->dns
, &lease
->dns_size
);
466 case DHCP_OPTION_NTP_SERVER
:
467 r
= lease_parse_in_addrs(option
, len
, &lease
->ntp
, &lease
->ntp_size
);
473 case DHCP_OPTION_POLICY_FILTER
:
474 r
= lease_parse_in_addrs_pairs(option
, len
, &lease
->policy_filter
, &lease
->policy_filter_size
);
480 case DHCP_OPTION_STATIC_ROUTE
:
481 r
= lease_parse_routes(option
, len
, &lease
->static_route
, &lease
->static_route_size
,
482 &lease
->static_route_allocated
);
488 case DHCP_OPTION_INTERFACE_MTU
:
489 lease_parse_u16(option
, len
, &lease
->mtu
, 68);
493 case DHCP_OPTION_INTERFACE_MDR
:
494 lease_parse_u16(option
, len
, &lease
->mdr
, 576);
498 case DHCP_OPTION_INTERFACE_TTL
:
499 lease_parse_u8(option
, len
, &lease
->ttl
, 1);
503 case DHCP_OPTION_BOOT_FILE_SIZE
:
504 lease_parse_u16(option
, len
, &lease
->boot_file_size
, 0);
508 case DHCP_OPTION_DOMAIN_NAME
:
510 _cleanup_free_
char *domainname
= NULL
;
513 r
= lease_parse_string(option
, len
, &domainname
);
517 /* Chop off trailing dot of domain name that some DHCP
518 * servers send us back. Internally we want to store
519 * host names without trailing dots and
520 * host_name_is_valid() doesn't accept them. */
521 e
= endswith(domainname
, ".");
525 if (is_localhost(domainname
))
528 r
= dns_name_is_valid(domainname
);
531 log_error_errno(r
, "Failed to validate domain name: %s: %m", domainname
);
533 log_warning("Domain name is not valid, ignoring: %s", domainname
);
537 free(lease
->domainname
);
538 lease
->domainname
= domainname
;
543 case DHCP_OPTION_HOST_NAME
:
545 _cleanup_free_
char *hostname
= NULL
;
548 r
= lease_parse_string(option
, len
, &hostname
);
552 e
= endswith(hostname
, ".");
556 if (!hostname_is_valid(hostname
) || is_localhost(hostname
))
559 free(lease
->hostname
);
560 lease
->hostname
= hostname
;
565 case DHCP_OPTION_ROOT_PATH
:
566 r
= lease_parse_string(option
, len
, &lease
->root_path
);
572 case DHCP_OPTION_RENEWAL_T1_TIME
:
573 lease_parse_u32(option
, len
, &lease
->t1
, 1);
577 case DHCP_OPTION_REBINDING_T2_TIME
:
578 lease_parse_u32(option
, len
, &lease
->t2
, 1);
582 case DHCP_OPTION_ENABLE_IP_FORWARDING
:
583 lease_parse_bool(option
, len
, &lease
->ip_forward
);
587 case DHCP_OPTION_ENABLE_IP_FORWARDING_NL
:
588 lease_parse_bool(option
, len
, &lease
->ip_forward_non_local
);
592 case DHCP_OPTION_CLASSLESS_STATIC_ROUTE
:
593 r
= lease_parse_classless_routes(option
, len
, &lease
->static_route
, &lease
->static_route_size
,
594 &lease
->static_route_allocated
);
600 case DHCP_OPTION_VENDOR_SPECIFIC
:
602 free(lease
->vendor_specific
);
603 lease
->vendor_specific
= memdup(option
, len
);
604 if (!lease
->vendor_specific
)
606 lease
->vendor_specific_len
= len
;
615 int dhcp_lease_new(sd_dhcp_lease
**ret
) {
616 sd_dhcp_lease
*lease
;
618 lease
= new0(sd_dhcp_lease
, 1);
622 lease
->router
= INADDR_ANY
;
623 lease
->n_ref
= REFCNT_INIT
;
629 int sd_dhcp_lease_save(sd_dhcp_lease
*lease
, const char *lease_file
) {
630 _cleanup_free_
char *temp_path
= NULL
;
631 _cleanup_fclose_
FILE *f
= NULL
;
632 struct in_addr address
;
633 const struct in_addr
*addresses
;
634 const uint8_t *client_id
, *data
;
635 size_t client_id_len
, data_len
;
638 struct sd_dhcp_route
*routes
;
644 r
= fopen_temporary(lease_file
, &f
, &temp_path
);
648 fchmod(fileno(f
), 0644);
650 r
= sd_dhcp_lease_get_address(lease
, &address
);
655 "# This is private data. Do not parse.\n"
656 "ADDRESS=%s\n", inet_ntoa(address
));
658 r
= sd_dhcp_lease_get_netmask(lease
, &address
);
662 fprintf(f
, "NETMASK=%s\n", inet_ntoa(address
));
664 r
= sd_dhcp_lease_get_router(lease
, &address
);
666 fprintf(f
, "ROUTER=%s\n", inet_ntoa(address
));
668 r
= sd_dhcp_lease_get_server_identifier(lease
, &address
);
670 fprintf(f
, "SERVER_ADDRESS=%s\n",
673 r
= sd_dhcp_lease_get_next_server(lease
, &address
);
675 fprintf(f
, "NEXT_SERVER=%s\n", inet_ntoa(address
));
677 r
= sd_dhcp_lease_get_mtu(lease
, &mtu
);
679 fprintf(f
, "MTU=%" PRIu16
"\n", mtu
);
682 r
= sd_dhcp_lease_get_dns(lease
, &addresses
);
684 serialize_in_addrs(f
, addresses
, r
);
688 r
= sd_dhcp_lease_get_ntp(lease
, &addresses
);
690 serialize_in_addrs(f
, addresses
, r
);
693 r
= sd_dhcp_lease_get_domainname(lease
, &string
);
695 fprintf(f
, "DOMAINNAME=%s\n", string
);
697 r
= sd_dhcp_lease_get_hostname(lease
, &string
);
699 fprintf(f
, "HOSTNAME=%s\n", string
);
701 r
= sd_dhcp_lease_get_root_path(lease
, &string
);
703 fprintf(f
, "ROOT_PATH=%s\n", string
);
705 r
= sd_dhcp_lease_get_routes(lease
, &routes
);
707 serialize_dhcp_routes(f
, "ROUTES", routes
, r
);
709 r
= sd_dhcp_lease_get_client_id(lease
, &client_id
, &client_id_len
);
711 _cleanup_free_
char *client_id_hex
;
713 client_id_hex
= hexmem(client_id
, client_id_len
);
714 if (!client_id_hex
) {
718 fprintf(f
, "CLIENTID=%s\n", client_id_hex
);
721 r
= sd_dhcp_lease_get_vendor_specific(lease
, &data
, &data_len
);
723 _cleanup_free_
char *option_hex
= NULL
;
725 option_hex
= hexmem(data
, data_len
);
730 fprintf(f
, "VENDOR_SPECIFIC=%s\n", option_hex
);
737 if (ferror(f
) || rename(temp_path
, lease_file
) < 0) {
745 log_error_errno(r
, "Failed to save lease data %s: %m", lease_file
);
750 int sd_dhcp_lease_load(sd_dhcp_lease
**ret
, const char *lease_file
) {
751 _cleanup_dhcp_lease_unref_ sd_dhcp_lease
*lease
= NULL
;
752 _cleanup_free_
char *address
= NULL
, *router
= NULL
, *netmask
= NULL
,
753 *server_address
= NULL
, *next_server
= NULL
,
754 *dns
= NULL
, *ntp
= NULL
, *mtu
= NULL
,
755 *routes
= NULL
, *client_id_hex
= NULL
,
756 *vendor_specific_hex
= NULL
;
763 r
= dhcp_lease_new(&lease
);
767 r
= parse_env_file(lease_file
, NEWLINE
,
771 "SERVER_IDENTIFIER", &server_address
,
772 "NEXT_SERVER", &next_server
,
776 "DOMAINNAME", &lease
->domainname
,
777 "HOSTNAME", &lease
->hostname
,
778 "ROOT_PATH", &lease
->root_path
,
780 "CLIENTID", &client_id_hex
,
781 "VENDOR_SPECIFIC", &vendor_specific_hex
,
787 return log_error_errno(r
, "Failed to read %s: %m", lease_file
);
790 r
= inet_pton(AF_INET
, address
, &addr
);
794 lease
->address
= addr
.s_addr
;
797 r
= inet_pton(AF_INET
, router
, &addr
);
801 lease
->router
= addr
.s_addr
;
804 r
= inet_pton(AF_INET
, netmask
, &addr
);
808 lease
->subnet_mask
= addr
.s_addr
;
810 if (server_address
) {
811 r
= inet_pton(AF_INET
, server_address
, &addr
);
815 lease
->server_address
= addr
.s_addr
;
819 r
= inet_pton(AF_INET
, next_server
, &addr
);
823 lease
->next_server
= addr
.s_addr
;
827 r
= deserialize_in_addrs(&lease
->dns
, dns
);
835 r
= deserialize_in_addrs(&lease
->ntp
, ntp
);
844 if (sscanf(mtu
, "%" SCNu16
, &u
) > 0)
849 r
= deserialize_dhcp_routes(&lease
->static_route
, &lease
->static_route_size
,
850 &lease
->static_route_allocated
, routes
);
856 if (strlen(client_id_hex
) % 2)
859 r
= unhexmem(client_id_hex
, strlen(client_id_hex
), (void**) &lease
->client_id
, &lease
->client_id_len
);
864 if (vendor_specific_hex
) {
865 if (strlen(vendor_specific_hex
) % 2)
868 r
= unhexmem(vendor_specific_hex
, strlen(vendor_specific_hex
), (void**) &lease
->vendor_specific
, &lease
->vendor_specific_len
);
879 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease
*lease
) {
880 struct in_addr address
;
886 address
.s_addr
= lease
->address
;
888 /* fall back to the default subnet masks based on address class */
889 r
= in_addr_default_subnet_mask(&address
, &mask
);
893 lease
->subnet_mask
= mask
.s_addr
;
898 int sd_dhcp_lease_get_client_id(sd_dhcp_lease
*lease
, const uint8_t **client_id
,
899 size_t *client_id_len
) {
900 assert_return(lease
, -EINVAL
);
901 assert_return(client_id
, -EINVAL
);
902 assert_return(client_id_len
, -EINVAL
);
904 *client_id
= lease
->client_id
;
905 *client_id_len
= lease
->client_id_len
;
909 int dhcp_lease_set_client_id(sd_dhcp_lease
*lease
, const uint8_t *client_id
,
910 size_t client_id_len
) {
911 assert_return(lease
, -EINVAL
);
912 assert_return((!client_id
&& !client_id_len
) ||
913 (client_id
&& client_id_len
), -EINVAL
);
915 free (lease
->client_id
);
916 lease
->client_id
= NULL
;
917 lease
->client_id_len
= 0;
920 lease
->client_id
= memdup (client_id
, client_id_len
);
921 lease
->client_id_len
= client_id_len
;