]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-dhcp-lease.c
man/udevadm: remove superfluous --version from subcommands (#8549)
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp-lease.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
a6cc569e
TG
2/***
3 This file is part of systemd.
4
5 Copyright (C) 2013 Intel Corporation. All rights reserved.
6 Copyright (C) 2014 Tom Gundersen
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
07630cea 22#include <arpa/inet.h>
a6cc569e 23#include <errno.h>
a6cc569e 24#include <stdio.h>
0d536673 25#include <stdio_ext.h>
07630cea
LP
26#include <stdlib.h>
27#include <string.h>
28
29#include "sd-dhcp-lease.h"
a6cc569e 30
b5efdb8a 31#include "alloc-util.h"
07630cea
LP
32#include "dhcp-lease-internal.h"
33#include "dhcp-protocol.h"
34#include "dns-domain.h"
3ffd4af2 35#include "fd-util.h"
fe8db0c5 36#include "fileio.h"
b11d6a7b 37#include "hexdecoct.h"
958b66ea 38#include "hostname-util.h"
07630cea 39#include "in-addr-util.h"
0339cd77 40#include "network-internal.h"
6bedfcbb 41#include "parse-util.h"
d054f0a4 42#include "stdio-util.h"
b11d6a7b 43#include "string-util.h"
07630cea 44#include "unaligned.h"
a6cc569e
TG
45
46int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
47 assert_return(lease, -EINVAL);
48 assert_return(addr, -EINVAL);
49
0339cd77
LP
50 if (lease->address == 0)
51 return -ENODATA;
52
a6cc569e 53 addr->s_addr = lease->address;
0339cd77
LP
54 return 0;
55}
a6cc569e 56
0339cd77
LP
57int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr) {
58 assert_return(lease, -EINVAL);
59 assert_return(addr, -EINVAL);
60
61 if (!lease->have_broadcast)
62 return -ENODATA;
63
64 addr->s_addr = lease->broadcast;
a6cc569e
TG
65 return 0;
66}
67
68ceb9df
PF
68int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
69 assert_return(lease, -EINVAL);
1c6eb4e3 70 assert_return(lifetime, -EINVAL);
68ceb9df 71
0339cd77
LP
72 if (lease->lifetime <= 0)
73 return -ENODATA;
74
68ceb9df 75 *lifetime = lease->lifetime;
0339cd77
LP
76 return 0;
77}
68ceb9df 78
0339cd77
LP
79int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1) {
80 assert_return(lease, -EINVAL);
81 assert_return(t1, -EINVAL);
82
83 if (lease->t1 <= 0)
84 return -ENODATA;
85
86 *t1 = lease->t1;
87 return 0;
88}
89
90int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2) {
91 assert_return(lease, -EINVAL);
92 assert_return(t2, -EINVAL);
93
94 if (lease->t2 <= 0)
95 return -ENODATA;
96
97 *t2 = lease->t2;
68ceb9df
PF
98 return 0;
99}
100
a6cc569e
TG
101int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
102 assert_return(lease, -EINVAL);
103 assert_return(mtu, -EINVAL);
104
0339cd77
LP
105 if (lease->mtu <= 0)
106 return -ENODATA;
a6cc569e 107
0339cd77 108 *mtu = lease->mtu;
a6cc569e
TG
109 return 0;
110}
111
a2ba62c7 112int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) {
a6cc569e
TG
113 assert_return(lease, -EINVAL);
114 assert_return(addr, -EINVAL);
a6cc569e 115
0339cd77
LP
116 if (lease->dns_size <= 0)
117 return -ENODATA;
a6cc569e 118
0339cd77
LP
119 *addr = lease->dns;
120 return (int) lease->dns_size;
a6cc569e
TG
121}
122
a2ba62c7 123int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) {
46844696
TG
124 assert_return(lease, -EINVAL);
125 assert_return(addr, -EINVAL);
46844696 126
0339cd77
LP
127 if (lease->ntp_size <= 0)
128 return -ENODATA;
46844696 129
0339cd77
LP
130 *addr = lease->ntp;
131 return (int) lease->ntp_size;
46844696
TG
132}
133
a6cc569e
TG
134int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
135 assert_return(lease, -EINVAL);
136 assert_return(domainname, -EINVAL);
137
0339cd77
LP
138 if (!lease->domainname)
139 return -ENODATA;
a6cc569e 140
0339cd77 141 *domainname = lease->domainname;
a6cc569e
TG
142 return 0;
143}
144
145int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
146 assert_return(lease, -EINVAL);
147 assert_return(hostname, -EINVAL);
148
0339cd77
LP
149 if (!lease->hostname)
150 return -ENODATA;
a6cc569e 151
0339cd77 152 *hostname = lease->hostname;
a6cc569e
TG
153 return 0;
154}
155
ce78df79
TG
156int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
157 assert_return(lease, -EINVAL);
158 assert_return(root_path, -EINVAL);
159
0339cd77
LP
160 if (!lease->root_path)
161 return -ENODATA;
ce78df79 162
0339cd77 163 *root_path = lease->root_path;
ce78df79
TG
164 return 0;
165}
166
a6cc569e
TG
167int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) {
168 assert_return(lease, -EINVAL);
169 assert_return(addr, -EINVAL);
170
0339cd77
LP
171 if (lease->router == 0)
172 return -ENODATA;
a6cc569e 173
0339cd77 174 addr->s_addr = lease->router;
a6cc569e
TG
175 return 0;
176}
177
178int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
179 assert_return(lease, -EINVAL);
180 assert_return(addr, -EINVAL);
181
0339cd77
LP
182 if (!lease->have_subnet_mask)
183 return -ENODATA;
a6cc569e 184
0339cd77 185 addr->s_addr = lease->subnet_mask;
a6cc569e
TG
186 return 0;
187}
188
0ad853bc
TG
189int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
190 assert_return(lease, -EINVAL);
191 assert_return(addr, -EINVAL);
192
0339cd77
LP
193 if (lease->server_address == 0)
194 return -ENODATA;
0ad853bc 195
0339cd77 196 addr->s_addr = lease->server_address;
0ad853bc
TG
197 return 0;
198}
199
8e34a618
TG
200int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
201 assert_return(lease, -EINVAL);
202 assert_return(addr, -EINVAL);
203
0339cd77
LP
204 if (lease->next_server == 0)
205 return -ENODATA;
8e34a618 206
0339cd77 207 addr->s_addr = lease->next_server;
8e34a618
TG
208 return 0;
209}
210
f8693fc7
BG
211/*
212 * The returned routes array must be freed by the caller.
213 * Route objects have the same lifetime of the lease and must not be freed.
214 */
215int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes) {
216 sd_dhcp_route **ret;
217 unsigned i;
218
e1ea665e
EY
219 assert_return(lease, -EINVAL);
220 assert_return(routes, -EINVAL);
e1ea665e 221
0339cd77
LP
222 if (lease->static_route_size <= 0)
223 return -ENODATA;
e1ea665e 224
f8693fc7
BG
225 ret = new(sd_dhcp_route *, lease->static_route_size);
226 if (!ret)
227 return -ENOMEM;
228
229 for (i = 0; i < lease->static_route_size; i++)
230 ret[i] = &lease->static_route[i];
231
232 *routes = ret;
0339cd77 233 return (int) lease->static_route_size;
e1ea665e
EY
234}
235
b85bc551
DW
236int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) {
237 unsigned r;
238
239 assert_return(lease, -EINVAL);
240 assert_return(domains, -EINVAL);
241
242 r = strv_length(lease->search_domains);
243 if (r > 0) {
244 *domains = lease->search_domains;
245 return (int) r;
246 }
247
248 return -ENODATA;
249}
250
0339cd77 251int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len) {
e43a8393
BG
252 assert_return(lease, -EINVAL);
253 assert_return(data, -EINVAL);
254 assert_return(data_len, -EINVAL);
255
0339cd77
LP
256 if (lease->vendor_specific_len <= 0)
257 return -ENODATA;
e43a8393
BG
258
259 *data = lease->vendor_specific;
260 *data_len = lease->vendor_specific_len;
e43a8393
BG
261 return 0;
262}
263
a6cc569e 264sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
3733eec3
LP
265
266 if (!lease)
267 return NULL;
268
269 assert(lease->n_ref >= 1);
270 lease->n_ref++;
a6cc569e
TG
271
272 return lease;
273}
274
275sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
7e753d9d 276
3733eec3
LP
277 if (!lease)
278 return NULL;
7e753d9d 279
3733eec3
LP
280 assert(lease->n_ref >= 1);
281 lease->n_ref--;
282
283 if (lease->n_ref > 0)
284 return NULL;
285
286 while (lease->private_options) {
287 struct sd_dhcp_raw_option *option = lease->private_options;
288
289 LIST_REMOVE(options, lease->private_options, option);
290
291 free(option->data);
292 free(option);
a6cc569e
TG
293 }
294
3733eec3
LP
295 free(lease->hostname);
296 free(lease->domainname);
297 free(lease->dns);
298 free(lease->ntp);
299 free(lease->static_route);
300 free(lease->client_id);
301 free(lease->vendor_specific);
b85bc551 302 strv_free(lease->search_domains);
6b430fdb 303 return mfree(lease);
a6cc569e
TG
304}
305
0339cd77 306static int lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
e140ae58
TG
307 assert(option);
308 assert(ret);
309
0339cd77
LP
310 if (len != 4)
311 return -EINVAL;
e140ae58 312
0339cd77
LP
313 *ret = unaligned_read_be32((be32_t*) option);
314 if (*ret < min)
315 *ret = min;
e140ae58 316
0339cd77 317 return 0;
e140ae58
TG
318}
319
0339cd77 320static int lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
e140ae58
TG
321 assert(option);
322 assert(ret);
323
0339cd77
LP
324 if (len != 2)
325 return -EINVAL;
e140ae58 326
0339cd77
LP
327 *ret = unaligned_read_be16((be16_t*) option);
328 if (*ret < min)
329 *ret = min;
f5c0c00f 330
0339cd77 331 return 0;
f5c0c00f
TG
332}
333
0339cd77 334static int lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
f5c0c00f
TG
335 assert(option);
336 assert(ret);
337
0339cd77
LP
338 if (len != 4)
339 return -EINVAL;
f5c0c00f 340
0339cd77
LP
341 memcpy(ret, option, 4);
342 return 0;
f5c0c00f
TG
343}
344
e140ae58
TG
345static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
346 assert(option);
347 assert(ret);
348
0339cd77
LP
349 if (len <= 0)
350 *ret = mfree(*ret);
351 else {
e140ae58
TG
352 char *string;
353
e989fd9b
LP
354 /*
355 * One trailing NUL byte is OK, we don't mind. See:
356 * https://github.com/systemd/systemd/issues/1337
357 */
358 if (memchr(option, 0, len - 1))
43f447b1
LP
359 return -EINVAL;
360
e989fd9b 361 string = strndup((const char *) option, len);
e140ae58 362 if (!string)
43f447b1 363 return -ENOMEM;
e140ae58
TG
364
365 free(*ret);
366 *ret = string;
0339cd77 367 }
e140ae58
TG
368
369 return 0;
370}
371
978c6477
LP
372static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) {
373 _cleanup_free_ char *name = NULL, *normalized = NULL;
374 int r;
375
376 assert(option);
377 assert(ret);
378
379 r = lease_parse_string(option, len, &name);
380 if (r < 0)
381 return r;
382 if (!name) {
383 *ret = mfree(*ret);
384 return 0;
385 }
386
387 r = dns_name_normalize(name, &normalized);
388 if (r < 0)
389 return r;
390
391 if (is_localhost(normalized))
392 return -EINVAL;
393
394 if (dns_name_is_root(normalized))
395 return -EINVAL;
396
f9ecfd3b 397 free_and_replace(*ret, normalized);
978c6477
LP
398
399 return 0;
400}
401
d9ec2e63
LP
402static void filter_bogus_addresses(struct in_addr *addresses, size_t *n) {
403 size_t i, j;
404
405 /* Silently filter DNS/NTP servers supplied to us that do not make outside of the local scope. */
406
407 for (i = 0, j = 0; i < *n; i ++) {
408
409 if (in4_addr_is_null(addresses+i) ||
410 in4_addr_is_localhost(addresses+i))
411 continue;
412
413 addresses[j++] = addresses[i];
414 }
415
416 *n = j;
417}
418
0339cd77 419static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) {
e140ae58
TG
420 assert(option);
421 assert(ret);
0339cd77 422 assert(n_ret);
e140ae58 423
0339cd77
LP
424 if (len <= 0) {
425 *ret = mfree(*ret);
426 *n_ret = 0;
427 } else {
428 size_t n_addresses;
e140ae58
TG
429 struct in_addr *addresses;
430
0339cd77
LP
431 if (len % 4 != 0)
432 return -EINVAL;
e140ae58 433
0339cd77
LP
434 n_addresses = len / 4;
435
436 addresses = newdup(struct in_addr, option, n_addresses);
e140ae58
TG
437 if (!addresses)
438 return -ENOMEM;
439
d9ec2e63
LP
440 filter_bogus_addresses(addresses, &n_addresses);
441
e140ae58
TG
442 free(*ret);
443 *ret = addresses;
0339cd77 444 *n_ret = n_addresses;
e140ae58
TG
445 }
446
447 return 0;
448}
449
0339cd77
LP
450static int lease_parse_routes(
451 const uint8_t *option, size_t len,
452 struct sd_dhcp_route **routes, size_t *routes_size, size_t *routes_allocated) {
e1ea665e
EY
453
454 struct in_addr addr;
455
0339cd77 456 assert(option || len <= 0);
e1ea665e
EY
457 assert(routes);
458 assert(routes_size);
459 assert(routes_allocated);
460
0339cd77 461 if (len <= 0)
e1ea665e
EY
462 return 0;
463
464 if (len % 8 != 0)
465 return -EINVAL;
466
467 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + (len / 8)))
468 return -ENOMEM;
469
470 while (len >= 8) {
471 struct sd_dhcp_route *route = *routes + *routes_size;
1caa12d0 472 int r;
e1ea665e 473
8cdc46e7 474 route->option = SD_DHCP_OPTION_STATIC_ROUTE;
5a941f5f 475 r = in4_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen);
1caa12d0 476 if (r < 0) {
0339cd77 477 log_debug("Failed to determine destination prefix length from class based IP, ignoring");
e1ea665e
EY
478 continue;
479 }
480
0339cd77 481 assert_se(lease_parse_be32(option, 4, &addr.s_addr) >= 0);
e1ea665e
EY
482 route->dst_addr = inet_makeaddr(inet_netof(addr), 0);
483 option += 4;
484
0339cd77 485 assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0);
e1ea665e
EY
486 option += 4;
487
488 len -= 8;
489 (*routes_size)++;
490 }
491
492 return 0;
493}
494
495/* parses RFC3442 Classless Static Route Option */
0339cd77
LP
496static int lease_parse_classless_routes(
497 const uint8_t *option, size_t len,
498 struct sd_dhcp_route **routes, size_t *routes_size, size_t *routes_allocated) {
e1ea665e 499
0339cd77 500 assert(option || len <= 0);
e1ea665e
EY
501 assert(routes);
502 assert(routes_size);
503 assert(routes_allocated);
504
0339cd77
LP
505 if (len <= 0)
506 return 0;
507
e1ea665e
EY
508 /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */
509
510 while (len > 0) {
511 uint8_t dst_octets;
512 struct sd_dhcp_route *route;
513
514 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1))
0339cd77 515 return -ENOMEM;
e1ea665e
EY
516
517 route = *routes + *routes_size;
8cdc46e7 518 route->option = SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE;
e1ea665e
EY
519
520 dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1);
521 route->dst_prefixlen = *option;
522 option++;
523 len--;
524
525 /* can't have more than 4 octets in IPv4 */
526 if (dst_octets > 4 || len < dst_octets)
527 return -EINVAL;
528
529 route->dst_addr.s_addr = 0;
530 memcpy(&route->dst_addr.s_addr, option, dst_octets);
531 option += dst_octets;
532 len -= dst_octets;
533
534 if (len < 4)
535 return -EINVAL;
536
b14fff6e 537 assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0);
e1ea665e
EY
538 option += 4;
539 len -= 4;
540
541 (*routes_size)++;
542 }
543
544 return 0;
545}
546
e4735228 547int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
2d03c0b8 548 sd_dhcp_lease *lease = userdata;
e140ae58
TG
549 int r;
550
551 assert(lease);
a6cc569e
TG
552
553 switch(code) {
554
22805d92 555 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
0339cd77
LP
556 r = lease_parse_u32(option, len, &lease->lifetime, 1);
557 if (r < 0)
558 log_debug_errno(r, "Failed to parse lease time, ignoring: %m");
559
a6cc569e
TG
560 break;
561
22805d92 562 case SD_DHCP_OPTION_SERVER_IDENTIFIER:
0339cd77
LP
563 r = lease_parse_be32(option, len, &lease->server_address);
564 if (r < 0)
565 log_debug_errno(r, "Failed to parse server identifier, ignoring: %m");
566
a6cc569e
TG
567 break;
568
22805d92 569 case SD_DHCP_OPTION_SUBNET_MASK:
0339cd77
LP
570 r = lease_parse_be32(option, len, &lease->subnet_mask);
571 if (r < 0)
572 log_debug_errno(r, "Failed to parse subnet mask, ignoring: %m");
573 else
574 lease->have_subnet_mask = true;
a6cc569e
TG
575 break;
576
22805d92 577 case SD_DHCP_OPTION_BROADCAST:
0339cd77
LP
578 r = lease_parse_be32(option, len, &lease->broadcast);
579 if (r < 0)
580 log_debug_errno(r, "Failed to parse broadcast address, ignoring: %m");
581 else
582 lease->have_broadcast = true;
f5c0c00f
TG
583 break;
584
22805d92 585 case SD_DHCP_OPTION_ROUTER:
0339cd77
LP
586 if (len >= 4) {
587 r = lease_parse_be32(option, 4, &lease->router);
588 if (r < 0)
589 log_debug_errno(r, "Failed to parse router address, ignoring: %m");
590 }
a6cc569e
TG
591 break;
592
22805d92 593 case SD_DHCP_OPTION_DOMAIN_NAME_SERVER:
0339cd77
LP
594 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
595 if (r < 0)
596 log_debug_errno(r, "Failed to parse DNS server, ignoring: %m");
a6cc569e
TG
597 break;
598
22805d92 599 case SD_DHCP_OPTION_NTP_SERVER:
0339cd77
LP
600 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
601 if (r < 0)
602 log_debug_errno(r, "Failed to parse NTP server, ignoring: %m");
f5c0c00f
TG
603 break;
604
22805d92 605 case SD_DHCP_OPTION_STATIC_ROUTE:
0339cd77
LP
606 r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size, &lease->static_route_allocated);
607 if (r < 0)
608 log_debug_errno(r, "Failed to parse static routes, ignoring: %m");
f5c0c00f
TG
609 break;
610
22805d92 611 case SD_DHCP_OPTION_INTERFACE_MTU:
0339cd77
LP
612 r = lease_parse_u16(option, len, &lease->mtu, 68);
613 if (r < 0)
614 log_debug_errno(r, "Failed to parse MTU, ignoring: %m");
955d99ed 615 if (lease->mtu < DHCP_DEFAULT_MIN_SIZE) {
4dd53da9 616 log_debug("MTU value of %" PRIu16 " too small. Using default MTU value of %d instead.", lease->mtu, DHCP_DEFAULT_MIN_SIZE);
955d99ed
MG
617 lease->mtu = DHCP_DEFAULT_MIN_SIZE;
618 }
619
f5c0c00f
TG
620 break;
621
978c6477
LP
622 case SD_DHCP_OPTION_DOMAIN_NAME:
623 r = lease_parse_domain(option, len, &lease->domainname);
0339cd77
LP
624 if (r < 0) {
625 log_debug_errno(r, "Failed to parse domain name, ignoring: %m");
626 return 0;
627 }
a6cc569e 628
784d9b9c 629 break;
784d9b9c 630
b85bc551
DW
631 case SD_DHCP_OPTION_DOMAIN_SEARCH_LIST:
632 r = dhcp_lease_parse_search_domains(option, len, &lease->search_domains);
633 if (r < 0)
634 log_debug_errno(r, "Failed to parse Domain Search List, ignoring: %m");
635 break;
636
978c6477
LP
637 case SD_DHCP_OPTION_HOST_NAME:
638 r = lease_parse_domain(option, len, &lease->hostname);
0339cd77
LP
639 if (r < 0) {
640 log_debug_errno(r, "Failed to parse host name, ignoring: %m");
641 return 0;
642 }
a6cc569e 643
784d9b9c 644 break;
ce78df79 645
22805d92 646 case SD_DHCP_OPTION_ROOT_PATH:
0339cd77
LP
647 r = lease_parse_string(option, len, &lease->root_path);
648 if (r < 0)
649 log_debug_errno(r, "Failed to parse root path, ignoring: %m");
650 break;
ce78df79 651
22805d92 652 case SD_DHCP_OPTION_RENEWAL_T1_TIME:
0339cd77
LP
653 r = lease_parse_u32(option, len, &lease->t1, 1);
654 if (r < 0)
655 log_debug_errno(r, "Failed to parse T1 time, ignoring: %m");
a6cc569e
TG
656 break;
657
22805d92 658 case SD_DHCP_OPTION_REBINDING_T2_TIME:
0339cd77
LP
659 r = lease_parse_u32(option, len, &lease->t2, 1);
660 if (r < 0)
661 log_debug_errno(r, "Failed to parse T2 time, ignoring: %m");
a6cc569e 662 break;
e1ea665e 663
22805d92 664 case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
0339cd77 665 r = lease_parse_classless_routes(
2d03c0b8
LP
666 option, len,
667 &lease->static_route,
668 &lease->static_route_size,
669 &lease->static_route_allocated);
0339cd77
LP
670 if (r < 0)
671 log_debug_errno(r, "Failed to parse classless routes, ignoring: %m");
672 break;
e43a8393 673
22805d92 674 case SD_DHCP_OPTION_NEW_TZDB_TIMEZONE: {
8eb9058d
LP
675 _cleanup_free_ char *tz = NULL;
676
677 r = lease_parse_string(option, len, &tz);
0339cd77
LP
678 if (r < 0) {
679 log_debug_errno(r, "Failed to parse timezone option, ignoring: %m");
680 return 0;
681 }
8eb9058d 682
0339cd77
LP
683 if (!timezone_is_valid(tz)) {
684 log_debug_errno(r, "Timezone is not valid, ignoring: %m");
685 return 0;
686 }
8eb9058d 687
f9ecfd3b 688 free_and_replace(lease->timezone, tz);
0339cd77 689
8eb9058d
LP
690 break;
691 }
692
22805d92 693 case SD_DHCP_OPTION_VENDOR_SPECIFIC:
2d03c0b8 694
0339cd77
LP
695 if (len <= 0)
696 lease->vendor_specific = mfree(lease->vendor_specific);
697 else {
698 void *p;
699
700 p = memdup(option, len);
701 if (!p)
e43a8393 702 return -ENOMEM;
e43a8393 703
0339cd77
LP
704 free(lease->vendor_specific);
705 lease->vendor_specific = p;
706 }
7e753d9d 707
0339cd77
LP
708 lease->vendor_specific_len = len;
709 break;
7e753d9d 710
22805d92 711 case SD_DHCP_OPTION_PRIVATE_BASE ... SD_DHCP_OPTION_PRIVATE_LAST:
7e753d9d
AC
712 r = dhcp_lease_insert_private_option(lease, code, option, len);
713 if (r < 0)
714 return r;
0339cd77
LP
715
716 break;
717
718 default:
f693e9b3 719 log_debug("Ignoring option DHCP option %"PRIu8" while parsing.", code);
0339cd77 720 break;
a6cc569e
TG
721 }
722
723 return 0;
724}
725
b85bc551
DW
726/* Parses compressed domain names. */
727int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***domains) {
728 _cleanup_strv_free_ char **names = NULL;
729 size_t pos = 0, cnt = 0;
730 int r;
731
732 assert(domains);
733 assert_return(option && len > 0, -ENODATA);
734
735 while (pos < len) {
736 _cleanup_free_ char *name = NULL;
737 size_t n = 0, allocated = 0;
738 size_t jump_barrier = pos, next_chunk = 0;
739 bool first = true;
740
741 for (;;) {
742 uint8_t c;
743 c = option[pos++];
744
745 if (c == 0) {
746 /* End of name */
747 break;
748 } else if (c <= 63) {
749 const char *label;
750
751 /* Literal label */
752 label = (const char*) (option + pos);
753 pos += c;
754 if (pos >= len)
755 return -EBADMSG;
756
757 if (!GREEDY_REALLOC(name, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
758 return -ENOMEM;
759
760 if (first)
761 first = false;
762 else
763 name[n++] = '.';
764
765 r = dns_label_escape(label, c, name + n, DNS_LABEL_ESCAPED_MAX);
766 if (r < 0)
767 return r;
768
769 n += r;
770 } else if ((c & 0xc0) == 0xc0) {
771 /* Pointer */
772
773 uint8_t d;
774 uint16_t ptr;
775
776 if (pos >= len)
777 return -EBADMSG;
778
779 d = option[pos++];
780 ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
781
782 /* Jumps are limited to a "prior occurrence" (RFC-1035 4.1.4) */
783 if (ptr >= jump_barrier)
784 return -EBADMSG;
785 jump_barrier = ptr;
786
787 /* Save current location so we don't end up re-parsing what's parsed so far. */
788 if (next_chunk == 0)
789 next_chunk = pos;
790
791 pos = ptr;
792 } else
793 return -EBADMSG;
794 }
795
796 if (!GREEDY_REALLOC(name, allocated, n + 1))
797 return -ENOMEM;
798 name[n] = 0;
799
800 r = strv_extend(&names, name);
801 if (r < 0)
802 return r;
803
804 cnt++;
805
806 if (next_chunk != 0)
807 pos = next_chunk;
808 }
809
810 *domains = names;
811 names = NULL;
812
813 return cnt;
814}
815
0339cd77 816int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len) {
7e753d9d
AC
817 struct sd_dhcp_raw_option *cur, *option;
818
0339cd77
LP
819 assert(lease);
820
7e753d9d
AC
821 LIST_FOREACH(options, cur, lease->private_options) {
822 if (tag < cur->tag)
823 break;
0339cd77
LP
824 if (tag == cur->tag) {
825 log_debug("Ignoring duplicate option, tagged %i.", tag);
7e753d9d
AC
826 return 0;
827 }
828 }
829
830 option = new(struct sd_dhcp_raw_option, 1);
831 if (!option)
832 return -ENOMEM;
833
834 option->tag = tag;
835 option->length = len;
836 option->data = memdup(data, len);
837 if (!option->data) {
838 free(option);
839 return -ENOMEM;
840 }
841
842 LIST_INSERT_BEFORE(options, lease->private_options, cur, option);
7e753d9d
AC
843 return 0;
844}
845
a6cc569e 846int dhcp_lease_new(sd_dhcp_lease **ret) {
6e00a806 847 sd_dhcp_lease *lease;
a6cc569e
TG
848
849 lease = new0(sd_dhcp_lease, 1);
850 if (!lease)
851 return -ENOMEM;
852
8ddbeaa2 853 lease->router = INADDR_ANY;
3733eec3 854 lease->n_ref = 1;
a6cc569e
TG
855
856 *ret = lease;
a6cc569e
TG
857 return 0;
858}
fe8db0c5 859
bd91b83e 860int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
fe8db0c5
TG
861 _cleanup_free_ char *temp_path = NULL;
862 _cleanup_fclose_ FILE *f = NULL;
a073309f 863 struct sd_dhcp_raw_option *option;
fe8db0c5 864 struct in_addr address;
a2ba62c7 865 const struct in_addr *addresses;
e4735228 866 const void *client_id, *data;
e43a8393 867 size_t client_id_len, data_len;
fe8db0c5
TG
868 const char *string;
869 uint16_t mtu;
f8693fc7 870 _cleanup_free_ sd_dhcp_route **routes = NULL;
b85bc551 871 char **search_domains = NULL;
0339cd77 872 uint32_t t1, t2, lifetime;
fe8db0c5
TG
873 int r;
874
875 assert(lease);
876 assert(lease_file);
877
fe8db0c5
TG
878 r = fopen_temporary(lease_file, &f, &temp_path);
879 if (r < 0)
dacd6cee 880 goto fail;
fe8db0c5 881
0d536673
LP
882 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
883 (void) fchmod(fileno(f), 0644);
fe8db0c5 884
fe8db0c5 885 fprintf(f,
0339cd77 886 "# This is private data. Do not parse.\n");
fe8db0c5 887
0339cd77
LP
888 r = sd_dhcp_lease_get_address(lease, &address);
889 if (r >= 0)
890 fprintf(f, "ADDRESS=%s\n", inet_ntoa(address));
fe8db0c5 891
0339cd77
LP
892 r = sd_dhcp_lease_get_netmask(lease, &address);
893 if (r >= 0)
894 fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
fe8db0c5 895
8ddbeaa2
UTL
896 r = sd_dhcp_lease_get_router(lease, &address);
897 if (r >= 0)
898 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
899
0ad853bc 900 r = sd_dhcp_lease_get_server_identifier(lease, &address);
109731eb 901 if (r >= 0)
0339cd77 902 fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntoa(address));
0ad853bc 903
8e34a618 904 r = sd_dhcp_lease_get_next_server(lease, &address);
109731eb
TG
905 if (r >= 0)
906 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
8e34a618 907
0339cd77
LP
908 r = sd_dhcp_lease_get_broadcast(lease, &address);
909 if (r >= 0)
910 fprintf(f, "BROADCAST=%s\n", inet_ntoa(address));
911
fe8db0c5
TG
912 r = sd_dhcp_lease_get_mtu(lease, &mtu);
913 if (r >= 0)
914 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
915
0339cd77
LP
916 r = sd_dhcp_lease_get_t1(lease, &t1);
917 if (r >= 0)
918 fprintf(f, "T1=%" PRIu32 "\n", t1);
919
920 r = sd_dhcp_lease_get_t2(lease, &t2);
109731eb 921 if (r >= 0)
0339cd77
LP
922 fprintf(f, "T2=%" PRIu32 "\n", t2);
923
924 r = sd_dhcp_lease_get_lifetime(lease, &lifetime);
925 if (r >= 0)
926 fprintf(f, "LIFETIME=%" PRIu32 "\n", lifetime);
927
928 r = sd_dhcp_lease_get_dns(lease, &addresses);
929 if (r > 0) {
0d536673 930 fputs("DNS=", f);
b0e39c82 931 serialize_in_addrs(f, addresses, r);
0d536673 932 fputs("\n", f);
0339cd77 933 }
109731eb 934
a2ba62c7 935 r = sd_dhcp_lease_get_ntp(lease, &addresses);
0339cd77 936 if (r > 0) {
0d536673 937 fputs("NTP=", f);
b0e39c82 938 serialize_in_addrs(f, addresses, r);
0d536673 939 fputs("\n", f);
0339cd77 940 }
fe8db0c5
TG
941
942 r = sd_dhcp_lease_get_domainname(lease, &string);
943 if (r >= 0)
944 fprintf(f, "DOMAINNAME=%s\n", string);
945
b85bc551
DW
946 r = sd_dhcp_lease_get_search_domains(lease, &search_domains);
947 if (r > 0) {
0d536673 948 fputs("DOMAIN_SEARCH_LIST=", f);
b85bc551 949 fputstrv(f, search_domains, NULL, NULL);
0d536673 950 fputs("\n", f);
b85bc551
DW
951 }
952
fe8db0c5
TG
953 r = sd_dhcp_lease_get_hostname(lease, &string);
954 if (r >= 0)
955 fprintf(f, "HOSTNAME=%s\n", string);
956
ce78df79
TG
957 r = sd_dhcp_lease_get_root_path(lease, &string);
958 if (r >= 0)
959 fprintf(f, "ROOT_PATH=%s\n", string);
960
a2ba62c7 961 r = sd_dhcp_lease_get_routes(lease, &routes);
0339cd77 962 if (r > 0)
a2ba62c7 963 serialize_dhcp_routes(f, "ROUTES", routes, r);
e1ea665e 964
8eb9058d
LP
965 r = sd_dhcp_lease_get_timezone(lease, &string);
966 if (r >= 0)
967 fprintf(f, "TIMEZONE=%s\n", string);
968
e37f74a6
DW
969 r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
970 if (r >= 0) {
3587161a 971 _cleanup_free_ char *client_id_hex = NULL;
e37f74a6 972
dde8bb32 973 client_id_hex = hexmem(client_id, client_id_len);
e37f74a6
DW
974 if (!client_id_hex) {
975 r = -ENOMEM;
dacd6cee 976 goto fail;
e37f74a6
DW
977 }
978 fprintf(f, "CLIENTID=%s\n", client_id_hex);
979 }
980
e43a8393
BG
981 r = sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len);
982 if (r >= 0) {
983 _cleanup_free_ char *option_hex = NULL;
984
985 option_hex = hexmem(data, data_len);
986 if (!option_hex) {
987 r = -ENOMEM;
dacd6cee 988 goto fail;
e43a8393
BG
989 }
990 fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
991 }
992
a073309f 993 LIST_FOREACH(options, option, lease->private_options) {
dbcb4a90 994 char key[STRLEN("OPTION_000")+1];
0339cd77 995
d054f0a4 996 xsprintf(key, "OPTION_%" PRIu8, option->tag);
a073309f
AC
997 r = serialize_dhcp_option(f, key, option->data, option->length);
998 if (r < 0)
999 goto fail;
1000 }
1001
dacd6cee
LP
1002 r = fflush_and_check(f);
1003 if (r < 0)
1004 goto fail;
fe8db0c5 1005
dacd6cee 1006 if (rename(temp_path, lease_file) < 0) {
fe8db0c5 1007 r = -errno;
dacd6cee 1008 goto fail;
fe8db0c5
TG
1009 }
1010
dacd6cee
LP
1011 return 0;
1012
1013fail:
1014 if (temp_path)
1015 (void) unlink(temp_path);
fe8db0c5 1016
dacd6cee 1017 return log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
fe8db0c5
TG
1018}
1019
bd91b83e 1020int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
0339cd77 1021
4afd3348 1022 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
0339cd77
LP
1023 _cleanup_free_ char
1024 *address = NULL,
1025 *router = NULL,
1026 *netmask = NULL,
1027 *server_address = NULL,
1028 *next_server = NULL,
1029 *broadcast = NULL,
1030 *dns = NULL,
1031 *ntp = NULL,
1032 *mtu = NULL,
1033 *routes = NULL,
b85bc551 1034 *domains = NULL,
0339cd77
LP
1035 *client_id_hex = NULL,
1036 *vendor_specific_hex = NULL,
1037 *lifetime = NULL,
1038 *t1 = NULL,
1039 *t2 = NULL,
22805d92 1040 *options[SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE + 1] = {};
0339cd77 1041
a073309f 1042 int r, i;
fe8db0c5
TG
1043
1044 assert(lease_file);
1045 assert(ret);
1046
1047 r = dhcp_lease_new(&lease);
1048 if (r < 0)
1049 return r;
1050
1051 r = parse_env_file(lease_file, NEWLINE,
1052 "ADDRESS", &address,
1053 "ROUTER", &router,
1054 "NETMASK", &netmask,
0ad853bc 1055 "SERVER_IDENTIFIER", &server_address,
8e34a618 1056 "NEXT_SERVER", &next_server,
0339cd77 1057 "BROADCAST", &broadcast,
109731eb
TG
1058 "DNS", &dns,
1059 "NTP", &ntp,
fe8db0c5
TG
1060 "MTU", &mtu,
1061 "DOMAINNAME", &lease->domainname,
1062 "HOSTNAME", &lease->hostname,
b85bc551 1063 "DOMAIN_SEARCH_LIST", &domains,
ce78df79 1064 "ROOT_PATH", &lease->root_path,
e1ea665e 1065 "ROUTES", &routes,
e37f74a6 1066 "CLIENTID", &client_id_hex,
8eb9058d 1067 "TIMEZONE", &lease->timezone,
e43a8393 1068 "VENDOR_SPECIFIC", &vendor_specific_hex,
0339cd77
LP
1069 "LIFETIME", &lifetime,
1070 "T1", &t1,
1071 "T2", &t2,
a073309f
AC
1072 "OPTION_224", &options[0],
1073 "OPTION_225", &options[1],
1074 "OPTION_226", &options[2],
1075 "OPTION_227", &options[3],
1076 "OPTION_228", &options[4],
1077 "OPTION_229", &options[5],
1078 "OPTION_230", &options[6],
1079 "OPTION_231", &options[7],
1080 "OPTION_232", &options[8],
1081 "OPTION_233", &options[9],
1082 "OPTION_234", &options[10],
1083 "OPTION_235", &options[11],
1084 "OPTION_236", &options[12],
1085 "OPTION_237", &options[13],
1086 "OPTION_238", &options[14],
1087 "OPTION_239", &options[15],
1088 "OPTION_240", &options[16],
1089 "OPTION_241", &options[17],
1090 "OPTION_242", &options[18],
1091 "OPTION_243", &options[19],
1092 "OPTION_244", &options[20],
1093 "OPTION_245", &options[21],
1094 "OPTION_246", &options[22],
1095 "OPTION_247", &options[23],
1096 "OPTION_248", &options[24],
1097 "OPTION_249", &options[25],
1098 "OPTION_250", &options[26],
1099 "OPTION_251", &options[27],
1100 "OPTION_252", &options[28],
1101 "OPTION_253", &options[29],
1102 "OPTION_254", &options[30],
fe8db0c5 1103 NULL);
fe8db0c5
TG
1104 if (r < 0)
1105 return r;
1106
0339cd77
LP
1107 if (address) {
1108 r = inet_pton(AF_INET, address, &lease->address);
1109 if (r <= 0)
e26ea7fc 1110 log_debug("Failed to parse address %s, ignoring.", address);
0339cd77 1111 }
fe8db0c5 1112
8ddbeaa2 1113 if (router) {
0339cd77
LP
1114 r = inet_pton(AF_INET, router, &lease->router);
1115 if (r <= 0)
e26ea7fc 1116 log_debug("Failed to parse router %s, ignoring.", router);
8ddbeaa2 1117 }
fe8db0c5 1118
0339cd77
LP
1119 if (netmask) {
1120 r = inet_pton(AF_INET, netmask, &lease->subnet_mask);
1121 if (r <= 0)
e26ea7fc 1122 log_debug("Failed to parse netmask %s, ignoring.", netmask);
0339cd77
LP
1123 else
1124 lease->have_subnet_mask = true;
1125 }
fe8db0c5 1126
0ad853bc 1127 if (server_address) {
0339cd77
LP
1128 r = inet_pton(AF_INET, server_address, &lease->server_address);
1129 if (r <= 0)
e26ea7fc 1130 log_debug("Failed to parse server address %s, ignoring.", server_address);
0ad853bc
TG
1131 }
1132
8e34a618 1133 if (next_server) {
0339cd77
LP
1134 r = inet_pton(AF_INET, next_server, &lease->next_server);
1135 if (r <= 0)
e26ea7fc 1136 log_debug("Failed to parse next server %s, ignoring.", next_server);
0339cd77 1137 }
8e34a618 1138
0339cd77
LP
1139 if (broadcast) {
1140 r = inet_pton(AF_INET, broadcast, &lease->broadcast);
1141 if (r <= 0)
e26ea7fc 1142 log_debug("Failed to parse broadcast address %s, ignoring.", broadcast);
0339cd77
LP
1143 else
1144 lease->have_broadcast = true;
8e34a618
TG
1145 }
1146
109731eb 1147 if (dns) {
a2ba62c7 1148 r = deserialize_in_addrs(&lease->dns, dns);
109731eb 1149 if (r < 0)
0339cd77
LP
1150 log_debug_errno(r, "Failed to deserialize DNS servers %s, ignoring: %m", dns);
1151 else
1152 lease->dns_size = r;
109731eb
TG
1153 }
1154
1155 if (ntp) {
a2ba62c7 1156 r = deserialize_in_addrs(&lease->ntp, ntp);
109731eb 1157 if (r < 0)
0339cd77
LP
1158 log_debug_errno(r, "Failed to deserialize NTP servers %s, ignoring: %m", ntp);
1159 else
1160 lease->ntp_size = r;
109731eb
TG
1161 }
1162
fe8db0c5 1163 if (mtu) {
0339cd77
LP
1164 r = safe_atou16(mtu, &lease->mtu);
1165 if (r < 0)
1166 log_debug_errno(r, "Failed to parse MTU %s, ignoring: %m", mtu);
fe8db0c5
TG
1167 }
1168
b85bc551
DW
1169 if (domains) {
1170 _cleanup_strv_free_ char **a = NULL;
1171 a = strv_split(domains, " ");
1172 if (!a)
1173 return -ENOMEM;
1174
1175 if (!strv_isempty(a)) {
1176 lease->search_domains = a;
1177 a = NULL;
1178 }
1179 }
1180
e1ea665e 1181 if (routes) {
0339cd77
LP
1182 r = deserialize_dhcp_routes(
1183 &lease->static_route,
1184 &lease->static_route_size,
1185 &lease->static_route_allocated,
1186 routes);
1187 if (r < 0)
1188 log_debug_errno(r, "Failed to parse DHCP routes %s, ignoring: %m", routes);
1189 }
1190
1191 if (lifetime) {
1192 r = safe_atou32(lifetime, &lease->lifetime);
1193 if (r < 0)
1194 log_debug_errno(r, "Failed to parse lifetime %s, ignoring: %m", lifetime);
1195 }
1196
1197 if (t1) {
1198 r = safe_atou32(t1, &lease->t1);
1199 if (r < 0)
1200 log_debug_errno(r, "Failed to parse T1 %s, ignoring: %m", t1);
1201 }
1202
1203 if (t2) {
1204 r = safe_atou32(t2, &lease->t2);
e1ea665e 1205 if (r < 0)
0339cd77 1206 log_debug_errno(r, "Failed to parse T2 %s, ignoring: %m", t2);
e1ea665e
EY
1207 }
1208
e37f74a6 1209 if (client_id_hex) {
9b57d9ae 1210 r = deserialize_dhcp_option(&lease->client_id, &lease->client_id_len, client_id_hex);
30494563 1211 if (r < 0)
0339cd77 1212 log_debug_errno(r, "Failed to parse client ID %s, ignoring: %m", client_id_hex);
e37f74a6
DW
1213 }
1214
e43a8393 1215 if (vendor_specific_hex) {
9b57d9ae 1216 r = deserialize_dhcp_option(&lease->vendor_specific, &lease->vendor_specific_len, vendor_specific_hex);
e43a8393 1217 if (r < 0)
0339cd77 1218 log_debug_errno(r, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex);
e43a8393
BG
1219 }
1220
22805d92 1221 for (i = 0; i <= SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE; i++) {
e4735228 1222 _cleanup_free_ void *data = NULL;
a073309f
AC
1223 size_t len;
1224
1225 if (!options[i])
1226 continue;
1227
1228 r = deserialize_dhcp_option(&data, &len, options[i]);
0339cd77
LP
1229 if (r < 0) {
1230 log_debug_errno(r, "Failed to parse private DHCP option %s, ignoring: %m", options[i]);
1231 continue;
1232 }
a073309f 1233
22805d92 1234 r = dhcp_lease_insert_private_option(lease, SD_DHCP_OPTION_PRIVATE_BASE + i, data, len);
626be147 1235 if (r < 0)
a073309f
AC
1236 return r;
1237 }
1238
fe8db0c5
TG
1239 *ret = lease;
1240 lease = NULL;
1241
1242 return 0;
1243}
9e64dd72
TG
1244
1245int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
0339cd77 1246 struct in_addr address, mask;
df40eee8 1247 int r;
9e64dd72
TG
1248
1249 assert(lease);
9e64dd72 1250
0339cd77
LP
1251 if (lease->address == 0)
1252 return -ENODATA;
1253
df40eee8 1254 address.s_addr = lease->address;
9e64dd72
TG
1255
1256 /* fall back to the default subnet masks based on address class */
5a941f5f 1257 r = in4_addr_default_subnet_mask(&address, &mask);
df40eee8
TG
1258 if (r < 0)
1259 return r;
9e64dd72 1260
df40eee8 1261 lease->subnet_mask = mask.s_addr;
0339cd77 1262 lease->have_subnet_mask = true;
9e64dd72
TG
1263
1264 return 0;
1265}
e37f74a6 1266
0339cd77 1267int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len) {
e37f74a6
DW
1268 assert_return(lease, -EINVAL);
1269 assert_return(client_id, -EINVAL);
1270 assert_return(client_id_len, -EINVAL);
1271
0339cd77
LP
1272 if (!lease->client_id)
1273 return -ENODATA;
1274
e37f74a6
DW
1275 *client_id = lease->client_id;
1276 *client_id_len = lease->client_id_len;
0339cd77 1277
e37f74a6
DW
1278 return 0;
1279}
1280
0339cd77 1281int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len) {
e37f74a6 1282 assert_return(lease, -EINVAL);
0339cd77
LP
1283 assert_return(client_id || client_id_len <= 0, -EINVAL);
1284
1285 if (client_id_len <= 0)
1286 lease->client_id = mfree(lease->client_id);
1287 else {
1288 void *p;
e37f74a6 1289
0339cd77
LP
1290 p = memdup(client_id, client_id_len);
1291 if (!p)
1292 return -ENOMEM;
e37f74a6 1293
0339cd77
LP
1294 free(lease->client_id);
1295 lease->client_id = p;
e37f74a6
DW
1296 lease->client_id_len = client_id_len;
1297 }
1298
1299 return 0;
1300}
8eb9058d 1301
64d6c229 1302int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **tz) {
8eb9058d 1303 assert_return(lease, -EINVAL);
64d6c229 1304 assert_return(tz, -EINVAL);
8eb9058d
LP
1305
1306 if (!lease->timezone)
0339cd77 1307 return -ENODATA;
8eb9058d 1308
64d6c229 1309 *tz = lease->timezone;
8eb9058d
LP
1310 return 0;
1311}
f8693fc7
BG
1312
1313int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination) {
1314 assert_return(route, -EINVAL);
1315 assert_return(destination, -EINVAL);
1316
1317 *destination = route->dst_addr;
1318 return 0;
1319}
1320
1321int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length) {
1322 assert_return(route, -EINVAL);
1323 assert_return(length, -EINVAL);
1324
1325 *length = route->dst_prefixlen;
1326 return 0;
1327}
1328
1329int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway) {
1330 assert_return(route, -EINVAL);
1331 assert_return(gateway, -EINVAL);
1332
1333 *gateway = route->gw_addr;
1334 return 0;
1335}