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