]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp-lease.c
networkd: ignore Static Routes option when Classless Static Routes is given (#7807)
[thirdparty/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 route->option = SD_DHCP_OPTION_STATIC_ROUTE;
475 r = in4_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen);
476 if (r < 0) {
477 log_debug("Failed to determine destination prefix length from class based IP, ignoring");
478 continue;
479 }
480
481 assert_se(lease_parse_be32(option, 4, &addr.s_addr) >= 0);
482 route->dst_addr = inet_makeaddr(inet_netof(addr), 0);
483 option += 4;
484
485 assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0);
486 option += 4;
487
488 len -= 8;
489 (*routes_size)++;
490 }
491
492 return 0;
493 }
494
495 /* parses RFC3442 Classless Static Route Option */
496 static int lease_parse_classless_routes(
497 const uint8_t *option, size_t len,
498 struct sd_dhcp_route **routes, size_t *routes_size, size_t *routes_allocated) {
499
500 assert(option || len <= 0);
501 assert(routes);
502 assert(routes_size);
503 assert(routes_allocated);
504
505 if (len <= 0)
506 return 0;
507
508 /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */
509
510 while (len > 0) {
511 uint8_t dst_octets;
512 struct sd_dhcp_route *route;
513
514 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1))
515 return -ENOMEM;
516
517 route = *routes + *routes_size;
518 route->option = SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE;
519
520 dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1);
521 route->dst_prefixlen = *option;
522 option++;
523 len--;
524
525 /* can't have more than 4 octets in IPv4 */
526 if (dst_octets > 4 || len < dst_octets)
527 return -EINVAL;
528
529 route->dst_addr.s_addr = 0;
530 memcpy(&route->dst_addr.s_addr, option, dst_octets);
531 option += dst_octets;
532 len -= dst_octets;
533
534 if (len < 4)
535 return -EINVAL;
536
537 assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0);
538 option += 4;
539 len -= 4;
540
541 (*routes_size)++;
542 }
543
544 return 0;
545 }
546
547 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
548 sd_dhcp_lease *lease = userdata;
549 int r;
550
551 assert(lease);
552
553 switch(code) {
554
555 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
556 r = lease_parse_u32(option, len, &lease->lifetime, 1);
557 if (r < 0)
558 log_debug_errno(r, "Failed to parse lease time, ignoring: %m");
559
560 break;
561
562 case SD_DHCP_OPTION_SERVER_IDENTIFIER:
563 r = lease_parse_be32(option, len, &lease->server_address);
564 if (r < 0)
565 log_debug_errno(r, "Failed to parse server identifier, ignoring: %m");
566
567 break;
568
569 case SD_DHCP_OPTION_SUBNET_MASK:
570 r = lease_parse_be32(option, len, &lease->subnet_mask);
571 if (r < 0)
572 log_debug_errno(r, "Failed to parse subnet mask, ignoring: %m");
573 else
574 lease->have_subnet_mask = true;
575 break;
576
577 case SD_DHCP_OPTION_BROADCAST:
578 r = lease_parse_be32(option, len, &lease->broadcast);
579 if (r < 0)
580 log_debug_errno(r, "Failed to parse broadcast address, ignoring: %m");
581 else
582 lease->have_broadcast = true;
583 break;
584
585 case SD_DHCP_OPTION_ROUTER:
586 if (len >= 4) {
587 r = lease_parse_be32(option, 4, &lease->router);
588 if (r < 0)
589 log_debug_errno(r, "Failed to parse router address, ignoring: %m");
590 }
591 break;
592
593 case SD_DHCP_OPTION_DOMAIN_NAME_SERVER:
594 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
595 if (r < 0)
596 log_debug_errno(r, "Failed to parse DNS server, ignoring: %m");
597 break;
598
599 case SD_DHCP_OPTION_NTP_SERVER:
600 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
601 if (r < 0)
602 log_debug_errno(r, "Failed to parse NTP server, ignoring: %m");
603 break;
604
605 case SD_DHCP_OPTION_STATIC_ROUTE:
606 r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size, &lease->static_route_allocated);
607 if (r < 0)
608 log_debug_errno(r, "Failed to parse static routes, ignoring: %m");
609 break;
610
611 case SD_DHCP_OPTION_INTERFACE_MTU:
612 r = lease_parse_u16(option, len, &lease->mtu, 68);
613 if (r < 0)
614 log_debug_errno(r, "Failed to parse MTU, ignoring: %m");
615 if (lease->mtu < DHCP_DEFAULT_MIN_SIZE) {
616 log_debug("MTU value of %" PRIu16 " too small. Using default MTU value of %d instead.", lease->mtu, DHCP_DEFAULT_MIN_SIZE);
617 lease->mtu = DHCP_DEFAULT_MIN_SIZE;
618 }
619
620 break;
621
622 case SD_DHCP_OPTION_DOMAIN_NAME:
623 r = lease_parse_domain(option, len, &lease->domainname);
624 if (r < 0) {
625 log_debug_errno(r, "Failed to parse domain name, ignoring: %m");
626 return 0;
627 }
628
629 break;
630
631 case SD_DHCP_OPTION_DOMAIN_SEARCH_LIST:
632 r = dhcp_lease_parse_search_domains(option, len, &lease->search_domains);
633 if (r < 0)
634 log_debug_errno(r, "Failed to parse Domain Search List, ignoring: %m");
635 break;
636
637 case SD_DHCP_OPTION_HOST_NAME:
638 r = lease_parse_domain(option, len, &lease->hostname);
639 if (r < 0) {
640 log_debug_errno(r, "Failed to parse host name, ignoring: %m");
641 return 0;
642 }
643
644 break;
645
646 case SD_DHCP_OPTION_ROOT_PATH:
647 r = lease_parse_string(option, len, &lease->root_path);
648 if (r < 0)
649 log_debug_errno(r, "Failed to parse root path, ignoring: %m");
650 break;
651
652 case SD_DHCP_OPTION_RENEWAL_T1_TIME:
653 r = lease_parse_u32(option, len, &lease->t1, 1);
654 if (r < 0)
655 log_debug_errno(r, "Failed to parse T1 time, ignoring: %m");
656 break;
657
658 case SD_DHCP_OPTION_REBINDING_T2_TIME:
659 r = lease_parse_u32(option, len, &lease->t2, 1);
660 if (r < 0)
661 log_debug_errno(r, "Failed to parse T2 time, ignoring: %m");
662 break;
663
664 case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
665 r = lease_parse_classless_routes(
666 option, len,
667 &lease->static_route,
668 &lease->static_route_size,
669 &lease->static_route_allocated);
670 if (r < 0)
671 log_debug_errno(r, "Failed to parse classless routes, ignoring: %m");
672 break;
673
674 case SD_DHCP_OPTION_NEW_TZDB_TIMEZONE: {
675 _cleanup_free_ char *tz = NULL;
676
677 r = lease_parse_string(option, len, &tz);
678 if (r < 0) {
679 log_debug_errno(r, "Failed to parse timezone option, ignoring: %m");
680 return 0;
681 }
682
683 if (!timezone_is_valid(tz)) {
684 log_debug_errno(r, "Timezone is not valid, ignoring: %m");
685 return 0;
686 }
687
688 free_and_replace(lease->timezone, tz);
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 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
883 (void) fchmod(fileno(f), 0644);
884
885 fprintf(f,
886 "# This is private data. Do not parse.\n");
887
888 r = sd_dhcp_lease_get_address(lease, &address);
889 if (r >= 0)
890 fprintf(f, "ADDRESS=%s\n", inet_ntoa(address));
891
892 r = sd_dhcp_lease_get_netmask(lease, &address);
893 if (r >= 0)
894 fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
895
896 r = sd_dhcp_lease_get_router(lease, &address);
897 if (r >= 0)
898 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
899
900 r = sd_dhcp_lease_get_server_identifier(lease, &address);
901 if (r >= 0)
902 fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntoa(address));
903
904 r = sd_dhcp_lease_get_next_server(lease, &address);
905 if (r >= 0)
906 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
907
908 r = sd_dhcp_lease_get_broadcast(lease, &address);
909 if (r >= 0)
910 fprintf(f, "BROADCAST=%s\n", inet_ntoa(address));
911
912 r = sd_dhcp_lease_get_mtu(lease, &mtu);
913 if (r >= 0)
914 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
915
916 r = sd_dhcp_lease_get_t1(lease, &t1);
917 if (r >= 0)
918 fprintf(f, "T1=%" PRIu32 "\n", t1);
919
920 r = sd_dhcp_lease_get_t2(lease, &t2);
921 if (r >= 0)
922 fprintf(f, "T2=%" PRIu32 "\n", t2);
923
924 r = sd_dhcp_lease_get_lifetime(lease, &lifetime);
925 if (r >= 0)
926 fprintf(f, "LIFETIME=%" PRIu32 "\n", lifetime);
927
928 r = sd_dhcp_lease_get_dns(lease, &addresses);
929 if (r > 0) {
930 fputs("DNS=", f);
931 serialize_in_addrs(f, addresses, r);
932 fputs("\n", f);
933 }
934
935 r = sd_dhcp_lease_get_ntp(lease, &addresses);
936 if (r > 0) {
937 fputs("NTP=", f);
938 serialize_in_addrs(f, addresses, r);
939 fputs("\n", f);
940 }
941
942 r = sd_dhcp_lease_get_domainname(lease, &string);
943 if (r >= 0)
944 fprintf(f, "DOMAINNAME=%s\n", string);
945
946 r = sd_dhcp_lease_get_search_domains(lease, &search_domains);
947 if (r > 0) {
948 fputs("DOMAIN_SEARCH_LIST=", f);
949 fputstrv(f, search_domains, NULL, NULL);
950 fputs("\n", f);
951 }
952
953 r = sd_dhcp_lease_get_hostname(lease, &string);
954 if (r >= 0)
955 fprintf(f, "HOSTNAME=%s\n", string);
956
957 r = sd_dhcp_lease_get_root_path(lease, &string);
958 if (r >= 0)
959 fprintf(f, "ROOT_PATH=%s\n", string);
960
961 r = sd_dhcp_lease_get_routes(lease, &routes);
962 if (r > 0)
963 serialize_dhcp_routes(f, "ROUTES", routes, r);
964
965 r = sd_dhcp_lease_get_timezone(lease, &string);
966 if (r >= 0)
967 fprintf(f, "TIMEZONE=%s\n", string);
968
969 r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
970 if (r >= 0) {
971 _cleanup_free_ char *client_id_hex = NULL;
972
973 client_id_hex = hexmem(client_id, client_id_len);
974 if (!client_id_hex) {
975 r = -ENOMEM;
976 goto fail;
977 }
978 fprintf(f, "CLIENTID=%s\n", client_id_hex);
979 }
980
981 r = sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len);
982 if (r >= 0) {
983 _cleanup_free_ char *option_hex = NULL;
984
985 option_hex = hexmem(data, data_len);
986 if (!option_hex) {
987 r = -ENOMEM;
988 goto fail;
989 }
990 fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
991 }
992
993 LIST_FOREACH(options, option, lease->private_options) {
994 char key[STRLEN("OPTION_000")+1];
995
996 xsprintf(key, "OPTION_%" PRIu8, option->tag);
997 r = serialize_dhcp_option(f, key, option->data, option->length);
998 if (r < 0)
999 goto fail;
1000 }
1001
1002 r = fflush_and_check(f);
1003 if (r < 0)
1004 goto fail;
1005
1006 if (rename(temp_path, lease_file) < 0) {
1007 r = -errno;
1008 goto fail;
1009 }
1010
1011 return 0;
1012
1013 fail:
1014 if (temp_path)
1015 (void) unlink(temp_path);
1016
1017 return log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
1018 }
1019
1020 int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
1021
1022 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
1023 _cleanup_free_ char
1024 *address = NULL,
1025 *router = NULL,
1026 *netmask = NULL,
1027 *server_address = NULL,
1028 *next_server = NULL,
1029 *broadcast = NULL,
1030 *dns = NULL,
1031 *ntp = NULL,
1032 *mtu = NULL,
1033 *routes = NULL,
1034 *domains = NULL,
1035 *client_id_hex = NULL,
1036 *vendor_specific_hex = NULL,
1037 *lifetime = NULL,
1038 *t1 = NULL,
1039 *t2 = NULL,
1040 *options[SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE + 1] = {};
1041
1042 int r, i;
1043
1044 assert(lease_file);
1045 assert(ret);
1046
1047 r = dhcp_lease_new(&lease);
1048 if (r < 0)
1049 return r;
1050
1051 r = parse_env_file(lease_file, NEWLINE,
1052 "ADDRESS", &address,
1053 "ROUTER", &router,
1054 "NETMASK", &netmask,
1055 "SERVER_IDENTIFIER", &server_address,
1056 "NEXT_SERVER", &next_server,
1057 "BROADCAST", &broadcast,
1058 "DNS", &dns,
1059 "NTP", &ntp,
1060 "MTU", &mtu,
1061 "DOMAINNAME", &lease->domainname,
1062 "HOSTNAME", &lease->hostname,
1063 "DOMAIN_SEARCH_LIST", &domains,
1064 "ROOT_PATH", &lease->root_path,
1065 "ROUTES", &routes,
1066 "CLIENTID", &client_id_hex,
1067 "TIMEZONE", &lease->timezone,
1068 "VENDOR_SPECIFIC", &vendor_specific_hex,
1069 "LIFETIME", &lifetime,
1070 "T1", &t1,
1071 "T2", &t2,
1072 "OPTION_224", &options[0],
1073 "OPTION_225", &options[1],
1074 "OPTION_226", &options[2],
1075 "OPTION_227", &options[3],
1076 "OPTION_228", &options[4],
1077 "OPTION_229", &options[5],
1078 "OPTION_230", &options[6],
1079 "OPTION_231", &options[7],
1080 "OPTION_232", &options[8],
1081 "OPTION_233", &options[9],
1082 "OPTION_234", &options[10],
1083 "OPTION_235", &options[11],
1084 "OPTION_236", &options[12],
1085 "OPTION_237", &options[13],
1086 "OPTION_238", &options[14],
1087 "OPTION_239", &options[15],
1088 "OPTION_240", &options[16],
1089 "OPTION_241", &options[17],
1090 "OPTION_242", &options[18],
1091 "OPTION_243", &options[19],
1092 "OPTION_244", &options[20],
1093 "OPTION_245", &options[21],
1094 "OPTION_246", &options[22],
1095 "OPTION_247", &options[23],
1096 "OPTION_248", &options[24],
1097 "OPTION_249", &options[25],
1098 "OPTION_250", &options[26],
1099 "OPTION_251", &options[27],
1100 "OPTION_252", &options[28],
1101 "OPTION_253", &options[29],
1102 "OPTION_254", &options[30],
1103 NULL);
1104 if (r < 0)
1105 return r;
1106
1107 if (address) {
1108 r = inet_pton(AF_INET, address, &lease->address);
1109 if (r <= 0)
1110 log_debug("Failed to parse address %s, ignoring.", address);
1111 }
1112
1113 if (router) {
1114 r = inet_pton(AF_INET, router, &lease->router);
1115 if (r <= 0)
1116 log_debug("Failed to parse router %s, ignoring.", router);
1117 }
1118
1119 if (netmask) {
1120 r = inet_pton(AF_INET, netmask, &lease->subnet_mask);
1121 if (r <= 0)
1122 log_debug("Failed to parse netmask %s, ignoring.", netmask);
1123 else
1124 lease->have_subnet_mask = true;
1125 }
1126
1127 if (server_address) {
1128 r = inet_pton(AF_INET, server_address, &lease->server_address);
1129 if (r <= 0)
1130 log_debug("Failed to parse server address %s, ignoring.", server_address);
1131 }
1132
1133 if (next_server) {
1134 r = inet_pton(AF_INET, next_server, &lease->next_server);
1135 if (r <= 0)
1136 log_debug("Failed to parse next server %s, ignoring.", next_server);
1137 }
1138
1139 if (broadcast) {
1140 r = inet_pton(AF_INET, broadcast, &lease->broadcast);
1141 if (r <= 0)
1142 log_debug("Failed to parse broadcast address %s, ignoring.", broadcast);
1143 else
1144 lease->have_broadcast = true;
1145 }
1146
1147 if (dns) {
1148 r = deserialize_in_addrs(&lease->dns, dns);
1149 if (r < 0)
1150 log_debug_errno(r, "Failed to deserialize DNS servers %s, ignoring: %m", dns);
1151 else
1152 lease->dns_size = r;
1153 }
1154
1155 if (ntp) {
1156 r = deserialize_in_addrs(&lease->ntp, ntp);
1157 if (r < 0)
1158 log_debug_errno(r, "Failed to deserialize NTP servers %s, ignoring: %m", ntp);
1159 else
1160 lease->ntp_size = r;
1161 }
1162
1163 if (mtu) {
1164 r = safe_atou16(mtu, &lease->mtu);
1165 if (r < 0)
1166 log_debug_errno(r, "Failed to parse MTU %s, ignoring: %m", mtu);
1167 }
1168
1169 if (domains) {
1170 _cleanup_strv_free_ char **a = NULL;
1171 a = strv_split(domains, " ");
1172 if (!a)
1173 return -ENOMEM;
1174
1175 if (!strv_isempty(a)) {
1176 lease->search_domains = a;
1177 a = NULL;
1178 }
1179 }
1180
1181 if (routes) {
1182 r = deserialize_dhcp_routes(
1183 &lease->static_route,
1184 &lease->static_route_size,
1185 &lease->static_route_allocated,
1186 routes);
1187 if (r < 0)
1188 log_debug_errno(r, "Failed to parse DHCP routes %s, ignoring: %m", routes);
1189 }
1190
1191 if (lifetime) {
1192 r = safe_atou32(lifetime, &lease->lifetime);
1193 if (r < 0)
1194 log_debug_errno(r, "Failed to parse lifetime %s, ignoring: %m", lifetime);
1195 }
1196
1197 if (t1) {
1198 r = safe_atou32(t1, &lease->t1);
1199 if (r < 0)
1200 log_debug_errno(r, "Failed to parse T1 %s, ignoring: %m", t1);
1201 }
1202
1203 if (t2) {
1204 r = safe_atou32(t2, &lease->t2);
1205 if (r < 0)
1206 log_debug_errno(r, "Failed to parse T2 %s, ignoring: %m", t2);
1207 }
1208
1209 if (client_id_hex) {
1210 r = deserialize_dhcp_option(&lease->client_id, &lease->client_id_len, client_id_hex);
1211 if (r < 0)
1212 log_debug_errno(r, "Failed to parse client ID %s, ignoring: %m", client_id_hex);
1213 }
1214
1215 if (vendor_specific_hex) {
1216 r = deserialize_dhcp_option(&lease->vendor_specific, &lease->vendor_specific_len, vendor_specific_hex);
1217 if (r < 0)
1218 log_debug_errno(r, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex);
1219 }
1220
1221 for (i = 0; i <= SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE; i++) {
1222 _cleanup_free_ void *data = NULL;
1223 size_t len;
1224
1225 if (!options[i])
1226 continue;
1227
1228 r = deserialize_dhcp_option(&data, &len, options[i]);
1229 if (r < 0) {
1230 log_debug_errno(r, "Failed to parse private DHCP option %s, ignoring: %m", options[i]);
1231 continue;
1232 }
1233
1234 r = dhcp_lease_insert_private_option(lease, SD_DHCP_OPTION_PRIVATE_BASE + i, data, len);
1235 if (r < 0)
1236 return r;
1237 }
1238
1239 *ret = lease;
1240 lease = NULL;
1241
1242 return 0;
1243 }
1244
1245 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
1246 struct in_addr address, mask;
1247 int r;
1248
1249 assert(lease);
1250
1251 if (lease->address == 0)
1252 return -ENODATA;
1253
1254 address.s_addr = lease->address;
1255
1256 /* fall back to the default subnet masks based on address class */
1257 r = in4_addr_default_subnet_mask(&address, &mask);
1258 if (r < 0)
1259 return r;
1260
1261 lease->subnet_mask = mask.s_addr;
1262 lease->have_subnet_mask = true;
1263
1264 return 0;
1265 }
1266
1267 int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len) {
1268 assert_return(lease, -EINVAL);
1269 assert_return(client_id, -EINVAL);
1270 assert_return(client_id_len, -EINVAL);
1271
1272 if (!lease->client_id)
1273 return -ENODATA;
1274
1275 *client_id = lease->client_id;
1276 *client_id_len = lease->client_id_len;
1277
1278 return 0;
1279 }
1280
1281 int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len) {
1282 assert_return(lease, -EINVAL);
1283 assert_return(client_id || client_id_len <= 0, -EINVAL);
1284
1285 if (client_id_len <= 0)
1286 lease->client_id = mfree(lease->client_id);
1287 else {
1288 void *p;
1289
1290 p = memdup(client_id, client_id_len);
1291 if (!p)
1292 return -ENOMEM;
1293
1294 free(lease->client_id);
1295 lease->client_id = p;
1296 lease->client_id_len = client_id_len;
1297 }
1298
1299 return 0;
1300 }
1301
1302 int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **tz) {
1303 assert_return(lease, -EINVAL);
1304 assert_return(tz, -EINVAL);
1305
1306 if (!lease->timezone)
1307 return -ENODATA;
1308
1309 *tz = lease->timezone;
1310 return 0;
1311 }
1312
1313 int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination) {
1314 assert_return(route, -EINVAL);
1315 assert_return(destination, -EINVAL);
1316
1317 *destination = route->dst_addr;
1318 return 0;
1319 }
1320
1321 int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length) {
1322 assert_return(route, -EINVAL);
1323 assert_return(length, -EINVAL);
1324
1325 *length = route->dst_prefixlen;
1326 return 0;
1327 }
1328
1329 int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway) {
1330 assert_return(route, -EINVAL);
1331 assert_return(gateway, -EINVAL);
1332
1333 *gateway = route->gw_addr;
1334 return 0;
1335 }