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(lease, -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);
208 static void lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
213 *ret = unaligned_read_be32((be32_t*) option);
220 static void lease_parse_s32(const uint8_t *option, size_t len, int32_t *ret) {
221 lease_parse_u32(option, len, (uint32_t *)ret, 0);
224 static void lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
229 *ret = unaligned_read_be16((be16_t*) option);
236 static void lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
241 memcpy(ret, option, 4);
244 static void lease_parse_bool(const uint8_t *option, size_t len, bool *ret) {
252 static void lease_parse_u8(const uint8_t *option, size_t len, uint8_t *ret, uint8_t min) {
264 static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
271 string = strndup((const char *)option, len);
282 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) {
287 if (len && !(len % (4 * mult))) {
289 struct in_addr *addresses;
293 addresses = newdup(struct in_addr, option, size);
305 static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
306 return lease_parse_in_addrs_aux(option, len, ret, ret_size, 1);
309 static int lease_parse_in_addrs_pairs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
310 return lease_parse_in_addrs_aux(option, len, ret, ret_size, 2);
313 static int class_prefixlen(uint8_t msb_octet, uint8_t *ret) {
317 else if (msb_octet < 192)
320 else if (msb_octet < 224)
324 /* Class D or E -- no subnet mask */
330 static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
331 size_t *routes_size, size_t *routes_allocated) {
338 assert(routes_allocated);
346 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + (len / 8)))
350 struct sd_dhcp_route *route = *routes + *routes_size;
352 if (class_prefixlen(*option, &route->dst_prefixlen) < 0) {
353 log_error("Failed to determine destination prefix length from class based IP, ignoring");
357 lease_parse_be32(option, 4, &addr.s_addr);
358 route->dst_addr = inet_makeaddr(inet_netof(addr), 0);
361 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
371 /* parses RFC3442 Classless Static Route Option */
372 static int lease_parse_classless_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
373 size_t *routes_size, size_t *routes_allocated) {
378 assert(routes_allocated);
380 /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */
384 struct sd_dhcp_route *route;
386 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1))
389 route = *routes + *routes_size;
391 dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1);
392 route->dst_prefixlen = *option;
396 /* can't have more than 4 octets in IPv4 */
397 if (dst_octets > 4 || len < dst_octets)
400 route->dst_addr.s_addr = 0;
401 memcpy(&route->dst_addr.s_addr, option, dst_octets);
402 option += dst_octets;
408 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
418 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
420 sd_dhcp_lease *lease = user_data;
427 case DHCP_OPTION_TIME_OFFSET:
428 lease_parse_s32(option, len, &lease->time_offset);
432 case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT:
433 lease_parse_u32(option, len, &lease->mtu_aging_timeout, 0);
437 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
438 lease_parse_u32(option, len, &lease->lifetime, 1);
442 case DHCP_OPTION_SERVER_IDENTIFIER:
443 lease_parse_be32(option, len, &lease->server_address);
447 case DHCP_OPTION_SUBNET_MASK:
448 lease_parse_be32(option, len, &lease->subnet_mask);
452 case DHCP_OPTION_BROADCAST:
453 lease_parse_be32(option, len, &lease->broadcast);
457 case DHCP_OPTION_ROUTER:
458 lease_parse_be32(option, len, &lease->router);
462 case DHCP_OPTION_DOMAIN_NAME_SERVER:
463 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
469 case DHCP_OPTION_NTP_SERVER:
470 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
476 case DHCP_OPTION_POLICY_FILTER:
477 r = lease_parse_in_addrs_pairs(option, len, &lease->policy_filter, &lease->policy_filter_size);
483 case DHCP_OPTION_STATIC_ROUTE:
484 r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size,
485 &lease->static_route_allocated);
491 case DHCP_OPTION_INTERFACE_MTU:
492 lease_parse_u16(option, len, &lease->mtu, 68);
496 case DHCP_OPTION_INTERFACE_MDR:
497 lease_parse_u16(option, len, &lease->mdr, 576);
501 case DHCP_OPTION_INTERFACE_TTL:
502 lease_parse_u8(option, len, &lease->ttl, 1);
506 case DHCP_OPTION_BOOT_FILE_SIZE:
507 lease_parse_u16(option, len, &lease->boot_file_size, 0);
511 case DHCP_OPTION_DOMAIN_NAME:
513 _cleanup_free_ char *domainname = NULL;
515 r = lease_parse_string(option, len, &domainname);
519 if (!hostname_is_valid(domainname) || is_localhost(domainname))
522 free(lease->domainname);
523 lease->domainname = domainname;
528 case DHCP_OPTION_HOST_NAME:
530 _cleanup_free_ char *hostname = NULL;
532 r = lease_parse_string(option, len, &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 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;
605 struct sd_dhcp_route *routes;
611 r = fopen_temporary(lease_file, &f, &temp_path);
615 fchmod(fileno(f), 0644);
617 r = sd_dhcp_lease_get_address(lease, &address);
622 "# This is private data. Do not parse.\n"
623 "ADDRESS=%s\n", inet_ntoa(address));
625 r = sd_dhcp_lease_get_netmask(lease, &address);
629 fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
631 r = sd_dhcp_lease_get_router(lease, &address);
633 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
635 r = sd_dhcp_lease_get_server_identifier(lease, &address);
637 fprintf(f, "SERVER_ADDRESS=%s\n",
640 r = sd_dhcp_lease_get_next_server(lease, &address);
642 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
644 r = sd_dhcp_lease_get_mtu(lease, &mtu);
646 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
649 r = sd_dhcp_lease_get_dns(lease, &addresses);
651 serialize_in_addrs(f, addresses, r);
655 r = sd_dhcp_lease_get_ntp(lease, &addresses);
657 serialize_in_addrs(f, addresses, r);
660 r = sd_dhcp_lease_get_domainname(lease, &string);
662 fprintf(f, "DOMAINNAME=%s\n", string);
664 r = sd_dhcp_lease_get_hostname(lease, &string);
666 fprintf(f, "HOSTNAME=%s\n", string);
668 r = sd_dhcp_lease_get_root_path(lease, &string);
670 fprintf(f, "ROOT_PATH=%s\n", string);
672 r = sd_dhcp_lease_get_routes(lease, &routes);
674 serialize_dhcp_routes(f, "ROUTES", routes, r);
680 if (ferror(f) || rename(temp_path, lease_file) < 0) {
688 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
693 int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
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, *routes = NULL;
704 r = dhcp_lease_new(&lease);
708 r = parse_env_file(lease_file, NEWLINE,
712 "SERVER_IDENTIFIER", &server_address,
713 "NEXT_SERVER", &next_server,
717 "DOMAINNAME", &lease->domainname,
718 "HOSTNAME", &lease->hostname,
719 "ROOT_PATH", &lease->root_path,
726 log_error("Failed to read %s: %s", lease_file, strerror(-r));
730 r = inet_pton(AF_INET, address, &addr);
734 lease->address = addr.s_addr;
737 r = inet_pton(AF_INET, router, &addr);
741 lease->router = addr.s_addr;
744 r = inet_pton(AF_INET, netmask, &addr);
748 lease->subnet_mask = addr.s_addr;
750 if (server_address) {
751 r = inet_pton(AF_INET, server_address, &addr);
755 lease->server_address = addr.s_addr;
759 r = inet_pton(AF_INET, next_server, &addr);
763 lease->next_server = addr.s_addr;
767 r = deserialize_in_addrs(&lease->dns, dns);
775 r = deserialize_in_addrs(&lease->ntp, ntp);
784 if (sscanf(mtu, "%" SCNu16, &u) > 0)
789 r = deserialize_dhcp_routes(&lease->static_route, &lease->static_route_size,
790 &lease->static_route_allocated, routes);
801 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
802 struct in_addr address;
808 address.s_addr = lease->address;
810 /* fall back to the default subnet masks based on address class */
811 r = in_addr_default_subnet_mask(&address, &mask);
815 lease->subnet_mask = mask.s_addr;