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 "in-addr-util.h"
35 #include "dhcp-protocol.h"
36 #include "dhcp-internal.h"
37 #include "dhcp-lease-internal.h"
38 #include "sd-dhcp-lease.h"
39 #include "sd-dhcp-client.h"
40 #include "network-internal.h"
42 int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
43 assert_return(lease, -EINVAL);
44 assert_return(addr, -EINVAL);
46 addr->s_addr = lease->address;
51 int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
52 assert_return(lease, -EINVAL);
53 assert_return(lease, -EINVAL);
55 *lifetime = lease->lifetime;
60 int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
61 assert_return(lease, -EINVAL);
62 assert_return(mtu, -EINVAL);
72 int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) {
73 assert_return(lease, -EINVAL);
74 assert_return(addr, -EINVAL);
76 if (lease->dns_size) {
78 return lease->dns_size;
85 int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) {
86 assert_return(lease, -EINVAL);
87 assert_return(addr, -EINVAL);
89 if (lease->ntp_size) {
91 return lease->ntp_size;
98 int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
99 assert_return(lease, -EINVAL);
100 assert_return(domainname, -EINVAL);
102 if (lease->domainname)
103 *domainname = lease->domainname;
110 int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
111 assert_return(lease, -EINVAL);
112 assert_return(hostname, -EINVAL);
115 *hostname = lease->hostname;
122 int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
123 assert_return(lease, -EINVAL);
124 assert_return(root_path, -EINVAL);
126 if (lease->root_path)
127 *root_path = lease->root_path;
134 int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) {
135 assert_return(lease, -EINVAL);
136 assert_return(addr, -EINVAL);
138 if (lease->router != INADDR_ANY)
139 addr->s_addr = lease->router;
146 int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
147 assert_return(lease, -EINVAL);
148 assert_return(addr, -EINVAL);
150 addr->s_addr = lease->subnet_mask;
155 int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
156 assert_return(lease, -EINVAL);
157 assert_return(addr, -EINVAL);
159 addr->s_addr = lease->server_address;
164 int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
165 assert_return(lease, -EINVAL);
166 assert_return(addr, -EINVAL);
168 addr->s_addr = lease->next_server;
173 int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes) {
175 assert_return(lease, -EINVAL);
176 assert_return(routes, -EINVAL);
178 if (lease->static_route_size) {
179 *routes = lease->static_route;
180 return lease->static_route_size;
187 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
189 assert_se(REFCNT_INC(lease->n_ref) >= 2);
194 sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
195 if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
196 free(lease->hostname);
197 free(lease->domainname);
200 free(lease->static_route);
207 static void lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
214 memcpy(&val, option, 4);
222 static void lease_parse_s32(const uint8_t *option, size_t len, int32_t *ret) {
223 lease_parse_u32(option, len, (uint32_t *)ret, 0);
226 static void lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
233 memcpy(&val, option, 2);
241 static void lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
246 memcpy(ret, option, 4);
249 static void lease_parse_bool(const uint8_t *option, size_t len, bool *ret) {
257 static void lease_parse_u8(const uint8_t *option, size_t len, uint8_t *ret, uint8_t min) {
269 static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
276 string = strndup((const char *)option, len);
287 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) {
292 if (len && !(len % (4 * mult))) {
294 struct in_addr *addresses;
298 addresses = newdup(struct in_addr, option, size);
310 static int lease_parse_in_addrs(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, 1);
314 static int lease_parse_in_addrs_pairs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
315 return lease_parse_in_addrs_aux(option, len, ret, ret_size, 2);
318 static int class_prefixlen(uint8_t msb_octet, uint8_t *ret) {
322 else if (msb_octet < 192)
325 else if (msb_octet < 224)
329 /* Class D or E -- no subnet mask */
335 static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
336 size_t *routes_size, size_t *routes_allocated) {
343 assert(routes_allocated);
351 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + (len / 8)))
355 struct sd_dhcp_route *route = *routes + *routes_size;
357 if (class_prefixlen(*option, &route->dst_prefixlen) < 0) {
358 log_error("Failed to determine destination prefix length from class based IP, ignoring");
362 lease_parse_be32(option, 4, &addr.s_addr);
363 route->dst_addr = inet_makeaddr(inet_netof(addr), 0);
366 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
376 /* parses RFC3442 Classless Static Route Option */
377 static int lease_parse_classless_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
378 size_t *routes_size, size_t *routes_allocated) {
383 assert(routes_allocated);
385 /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */
389 struct sd_dhcp_route *route;
391 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1))
394 route = *routes + *routes_size;
396 dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1);
397 route->dst_prefixlen = *option;
401 /* can't have more than 4 octets in IPv4 */
402 if (dst_octets > 4 || len < dst_octets)
405 route->dst_addr.s_addr = 0;
406 memcpy(&route->dst_addr.s_addr, option, dst_octets);
407 option += dst_octets;
413 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
423 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
425 sd_dhcp_lease *lease = user_data;
432 case DHCP_OPTION_TIME_OFFSET:
433 lease_parse_s32(option, len, &lease->time_offset);
437 case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT:
438 lease_parse_u32(option, len, &lease->mtu_aging_timeout, 0);
442 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
443 lease_parse_u32(option, len, &lease->lifetime, 1);
447 case DHCP_OPTION_SERVER_IDENTIFIER:
448 lease_parse_be32(option, len, &lease->server_address);
452 case DHCP_OPTION_SUBNET_MASK:
453 lease_parse_be32(option, len, &lease->subnet_mask);
457 case DHCP_OPTION_BROADCAST:
458 lease_parse_be32(option, len, &lease->broadcast);
462 case DHCP_OPTION_ROUTER:
463 lease_parse_be32(option, len, &lease->router);
467 case DHCP_OPTION_DOMAIN_NAME_SERVER:
468 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
474 case DHCP_OPTION_NTP_SERVER:
475 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
481 case DHCP_OPTION_POLICY_FILTER:
482 r = lease_parse_in_addrs_pairs(option, len, &lease->policy_filter, &lease->policy_filter_size);
488 case DHCP_OPTION_STATIC_ROUTE:
489 r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size,
490 &lease->static_route_allocated);
496 case DHCP_OPTION_INTERFACE_MTU:
497 lease_parse_u16(option, len, &lease->mtu, 68);
501 case DHCP_OPTION_INTERFACE_MDR:
502 lease_parse_u16(option, len, &lease->mdr, 576);
506 case DHCP_OPTION_INTERFACE_TTL:
507 lease_parse_u8(option, len, &lease->ttl, 1);
511 case DHCP_OPTION_BOOT_FILE_SIZE:
512 lease_parse_u16(option, len, &lease->boot_file_size, 0);
516 case DHCP_OPTION_DOMAIN_NAME:
518 _cleanup_free_ char *domainname = NULL;
520 r = lease_parse_string(option, len, &domainname);
524 if (!hostname_is_valid(domainname) || is_localhost(domainname))
527 free(lease->domainname);
528 lease->domainname = domainname;
533 case DHCP_OPTION_HOST_NAME:
535 _cleanup_free_ char *hostname = NULL;
537 r = lease_parse_string(option, len, &hostname);
541 if (!hostname_is_valid(hostname) || is_localhost(hostname))
544 free(lease->hostname);
545 lease->hostname = hostname;
550 case DHCP_OPTION_ROOT_PATH:
551 r = lease_parse_string(option, len, &lease->root_path);
557 case DHCP_OPTION_RENEWAL_T1_TIME:
558 lease_parse_u32(option, len, &lease->t1, 1);
562 case DHCP_OPTION_REBINDING_T2_TIME:
563 lease_parse_u32(option, len, &lease->t2, 1);
567 case DHCP_OPTION_ENABLE_IP_FORWARDING:
568 lease_parse_bool(option, len, &lease->ip_forward);
572 case DHCP_OPTION_ENABLE_IP_FORWARDING_NL:
573 lease_parse_bool(option, len, &lease->ip_forward_non_local);
577 case DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
578 r = lease_parse_classless_routes(option, len, &lease->static_route, &lease->static_route_size,
579 &lease->static_route_allocated);
589 int dhcp_lease_new(sd_dhcp_lease **ret) {
590 sd_dhcp_lease *lease;
592 lease = new0(sd_dhcp_lease, 1);
596 lease->router = INADDR_ANY;
597 lease->n_ref = REFCNT_INIT;
603 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
604 _cleanup_free_ char *temp_path = NULL;
605 _cleanup_fclose_ FILE *f = NULL;
606 struct in_addr address;
607 const struct in_addr *addresses;
610 struct sd_dhcp_route *routes;
616 r = fopen_temporary(lease_file, &f, &temp_path);
620 fchmod(fileno(f), 0644);
622 r = sd_dhcp_lease_get_address(lease, &address);
627 "# This is private data. Do not parse.\n"
628 "ADDRESS=%s\n", inet_ntoa(address));
630 r = sd_dhcp_lease_get_netmask(lease, &address);
634 fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
636 r = sd_dhcp_lease_get_router(lease, &address);
638 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
640 r = sd_dhcp_lease_get_server_identifier(lease, &address);
642 fprintf(f, "SERVER_ADDRESS=%s\n",
645 r = sd_dhcp_lease_get_next_server(lease, &address);
647 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
649 r = sd_dhcp_lease_get_mtu(lease, &mtu);
651 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
654 r = sd_dhcp_lease_get_dns(lease, &addresses);
656 serialize_in_addrs(f, addresses, r);
660 r = sd_dhcp_lease_get_ntp(lease, &addresses);
662 serialize_in_addrs(f, addresses, r);
665 r = sd_dhcp_lease_get_domainname(lease, &string);
667 fprintf(f, "DOMAINNAME=%s\n", string);
669 r = sd_dhcp_lease_get_hostname(lease, &string);
671 fprintf(f, "HOSTNAME=%s\n", string);
673 r = sd_dhcp_lease_get_root_path(lease, &string);
675 fprintf(f, "ROOT_PATH=%s\n", string);
677 r = sd_dhcp_lease_get_routes(lease, &routes);
679 serialize_dhcp_routes(f, "ROUTES", routes, r);
685 if (ferror(f) || rename(temp_path, lease_file) < 0) {
693 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
698 int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
699 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
700 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
701 *server_address = NULL, *next_server = NULL,
702 *dns = NULL, *ntp = NULL, *mtu = NULL, *routes = NULL;
709 r = dhcp_lease_new(&lease);
713 r = parse_env_file(lease_file, NEWLINE,
717 "SERVER_IDENTIFIER", &server_address,
718 "NEXT_SERVER", &next_server,
722 "DOMAINNAME", &lease->domainname,
723 "HOSTNAME", &lease->hostname,
724 "ROOT_PATH", &lease->root_path,
731 log_error("Failed to read %s: %s", lease_file, strerror(-r));
735 r = inet_pton(AF_INET, address, &addr);
739 lease->address = addr.s_addr;
742 r = inet_pton(AF_INET, router, &addr);
746 lease->router = addr.s_addr;
749 r = inet_pton(AF_INET, netmask, &addr);
753 lease->subnet_mask = addr.s_addr;
755 if (server_address) {
756 r = inet_pton(AF_INET, server_address, &addr);
760 lease->server_address = addr.s_addr;
764 r = inet_pton(AF_INET, next_server, &addr);
768 lease->next_server = addr.s_addr;
772 r = deserialize_in_addrs(&lease->dns, dns);
780 r = deserialize_in_addrs(&lease->ntp, ntp);
789 if (sscanf(mtu, "%" SCNu16, &u) > 0)
794 r = deserialize_dhcp_routes(&lease->static_route, &lease->static_route_size,
795 &lease->static_route_allocated, routes);
806 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
807 struct in_addr address;
813 address.s_addr = lease->address;
815 /* fall back to the default subnet masks based on address class */
816 r = in_addr_default_subnet_mask(&address, &mask);
820 lease->subnet_mask = mask.s_addr;