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