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 int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
130 assert_return(lease, -EINVAL);
131 assert_return(addr, -EINVAL);
133 addr->s_addr = lease->server_address;
138 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
140 assert_se(REFCNT_INC(lease->n_ref) >= 2);
145 sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
146 if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
147 free(lease->hostname);
148 free(lease->domainname);
156 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
158 sd_dhcp_lease *lease = user_data;
163 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
165 memcpy(&val, option, 4);
166 lease->lifetime = be32toh(val);
171 case DHCP_OPTION_SERVER_IDENTIFIER:
173 memcpy(&lease->server_address, option, 4);
177 case DHCP_OPTION_SUBNET_MASK:
179 memcpy(&lease->subnet_mask, option, 4);
183 case DHCP_OPTION_ROUTER:
185 memcpy(&lease->router, option, 4);
189 case DHCP_OPTION_DOMAIN_NAME_SERVER:
190 if (len && !(len % 4)) {
193 lease->dns_size = len / 4;
196 lease->dns = new0(struct in_addr, lease->dns_size);
200 for (i = 0; i < lease->dns_size; i++) {
201 memcpy(&lease->dns[i].s_addr, option + 4 * i, 4);
207 case DHCP_OPTION_INTERFACE_MTU:
211 memcpy(&mtu, option, 2);
212 lease->mtu = be16toh(mtu);
220 case DHCP_OPTION_DOMAIN_NAME:
222 free(lease->domainname);
223 lease->domainname = strndup((const char *)option, len);
228 case DHCP_OPTION_HOST_NAME:
230 free(lease->hostname);
231 lease->hostname = strndup((const char *)option, len);
236 case DHCP_OPTION_ROOT_PATH:
238 free(lease->root_path);
239 lease->root_path = strndup((const char *)option, len);
244 case DHCP_OPTION_RENEWAL_T1_TIME:
246 memcpy(&val, option, 4);
247 lease->t1 = be32toh(val);
252 case DHCP_OPTION_REBINDING_T2_TIME:
254 memcpy(&val, option, 4);
255 lease->t2 = be32toh(val);
264 int dhcp_lease_new(sd_dhcp_lease **ret) {
265 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
267 lease = new0(sd_dhcp_lease, 1);
271 lease->n_ref = REFCNT_INIT;
279 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
280 _cleanup_free_ char *temp_path = NULL;
281 _cleanup_fclose_ FILE *f = NULL;
282 char buf[INET_ADDRSTRLEN];
283 struct in_addr address;
291 r = mkdir_safe_label("/run/systemd/network/leases", 0755, 0, 0);
295 r = fopen_temporary(lease_file, &f, &temp_path);
299 fchmod(fileno(f), 0644);
301 r = sd_dhcp_lease_get_address(lease, &address);
305 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
312 "# This is private data. Do not parse.\n"
313 "ADDRESS=%s\n", string);
315 r = sd_dhcp_lease_get_router(lease, &address);
319 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
326 "ROUTER=%s\n", string);
328 r = sd_dhcp_lease_get_netmask(lease, &address);
332 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
339 "NETMASK=%s\n", string);
341 r = sd_dhcp_lease_get_server_identifier(lease, &address);
343 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
350 "SERVER_ADDRESS=%s\n", string);
353 r = sd_dhcp_lease_get_mtu(lease, &mtu);
355 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
357 /* TODO: DNS. See resolv.conf writing in network-manager.c */
359 r = sd_dhcp_lease_get_domainname(lease, &string);
361 fprintf(f, "DOMAINNAME=%s\n", string);
363 r = sd_dhcp_lease_get_hostname(lease, &string);
365 fprintf(f, "HOSTNAME=%s\n", string);
367 r = sd_dhcp_lease_get_root_path(lease, &string);
369 fprintf(f, "ROOT_PATH=%s\n", string);
375 if (ferror(f) || rename(temp_path, lease_file) < 0) {
383 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
388 int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
389 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
390 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
391 *server_address = NULL, *mtu = NULL;
398 r = dhcp_lease_new(&lease);
402 r = parse_env_file(lease_file, NEWLINE,
406 "SERVER_IDENTIFIER", &server_address,
408 "DOMAINNAME", &lease->domainname,
409 "HOSTNAME", &lease->hostname,
410 "ROOT_PATH", &lease->root_path,
416 log_error("Failed to read %s: %s", lease_file, strerror(-r));
420 r = inet_pton(AF_INET, address, &addr);
424 lease->address = addr.s_addr;
426 r = inet_pton(AF_INET, router, &addr);
430 lease->router = addr.s_addr;
432 r = inet_pton(AF_INET, netmask, &addr);
436 lease->subnet_mask = addr.s_addr;
438 if (server_address) {
439 r = inet_pton(AF_INET, server_address, &addr);
443 lease->server_address = addr.s_addr;
448 if (sscanf(mtu, "%" SCNu16, &u) > 0)