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