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