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