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 = fopen_temporary(lease_file, &f, &temp_path);
304 fchmod(fileno(f), 0644);
306 r = sd_dhcp_lease_get_address(lease, &address);
310 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
317 "# This is private data. Do not parse.\n"
318 "ADDRESS=%s\n", string);
320 r = sd_dhcp_lease_get_router(lease, &address);
324 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
331 "ROUTER=%s\n", string);
333 r = sd_dhcp_lease_get_netmask(lease, &address);
337 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
344 "NETMASK=%s\n", string);
346 r = sd_dhcp_lease_get_server_identifier(lease, &address);
348 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
355 "SERVER_ADDRESS=%s\n", string);
358 r = sd_dhcp_lease_get_next_server(lease, &address);
360 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
367 "NEXT_SERVER=%s\n", string);
370 r = sd_dhcp_lease_get_mtu(lease, &mtu);
372 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
374 /* TODO: DNS. See resolv.conf writing in network-manager.c */
376 r = sd_dhcp_lease_get_domainname(lease, &string);
378 fprintf(f, "DOMAINNAME=%s\n", string);
380 r = sd_dhcp_lease_get_hostname(lease, &string);
382 fprintf(f, "HOSTNAME=%s\n", string);
384 r = sd_dhcp_lease_get_root_path(lease, &string);
386 fprintf(f, "ROOT_PATH=%s\n", string);
392 if (ferror(f) || rename(temp_path, lease_file) < 0) {
400 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
405 int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
406 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
407 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
408 *server_address = NULL, *next_server = NULL,
416 r = dhcp_lease_new(&lease);
420 r = parse_env_file(lease_file, NEWLINE,
424 "SERVER_IDENTIFIER", &server_address,
425 "NEXT_SERVER", &next_server,
427 "DOMAINNAME", &lease->domainname,
428 "HOSTNAME", &lease->hostname,
429 "ROOT_PATH", &lease->root_path,
435 log_error("Failed to read %s: %s", lease_file, strerror(-r));
439 r = inet_pton(AF_INET, address, &addr);
443 lease->address = addr.s_addr;
445 r = inet_pton(AF_INET, router, &addr);
449 lease->router = addr.s_addr;
451 r = inet_pton(AF_INET, netmask, &addr);
455 lease->subnet_mask = addr.s_addr;
457 if (server_address) {
458 r = inet_pton(AF_INET, server_address, &addr);
462 lease->server_address = addr.s_addr;
466 r = inet_pton(AF_INET, next_server, &addr);
470 lease->next_server = addr.s_addr;
475 if (sscanf(mtu, "%" SCNu16, &u) > 0)
485 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
489 assert(lease->address != INADDR_ANY);
491 address = be32toh(lease->address);
493 /* fall back to the default subnet masks based on address class */
495 if ((address >> 31) == 0x0)
496 /* class A, leading bits: 0 */
497 lease->subnet_mask = htobe32(0xff000000);
498 else if ((address >> 30) == 0x2)
499 /* class B, leading bits 10 */
500 lease->subnet_mask = htobe32(0xffff0000);
501 else if ((address >> 29) == 0x6)
502 /* class C, leading bits 110 */
503 lease->subnet_mask = htobe32(0xffffff00);
505 /* class D or E, no default mask. give up */