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