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>
34 #include "dhcp-protocol.h"
35 #include "dhcp-internal.h"
36 #include "dhcp-lease-internal.h"
37 #include "sd-dhcp-lease.h"
38 #include "sd-dhcp-client.h"
39 #include "network-internal.h"
41 int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
42 assert_return(lease, -EINVAL);
43 assert_return(addr, -EINVAL);
45 addr->s_addr = lease->address;
50 int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
51 assert_return(lease, -EINVAL);
52 assert_return(lease, -EINVAL);
54 *lifetime = lease->lifetime;
59 int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
60 assert_return(lease, -EINVAL);
61 assert_return(mtu, -EINVAL);
71 int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, struct in_addr **addr, size_t *addr_size) {
72 assert_return(lease, -EINVAL);
73 assert_return(addr, -EINVAL);
74 assert_return(addr_size, -EINVAL);
76 if (lease->dns_size) {
77 *addr_size = lease->dns_size;
85 int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, struct in_addr **addr, size_t *addr_size) {
86 assert_return(lease, -EINVAL);
87 assert_return(addr, -EINVAL);
88 assert_return(addr_size, -EINVAL);
90 if (lease->ntp_size) {
91 *addr_size = 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,
175 size_t *routes_size) {
177 assert_return(lease, -EINVAL);
178 assert_return(routes, -EINVAL);
179 assert_return(routes_size, -EINVAL);
181 if (lease->static_route_size) {
182 *routes = lease->static_route;
183 *routes_size = lease->static_route_size;
190 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
192 assert_se(REFCNT_INC(lease->n_ref) >= 2);
197 sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
198 if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
199 free(lease->hostname);
200 free(lease->domainname);
203 free(lease->static_route);
210 static void lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
217 memcpy(&val, option, 4);
225 static void lease_parse_s32(const uint8_t *option, size_t len, int32_t *ret) {
226 lease_parse_u32(option, len, (uint32_t *)ret, 0);
229 static void lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
236 memcpy(&val, option, 2);
244 static void lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
249 memcpy(ret, option, 4);
252 static void lease_parse_bool(const uint8_t *option, size_t len, bool *ret) {
260 static void lease_parse_u8(const uint8_t *option, size_t len, uint8_t *ret, uint8_t min) {
272 static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
279 string = strndup((const char *)option, len);
290 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) {
295 if (len && !(len % (4 * mult))) {
297 struct in_addr *addresses;
301 addresses = newdup(struct in_addr, option, size);
313 static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
314 return lease_parse_in_addrs_aux(option, len, ret, ret_size, 1);
317 static int lease_parse_in_addrs_pairs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
318 return lease_parse_in_addrs_aux(option, len, ret, ret_size, 2);
321 static int class_prefixlen(uint8_t msb_octet, uint8_t *ret) {
325 else if (msb_octet < 192)
328 else if (msb_octet < 224)
332 /* Class D or E -- no subnet mask */
338 static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
339 size_t *routes_size, size_t *routes_allocated) {
346 assert(routes_allocated);
354 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + (len / 8)))
358 struct sd_dhcp_route *route = *routes + *routes_size;
360 if (class_prefixlen(*option, &route->dst_prefixlen) < 0) {
361 log_error("Failed to determine destination prefix length from class based IP, ignoring");
365 lease_parse_be32(option, 4, &addr.s_addr);
366 route->dst_addr = inet_makeaddr(inet_netof(addr), 0);
369 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
379 /* parses RFC3442 Classless Static Route Option */
380 static int lease_parse_classless_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
381 size_t *routes_size, size_t *routes_allocated) {
386 assert(routes_allocated);
388 /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */
392 struct sd_dhcp_route *route;
394 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1))
397 route = *routes + *routes_size;
399 dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1);
400 route->dst_prefixlen = *option;
404 /* can't have more than 4 octets in IPv4 */
405 if (dst_octets > 4 || len < dst_octets)
408 route->dst_addr.s_addr = 0;
409 memcpy(&route->dst_addr.s_addr, option, dst_octets);
410 option += dst_octets;
416 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
426 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
428 sd_dhcp_lease *lease = user_data;
435 case DHCP_OPTION_TIME_OFFSET:
436 lease_parse_s32(option, len, &lease->time_offset);
440 case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT:
441 lease_parse_u32(option, len, &lease->mtu_aging_timeout, 0);
445 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
446 lease_parse_u32(option, len, &lease->lifetime, 1);
450 case DHCP_OPTION_SERVER_IDENTIFIER:
451 lease_parse_be32(option, len, &lease->server_address);
455 case DHCP_OPTION_SUBNET_MASK:
456 lease_parse_be32(option, len, &lease->subnet_mask);
460 case DHCP_OPTION_BROADCAST:
461 lease_parse_be32(option, len, &lease->broadcast);
465 case DHCP_OPTION_ROUTER:
466 lease_parse_be32(option, len, &lease->router);
470 case DHCP_OPTION_DOMAIN_NAME_SERVER:
471 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
477 case DHCP_OPTION_NTP_SERVER:
478 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
484 case DHCP_OPTION_POLICY_FILTER:
485 r = lease_parse_in_addrs_pairs(option, len, &lease->policy_filter, &lease->policy_filter_size);
491 case DHCP_OPTION_STATIC_ROUTE:
492 r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size,
493 &lease->static_route_allocated);
499 case DHCP_OPTION_INTERFACE_MTU:
500 lease_parse_u16(option, len, &lease->mtu, 68);
504 case DHCP_OPTION_INTERFACE_MDR:
505 lease_parse_u16(option, len, &lease->mdr, 576);
509 case DHCP_OPTION_INTERFACE_TTL:
510 lease_parse_u8(option, len, &lease->ttl, 1);
514 case DHCP_OPTION_BOOT_FILE_SIZE:
515 lease_parse_u16(option, len, &lease->boot_file_size, 0);
519 case DHCP_OPTION_DOMAIN_NAME:
520 r = lease_parse_string(option, len, &lease->domainname);
526 case DHCP_OPTION_HOST_NAME:
527 r = lease_parse_string(option, len, &lease->hostname);
533 case DHCP_OPTION_ROOT_PATH:
534 r = lease_parse_string(option, len, &lease->root_path);
540 case DHCP_OPTION_RENEWAL_T1_TIME:
541 lease_parse_u32(option, len, &lease->t1, 1);
545 case DHCP_OPTION_REBINDING_T2_TIME:
546 lease_parse_u32(option, len, &lease->t2, 1);
550 case DHCP_OPTION_ENABLE_IP_FORWARDING:
551 lease_parse_bool(option, len, &lease->ip_forward);
555 case DHCP_OPTION_ENABLE_IP_FORWARDING_NL:
556 lease_parse_bool(option, len, &lease->ip_forward_non_local);
560 case DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
561 r = lease_parse_classless_routes(option, len, &lease->static_route, &lease->static_route_size,
562 &lease->static_route_allocated);
572 int dhcp_lease_new(sd_dhcp_lease **ret) {
573 sd_dhcp_lease *lease;
575 lease = new0(sd_dhcp_lease, 1);
579 lease->router = INADDR_ANY;
580 lease->n_ref = REFCNT_INIT;
586 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
587 _cleanup_free_ char *temp_path = NULL;
588 _cleanup_fclose_ FILE *f = NULL;
589 struct in_addr address;
590 struct in_addr *addresses;
591 size_t addresses_size;
594 struct sd_dhcp_route *routes;
601 r = fopen_temporary(lease_file, &f, &temp_path);
605 fchmod(fileno(f), 0644);
607 r = sd_dhcp_lease_get_address(lease, &address);
612 "# This is private data. Do not parse.\n"
613 "ADDRESS=%s\n", inet_ntoa(address));
615 r = sd_dhcp_lease_get_netmask(lease, &address);
619 fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
621 r = sd_dhcp_lease_get_router(lease, &address);
623 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
625 r = sd_dhcp_lease_get_server_identifier(lease, &address);
627 fprintf(f, "SERVER_ADDRESS=%s\n",
630 r = sd_dhcp_lease_get_next_server(lease, &address);
632 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
634 r = sd_dhcp_lease_get_mtu(lease, &mtu);
636 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
638 r = sd_dhcp_lease_get_dns(lease, &addresses, &addresses_size);
640 serialize_in_addrs(f, "DNS", addresses, addresses_size);
642 r = sd_dhcp_lease_get_ntp(lease, &addresses, &addresses_size);
644 serialize_in_addrs(f, "NTP", addresses, addresses_size);
646 r = sd_dhcp_lease_get_domainname(lease, &string);
648 fprintf(f, "DOMAINNAME=%s\n", string);
650 r = sd_dhcp_lease_get_hostname(lease, &string);
652 fprintf(f, "HOSTNAME=%s\n", string);
654 r = sd_dhcp_lease_get_root_path(lease, &string);
656 fprintf(f, "ROOT_PATH=%s\n", string);
658 r = sd_dhcp_lease_get_routes(lease, &routes, &routes_size);
660 serialize_dhcp_routes(f, "ROUTES", routes, routes_size);
666 if (ferror(f) || rename(temp_path, lease_file) < 0) {
674 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
679 int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
680 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
681 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
682 *server_address = NULL, *next_server = NULL,
683 *dns = NULL, *ntp = NULL, *mtu = NULL, *routes = NULL;
690 r = dhcp_lease_new(&lease);
694 r = parse_env_file(lease_file, NEWLINE,
698 "SERVER_IDENTIFIER", &server_address,
699 "NEXT_SERVER", &next_server,
703 "DOMAINNAME", &lease->domainname,
704 "HOSTNAME", &lease->hostname,
705 "ROOT_PATH", &lease->root_path,
712 log_error("Failed to read %s: %s", lease_file, strerror(-r));
716 r = inet_pton(AF_INET, address, &addr);
720 lease->address = addr.s_addr;
723 r = inet_pton(AF_INET, router, &addr);
727 lease->router = addr.s_addr;
730 r = inet_pton(AF_INET, netmask, &addr);
734 lease->subnet_mask = addr.s_addr;
736 if (server_address) {
737 r = inet_pton(AF_INET, server_address, &addr);
741 lease->server_address = addr.s_addr;
745 r = inet_pton(AF_INET, next_server, &addr);
749 lease->next_server = addr.s_addr;
753 r = deserialize_in_addrs(&lease->dns, &lease->dns_size, dns);
759 r = deserialize_in_addrs(&lease->ntp, &lease->ntp_size, dns);
766 if (sscanf(mtu, "%" SCNu16, &u) > 0)
771 r = deserialize_dhcp_routes(&lease->static_route, &lease->static_route_size,
772 &lease->static_route_allocated, routes);
783 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
787 assert(lease->address != INADDR_ANY);
789 address = be32toh(lease->address);
791 /* fall back to the default subnet masks based on address class */
793 if ((address >> 31) == 0x0)
794 /* class A, leading bits: 0 */
795 lease->subnet_mask = htobe32(0xff000000);
796 else if ((address >> 30) == 0x2)
797 /* class B, leading bits 10 */
798 lease->subnet_mask = htobe32(0xffff0000);
799 else if ((address >> 29) == 0x6)
800 /* class C, leading bits 110 */
801 lease->subnet_mask = htobe32(0xffffff00);
803 /* class D or E, no default mask. give up */