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;
501 r = lease_parse_string(option, len, &domainname);
505 if (!hostname_is_valid(domainname) || is_localhost(domainname))
508 free(lease->domainname);
509 lease->domainname = domainname;
514 case DHCP_OPTION_HOST_NAME:
516 _cleanup_free_ char *hostname = NULL;
518 r = lease_parse_string(option, len, &hostname);
522 if (!hostname_is_valid(hostname) || is_localhost(hostname))
525 free(lease->hostname);
526 lease->hostname = hostname;
531 case DHCP_OPTION_ROOT_PATH:
532 r = lease_parse_string(option, len, &lease->root_path);
538 case DHCP_OPTION_RENEWAL_T1_TIME:
539 lease_parse_u32(option, len, &lease->t1, 1);
543 case DHCP_OPTION_REBINDING_T2_TIME:
544 lease_parse_u32(option, len, &lease->t2, 1);
548 case DHCP_OPTION_ENABLE_IP_FORWARDING:
549 lease_parse_bool(option, len, &lease->ip_forward);
553 case DHCP_OPTION_ENABLE_IP_FORWARDING_NL:
554 lease_parse_bool(option, len, &lease->ip_forward_non_local);
558 case DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
559 r = lease_parse_classless_routes(option, len, &lease->static_route, &lease->static_route_size,
560 &lease->static_route_allocated);
570 int dhcp_lease_new(sd_dhcp_lease **ret) {
571 sd_dhcp_lease *lease;
573 lease = new0(sd_dhcp_lease, 1);
577 lease->router = INADDR_ANY;
578 lease->n_ref = REFCNT_INIT;
584 int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
585 _cleanup_free_ char *temp_path = NULL;
586 _cleanup_fclose_ FILE *f = NULL;
587 struct in_addr address;
588 const struct in_addr *addresses;
589 const uint8_t *client_id;
590 size_t client_id_len;
593 struct sd_dhcp_route *routes;
599 r = fopen_temporary(lease_file, &f, &temp_path);
603 fchmod(fileno(f), 0644);
605 r = sd_dhcp_lease_get_address(lease, &address);
610 "# This is private data. Do not parse.\n"
611 "ADDRESS=%s\n", inet_ntoa(address));
613 r = sd_dhcp_lease_get_netmask(lease, &address);
617 fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
619 r = sd_dhcp_lease_get_router(lease, &address);
621 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
623 r = sd_dhcp_lease_get_server_identifier(lease, &address);
625 fprintf(f, "SERVER_ADDRESS=%s\n",
628 r = sd_dhcp_lease_get_next_server(lease, &address);
630 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
632 r = sd_dhcp_lease_get_mtu(lease, &mtu);
634 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
637 r = sd_dhcp_lease_get_dns(lease, &addresses);
639 serialize_in_addrs(f, addresses, r);
643 r = sd_dhcp_lease_get_ntp(lease, &addresses);
645 serialize_in_addrs(f, addresses, r);
648 r = sd_dhcp_lease_get_domainname(lease, &string);
650 fprintf(f, "DOMAINNAME=%s\n", string);
652 r = sd_dhcp_lease_get_hostname(lease, &string);
654 fprintf(f, "HOSTNAME=%s\n", string);
656 r = sd_dhcp_lease_get_root_path(lease, &string);
658 fprintf(f, "ROOT_PATH=%s\n", string);
660 r = sd_dhcp_lease_get_routes(lease, &routes);
662 serialize_dhcp_routes(f, "ROUTES", routes, r);
664 r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
666 _cleanup_free_ char *client_id_hex;
668 client_id_hex = hexmem (client_id, client_id_len);
669 if (!client_id_hex) {
673 fprintf(f, "CLIENTID=%s\n", client_id_hex);
680 if (ferror(f) || rename(temp_path, lease_file) < 0) {
688 log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
693 int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
694 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
695 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
696 *server_address = NULL, *next_server = NULL,
697 *dns = NULL, *ntp = NULL, *mtu = NULL,
698 *routes = NULL, *client_id_hex = NULL;
705 r = dhcp_lease_new(&lease);
709 r = parse_env_file(lease_file, NEWLINE,
713 "SERVER_IDENTIFIER", &server_address,
714 "NEXT_SERVER", &next_server,
718 "DOMAINNAME", &lease->domainname,
719 "HOSTNAME", &lease->hostname,
720 "ROOT_PATH", &lease->root_path,
722 "CLIENTID", &client_id_hex,
728 return log_error_errno(r, "Failed to read %s: %m", lease_file);
731 r = inet_pton(AF_INET, address, &addr);
735 lease->address = addr.s_addr;
738 r = inet_pton(AF_INET, router, &addr);
742 lease->router = addr.s_addr;
745 r = inet_pton(AF_INET, netmask, &addr);
749 lease->subnet_mask = addr.s_addr;
751 if (server_address) {
752 r = inet_pton(AF_INET, server_address, &addr);
756 lease->server_address = addr.s_addr;
760 r = inet_pton(AF_INET, next_server, &addr);
764 lease->next_server = addr.s_addr;
768 r = deserialize_in_addrs(&lease->dns, dns);
776 r = deserialize_in_addrs(&lease->ntp, ntp);
785 if (sscanf(mtu, "%" SCNu16, &u) > 0)
790 r = deserialize_dhcp_routes(&lease->static_route, &lease->static_route_size,
791 &lease->static_route_allocated, routes);
797 if (strlen (client_id_hex) % 2)
800 lease->client_id = unhexmem (client_id_hex, strlen (client_id_hex));
801 if (!lease->client_id)
803 lease->client_id_len = strlen (client_id_hex) / 2;
812 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
813 struct in_addr address;
819 address.s_addr = lease->address;
821 /* fall back to the default subnet masks based on address class */
822 r = in_addr_default_subnet_mask(&address, &mask);
826 lease->subnet_mask = mask.s_addr;
831 int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id,
832 size_t *client_id_len) {
833 assert_return(lease, -EINVAL);
834 assert_return(client_id, -EINVAL);
835 assert_return(client_id_len, -EINVAL);
837 *client_id = lease->client_id;
838 *client_id_len = lease->client_id_len;
842 int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id,
843 size_t client_id_len) {
844 assert_return(lease, -EINVAL);
845 assert_return((!client_id && !client_id_len) ||
846 (client_id && client_id_len), -EINVAL);
848 free (lease->client_id);
849 lease->client_id = NULL;
850 lease->client_id_len = 0;
853 lease->client_id = memdup (client_id, client_id_len);
854 lease->client_id_len = client_id_len;