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 sd_dhcp_lease *lease;
276 lease = new0(sd_dhcp_lease, 1);
280 lease->n_ref = REFCNT_INIT;
286 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
287 _cleanup_free_ char *temp_path = NULL;
288 _cleanup_fclose_ FILE *f = NULL;
289 char buf[INET_ADDRSTRLEN];
290 struct in_addr address;
298 r = fopen_temporary(lease_file, &f, &temp_path);
302 fchmod(fileno(f), 0644);
304 r = sd_dhcp_lease_get_address(lease, &address);
308 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
315 "# This is private data. Do not parse.\n"
316 "ADDRESS=%s\n", string);
318 r = sd_dhcp_lease_get_router(lease, &address);
322 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
329 "ROUTER=%s\n", string);
331 r = sd_dhcp_lease_get_netmask(lease, &address);
335 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
342 "NETMASK=%s\n", string);
344 r = sd_dhcp_lease_get_server_identifier(lease, &address);
346 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
353 "SERVER_ADDRESS=%s\n", string);
356 r = sd_dhcp_lease_get_next_server(lease, &address);
358 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
365 "NEXT_SERVER=%s\n", string);
368 r = sd_dhcp_lease_get_mtu(lease, &mtu);
370 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
372 /* TODO: DNS. See resolv.conf writing in network-manager.c */
374 r = sd_dhcp_lease_get_domainname(lease, &string);
376 fprintf(f, "DOMAINNAME=%s\n", string);
378 r = sd_dhcp_lease_get_hostname(lease, &string);
380 fprintf(f, "HOSTNAME=%s\n", string);
382 r = sd_dhcp_lease_get_root_path(lease, &string);
384 fprintf(f, "ROOT_PATH=%s\n", string);
390 if (ferror(f) || rename(temp_path, lease_file) < 0) {
398 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
403 int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
404 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
405 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
406 *server_address = NULL, *next_server = NULL,
414 r = dhcp_lease_new(&lease);
418 r = parse_env_file(lease_file, NEWLINE,
422 "SERVER_IDENTIFIER", &server_address,
423 "NEXT_SERVER", &next_server,
425 "DOMAINNAME", &lease->domainname,
426 "HOSTNAME", &lease->hostname,
427 "ROOT_PATH", &lease->root_path,
433 log_error("Failed to read %s: %s", lease_file, strerror(-r));
437 r = inet_pton(AF_INET, address, &addr);
441 lease->address = addr.s_addr;
443 r = inet_pton(AF_INET, router, &addr);
447 lease->router = addr.s_addr;
449 r = inet_pton(AF_INET, netmask, &addr);
453 lease->subnet_mask = addr.s_addr;
455 if (server_address) {
456 r = inet_pton(AF_INET, server_address, &addr);
460 lease->server_address = addr.s_addr;
464 r = inet_pton(AF_INET, next_server, &addr);
468 lease->next_server = addr.s_addr;
473 if (sscanf(mtu, "%" SCNu16, &u) > 0)
483 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
487 assert(lease->address != INADDR_ANY);
489 address = be32toh(lease->address);
491 /* fall back to the default subnet masks based on address class */
493 if ((address >> 31) == 0x0)
494 /* class A, leading bits: 0 */
495 lease->subnet_mask = htobe32(0xff000000);
496 else if ((address >> 30) == 0x2)
497 /* class B, leading bits 10 */
498 lease->subnet_mask = htobe32(0xffff0000);
499 else if ((address >> 29) == 0x6)
500 /* class C, leading bits 110 */
501 lease->subnet_mask = htobe32(0xffffff00);
503 /* class D or E, no default mask. give up */