]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp-lease.c
hostname-util: add relax parameter to hostname_is_valid
[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, false) || is_localhost(hostname))
557 break;
558
559 free_and_replace(&lease->hostname, hostname);
560 hostname = NULL;
561
562 break;
563 }
564 case DHCP_OPTION_ROOT_PATH:
565 r = lease_parse_string(option, len, &lease->root_path);
566 if (r < 0)
567 return r;
568
569 break;
570
571 case DHCP_OPTION_RENEWAL_T1_TIME:
572 lease_parse_u32(option, len, &lease->t1, 1);
573
574 break;
575
576 case DHCP_OPTION_REBINDING_T2_TIME:
577 lease_parse_u32(option, len, &lease->t2, 1);
578
579 break;
580
581 case DHCP_OPTION_ENABLE_IP_FORWARDING:
582 lease_parse_bool(option, len, &lease->ip_forward);
583
584 break;
585
586 case DHCP_OPTION_ENABLE_IP_FORWARDING_NL:
587 lease_parse_bool(option, len, &lease->ip_forward_non_local);
588
589 break;
590
591 case DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
592 r = lease_parse_classless_routes(option, len, &lease->static_route, &lease->static_route_size,
593 &lease->static_route_allocated);
594 if (r < 0)
595 return r;
596
597 break;
598
599 case DHCP_OPTION_VENDOR_SPECIFIC:
600 if (len >= 1) {
601 free(lease->vendor_specific);
602 lease->vendor_specific = memdup(option, len);
603 if (!lease->vendor_specific)
604 return -ENOMEM;
605 lease->vendor_specific_len = len;
606 }
607
608 break;
609 }
610
611 return 0;
612 }
613
614 int dhcp_lease_new(sd_dhcp_lease **ret) {
615 sd_dhcp_lease *lease;
616
617 lease = new0(sd_dhcp_lease, 1);
618 if (!lease)
619 return -ENOMEM;
620
621 lease->router = INADDR_ANY;
622 lease->n_ref = REFCNT_INIT;
623
624 *ret = lease;
625 return 0;
626 }
627
628 int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
629 _cleanup_free_ char *temp_path = NULL;
630 _cleanup_fclose_ FILE *f = NULL;
631 struct in_addr address;
632 const struct in_addr *addresses;
633 const uint8_t *client_id, *data;
634 size_t client_id_len, data_len;
635 const char *string;
636 uint16_t mtu;
637 struct sd_dhcp_route *routes;
638 int r;
639
640 assert(lease);
641 assert(lease_file);
642
643 r = fopen_temporary(lease_file, &f, &temp_path);
644 if (r < 0)
645 goto finish;
646
647 fchmod(fileno(f), 0644);
648
649 r = sd_dhcp_lease_get_address(lease, &address);
650 if (r < 0)
651 goto finish;
652
653 fprintf(f,
654 "# This is private data. Do not parse.\n"
655 "ADDRESS=%s\n", inet_ntoa(address));
656
657 r = sd_dhcp_lease_get_netmask(lease, &address);
658 if (r < 0)
659 goto finish;
660
661 fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
662
663 r = sd_dhcp_lease_get_router(lease, &address);
664 if (r >= 0)
665 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
666
667 r = sd_dhcp_lease_get_server_identifier(lease, &address);
668 if (r >= 0)
669 fprintf(f, "SERVER_ADDRESS=%s\n",
670 inet_ntoa(address));
671
672 r = sd_dhcp_lease_get_next_server(lease, &address);
673 if (r >= 0)
674 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
675
676 r = sd_dhcp_lease_get_mtu(lease, &mtu);
677 if (r >= 0)
678 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
679
680 fputs("DNS=", f);
681 r = sd_dhcp_lease_get_dns(lease, &addresses);
682 if (r >= 0)
683 serialize_in_addrs(f, addresses, r);
684 fputs("\n", f);
685
686 fputs("NTP=", f);
687 r = sd_dhcp_lease_get_ntp(lease, &addresses);
688 if (r >= 0)
689 serialize_in_addrs(f, addresses, r);
690 fputs("\n", f);
691
692 r = sd_dhcp_lease_get_domainname(lease, &string);
693 if (r >= 0)
694 fprintf(f, "DOMAINNAME=%s\n", string);
695
696 r = sd_dhcp_lease_get_hostname(lease, &string);
697 if (r >= 0)
698 fprintf(f, "HOSTNAME=%s\n", string);
699
700 r = sd_dhcp_lease_get_root_path(lease, &string);
701 if (r >= 0)
702 fprintf(f, "ROOT_PATH=%s\n", string);
703
704 r = sd_dhcp_lease_get_routes(lease, &routes);
705 if (r >= 0)
706 serialize_dhcp_routes(f, "ROUTES", routes, r);
707
708 r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
709 if (r >= 0) {
710 _cleanup_free_ char *client_id_hex;
711
712 client_id_hex = hexmem(client_id, client_id_len);
713 if (!client_id_hex) {
714 r = -ENOMEM;
715 goto finish;
716 }
717 fprintf(f, "CLIENTID=%s\n", client_id_hex);
718 }
719
720 r = sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len);
721 if (r >= 0) {
722 _cleanup_free_ char *option_hex = NULL;
723
724 option_hex = hexmem(data, data_len);
725 if (!option_hex) {
726 r = -ENOMEM;
727 goto finish;
728 }
729 fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
730 }
731
732 r = 0;
733
734 fflush(f);
735
736 if (ferror(f) || rename(temp_path, lease_file) < 0) {
737 r = -errno;
738 unlink(lease_file);
739 unlink(temp_path);
740 }
741
742 finish:
743 if (r < 0)
744 log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
745
746 return r;
747 }
748
749 int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
750 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
751 _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
752 *server_address = NULL, *next_server = NULL,
753 *dns = NULL, *ntp = NULL, *mtu = NULL,
754 *routes = NULL, *client_id_hex = NULL,
755 *vendor_specific_hex = NULL;
756 struct in_addr addr;
757 int r;
758
759 assert(lease_file);
760 assert(ret);
761
762 r = dhcp_lease_new(&lease);
763 if (r < 0)
764 return r;
765
766 r = parse_env_file(lease_file, NEWLINE,
767 "ADDRESS", &address,
768 "ROUTER", &router,
769 "NETMASK", &netmask,
770 "SERVER_IDENTIFIER", &server_address,
771 "NEXT_SERVER", &next_server,
772 "DNS", &dns,
773 "NTP", &ntp,
774 "MTU", &mtu,
775 "DOMAINNAME", &lease->domainname,
776 "HOSTNAME", &lease->hostname,
777 "ROOT_PATH", &lease->root_path,
778 "ROUTES", &routes,
779 "CLIENTID", &client_id_hex,
780 "VENDOR_SPECIFIC", &vendor_specific_hex,
781 NULL);
782 if (r < 0) {
783 if (r == -ENOENT)
784 return 0;
785
786 return log_error_errno(r, "Failed to read %s: %m", lease_file);
787 }
788
789 r = inet_pton(AF_INET, address, &addr);
790 if (r < 0)
791 return r;
792
793 lease->address = addr.s_addr;
794
795 if (router) {
796 r = inet_pton(AF_INET, router, &addr);
797 if (r < 0)
798 return r;
799
800 lease->router = addr.s_addr;
801 }
802
803 r = inet_pton(AF_INET, netmask, &addr);
804 if (r < 0)
805 return r;
806
807 lease->subnet_mask = addr.s_addr;
808
809 if (server_address) {
810 r = inet_pton(AF_INET, server_address, &addr);
811 if (r < 0)
812 return r;
813
814 lease->server_address = addr.s_addr;
815 }
816
817 if (next_server) {
818 r = inet_pton(AF_INET, next_server, &addr);
819 if (r < 0)
820 return r;
821
822 lease->next_server = addr.s_addr;
823 }
824
825 if (dns) {
826 r = deserialize_in_addrs(&lease->dns, dns);
827 if (r < 0)
828 return r;
829
830 lease->dns_size = r;
831 }
832
833 if (ntp) {
834 r = deserialize_in_addrs(&lease->ntp, ntp);
835 if (r < 0)
836 return r;
837
838 lease->ntp_size = r;
839 }
840
841 if (mtu) {
842 uint16_t u;
843 if (sscanf(mtu, "%" SCNu16, &u) > 0)
844 lease->mtu = u;
845 }
846
847 if (routes) {
848 r = deserialize_dhcp_routes(&lease->static_route, &lease->static_route_size,
849 &lease->static_route_allocated, routes);
850 if (r < 0)
851 return r;
852 }
853
854 if (client_id_hex) {
855 if (strlen(client_id_hex) % 2)
856 return -EINVAL;
857
858 r = unhexmem(client_id_hex, strlen(client_id_hex), (void**) &lease->client_id, &lease->client_id_len);
859 if (r < 0)
860 return r;
861 }
862
863 if (vendor_specific_hex) {
864 if (strlen(vendor_specific_hex) % 2)
865 return -EINVAL;
866
867 r = unhexmem(vendor_specific_hex, strlen(vendor_specific_hex), (void**) &lease->vendor_specific, &lease->vendor_specific_len);
868 if (r < 0)
869 return r;
870 }
871
872 *ret = lease;
873 lease = NULL;
874
875 return 0;
876 }
877
878 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
879 struct in_addr address;
880 struct in_addr mask;
881 int r;
882
883 assert(lease);
884
885 address.s_addr = lease->address;
886
887 /* fall back to the default subnet masks based on address class */
888 r = in_addr_default_subnet_mask(&address, &mask);
889 if (r < 0)
890 return r;
891
892 lease->subnet_mask = mask.s_addr;
893
894 return 0;
895 }
896
897 int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id,
898 size_t *client_id_len) {
899 assert_return(lease, -EINVAL);
900 assert_return(client_id, -EINVAL);
901 assert_return(client_id_len, -EINVAL);
902
903 *client_id = lease->client_id;
904 *client_id_len = lease->client_id_len;
905 return 0;
906 }
907
908 int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id,
909 size_t client_id_len) {
910 assert_return(lease, -EINVAL);
911 assert_return((!client_id && !client_id_len) ||
912 (client_id && client_id_len), -EINVAL);
913
914 free (lease->client_id);
915 lease->client_id = NULL;
916 lease->client_id_len = 0;
917
918 if (client_id) {
919 lease->client_id = memdup (client_id, client_id_len);
920 lease->client_id_len = client_id_len;
921 }
922
923 return 0;
924 }