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 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
176 assert_se(REFCNT_INC(lease->n_ref) >= 2);
181 sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
182 if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
183 free(lease->hostname);
184 free(lease->domainname);
193 static void lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
200 memcpy(&val, option, 4);
208 static void lease_parse_s32(const uint8_t *option, size_t len, int32_t *ret) {
209 lease_parse_u32(option, len, (uint32_t *)ret, 0);
212 static void lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
219 memcpy(&val, option, 2);
227 static void lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
232 memcpy(ret, option, 4);
235 static void lease_parse_bool(const uint8_t *option, size_t len, bool *ret) {
243 static void lease_parse_u8(const uint8_t *option, size_t len, uint8_t *ret, uint8_t min) {
255 static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
262 string = strndup((const char *)option, len);
273 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) {
278 if (len && !(len % (4 * mult))) {
280 struct in_addr *addresses;
284 addresses = newdup(struct in_addr, option, size);
296 static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
297 return lease_parse_in_addrs_aux(option, len, ret, ret_size, 1);
300 static int lease_parse_in_addrs_pairs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
301 return lease_parse_in_addrs_aux(option, len, ret, ret_size, 2);
304 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
306 sd_dhcp_lease *lease = user_data;
313 case DHCP_OPTION_TIME_OFFSET:
314 lease_parse_s32(option, len, &lease->time_offset);
318 case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT:
319 lease_parse_u32(option, len, &lease->mtu_aging_timeout, 0);
323 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
324 lease_parse_u32(option, len, &lease->lifetime, 1);
328 case DHCP_OPTION_SERVER_IDENTIFIER:
329 lease_parse_be32(option, len, &lease->server_address);
333 case DHCP_OPTION_SUBNET_MASK:
334 lease_parse_be32(option, len, &lease->subnet_mask);
338 case DHCP_OPTION_BROADCAST:
339 lease_parse_be32(option, len, &lease->broadcast);
343 case DHCP_OPTION_ROUTER:
344 lease_parse_be32(option, len, &lease->router);
348 case DHCP_OPTION_DOMAIN_NAME_SERVER:
349 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
355 case DHCP_OPTION_NTP_SERVER:
356 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
362 case DHCP_OPTION_POLICY_FILTER:
363 r = lease_parse_in_addrs_pairs(option, len, &lease->policy_filter, &lease->policy_filter_size);
369 case DHCP_OPTION_STATIC_ROUTE:
370 r = lease_parse_in_addrs_pairs(option, len, &lease->static_route, &lease->static_route_size);
376 case DHCP_OPTION_INTERFACE_MTU:
377 lease_parse_u16(option, len, &lease->mtu, 68);
381 case DHCP_OPTION_INTERFACE_MDR:
382 lease_parse_u16(option, len, &lease->mdr, 576);
386 case DHCP_OPTION_INTERFACE_TTL:
387 lease_parse_u8(option, len, &lease->ttl, 1);
391 case DHCP_OPTION_BOOT_FILE_SIZE:
392 lease_parse_u16(option, len, &lease->boot_file_size, 0);
396 case DHCP_OPTION_DOMAIN_NAME:
397 r = lease_parse_string(option, len, &lease->domainname);
403 case DHCP_OPTION_HOST_NAME:
404 r = lease_parse_string(option, len, &lease->hostname);
410 case DHCP_OPTION_ROOT_PATH:
411 r = lease_parse_string(option, len, &lease->root_path);
417 case DHCP_OPTION_RENEWAL_T1_TIME:
418 lease_parse_u32(option, len, &lease->t1, 1);
422 case DHCP_OPTION_REBINDING_T2_TIME:
423 lease_parse_u32(option, len, &lease->t2, 1);
427 case DHCP_OPTION_ENABLE_IP_FORWARDING:
428 lease_parse_bool(option, len, &lease->ip_forward);
432 case DHCP_OPTION_ENABLE_IP_FORWARDING_NL:
433 lease_parse_bool(option, len, &lease->ip_forward_non_local);
441 int dhcp_lease_new(sd_dhcp_lease **ret) {
442 sd_dhcp_lease *lease;
444 lease = new0(sd_dhcp_lease, 1);
448 lease->router = INADDR_ANY;
449 lease->n_ref = REFCNT_INIT;
455 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
456 _cleanup_free_ char *temp_path = NULL;
457 _cleanup_fclose_ FILE *f = NULL;
458 struct in_addr address;
459 struct in_addr *addresses;
460 size_t addresses_size;
468 r = fopen_temporary(lease_file, &f, &temp_path);
472 fchmod(fileno(f), 0644);
474 r = sd_dhcp_lease_get_address(lease, &address);
479 "# This is private data. Do not parse.\n"
480 "ADDRESS=%s\n", inet_ntoa(address));
482 r = sd_dhcp_lease_get_netmask(lease, &address);
486 fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
488 r = sd_dhcp_lease_get_router(lease, &address);
490 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
492 r = sd_dhcp_lease_get_server_identifier(lease, &address);
494 fprintf(f, "SERVER_ADDRESS=%s\n",
497 r = sd_dhcp_lease_get_next_server(lease, &address);
499 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
501 r = sd_dhcp_lease_get_mtu(lease, &mtu);
503 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
505 r = sd_dhcp_lease_get_dns(lease, &addresses, &addresses_size);
507 serialize_in_addrs(f, "DNS", addresses, addresses_size);
509 r = sd_dhcp_lease_get_ntp(lease, &addresses, &addresses_size);
511 serialize_in_addrs(f, "NTP", addresses, addresses_size);
513 r = sd_dhcp_lease_get_domainname(lease, &string);
515 fprintf(f, "DOMAINNAME=%s\n", string);
517 r = sd_dhcp_lease_get_hostname(lease, &string);
519 fprintf(f, "HOSTNAME=%s\n", string);
521 r = sd_dhcp_lease_get_root_path(lease, &string);
523 fprintf(f, "ROOT_PATH=%s\n", string);
529 if (ferror(f) || rename(temp_path, lease_file) < 0) {
537 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
542 int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
543 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
544 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
545 *server_address = NULL, *next_server = NULL,
546 *dns = NULL, *ntp = NULL, *mtu = NULL;
553 r = dhcp_lease_new(&lease);
557 r = parse_env_file(lease_file, NEWLINE,
561 "SERVER_IDENTIFIER", &server_address,
562 "NEXT_SERVER", &next_server,
566 "DOMAINNAME", &lease->domainname,
567 "HOSTNAME", &lease->hostname,
568 "ROOT_PATH", &lease->root_path,
574 log_error("Failed to read %s: %s", lease_file, strerror(-r));
578 r = inet_pton(AF_INET, address, &addr);
582 lease->address = addr.s_addr;
585 r = inet_pton(AF_INET, router, &addr);
589 lease->router = addr.s_addr;
592 r = inet_pton(AF_INET, netmask, &addr);
596 lease->subnet_mask = addr.s_addr;
598 if (server_address) {
599 r = inet_pton(AF_INET, server_address, &addr);
603 lease->server_address = addr.s_addr;
607 r = inet_pton(AF_INET, next_server, &addr);
611 lease->next_server = addr.s_addr;
615 r = deserialize_in_addrs(&lease->dns, &lease->dns_size, dns);
621 r = deserialize_in_addrs(&lease->ntp, &lease->ntp_size, dns);
628 if (sscanf(mtu, "%" SCNu16, &u) > 0)
638 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
642 assert(lease->address != INADDR_ANY);
644 address = be32toh(lease->address);
646 /* fall back to the default subnet masks based on address class */
648 if ((address >> 31) == 0x0)
649 /* class A, leading bits: 0 */
650 lease->subnet_mask = htobe32(0xff000000);
651 else if ((address >> 30) == 0x2)
652 /* class B, leading bits 10 */
653 lease->subnet_mask = htobe32(0xffff0000);
654 else if ((address >> 29) == 0x6)
655 /* class C, leading bits 110 */
656 lease->subnet_mask = htobe32(0xffffff00);
658 /* class D or E, no default mask. give up */