]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp-lease.c
Merge pull request #144 from teg/udev-spawn-log-less-2
[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 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
183 if (lease)
184 assert_se(REFCNT_INC(lease->n_ref) >= 2);
185
186 return lease;
187 }
188
189 sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
190 if (lease && REFCNT_DEC(lease->n_ref) == 0) {
191 free(lease->hostname);
192 free(lease->domainname);
193 free(lease->dns);
194 free(lease->ntp);
195 free(lease->static_route);
196 free(lease->client_id);
197 free(lease);
198 }
199
200 return NULL;
201 }
202
203 static void lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
204 assert(option);
205 assert(ret);
206
207 if (len == 4) {
208 *ret = unaligned_read_be32((be32_t*) option);
209
210 if (*ret < min)
211 *ret = min;
212 }
213 }
214
215 static void lease_parse_s32(const uint8_t *option, size_t len, int32_t *ret) {
216 lease_parse_u32(option, len, (uint32_t *)ret, 0);
217 }
218
219 static void lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
220 assert(option);
221 assert(ret);
222
223 if (len == 2) {
224 *ret = unaligned_read_be16((be16_t*) option);
225
226 if (*ret < min)
227 *ret = min;
228 }
229 }
230
231 static void lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
232 assert(option);
233 assert(ret);
234
235 if (len == 4)
236 memcpy(ret, option, 4);
237 }
238
239 static void lease_parse_bool(const uint8_t *option, size_t len, bool *ret) {
240 assert(option);
241 assert(ret);
242
243 if (len == 1)
244 *ret = !!(*option);
245 }
246
247 static void lease_parse_u8(const uint8_t *option, size_t len, uint8_t *ret, uint8_t min) {
248 assert(option);
249 assert(ret);
250
251 if (len == 1) {
252 *ret = *option;
253
254 if (*ret < min)
255 *ret = min;
256 }
257 }
258
259 static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
260 assert(option);
261 assert(ret);
262
263 if (len >= 1) {
264 char *string;
265
266 string = strndup((const char *)option, len);
267 if (!string)
268 return -errno;
269
270 free(*ret);
271 *ret = string;
272 }
273
274 return 0;
275 }
276
277 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) {
278 assert(option);
279 assert(ret);
280 assert(ret_size);
281
282 if (len && !(len % (4 * mult))) {
283 size_t size;
284 struct in_addr *addresses;
285
286 size = len / 4;
287
288 addresses = newdup(struct in_addr, option, size);
289 if (!addresses)
290 return -ENOMEM;
291
292 free(*ret);
293 *ret = addresses;
294 *ret_size = size;
295 }
296
297 return 0;
298 }
299
300 static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
301 return lease_parse_in_addrs_aux(option, len, ret, ret_size, 1);
302 }
303
304 static int lease_parse_in_addrs_pairs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
305 return lease_parse_in_addrs_aux(option, len, ret, ret_size, 2);
306 }
307
308 static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
309 size_t *routes_size, size_t *routes_allocated) {
310
311 struct in_addr addr;
312
313 assert(option);
314 assert(routes);
315 assert(routes_size);
316 assert(routes_allocated);
317
318 if (!len)
319 return 0;
320
321 if (len % 8 != 0)
322 return -EINVAL;
323
324 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + (len / 8)))
325 return -ENOMEM;
326
327 while (len >= 8) {
328 struct sd_dhcp_route *route = *routes + *routes_size;
329 int r;
330
331 r = in_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen);
332 if (r < 0) {
333 log_error("Failed to determine destination prefix length from class based IP, ignoring");
334 continue;
335 }
336
337 lease_parse_be32(option, 4, &addr.s_addr);
338 route->dst_addr = inet_makeaddr(inet_netof(addr), 0);
339 option += 4;
340
341 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
342 option += 4;
343
344 len -= 8;
345 (*routes_size)++;
346 }
347
348 return 0;
349 }
350
351 /* parses RFC3442 Classless Static Route Option */
352 static int lease_parse_classless_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
353 size_t *routes_size, size_t *routes_allocated) {
354
355 assert(option);
356 assert(routes);
357 assert(routes_size);
358 assert(routes_allocated);
359
360 /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */
361
362 while (len > 0) {
363 uint8_t dst_octets;
364 struct sd_dhcp_route *route;
365
366 if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1))
367 return -ENOMEM;
368
369 route = *routes + *routes_size;
370
371 dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1);
372 route->dst_prefixlen = *option;
373 option++;
374 len--;
375
376 /* can't have more than 4 octets in IPv4 */
377 if (dst_octets > 4 || len < dst_octets)
378 return -EINVAL;
379
380 route->dst_addr.s_addr = 0;
381 memcpy(&route->dst_addr.s_addr, option, dst_octets);
382 option += dst_octets;
383 len -= dst_octets;
384
385 if (len < 4)
386 return -EINVAL;
387
388 lease_parse_be32(option, 4, &route->gw_addr.s_addr);
389 option += 4;
390 len -= 4;
391
392 (*routes_size)++;
393 }
394
395 return 0;
396 }
397
398 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
399 void *user_data) {
400 sd_dhcp_lease *lease = user_data;
401 int r;
402
403 assert(lease);
404
405 switch(code) {
406
407 case DHCP_OPTION_TIME_OFFSET:
408 lease_parse_s32(option, len, &lease->time_offset);
409
410 break;
411
412 case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT:
413 lease_parse_u32(option, len, &lease->mtu_aging_timeout, 0);
414
415 break;
416
417 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
418 lease_parse_u32(option, len, &lease->lifetime, 1);
419
420 break;
421
422 case DHCP_OPTION_SERVER_IDENTIFIER:
423 lease_parse_be32(option, len, &lease->server_address);
424
425 break;
426
427 case DHCP_OPTION_SUBNET_MASK:
428 lease_parse_be32(option, len, &lease->subnet_mask);
429
430 break;
431
432 case DHCP_OPTION_BROADCAST:
433 lease_parse_be32(option, len, &lease->broadcast);
434
435 break;
436
437 case DHCP_OPTION_ROUTER:
438 lease_parse_be32(option, len, &lease->router);
439
440 break;
441
442 case DHCP_OPTION_DOMAIN_NAME_SERVER:
443 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
444 if (r < 0)
445 return r;
446
447 break;
448
449 case DHCP_OPTION_NTP_SERVER:
450 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
451 if (r < 0)
452 return r;
453
454 break;
455
456 case DHCP_OPTION_POLICY_FILTER:
457 r = lease_parse_in_addrs_pairs(option, len, &lease->policy_filter, &lease->policy_filter_size);
458 if (r < 0)
459 return r;
460
461 break;
462
463 case DHCP_OPTION_STATIC_ROUTE:
464 r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size,
465 &lease->static_route_allocated);
466 if (r < 0)
467 return r;
468
469 break;
470
471 case DHCP_OPTION_INTERFACE_MTU:
472 lease_parse_u16(option, len, &lease->mtu, 68);
473
474 break;
475
476 case DHCP_OPTION_INTERFACE_MDR:
477 lease_parse_u16(option, len, &lease->mdr, 576);
478
479 break;
480
481 case DHCP_OPTION_INTERFACE_TTL:
482 lease_parse_u8(option, len, &lease->ttl, 1);
483
484 break;
485
486 case DHCP_OPTION_BOOT_FILE_SIZE:
487 lease_parse_u16(option, len, &lease->boot_file_size, 0);
488
489 break;
490
491 case DHCP_OPTION_DOMAIN_NAME:
492 {
493 _cleanup_free_ char *domainname = NULL;
494 char *e;
495
496 r = lease_parse_string(option, len, &domainname);
497 if (r < 0)
498 return r;
499
500 /* Chop off trailing dot of domain name that some DHCP
501 * servers send us back. Internally we want to store
502 * host names without trailing dots and
503 * host_name_is_valid() doesn't accept them. */
504 e = endswith(domainname, ".");
505 if (e)
506 *e = 0;
507
508 if (is_localhost(domainname))
509 break;
510
511 r = dns_name_is_valid(domainname);
512 if (r <= 0) {
513 if (r < 0)
514 log_error_errno(r, "Failed to validate domain name: %s: %m", domainname);
515 if (r == 0)
516 log_warning("Domain name is not valid, ignoring: %s", domainname);
517 break;
518 }
519
520 free(lease->domainname);
521 lease->domainname = domainname;
522 domainname = NULL;
523
524 break;
525 }
526 case DHCP_OPTION_HOST_NAME:
527 {
528 _cleanup_free_ char *hostname = NULL;
529 char *e;
530
531 r = lease_parse_string(option, len, &hostname);
532 if (r < 0)
533 return r;
534
535 e = endswith(hostname, ".");
536 if (e)
537 *e = 0;
538
539 if (!hostname_is_valid(hostname) || is_localhost(hostname))
540 break;
541
542 free(lease->hostname);
543 lease->hostname = hostname;
544 hostname = NULL;
545
546 break;
547 }
548 case DHCP_OPTION_ROOT_PATH:
549 r = lease_parse_string(option, len, &lease->root_path);
550 if (r < 0)
551 return r;
552
553 break;
554
555 case DHCP_OPTION_RENEWAL_T1_TIME:
556 lease_parse_u32(option, len, &lease->t1, 1);
557
558 break;
559
560 case DHCP_OPTION_REBINDING_T2_TIME:
561 lease_parse_u32(option, len, &lease->t2, 1);
562
563 break;
564
565 case DHCP_OPTION_ENABLE_IP_FORWARDING:
566 lease_parse_bool(option, len, &lease->ip_forward);
567
568 break;
569
570 case DHCP_OPTION_ENABLE_IP_FORWARDING_NL:
571 lease_parse_bool(option, len, &lease->ip_forward_non_local);
572
573 break;
574
575 case DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
576 r = lease_parse_classless_routes(option, len, &lease->static_route, &lease->static_route_size,
577 &lease->static_route_allocated);
578 if (r < 0)
579 return r;
580
581 break;
582 }
583
584 return 0;
585 }
586
587 int dhcp_lease_new(sd_dhcp_lease **ret) {
588 sd_dhcp_lease *lease;
589
590 lease = new0(sd_dhcp_lease, 1);
591 if (!lease)
592 return -ENOMEM;
593
594 lease->router = INADDR_ANY;
595 lease->n_ref = REFCNT_INIT;
596
597 *ret = lease;
598 return 0;
599 }
600
601 int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
602 _cleanup_free_ char *temp_path = NULL;
603 _cleanup_fclose_ FILE *f = NULL;
604 struct in_addr address;
605 const struct in_addr *addresses;
606 const uint8_t *client_id;
607 size_t client_id_len;
608 const char *string;
609 uint16_t mtu;
610 struct sd_dhcp_route *routes;
611 int r;
612
613 assert(lease);
614 assert(lease_file);
615
616 r = fopen_temporary(lease_file, &f, &temp_path);
617 if (r < 0)
618 goto finish;
619
620 fchmod(fileno(f), 0644);
621
622 r = sd_dhcp_lease_get_address(lease, &address);
623 if (r < 0)
624 goto finish;
625
626 fprintf(f,
627 "# This is private data. Do not parse.\n"
628 "ADDRESS=%s\n", inet_ntoa(address));
629
630 r = sd_dhcp_lease_get_netmask(lease, &address);
631 if (r < 0)
632 goto finish;
633
634 fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
635
636 r = sd_dhcp_lease_get_router(lease, &address);
637 if (r >= 0)
638 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
639
640 r = sd_dhcp_lease_get_server_identifier(lease, &address);
641 if (r >= 0)
642 fprintf(f, "SERVER_ADDRESS=%s\n",
643 inet_ntoa(address));
644
645 r = sd_dhcp_lease_get_next_server(lease, &address);
646 if (r >= 0)
647 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
648
649 r = sd_dhcp_lease_get_mtu(lease, &mtu);
650 if (r >= 0)
651 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
652
653 fputs("DNS=", f);
654 r = sd_dhcp_lease_get_dns(lease, &addresses);
655 if (r >= 0)
656 serialize_in_addrs(f, addresses, r);
657 fputs("\n", f);
658
659 fputs("NTP=", f);
660 r = sd_dhcp_lease_get_ntp(lease, &addresses);
661 if (r >= 0)
662 serialize_in_addrs(f, addresses, r);
663 fputs("\n", f);
664
665 r = sd_dhcp_lease_get_domainname(lease, &string);
666 if (r >= 0)
667 fprintf(f, "DOMAINNAME=%s\n", string);
668
669 r = sd_dhcp_lease_get_hostname(lease, &string);
670 if (r >= 0)
671 fprintf(f, "HOSTNAME=%s\n", string);
672
673 r = sd_dhcp_lease_get_root_path(lease, &string);
674 if (r >= 0)
675 fprintf(f, "ROOT_PATH=%s\n", string);
676
677 r = sd_dhcp_lease_get_routes(lease, &routes);
678 if (r >= 0)
679 serialize_dhcp_routes(f, "ROUTES", routes, r);
680
681 r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
682 if (r >= 0) {
683 _cleanup_free_ char *client_id_hex;
684
685 client_id_hex = hexmem(client_id, client_id_len);
686 if (!client_id_hex) {
687 r = -ENOMEM;
688 goto finish;
689 }
690 fprintf(f, "CLIENTID=%s\n", client_id_hex);
691 }
692
693 r = 0;
694
695 fflush(f);
696
697 if (ferror(f) || rename(temp_path, lease_file) < 0) {
698 r = -errno;
699 unlink(lease_file);
700 unlink(temp_path);
701 }
702
703 finish:
704 if (r < 0)
705 log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
706
707 return r;
708 }
709
710 int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
711 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
712 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
713 *server_address = NULL, *next_server = NULL,
714 *dns = NULL, *ntp = NULL, *mtu = NULL,
715 *routes = NULL, *client_id_hex = NULL;
716 struct in_addr addr;
717 int r;
718
719 assert(lease_file);
720 assert(ret);
721
722 r = dhcp_lease_new(&lease);
723 if (r < 0)
724 return r;
725
726 r = parse_env_file(lease_file, NEWLINE,
727 "ADDRESS", &address,
728 "ROUTER", &router,
729 "NETMASK", &netmask,
730 "SERVER_IDENTIFIER", &server_address,
731 "NEXT_SERVER", &next_server,
732 "DNS", &dns,
733 "NTP", &ntp,
734 "MTU", &mtu,
735 "DOMAINNAME", &lease->domainname,
736 "HOSTNAME", &lease->hostname,
737 "ROOT_PATH", &lease->root_path,
738 "ROUTES", &routes,
739 "CLIENTID", &client_id_hex,
740 NULL);
741 if (r < 0) {
742 if (r == -ENOENT)
743 return 0;
744
745 return log_error_errno(r, "Failed to read %s: %m", lease_file);
746 }
747
748 r = inet_pton(AF_INET, address, &addr);
749 if (r < 0)
750 return r;
751
752 lease->address = addr.s_addr;
753
754 if (router) {
755 r = inet_pton(AF_INET, router, &addr);
756 if (r < 0)
757 return r;
758
759 lease->router = addr.s_addr;
760 }
761
762 r = inet_pton(AF_INET, netmask, &addr);
763 if (r < 0)
764 return r;
765
766 lease->subnet_mask = addr.s_addr;
767
768 if (server_address) {
769 r = inet_pton(AF_INET, server_address, &addr);
770 if (r < 0)
771 return r;
772
773 lease->server_address = addr.s_addr;
774 }
775
776 if (next_server) {
777 r = inet_pton(AF_INET, next_server, &addr);
778 if (r < 0)
779 return r;
780
781 lease->next_server = addr.s_addr;
782 }
783
784 if (dns) {
785 r = deserialize_in_addrs(&lease->dns, dns);
786 if (r < 0)
787 return r;
788
789 lease->dns_size = r;
790 }
791
792 if (ntp) {
793 r = deserialize_in_addrs(&lease->ntp, ntp);
794 if (r < 0)
795 return r;
796
797 lease->ntp_size = r;
798 }
799
800 if (mtu) {
801 uint16_t u;
802 if (sscanf(mtu, "%" SCNu16, &u) > 0)
803 lease->mtu = u;
804 }
805
806 if (routes) {
807 r = deserialize_dhcp_routes(&lease->static_route, &lease->static_route_size,
808 &lease->static_route_allocated, routes);
809 if (r < 0)
810 return r;
811 }
812
813 if (client_id_hex) {
814 if (strlen (client_id_hex) % 2)
815 return -EINVAL;
816
817 lease->client_id = unhexmem (client_id_hex, strlen (client_id_hex));
818 if (!lease->client_id)
819 return -ENOMEM;
820 lease->client_id_len = strlen (client_id_hex) / 2;
821 }
822
823 *ret = lease;
824 lease = NULL;
825
826 return 0;
827 }
828
829 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
830 struct in_addr address;
831 struct in_addr mask;
832 int r;
833
834 assert(lease);
835
836 address.s_addr = lease->address;
837
838 /* fall back to the default subnet masks based on address class */
839 r = in_addr_default_subnet_mask(&address, &mask);
840 if (r < 0)
841 return r;
842
843 lease->subnet_mask = mask.s_addr;
844
845 return 0;
846 }
847
848 int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id,
849 size_t *client_id_len) {
850 assert_return(lease, -EINVAL);
851 assert_return(client_id, -EINVAL);
852 assert_return(client_id_len, -EINVAL);
853
854 *client_id = lease->client_id;
855 *client_id_len = lease->client_id_len;
856 return 0;
857 }
858
859 int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id,
860 size_t client_id_len) {
861 assert_return(lease, -EINVAL);
862 assert_return((!client_id && !client_id_len) ||
863 (client_id && client_id_len), -EINVAL);
864
865 free (lease->client_id);
866 lease->client_id = NULL;
867 lease->client_id_len = 0;
868
869 if (client_id) {
870 lease->client_id = memdup (client_id, client_id_len);
871 lease->client_id_len = client_id_len;
872 }
873
874 return 0;
875 }