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