]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp-lease.c
sd-dhcp-lease: fix handling of multiple routers
[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 if(len >= 4)
439 lease_parse_be32(option, 4, &lease->router);
440
441 break;
442
443 case DHCP_OPTION_DOMAIN_NAME_SERVER:
444 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
445 if (r < 0)
446 return r;
447
448 break;
449
450 case DHCP_OPTION_NTP_SERVER:
451 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
452 if (r < 0)
453 return r;
454
455 break;
456
457 case DHCP_OPTION_POLICY_FILTER:
458 r = lease_parse_in_addrs_pairs(option, len, &lease->policy_filter, &lease->policy_filter_size);
459 if (r < 0)
460 return r;
461
462 break;
463
464 case DHCP_OPTION_STATIC_ROUTE:
465 r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size,
466 &lease->static_route_allocated);
467 if (r < 0)
468 return r;
469
470 break;
471
472 case DHCP_OPTION_INTERFACE_MTU:
473 lease_parse_u16(option, len, &lease->mtu, 68);
474
475 break;
476
477 case DHCP_OPTION_INTERFACE_MDR:
478 lease_parse_u16(option, len, &lease->mdr, 576);
479
480 break;
481
482 case DHCP_OPTION_INTERFACE_TTL:
483 lease_parse_u8(option, len, &lease->ttl, 1);
484
485 break;
486
487 case DHCP_OPTION_BOOT_FILE_SIZE:
488 lease_parse_u16(option, len, &lease->boot_file_size, 0);
489
490 break;
491
492 case DHCP_OPTION_DOMAIN_NAME:
493 {
494 _cleanup_free_ char *domainname = NULL;
495 char *e;
496
497 r = lease_parse_string(option, len, &domainname);
498 if (r < 0)
499 return r;
500
501 /* Chop off trailing dot of domain name that some DHCP
502 * servers send us back. Internally we want to store
503 * host names without trailing dots and
504 * host_name_is_valid() doesn't accept them. */
505 e = endswith(domainname, ".");
506 if (e)
507 *e = 0;
508
509 if (is_localhost(domainname))
510 break;
511
512 r = dns_name_is_valid(domainname);
513 if (r <= 0) {
514 if (r < 0)
515 log_error_errno(r, "Failed to validate domain name: %s: %m", domainname);
516 if (r == 0)
517 log_warning("Domain name is not valid, ignoring: %s", domainname);
518 break;
519 }
520
521 free(lease->domainname);
522 lease->domainname = domainname;
523 domainname = NULL;
524
525 break;
526 }
527 case DHCP_OPTION_HOST_NAME:
528 {
529 _cleanup_free_ char *hostname = NULL;
530 char *e;
531
532 r = lease_parse_string(option, len, &hostname);
533 if (r < 0)
534 return r;
535
536 e = endswith(hostname, ".");
537 if (e)
538 *e = 0;
539
540 if (!hostname_is_valid(hostname) || is_localhost(hostname))
541 break;
542
543 free(lease->hostname);
544 lease->hostname = hostname;
545 hostname = NULL;
546
547 break;
548 }
549 case DHCP_OPTION_ROOT_PATH:
550 r = lease_parse_string(option, len, &lease->root_path);
551 if (r < 0)
552 return r;
553
554 break;
555
556 case DHCP_OPTION_RENEWAL_T1_TIME:
557 lease_parse_u32(option, len, &lease->t1, 1);
558
559 break;
560
561 case DHCP_OPTION_REBINDING_T2_TIME:
562 lease_parse_u32(option, len, &lease->t2, 1);
563
564 break;
565
566 case DHCP_OPTION_ENABLE_IP_FORWARDING:
567 lease_parse_bool(option, len, &lease->ip_forward);
568
569 break;
570
571 case DHCP_OPTION_ENABLE_IP_FORWARDING_NL:
572 lease_parse_bool(option, len, &lease->ip_forward_non_local);
573
574 break;
575
576 case DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
577 r = lease_parse_classless_routes(option, len, &lease->static_route, &lease->static_route_size,
578 &lease->static_route_allocated);
579 if (r < 0)
580 return r;
581
582 break;
583 }
584
585 return 0;
586 }
587
588 int dhcp_lease_new(sd_dhcp_lease **ret) {
589 sd_dhcp_lease *lease;
590
591 lease = new0(sd_dhcp_lease, 1);
592 if (!lease)
593 return -ENOMEM;
594
595 lease->router = INADDR_ANY;
596 lease->n_ref = REFCNT_INIT;
597
598 *ret = lease;
599 return 0;
600 }
601
602 int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
603 _cleanup_free_ char *temp_path = NULL;
604 _cleanup_fclose_ FILE *f = NULL;
605 struct in_addr address;
606 const struct in_addr *addresses;
607 const uint8_t *client_id;
608 size_t client_id_len;
609 const char *string;
610 uint16_t mtu;
611 struct sd_dhcp_route *routes;
612 int r;
613
614 assert(lease);
615 assert(lease_file);
616
617 r = fopen_temporary(lease_file, &f, &temp_path);
618 if (r < 0)
619 goto finish;
620
621 fchmod(fileno(f), 0644);
622
623 r = sd_dhcp_lease_get_address(lease, &address);
624 if (r < 0)
625 goto finish;
626
627 fprintf(f,
628 "# This is private data. Do not parse.\n"
629 "ADDRESS=%s\n", inet_ntoa(address));
630
631 r = sd_dhcp_lease_get_netmask(lease, &address);
632 if (r < 0)
633 goto finish;
634
635 fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
636
637 r = sd_dhcp_lease_get_router(lease, &address);
638 if (r >= 0)
639 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
640
641 r = sd_dhcp_lease_get_server_identifier(lease, &address);
642 if (r >= 0)
643 fprintf(f, "SERVER_ADDRESS=%s\n",
644 inet_ntoa(address));
645
646 r = sd_dhcp_lease_get_next_server(lease, &address);
647 if (r >= 0)
648 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
649
650 r = sd_dhcp_lease_get_mtu(lease, &mtu);
651 if (r >= 0)
652 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
653
654 fputs("DNS=", f);
655 r = sd_dhcp_lease_get_dns(lease, &addresses);
656 if (r >= 0)
657 serialize_in_addrs(f, addresses, r);
658 fputs("\n", f);
659
660 fputs("NTP=", f);
661 r = sd_dhcp_lease_get_ntp(lease, &addresses);
662 if (r >= 0)
663 serialize_in_addrs(f, addresses, r);
664 fputs("\n", f);
665
666 r = sd_dhcp_lease_get_domainname(lease, &string);
667 if (r >= 0)
668 fprintf(f, "DOMAINNAME=%s\n", string);
669
670 r = sd_dhcp_lease_get_hostname(lease, &string);
671 if (r >= 0)
672 fprintf(f, "HOSTNAME=%s\n", string);
673
674 r = sd_dhcp_lease_get_root_path(lease, &string);
675 if (r >= 0)
676 fprintf(f, "ROOT_PATH=%s\n", string);
677
678 r = sd_dhcp_lease_get_routes(lease, &routes);
679 if (r >= 0)
680 serialize_dhcp_routes(f, "ROUTES", routes, r);
681
682 r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
683 if (r >= 0) {
684 _cleanup_free_ char *client_id_hex;
685
686 client_id_hex = hexmem(client_id, client_id_len);
687 if (!client_id_hex) {
688 r = -ENOMEM;
689 goto finish;
690 }
691 fprintf(f, "CLIENTID=%s\n", client_id_hex);
692 }
693
694 r = 0;
695
696 fflush(f);
697
698 if (ferror(f) || rename(temp_path, lease_file) < 0) {
699 r = -errno;
700 unlink(lease_file);
701 unlink(temp_path);
702 }
703
704 finish:
705 if (r < 0)
706 log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
707
708 return r;
709 }
710
711 int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
712 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
713 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
714 *server_address = NULL, *next_server = NULL,
715 *dns = NULL, *ntp = NULL, *mtu = NULL,
716 *routes = NULL, *client_id_hex = NULL;
717 struct in_addr addr;
718 int r;
719
720 assert(lease_file);
721 assert(ret);
722
723 r = dhcp_lease_new(&lease);
724 if (r < 0)
725 return r;
726
727 r = parse_env_file(lease_file, NEWLINE,
728 "ADDRESS", &address,
729 "ROUTER", &router,
730 "NETMASK", &netmask,
731 "SERVER_IDENTIFIER", &server_address,
732 "NEXT_SERVER", &next_server,
733 "DNS", &dns,
734 "NTP", &ntp,
735 "MTU", &mtu,
736 "DOMAINNAME", &lease->domainname,
737 "HOSTNAME", &lease->hostname,
738 "ROOT_PATH", &lease->root_path,
739 "ROUTES", &routes,
740 "CLIENTID", &client_id_hex,
741 NULL);
742 if (r < 0) {
743 if (r == -ENOENT)
744 return 0;
745
746 return log_error_errno(r, "Failed to read %s: %m", lease_file);
747 }
748
749 r = inet_pton(AF_INET, address, &addr);
750 if (r < 0)
751 return r;
752
753 lease->address = addr.s_addr;
754
755 if (router) {
756 r = inet_pton(AF_INET, router, &addr);
757 if (r < 0)
758 return r;
759
760 lease->router = addr.s_addr;
761 }
762
763 r = inet_pton(AF_INET, netmask, &addr);
764 if (r < 0)
765 return r;
766
767 lease->subnet_mask = addr.s_addr;
768
769 if (server_address) {
770 r = inet_pton(AF_INET, server_address, &addr);
771 if (r < 0)
772 return r;
773
774 lease->server_address = addr.s_addr;
775 }
776
777 if (next_server) {
778 r = inet_pton(AF_INET, next_server, &addr);
779 if (r < 0)
780 return r;
781
782 lease->next_server = addr.s_addr;
783 }
784
785 if (dns) {
786 r = deserialize_in_addrs(&lease->dns, dns);
787 if (r < 0)
788 return r;
789
790 lease->dns_size = r;
791 }
792
793 if (ntp) {
794 r = deserialize_in_addrs(&lease->ntp, ntp);
795 if (r < 0)
796 return r;
797
798 lease->ntp_size = r;
799 }
800
801 if (mtu) {
802 uint16_t u;
803 if (sscanf(mtu, "%" SCNu16, &u) > 0)
804 lease->mtu = u;
805 }
806
807 if (routes) {
808 r = deserialize_dhcp_routes(&lease->static_route, &lease->static_route_size,
809 &lease->static_route_allocated, routes);
810 if (r < 0)
811 return r;
812 }
813
814 if (client_id_hex) {
815 if (strlen (client_id_hex) % 2)
816 return -EINVAL;
817
818 lease->client_id = unhexmem (client_id_hex, strlen (client_id_hex));
819 if (!lease->client_id)
820 return -ENOMEM;
821 lease->client_id_len = strlen (client_id_hex) / 2;
822 }
823
824 *ret = lease;
825 lease = NULL;
826
827 return 0;
828 }
829
830 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
831 struct in_addr address;
832 struct in_addr mask;
833 int r;
834
835 assert(lease);
836
837 address.s_addr = lease->address;
838
839 /* fall back to the default subnet masks based on address class */
840 r = in_addr_default_subnet_mask(&address, &mask);
841 if (r < 0)
842 return r;
843
844 lease->subnet_mask = mask.s_addr;
845
846 return 0;
847 }
848
849 int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id,
850 size_t *client_id_len) {
851 assert_return(lease, -EINVAL);
852 assert_return(client_id, -EINVAL);
853 assert_return(client_id_len, -EINVAL);
854
855 *client_id = lease->client_id;
856 *client_id_len = lease->client_id_len;
857 return 0;
858 }
859
860 int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id,
861 size_t client_id_len) {
862 assert_return(lease, -EINVAL);
863 assert_return((!client_id && !client_id_len) ||
864 (client_id && client_id_len), -EINVAL);
865
866 free (lease->client_id);
867 lease->client_id = NULL;
868 lease->client_id_len = 0;
869
870 if (client_id) {
871 lease->client_id = memdup (client_id, client_id_len);
872 lease->client_id_len = client_id_len;
873 }
874
875 return 0;
876 }