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