]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp-lease.c
tree-wide: use "hostname" spelling everywhere
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp-lease.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 Copyright © 2013 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <arpa/inet.h>
7 #include <errno.h>
8 #include <stdlib.h>
9 #include <sys/stat.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12
13 #include "sd-dhcp-lease.h"
14
15 #include "alloc-util.h"
16 #include "dhcp-lease-internal.h"
17 #include "dhcp-protocol.h"
18 #include "dns-domain.h"
19 #include "env-file.h"
20 #include "fd-util.h"
21 #include "fileio.h"
22 #include "hexdecoct.h"
23 #include "hostname-util.h"
24 #include "in-addr-util.h"
25 #include "network-internal.h"
26 #include "parse-util.h"
27 #include "stdio-util.h"
28 #include "string-util.h"
29 #include "strv.h"
30 #include "tmpfile-util.h"
31 #include "unaligned.h"
32
33 int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
34 assert_return(lease, -EINVAL);
35 assert_return(addr, -EINVAL);
36
37 if (lease->address == 0)
38 return -ENODATA;
39
40 addr->s_addr = lease->address;
41 return 0;
42 }
43
44 int 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;
52 return 0;
53 }
54
55 int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
56 assert_return(lease, -EINVAL);
57 assert_return(lifetime, -EINVAL);
58
59 if (lease->lifetime <= 0)
60 return -ENODATA;
61
62 *lifetime = lease->lifetime;
63 return 0;
64 }
65
66 int 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
77 int 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;
85 return 0;
86 }
87
88 int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
89 assert_return(lease, -EINVAL);
90 assert_return(mtu, -EINVAL);
91
92 if (lease->mtu <= 0)
93 return -ENODATA;
94
95 *mtu = lease->mtu;
96 return 0;
97 }
98
99 int sd_dhcp_lease_get_servers(
100 sd_dhcp_lease *lease,
101 sd_dhcp_lease_info what,
102 const struct in_addr **addr) {
103
104 assert_return(lease, -EINVAL);
105 assert_return(addr, -EINVAL);
106
107 switch (what) {
108 case SD_DHCP_LEASE_DNS_SERVERS:
109 if (lease->dns_size <= 0)
110 return -ENODATA;
111
112 *addr = lease->dns;
113 return (int) lease->dns_size;
114
115 case SD_DHCP_LEASE_NTP_SERVERS:
116 if (lease->ntp_size <= 0)
117 return -ENODATA;
118
119 *addr = lease->ntp;
120 return (int) lease->ntp_size;
121
122 case SD_DHCP_LEASE_SIP_SERVERS:
123 if (lease->sip_size <= 0)
124 return -ENODATA;
125
126 *addr = lease->sip;
127 return (int) lease->sip_size;
128
129 case SD_DHCP_LEASE_POP3_SERVERS:
130 if (lease->pop3_server_size <= 0)
131 return -ENODATA;
132
133 *addr = lease->pop3_server;
134 return (int) lease->pop3_server_size;
135
136 case SD_DHCP_LEASE_SMTP_SERVERS:
137 if (lease->smtp_server_size <= 0)
138 return -ENODATA;
139
140 *addr = lease->smtp_server;
141 return (int) lease->smtp_server_size;
142
143 default:
144 log_debug("Uknown DHCP lease info item %d.", what);
145 return -ENXIO;
146 }
147 }
148
149 int 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 }
152 int 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 }
155 int 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 }
158 int 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 }
161 int sd_dhcp_lease_get_smtp_server(sd_dhcp_lease *lease, const struct in_addr **addr) {
162 return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_SMTP_SERVERS, addr);
163 }
164
165 int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
166 assert_return(lease, -EINVAL);
167 assert_return(domainname, -EINVAL);
168
169 if (!lease->domainname)
170 return -ENODATA;
171
172 *domainname = lease->domainname;
173 return 0;
174 }
175
176 int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
177 assert_return(lease, -EINVAL);
178 assert_return(hostname, -EINVAL);
179
180 if (!lease->hostname)
181 return -ENODATA;
182
183 *hostname = lease->hostname;
184 return 0;
185 }
186
187 int 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
191 if (!lease->root_path)
192 return -ENODATA;
193
194 *root_path = lease->root_path;
195 return 0;
196 }
197
198 int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr) {
199 assert_return(lease, -EINVAL);
200 assert_return(addr, -EINVAL);
201
202 if (lease->router_size <= 0)
203 return -ENODATA;
204
205 *addr = lease->router;
206 return (int) lease->router_size;
207 }
208
209 int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
210 assert_return(lease, -EINVAL);
211 assert_return(addr, -EINVAL);
212
213 if (!lease->have_subnet_mask)
214 return -ENODATA;
215
216 addr->s_addr = lease->subnet_mask;
217 return 0;
218 }
219
220 int 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
224 if (lease->server_address == 0)
225 return -ENODATA;
226
227 addr->s_addr = lease->server_address;
228 return 0;
229 }
230
231 int 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
235 if (lease->next_server == 0)
236 return -ENODATA;
237
238 addr->s_addr = lease->next_server;
239 return 0;
240 }
241
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 */
246 int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes) {
247 sd_dhcp_route **ret;
248 unsigned i;
249
250 assert_return(lease, -EINVAL);
251 assert_return(routes, -EINVAL);
252
253 if (lease->static_route_size <= 0)
254 return -ENODATA;
255
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;
264 return (int) lease->static_route_size;
265 }
266
267 int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) {
268 size_t r;
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
282 int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len) {
283 assert_return(lease, -EINVAL);
284 assert_return(data, -EINVAL);
285 assert_return(data_len, -EINVAL);
286
287 if (lease->vendor_specific_len <= 0)
288 return -ENODATA;
289
290 *data = lease->vendor_specific;
291 *data_len = lease->vendor_specific_len;
292 return 0;
293 }
294
295 static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) {
296 assert(lease);
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);
305 }
306
307 free(lease->root_path);
308 free(lease->router);
309 free(lease->timezone);
310 free(lease->hostname);
311 free(lease->domainname);
312 free(lease->dns);
313 free(lease->ntp);
314 free(lease->sip);
315 free(lease->pop3_server);
316 free(lease->smtp_server);
317 free(lease->static_route);
318 free(lease->client_id);
319 free(lease->vendor_specific);
320 strv_free(lease->search_domains);
321 return mfree(lease);
322 }
323
324 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_lease, sd_dhcp_lease, dhcp_lease_free);
325
326 static int lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
327 assert(option);
328 assert(ret);
329
330 if (len != 4)
331 return -EINVAL;
332
333 *ret = unaligned_read_be32((be32_t*) option);
334 if (*ret < min)
335 *ret = min;
336
337 return 0;
338 }
339
340 static int lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
341 assert(option);
342 assert(ret);
343
344 if (len != 2)
345 return -EINVAL;
346
347 *ret = unaligned_read_be16((be16_t*) option);
348 if (*ret < min)
349 *ret = min;
350
351 return 0;
352 }
353
354 static int lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
355 assert(option);
356 assert(ret);
357
358 if (len != 4)
359 return -EINVAL;
360
361 memcpy(ret, option, 4);
362 return 0;
363 }
364
365 static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
366 assert(option);
367 assert(ret);
368
369 if (len <= 0)
370 *ret = mfree(*ret);
371 else {
372 char *string;
373
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))
379 return -EINVAL;
380
381 string = memdup_suffix0((const char *) option, len);
382 if (!string)
383 return -ENOMEM;
384
385 free_and_replace(*ret, string);
386 }
387
388 return 0;
389 }
390
391 static 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
406 r = dns_name_normalize(name, 0, &normalized);
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
416 free_and_replace(*ret, normalized);
417
418 return 0;
419 }
420
421 static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) {
422 assert(option);
423 assert(ret);
424 assert(n_ret);
425
426 if (len <= 0) {
427 *ret = mfree(*ret);
428 *n_ret = 0;
429 } else {
430 size_t n_addresses;
431 struct in_addr *addresses;
432
433 if (len % 4 != 0)
434 return -EINVAL;
435
436 n_addresses = len / 4;
437
438 addresses = newdup(struct in_addr, option, n_addresses);
439 if (!addresses)
440 return -ENOMEM;
441
442 free(*ret);
443 *ret = addresses;
444 *n_ret = n_addresses;
445 }
446
447 return 0;
448 }
449
450 static 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
480 static 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) {
483
484 struct in_addr addr;
485
486 assert(option || len <= 0);
487 assert(routes);
488 assert(routes_size);
489 assert(routes_allocated);
490
491 if (len <= 0)
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;
502 int r;
503
504 route->option = SD_DHCP_OPTION_STATIC_ROUTE;
505 r = in4_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen);
506 if (r < 0) {
507 log_debug("Failed to determine destination prefix length from class based IP, ignoring");
508 continue;
509 }
510
511 assert_se(lease_parse_be32(option, 4, &addr.s_addr) >= 0);
512 route->dst_addr = inet_makeaddr(inet_netof(addr), 0);
513 option += 4;
514
515 assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0);
516 option += 4;
517
518 len -= 8;
519 (*routes_size)++;
520 }
521
522 return 0;
523 }
524
525 /* parses RFC3442 Classless Static Route Option */
526 static 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) {
529
530 assert(option || len <= 0);
531 assert(routes);
532 assert(routes_size);
533 assert(routes_allocated);
534
535 if (len <= 0)
536 return 0;
537
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))
545 return -ENOMEM;
546
547 route = *routes + *routes_size;
548 route->option = SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE;
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
567 assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0);
568 option += 4;
569 len -= 4;
570
571 (*routes_size)++;
572 }
573
574 return 0;
575 }
576
577 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
578 sd_dhcp_lease *lease = userdata;
579 int r;
580
581 assert(lease);
582
583 switch(code) {
584
585 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
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
590 break;
591
592 case SD_DHCP_OPTION_SERVER_IDENTIFIER:
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
597 break;
598
599 case SD_DHCP_OPTION_SUBNET_MASK:
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;
605 break;
606
607 case SD_DHCP_OPTION_BROADCAST:
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;
613 break;
614
615 case SD_DHCP_OPTION_ROUTER:
616 r = lease_parse_in_addrs(option, len, &lease->router, &lease->router_size);
617 if (r < 0)
618 log_debug_errno(r, "Failed to parse router addresses, ignoring: %m");
619 break;
620
621 case SD_DHCP_OPTION_DOMAIN_NAME_SERVER:
622 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
623 if (r < 0)
624 log_debug_errno(r, "Failed to parse DNS server, ignoring: %m");
625 break;
626
627 case SD_DHCP_OPTION_NTP_SERVER:
628 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
629 if (r < 0)
630 log_debug_errno(r, "Failed to parse NTP server, ignoring: %m");
631 break;
632
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
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
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
651 case SD_DHCP_OPTION_STATIC_ROUTE:
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");
655 break;
656
657 case SD_DHCP_OPTION_INTERFACE_MTU:
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");
661 if (lease->mtu < DHCP_DEFAULT_MIN_SIZE) {
662 log_debug("MTU value of %" PRIu16 " too small. Using default MTU value of %d instead.", lease->mtu, DHCP_DEFAULT_MIN_SIZE);
663 lease->mtu = DHCP_DEFAULT_MIN_SIZE;
664 }
665
666 break;
667
668 case SD_DHCP_OPTION_DOMAIN_NAME:
669 r = lease_parse_domain(option, len, &lease->domainname);
670 if (r < 0) {
671 log_debug_errno(r, "Failed to parse domain name, ignoring: %m");
672 return 0;
673 }
674
675 break;
676
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
683 case SD_DHCP_OPTION_HOST_NAME:
684 r = lease_parse_domain(option, len, &lease->hostname);
685 if (r < 0) {
686 log_debug_errno(r, "Failed to parse hostname, ignoring: %m");
687 return 0;
688 }
689
690 break;
691
692 case SD_DHCP_OPTION_ROOT_PATH:
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;
697
698 case SD_DHCP_OPTION_RENEWAL_T1_TIME:
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");
702 break;
703
704 case SD_DHCP_OPTION_REBINDING_T2_TIME:
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");
708 break;
709
710 case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
711 r = lease_parse_classless_routes(
712 option, len,
713 &lease->static_route,
714 &lease->static_route_size,
715 &lease->static_route_allocated);
716 if (r < 0)
717 log_debug_errno(r, "Failed to parse classless routes, ignoring: %m");
718 break;
719
720 case SD_DHCP_OPTION_NEW_TZDB_TIMEZONE: {
721 _cleanup_free_ char *tz = NULL;
722
723 r = lease_parse_string(option, len, &tz);
724 if (r < 0) {
725 log_debug_errno(r, "Failed to parse timezone option, ignoring: %m");
726 return 0;
727 }
728
729 if (!timezone_is_valid(tz, LOG_DEBUG)) {
730 log_debug_errno(r, "Timezone is not valid, ignoring: %m");
731 return 0;
732 }
733
734 free_and_replace(lease->timezone, tz);
735
736 break;
737 }
738
739 case SD_DHCP_OPTION_VENDOR_SPECIFIC:
740
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)
748 return -ENOMEM;
749
750 free(lease->vendor_specific);
751 lease->vendor_specific = p;
752 }
753
754 lease->vendor_specific_len = len;
755 break;
756
757 case SD_DHCP_OPTION_PRIVATE_BASE ... SD_DHCP_OPTION_PRIVATE_LAST:
758 r = dhcp_lease_insert_private_option(lease, code, option, len);
759 if (r < 0)
760 return r;
761
762 break;
763
764 default:
765 log_debug("Ignoring option DHCP option %"PRIu8" while parsing.", code);
766 break;
767 }
768
769 return 0;
770 }
771
772 /* Parses compressed domain names. */
773 int 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
856 *domains = TAKE_PTR(names);
857
858 return cnt;
859 }
860
861 int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len) {
862 struct sd_dhcp_raw_option *cur, *option;
863
864 assert(lease);
865
866 LIST_FOREACH(options, cur, lease->private_options) {
867 if (tag < cur->tag)
868 break;
869 if (tag == cur->tag) {
870 log_debug("Ignoring duplicate option, tagged %i.", tag);
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);
888 return 0;
889 }
890
891 int dhcp_lease_new(sd_dhcp_lease **ret) {
892 sd_dhcp_lease *lease;
893
894 lease = new0(sd_dhcp_lease, 1);
895 if (!lease)
896 return -ENOMEM;
897
898 lease->n_ref = 1;
899
900 *ret = lease;
901 return 0;
902 }
903
904 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
905 _cleanup_free_ char *temp_path = NULL;
906 _cleanup_fclose_ FILE *f = NULL;
907 struct sd_dhcp_raw_option *option;
908 struct in_addr address;
909 const struct in_addr *addresses;
910 const void *client_id, *data;
911 size_t client_id_len, data_len;
912 char sbuf[INET_ADDRSTRLEN];
913 const char *string;
914 uint16_t mtu;
915 _cleanup_free_ sd_dhcp_route **routes = NULL;
916 char **search_domains = NULL;
917 uint32_t t1, t2, lifetime;
918 int r;
919
920 assert(lease);
921 assert(lease_file);
922
923 r = fopen_temporary(lease_file, &f, &temp_path);
924 if (r < 0)
925 goto fail;
926
927 (void) fchmod(fileno(f), 0644);
928
929 fprintf(f,
930 "# This is private data. Do not parse.\n");
931
932 r = sd_dhcp_lease_get_address(lease, &address);
933 if (r >= 0)
934 fprintf(f, "ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
935
936 r = sd_dhcp_lease_get_netmask(lease, &address);
937 if (r >= 0)
938 fprintf(f, "NETMASK=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
939
940 r = sd_dhcp_lease_get_router(lease, &addresses);
941 if (r > 0) {
942 fputs("ROUTER=", f);
943 serialize_in_addrs(f, addresses, r, false, NULL);
944 fputc('\n', f);
945 }
946
947 r = sd_dhcp_lease_get_server_identifier(lease, &address);
948 if (r >= 0)
949 fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
950
951 r = sd_dhcp_lease_get_next_server(lease, &address);
952 if (r >= 0)
953 fprintf(f, "NEXT_SERVER=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
954
955 r = sd_dhcp_lease_get_broadcast(lease, &address);
956 if (r >= 0)
957 fprintf(f, "BROADCAST=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
958
959 r = sd_dhcp_lease_get_mtu(lease, &mtu);
960 if (r >= 0)
961 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
962
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);
968 if (r >= 0)
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) {
977 fputs("DNS=", f);
978 serialize_in_addrs(f, addresses, r, false, NULL);
979 fputc('\n', f);
980 }
981
982 r = sd_dhcp_lease_get_ntp(lease, &addresses);
983 if (r > 0) {
984 fputs("NTP=", f);
985 serialize_in_addrs(f, addresses, r, false, NULL);
986 fputc('\n', f);
987 }
988
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
996 r = sd_dhcp_lease_get_domainname(lease, &string);
997 if (r >= 0)
998 fprintf(f, "DOMAINNAME=%s\n", string);
999
1000 r = sd_dhcp_lease_get_search_domains(lease, &search_domains);
1001 if (r > 0) {
1002 fputs("DOMAIN_SEARCH_LIST=", f);
1003 fputstrv(f, search_domains, NULL, NULL);
1004 fputc('\n', f);
1005 }
1006
1007 r = sd_dhcp_lease_get_hostname(lease, &string);
1008 if (r >= 0)
1009 fprintf(f, "HOSTNAME=%s\n", string);
1010
1011 r = sd_dhcp_lease_get_root_path(lease, &string);
1012 if (r >= 0)
1013 fprintf(f, "ROOT_PATH=%s\n", string);
1014
1015 r = sd_dhcp_lease_get_routes(lease, &routes);
1016 if (r > 0)
1017 serialize_dhcp_routes(f, "ROUTES", routes, r);
1018
1019 r = sd_dhcp_lease_get_timezone(lease, &string);
1020 if (r >= 0)
1021 fprintf(f, "TIMEZONE=%s\n", string);
1022
1023 r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
1024 if (r >= 0) {
1025 _cleanup_free_ char *client_id_hex = NULL;
1026
1027 client_id_hex = hexmem(client_id, client_id_len);
1028 if (!client_id_hex) {
1029 r = -ENOMEM;
1030 goto fail;
1031 }
1032 fprintf(f, "CLIENTID=%s\n", client_id_hex);
1033 }
1034
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;
1042 goto fail;
1043 }
1044 fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
1045 }
1046
1047 LIST_FOREACH(options, option, lease->private_options) {
1048 char key[STRLEN("OPTION_000")+1];
1049
1050 xsprintf(key, "OPTION_%" PRIu8, option->tag);
1051 r = serialize_dhcp_option(f, key, option->data, option->length);
1052 if (r < 0)
1053 goto fail;
1054 }
1055
1056 r = fflush_and_check(f);
1057 if (r < 0)
1058 goto fail;
1059
1060 if (rename(temp_path, lease_file) < 0) {
1061 r = -errno;
1062 goto fail;
1063 }
1064
1065 return 0;
1066
1067 fail:
1068 if (temp_path)
1069 (void) unlink(temp_path);
1070
1071 return log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
1072 }
1073
1074 int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
1075
1076 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
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,
1086 *sip = NULL,
1087 *pop3_server = NULL,
1088 *smtp_server = NULL,
1089 *mtu = NULL,
1090 *routes = NULL,
1091 *domains = NULL,
1092 *client_id_hex = NULL,
1093 *vendor_specific_hex = NULL,
1094 *lifetime = NULL,
1095 *t1 = NULL,
1096 *t2 = NULL,
1097 *options[SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE + 1] = {};
1098
1099 int r, i;
1100
1101 assert(lease_file);
1102 assert(ret);
1103
1104 r = dhcp_lease_new(&lease);
1105 if (r < 0)
1106 return r;
1107
1108 r = parse_env_file(NULL, lease_file,
1109 "ADDRESS", &address,
1110 "ROUTER", &router,
1111 "NETMASK", &netmask,
1112 "SERVER_IDENTIFIER", &server_address,
1113 "NEXT_SERVER", &next_server,
1114 "BROADCAST", &broadcast,
1115 "DNS", &dns,
1116 "NTP", &ntp,
1117 "SIP", &sip,
1118 "POP3_SERVERS", &pop3_server,
1119 "SMTP_SERVERS", &smtp_server,
1120 "MTU", &mtu,
1121 "DOMAINNAME", &lease->domainname,
1122 "HOSTNAME", &lease->hostname,
1123 "DOMAIN_SEARCH_LIST", &domains,
1124 "ROOT_PATH", &lease->root_path,
1125 "ROUTES", &routes,
1126 "CLIENTID", &client_id_hex,
1127 "TIMEZONE", &lease->timezone,
1128 "VENDOR_SPECIFIC", &vendor_specific_hex,
1129 "LIFETIME", &lifetime,
1130 "T1", &t1,
1131 "T2", &t2,
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],
1162 "OPTION_254", &options[30]);
1163 if (r < 0)
1164 return r;
1165
1166 if (address) {
1167 r = inet_pton(AF_INET, address, &lease->address);
1168 if (r <= 0)
1169 log_debug("Failed to parse address %s, ignoring.", address);
1170 }
1171
1172 if (router) {
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;
1178 }
1179
1180 if (netmask) {
1181 r = inet_pton(AF_INET, netmask, &lease->subnet_mask);
1182 if (r <= 0)
1183 log_debug("Failed to parse netmask %s, ignoring.", netmask);
1184 else
1185 lease->have_subnet_mask = true;
1186 }
1187
1188 if (server_address) {
1189 r = inet_pton(AF_INET, server_address, &lease->server_address);
1190 if (r <= 0)
1191 log_debug("Failed to parse server address %s, ignoring.", server_address);
1192 }
1193
1194 if (next_server) {
1195 r = inet_pton(AF_INET, next_server, &lease->next_server);
1196 if (r <= 0)
1197 log_debug("Failed to parse next server %s, ignoring.", next_server);
1198 }
1199
1200 if (broadcast) {
1201 r = inet_pton(AF_INET, broadcast, &lease->broadcast);
1202 if (r <= 0)
1203 log_debug("Failed to parse broadcast address %s, ignoring.", broadcast);
1204 else
1205 lease->have_broadcast = true;
1206 }
1207
1208 if (dns) {
1209 r = deserialize_in_addrs(&lease->dns, dns);
1210 if (r < 0)
1211 log_debug_errno(r, "Failed to deserialize DNS servers %s, ignoring: %m", dns);
1212 else
1213 lease->dns_size = r;
1214 }
1215
1216 if (ntp) {
1217 r = deserialize_in_addrs(&lease->ntp, ntp);
1218 if (r < 0)
1219 log_debug_errno(r, "Failed to deserialize NTP servers %s, ignoring: %m", ntp);
1220 else
1221 lease->ntp_size = r;
1222 }
1223
1224 if (sip) {
1225 r = deserialize_in_addrs(&lease->sip, sip);
1226 if (r < 0)
1227 log_debug_errno(r, "Failed to deserialize SIP servers %s, ignoring: %m", sip);
1228 else
1229 lease->sip_size = r;
1230 }
1231
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
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
1248 if (mtu) {
1249 r = safe_atou16(mtu, &lease->mtu);
1250 if (r < 0)
1251 log_debug_errno(r, "Failed to parse MTU %s, ignoring: %m", mtu);
1252 }
1253
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
1266 if (routes) {
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);
1290 if (r < 0)
1291 log_debug_errno(r, "Failed to parse T2 %s, ignoring: %m", t2);
1292 }
1293
1294 if (client_id_hex) {
1295 r = unhexmem(client_id_hex, (size_t) -1, &lease->client_id, &lease->client_id_len);
1296 if (r < 0)
1297 log_debug_errno(r, "Failed to parse client ID %s, ignoring: %m", client_id_hex);
1298 }
1299
1300 if (vendor_specific_hex) {
1301 r = unhexmem(vendor_specific_hex, (size_t) -1, &lease->vendor_specific, &lease->vendor_specific_len);
1302 if (r < 0)
1303 log_debug_errno(r, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex);
1304 }
1305
1306 for (i = 0; i <= SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE; i++) {
1307 _cleanup_free_ void *data = NULL;
1308 size_t len;
1309
1310 if (!options[i])
1311 continue;
1312
1313 r = unhexmem(options[i], (size_t) -1, &data, &len);
1314 if (r < 0) {
1315 log_debug_errno(r, "Failed to parse private DHCP option %s, ignoring: %m", options[i]);
1316 continue;
1317 }
1318
1319 r = dhcp_lease_insert_private_option(lease, SD_DHCP_OPTION_PRIVATE_BASE + i, data, len);
1320 if (r < 0)
1321 return r;
1322 }
1323
1324 *ret = TAKE_PTR(lease);
1325
1326 return 0;
1327 }
1328
1329 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
1330 struct in_addr address, mask;
1331 int r;
1332
1333 assert(lease);
1334
1335 if (lease->address == 0)
1336 return -ENODATA;
1337
1338 address.s_addr = lease->address;
1339
1340 /* fall back to the default subnet masks based on address class */
1341 r = in4_addr_default_subnet_mask(&address, &mask);
1342 if (r < 0)
1343 return r;
1344
1345 lease->subnet_mask = mask.s_addr;
1346 lease->have_subnet_mask = true;
1347
1348 return 0;
1349 }
1350
1351 int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len) {
1352 assert_return(lease, -EINVAL);
1353 assert_return(client_id, -EINVAL);
1354 assert_return(client_id_len, -EINVAL);
1355
1356 if (!lease->client_id)
1357 return -ENODATA;
1358
1359 *client_id = lease->client_id;
1360 *client_id_len = lease->client_id_len;
1361
1362 return 0;
1363 }
1364
1365 int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len) {
1366 assert_return(lease, -EINVAL);
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;
1373
1374 p = memdup(client_id, client_id_len);
1375 if (!p)
1376 return -ENOMEM;
1377
1378 free(lease->client_id);
1379 lease->client_id = p;
1380 lease->client_id_len = client_id_len;
1381 }
1382
1383 return 0;
1384 }
1385
1386 int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **tz) {
1387 assert_return(lease, -EINVAL);
1388 assert_return(tz, -EINVAL);
1389
1390 if (!lease->timezone)
1391 return -ENODATA;
1392
1393 *tz = lease->timezone;
1394 return 0;
1395 }
1396
1397 int 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
1405 int 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
1413 int 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 }
1420
1421 int sd_dhcp_route_get_option(sd_dhcp_route *route) {
1422 assert_return(route, -EINVAL);
1423
1424 return route->option;
1425 }