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_ntp(sd_dhcp_lease *lease, struct in_addr **addr, size_t *addr_size) {
76 assert_return(lease, -EINVAL);
77 assert_return(addr, -EINVAL);
78 assert_return(addr_size, -EINVAL);
80 if (lease->ntp_size) {
81 *addr_size = lease->ntp_size;
89 int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
90 assert_return(lease, -EINVAL);
91 assert_return(domainname, -EINVAL);
93 if (lease->domainname)
94 *domainname = lease->domainname;
101 int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
102 assert_return(lease, -EINVAL);
103 assert_return(hostname, -EINVAL);
106 *hostname = lease->hostname;
113 int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
114 assert_return(lease, -EINVAL);
115 assert_return(root_path, -EINVAL);
117 if (lease->root_path)
118 *root_path = lease->root_path;
125 int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) {
126 assert_return(lease, -EINVAL);
127 assert_return(addr, -EINVAL);
129 addr->s_addr = lease->router;
134 int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
135 assert_return(lease, -EINVAL);
136 assert_return(addr, -EINVAL);
138 addr->s_addr = lease->subnet_mask;
143 int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
144 assert_return(lease, -EINVAL);
145 assert_return(addr, -EINVAL);
147 addr->s_addr = lease->server_address;
152 int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
153 assert_return(lease, -EINVAL);
154 assert_return(addr, -EINVAL);
156 addr->s_addr = lease->next_server;
161 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
163 assert_se(REFCNT_INC(lease->n_ref) >= 2);
168 sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
169 if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
170 free(lease->hostname);
171 free(lease->domainname);
179 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
181 sd_dhcp_lease *lease = user_data;
186 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
188 memcpy(&val, option, 4);
189 lease->lifetime = be32toh(val);
194 case DHCP_OPTION_SERVER_IDENTIFIER:
196 memcpy(&lease->server_address, option, 4);
200 case DHCP_OPTION_SUBNET_MASK:
202 memcpy(&lease->subnet_mask, option, 4);
206 case DHCP_OPTION_ROUTER:
208 memcpy(&lease->router, option, 4);
212 case DHCP_OPTION_DOMAIN_NAME_SERVER:
213 if (len && !(len % 4)) {
214 lease->dns_size = len / 4;
217 lease->dns = newdup(struct in_addr, option, lease->dns_size);
224 case DHCP_OPTION_NTP_SERVER:
225 if (len && !(len % 4)) {
226 lease->ntp_size = len / 4;
229 lease->ntp = newdup(struct in_addr, option, lease->ntp_size);
236 case DHCP_OPTION_INTERFACE_MTU:
240 memcpy(&mtu, option, 2);
241 lease->mtu = be16toh(mtu);
249 case DHCP_OPTION_DOMAIN_NAME:
251 free(lease->domainname);
252 lease->domainname = strndup((const char *)option, len);
257 case DHCP_OPTION_HOST_NAME:
259 free(lease->hostname);
260 lease->hostname = strndup((const char *)option, len);
265 case DHCP_OPTION_ROOT_PATH:
267 free(lease->root_path);
268 lease->root_path = strndup((const char *)option, len);
273 case DHCP_OPTION_RENEWAL_T1_TIME:
275 memcpy(&val, option, 4);
276 lease->t1 = be32toh(val);
281 case DHCP_OPTION_REBINDING_T2_TIME:
283 memcpy(&val, option, 4);
284 lease->t2 = be32toh(val);
293 int dhcp_lease_new(sd_dhcp_lease **ret) {
294 sd_dhcp_lease *lease;
296 lease = new0(sd_dhcp_lease, 1);
300 lease->n_ref = REFCNT_INIT;
306 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
307 _cleanup_free_ char *temp_path = NULL;
308 _cleanup_fclose_ FILE *f = NULL;
309 char buf[INET_ADDRSTRLEN];
310 struct in_addr address;
318 r = fopen_temporary(lease_file, &f, &temp_path);
322 fchmod(fileno(f), 0644);
324 r = sd_dhcp_lease_get_address(lease, &address);
328 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
335 "# This is private data. Do not parse.\n"
336 "ADDRESS=%s\n", string);
338 r = sd_dhcp_lease_get_router(lease, &address);
342 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
349 "ROUTER=%s\n", string);
351 r = sd_dhcp_lease_get_netmask(lease, &address);
355 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
362 "NETMASK=%s\n", string);
364 r = sd_dhcp_lease_get_server_identifier(lease, &address);
366 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
373 "SERVER_ADDRESS=%s\n", string);
376 r = sd_dhcp_lease_get_next_server(lease, &address);
378 string = inet_ntop(AF_INET, &address, buf, INET_ADDRSTRLEN);
385 "NEXT_SERVER=%s\n", string);
388 r = sd_dhcp_lease_get_mtu(lease, &mtu);
390 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
392 /* TODO: DNS. See resolv.conf writing in network-manager.c */
394 r = sd_dhcp_lease_get_domainname(lease, &string);
396 fprintf(f, "DOMAINNAME=%s\n", string);
398 r = sd_dhcp_lease_get_hostname(lease, &string);
400 fprintf(f, "HOSTNAME=%s\n", string);
402 r = sd_dhcp_lease_get_root_path(lease, &string);
404 fprintf(f, "ROOT_PATH=%s\n", string);
410 if (ferror(f) || rename(temp_path, lease_file) < 0) {
418 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
423 int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
424 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
425 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
426 *server_address = NULL, *next_server = NULL,
434 r = dhcp_lease_new(&lease);
438 r = parse_env_file(lease_file, NEWLINE,
442 "SERVER_IDENTIFIER", &server_address,
443 "NEXT_SERVER", &next_server,
445 "DOMAINNAME", &lease->domainname,
446 "HOSTNAME", &lease->hostname,
447 "ROOT_PATH", &lease->root_path,
453 log_error("Failed to read %s: %s", lease_file, strerror(-r));
457 r = inet_pton(AF_INET, address, &addr);
461 lease->address = addr.s_addr;
463 r = inet_pton(AF_INET, router, &addr);
467 lease->router = addr.s_addr;
469 r = inet_pton(AF_INET, netmask, &addr);
473 lease->subnet_mask = addr.s_addr;
475 if (server_address) {
476 r = inet_pton(AF_INET, server_address, &addr);
480 lease->server_address = addr.s_addr;
484 r = inet_pton(AF_INET, next_server, &addr);
488 lease->next_server = addr.s_addr;
493 if (sscanf(mtu, "%" SCNu16, &u) > 0)
503 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
507 assert(lease->address != INADDR_ANY);
509 address = be32toh(lease->address);
511 /* fall back to the default subnet masks based on address class */
513 if ((address >> 31) == 0x0)
514 /* class A, leading bits: 0 */
515 lease->subnet_mask = htobe32(0xff000000);
516 else if ((address >> 30) == 0x2)
517 /* class B, leading bits 10 */
518 lease->subnet_mask = htobe32(0xffff0000);
519 else if ((address >> 29) == 0x6)
520 /* class C, leading bits 110 */
521 lease->subnet_mask = htobe32(0xffffff00);
523 /* class D or E, no default mask. give up */