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 <net/ethernet.h>
26 #include <arpa/inet.h>
27 #include <sys/param.h>
33 #include "unaligned.h"
34 #include "in-addr-util.h"
36 #include "dhcp-protocol.h"
37 #include "dhcp-internal.h"
38 #include "dhcp-lease-internal.h"
39 #include "sd-dhcp-lease.h"
40 #include "sd-dhcp-client.h"
41 #include "network-internal.h"
43 int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
44 assert_return(lease, -EINVAL);
45 assert_return(addr, -EINVAL);
47 addr->s_addr = lease->address;
52 int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
53 assert_return(lease, -EINVAL);
54 assert_return(lifetime, -EINVAL);
56 *lifetime = lease->lifetime;
61 int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
62 assert_return(lease, -EINVAL);
63 assert_return(mtu, -EINVAL);
73 int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) {
74 assert_return(lease, -EINVAL);
75 assert_return(addr, -EINVAL);
77 if (lease->dns_size) {
79 return lease->dns_size;
86 int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) {
87 assert_return(lease, -EINVAL);
88 assert_return(addr, -EINVAL);
90 if (lease->ntp_size) {
92 return lease->ntp_size;
99 int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
100 assert_return(lease, -EINVAL);
101 assert_return(domainname, -EINVAL);
103 if (lease->domainname)
104 *domainname = lease->domainname;
111 int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
112 assert_return(lease, -EINVAL);
113 assert_return(hostname, -EINVAL);
116 *hostname = lease->hostname;
123 int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
124 assert_return(lease, -EINVAL);
125 assert_return(root_path, -EINVAL);
127 if (lease->root_path)
128 *root_path = lease->root_path;
135 int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) {
136 assert_return(lease, -EINVAL);
137 assert_return(addr, -EINVAL);
139 if (lease->router != INADDR_ANY)
140 addr->s_addr = lease->router;
147 int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
148 assert_return(lease, -EINVAL);
149 assert_return(addr, -EINVAL);
151 addr->s_addr = lease->subnet_mask;
156 int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
157 assert_return(lease, -EINVAL);
158 assert_return(addr, -EINVAL);
160 addr->s_addr = lease->server_address;
165 int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
166 assert_return(lease, -EINVAL);
167 assert_return(addr, -EINVAL);
169 addr->s_addr = lease->next_server;
174 int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes) {
176 assert_return(lease, -EINVAL);
177 assert_return(routes, -EINVAL);
179 if (lease->static_route_size) {
180 *routes = lease->static_route;
181 return lease->static_route_size;
188 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
190 assert_se(REFCNT_INC(lease->n_ref) >= 2);
195 sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
196 if (lease && REFCNT_DEC(lease->n_ref) == 0) {
197 free(lease->hostname);
198 free(lease->domainname);
201 free(lease->static_route);
202 free(lease->client_id);
209 static void lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
214 *ret = unaligned_read_be32((be32_t*) option);
221 static void lease_parse_s32(const uint8_t *option, size_t len, int32_t *ret) {
222 lease_parse_u32(option, len, (uint32_t *)ret, 0);
225 static void lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
230 *ret = unaligned_read_be16((be16_t*) option);
237 static void lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
242 memcpy(ret, option, 4);
245 static void lease_parse_bool(const uint8_t *option, size_t len, bool *ret) {
253 static void lease_parse_u8(const uint8_t *option, size_t len, uint8_t *ret, uint8_t min) {
265 static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
272 string = strndup((const char *)option, len);
283 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) {
288 if (len && !(len % (4 * mult))) {
290 struct in_addr *addresses;
294 addresses = newdup(struct in_addr, option, size);
306 static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
307 return lease_parse_in_addrs_aux(option, len, ret, ret_size, 1);
310 static int lease_parse_in_addrs_pairs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
311 return lease_parse_in_addrs_aux(option, len, ret, ret_size, 2);
314 static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
315 size_t *routes_size, size_t *routes_allocated) {
322 assert(routes_allocated);
330 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + (len / 8)))
334 struct sd_dhcp_route *route = *routes + *routes_size;
337 r = in_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen);
339 log_error("Failed to determine destination prefix length from class based IP, ignoring");
343 lease_parse_be32(option, 4, &addr.s_addr);
344 route->dst_addr = inet_makeaddr(inet_netof(addr), 0);
347 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
357 /* parses RFC3442 Classless Static Route Option */
358 static int lease_parse_classless_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
359 size_t *routes_size, size_t *routes_allocated) {
364 assert(routes_allocated);
366 /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */
370 struct sd_dhcp_route *route;
372 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1))
375 route = *routes + *routes_size;
377 dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1);
378 route->dst_prefixlen = *option;
382 /* can't have more than 4 octets in IPv4 */
383 if (dst_octets > 4 || len < dst_octets)
386 route->dst_addr.s_addr = 0;
387 memcpy(&route->dst_addr.s_addr, option, dst_octets);
388 option += dst_octets;
394 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
404 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
406 sd_dhcp_lease *lease = user_data;
413 case DHCP_OPTION_TIME_OFFSET:
414 lease_parse_s32(option, len, &lease->time_offset);
418 case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT:
419 lease_parse_u32(option, len, &lease->mtu_aging_timeout, 0);
423 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
424 lease_parse_u32(option, len, &lease->lifetime, 1);
428 case DHCP_OPTION_SERVER_IDENTIFIER:
429 lease_parse_be32(option, len, &lease->server_address);
433 case DHCP_OPTION_SUBNET_MASK:
434 lease_parse_be32(option, len, &lease->subnet_mask);
438 case DHCP_OPTION_BROADCAST:
439 lease_parse_be32(option, len, &lease->broadcast);
443 case DHCP_OPTION_ROUTER:
444 lease_parse_be32(option, len, &lease->router);
448 case DHCP_OPTION_DOMAIN_NAME_SERVER:
449 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
455 case DHCP_OPTION_NTP_SERVER:
456 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
462 case DHCP_OPTION_POLICY_FILTER:
463 r = lease_parse_in_addrs_pairs(option, len, &lease->policy_filter, &lease->policy_filter_size);
469 case DHCP_OPTION_STATIC_ROUTE:
470 r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size,
471 &lease->static_route_allocated);
477 case DHCP_OPTION_INTERFACE_MTU:
478 lease_parse_u16(option, len, &lease->mtu, 68);
482 case DHCP_OPTION_INTERFACE_MDR:
483 lease_parse_u16(option, len, &lease->mdr, 576);
487 case DHCP_OPTION_INTERFACE_TTL:
488 lease_parse_u8(option, len, &lease->ttl, 1);
492 case DHCP_OPTION_BOOT_FILE_SIZE:
493 lease_parse_u16(option, len, &lease->boot_file_size, 0);
497 case DHCP_OPTION_DOMAIN_NAME:
499 _cleanup_free_ char *domainname = NULL;
502 r = lease_parse_string(option, len, &domainname);
506 /* Chop off trailing dot of domain name that some DHCP
507 * servers send us back. Internally we want to store
508 * host names without trailing dots and
509 * host_name_is_valid() doesn't accept them. */
510 e = endswith(domainname, ".");
514 if (!hostname_is_valid(domainname) || is_localhost(domainname))
517 free(lease->domainname);
518 lease->domainname = domainname;
523 case DHCP_OPTION_HOST_NAME:
525 _cleanup_free_ char *hostname = NULL;
528 r = lease_parse_string(option, len, &hostname);
532 e = endswith(hostname, ".");
536 if (!hostname_is_valid(hostname) || is_localhost(hostname))
539 free(lease->hostname);
540 lease->hostname = hostname;
545 case DHCP_OPTION_ROOT_PATH:
546 r = lease_parse_string(option, len, &lease->root_path);
552 case DHCP_OPTION_RENEWAL_T1_TIME:
553 lease_parse_u32(option, len, &lease->t1, 1);
557 case DHCP_OPTION_REBINDING_T2_TIME:
558 lease_parse_u32(option, len, &lease->t2, 1);
562 case DHCP_OPTION_ENABLE_IP_FORWARDING:
563 lease_parse_bool(option, len, &lease->ip_forward);
567 case DHCP_OPTION_ENABLE_IP_FORWARDING_NL:
568 lease_parse_bool(option, len, &lease->ip_forward_non_local);
572 case DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
573 r = lease_parse_classless_routes(option, len, &lease->static_route, &lease->static_route_size,
574 &lease->static_route_allocated);
584 int dhcp_lease_new(sd_dhcp_lease **ret) {
585 sd_dhcp_lease *lease;
587 lease = new0(sd_dhcp_lease, 1);
591 lease->router = INADDR_ANY;
592 lease->n_ref = REFCNT_INIT;
598 int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
599 _cleanup_free_ char *temp_path = NULL;
600 _cleanup_fclose_ FILE *f = NULL;
601 struct in_addr address;
602 const struct in_addr *addresses;
603 const uint8_t *client_id;
604 size_t client_id_len;
607 struct sd_dhcp_route *routes;
613 r = fopen_temporary(lease_file, &f, &temp_path);
617 fchmod(fileno(f), 0644);
619 r = sd_dhcp_lease_get_address(lease, &address);
624 "# This is private data. Do not parse.\n"
625 "ADDRESS=%s\n", inet_ntoa(address));
627 r = sd_dhcp_lease_get_netmask(lease, &address);
631 fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
633 r = sd_dhcp_lease_get_router(lease, &address);
635 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
637 r = sd_dhcp_lease_get_server_identifier(lease, &address);
639 fprintf(f, "SERVER_ADDRESS=%s\n",
642 r = sd_dhcp_lease_get_next_server(lease, &address);
644 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
646 r = sd_dhcp_lease_get_mtu(lease, &mtu);
648 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
651 r = sd_dhcp_lease_get_dns(lease, &addresses);
653 serialize_in_addrs(f, addresses, r);
657 r = sd_dhcp_lease_get_ntp(lease, &addresses);
659 serialize_in_addrs(f, addresses, r);
662 r = sd_dhcp_lease_get_domainname(lease, &string);
664 fprintf(f, "DOMAINNAME=%s\n", string);
666 r = sd_dhcp_lease_get_hostname(lease, &string);
668 fprintf(f, "HOSTNAME=%s\n", string);
670 r = sd_dhcp_lease_get_root_path(lease, &string);
672 fprintf(f, "ROOT_PATH=%s\n", string);
674 r = sd_dhcp_lease_get_routes(lease, &routes);
676 serialize_dhcp_routes(f, "ROUTES", routes, r);
678 r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
680 _cleanup_free_ char *client_id_hex;
682 client_id_hex = hexmem (client_id, client_id_len);
683 if (!client_id_hex) {
687 fprintf(f, "CLIENTID=%s\n", client_id_hex);
694 if (ferror(f) || rename(temp_path, lease_file) < 0) {
702 log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
707 int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
708 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
709 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
710 *server_address = NULL, *next_server = NULL,
711 *dns = NULL, *ntp = NULL, *mtu = NULL,
712 *routes = NULL, *client_id_hex = NULL;
719 r = dhcp_lease_new(&lease);
723 r = parse_env_file(lease_file, NEWLINE,
727 "SERVER_IDENTIFIER", &server_address,
728 "NEXT_SERVER", &next_server,
732 "DOMAINNAME", &lease->domainname,
733 "HOSTNAME", &lease->hostname,
734 "ROOT_PATH", &lease->root_path,
736 "CLIENTID", &client_id_hex,
742 return log_error_errno(r, "Failed to read %s: %m", lease_file);
745 r = inet_pton(AF_INET, address, &addr);
749 lease->address = addr.s_addr;
752 r = inet_pton(AF_INET, router, &addr);
756 lease->router = addr.s_addr;
759 r = inet_pton(AF_INET, netmask, &addr);
763 lease->subnet_mask = addr.s_addr;
765 if (server_address) {
766 r = inet_pton(AF_INET, server_address, &addr);
770 lease->server_address = addr.s_addr;
774 r = inet_pton(AF_INET, next_server, &addr);
778 lease->next_server = addr.s_addr;
782 r = deserialize_in_addrs(&lease->dns, dns);
790 r = deserialize_in_addrs(&lease->ntp, ntp);
799 if (sscanf(mtu, "%" SCNu16, &u) > 0)
804 r = deserialize_dhcp_routes(&lease->static_route, &lease->static_route_size,
805 &lease->static_route_allocated, routes);
811 if (strlen (client_id_hex) % 2)
814 lease->client_id = unhexmem (client_id_hex, strlen (client_id_hex));
815 if (!lease->client_id)
817 lease->client_id_len = strlen (client_id_hex) / 2;
826 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
827 struct in_addr address;
833 address.s_addr = lease->address;
835 /* fall back to the default subnet masks based on address class */
836 r = in_addr_default_subnet_mask(&address, &mask);
840 lease->subnet_mask = mask.s_addr;
845 int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id,
846 size_t *client_id_len) {
847 assert_return(lease, -EINVAL);
848 assert_return(client_id, -EINVAL);
849 assert_return(client_id_len, -EINVAL);
851 *client_id = lease->client_id;
852 *client_id_len = lease->client_id_len;
856 int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id,
857 size_t client_id_len) {
858 assert_return(lease, -EINVAL);
859 assert_return((!client_id && !client_id_len) ||
860 (client_id && client_id_len), -EINVAL);
862 free (lease->client_id);
863 lease->client_id = NULL;
864 lease->client_id_len = 0;
867 lease->client_id = memdup (client_id, client_id_len);
868 lease->client_id_len = client_id_len;