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