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