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 lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
314 size_t *routes_size, size_t *routes_allocated) {
321 assert(routes_allocated);
329 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + (len / 8)))
333 struct sd_dhcp_route *route = *routes + *routes_size;
336 r = in_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen);
338 log_error("Failed to determine destination prefix length from class based IP, ignoring");
342 lease_parse_be32(option, 4, &addr.s_addr);
343 route->dst_addr = inet_makeaddr(inet_netof(addr), 0);
346 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
356 /* parses RFC3442 Classless Static Route Option */
357 static int lease_parse_classless_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
358 size_t *routes_size, size_t *routes_allocated) {
363 assert(routes_allocated);
365 /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */
369 struct sd_dhcp_route *route;
371 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1))
374 route = *routes + *routes_size;
376 dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1);
377 route->dst_prefixlen = *option;
381 /* can't have more than 4 octets in IPv4 */
382 if (dst_octets > 4 || len < dst_octets)
385 route->dst_addr.s_addr = 0;
386 memcpy(&route->dst_addr.s_addr, option, dst_octets);
387 option += dst_octets;
393 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
403 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
405 sd_dhcp_lease *lease = user_data;
412 case DHCP_OPTION_TIME_OFFSET:
413 lease_parse_s32(option, len, &lease->time_offset);
417 case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT:
418 lease_parse_u32(option, len, &lease->mtu_aging_timeout, 0);
422 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
423 lease_parse_u32(option, len, &lease->lifetime, 1);
427 case DHCP_OPTION_SERVER_IDENTIFIER:
428 lease_parse_be32(option, len, &lease->server_address);
432 case DHCP_OPTION_SUBNET_MASK:
433 lease_parse_be32(option, len, &lease->subnet_mask);
437 case DHCP_OPTION_BROADCAST:
438 lease_parse_be32(option, len, &lease->broadcast);
442 case DHCP_OPTION_ROUTER:
443 lease_parse_be32(option, len, &lease->router);
447 case DHCP_OPTION_DOMAIN_NAME_SERVER:
448 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
454 case DHCP_OPTION_NTP_SERVER:
455 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
461 case DHCP_OPTION_POLICY_FILTER:
462 r = lease_parse_in_addrs_pairs(option, len, &lease->policy_filter, &lease->policy_filter_size);
468 case DHCP_OPTION_STATIC_ROUTE:
469 r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size,
470 &lease->static_route_allocated);
476 case DHCP_OPTION_INTERFACE_MTU:
477 lease_parse_u16(option, len, &lease->mtu, 68);
481 case DHCP_OPTION_INTERFACE_MDR:
482 lease_parse_u16(option, len, &lease->mdr, 576);
486 case DHCP_OPTION_INTERFACE_TTL:
487 lease_parse_u8(option, len, &lease->ttl, 1);
491 case DHCP_OPTION_BOOT_FILE_SIZE:
492 lease_parse_u16(option, len, &lease->boot_file_size, 0);
496 case DHCP_OPTION_DOMAIN_NAME:
498 _cleanup_free_ char *domainname = NULL;
500 r = lease_parse_string(option, len, &domainname);
504 if (!hostname_is_valid(domainname) || is_localhost(domainname))
507 free(lease->domainname);
508 lease->domainname = domainname;
513 case DHCP_OPTION_HOST_NAME:
515 _cleanup_free_ char *hostname = NULL;
517 r = lease_parse_string(option, len, &hostname);
521 if (!hostname_is_valid(hostname) || is_localhost(hostname))
524 free(lease->hostname);
525 lease->hostname = hostname;
530 case DHCP_OPTION_ROOT_PATH:
531 r = lease_parse_string(option, len, &lease->root_path);
537 case DHCP_OPTION_RENEWAL_T1_TIME:
538 lease_parse_u32(option, len, &lease->t1, 1);
542 case DHCP_OPTION_REBINDING_T2_TIME:
543 lease_parse_u32(option, len, &lease->t2, 1);
547 case DHCP_OPTION_ENABLE_IP_FORWARDING:
548 lease_parse_bool(option, len, &lease->ip_forward);
552 case DHCP_OPTION_ENABLE_IP_FORWARDING_NL:
553 lease_parse_bool(option, len, &lease->ip_forward_non_local);
557 case DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
558 r = lease_parse_classless_routes(option, len, &lease->static_route, &lease->static_route_size,
559 &lease->static_route_allocated);
569 int dhcp_lease_new(sd_dhcp_lease **ret) {
570 sd_dhcp_lease *lease;
572 lease = new0(sd_dhcp_lease, 1);
576 lease->router = INADDR_ANY;
577 lease->n_ref = REFCNT_INIT;
583 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
584 _cleanup_free_ char *temp_path = NULL;
585 _cleanup_fclose_ FILE *f = NULL;
586 struct in_addr address;
587 const struct in_addr *addresses;
590 struct sd_dhcp_route *routes;
596 r = fopen_temporary(lease_file, &f, &temp_path);
600 fchmod(fileno(f), 0644);
602 r = sd_dhcp_lease_get_address(lease, &address);
607 "# This is private data. Do not parse.\n"
608 "ADDRESS=%s\n", inet_ntoa(address));
610 r = sd_dhcp_lease_get_netmask(lease, &address);
614 fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
616 r = sd_dhcp_lease_get_router(lease, &address);
618 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
620 r = sd_dhcp_lease_get_server_identifier(lease, &address);
622 fprintf(f, "SERVER_ADDRESS=%s\n",
625 r = sd_dhcp_lease_get_next_server(lease, &address);
627 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
629 r = sd_dhcp_lease_get_mtu(lease, &mtu);
631 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
634 r = sd_dhcp_lease_get_dns(lease, &addresses);
636 serialize_in_addrs(f, addresses, r);
640 r = sd_dhcp_lease_get_ntp(lease, &addresses);
642 serialize_in_addrs(f, addresses, r);
645 r = sd_dhcp_lease_get_domainname(lease, &string);
647 fprintf(f, "DOMAINNAME=%s\n", string);
649 r = sd_dhcp_lease_get_hostname(lease, &string);
651 fprintf(f, "HOSTNAME=%s\n", string);
653 r = sd_dhcp_lease_get_root_path(lease, &string);
655 fprintf(f, "ROOT_PATH=%s\n", string);
657 r = sd_dhcp_lease_get_routes(lease, &routes);
659 serialize_dhcp_routes(f, "ROUTES", routes, r);
665 if (ferror(f) || rename(temp_path, lease_file) < 0) {
673 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
678 int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
679 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
680 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
681 *server_address = NULL, *next_server = NULL,
682 *dns = NULL, *ntp = NULL, *mtu = NULL, *routes = NULL;
689 r = dhcp_lease_new(&lease);
693 r = parse_env_file(lease_file, NEWLINE,
697 "SERVER_IDENTIFIER", &server_address,
698 "NEXT_SERVER", &next_server,
702 "DOMAINNAME", &lease->domainname,
703 "HOSTNAME", &lease->hostname,
704 "ROOT_PATH", &lease->root_path,
711 log_error("Failed to read %s: %s", lease_file, strerror(-r));
715 r = inet_pton(AF_INET, address, &addr);
719 lease->address = addr.s_addr;
722 r = inet_pton(AF_INET, router, &addr);
726 lease->router = addr.s_addr;
729 r = inet_pton(AF_INET, netmask, &addr);
733 lease->subnet_mask = addr.s_addr;
735 if (server_address) {
736 r = inet_pton(AF_INET, server_address, &addr);
740 lease->server_address = addr.s_addr;
744 r = inet_pton(AF_INET, next_server, &addr);
748 lease->next_server = addr.s_addr;
752 r = deserialize_in_addrs(&lease->dns, dns);
760 r = deserialize_in_addrs(&lease->ntp, ntp);
769 if (sscanf(mtu, "%" SCNu16, &u) > 0)
774 r = deserialize_dhcp_routes(&lease->static_route, &lease->static_route_size,
775 &lease->static_route_allocated, routes);
786 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
787 struct in_addr address;
793 address.s_addr = lease->address;
795 /* fall back to the default subnet masks based on address class */
796 r = in_addr_default_subnet_mask(&address, &mask);
800 lease->subnet_mask = mask.s_addr;