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_domainname(sd_dhcp_lease *lease, const char **domainname) {
76 assert_return(lease, -EINVAL);
77 assert_return(domainname, -EINVAL);
79 if (lease->domainname)
80 *domainname = lease->domainname;
87 int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
88 assert_return(lease, -EINVAL);
89 assert_return(hostname, -EINVAL);
92 *hostname = lease->hostname;
99 int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
100 assert_return(lease, -EINVAL);
101 assert_return(root_path, -EINVAL);
103 if (lease->root_path)
104 *root_path = lease->root_path;
111 int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) {
112 assert_return(lease, -EINVAL);
113 assert_return(addr, -EINVAL);
115 addr->s_addr = lease->router;
120 int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
121 assert_return(lease, -EINVAL);
122 assert_return(addr, -EINVAL);
124 addr->s_addr = lease->subnet_mask;
129 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
131 assert_se(REFCNT_INC(lease->n_ref) >= 2);
136 sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
137 if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
138 free(lease->hostname);
139 free(lease->domainname);
147 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
149 sd_dhcp_lease *lease = user_data;
154 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
156 memcpy(&val, option, 4);
157 lease->lifetime = be32toh(val);
162 case DHCP_OPTION_SERVER_IDENTIFIER:
164 memcpy(&lease->server_address, option, 4);
168 case DHCP_OPTION_SUBNET_MASK:
170 memcpy(&lease->subnet_mask, option, 4);
174 case DHCP_OPTION_ROUTER:
176 memcpy(&lease->router, option, 4);
180 case DHCP_OPTION_DOMAIN_NAME_SERVER:
181 if (len && !(len % 4)) {
184 lease->dns_size = len / 4;
187 lease->dns = new0(struct in_addr, lease->dns_size);
191 for (i = 0; i < lease->dns_size; i++) {
192 memcpy(&lease->dns[i].s_addr, option + 4 * i, 4);
198 case DHCP_OPTION_INTERFACE_MTU:
202 memcpy(&mtu, option, 2);
203 lease->mtu = be16toh(mtu);
211 case DHCP_OPTION_DOMAIN_NAME:
213 free(lease->domainname);
214 lease->domainname = strndup((const char *)option, len);
219 case DHCP_OPTION_HOST_NAME:
221 free(lease->hostname);
222 lease->hostname = strndup((const char *)option, len);
227 case DHCP_OPTION_ROOT_PATH:
229 free(lease->root_path);
230 lease->root_path = strndup((const char *)option, len);
235 case DHCP_OPTION_RENEWAL_T1_TIME:
237 memcpy(&val, option, 4);
238 lease->t1 = be32toh(val);
243 case DHCP_OPTION_REBINDING_T2_TIME:
245 memcpy(&val, option, 4);
246 lease->t2 = be32toh(val);
255 int dhcp_lease_new(sd_dhcp_lease **ret) {
256 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
258 lease = new0(sd_dhcp_lease, 1);
262 lease->n_ref = REFCNT_INIT;
270 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
271 _cleanup_free_ char *temp_path = NULL;
272 _cleanup_fclose_ FILE *f = NULL;
273 char buf[INET_ADDRSTRLEN];
274 struct in_addr address;
282 r = mkdir_safe_label("/run/systemd/network/leases", 0755, 0, 0);
286 r = fopen_temporary(lease_file, &f, &temp_path);
290 fchmod(fileno(f), 0644);
292 r = sd_dhcp_lease_get_address(lease, &address);
296 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
303 "# This is private data. Do not parse.\n"
304 "ADDRESS=%s\n", string);
306 r = sd_dhcp_lease_get_router(lease, &address);
310 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
317 "ROUTER=%s\n", string);
319 r = sd_dhcp_lease_get_netmask(lease, &address);
323 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
330 "NETMASK=%s\n", string);
332 r = sd_dhcp_lease_get_mtu(lease, &mtu);
334 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
336 /* TODO: DNS. See resolv.conf writing in network-manager.c */
338 r = sd_dhcp_lease_get_domainname(lease, &string);
340 fprintf(f, "DOMAINNAME=%s\n", string);
342 r = sd_dhcp_lease_get_hostname(lease, &string);
344 fprintf(f, "HOSTNAME=%s\n", string);
346 r = sd_dhcp_lease_get_root_path(lease, &string);
348 fprintf(f, "ROOT_PATH=%s\n", string);
354 if (ferror(f) || rename(temp_path, lease_file) < 0) {
362 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
367 int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
368 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
369 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
377 r = dhcp_lease_new(&lease);
381 r = parse_env_file(lease_file, NEWLINE,
386 "DOMAINNAME", &lease->domainname,
387 "HOSTNAME", &lease->hostname,
388 "ROOT_PATH", &lease->root_path,
394 log_error("Failed to read %s: %s", lease_file, strerror(-r));
398 r = inet_pton(AF_INET, address, &addr);
402 lease->address = addr.s_addr;
404 r = inet_pton(AF_INET, router, &addr);
408 lease->router = addr.s_addr;
410 r = inet_pton(AF_INET, netmask, &addr);
414 lease->subnet_mask = addr.s_addr;
418 if (sscanf(mtu, "%" SCNu16, &u) > 0)