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)) {
216 lease->dns_size = len / 4;
219 lease->dns = new0(struct in_addr, lease->dns_size);
223 for (i = 0; i < lease->dns_size; i++) {
224 memcpy(&lease->dns[i].s_addr, option + 4 * i, 4);
230 case DHCP_OPTION_NTP_SERVER:
231 if (len && !(len % 4)) {
234 lease->ntp_size = len / 4;
237 lease->ntp = new0(struct in_addr, lease->ntp_size);
241 for (i = 0; i < lease->ntp_size; i++) {
242 memcpy(&lease->ntp[i].s_addr, option + 4 * i, 4);
248 case DHCP_OPTION_INTERFACE_MTU:
252 memcpy(&mtu, option, 2);
253 lease->mtu = be16toh(mtu);
261 case DHCP_OPTION_DOMAIN_NAME:
263 free(lease->domainname);
264 lease->domainname = strndup((const char *)option, len);
269 case DHCP_OPTION_HOST_NAME:
271 free(lease->hostname);
272 lease->hostname = strndup((const char *)option, len);
277 case DHCP_OPTION_ROOT_PATH:
279 free(lease->root_path);
280 lease->root_path = strndup((const char *)option, len);
285 case DHCP_OPTION_RENEWAL_T1_TIME:
287 memcpy(&val, option, 4);
288 lease->t1 = be32toh(val);
293 case DHCP_OPTION_REBINDING_T2_TIME:
295 memcpy(&val, option, 4);
296 lease->t2 = be32toh(val);
305 int dhcp_lease_new(sd_dhcp_lease **ret) {
306 sd_dhcp_lease *lease;
308 lease = new0(sd_dhcp_lease, 1);
312 lease->n_ref = REFCNT_INIT;
318 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
319 _cleanup_free_ char *temp_path = NULL;
320 _cleanup_fclose_ FILE *f = NULL;
321 char buf[INET_ADDRSTRLEN];
322 struct in_addr address;
330 r = fopen_temporary(lease_file, &f, &temp_path);
334 fchmod(fileno(f), 0644);
336 r = sd_dhcp_lease_get_address(lease, &address);
340 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
347 "# This is private data. Do not parse.\n"
348 "ADDRESS=%s\n", string);
350 r = sd_dhcp_lease_get_router(lease, &address);
354 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
361 "ROUTER=%s\n", string);
363 r = sd_dhcp_lease_get_netmask(lease, &address);
367 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
374 "NETMASK=%s\n", string);
376 r = sd_dhcp_lease_get_server_identifier(lease, &address);
378 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
385 "SERVER_ADDRESS=%s\n", string);
388 r = sd_dhcp_lease_get_next_server(lease, &address);
390 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
397 "NEXT_SERVER=%s\n", string);
400 r = sd_dhcp_lease_get_mtu(lease, &mtu);
402 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
404 /* TODO: DNS. See resolv.conf writing in network-manager.c */
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,
446 r = dhcp_lease_new(&lease);
450 r = parse_env_file(lease_file, NEWLINE,
454 "SERVER_IDENTIFIER", &server_address,
455 "NEXT_SERVER", &next_server,
457 "DOMAINNAME", &lease->domainname,
458 "HOSTNAME", &lease->hostname,
459 "ROOT_PATH", &lease->root_path,
465 log_error("Failed to read %s: %s", lease_file, strerror(-r));
469 r = inet_pton(AF_INET, address, &addr);
473 lease->address = addr.s_addr;
475 r = inet_pton(AF_INET, router, &addr);
479 lease->router = addr.s_addr;
481 r = inet_pton(AF_INET, netmask, &addr);
485 lease->subnet_mask = addr.s_addr;
487 if (server_address) {
488 r = inet_pton(AF_INET, server_address, &addr);
492 lease->server_address = addr.s_addr;
496 r = inet_pton(AF_INET, next_server, &addr);
500 lease->next_server = addr.s_addr;
505 if (sscanf(mtu, "%" SCNu16, &u) > 0)
515 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
519 assert(lease->address != INADDR_ANY);
521 address = be32toh(lease->address);
523 /* fall back to the default subnet masks based on address class */
525 if ((address >> 31) == 0x0)
526 /* class A, leading bits: 0 */
527 lease->subnet_mask = htobe32(0xff000000);
528 else if ((address >> 30) == 0x2)
529 /* class B, leading bits 10 */
530 lease->subnet_mask = htobe32(0xffff0000);
531 else if ((address >> 29) == 0x6)
532 /* class C, leading bits 110 */
533 lease->subnet_mask = htobe32(0xffffff00);
535 /* class D or E, no default mask. give up */