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_router(sd_dhcp_lease *lease, struct in_addr *addr) {
100 assert_return(lease, -EINVAL);
101 assert_return(addr, -EINVAL);
103 addr->s_addr = lease->router;
108 int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
109 assert_return(lease, -EINVAL);
110 assert_return(addr, -EINVAL);
112 addr->s_addr = lease->subnet_mask;
117 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
119 assert_se(REFCNT_INC(lease->n_ref) >= 2);
124 sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
125 if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
126 free(lease->hostname);
127 free(lease->domainname);
135 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
137 sd_dhcp_lease *lease = user_data;
142 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
144 memcpy(&val, option, 4);
145 lease->lifetime = be32toh(val);
150 case DHCP_OPTION_SERVER_IDENTIFIER:
152 memcpy(&lease->server_address, option, 4);
156 case DHCP_OPTION_SUBNET_MASK:
158 memcpy(&lease->subnet_mask, option, 4);
162 case DHCP_OPTION_ROUTER:
164 memcpy(&lease->router, option, 4);
168 case DHCP_OPTION_DOMAIN_NAME_SERVER:
169 if (len && !(len % 4)) {
172 lease->dns_size = len / 4;
175 lease->dns = new0(struct in_addr, lease->dns_size);
179 for (i = 0; i < lease->dns_size; i++) {
180 memcpy(&lease->dns[i].s_addr, option + 4 * i, 4);
186 case DHCP_OPTION_INTERFACE_MTU:
190 memcpy(&mtu, option, 2);
191 lease->mtu = be16toh(mtu);
199 case DHCP_OPTION_DOMAIN_NAME:
201 free(lease->domainname);
202 lease->domainname = strndup((const char *)option, len);
207 case DHCP_OPTION_HOST_NAME:
209 free(lease->hostname);
210 lease->hostname = strndup((const char *)option, len);
215 case DHCP_OPTION_RENEWAL_T1_TIME:
217 memcpy(&val, option, 4);
218 lease->t1 = be32toh(val);
223 case DHCP_OPTION_REBINDING_T2_TIME:
225 memcpy(&val, option, 4);
226 lease->t2 = be32toh(val);
235 int dhcp_lease_new(sd_dhcp_lease **ret) {
236 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
238 lease = new0(sd_dhcp_lease, 1);
242 lease->n_ref = REFCNT_INIT;
250 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
251 _cleanup_free_ char *temp_path = NULL;
252 _cleanup_fclose_ FILE *f = NULL;
253 char buf[INET_ADDRSTRLEN];
254 struct in_addr address;
262 r = mkdir_safe_label("/run/systemd/network/leases", 0755, 0, 0);
266 r = fopen_temporary(lease_file, &f, &temp_path);
270 fchmod(fileno(f), 0644);
272 r = sd_dhcp_lease_get_address(lease, &address);
276 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
283 "# This is private data. Do not parse.\n"
284 "ADDRESS=%s\n", string);
286 r = sd_dhcp_lease_get_router(lease, &address);
290 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
297 "ROUTER=%s\n", string);
299 r = sd_dhcp_lease_get_netmask(lease, &address);
303 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
310 "NETMASK=%s\n", string);
312 r = sd_dhcp_lease_get_mtu(lease, &mtu);
314 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
316 /* TODO: DNS. See resolv.conf writing in network-manager.c */
318 r = sd_dhcp_lease_get_domainname(lease, &string);
320 fprintf(f, "DOMAINNAME=%s\n", string);
322 r = sd_dhcp_lease_get_hostname(lease, &string);
324 fprintf(f, "HOSTNAME=%s\n", string);
330 if (ferror(f) || rename(temp_path, lease_file) < 0) {
338 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
343 int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
344 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
345 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
353 r = dhcp_lease_new(&lease);
357 r = parse_env_file(lease_file, NEWLINE,
362 "DOMAINNAME", &lease->domainname,
363 "HOSTNAME", &lease->hostname,
369 log_error("Failed to read %s: %s", lease_file, strerror(-r));
373 r = inet_pton(AF_INET, address, &addr);
377 lease->address = addr.s_addr;
379 r = inet_pton(AF_INET, router, &addr);
383 lease->router = addr.s_addr;
385 r = inet_pton(AF_INET, netmask, &addr);
389 lease->subnet_mask = addr.s_addr;
393 if (sscanf(mtu, "%" SCNu16, &u) > 0)