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, const struct in_addr **addr) {
72 assert_return(lease, -EINVAL);
73 assert_return(addr, -EINVAL);
75 if (lease->dns_size) {
77 return lease->dns_size;
84 int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) {
85 assert_return(lease, -EINVAL);
86 assert_return(addr, -EINVAL);
88 if (lease->ntp_size) {
90 return lease->ntp_size;
97 int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
98 assert_return(lease, -EINVAL);
99 assert_return(domainname, -EINVAL);
101 if (lease->domainname)
102 *domainname = lease->domainname;
109 int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
110 assert_return(lease, -EINVAL);
111 assert_return(hostname, -EINVAL);
114 *hostname = lease->hostname;
121 int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
122 assert_return(lease, -EINVAL);
123 assert_return(root_path, -EINVAL);
125 if (lease->root_path)
126 *root_path = lease->root_path;
133 int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) {
134 assert_return(lease, -EINVAL);
135 assert_return(addr, -EINVAL);
137 if (lease->router != INADDR_ANY)
138 addr->s_addr = lease->router;
145 int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
146 assert_return(lease, -EINVAL);
147 assert_return(addr, -EINVAL);
149 addr->s_addr = lease->subnet_mask;
154 int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
155 assert_return(lease, -EINVAL);
156 assert_return(addr, -EINVAL);
158 addr->s_addr = lease->server_address;
163 int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
164 assert_return(lease, -EINVAL);
165 assert_return(addr, -EINVAL);
167 addr->s_addr = lease->next_server;
172 int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes) {
174 assert_return(lease, -EINVAL);
175 assert_return(routes, -EINVAL);
177 if (lease->static_route_size) {
178 *routes = lease->static_route;
179 return lease->static_route_size;
186 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
188 assert_se(REFCNT_INC(lease->n_ref) >= 2);
193 sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
194 if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
195 free(lease->hostname);
196 free(lease->domainname);
199 free(lease->static_route);
206 static void lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
213 memcpy(&val, option, 4);
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) {
232 memcpy(&val, option, 2);
240 static void lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
245 memcpy(ret, option, 4);
248 static void lease_parse_bool(const uint8_t *option, size_t len, bool *ret) {
256 static void lease_parse_u8(const uint8_t *option, size_t len, uint8_t *ret, uint8_t min) {
268 static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
275 string = strndup((const char *)option, len);
286 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) {
291 if (len && !(len % (4 * mult))) {
293 struct in_addr *addresses;
297 addresses = newdup(struct in_addr, option, size);
309 static int lease_parse_in_addrs(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, 1);
313 static int lease_parse_in_addrs_pairs(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, 2);
317 static int class_prefixlen(uint8_t msb_octet, uint8_t *ret) {
321 else if (msb_octet < 192)
324 else if (msb_octet < 224)
328 /* Class D or E -- no subnet mask */
334 static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
335 size_t *routes_size, size_t *routes_allocated) {
342 assert(routes_allocated);
350 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + (len / 8)))
354 struct sd_dhcp_route *route = *routes + *routes_size;
356 if (class_prefixlen(*option, &route->dst_prefixlen) < 0) {
357 log_error("Failed to determine destination prefix length from class based IP, ignoring");
361 lease_parse_be32(option, 4, &addr.s_addr);
362 route->dst_addr = inet_makeaddr(inet_netof(addr), 0);
365 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
375 /* parses RFC3442 Classless Static Route Option */
376 static int lease_parse_classless_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
377 size_t *routes_size, size_t *routes_allocated) {
382 assert(routes_allocated);
384 /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */
388 struct sd_dhcp_route *route;
390 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1))
393 route = *routes + *routes_size;
395 dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1);
396 route->dst_prefixlen = *option;
400 /* can't have more than 4 octets in IPv4 */
401 if (dst_octets > 4 || len < dst_octets)
404 route->dst_addr.s_addr = 0;
405 memcpy(&route->dst_addr.s_addr, option, dst_octets);
406 option += dst_octets;
412 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
422 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
424 sd_dhcp_lease *lease = user_data;
431 case DHCP_OPTION_TIME_OFFSET:
432 lease_parse_s32(option, len, &lease->time_offset);
436 case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT:
437 lease_parse_u32(option, len, &lease->mtu_aging_timeout, 0);
441 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
442 lease_parse_u32(option, len, &lease->lifetime, 1);
446 case DHCP_OPTION_SERVER_IDENTIFIER:
447 lease_parse_be32(option, len, &lease->server_address);
451 case DHCP_OPTION_SUBNET_MASK:
452 lease_parse_be32(option, len, &lease->subnet_mask);
456 case DHCP_OPTION_BROADCAST:
457 lease_parse_be32(option, len, &lease->broadcast);
461 case DHCP_OPTION_ROUTER:
462 lease_parse_be32(option, len, &lease->router);
466 case DHCP_OPTION_DOMAIN_NAME_SERVER:
467 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
473 case DHCP_OPTION_NTP_SERVER:
474 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
480 case DHCP_OPTION_POLICY_FILTER:
481 r = lease_parse_in_addrs_pairs(option, len, &lease->policy_filter, &lease->policy_filter_size);
487 case DHCP_OPTION_STATIC_ROUTE:
488 r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size,
489 &lease->static_route_allocated);
495 case DHCP_OPTION_INTERFACE_MTU:
496 lease_parse_u16(option, len, &lease->mtu, 68);
500 case DHCP_OPTION_INTERFACE_MDR:
501 lease_parse_u16(option, len, &lease->mdr, 576);
505 case DHCP_OPTION_INTERFACE_TTL:
506 lease_parse_u8(option, len, &lease->ttl, 1);
510 case DHCP_OPTION_BOOT_FILE_SIZE:
511 lease_parse_u16(option, len, &lease->boot_file_size, 0);
515 case DHCP_OPTION_DOMAIN_NAME:
517 _cleanup_free_ char *domainname = NULL;
519 r = lease_parse_string(option, len, &domainname);
523 if (!hostname_is_valid(domainname) || is_localhost(domainname))
526 free(lease->domainname);
527 lease->domainname = domainname;
532 case DHCP_OPTION_HOST_NAME:
534 _cleanup_free_ char *hostname = NULL;
536 r = lease_parse_string(option, len, &hostname);
540 if (!hostname_is_valid(hostname) || is_localhost(hostname))
543 free(lease->hostname);
544 lease->hostname = hostname;
549 case DHCP_OPTION_ROOT_PATH:
550 r = lease_parse_string(option, len, &lease->root_path);
556 case DHCP_OPTION_RENEWAL_T1_TIME:
557 lease_parse_u32(option, len, &lease->t1, 1);
561 case DHCP_OPTION_REBINDING_T2_TIME:
562 lease_parse_u32(option, len, &lease->t2, 1);
566 case DHCP_OPTION_ENABLE_IP_FORWARDING:
567 lease_parse_bool(option, len, &lease->ip_forward);
571 case DHCP_OPTION_ENABLE_IP_FORWARDING_NL:
572 lease_parse_bool(option, len, &lease->ip_forward_non_local);
576 case DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
577 r = lease_parse_classless_routes(option, len, &lease->static_route, &lease->static_route_size,
578 &lease->static_route_allocated);
588 int dhcp_lease_new(sd_dhcp_lease **ret) {
589 sd_dhcp_lease *lease;
591 lease = new0(sd_dhcp_lease, 1);
595 lease->router = INADDR_ANY;
596 lease->n_ref = REFCNT_INIT;
602 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
603 _cleanup_free_ char *temp_path = NULL;
604 _cleanup_fclose_ FILE *f = NULL;
605 struct in_addr address;
606 const struct in_addr *addresses;
609 struct sd_dhcp_route *routes;
615 r = fopen_temporary(lease_file, &f, &temp_path);
619 fchmod(fileno(f), 0644);
621 r = sd_dhcp_lease_get_address(lease, &address);
626 "# This is private data. Do not parse.\n"
627 "ADDRESS=%s\n", inet_ntoa(address));
629 r = sd_dhcp_lease_get_netmask(lease, &address);
633 fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
635 r = sd_dhcp_lease_get_router(lease, &address);
637 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
639 r = sd_dhcp_lease_get_server_identifier(lease, &address);
641 fprintf(f, "SERVER_ADDRESS=%s\n",
644 r = sd_dhcp_lease_get_next_server(lease, &address);
646 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
648 r = sd_dhcp_lease_get_mtu(lease, &mtu);
650 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
653 r = sd_dhcp_lease_get_dns(lease, &addresses);
655 serialize_in_addrs(f, addresses, r);
659 r = sd_dhcp_lease_get_ntp(lease, &addresses);
661 serialize_in_addrs(f, addresses, r);
664 r = sd_dhcp_lease_get_domainname(lease, &string);
666 fprintf(f, "DOMAINNAME=%s\n", string);
668 r = sd_dhcp_lease_get_hostname(lease, &string);
670 fprintf(f, "HOSTNAME=%s\n", string);
672 r = sd_dhcp_lease_get_root_path(lease, &string);
674 fprintf(f, "ROOT_PATH=%s\n", string);
676 r = sd_dhcp_lease_get_routes(lease, &routes);
678 serialize_dhcp_routes(f, "ROUTES", routes, r);
684 if (ferror(f) || rename(temp_path, lease_file) < 0) {
692 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
697 int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
698 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
699 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
700 *server_address = NULL, *next_server = NULL,
701 *dns = NULL, *ntp = NULL, *mtu = NULL, *routes = NULL;
708 r = dhcp_lease_new(&lease);
712 r = parse_env_file(lease_file, NEWLINE,
716 "SERVER_IDENTIFIER", &server_address,
717 "NEXT_SERVER", &next_server,
721 "DOMAINNAME", &lease->domainname,
722 "HOSTNAME", &lease->hostname,
723 "ROOT_PATH", &lease->root_path,
730 log_error("Failed to read %s: %s", lease_file, strerror(-r));
734 r = inet_pton(AF_INET, address, &addr);
738 lease->address = addr.s_addr;
741 r = inet_pton(AF_INET, router, &addr);
745 lease->router = addr.s_addr;
748 r = inet_pton(AF_INET, netmask, &addr);
752 lease->subnet_mask = addr.s_addr;
754 if (server_address) {
755 r = inet_pton(AF_INET, server_address, &addr);
759 lease->server_address = addr.s_addr;
763 r = inet_pton(AF_INET, next_server, &addr);
767 lease->next_server = addr.s_addr;
771 r = deserialize_in_addrs(&lease->dns, dns);
779 r = deserialize_in_addrs(&lease->ntp, ntp);
788 if (sscanf(mtu, "%" SCNu16, &u) > 0)
793 r = deserialize_dhcp_routes(&lease->static_route, &lease->static_route_size,
794 &lease->static_route_allocated, routes);
805 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
809 assert(lease->address != INADDR_ANY);
811 address = be32toh(lease->address);
813 /* fall back to the default subnet masks based on address class */
815 if ((address >> 31) == 0x0)
816 /* class A, leading bits: 0 */
817 lease->subnet_mask = htobe32(0xff000000);
818 else if ((address >> 30) == 0x2)
819 /* class B, leading bits 10 */
820 lease->subnet_mask = htobe32(0xffff0000);
821 else if ((address >> 29) == 0x6)
822 /* class C, leading bits 110 */
823 lease->subnet_mask = htobe32(0xffffff00);
825 /* class D or E, no default mask. give up */