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