]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp-lease.c
Merge pull request #1790 from endocode/kayrus/fix_man_kernel_cl
[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 "string-util.h"
41 #include "unaligned.h"
42
43 int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
44 assert_return(lease, -EINVAL);
45 assert_return(addr, -EINVAL);
46
47 if (lease->address == 0)
48 return -ENODATA;
49
50 addr->s_addr = lease->address;
51 return 0;
52 }
53
54 int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr) {
55 assert_return(lease, -EINVAL);
56 assert_return(addr, -EINVAL);
57
58 if (!lease->have_broadcast)
59 return -ENODATA;
60
61 addr->s_addr = lease->broadcast;
62 return 0;
63 }
64
65 int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
66 assert_return(lease, -EINVAL);
67 assert_return(lifetime, -EINVAL);
68
69 if (lease->lifetime <= 0)
70 return -ENODATA;
71
72 *lifetime = lease->lifetime;
73 return 0;
74 }
75
76 int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1) {
77 assert_return(lease, -EINVAL);
78 assert_return(t1, -EINVAL);
79
80 if (lease->t1 <= 0)
81 return -ENODATA;
82
83 *t1 = lease->t1;
84 return 0;
85 }
86
87 int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2) {
88 assert_return(lease, -EINVAL);
89 assert_return(t2, -EINVAL);
90
91 if (lease->t2 <= 0)
92 return -ENODATA;
93
94 *t2 = lease->t2;
95 return 0;
96 }
97
98 int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
99 assert_return(lease, -EINVAL);
100 assert_return(mtu, -EINVAL);
101
102 if (lease->mtu <= 0)
103 return -ENODATA;
104
105 *mtu = lease->mtu;
106 return 0;
107 }
108
109 int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) {
110 assert_return(lease, -EINVAL);
111 assert_return(addr, -EINVAL);
112
113 if (lease->dns_size <= 0)
114 return -ENODATA;
115
116 *addr = lease->dns;
117 return (int) lease->dns_size;
118 }
119
120 int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) {
121 assert_return(lease, -EINVAL);
122 assert_return(addr, -EINVAL);
123
124 if (lease->ntp_size <= 0)
125 return -ENODATA;
126
127 *addr = lease->ntp;
128 return (int) lease->ntp_size;
129 }
130
131 int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
132 assert_return(lease, -EINVAL);
133 assert_return(domainname, -EINVAL);
134
135 if (!lease->domainname)
136 return -ENODATA;
137
138 *domainname = lease->domainname;
139 return 0;
140 }
141
142 int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
143 assert_return(lease, -EINVAL);
144 assert_return(hostname, -EINVAL);
145
146 if (!lease->hostname)
147 return -ENODATA;
148
149 *hostname = lease->hostname;
150 return 0;
151 }
152
153 int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
154 assert_return(lease, -EINVAL);
155 assert_return(root_path, -EINVAL);
156
157 if (!lease->root_path)
158 return -ENODATA;
159
160 *root_path = lease->root_path;
161 return 0;
162 }
163
164 int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) {
165 assert_return(lease, -EINVAL);
166 assert_return(addr, -EINVAL);
167
168 if (lease->router == 0)
169 return -ENODATA;
170
171 addr->s_addr = lease->router;
172 return 0;
173 }
174
175 int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
176 assert_return(lease, -EINVAL);
177 assert_return(addr, -EINVAL);
178
179 if (!lease->have_subnet_mask)
180 return -ENODATA;
181
182 addr->s_addr = lease->subnet_mask;
183 return 0;
184 }
185
186 int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
187 assert_return(lease, -EINVAL);
188 assert_return(addr, -EINVAL);
189
190 if (lease->server_address == 0)
191 return -ENODATA;
192
193 addr->s_addr = lease->server_address;
194 return 0;
195 }
196
197 int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
198 assert_return(lease, -EINVAL);
199 assert_return(addr, -EINVAL);
200
201 if (lease->next_server == 0)
202 return -ENODATA;
203
204 addr->s_addr = lease->next_server;
205 return 0;
206 }
207
208 int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes) {
209 assert_return(lease, -EINVAL);
210 assert_return(routes, -EINVAL);
211
212 if (lease->static_route_size <= 0)
213 return -ENODATA;
214
215 *routes = lease->static_route;
216 return (int) lease->static_route_size;
217 }
218
219 int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len) {
220 assert_return(lease, -EINVAL);
221 assert_return(data, -EINVAL);
222 assert_return(data_len, -EINVAL);
223
224 if (lease->vendor_specific_len <= 0)
225 return -ENODATA;
226
227 *data = lease->vendor_specific;
228 *data_len = lease->vendor_specific_len;
229 return 0;
230 }
231
232 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
233
234 if (!lease)
235 return NULL;
236
237 assert(lease->n_ref >= 1);
238 lease->n_ref++;
239
240 return lease;
241 }
242
243 sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
244
245 if (!lease)
246 return NULL;
247
248 assert(lease->n_ref >= 1);
249 lease->n_ref--;
250
251 if (lease->n_ref > 0)
252 return NULL;
253
254 while (lease->private_options) {
255 struct sd_dhcp_raw_option *option = lease->private_options;
256
257 LIST_REMOVE(options, lease->private_options, option);
258
259 free(option->data);
260 free(option);
261 }
262
263 free(lease->hostname);
264 free(lease->domainname);
265 free(lease->dns);
266 free(lease->ntp);
267 free(lease->static_route);
268 free(lease->client_id);
269 free(lease->vendor_specific);
270 free(lease);
271
272 return NULL;
273 }
274
275 static int lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
276 assert(option);
277 assert(ret);
278
279 if (len != 4)
280 return -EINVAL;
281
282 *ret = unaligned_read_be32((be32_t*) option);
283 if (*ret < min)
284 *ret = min;
285
286 return 0;
287 }
288
289 static int lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
290 assert(option);
291 assert(ret);
292
293 if (len != 2)
294 return -EINVAL;
295
296 *ret = unaligned_read_be16((be16_t*) option);
297 if (*ret < min)
298 *ret = min;
299
300 return 0;
301 }
302
303 static int lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
304 assert(option);
305 assert(ret);
306
307 if (len != 4)
308 return -EINVAL;
309
310 memcpy(ret, option, 4);
311 return 0;
312 }
313
314 static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
315 assert(option);
316 assert(ret);
317
318 if (len <= 0)
319 *ret = mfree(*ret);
320 else {
321 char *string;
322
323 /*
324 * One trailing NUL byte is OK, we don't mind. See:
325 * https://github.com/systemd/systemd/issues/1337
326 */
327 if (memchr(option, 0, len - 1))
328 return -EINVAL;
329
330 string = strndup((const char *) option, len);
331 if (!string)
332 return -ENOMEM;
333
334 free(*ret);
335 *ret = string;
336 }
337
338 return 0;
339 }
340
341 static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) {
342 assert(option);
343 assert(ret);
344 assert(n_ret);
345
346 if (len <= 0) {
347 *ret = mfree(*ret);
348 *n_ret = 0;
349 } else {
350 size_t n_addresses;
351 struct in_addr *addresses;
352
353 if (len % 4 != 0)
354 return -EINVAL;
355
356 n_addresses = len / 4;
357
358 addresses = newdup(struct in_addr, option, n_addresses);
359 if (!addresses)
360 return -ENOMEM;
361
362 free(*ret);
363 *ret = addresses;
364 *n_ret = n_addresses;
365 }
366
367 return 0;
368 }
369
370 static int lease_parse_routes(
371 const uint8_t *option, size_t len,
372 struct sd_dhcp_route **routes, size_t *routes_size, size_t *routes_allocated) {
373
374 struct in_addr addr;
375
376 assert(option || len <= 0);
377 assert(routes);
378 assert(routes_size);
379 assert(routes_allocated);
380
381 if (len <= 0)
382 return 0;
383
384 if (len % 8 != 0)
385 return -EINVAL;
386
387 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + (len / 8)))
388 return -ENOMEM;
389
390 while (len >= 8) {
391 struct sd_dhcp_route *route = *routes + *routes_size;
392 int r;
393
394 r = in_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen);
395 if (r < 0) {
396 log_debug("Failed to determine destination prefix length from class based IP, ignoring");
397 continue;
398 }
399
400 assert_se(lease_parse_be32(option, 4, &addr.s_addr) >= 0);
401 route->dst_addr = inet_makeaddr(inet_netof(addr), 0);
402 option += 4;
403
404 assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0);
405 option += 4;
406
407 len -= 8;
408 (*routes_size)++;
409 }
410
411 return 0;
412 }
413
414 /* parses RFC3442 Classless Static Route Option */
415 static int lease_parse_classless_routes(
416 const uint8_t *option, size_t len,
417 struct sd_dhcp_route **routes, size_t *routes_size, size_t *routes_allocated) {
418
419 assert(option || len <= 0);
420 assert(routes);
421 assert(routes_size);
422 assert(routes_allocated);
423
424 if (len <= 0)
425 return 0;
426
427 /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */
428
429 while (len > 0) {
430 uint8_t dst_octets;
431 struct sd_dhcp_route *route;
432
433 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1))
434 return -ENOMEM;
435
436 route = *routes + *routes_size;
437
438 dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1);
439 route->dst_prefixlen = *option;
440 option++;
441 len--;
442
443 /* can't have more than 4 octets in IPv4 */
444 if (dst_octets > 4 || len < dst_octets)
445 return -EINVAL;
446
447 route->dst_addr.s_addr = 0;
448 memcpy(&route->dst_addr.s_addr, option, dst_octets);
449 option += dst_octets;
450 len -= dst_octets;
451
452 if (len < 4)
453 return -EINVAL;
454
455 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
456 option += 4;
457 len -= 4;
458
459 (*routes_size)++;
460 }
461
462 return 0;
463 }
464
465 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
466 sd_dhcp_lease *lease = userdata;
467 int r;
468
469 assert(lease);
470
471 switch(code) {
472
473 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
474 r = lease_parse_u32(option, len, &lease->lifetime, 1);
475 if (r < 0)
476 log_debug_errno(r, "Failed to parse lease time, ignoring: %m");
477
478 break;
479
480 case DHCP_OPTION_SERVER_IDENTIFIER:
481 r = lease_parse_be32(option, len, &lease->server_address);
482 if (r < 0)
483 log_debug_errno(r, "Failed to parse server identifier, ignoring: %m");
484
485 break;
486
487 case DHCP_OPTION_SUBNET_MASK:
488 r = lease_parse_be32(option, len, &lease->subnet_mask);
489 if (r < 0)
490 log_debug_errno(r, "Failed to parse subnet mask, ignoring: %m");
491 else
492 lease->have_subnet_mask = true;
493 break;
494
495 case DHCP_OPTION_BROADCAST:
496 r = lease_parse_be32(option, len, &lease->broadcast);
497 if (r < 0)
498 log_debug_errno(r, "Failed to parse broadcast address, ignoring: %m");
499 else
500 lease->have_broadcast = true;
501 break;
502
503 case DHCP_OPTION_ROUTER:
504 if (len >= 4) {
505 r = lease_parse_be32(option, 4, &lease->router);
506 if (r < 0)
507 log_debug_errno(r, "Failed to parse router address, ignoring: %m");
508 }
509 break;
510
511 case DHCP_OPTION_DOMAIN_NAME_SERVER:
512 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
513 if (r < 0)
514 log_debug_errno(r, "Failed to parse DNS server, ignoring: %m");
515 break;
516
517 case DHCP_OPTION_NTP_SERVER:
518 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
519 if (r < 0)
520 log_debug_errno(r, "Failed to parse NTP server, ignoring: %m");
521 break;
522
523 case DHCP_OPTION_STATIC_ROUTE:
524 r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size, &lease->static_route_allocated);
525 if (r < 0)
526 log_debug_errno(r, "Failed to parse static routes, ignoring: %m");
527 break;
528
529 case DHCP_OPTION_INTERFACE_MTU:
530 r = lease_parse_u16(option, len, &lease->mtu, 68);
531 if (r < 0)
532 log_debug_errno(r, "Failed to parse MTU, ignoring: %m");
533 break;
534
535 case DHCP_OPTION_DOMAIN_NAME: {
536 _cleanup_free_ char *domainname = NULL, *normalized = NULL;
537
538 r = lease_parse_string(option, len, &domainname);
539 if (r < 0) {
540 log_debug_errno(r, "Failed to parse domain name, ignoring: %m");
541 return 0;
542 }
543
544 r = dns_name_normalize(domainname, &normalized);
545 if (r < 0) {
546 log_debug_errno(r, "Failed to normalize domain name '%s': %m", domainname);
547 return 0;
548 }
549
550 if (is_localhost(normalized)) {
551 log_debug_errno(r, "Detected 'localhost' as suggested domain name, ignoring.");
552 break;
553 }
554
555 free(lease->domainname);
556 lease->domainname = normalized;
557 normalized = NULL;
558
559 break;
560 }
561
562 case DHCP_OPTION_HOST_NAME: {
563 _cleanup_free_ char *hostname = NULL, *normalized = NULL;
564
565 r = lease_parse_string(option, len, &hostname);
566 if (r < 0) {
567 log_debug_errno(r, "Failed to parse host name, ignoring: %m");
568 return 0;
569 }
570
571 r = dns_name_normalize(hostname, &normalized);
572 if (r < 0) {
573 log_debug_errno(r, "Failed to normalize host name '%s', ignoring: %m", hostname);
574 return 0;
575 }
576
577 if (is_localhost(normalized)) {
578 log_debug_errno(r, "Detected 'localhost' as suggested host name, ignoring.");
579 return 0;
580 }
581
582 free(lease->hostname);
583 lease->hostname = normalized;
584 normalized = NULL;
585
586 break;
587 }
588
589 case DHCP_OPTION_ROOT_PATH:
590 r = lease_parse_string(option, len, &lease->root_path);
591 if (r < 0)
592 log_debug_errno(r, "Failed to parse root path, ignoring: %m");
593 break;
594
595 case DHCP_OPTION_RENEWAL_T1_TIME:
596 r = lease_parse_u32(option, len, &lease->t1, 1);
597 if (r < 0)
598 log_debug_errno(r, "Failed to parse T1 time, ignoring: %m");
599 break;
600
601 case DHCP_OPTION_REBINDING_T2_TIME:
602 r = lease_parse_u32(option, len, &lease->t2, 1);
603 if (r < 0)
604 log_debug_errno(r, "Failed to parse T2 time, ignoring: %m");
605 break;
606
607 case DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
608 r = lease_parse_classless_routes(
609 option, len,
610 &lease->static_route,
611 &lease->static_route_size,
612 &lease->static_route_allocated);
613 if (r < 0)
614 log_debug_errno(r, "Failed to parse classless routes, ignoring: %m");
615 break;
616
617 case DHCP_OPTION_NEW_TZDB_TIMEZONE: {
618 _cleanup_free_ char *tz = NULL;
619
620 r = lease_parse_string(option, len, &tz);
621 if (r < 0) {
622 log_debug_errno(r, "Failed to parse timezone option, ignoring: %m");
623 return 0;
624 }
625
626 if (!timezone_is_valid(tz)) {
627 log_debug_errno(r, "Timezone is not valid, ignoring: %m");
628 return 0;
629 }
630
631 free(lease->timezone);
632 lease->timezone = tz;
633 tz = NULL;
634
635 break;
636 }
637
638 case DHCP_OPTION_VENDOR_SPECIFIC:
639
640 if (len <= 0)
641 lease->vendor_specific = mfree(lease->vendor_specific);
642 else {
643 void *p;
644
645 p = memdup(option, len);
646 if (!p)
647 return -ENOMEM;
648
649 free(lease->vendor_specific);
650 lease->vendor_specific = p;
651 }
652
653 lease->vendor_specific_len = len;
654 break;
655
656 case DHCP_OPTION_PRIVATE_BASE ... DHCP_OPTION_PRIVATE_LAST:
657 r = dhcp_lease_insert_private_option(lease, code, option, len);
658 if (r < 0)
659 return r;
660
661 break;
662
663 default:
664 log_debug("Ignoring option DHCP option %i while parsing.", code);
665 break;
666 }
667
668 return 0;
669 }
670
671 int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len) {
672 struct sd_dhcp_raw_option *cur, *option;
673
674 assert(lease);
675
676 LIST_FOREACH(options, cur, lease->private_options) {
677 if (tag < cur->tag)
678 break;
679 if (tag == cur->tag) {
680 log_debug("Ignoring duplicate option, tagged %i.", tag);
681 return 0;
682 }
683 }
684
685 option = new(struct sd_dhcp_raw_option, 1);
686 if (!option)
687 return -ENOMEM;
688
689 option->tag = tag;
690 option->length = len;
691 option->data = memdup(data, len);
692 if (!option->data) {
693 free(option);
694 return -ENOMEM;
695 }
696
697 LIST_INSERT_BEFORE(options, lease->private_options, cur, option);
698 return 0;
699 }
700
701 int dhcp_lease_new(sd_dhcp_lease **ret) {
702 sd_dhcp_lease *lease;
703
704 lease = new0(sd_dhcp_lease, 1);
705 if (!lease)
706 return -ENOMEM;
707
708 lease->router = INADDR_ANY;
709 lease->n_ref = 1;
710
711 *ret = lease;
712 return 0;
713 }
714
715 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
716 _cleanup_free_ char *temp_path = NULL;
717 _cleanup_fclose_ FILE *f = NULL;
718 struct sd_dhcp_raw_option *option;
719 struct in_addr address;
720 const struct in_addr *addresses;
721 const void *client_id, *data;
722 size_t client_id_len, data_len;
723 const char *string;
724 uint16_t mtu;
725 struct sd_dhcp_route *routes;
726 uint32_t t1, t2, lifetime;
727 int r;
728
729 assert(lease);
730 assert(lease_file);
731
732 r = fopen_temporary(lease_file, &f, &temp_path);
733 if (r < 0)
734 goto fail;
735
736 fchmod(fileno(f), 0644);
737
738 fprintf(f,
739 "# This is private data. Do not parse.\n");
740
741 r = sd_dhcp_lease_get_address(lease, &address);
742 if (r >= 0)
743 fprintf(f, "ADDRESS=%s\n", inet_ntoa(address));
744
745 r = sd_dhcp_lease_get_netmask(lease, &address);
746 if (r >= 0)
747 fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
748
749 r = sd_dhcp_lease_get_router(lease, &address);
750 if (r >= 0)
751 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
752
753 r = sd_dhcp_lease_get_server_identifier(lease, &address);
754 if (r >= 0)
755 fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntoa(address));
756
757 r = sd_dhcp_lease_get_next_server(lease, &address);
758 if (r >= 0)
759 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
760
761 r = sd_dhcp_lease_get_broadcast(lease, &address);
762 if (r >= 0)
763 fprintf(f, "BROADCAST=%s\n", inet_ntoa(address));
764
765 r = sd_dhcp_lease_get_mtu(lease, &mtu);
766 if (r >= 0)
767 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
768
769 r = sd_dhcp_lease_get_t1(lease, &t1);
770 if (r >= 0)
771 fprintf(f, "T1=%" PRIu32 "\n", t1);
772
773 r = sd_dhcp_lease_get_t2(lease, &t2);
774 if (r >= 0)
775 fprintf(f, "T2=%" PRIu32 "\n", t2);
776
777 r = sd_dhcp_lease_get_lifetime(lease, &lifetime);
778 if (r >= 0)
779 fprintf(f, "LIFETIME=%" PRIu32 "\n", lifetime);
780
781 r = sd_dhcp_lease_get_dns(lease, &addresses);
782 if (r > 0) {
783 fputs("DNS=", f);
784 serialize_in_addrs(f, addresses, r);
785 fputs("\n", f);
786 }
787
788 r = sd_dhcp_lease_get_ntp(lease, &addresses);
789 if (r > 0) {
790 fputs("NTP=", f);
791 serialize_in_addrs(f, addresses, r);
792 fputs("\n", f);
793 }
794
795 r = sd_dhcp_lease_get_domainname(lease, &string);
796 if (r >= 0)
797 fprintf(f, "DOMAINNAME=%s\n", string);
798
799 r = sd_dhcp_lease_get_hostname(lease, &string);
800 if (r >= 0)
801 fprintf(f, "HOSTNAME=%s\n", string);
802
803 r = sd_dhcp_lease_get_root_path(lease, &string);
804 if (r >= 0)
805 fprintf(f, "ROOT_PATH=%s\n", string);
806
807 r = sd_dhcp_lease_get_routes(lease, &routes);
808 if (r > 0)
809 serialize_dhcp_routes(f, "ROUTES", routes, r);
810
811 r = sd_dhcp_lease_get_timezone(lease, &string);
812 if (r >= 0)
813 fprintf(f, "TIMEZONE=%s\n", string);
814
815 r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
816 if (r >= 0) {
817 _cleanup_free_ char *client_id_hex;
818
819 client_id_hex = hexmem(client_id, client_id_len);
820 if (!client_id_hex) {
821 r = -ENOMEM;
822 goto fail;
823 }
824 fprintf(f, "CLIENTID=%s\n", client_id_hex);
825 }
826
827 r = sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len);
828 if (r >= 0) {
829 _cleanup_free_ char *option_hex = NULL;
830
831 option_hex = hexmem(data, data_len);
832 if (!option_hex) {
833 r = -ENOMEM;
834 goto fail;
835 }
836 fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
837 }
838
839 LIST_FOREACH(options, option, lease->private_options) {
840 char key[strlen("OPTION_000")+1];
841
842 snprintf(key, sizeof(key), "OPTION_%"PRIu8, option->tag);
843 r = serialize_dhcp_option(f, key, option->data, option->length);
844 if (r < 0)
845 goto fail;
846 }
847
848 r = fflush_and_check(f);
849 if (r < 0)
850 goto fail;
851
852 if (rename(temp_path, lease_file) < 0) {
853 r = -errno;
854 goto fail;
855 }
856
857 return 0;
858
859 fail:
860 if (temp_path)
861 (void) unlink(temp_path);
862
863 return log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
864 }
865
866 int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
867
868 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
869 _cleanup_free_ char
870 *address = NULL,
871 *router = NULL,
872 *netmask = NULL,
873 *server_address = NULL,
874 *next_server = NULL,
875 *broadcast = NULL,
876 *dns = NULL,
877 *ntp = NULL,
878 *mtu = NULL,
879 *routes = NULL,
880 *client_id_hex = NULL,
881 *vendor_specific_hex = NULL,
882 *lifetime = NULL,
883 *t1 = NULL,
884 *t2 = NULL,
885 *options[DHCP_OPTION_PRIVATE_LAST - DHCP_OPTION_PRIVATE_BASE + 1] = {};
886
887 int r, i;
888
889 assert(lease_file);
890 assert(ret);
891
892 r = dhcp_lease_new(&lease);
893 if (r < 0)
894 return r;
895
896 r = parse_env_file(lease_file, NEWLINE,
897 "ADDRESS", &address,
898 "ROUTER", &router,
899 "NETMASK", &netmask,
900 "SERVER_IDENTIFIER", &server_address,
901 "NEXT_SERVER", &next_server,
902 "BROADCAST", &broadcast,
903 "DNS", &dns,
904 "NTP", &ntp,
905 "MTU", &mtu,
906 "DOMAINNAME", &lease->domainname,
907 "HOSTNAME", &lease->hostname,
908 "ROOT_PATH", &lease->root_path,
909 "ROUTES", &routes,
910 "CLIENTID", &client_id_hex,
911 "TIMEZONE", &lease->timezone,
912 "VENDOR_SPECIFIC", &vendor_specific_hex,
913 "LIFETIME", &lifetime,
914 "T1", &t1,
915 "T2", &t2,
916 "OPTION_224", &options[0],
917 "OPTION_225", &options[1],
918 "OPTION_226", &options[2],
919 "OPTION_227", &options[3],
920 "OPTION_228", &options[4],
921 "OPTION_229", &options[5],
922 "OPTION_230", &options[6],
923 "OPTION_231", &options[7],
924 "OPTION_232", &options[8],
925 "OPTION_233", &options[9],
926 "OPTION_234", &options[10],
927 "OPTION_235", &options[11],
928 "OPTION_236", &options[12],
929 "OPTION_237", &options[13],
930 "OPTION_238", &options[14],
931 "OPTION_239", &options[15],
932 "OPTION_240", &options[16],
933 "OPTION_241", &options[17],
934 "OPTION_242", &options[18],
935 "OPTION_243", &options[19],
936 "OPTION_244", &options[20],
937 "OPTION_245", &options[21],
938 "OPTION_246", &options[22],
939 "OPTION_247", &options[23],
940 "OPTION_248", &options[24],
941 "OPTION_249", &options[25],
942 "OPTION_250", &options[26],
943 "OPTION_251", &options[27],
944 "OPTION_252", &options[28],
945 "OPTION_253", &options[29],
946 "OPTION_254", &options[30],
947 NULL);
948 if (r < 0)
949 return r;
950
951 if (address) {
952 r = inet_pton(AF_INET, address, &lease->address);
953 if (r <= 0)
954 log_debug("Failed to parse address %s, ignoring.", address);
955 }
956
957 if (router) {
958 r = inet_pton(AF_INET, router, &lease->router);
959 if (r <= 0)
960 log_debug("Failed to parse router %s, ignoring.", router);
961 }
962
963 if (netmask) {
964 r = inet_pton(AF_INET, netmask, &lease->subnet_mask);
965 if (r <= 0)
966 log_debug("Failed to parse netmask %s, ignoring.", netmask);
967 else
968 lease->have_subnet_mask = true;
969 }
970
971 if (server_address) {
972 r = inet_pton(AF_INET, server_address, &lease->server_address);
973 if (r <= 0)
974 log_debug("Failed to parse server address %s, ignoring.", server_address);
975 }
976
977 if (next_server) {
978 r = inet_pton(AF_INET, next_server, &lease->next_server);
979 if (r <= 0)
980 log_debug("Failed to parse next server %s, ignoring.", next_server);
981 }
982
983 if (broadcast) {
984 r = inet_pton(AF_INET, broadcast, &lease->broadcast);
985 if (r <= 0)
986 log_debug("Failed to parse broadcast address %s, ignoring.", broadcast);
987 else
988 lease->have_broadcast = true;
989 }
990
991 if (dns) {
992 r = deserialize_in_addrs(&lease->dns, dns);
993 if (r < 0)
994 log_debug_errno(r, "Failed to deserialize DNS servers %s, ignoring: %m", dns);
995 else
996 lease->dns_size = r;
997 }
998
999 if (ntp) {
1000 r = deserialize_in_addrs(&lease->ntp, ntp);
1001 if (r < 0)
1002 log_debug_errno(r, "Failed to deserialize NTP servers %s, ignoring: %m", ntp);
1003 else
1004 lease->ntp_size = r;
1005 }
1006
1007 if (mtu) {
1008 r = safe_atou16(mtu, &lease->mtu);
1009 if (r < 0)
1010 log_debug_errno(r, "Failed to parse MTU %s, ignoring: %m", mtu);
1011 }
1012
1013 if (routes) {
1014 r = deserialize_dhcp_routes(
1015 &lease->static_route,
1016 &lease->static_route_size,
1017 &lease->static_route_allocated,
1018 routes);
1019 if (r < 0)
1020 log_debug_errno(r, "Failed to parse DHCP routes %s, ignoring: %m", routes);
1021 }
1022
1023 if (lifetime) {
1024 r = safe_atou32(lifetime, &lease->lifetime);
1025 if (r < 0)
1026 log_debug_errno(r, "Failed to parse lifetime %s, ignoring: %m", lifetime);
1027 }
1028
1029 if (t1) {
1030 r = safe_atou32(t1, &lease->t1);
1031 if (r < 0)
1032 log_debug_errno(r, "Failed to parse T1 %s, ignoring: %m", t1);
1033 }
1034
1035 if (t2) {
1036 r = safe_atou32(t2, &lease->t2);
1037 if (r < 0)
1038 log_debug_errno(r, "Failed to parse T2 %s, ignoring: %m", t2);
1039 }
1040
1041 if (client_id_hex) {
1042 r = deserialize_dhcp_option(&lease->client_id, &lease->client_id_len, client_id_hex);
1043 if (r < 0)
1044 log_debug_errno(r, "Failed to parse client ID %s, ignoring: %m", client_id_hex);
1045 }
1046
1047 if (vendor_specific_hex) {
1048 r = deserialize_dhcp_option(&lease->vendor_specific, &lease->vendor_specific_len, vendor_specific_hex);
1049 if (r < 0)
1050 log_debug_errno(r, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex);
1051 }
1052
1053 for (i = 0; i <= DHCP_OPTION_PRIVATE_LAST - DHCP_OPTION_PRIVATE_BASE; i++) {
1054 _cleanup_free_ void *data = NULL;
1055 size_t len;
1056
1057 if (!options[i])
1058 continue;
1059
1060 r = deserialize_dhcp_option(&data, &len, options[i]);
1061 if (r < 0) {
1062 log_debug_errno(r, "Failed to parse private DHCP option %s, ignoring: %m", options[i]);
1063 continue;
1064 }
1065
1066 r = dhcp_lease_insert_private_option(lease, DHCP_OPTION_PRIVATE_BASE + i, data, len);
1067 if (r < 0)
1068 return r;
1069 }
1070
1071 *ret = lease;
1072 lease = NULL;
1073
1074 return 0;
1075 }
1076
1077 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
1078 struct in_addr address, mask;
1079 int r;
1080
1081 assert(lease);
1082
1083 if (lease->address == 0)
1084 return -ENODATA;
1085
1086 address.s_addr = lease->address;
1087
1088 /* fall back to the default subnet masks based on address class */
1089 r = in_addr_default_subnet_mask(&address, &mask);
1090 if (r < 0)
1091 return r;
1092
1093 lease->subnet_mask = mask.s_addr;
1094 lease->have_subnet_mask = true;
1095
1096 return 0;
1097 }
1098
1099 int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len) {
1100 assert_return(lease, -EINVAL);
1101 assert_return(client_id, -EINVAL);
1102 assert_return(client_id_len, -EINVAL);
1103
1104 if (!lease->client_id)
1105 return -ENODATA;
1106
1107 *client_id = lease->client_id;
1108 *client_id_len = lease->client_id_len;
1109
1110 return 0;
1111 }
1112
1113 int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len) {
1114 assert_return(lease, -EINVAL);
1115 assert_return(client_id || client_id_len <= 0, -EINVAL);
1116
1117 if (client_id_len <= 0)
1118 lease->client_id = mfree(lease->client_id);
1119 else {
1120 void *p;
1121
1122 p = memdup(client_id, client_id_len);
1123 if (!p)
1124 return -ENOMEM;
1125
1126 free(lease->client_id);
1127 lease->client_id = p;
1128 lease->client_id_len = client_id_len;
1129 }
1130
1131 return 0;
1132 }
1133
1134 int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **tz) {
1135 assert_return(lease, -EINVAL);
1136 assert_return(tz, -EINVAL);
1137
1138 if (!lease->timezone)
1139 return -ENODATA;
1140
1141 *tz = lease->timezone;
1142 return 0;
1143 }