]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-dhcp-lease.c
manager: initialize timeouts when allocating a naked Manager object
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp-lease.c
CommitLineData
a6cc569e
TG
1/***
2 This file is part of systemd.
3
4 Copyright (C) 2013 Intel Corporation. All rights reserved.
5 Copyright (C) 2014 Tom Gundersen
6
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.
11
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.
16
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/>.
19***/
20
07630cea 21#include <arpa/inet.h>
a6cc569e 22#include <errno.h>
a6cc569e 23#include <stdio.h>
07630cea
LP
24#include <stdlib.h>
25#include <string.h>
26
27#include "sd-dhcp-lease.h"
a6cc569e 28
b5efdb8a 29#include "alloc-util.h"
07630cea
LP
30#include "dhcp-lease-internal.h"
31#include "dhcp-protocol.h"
32#include "dns-domain.h"
3ffd4af2 33#include "fd-util.h"
fe8db0c5 34#include "fileio.h"
b11d6a7b 35#include "hexdecoct.h"
958b66ea 36#include "hostname-util.h"
07630cea 37#include "in-addr-util.h"
0339cd77 38#include "network-internal.h"
6bedfcbb 39#include "parse-util.h"
d054f0a4 40#include "stdio-util.h"
b11d6a7b 41#include "string-util.h"
07630cea 42#include "unaligned.h"
a6cc569e
TG
43
44int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
45 assert_return(lease, -EINVAL);
46 assert_return(addr, -EINVAL);
47
0339cd77
LP
48 if (lease->address == 0)
49 return -ENODATA;
50
a6cc569e 51 addr->s_addr = lease->address;
0339cd77
LP
52 return 0;
53}
a6cc569e 54
0339cd77
LP
55int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr) {
56 assert_return(lease, -EINVAL);
57 assert_return(addr, -EINVAL);
58
59 if (!lease->have_broadcast)
60 return -ENODATA;
61
62 addr->s_addr = lease->broadcast;
a6cc569e
TG
63 return 0;
64}
65
68ceb9df
PF
66int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
67 assert_return(lease, -EINVAL);
1c6eb4e3 68 assert_return(lifetime, -EINVAL);
68ceb9df 69
0339cd77
LP
70 if (lease->lifetime <= 0)
71 return -ENODATA;
72
68ceb9df 73 *lifetime = lease->lifetime;
0339cd77
LP
74 return 0;
75}
68ceb9df 76
0339cd77
LP
77int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1) {
78 assert_return(lease, -EINVAL);
79 assert_return(t1, -EINVAL);
80
81 if (lease->t1 <= 0)
82 return -ENODATA;
83
84 *t1 = lease->t1;
85 return 0;
86}
87
88int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2) {
89 assert_return(lease, -EINVAL);
90 assert_return(t2, -EINVAL);
91
92 if (lease->t2 <= 0)
93 return -ENODATA;
94
95 *t2 = lease->t2;
68ceb9df
PF
96 return 0;
97}
98
a6cc569e
TG
99int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
100 assert_return(lease, -EINVAL);
101 assert_return(mtu, -EINVAL);
102
0339cd77
LP
103 if (lease->mtu <= 0)
104 return -ENODATA;
a6cc569e 105
0339cd77 106 *mtu = lease->mtu;
a6cc569e
TG
107 return 0;
108}
109
a2ba62c7 110int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) {
a6cc569e
TG
111 assert_return(lease, -EINVAL);
112 assert_return(addr, -EINVAL);
a6cc569e 113
0339cd77
LP
114 if (lease->dns_size <= 0)
115 return -ENODATA;
a6cc569e 116
0339cd77
LP
117 *addr = lease->dns;
118 return (int) lease->dns_size;
a6cc569e
TG
119}
120
a2ba62c7 121int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) {
46844696
TG
122 assert_return(lease, -EINVAL);
123 assert_return(addr, -EINVAL);
46844696 124
0339cd77
LP
125 if (lease->ntp_size <= 0)
126 return -ENODATA;
46844696 127
0339cd77
LP
128 *addr = lease->ntp;
129 return (int) lease->ntp_size;
46844696
TG
130}
131
a6cc569e
TG
132int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
133 assert_return(lease, -EINVAL);
134 assert_return(domainname, -EINVAL);
135
0339cd77
LP
136 if (!lease->domainname)
137 return -ENODATA;
a6cc569e 138
0339cd77 139 *domainname = lease->domainname;
a6cc569e
TG
140 return 0;
141}
142
143int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
144 assert_return(lease, -EINVAL);
145 assert_return(hostname, -EINVAL);
146
0339cd77
LP
147 if (!lease->hostname)
148 return -ENODATA;
a6cc569e 149
0339cd77 150 *hostname = lease->hostname;
a6cc569e
TG
151 return 0;
152}
153
ce78df79
TG
154int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
155 assert_return(lease, -EINVAL);
156 assert_return(root_path, -EINVAL);
157
0339cd77
LP
158 if (!lease->root_path)
159 return -ENODATA;
ce78df79 160
0339cd77 161 *root_path = lease->root_path;
ce78df79
TG
162 return 0;
163}
164
a6cc569e
TG
165int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) {
166 assert_return(lease, -EINVAL);
167 assert_return(addr, -EINVAL);
168
0339cd77
LP
169 if (lease->router == 0)
170 return -ENODATA;
a6cc569e 171
0339cd77 172 addr->s_addr = lease->router;
a6cc569e
TG
173 return 0;
174}
175
176int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
177 assert_return(lease, -EINVAL);
178 assert_return(addr, -EINVAL);
179
0339cd77
LP
180 if (!lease->have_subnet_mask)
181 return -ENODATA;
a6cc569e 182
0339cd77 183 addr->s_addr = lease->subnet_mask;
a6cc569e
TG
184 return 0;
185}
186
0ad853bc
TG
187int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
188 assert_return(lease, -EINVAL);
189 assert_return(addr, -EINVAL);
190
0339cd77
LP
191 if (lease->server_address == 0)
192 return -ENODATA;
0ad853bc 193
0339cd77 194 addr->s_addr = lease->server_address;
0ad853bc
TG
195 return 0;
196}
197
8e34a618
TG
198int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
199 assert_return(lease, -EINVAL);
200 assert_return(addr, -EINVAL);
201
0339cd77
LP
202 if (lease->next_server == 0)
203 return -ENODATA;
8e34a618 204
0339cd77 205 addr->s_addr = lease->next_server;
8e34a618
TG
206 return 0;
207}
208
f8693fc7
BG
209/*
210 * The returned routes array must be freed by the caller.
211 * Route objects have the same lifetime of the lease and must not be freed.
212 */
213int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes) {
214 sd_dhcp_route **ret;
215 unsigned i;
216
e1ea665e
EY
217 assert_return(lease, -EINVAL);
218 assert_return(routes, -EINVAL);
e1ea665e 219
0339cd77
LP
220 if (lease->static_route_size <= 0)
221 return -ENODATA;
e1ea665e 222
f8693fc7
BG
223 ret = new(sd_dhcp_route *, lease->static_route_size);
224 if (!ret)
225 return -ENOMEM;
226
227 for (i = 0; i < lease->static_route_size; i++)
228 ret[i] = &lease->static_route[i];
229
230 *routes = ret;
0339cd77 231 return (int) lease->static_route_size;
e1ea665e
EY
232}
233
b85bc551
DW
234int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) {
235 unsigned r;
236
237 assert_return(lease, -EINVAL);
238 assert_return(domains, -EINVAL);
239
240 r = strv_length(lease->search_domains);
241 if (r > 0) {
242 *domains = lease->search_domains;
243 return (int) r;
244 }
245
246 return -ENODATA;
247}
248
0339cd77 249int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len) {
e43a8393
BG
250 assert_return(lease, -EINVAL);
251 assert_return(data, -EINVAL);
252 assert_return(data_len, -EINVAL);
253
0339cd77
LP
254 if (lease->vendor_specific_len <= 0)
255 return -ENODATA;
e43a8393
BG
256
257 *data = lease->vendor_specific;
258 *data_len = lease->vendor_specific_len;
e43a8393
BG
259 return 0;
260}
261
a6cc569e 262sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
3733eec3
LP
263
264 if (!lease)
265 return NULL;
266
267 assert(lease->n_ref >= 1);
268 lease->n_ref++;
a6cc569e
TG
269
270 return lease;
271}
272
273sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
7e753d9d 274
3733eec3
LP
275 if (!lease)
276 return NULL;
7e753d9d 277
3733eec3
LP
278 assert(lease->n_ref >= 1);
279 lease->n_ref--;
280
281 if (lease->n_ref > 0)
282 return NULL;
283
284 while (lease->private_options) {
285 struct sd_dhcp_raw_option *option = lease->private_options;
286
287 LIST_REMOVE(options, lease->private_options, option);
288
289 free(option->data);
290 free(option);
a6cc569e
TG
291 }
292
3733eec3
LP
293 free(lease->hostname);
294 free(lease->domainname);
295 free(lease->dns);
296 free(lease->ntp);
297 free(lease->static_route);
298 free(lease->client_id);
299 free(lease->vendor_specific);
b85bc551 300 strv_free(lease->search_domains);
6b430fdb 301 return mfree(lease);
a6cc569e
TG
302}
303
0339cd77 304static int lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
e140ae58
TG
305 assert(option);
306 assert(ret);
307
0339cd77
LP
308 if (len != 4)
309 return -EINVAL;
e140ae58 310
0339cd77
LP
311 *ret = unaligned_read_be32((be32_t*) option);
312 if (*ret < min)
313 *ret = min;
e140ae58 314
0339cd77 315 return 0;
e140ae58
TG
316}
317
0339cd77 318static int lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
e140ae58
TG
319 assert(option);
320 assert(ret);
321
0339cd77
LP
322 if (len != 2)
323 return -EINVAL;
e140ae58 324
0339cd77
LP
325 *ret = unaligned_read_be16((be16_t*) option);
326 if (*ret < min)
327 *ret = min;
f5c0c00f 328
0339cd77 329 return 0;
f5c0c00f
TG
330}
331
0339cd77 332static int lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
f5c0c00f
TG
333 assert(option);
334 assert(ret);
335
0339cd77
LP
336 if (len != 4)
337 return -EINVAL;
f5c0c00f 338
0339cd77
LP
339 memcpy(ret, option, 4);
340 return 0;
f5c0c00f
TG
341}
342
e140ae58
TG
343static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
344 assert(option);
345 assert(ret);
346
0339cd77
LP
347 if (len <= 0)
348 *ret = mfree(*ret);
349 else {
e140ae58
TG
350 char *string;
351
e989fd9b
LP
352 /*
353 * One trailing NUL byte is OK, we don't mind. See:
354 * https://github.com/systemd/systemd/issues/1337
355 */
356 if (memchr(option, 0, len - 1))
43f447b1
LP
357 return -EINVAL;
358
e989fd9b 359 string = strndup((const char *) option, len);
e140ae58 360 if (!string)
43f447b1 361 return -ENOMEM;
e140ae58
TG
362
363 free(*ret);
364 *ret = string;
0339cd77 365 }
e140ae58
TG
366
367 return 0;
368}
369
978c6477
LP
370static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) {
371 _cleanup_free_ char *name = NULL, *normalized = NULL;
372 int r;
373
374 assert(option);
375 assert(ret);
376
377 r = lease_parse_string(option, len, &name);
378 if (r < 0)
379 return r;
380 if (!name) {
381 *ret = mfree(*ret);
382 return 0;
383 }
384
385 r = dns_name_normalize(name, &normalized);
386 if (r < 0)
387 return r;
388
389 if (is_localhost(normalized))
390 return -EINVAL;
391
392 if (dns_name_is_root(normalized))
393 return -EINVAL;
394
395 free(*ret);
396 *ret = normalized;
397 normalized = NULL;
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
1caa12d0
TG
474 r = in_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen);
475 if (r < 0) {
0339cd77 476 log_debug("Failed to determine destination prefix length from class based IP, ignoring");
e1ea665e
EY
477 continue;
478 }
479
0339cd77 480 assert_se(lease_parse_be32(option, 4, &addr.s_addr) >= 0);
e1ea665e
EY
481 route->dst_addr = inet_makeaddr(inet_netof(addr), 0);
482 option += 4;
483
0339cd77 484 assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0);
e1ea665e
EY
485 option += 4;
486
487 len -= 8;
488 (*routes_size)++;
489 }
490
491 return 0;
492}
493
494/* parses RFC3442 Classless Static Route Option */
0339cd77
LP
495static int lease_parse_classless_routes(
496 const uint8_t *option, size_t len,
497 struct sd_dhcp_route **routes, size_t *routes_size, size_t *routes_allocated) {
e1ea665e 498
0339cd77 499 assert(option || len <= 0);
e1ea665e
EY
500 assert(routes);
501 assert(routes_size);
502 assert(routes_allocated);
503
0339cd77
LP
504 if (len <= 0)
505 return 0;
506
e1ea665e
EY
507 /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */
508
509 while (len > 0) {
510 uint8_t dst_octets;
511 struct sd_dhcp_route *route;
512
513 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1))
0339cd77 514 return -ENOMEM;
e1ea665e
EY
515
516 route = *routes + *routes_size;
517
518 dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1);
519 route->dst_prefixlen = *option;
520 option++;
521 len--;
522
523 /* can't have more than 4 octets in IPv4 */
524 if (dst_octets > 4 || len < dst_octets)
525 return -EINVAL;
526
527 route->dst_addr.s_addr = 0;
528 memcpy(&route->dst_addr.s_addr, option, dst_octets);
529 option += dst_octets;
530 len -= dst_octets;
531
532 if (len < 4)
533 return -EINVAL;
534
b14fff6e 535 assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0);
e1ea665e
EY
536 option += 4;
537 len -= 4;
538
539 (*routes_size)++;
540 }
541
542 return 0;
543}
544
e4735228 545int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
2d03c0b8 546 sd_dhcp_lease *lease = userdata;
e140ae58
TG
547 int r;
548
549 assert(lease);
a6cc569e
TG
550
551 switch(code) {
552
22805d92 553 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
0339cd77
LP
554 r = lease_parse_u32(option, len, &lease->lifetime, 1);
555 if (r < 0)
556 log_debug_errno(r, "Failed to parse lease time, ignoring: %m");
557
a6cc569e
TG
558 break;
559
22805d92 560 case SD_DHCP_OPTION_SERVER_IDENTIFIER:
0339cd77
LP
561 r = lease_parse_be32(option, len, &lease->server_address);
562 if (r < 0)
563 log_debug_errno(r, "Failed to parse server identifier, ignoring: %m");
564
a6cc569e
TG
565 break;
566
22805d92 567 case SD_DHCP_OPTION_SUBNET_MASK:
0339cd77
LP
568 r = lease_parse_be32(option, len, &lease->subnet_mask);
569 if (r < 0)
570 log_debug_errno(r, "Failed to parse subnet mask, ignoring: %m");
571 else
572 lease->have_subnet_mask = true;
a6cc569e
TG
573 break;
574
22805d92 575 case SD_DHCP_OPTION_BROADCAST:
0339cd77
LP
576 r = lease_parse_be32(option, len, &lease->broadcast);
577 if (r < 0)
578 log_debug_errno(r, "Failed to parse broadcast address, ignoring: %m");
579 else
580 lease->have_broadcast = true;
f5c0c00f
TG
581 break;
582
22805d92 583 case SD_DHCP_OPTION_ROUTER:
0339cd77
LP
584 if (len >= 4) {
585 r = lease_parse_be32(option, 4, &lease->router);
586 if (r < 0)
587 log_debug_errno(r, "Failed to parse router address, ignoring: %m");
588 }
a6cc569e
TG
589 break;
590
22805d92 591 case SD_DHCP_OPTION_DOMAIN_NAME_SERVER:
0339cd77
LP
592 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
593 if (r < 0)
594 log_debug_errno(r, "Failed to parse DNS server, ignoring: %m");
a6cc569e
TG
595 break;
596
22805d92 597 case SD_DHCP_OPTION_NTP_SERVER:
0339cd77
LP
598 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
599 if (r < 0)
600 log_debug_errno(r, "Failed to parse NTP server, ignoring: %m");
f5c0c00f
TG
601 break;
602
22805d92 603 case SD_DHCP_OPTION_STATIC_ROUTE:
0339cd77
LP
604 r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size, &lease->static_route_allocated);
605 if (r < 0)
606 log_debug_errno(r, "Failed to parse static routes, ignoring: %m");
f5c0c00f
TG
607 break;
608
22805d92 609 case SD_DHCP_OPTION_INTERFACE_MTU:
0339cd77
LP
610 r = lease_parse_u16(option, len, &lease->mtu, 68);
611 if (r < 0)
612 log_debug_errno(r, "Failed to parse MTU, ignoring: %m");
955d99ed 613 if (lease->mtu < DHCP_DEFAULT_MIN_SIZE) {
4dd53da9 614 log_debug("MTU value of %" PRIu16 " too small. Using default MTU value of %d instead.", lease->mtu, DHCP_DEFAULT_MIN_SIZE);
955d99ed
MG
615 lease->mtu = DHCP_DEFAULT_MIN_SIZE;
616 }
617
f5c0c00f
TG
618 break;
619
978c6477
LP
620 case SD_DHCP_OPTION_DOMAIN_NAME:
621 r = lease_parse_domain(option, len, &lease->domainname);
0339cd77
LP
622 if (r < 0) {
623 log_debug_errno(r, "Failed to parse domain name, ignoring: %m");
624 return 0;
625 }
a6cc569e 626
784d9b9c 627 break;
784d9b9c 628
b85bc551
DW
629 case SD_DHCP_OPTION_DOMAIN_SEARCH_LIST:
630 r = dhcp_lease_parse_search_domains(option, len, &lease->search_domains);
631 if (r < 0)
632 log_debug_errno(r, "Failed to parse Domain Search List, ignoring: %m");
633 break;
634
978c6477
LP
635 case SD_DHCP_OPTION_HOST_NAME:
636 r = lease_parse_domain(option, len, &lease->hostname);
0339cd77
LP
637 if (r < 0) {
638 log_debug_errno(r, "Failed to parse host name, ignoring: %m");
639 return 0;
640 }
a6cc569e 641
784d9b9c 642 break;
ce78df79 643
22805d92 644 case SD_DHCP_OPTION_ROOT_PATH:
0339cd77
LP
645 r = lease_parse_string(option, len, &lease->root_path);
646 if (r < 0)
647 log_debug_errno(r, "Failed to parse root path, ignoring: %m");
648 break;
ce78df79 649
22805d92 650 case SD_DHCP_OPTION_RENEWAL_T1_TIME:
0339cd77
LP
651 r = lease_parse_u32(option, len, &lease->t1, 1);
652 if (r < 0)
653 log_debug_errno(r, "Failed to parse T1 time, ignoring: %m");
a6cc569e
TG
654 break;
655
22805d92 656 case SD_DHCP_OPTION_REBINDING_T2_TIME:
0339cd77
LP
657 r = lease_parse_u32(option, len, &lease->t2, 1);
658 if (r < 0)
659 log_debug_errno(r, "Failed to parse T2 time, ignoring: %m");
a6cc569e 660 break;
e1ea665e 661
22805d92 662 case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
0339cd77 663 r = lease_parse_classless_routes(
2d03c0b8
LP
664 option, len,
665 &lease->static_route,
666 &lease->static_route_size,
667 &lease->static_route_allocated);
0339cd77
LP
668 if (r < 0)
669 log_debug_errno(r, "Failed to parse classless routes, ignoring: %m");
670 break;
e43a8393 671
22805d92 672 case SD_DHCP_OPTION_NEW_TZDB_TIMEZONE: {
8eb9058d
LP
673 _cleanup_free_ char *tz = NULL;
674
675 r = lease_parse_string(option, len, &tz);
0339cd77
LP
676 if (r < 0) {
677 log_debug_errno(r, "Failed to parse timezone option, ignoring: %m");
678 return 0;
679 }
8eb9058d 680
0339cd77
LP
681 if (!timezone_is_valid(tz)) {
682 log_debug_errno(r, "Timezone is not valid, ignoring: %m");
683 return 0;
684 }
8eb9058d
LP
685
686 free(lease->timezone);
687 lease->timezone = tz;
688 tz = NULL;
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
TG
881
882 fchmod(fileno(f), 0644);
883
fe8db0c5 884 fprintf(f,
0339cd77 885 "# This is private data. Do not parse.\n");
fe8db0c5 886
0339cd77
LP
887 r = sd_dhcp_lease_get_address(lease, &address);
888 if (r >= 0)
889 fprintf(f, "ADDRESS=%s\n", inet_ntoa(address));
fe8db0c5 890
0339cd77
LP
891 r = sd_dhcp_lease_get_netmask(lease, &address);
892 if (r >= 0)
893 fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
fe8db0c5 894
8ddbeaa2
UTL
895 r = sd_dhcp_lease_get_router(lease, &address);
896 if (r >= 0)
897 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
898
0ad853bc 899 r = sd_dhcp_lease_get_server_identifier(lease, &address);
109731eb 900 if (r >= 0)
0339cd77 901 fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntoa(address));
0ad853bc 902
8e34a618 903 r = sd_dhcp_lease_get_next_server(lease, &address);
109731eb
TG
904 if (r >= 0)
905 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
8e34a618 906
0339cd77
LP
907 r = sd_dhcp_lease_get_broadcast(lease, &address);
908 if (r >= 0)
909 fprintf(f, "BROADCAST=%s\n", inet_ntoa(address));
910
fe8db0c5
TG
911 r = sd_dhcp_lease_get_mtu(lease, &mtu);
912 if (r >= 0)
913 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
914
0339cd77
LP
915 r = sd_dhcp_lease_get_t1(lease, &t1);
916 if (r >= 0)
917 fprintf(f, "T1=%" PRIu32 "\n", t1);
918
919 r = sd_dhcp_lease_get_t2(lease, &t2);
109731eb 920 if (r >= 0)
0339cd77
LP
921 fprintf(f, "T2=%" PRIu32 "\n", t2);
922
923 r = sd_dhcp_lease_get_lifetime(lease, &lifetime);
924 if (r >= 0)
925 fprintf(f, "LIFETIME=%" PRIu32 "\n", lifetime);
926
927 r = sd_dhcp_lease_get_dns(lease, &addresses);
928 if (r > 0) {
4b61c875 929 fputs_unlocked("DNS=", f);
b0e39c82 930 serialize_in_addrs(f, addresses, r);
4b61c875 931 fputs_unlocked("\n", f);
0339cd77 932 }
109731eb 933
a2ba62c7 934 r = sd_dhcp_lease_get_ntp(lease, &addresses);
0339cd77 935 if (r > 0) {
4b61c875 936 fputs_unlocked("NTP=", f);
b0e39c82 937 serialize_in_addrs(f, addresses, r);
4b61c875 938 fputs_unlocked("\n", f);
0339cd77 939 }
fe8db0c5
TG
940
941 r = sd_dhcp_lease_get_domainname(lease, &string);
942 if (r >= 0)
943 fprintf(f, "DOMAINNAME=%s\n", string);
944
b85bc551
DW
945 r = sd_dhcp_lease_get_search_domains(lease, &search_domains);
946 if (r > 0) {
4b61c875 947 fputs_unlocked("DOMAIN_SEARCH_LIST=", f);
b85bc551 948 fputstrv(f, search_domains, NULL, NULL);
4b61c875 949 fputs_unlocked("\n", f);
b85bc551
DW
950 }
951
fe8db0c5
TG
952 r = sd_dhcp_lease_get_hostname(lease, &string);
953 if (r >= 0)
954 fprintf(f, "HOSTNAME=%s\n", string);
955
ce78df79
TG
956 r = sd_dhcp_lease_get_root_path(lease, &string);
957 if (r >= 0)
958 fprintf(f, "ROOT_PATH=%s\n", string);
959
a2ba62c7 960 r = sd_dhcp_lease_get_routes(lease, &routes);
0339cd77 961 if (r > 0)
a2ba62c7 962 serialize_dhcp_routes(f, "ROUTES", routes, r);
e1ea665e 963
8eb9058d
LP
964 r = sd_dhcp_lease_get_timezone(lease, &string);
965 if (r >= 0)
966 fprintf(f, "TIMEZONE=%s\n", string);
967
e37f74a6
DW
968 r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
969 if (r >= 0) {
3587161a 970 _cleanup_free_ char *client_id_hex = NULL;
e37f74a6 971
dde8bb32 972 client_id_hex = hexmem(client_id, client_id_len);
e37f74a6
DW
973 if (!client_id_hex) {
974 r = -ENOMEM;
dacd6cee 975 goto fail;
e37f74a6
DW
976 }
977 fprintf(f, "CLIENTID=%s\n", client_id_hex);
978 }
979
e43a8393
BG
980 r = sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len);
981 if (r >= 0) {
982 _cleanup_free_ char *option_hex = NULL;
983
984 option_hex = hexmem(data, data_len);
985 if (!option_hex) {
986 r = -ENOMEM;
dacd6cee 987 goto fail;
e43a8393
BG
988 }
989 fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
990 }
991
a073309f 992 LIST_FOREACH(options, option, lease->private_options) {
30afef87 993 char key[strlen("OPTION_000")+1];
0339cd77 994
d054f0a4 995 xsprintf(key, "OPTION_%" PRIu8, option->tag);
a073309f
AC
996 r = serialize_dhcp_option(f, key, option->data, option->length);
997 if (r < 0)
998 goto fail;
999 }
1000
dacd6cee
LP
1001 r = fflush_and_check(f);
1002 if (r < 0)
1003 goto fail;
fe8db0c5 1004
dacd6cee 1005 if (rename(temp_path, lease_file) < 0) {
fe8db0c5 1006 r = -errno;
dacd6cee 1007 goto fail;
fe8db0c5
TG
1008 }
1009
dacd6cee
LP
1010 return 0;
1011
1012fail:
1013 if (temp_path)
1014 (void) unlink(temp_path);
fe8db0c5 1015
dacd6cee 1016 return log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
fe8db0c5
TG
1017}
1018
bd91b83e 1019int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
0339cd77 1020
4afd3348 1021 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
0339cd77
LP
1022 _cleanup_free_ char
1023 *address = NULL,
1024 *router = NULL,
1025 *netmask = NULL,
1026 *server_address = NULL,
1027 *next_server = NULL,
1028 *broadcast = NULL,
1029 *dns = NULL,
1030 *ntp = NULL,
1031 *mtu = NULL,
1032 *routes = NULL,
b85bc551 1033 *domains = NULL,
0339cd77
LP
1034 *client_id_hex = NULL,
1035 *vendor_specific_hex = NULL,
1036 *lifetime = NULL,
1037 *t1 = NULL,
1038 *t2 = NULL,
22805d92 1039 *options[SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE + 1] = {};
0339cd77 1040
a073309f 1041 int r, i;
fe8db0c5
TG
1042
1043 assert(lease_file);
1044 assert(ret);
1045
1046 r = dhcp_lease_new(&lease);
1047 if (r < 0)
1048 return r;
1049
1050 r = parse_env_file(lease_file, NEWLINE,
1051 "ADDRESS", &address,
1052 "ROUTER", &router,
1053 "NETMASK", &netmask,
0ad853bc 1054 "SERVER_IDENTIFIER", &server_address,
8e34a618 1055 "NEXT_SERVER", &next_server,
0339cd77 1056 "BROADCAST", &broadcast,
109731eb
TG
1057 "DNS", &dns,
1058 "NTP", &ntp,
fe8db0c5
TG
1059 "MTU", &mtu,
1060 "DOMAINNAME", &lease->domainname,
1061 "HOSTNAME", &lease->hostname,
b85bc551 1062 "DOMAIN_SEARCH_LIST", &domains,
ce78df79 1063 "ROOT_PATH", &lease->root_path,
e1ea665e 1064 "ROUTES", &routes,
e37f74a6 1065 "CLIENTID", &client_id_hex,
8eb9058d 1066 "TIMEZONE", &lease->timezone,
e43a8393 1067 "VENDOR_SPECIFIC", &vendor_specific_hex,
0339cd77
LP
1068 "LIFETIME", &lifetime,
1069 "T1", &t1,
1070 "T2", &t2,
a073309f
AC
1071 "OPTION_224", &options[0],
1072 "OPTION_225", &options[1],
1073 "OPTION_226", &options[2],
1074 "OPTION_227", &options[3],
1075 "OPTION_228", &options[4],
1076 "OPTION_229", &options[5],
1077 "OPTION_230", &options[6],
1078 "OPTION_231", &options[7],
1079 "OPTION_232", &options[8],
1080 "OPTION_233", &options[9],
1081 "OPTION_234", &options[10],
1082 "OPTION_235", &options[11],
1083 "OPTION_236", &options[12],
1084 "OPTION_237", &options[13],
1085 "OPTION_238", &options[14],
1086 "OPTION_239", &options[15],
1087 "OPTION_240", &options[16],
1088 "OPTION_241", &options[17],
1089 "OPTION_242", &options[18],
1090 "OPTION_243", &options[19],
1091 "OPTION_244", &options[20],
1092 "OPTION_245", &options[21],
1093 "OPTION_246", &options[22],
1094 "OPTION_247", &options[23],
1095 "OPTION_248", &options[24],
1096 "OPTION_249", &options[25],
1097 "OPTION_250", &options[26],
1098 "OPTION_251", &options[27],
1099 "OPTION_252", &options[28],
1100 "OPTION_253", &options[29],
1101 "OPTION_254", &options[30],
fe8db0c5 1102 NULL);
fe8db0c5
TG
1103 if (r < 0)
1104 return r;
1105
0339cd77
LP
1106 if (address) {
1107 r = inet_pton(AF_INET, address, &lease->address);
1108 if (r <= 0)
e26ea7fc 1109 log_debug("Failed to parse address %s, ignoring.", address);
0339cd77 1110 }
fe8db0c5 1111
8ddbeaa2 1112 if (router) {
0339cd77
LP
1113 r = inet_pton(AF_INET, router, &lease->router);
1114 if (r <= 0)
e26ea7fc 1115 log_debug("Failed to parse router %s, ignoring.", router);
8ddbeaa2 1116 }
fe8db0c5 1117
0339cd77
LP
1118 if (netmask) {
1119 r = inet_pton(AF_INET, netmask, &lease->subnet_mask);
1120 if (r <= 0)
e26ea7fc 1121 log_debug("Failed to parse netmask %s, ignoring.", netmask);
0339cd77
LP
1122 else
1123 lease->have_subnet_mask = true;
1124 }
fe8db0c5 1125
0ad853bc 1126 if (server_address) {
0339cd77
LP
1127 r = inet_pton(AF_INET, server_address, &lease->server_address);
1128 if (r <= 0)
e26ea7fc 1129 log_debug("Failed to parse server address %s, ignoring.", server_address);
0ad853bc
TG
1130 }
1131
8e34a618 1132 if (next_server) {
0339cd77
LP
1133 r = inet_pton(AF_INET, next_server, &lease->next_server);
1134 if (r <= 0)
e26ea7fc 1135 log_debug("Failed to parse next server %s, ignoring.", next_server);
0339cd77 1136 }
8e34a618 1137
0339cd77
LP
1138 if (broadcast) {
1139 r = inet_pton(AF_INET, broadcast, &lease->broadcast);
1140 if (r <= 0)
e26ea7fc 1141 log_debug("Failed to parse broadcast address %s, ignoring.", broadcast);
0339cd77
LP
1142 else
1143 lease->have_broadcast = true;
8e34a618
TG
1144 }
1145
109731eb 1146 if (dns) {
a2ba62c7 1147 r = deserialize_in_addrs(&lease->dns, dns);
109731eb 1148 if (r < 0)
0339cd77
LP
1149 log_debug_errno(r, "Failed to deserialize DNS servers %s, ignoring: %m", dns);
1150 else
1151 lease->dns_size = r;
109731eb
TG
1152 }
1153
1154 if (ntp) {
a2ba62c7 1155 r = deserialize_in_addrs(&lease->ntp, ntp);
109731eb 1156 if (r < 0)
0339cd77
LP
1157 log_debug_errno(r, "Failed to deserialize NTP servers %s, ignoring: %m", ntp);
1158 else
1159 lease->ntp_size = r;
109731eb
TG
1160 }
1161
fe8db0c5 1162 if (mtu) {
0339cd77
LP
1163 r = safe_atou16(mtu, &lease->mtu);
1164 if (r < 0)
1165 log_debug_errno(r, "Failed to parse MTU %s, ignoring: %m", mtu);
fe8db0c5
TG
1166 }
1167
b85bc551
DW
1168 if (domains) {
1169 _cleanup_strv_free_ char **a = NULL;
1170 a = strv_split(domains, " ");
1171 if (!a)
1172 return -ENOMEM;
1173
1174 if (!strv_isempty(a)) {
1175 lease->search_domains = a;
1176 a = NULL;
1177 }
1178 }
1179
e1ea665e 1180 if (routes) {
0339cd77
LP
1181 r = deserialize_dhcp_routes(
1182 &lease->static_route,
1183 &lease->static_route_size,
1184 &lease->static_route_allocated,
1185 routes);
1186 if (r < 0)
1187 log_debug_errno(r, "Failed to parse DHCP routes %s, ignoring: %m", routes);
1188 }
1189
1190 if (lifetime) {
1191 r = safe_atou32(lifetime, &lease->lifetime);
1192 if (r < 0)
1193 log_debug_errno(r, "Failed to parse lifetime %s, ignoring: %m", lifetime);
1194 }
1195
1196 if (t1) {
1197 r = safe_atou32(t1, &lease->t1);
1198 if (r < 0)
1199 log_debug_errno(r, "Failed to parse T1 %s, ignoring: %m", t1);
1200 }
1201
1202 if (t2) {
1203 r = safe_atou32(t2, &lease->t2);
e1ea665e 1204 if (r < 0)
0339cd77 1205 log_debug_errno(r, "Failed to parse T2 %s, ignoring: %m", t2);
e1ea665e
EY
1206 }
1207
e37f74a6 1208 if (client_id_hex) {
9b57d9ae 1209 r = deserialize_dhcp_option(&lease->client_id, &lease->client_id_len, client_id_hex);
30494563 1210 if (r < 0)
0339cd77 1211 log_debug_errno(r, "Failed to parse client ID %s, ignoring: %m", client_id_hex);
e37f74a6
DW
1212 }
1213
e43a8393 1214 if (vendor_specific_hex) {
9b57d9ae 1215 r = deserialize_dhcp_option(&lease->vendor_specific, &lease->vendor_specific_len, vendor_specific_hex);
e43a8393 1216 if (r < 0)
0339cd77 1217 log_debug_errno(r, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex);
e43a8393
BG
1218 }
1219
22805d92 1220 for (i = 0; i <= SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE; i++) {
e4735228 1221 _cleanup_free_ void *data = NULL;
a073309f
AC
1222 size_t len;
1223
1224 if (!options[i])
1225 continue;
1226
1227 r = deserialize_dhcp_option(&data, &len, options[i]);
0339cd77
LP
1228 if (r < 0) {
1229 log_debug_errno(r, "Failed to parse private DHCP option %s, ignoring: %m", options[i]);
1230 continue;
1231 }
a073309f 1232
22805d92 1233 r = dhcp_lease_insert_private_option(lease, SD_DHCP_OPTION_PRIVATE_BASE + i, data, len);
626be147 1234 if (r < 0)
a073309f
AC
1235 return r;
1236 }
1237
fe8db0c5
TG
1238 *ret = lease;
1239 lease = NULL;
1240
1241 return 0;
1242}
9e64dd72
TG
1243
1244int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
0339cd77 1245 struct in_addr address, mask;
df40eee8 1246 int r;
9e64dd72
TG
1247
1248 assert(lease);
9e64dd72 1249
0339cd77
LP
1250 if (lease->address == 0)
1251 return -ENODATA;
1252
df40eee8 1253 address.s_addr = lease->address;
9e64dd72
TG
1254
1255 /* fall back to the default subnet masks based on address class */
df40eee8
TG
1256 r = in_addr_default_subnet_mask(&address, &mask);
1257 if (r < 0)
1258 return r;
9e64dd72 1259
df40eee8 1260 lease->subnet_mask = mask.s_addr;
0339cd77 1261 lease->have_subnet_mask = true;
9e64dd72
TG
1262
1263 return 0;
1264}
e37f74a6 1265
0339cd77 1266int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len) {
e37f74a6
DW
1267 assert_return(lease, -EINVAL);
1268 assert_return(client_id, -EINVAL);
1269 assert_return(client_id_len, -EINVAL);
1270
0339cd77
LP
1271 if (!lease->client_id)
1272 return -ENODATA;
1273
e37f74a6
DW
1274 *client_id = lease->client_id;
1275 *client_id_len = lease->client_id_len;
0339cd77 1276
e37f74a6
DW
1277 return 0;
1278}
1279
0339cd77 1280int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len) {
e37f74a6 1281 assert_return(lease, -EINVAL);
0339cd77
LP
1282 assert_return(client_id || client_id_len <= 0, -EINVAL);
1283
1284 if (client_id_len <= 0)
1285 lease->client_id = mfree(lease->client_id);
1286 else {
1287 void *p;
e37f74a6 1288
0339cd77
LP
1289 p = memdup(client_id, client_id_len);
1290 if (!p)
1291 return -ENOMEM;
e37f74a6 1292
0339cd77
LP
1293 free(lease->client_id);
1294 lease->client_id = p;
e37f74a6
DW
1295 lease->client_id_len = client_id_len;
1296 }
1297
1298 return 0;
1299}
8eb9058d 1300
64d6c229 1301int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **tz) {
8eb9058d 1302 assert_return(lease, -EINVAL);
64d6c229 1303 assert_return(tz, -EINVAL);
8eb9058d
LP
1304
1305 if (!lease->timezone)
0339cd77 1306 return -ENODATA;
8eb9058d 1307
64d6c229 1308 *tz = lease->timezone;
8eb9058d
LP
1309 return 0;
1310}
f8693fc7
BG
1311
1312int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination) {
1313 assert_return(route, -EINVAL);
1314 assert_return(destination, -EINVAL);
1315
1316 *destination = route->dst_addr;
1317 return 0;
1318}
1319
1320int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length) {
1321 assert_return(route, -EINVAL);
1322 assert_return(length, -EINVAL);
1323
1324 *length = route->dst_prefixlen;
1325 return 0;
1326}
1327
1328int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway) {
1329 assert_return(route, -EINVAL);
1330 assert_return(gateway, -EINVAL);
1331
1332 *gateway = route->gw_addr;
1333 return 0;
1334}