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"
36 int sd_dhcp_lease_get_address(sd_dhcp_lease
*lease
, struct in_addr
*addr
) {
37 assert_return(lease
, -EINVAL
);
38 assert_return(addr
, -EINVAL
);
40 addr
->s_addr
= lease
->address
;
45 int sd_dhcp_lease_get_lifetime(sd_dhcp_lease
*lease
, uint32_t *lifetime
) {
46 assert_return(lease
, -EINVAL
);
47 assert_return(lifetime
, -EINVAL
);
49 *lifetime
= lease
->lifetime
;
54 int sd_dhcp_lease_get_mtu(sd_dhcp_lease
*lease
, uint16_t *mtu
) {
55 assert_return(lease
, -EINVAL
);
56 assert_return(mtu
, -EINVAL
);
66 int sd_dhcp_lease_get_dns(sd_dhcp_lease
*lease
, const struct in_addr
**addr
) {
67 assert_return(lease
, -EINVAL
);
68 assert_return(addr
, -EINVAL
);
70 if (lease
->dns_size
) {
72 return lease
->dns_size
;
79 int sd_dhcp_lease_get_ntp(sd_dhcp_lease
*lease
, const struct in_addr
**addr
) {
80 assert_return(lease
, -EINVAL
);
81 assert_return(addr
, -EINVAL
);
83 if (lease
->ntp_size
) {
85 return lease
->ntp_size
;
92 int sd_dhcp_lease_get_domainname(sd_dhcp_lease
*lease
, const char **domainname
) {
93 assert_return(lease
, -EINVAL
);
94 assert_return(domainname
, -EINVAL
);
96 if (lease
->domainname
)
97 *domainname
= lease
->domainname
;
104 int sd_dhcp_lease_get_hostname(sd_dhcp_lease
*lease
, const char **hostname
) {
105 assert_return(lease
, -EINVAL
);
106 assert_return(hostname
, -EINVAL
);
109 *hostname
= lease
->hostname
;
116 int sd_dhcp_lease_get_root_path(sd_dhcp_lease
*lease
, const char **root_path
) {
117 assert_return(lease
, -EINVAL
);
118 assert_return(root_path
, -EINVAL
);
120 if (lease
->root_path
)
121 *root_path
= lease
->root_path
;
128 int sd_dhcp_lease_get_router(sd_dhcp_lease
*lease
, struct in_addr
*addr
) {
129 assert_return(lease
, -EINVAL
);
130 assert_return(addr
, -EINVAL
);
132 if (lease
->router
!= INADDR_ANY
)
133 addr
->s_addr
= lease
->router
;
140 int sd_dhcp_lease_get_netmask(sd_dhcp_lease
*lease
, struct in_addr
*addr
) {
141 assert_return(lease
, -EINVAL
);
142 assert_return(addr
, -EINVAL
);
144 addr
->s_addr
= lease
->subnet_mask
;
149 int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease
*lease
, struct in_addr
*addr
) {
150 assert_return(lease
, -EINVAL
);
151 assert_return(addr
, -EINVAL
);
153 addr
->s_addr
= lease
->server_address
;
158 int sd_dhcp_lease_get_next_server(sd_dhcp_lease
*lease
, struct in_addr
*addr
) {
159 assert_return(lease
, -EINVAL
);
160 assert_return(addr
, -EINVAL
);
162 addr
->s_addr
= lease
->next_server
;
167 int sd_dhcp_lease_get_routes(sd_dhcp_lease
*lease
, struct sd_dhcp_route
**routes
) {
169 assert_return(lease
, -EINVAL
);
170 assert_return(routes
, -EINVAL
);
172 if (lease
->static_route_size
) {
173 *routes
= lease
->static_route
;
174 return lease
->static_route_size
;
181 sd_dhcp_lease
*sd_dhcp_lease_ref(sd_dhcp_lease
*lease
) {
183 assert_se(REFCNT_INC(lease
->n_ref
) >= 2);
188 sd_dhcp_lease
*sd_dhcp_lease_unref(sd_dhcp_lease
*lease
) {
189 if (lease
&& REFCNT_DEC(lease
->n_ref
) == 0) {
190 free(lease
->hostname
);
191 free(lease
->domainname
);
194 free(lease
->static_route
);
195 free(lease
->client_id
);
202 static void lease_parse_u32(const uint8_t *option
, size_t len
, uint32_t *ret
, uint32_t min
) {
207 *ret
= unaligned_read_be32((be32_t
*) option
);
214 static void lease_parse_s32(const uint8_t *option
, size_t len
, int32_t *ret
) {
215 lease_parse_u32(option
, len
, (uint32_t *)ret
, 0);
218 static void lease_parse_u16(const uint8_t *option
, size_t len
, uint16_t *ret
, uint16_t min
) {
223 *ret
= unaligned_read_be16((be16_t
*) option
);
230 static void lease_parse_be32(const uint8_t *option
, size_t len
, be32_t
*ret
) {
235 memcpy(ret
, option
, 4);
238 static void lease_parse_bool(const uint8_t *option
, size_t len
, bool *ret
) {
246 static void lease_parse_u8(const uint8_t *option
, size_t len
, uint8_t *ret
, uint8_t min
) {
258 static int lease_parse_string(const uint8_t *option
, size_t len
, char **ret
) {
265 string
= strndup((const char *)option
, len
);
276 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
) {
281 if (len
&& !(len
% (4 * mult
))) {
283 struct in_addr
*addresses
;
287 addresses
= newdup(struct in_addr
, option
, size
);
299 static int lease_parse_in_addrs(const uint8_t *option
, size_t len
, struct in_addr
**ret
, size_t *ret_size
) {
300 return lease_parse_in_addrs_aux(option
, len
, ret
, ret_size
, 1);
303 static int lease_parse_in_addrs_pairs(const uint8_t *option
, size_t len
, struct in_addr
**ret
, size_t *ret_size
) {
304 return lease_parse_in_addrs_aux(option
, len
, ret
, ret_size
, 2);
307 static int lease_parse_routes(const uint8_t *option
, size_t len
, struct sd_dhcp_route
**routes
,
308 size_t *routes_size
, size_t *routes_allocated
) {
315 assert(routes_allocated
);
323 if (!GREEDY_REALLOC(*routes
, *routes_allocated
, *routes_size
+ (len
/ 8)))
327 struct sd_dhcp_route
*route
= *routes
+ *routes_size
;
330 r
= in_addr_default_prefixlen((struct in_addr
*) option
, &route
->dst_prefixlen
);
332 log_error("Failed to determine destination prefix length from class based IP, ignoring");
336 lease_parse_be32(option
, 4, &addr
.s_addr
);
337 route
->dst_addr
= inet_makeaddr(inet_netof(addr
), 0);
340 lease_parse_be32(option
, 4, &route
->gw_addr
.s_addr
);
350 /* parses RFC3442 Classless Static Route Option */
351 static int lease_parse_classless_routes(const uint8_t *option
, size_t len
, struct sd_dhcp_route
**routes
,
352 size_t *routes_size
, size_t *routes_allocated
) {
357 assert(routes_allocated
);
359 /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */
363 struct sd_dhcp_route
*route
;
365 if (!GREEDY_REALLOC(*routes
, *routes_allocated
, *routes_size
+ 1))
368 route
= *routes
+ *routes_size
;
370 dst_octets
= (*option
== 0 ? 0 : ((*option
- 1) / 8) + 1);
371 route
->dst_prefixlen
= *option
;
375 /* can't have more than 4 octets in IPv4 */
376 if (dst_octets
> 4 || len
< dst_octets
)
379 route
->dst_addr
.s_addr
= 0;
380 memcpy(&route
->dst_addr
.s_addr
, option
, dst_octets
);
381 option
+= dst_octets
;
387 lease_parse_be32(option
, 4, &route
->gw_addr
.s_addr
);
397 int dhcp_lease_parse_options(uint8_t code
, uint8_t len
, const uint8_t *option
,
399 sd_dhcp_lease
*lease
= user_data
;
406 case DHCP_OPTION_TIME_OFFSET
:
407 lease_parse_s32(option
, len
, &lease
->time_offset
);
411 case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT
:
412 lease_parse_u32(option
, len
, &lease
->mtu_aging_timeout
, 0);
416 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME
:
417 lease_parse_u32(option
, len
, &lease
->lifetime
, 1);
421 case DHCP_OPTION_SERVER_IDENTIFIER
:
422 lease_parse_be32(option
, len
, &lease
->server_address
);
426 case DHCP_OPTION_SUBNET_MASK
:
427 lease_parse_be32(option
, len
, &lease
->subnet_mask
);
431 case DHCP_OPTION_BROADCAST
:
432 lease_parse_be32(option
, len
, &lease
->broadcast
);
436 case DHCP_OPTION_ROUTER
:
437 lease_parse_be32(option
, len
, &lease
->router
);
441 case DHCP_OPTION_DOMAIN_NAME_SERVER
:
442 r
= lease_parse_in_addrs(option
, len
, &lease
->dns
, &lease
->dns_size
);
448 case DHCP_OPTION_NTP_SERVER
:
449 r
= lease_parse_in_addrs(option
, len
, &lease
->ntp
, &lease
->ntp_size
);
455 case DHCP_OPTION_POLICY_FILTER
:
456 r
= lease_parse_in_addrs_pairs(option
, len
, &lease
->policy_filter
, &lease
->policy_filter_size
);
462 case DHCP_OPTION_STATIC_ROUTE
:
463 r
= lease_parse_routes(option
, len
, &lease
->static_route
, &lease
->static_route_size
,
464 &lease
->static_route_allocated
);
470 case DHCP_OPTION_INTERFACE_MTU
:
471 lease_parse_u16(option
, len
, &lease
->mtu
, 68);
475 case DHCP_OPTION_INTERFACE_MDR
:
476 lease_parse_u16(option
, len
, &lease
->mdr
, 576);
480 case DHCP_OPTION_INTERFACE_TTL
:
481 lease_parse_u8(option
, len
, &lease
->ttl
, 1);
485 case DHCP_OPTION_BOOT_FILE_SIZE
:
486 lease_parse_u16(option
, len
, &lease
->boot_file_size
, 0);
490 case DHCP_OPTION_DOMAIN_NAME
:
492 _cleanup_free_
char *domainname
= NULL
;
495 r
= lease_parse_string(option
, len
, &domainname
);
499 /* Chop off trailing dot of domain name that some DHCP
500 * servers send us back. Internally we want to store
501 * host names without trailing dots and
502 * host_name_is_valid() doesn't accept them. */
503 e
= endswith(domainname
, ".");
507 if (!hostname_is_valid(domainname
) || is_localhost(domainname
))
510 free(lease
->domainname
);
511 lease
->domainname
= domainname
;
516 case DHCP_OPTION_HOST_NAME
:
518 _cleanup_free_
char *hostname
= NULL
;
521 r
= lease_parse_string(option
, len
, &hostname
);
525 e
= endswith(hostname
, ".");
529 if (!hostname_is_valid(hostname
) || is_localhost(hostname
))
532 free(lease
->hostname
);
533 lease
->hostname
= hostname
;
538 case DHCP_OPTION_ROOT_PATH
:
539 r
= lease_parse_string(option
, len
, &lease
->root_path
);
545 case DHCP_OPTION_RENEWAL_T1_TIME
:
546 lease_parse_u32(option
, len
, &lease
->t1
, 1);
550 case DHCP_OPTION_REBINDING_T2_TIME
:
551 lease_parse_u32(option
, len
, &lease
->t2
, 1);
555 case DHCP_OPTION_ENABLE_IP_FORWARDING
:
556 lease_parse_bool(option
, len
, &lease
->ip_forward
);
560 case DHCP_OPTION_ENABLE_IP_FORWARDING_NL
:
561 lease_parse_bool(option
, len
, &lease
->ip_forward_non_local
);
565 case DHCP_OPTION_CLASSLESS_STATIC_ROUTE
:
566 r
= lease_parse_classless_routes(option
, len
, &lease
->static_route
, &lease
->static_route_size
,
567 &lease
->static_route_allocated
);
577 int dhcp_lease_new(sd_dhcp_lease
**ret
) {
578 sd_dhcp_lease
*lease
;
580 lease
= new0(sd_dhcp_lease
, 1);
584 lease
->router
= INADDR_ANY
;
585 lease
->n_ref
= REFCNT_INIT
;
591 int sd_dhcp_lease_save(sd_dhcp_lease
*lease
, const char *lease_file
) {
592 _cleanup_free_
char *temp_path
= NULL
;
593 _cleanup_fclose_
FILE *f
= NULL
;
594 struct in_addr address
;
595 const struct in_addr
*addresses
;
596 const uint8_t *client_id
;
597 size_t client_id_len
;
600 struct sd_dhcp_route
*routes
;
606 r
= fopen_temporary(lease_file
, &f
, &temp_path
);
610 fchmod(fileno(f
), 0644);
612 r
= sd_dhcp_lease_get_address(lease
, &address
);
617 "# This is private data. Do not parse.\n"
618 "ADDRESS=%s\n", inet_ntoa(address
));
620 r
= sd_dhcp_lease_get_netmask(lease
, &address
);
624 fprintf(f
, "NETMASK=%s\n", inet_ntoa(address
));
626 r
= sd_dhcp_lease_get_router(lease
, &address
);
628 fprintf(f
, "ROUTER=%s\n", inet_ntoa(address
));
630 r
= sd_dhcp_lease_get_server_identifier(lease
, &address
);
632 fprintf(f
, "SERVER_ADDRESS=%s\n",
635 r
= sd_dhcp_lease_get_next_server(lease
, &address
);
637 fprintf(f
, "NEXT_SERVER=%s\n", inet_ntoa(address
));
639 r
= sd_dhcp_lease_get_mtu(lease
, &mtu
);
641 fprintf(f
, "MTU=%" PRIu16
"\n", mtu
);
644 r
= sd_dhcp_lease_get_dns(lease
, &addresses
);
646 serialize_in_addrs(f
, addresses
, r
);
650 r
= sd_dhcp_lease_get_ntp(lease
, &addresses
);
652 serialize_in_addrs(f
, addresses
, r
);
655 r
= sd_dhcp_lease_get_domainname(lease
, &string
);
657 fprintf(f
, "DOMAINNAME=%s\n", string
);
659 r
= sd_dhcp_lease_get_hostname(lease
, &string
);
661 fprintf(f
, "HOSTNAME=%s\n", string
);
663 r
= sd_dhcp_lease_get_root_path(lease
, &string
);
665 fprintf(f
, "ROOT_PATH=%s\n", string
);
667 r
= sd_dhcp_lease_get_routes(lease
, &routes
);
669 serialize_dhcp_routes(f
, "ROUTES", routes
, r
);
671 r
= sd_dhcp_lease_get_client_id(lease
, &client_id
, &client_id_len
);
673 _cleanup_free_
char *client_id_hex
;
675 client_id_hex
= hexmem(client_id
, client_id_len
);
676 if (!client_id_hex
) {
680 fprintf(f
, "CLIENTID=%s\n", client_id_hex
);
687 if (ferror(f
) || rename(temp_path
, lease_file
) < 0) {
695 log_error_errno(r
, "Failed to save lease data %s: %m", lease_file
);
700 int sd_dhcp_lease_load(sd_dhcp_lease
**ret
, const char *lease_file
) {
701 _cleanup_dhcp_lease_unref_ sd_dhcp_lease
*lease
= NULL
;
702 _cleanup_free_
char *address
= NULL
, *router
= NULL
, *netmask
= NULL
,
703 *server_address
= NULL
, *next_server
= NULL
,
704 *dns
= NULL
, *ntp
= NULL
, *mtu
= NULL
,
705 *routes
= NULL
, *client_id_hex
= NULL
;
712 r
= dhcp_lease_new(&lease
);
716 r
= parse_env_file(lease_file
, NEWLINE
,
720 "SERVER_IDENTIFIER", &server_address
,
721 "NEXT_SERVER", &next_server
,
725 "DOMAINNAME", &lease
->domainname
,
726 "HOSTNAME", &lease
->hostname
,
727 "ROOT_PATH", &lease
->root_path
,
729 "CLIENTID", &client_id_hex
,
735 return log_error_errno(r
, "Failed to read %s: %m", lease_file
);
738 r
= inet_pton(AF_INET
, address
, &addr
);
742 lease
->address
= addr
.s_addr
;
745 r
= inet_pton(AF_INET
, router
, &addr
);
749 lease
->router
= addr
.s_addr
;
752 r
= inet_pton(AF_INET
, netmask
, &addr
);
756 lease
->subnet_mask
= addr
.s_addr
;
758 if (server_address
) {
759 r
= inet_pton(AF_INET
, server_address
, &addr
);
763 lease
->server_address
= addr
.s_addr
;
767 r
= inet_pton(AF_INET
, next_server
, &addr
);
771 lease
->next_server
= addr
.s_addr
;
775 r
= deserialize_in_addrs(&lease
->dns
, dns
);
783 r
= deserialize_in_addrs(&lease
->ntp
, ntp
);
792 if (sscanf(mtu
, "%" SCNu16
, &u
) > 0)
797 r
= deserialize_dhcp_routes(&lease
->static_route
, &lease
->static_route_size
,
798 &lease
->static_route_allocated
, routes
);
804 if (strlen (client_id_hex
) % 2)
807 lease
->client_id
= unhexmem (client_id_hex
, strlen (client_id_hex
));
808 if (!lease
->client_id
)
810 lease
->client_id_len
= strlen (client_id_hex
) / 2;
819 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease
*lease
) {
820 struct in_addr address
;
826 address
.s_addr
= lease
->address
;
828 /* fall back to the default subnet masks based on address class */
829 r
= in_addr_default_subnet_mask(&address
, &mask
);
833 lease
->subnet_mask
= mask
.s_addr
;
838 int sd_dhcp_lease_get_client_id(sd_dhcp_lease
*lease
, const uint8_t **client_id
,
839 size_t *client_id_len
) {
840 assert_return(lease
, -EINVAL
);
841 assert_return(client_id
, -EINVAL
);
842 assert_return(client_id_len
, -EINVAL
);
844 *client_id
= lease
->client_id
;
845 *client_id_len
= lease
->client_id_len
;
849 int dhcp_lease_set_client_id(sd_dhcp_lease
*lease
, const uint8_t *client_id
,
850 size_t client_id_len
) {
851 assert_return(lease
, -EINVAL
);
852 assert_return((!client_id
&& !client_id_len
) ||
853 (client_id
&& client_id_len
), -EINVAL
);
855 free (lease
->client_id
);
856 lease
->client_id
= NULL
;
857 lease
->client_id_len
= 0;
860 lease
->client_id
= memdup (client_id
, client_id_len
);
861 lease
->client_id_len
= client_id_len
;