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"
40 int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
41 assert_return(lease, -EINVAL);
42 assert_return(addr, -EINVAL);
44 addr->s_addr = lease->address;
49 int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
50 assert_return(lease, -EINVAL);
51 assert_return(mtu, -EINVAL);
61 int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, struct in_addr **addr, size_t *addr_size) {
62 assert_return(lease, -EINVAL);
63 assert_return(addr, -EINVAL);
64 assert_return(addr_size, -EINVAL);
66 if (lease->dns_size) {
67 *addr_size = lease->dns_size;
75 int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, struct in_addr **addr, size_t *addr_size) {
76 assert_return(lease, -EINVAL);
77 assert_return(addr, -EINVAL);
78 assert_return(addr_size, -EINVAL);
80 if (lease->ntp_size) {
81 *addr_size = lease->ntp_size;
89 int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
90 assert_return(lease, -EINVAL);
91 assert_return(domainname, -EINVAL);
93 if (lease->domainname)
94 *domainname = lease->domainname;
101 int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
102 assert_return(lease, -EINVAL);
103 assert_return(hostname, -EINVAL);
106 *hostname = lease->hostname;
113 int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
114 assert_return(lease, -EINVAL);
115 assert_return(root_path, -EINVAL);
117 if (lease->root_path)
118 *root_path = lease->root_path;
125 int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) {
126 assert_return(lease, -EINVAL);
127 assert_return(addr, -EINVAL);
129 addr->s_addr = lease->router;
134 int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
135 assert_return(lease, -EINVAL);
136 assert_return(addr, -EINVAL);
138 addr->s_addr = lease->subnet_mask;
143 int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
144 assert_return(lease, -EINVAL);
145 assert_return(addr, -EINVAL);
147 addr->s_addr = lease->server_address;
152 int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
153 assert_return(lease, -EINVAL);
154 assert_return(addr, -EINVAL);
156 addr->s_addr = lease->next_server;
161 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
163 assert_se(REFCNT_INC(lease->n_ref) >= 2);
168 sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
169 if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
170 free(lease->hostname);
171 free(lease->domainname);
179 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
181 sd_dhcp_lease *lease = user_data;
186 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
188 memcpy(&val, option, 4);
189 lease->lifetime = be32toh(val);
194 case DHCP_OPTION_SERVER_IDENTIFIER:
196 memcpy(&lease->server_address, option, 4);
200 case DHCP_OPTION_SUBNET_MASK:
202 memcpy(&lease->subnet_mask, option, 4);
206 case DHCP_OPTION_ROUTER:
208 memcpy(&lease->router, option, 4);
212 case DHCP_OPTION_DOMAIN_NAME_SERVER:
213 if (len && !(len % 4)) {
214 lease->dns_size = len / 4;
217 lease->dns = newdup(struct in_addr, option, lease->dns_size);
224 case DHCP_OPTION_NTP_SERVER:
225 if (len && !(len % 4)) {
226 lease->ntp_size = len / 4;
229 lease->ntp = newdup(struct in_addr, option, lease->ntp_size);
236 case DHCP_OPTION_INTERFACE_MTU:
240 memcpy(&mtu, option, 2);
241 lease->mtu = be16toh(mtu);
249 case DHCP_OPTION_DOMAIN_NAME:
251 free(lease->domainname);
252 lease->domainname = strndup((const char *)option, len);
257 case DHCP_OPTION_HOST_NAME:
259 free(lease->hostname);
260 lease->hostname = strndup((const char *)option, len);
265 case DHCP_OPTION_ROOT_PATH:
267 free(lease->root_path);
268 lease->root_path = strndup((const char *)option, len);
273 case DHCP_OPTION_RENEWAL_T1_TIME:
275 memcpy(&val, option, 4);
276 lease->t1 = be32toh(val);
281 case DHCP_OPTION_REBINDING_T2_TIME:
283 memcpy(&val, option, 4);
284 lease->t2 = be32toh(val);
293 int dhcp_lease_new(sd_dhcp_lease **ret) {
294 sd_dhcp_lease *lease;
296 lease = new0(sd_dhcp_lease, 1);
300 lease->n_ref = REFCNT_INIT;
306 static void serialize_addresses(FILE *f, const char *key, struct in_addr *addresses, size_t size) {
315 for (i = 0; i < size; i++)
316 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
317 (i < (size - 1)) ? " ": "");
322 static int deserialize_addresses(struct in_addr **addresses, size_t *size, const char *string) {
326 FOREACH_WORD(word, len, string, state) {
327 struct in_addr *new_addresses;
330 new_addresses = realloc(*addresses, (*size + 1) * sizeof(struct in_addr));
334 *addresses = new_addresses;
336 r = inet_aton(word, &(new_addresses[*size]));
346 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
347 _cleanup_free_ char *temp_path = NULL;
348 _cleanup_fclose_ FILE *f = NULL;
349 struct in_addr address;
350 struct in_addr *addresses;
351 size_t addresses_size;
359 r = fopen_temporary(lease_file, &f, &temp_path);
363 fchmod(fileno(f), 0644);
365 r = sd_dhcp_lease_get_address(lease, &address);
370 "# This is private data. Do not parse.\n"
371 "ADDRESS=%s\n", inet_ntoa(address));
373 r = sd_dhcp_lease_get_router(lease, &address);
377 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
379 r = sd_dhcp_lease_get_netmask(lease, &address);
383 fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
385 r = sd_dhcp_lease_get_server_identifier(lease, &address);
387 fprintf(f, "SERVER_ADDRESS=%s\n",
390 r = sd_dhcp_lease_get_next_server(lease, &address);
392 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
394 r = sd_dhcp_lease_get_mtu(lease, &mtu);
396 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
398 r = sd_dhcp_lease_get_dns(lease, &addresses, &addresses_size);
400 serialize_addresses(f, "DNS", addresses, addresses_size);
402 r = sd_dhcp_lease_get_ntp(lease, &addresses, &addresses_size);
404 serialize_addresses(f, "NTP", addresses, addresses_size);
406 r = sd_dhcp_lease_get_domainname(lease, &string);
408 fprintf(f, "DOMAINNAME=%s\n", string);
410 r = sd_dhcp_lease_get_hostname(lease, &string);
412 fprintf(f, "HOSTNAME=%s\n", string);
414 r = sd_dhcp_lease_get_root_path(lease, &string);
416 fprintf(f, "ROOT_PATH=%s\n", string);
422 if (ferror(f) || rename(temp_path, lease_file) < 0) {
430 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
435 int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
436 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
437 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
438 *server_address = NULL, *next_server = NULL,
439 *dns = NULL, *ntp = NULL, *mtu = NULL;
446 r = dhcp_lease_new(&lease);
450 r = parse_env_file(lease_file, NEWLINE,
454 "SERVER_IDENTIFIER", &server_address,
455 "NEXT_SERVER", &next_server,
459 "DOMAINNAME", &lease->domainname,
460 "HOSTNAME", &lease->hostname,
461 "ROOT_PATH", &lease->root_path,
467 log_error("Failed to read %s: %s", lease_file, strerror(-r));
471 r = inet_pton(AF_INET, address, &addr);
475 lease->address = addr.s_addr;
477 r = inet_pton(AF_INET, router, &addr);
481 lease->router = addr.s_addr;
483 r = inet_pton(AF_INET, netmask, &addr);
487 lease->subnet_mask = addr.s_addr;
489 if (server_address) {
490 r = inet_pton(AF_INET, server_address, &addr);
494 lease->server_address = addr.s_addr;
498 r = inet_pton(AF_INET, next_server, &addr);
502 lease->next_server = addr.s_addr;
506 r = deserialize_addresses(&lease->dns, &lease->dns_size, dns);
512 r = deserialize_addresses(&lease->ntp, &lease->ntp_size, dns);
519 if (sscanf(mtu, "%" SCNu16, &u) > 0)
529 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
533 assert(lease->address != INADDR_ANY);
535 address = be32toh(lease->address);
537 /* fall back to the default subnet masks based on address class */
539 if ((address >> 31) == 0x0)
540 /* class A, leading bits: 0 */
541 lease->subnet_mask = htobe32(0xff000000);
542 else if ((address >> 30) == 0x2)
543 /* class B, leading bits 10 */
544 lease->subnet_mask = htobe32(0xffff0000);
545 else if ((address >> 29) == 0x6)
546 /* class C, leading bits 110 */
547 lease->subnet_mask = htobe32(0xffffff00);
549 /* class D or E, no default mask. give up */