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