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