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 if (lease->router != INADDR_ANY)
130 addr->s_addr = lease->router;
137 int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
138 assert_return(lease, -EINVAL);
139 assert_return(addr, -EINVAL);
141 addr->s_addr = lease->subnet_mask;
146 int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
147 assert_return(lease, -EINVAL);
148 assert_return(addr, -EINVAL);
150 addr->s_addr = lease->server_address;
155 int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
156 assert_return(lease, -EINVAL);
157 assert_return(addr, -EINVAL);
159 addr->s_addr = lease->next_server;
164 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
166 assert_se(REFCNT_INC(lease->n_ref) >= 2);
171 sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
172 if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
173 free(lease->hostname);
174 free(lease->domainname);
182 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
184 sd_dhcp_lease *lease = user_data;
189 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
191 memcpy(&val, option, 4);
192 lease->lifetime = be32toh(val);
197 case DHCP_OPTION_SERVER_IDENTIFIER:
199 memcpy(&lease->server_address, option, 4);
203 case DHCP_OPTION_SUBNET_MASK:
205 memcpy(&lease->subnet_mask, option, 4);
209 case DHCP_OPTION_ROUTER:
211 memcpy(&lease->router, option, 4);
215 case DHCP_OPTION_DOMAIN_NAME_SERVER:
216 if (len && !(len % 4)) {
217 lease->dns_size = len / 4;
220 lease->dns = newdup(struct in_addr, option, lease->dns_size);
227 case DHCP_OPTION_NTP_SERVER:
228 if (len && !(len % 4)) {
229 lease->ntp_size = len / 4;
232 lease->ntp = newdup(struct in_addr, option, lease->ntp_size);
239 case DHCP_OPTION_INTERFACE_MTU:
243 memcpy(&mtu, option, 2);
244 lease->mtu = be16toh(mtu);
252 case DHCP_OPTION_DOMAIN_NAME:
254 free(lease->domainname);
255 lease->domainname = strndup((const char *)option, len);
260 case DHCP_OPTION_HOST_NAME:
262 free(lease->hostname);
263 lease->hostname = strndup((const char *)option, len);
268 case DHCP_OPTION_ROOT_PATH:
270 free(lease->root_path);
271 lease->root_path = strndup((const char *)option, len);
276 case DHCP_OPTION_RENEWAL_T1_TIME:
278 memcpy(&val, option, 4);
279 lease->t1 = be32toh(val);
284 case DHCP_OPTION_REBINDING_T2_TIME:
286 memcpy(&val, option, 4);
287 lease->t2 = be32toh(val);
296 int dhcp_lease_new(sd_dhcp_lease **ret) {
297 sd_dhcp_lease *lease;
299 lease = new0(sd_dhcp_lease, 1);
303 lease->router = INADDR_ANY;
304 lease->n_ref = REFCNT_INIT;
310 static void serialize_addresses(FILE *f, const char *key, struct in_addr *addresses, size_t size) {
319 for (i = 0; i < size; i++)
320 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
321 (i < (size - 1)) ? " ": "");
326 static int deserialize_addresses(struct in_addr **addresses, size_t *size, const char *string) {
330 FOREACH_WORD(word, len, string, state) {
331 struct in_addr *new_addresses;
334 new_addresses = realloc(*addresses, (*size + 1) * sizeof(struct in_addr));
338 *addresses = new_addresses;
340 r = inet_aton(word, &(new_addresses[*size]));
350 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
351 _cleanup_free_ char *temp_path = NULL;
352 _cleanup_fclose_ FILE *f = NULL;
353 struct in_addr address;
354 struct in_addr *addresses;
355 size_t addresses_size;
363 r = fopen_temporary(lease_file, &f, &temp_path);
367 fchmod(fileno(f), 0644);
369 r = sd_dhcp_lease_get_address(lease, &address);
374 "# This is private data. Do not parse.\n"
375 "ADDRESS=%s\n", inet_ntoa(address));
377 r = sd_dhcp_lease_get_netmask(lease, &address);
381 fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
383 r = sd_dhcp_lease_get_router(lease, &address);
385 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
387 r = sd_dhcp_lease_get_server_identifier(lease, &address);
389 fprintf(f, "SERVER_ADDRESS=%s\n",
392 r = sd_dhcp_lease_get_next_server(lease, &address);
394 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
396 r = sd_dhcp_lease_get_mtu(lease, &mtu);
398 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
400 r = sd_dhcp_lease_get_dns(lease, &addresses, &addresses_size);
402 serialize_addresses(f, "DNS", addresses, addresses_size);
404 r = sd_dhcp_lease_get_ntp(lease, &addresses, &addresses_size);
406 serialize_addresses(f, "NTP", addresses, addresses_size);
408 r = sd_dhcp_lease_get_domainname(lease, &string);
410 fprintf(f, "DOMAINNAME=%s\n", string);
412 r = sd_dhcp_lease_get_hostname(lease, &string);
414 fprintf(f, "HOSTNAME=%s\n", string);
416 r = sd_dhcp_lease_get_root_path(lease, &string);
418 fprintf(f, "ROOT_PATH=%s\n", string);
424 if (ferror(f) || rename(temp_path, lease_file) < 0) {
432 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
437 int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
438 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
439 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
440 *server_address = NULL, *next_server = NULL,
441 *dns = NULL, *ntp = NULL, *mtu = NULL;
448 r = dhcp_lease_new(&lease);
452 r = parse_env_file(lease_file, NEWLINE,
456 "SERVER_IDENTIFIER", &server_address,
457 "NEXT_SERVER", &next_server,
461 "DOMAINNAME", &lease->domainname,
462 "HOSTNAME", &lease->hostname,
463 "ROOT_PATH", &lease->root_path,
469 log_error("Failed to read %s: %s", lease_file, strerror(-r));
473 r = inet_pton(AF_INET, address, &addr);
477 lease->address = addr.s_addr;
480 r = inet_pton(AF_INET, router, &addr);
484 lease->router = addr.s_addr;
487 r = inet_pton(AF_INET, netmask, &addr);
491 lease->subnet_mask = addr.s_addr;
493 if (server_address) {
494 r = inet_pton(AF_INET, server_address, &addr);
498 lease->server_address = addr.s_addr;
502 r = inet_pton(AF_INET, next_server, &addr);
506 lease->next_server = addr.s_addr;
510 r = deserialize_addresses(&lease->dns, &lease->dns_size, dns);
516 r = deserialize_addresses(&lease->ntp, &lease->ntp_size, dns);
523 if (sscanf(mtu, "%" SCNu16, &u) > 0)
533 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
537 assert(lease->address != INADDR_ANY);
539 address = be32toh(lease->address);
541 /* fall back to the default subnet masks based on address class */
543 if ((address >> 31) == 0x0)
544 /* class A, leading bits: 0 */
545 lease->subnet_mask = htobe32(0xff000000);
546 else if ((address >> 30) == 0x2)
547 /* class B, leading bits 10 */
548 lease->subnet_mask = htobe32(0xffff0000);
549 else if ((address >> 29) == 0x6)
550 /* class C, leading bits 110 */
551 lease->subnet_mask = htobe32(0xffffff00);
553 /* class D or E, no default mask. give up */