]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp-lease.c
Merge pull request #787 from dvdhrm/bus-list
[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 fail;
647
648 fchmod(fileno(f), 0644);
649
650 r = sd_dhcp_lease_get_address(lease, &address);
651 if (r < 0)
652 goto fail;
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 fail;
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 fail;
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 fail;
729 }
730 fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
731 }
732
733 r = fflush_and_check(f);
734 if (r < 0)
735 goto fail;
736
737 if (rename(temp_path, lease_file) < 0) {
738 r = -errno;
739 goto fail;
740 }
741
742 return 0;
743
744 fail:
745 if (temp_path)
746 (void) unlink(temp_path);
747
748 return log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
749 }
750
751 int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
752 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
753 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
754 *server_address = NULL, *next_server = NULL,
755 *dns = NULL, *ntp = NULL, *mtu = NULL,
756 *routes = NULL, *client_id_hex = NULL,
757 *vendor_specific_hex = NULL;
758 struct in_addr addr;
759 int r;
760
761 assert(lease_file);
762 assert(ret);
763
764 r = dhcp_lease_new(&lease);
765 if (r < 0)
766 return r;
767
768 r = parse_env_file(lease_file, NEWLINE,
769 "ADDRESS", &address,
770 "ROUTER", &router,
771 "NETMASK", &netmask,
772 "SERVER_IDENTIFIER", &server_address,
773 "NEXT_SERVER", &next_server,
774 "DNS", &dns,
775 "NTP", &ntp,
776 "MTU", &mtu,
777 "DOMAINNAME", &lease->domainname,
778 "HOSTNAME", &lease->hostname,
779 "ROOT_PATH", &lease->root_path,
780 "ROUTES", &routes,
781 "CLIENTID", &client_id_hex,
782 "VENDOR_SPECIFIC", &vendor_specific_hex,
783 NULL);
784 if (r < 0) {
785 if (r == -ENOENT)
786 return 0;
787
788 return log_error_errno(r, "Failed to read %s: %m", lease_file);
789 }
790
791 r = inet_pton(AF_INET, address, &addr);
792 if (r < 0)
793 return r;
794
795 lease->address = addr.s_addr;
796
797 if (router) {
798 r = inet_pton(AF_INET, router, &addr);
799 if (r < 0)
800 return r;
801
802 lease->router = addr.s_addr;
803 }
804
805 r = inet_pton(AF_INET, netmask, &addr);
806 if (r < 0)
807 return r;
808
809 lease->subnet_mask = addr.s_addr;
810
811 if (server_address) {
812 r = inet_pton(AF_INET, server_address, &addr);
813 if (r < 0)
814 return r;
815
816 lease->server_address = addr.s_addr;
817 }
818
819 if (next_server) {
820 r = inet_pton(AF_INET, next_server, &addr);
821 if (r < 0)
822 return r;
823
824 lease->next_server = addr.s_addr;
825 }
826
827 if (dns) {
828 r = deserialize_in_addrs(&lease->dns, dns);
829 if (r < 0)
830 return r;
831
832 lease->dns_size = r;
833 }
834
835 if (ntp) {
836 r = deserialize_in_addrs(&lease->ntp, ntp);
837 if (r < 0)
838 return r;
839
840 lease->ntp_size = r;
841 }
842
843 if (mtu) {
844 uint16_t u;
845 if (sscanf(mtu, "%" SCNu16, &u) > 0)
846 lease->mtu = u;
847 }
848
849 if (routes) {
850 r = deserialize_dhcp_routes(&lease->static_route, &lease->static_route_size,
851 &lease->static_route_allocated, routes);
852 if (r < 0)
853 return r;
854 }
855
856 if (client_id_hex) {
857 if (strlen(client_id_hex) % 2)
858 return -EINVAL;
859
860 r = unhexmem(client_id_hex, strlen(client_id_hex), (void**) &lease->client_id, &lease->client_id_len);
861 if (r < 0)
862 return r;
863 }
864
865 if (vendor_specific_hex) {
866 if (strlen(vendor_specific_hex) % 2)
867 return -EINVAL;
868
869 r = unhexmem(vendor_specific_hex, strlen(vendor_specific_hex), (void**) &lease->vendor_specific, &lease->vendor_specific_len);
870 if (r < 0)
871 return r;
872 }
873
874 *ret = lease;
875 lease = NULL;
876
877 return 0;
878 }
879
880 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
881 struct in_addr address;
882 struct in_addr mask;
883 int r;
884
885 assert(lease);
886
887 address.s_addr = lease->address;
888
889 /* fall back to the default subnet masks based on address class */
890 r = in_addr_default_subnet_mask(&address, &mask);
891 if (r < 0)
892 return r;
893
894 lease->subnet_mask = mask.s_addr;
895
896 return 0;
897 }
898
899 int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id,
900 size_t *client_id_len) {
901 assert_return(lease, -EINVAL);
902 assert_return(client_id, -EINVAL);
903 assert_return(client_id_len, -EINVAL);
904
905 *client_id = lease->client_id;
906 *client_id_len = lease->client_id_len;
907 return 0;
908 }
909
910 int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id,
911 size_t client_id_len) {
912 assert_return(lease, -EINVAL);
913 assert_return((!client_id && !client_id_len) ||
914 (client_id && client_id_len), -EINVAL);
915
916 free (lease->client_id);
917 lease->client_id = NULL;
918 lease->client_id_len = 0;
919
920 if (client_id) {
921 lease->client_id = memdup (client_id, client_id_len);
922 lease->client_id_len = client_id_len;
923 }
924
925 return 0;
926 }