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 int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
139 assert_return(lease, -EINVAL);
140 assert_return(addr, -EINVAL);
142 addr->s_addr = lease->next_server;
147 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
149 assert_se(REFCNT_INC(lease->n_ref) >= 2);
154 sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
155 if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
156 free(lease->hostname);
157 free(lease->domainname);
165 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
167 sd_dhcp_lease *lease = user_data;
172 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
174 memcpy(&val, option, 4);
175 lease->lifetime = be32toh(val);
180 case DHCP_OPTION_SERVER_IDENTIFIER:
182 memcpy(&lease->server_address, option, 4);
186 case DHCP_OPTION_SUBNET_MASK:
188 memcpy(&lease->subnet_mask, option, 4);
192 case DHCP_OPTION_ROUTER:
194 memcpy(&lease->router, option, 4);
198 case DHCP_OPTION_DOMAIN_NAME_SERVER:
199 if (len && !(len % 4)) {
202 lease->dns_size = len / 4;
205 lease->dns = new0(struct in_addr, lease->dns_size);
209 for (i = 0; i < lease->dns_size; i++) {
210 memcpy(&lease->dns[i].s_addr, option + 4 * i, 4);
216 case DHCP_OPTION_INTERFACE_MTU:
220 memcpy(&mtu, option, 2);
221 lease->mtu = be16toh(mtu);
229 case DHCP_OPTION_DOMAIN_NAME:
231 free(lease->domainname);
232 lease->domainname = strndup((const char *)option, len);
237 case DHCP_OPTION_HOST_NAME:
239 free(lease->hostname);
240 lease->hostname = strndup((const char *)option, len);
245 case DHCP_OPTION_ROOT_PATH:
247 free(lease->root_path);
248 lease->root_path = strndup((const char *)option, len);
253 case DHCP_OPTION_RENEWAL_T1_TIME:
255 memcpy(&val, option, 4);
256 lease->t1 = be32toh(val);
261 case DHCP_OPTION_REBINDING_T2_TIME:
263 memcpy(&val, option, 4);
264 lease->t2 = be32toh(val);
273 int dhcp_lease_new(sd_dhcp_lease **ret) {
274 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
276 lease = new0(sd_dhcp_lease, 1);
280 lease->n_ref = REFCNT_INIT;
288 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
289 _cleanup_free_ char *temp_path = NULL;
290 _cleanup_fclose_ FILE *f = NULL;
291 char buf[INET_ADDRSTRLEN];
292 struct in_addr address;
300 r = mkdir_safe_label("/run/systemd/network/leases", 0755, 0, 0);
304 r = fopen_temporary(lease_file, &f, &temp_path);
308 fchmod(fileno(f), 0644);
310 r = sd_dhcp_lease_get_address(lease, &address);
314 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
321 "# This is private data. Do not parse.\n"
322 "ADDRESS=%s\n", string);
324 r = sd_dhcp_lease_get_router(lease, &address);
328 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
335 "ROUTER=%s\n", string);
337 r = sd_dhcp_lease_get_netmask(lease, &address);
341 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
348 "NETMASK=%s\n", string);
350 r = sd_dhcp_lease_get_server_identifier(lease, &address);
352 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
359 "SERVER_ADDRESS=%s\n", string);
362 r = sd_dhcp_lease_get_next_server(lease, &address);
364 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
371 "NEXT_SERVER=%s\n", string);
374 r = sd_dhcp_lease_get_mtu(lease, &mtu);
376 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
378 /* TODO: DNS. See resolv.conf writing in network-manager.c */
380 r = sd_dhcp_lease_get_domainname(lease, &string);
382 fprintf(f, "DOMAINNAME=%s\n", string);
384 r = sd_dhcp_lease_get_hostname(lease, &string);
386 fprintf(f, "HOSTNAME=%s\n", string);
388 r = sd_dhcp_lease_get_root_path(lease, &string);
390 fprintf(f, "ROOT_PATH=%s\n", string);
396 if (ferror(f) || rename(temp_path, lease_file) < 0) {
404 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
409 int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
410 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
411 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
412 *server_address = NULL, *next_server = NULL,
420 r = dhcp_lease_new(&lease);
424 r = parse_env_file(lease_file, NEWLINE,
428 "SERVER_IDENTIFIER", &server_address,
429 "NEXT_SERVER", &next_server,
431 "DOMAINNAME", &lease->domainname,
432 "HOSTNAME", &lease->hostname,
433 "ROOT_PATH", &lease->root_path,
439 log_error("Failed to read %s: %s", lease_file, strerror(-r));
443 r = inet_pton(AF_INET, address, &addr);
447 lease->address = addr.s_addr;
449 r = inet_pton(AF_INET, router, &addr);
453 lease->router = addr.s_addr;
455 r = inet_pton(AF_INET, netmask, &addr);
459 lease->subnet_mask = addr.s_addr;
461 if (server_address) {
462 r = inet_pton(AF_INET, server_address, &addr);
466 lease->server_address = addr.s_addr;
470 r = inet_pton(AF_INET, next_server, &addr);
474 lease->next_server = addr.s_addr;
479 if (sscanf(mtu, "%" SCNu16, &u) > 0)