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 sd_dhcp_lease
*sd_dhcp_lease_ref(sd_dhcp_lease
*lease
) {
184 assert_se(REFCNT_INC(lease
->n_ref
) >= 2);
189 sd_dhcp_lease
*sd_dhcp_lease_unref(sd_dhcp_lease
*lease
) {
190 if (lease
&& REFCNT_DEC(lease
->n_ref
) == 0) {
191 free(lease
->hostname
);
192 free(lease
->domainname
);
195 free(lease
->static_route
);
196 free(lease
->client_id
);
203 static void lease_parse_u32(const uint8_t *option
, size_t len
, uint32_t *ret
, uint32_t min
) {
208 *ret
= unaligned_read_be32((be32_t
*) option
);
215 static void lease_parse_s32(const uint8_t *option
, size_t len
, int32_t *ret
) {
216 lease_parse_u32(option
, len
, (uint32_t *)ret
, 0);
219 static void lease_parse_u16(const uint8_t *option
, size_t len
, uint16_t *ret
, uint16_t min
) {
224 *ret
= unaligned_read_be16((be16_t
*) option
);
231 static void lease_parse_be32(const uint8_t *option
, size_t len
, be32_t
*ret
) {
236 memcpy(ret
, option
, 4);
239 static void lease_parse_bool(const uint8_t *option
, size_t len
, bool *ret
) {
247 static void lease_parse_u8(const uint8_t *option
, size_t len
, uint8_t *ret
, uint8_t min
) {
259 static int lease_parse_string(const uint8_t *option
, size_t len
, char **ret
) {
266 string
= strndup((const char *)option
, len
);
277 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
) {
282 if (len
&& !(len
% (4 * mult
))) {
284 struct in_addr
*addresses
;
288 addresses
= newdup(struct in_addr
, option
, size
);
300 static int lease_parse_in_addrs(const uint8_t *option
, size_t len
, struct in_addr
**ret
, size_t *ret_size
) {
301 return lease_parse_in_addrs_aux(option
, len
, ret
, ret_size
, 1);
304 static int lease_parse_in_addrs_pairs(const uint8_t *option
, size_t len
, struct in_addr
**ret
, size_t *ret_size
) {
305 return lease_parse_in_addrs_aux(option
, len
, ret
, ret_size
, 2);
308 static int lease_parse_routes(const uint8_t *option
, size_t len
, struct sd_dhcp_route
**routes
,
309 size_t *routes_size
, size_t *routes_allocated
) {
316 assert(routes_allocated
);
324 if (!GREEDY_REALLOC(*routes
, *routes_allocated
, *routes_size
+ (len
/ 8)))
328 struct sd_dhcp_route
*route
= *routes
+ *routes_size
;
331 r
= in_addr_default_prefixlen((struct in_addr
*) option
, &route
->dst_prefixlen
);
333 log_error("Failed to determine destination prefix length from class based IP, ignoring");
337 lease_parse_be32(option
, 4, &addr
.s_addr
);
338 route
->dst_addr
= inet_makeaddr(inet_netof(addr
), 0);
341 lease_parse_be32(option
, 4, &route
->gw_addr
.s_addr
);
351 /* parses RFC3442 Classless Static Route Option */
352 static int lease_parse_classless_routes(const uint8_t *option
, size_t len
, struct sd_dhcp_route
**routes
,
353 size_t *routes_size
, size_t *routes_allocated
) {
358 assert(routes_allocated
);
360 /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */
364 struct sd_dhcp_route
*route
;
366 if (!GREEDY_REALLOC(*routes
, *routes_allocated
, *routes_size
+ 1))
369 route
= *routes
+ *routes_size
;
371 dst_octets
= (*option
== 0 ? 0 : ((*option
- 1) / 8) + 1);
372 route
->dst_prefixlen
= *option
;
376 /* can't have more than 4 octets in IPv4 */
377 if (dst_octets
> 4 || len
< dst_octets
)
380 route
->dst_addr
.s_addr
= 0;
381 memcpy(&route
->dst_addr
.s_addr
, option
, dst_octets
);
382 option
+= dst_octets
;
388 lease_parse_be32(option
, 4, &route
->gw_addr
.s_addr
);
398 int dhcp_lease_parse_options(uint8_t code
, uint8_t len
, const uint8_t *option
,
400 sd_dhcp_lease
*lease
= user_data
;
407 case DHCP_OPTION_TIME_OFFSET
:
408 lease_parse_s32(option
, len
, &lease
->time_offset
);
412 case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT
:
413 lease_parse_u32(option
, len
, &lease
->mtu_aging_timeout
, 0);
417 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME
:
418 lease_parse_u32(option
, len
, &lease
->lifetime
, 1);
422 case DHCP_OPTION_SERVER_IDENTIFIER
:
423 lease_parse_be32(option
, len
, &lease
->server_address
);
427 case DHCP_OPTION_SUBNET_MASK
:
428 lease_parse_be32(option
, len
, &lease
->subnet_mask
);
432 case DHCP_OPTION_BROADCAST
:
433 lease_parse_be32(option
, len
, &lease
->broadcast
);
437 case DHCP_OPTION_ROUTER
:
438 lease_parse_be32(option
, len
, &lease
->router
);
442 case DHCP_OPTION_DOMAIN_NAME_SERVER
:
443 r
= lease_parse_in_addrs(option
, len
, &lease
->dns
, &lease
->dns_size
);
449 case DHCP_OPTION_NTP_SERVER
:
450 r
= lease_parse_in_addrs(option
, len
, &lease
->ntp
, &lease
->ntp_size
);
456 case DHCP_OPTION_POLICY_FILTER
:
457 r
= lease_parse_in_addrs_pairs(option
, len
, &lease
->policy_filter
, &lease
->policy_filter_size
);
463 case DHCP_OPTION_STATIC_ROUTE
:
464 r
= lease_parse_routes(option
, len
, &lease
->static_route
, &lease
->static_route_size
,
465 &lease
->static_route_allocated
);
471 case DHCP_OPTION_INTERFACE_MTU
:
472 lease_parse_u16(option
, len
, &lease
->mtu
, 68);
476 case DHCP_OPTION_INTERFACE_MDR
:
477 lease_parse_u16(option
, len
, &lease
->mdr
, 576);
481 case DHCP_OPTION_INTERFACE_TTL
:
482 lease_parse_u8(option
, len
, &lease
->ttl
, 1);
486 case DHCP_OPTION_BOOT_FILE_SIZE
:
487 lease_parse_u16(option
, len
, &lease
->boot_file_size
, 0);
491 case DHCP_OPTION_DOMAIN_NAME
:
493 _cleanup_free_
char *domainname
= NULL
;
496 r
= lease_parse_string(option
, len
, &domainname
);
500 /* Chop off trailing dot of domain name that some DHCP
501 * servers send us back. Internally we want to store
502 * host names without trailing dots and
503 * host_name_is_valid() doesn't accept them. */
504 e
= endswith(domainname
, ".");
508 if (is_localhost(domainname
))
511 r
= dns_name_is_valid(domainname
);
514 log_error_errno(r
, "Failed to validate domain name: %s: %m", domainname
);
516 log_warning("Domain name is not valid, ignoring: %s", domainname
);
520 free(lease
->domainname
);
521 lease
->domainname
= domainname
;
526 case DHCP_OPTION_HOST_NAME
:
528 _cleanup_free_
char *hostname
= NULL
;
531 r
= lease_parse_string(option
, len
, &hostname
);
535 e
= endswith(hostname
, ".");
539 if (!hostname_is_valid(hostname
) || is_localhost(hostname
))
542 free(lease
->hostname
);
543 lease
->hostname
= hostname
;
548 case DHCP_OPTION_ROOT_PATH
:
549 r
= lease_parse_string(option
, len
, &lease
->root_path
);
555 case DHCP_OPTION_RENEWAL_T1_TIME
:
556 lease_parse_u32(option
, len
, &lease
->t1
, 1);
560 case DHCP_OPTION_REBINDING_T2_TIME
:
561 lease_parse_u32(option
, len
, &lease
->t2
, 1);
565 case DHCP_OPTION_ENABLE_IP_FORWARDING
:
566 lease_parse_bool(option
, len
, &lease
->ip_forward
);
570 case DHCP_OPTION_ENABLE_IP_FORWARDING_NL
:
571 lease_parse_bool(option
, len
, &lease
->ip_forward_non_local
);
575 case DHCP_OPTION_CLASSLESS_STATIC_ROUTE
:
576 r
= lease_parse_classless_routes(option
, len
, &lease
->static_route
, &lease
->static_route_size
,
577 &lease
->static_route_allocated
);
587 int dhcp_lease_new(sd_dhcp_lease
**ret
) {
588 sd_dhcp_lease
*lease
;
590 lease
= new0(sd_dhcp_lease
, 1);
594 lease
->router
= INADDR_ANY
;
595 lease
->n_ref
= REFCNT_INIT
;
601 int sd_dhcp_lease_save(sd_dhcp_lease
*lease
, const char *lease_file
) {
602 _cleanup_free_
char *temp_path
= NULL
;
603 _cleanup_fclose_
FILE *f
= NULL
;
604 struct in_addr address
;
605 const struct in_addr
*addresses
;
606 const uint8_t *client_id
;
607 size_t client_id_len
;
610 struct sd_dhcp_route
*routes
;
616 r
= fopen_temporary(lease_file
, &f
, &temp_path
);
620 fchmod(fileno(f
), 0644);
622 r
= sd_dhcp_lease_get_address(lease
, &address
);
627 "# This is private data. Do not parse.\n"
628 "ADDRESS=%s\n", inet_ntoa(address
));
630 r
= sd_dhcp_lease_get_netmask(lease
, &address
);
634 fprintf(f
, "NETMASK=%s\n", inet_ntoa(address
));
636 r
= sd_dhcp_lease_get_router(lease
, &address
);
638 fprintf(f
, "ROUTER=%s\n", inet_ntoa(address
));
640 r
= sd_dhcp_lease_get_server_identifier(lease
, &address
);
642 fprintf(f
, "SERVER_ADDRESS=%s\n",
645 r
= sd_dhcp_lease_get_next_server(lease
, &address
);
647 fprintf(f
, "NEXT_SERVER=%s\n", inet_ntoa(address
));
649 r
= sd_dhcp_lease_get_mtu(lease
, &mtu
);
651 fprintf(f
, "MTU=%" PRIu16
"\n", mtu
);
654 r
= sd_dhcp_lease_get_dns(lease
, &addresses
);
656 serialize_in_addrs(f
, addresses
, r
);
660 r
= sd_dhcp_lease_get_ntp(lease
, &addresses
);
662 serialize_in_addrs(f
, addresses
, r
);
665 r
= sd_dhcp_lease_get_domainname(lease
, &string
);
667 fprintf(f
, "DOMAINNAME=%s\n", string
);
669 r
= sd_dhcp_lease_get_hostname(lease
, &string
);
671 fprintf(f
, "HOSTNAME=%s\n", string
);
673 r
= sd_dhcp_lease_get_root_path(lease
, &string
);
675 fprintf(f
, "ROOT_PATH=%s\n", string
);
677 r
= sd_dhcp_lease_get_routes(lease
, &routes
);
679 serialize_dhcp_routes(f
, "ROUTES", routes
, r
);
681 r
= sd_dhcp_lease_get_client_id(lease
, &client_id
, &client_id_len
);
683 _cleanup_free_
char *client_id_hex
;
685 client_id_hex
= hexmem(client_id
, client_id_len
);
686 if (!client_id_hex
) {
690 fprintf(f
, "CLIENTID=%s\n", client_id_hex
);
697 if (ferror(f
) || rename(temp_path
, lease_file
) < 0) {
705 log_error_errno(r
, "Failed to save lease data %s: %m", lease_file
);
710 int sd_dhcp_lease_load(sd_dhcp_lease
**ret
, const char *lease_file
) {
711 _cleanup_dhcp_lease_unref_ sd_dhcp_lease
*lease
= NULL
;
712 _cleanup_free_
char *address
= NULL
, *router
= NULL
, *netmask
= NULL
,
713 *server_address
= NULL
, *next_server
= NULL
,
714 *dns
= NULL
, *ntp
= NULL
, *mtu
= NULL
,
715 *routes
= NULL
, *client_id_hex
= NULL
;
722 r
= dhcp_lease_new(&lease
);
726 r
= parse_env_file(lease_file
, NEWLINE
,
730 "SERVER_IDENTIFIER", &server_address
,
731 "NEXT_SERVER", &next_server
,
735 "DOMAINNAME", &lease
->domainname
,
736 "HOSTNAME", &lease
->hostname
,
737 "ROOT_PATH", &lease
->root_path
,
739 "CLIENTID", &client_id_hex
,
745 return log_error_errno(r
, "Failed to read %s: %m", lease_file
);
748 r
= inet_pton(AF_INET
, address
, &addr
);
752 lease
->address
= addr
.s_addr
;
755 r
= inet_pton(AF_INET
, router
, &addr
);
759 lease
->router
= addr
.s_addr
;
762 r
= inet_pton(AF_INET
, netmask
, &addr
);
766 lease
->subnet_mask
= addr
.s_addr
;
768 if (server_address
) {
769 r
= inet_pton(AF_INET
, server_address
, &addr
);
773 lease
->server_address
= addr
.s_addr
;
777 r
= inet_pton(AF_INET
, next_server
, &addr
);
781 lease
->next_server
= addr
.s_addr
;
785 r
= deserialize_in_addrs(&lease
->dns
, dns
);
793 r
= deserialize_in_addrs(&lease
->ntp
, ntp
);
802 if (sscanf(mtu
, "%" SCNu16
, &u
) > 0)
807 r
= deserialize_dhcp_routes(&lease
->static_route
, &lease
->static_route_size
,
808 &lease
->static_route_allocated
, routes
);
814 if (strlen (client_id_hex
) % 2)
817 lease
->client_id
= unhexmem (client_id_hex
, strlen (client_id_hex
));
818 if (!lease
->client_id
)
820 lease
->client_id_len
= strlen (client_id_hex
) / 2;
829 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease
*lease
) {
830 struct in_addr address
;
836 address
.s_addr
= lease
->address
;
838 /* fall back to the default subnet masks based on address class */
839 r
= in_addr_default_subnet_mask(&address
, &mask
);
843 lease
->subnet_mask
= mask
.s_addr
;
848 int sd_dhcp_lease_get_client_id(sd_dhcp_lease
*lease
, const uint8_t **client_id
,
849 size_t *client_id_len
) {
850 assert_return(lease
, -EINVAL
);
851 assert_return(client_id
, -EINVAL
);
852 assert_return(client_id_len
, -EINVAL
);
854 *client_id
= lease
->client_id
;
855 *client_id_len
= lease
->client_id_len
;
859 int dhcp_lease_set_client_id(sd_dhcp_lease
*lease
, const uint8_t *client_id
,
860 size_t client_id_len
) {
861 assert_return(lease
, -EINVAL
);
862 assert_return((!client_id
&& !client_id_len
) ||
863 (client_id
&& client_id_len
), -EINVAL
);
865 free (lease
->client_id
);
866 lease
->client_id
= NULL
;
867 lease
->client_id_len
= 0;
870 lease
->client_id
= memdup (client_id
, client_id_len
);
871 lease
->client_id_len
= client_id_len
;