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