]> git.ipfire.org Git - thirdparty/systemd.git/blob - 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
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>
26 #include <arpa/inet.h>
27 #include <sys/param.h>
28
29 #include "util.h"
30 #include "list.h"
31 #include "mkdir.h"
32 #include "fileio.h"
33 #include "in-addr-util.h"
34
35 #include "dhcp-protocol.h"
36 #include "dhcp-internal.h"
37 #include "dhcp-lease-internal.h"
38 #include "sd-dhcp-lease.h"
39 #include "sd-dhcp-client.h"
40 #include "network-internal.h"
41
42 int 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
51 int 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
60 int 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
72 int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) {
73 assert_return(lease, -EINVAL);
74 assert_return(addr, -EINVAL);
75
76 if (lease->dns_size) {
77 *addr = lease->dns;
78 return lease->dns_size;
79 } else
80 return -ENOENT;
81
82 return 0;
83 }
84
85 int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) {
86 assert_return(lease, -EINVAL);
87 assert_return(addr, -EINVAL);
88
89 if (lease->ntp_size) {
90 *addr = lease->ntp;
91 return lease->ntp_size;
92 } else
93 return -ENOENT;
94
95 return 0;
96 }
97
98 int 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
110 int 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
122 int 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
134 int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) {
135 assert_return(lease, -EINVAL);
136 assert_return(addr, -EINVAL);
137
138 if (lease->router != INADDR_ANY)
139 addr->s_addr = lease->router;
140 else
141 return -ENOENT;
142
143 return 0;
144 }
145
146 int 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
155 int 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
164 int 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
173 int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes) {
174
175 assert_return(lease, -EINVAL);
176 assert_return(routes, -EINVAL);
177
178 if (lease->static_route_size) {
179 *routes = lease->static_route;
180 return lease->static_route_size;
181 } else
182 return -ENOENT;
183
184 return 0;
185 }
186
187 sd_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
194 sd_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);
199 free(lease->ntp);
200 free(lease->static_route);
201 free(lease);
202 }
203
204 return NULL;
205 }
206
207 static 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
222 static 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
226 static 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
241 static 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
249 static 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
257 static 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
269 static 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
287 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) {
288 assert(option);
289 assert(ret);
290 assert(ret_size);
291
292 if (len && !(len % (4 * mult))) {
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
310 static 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
314 static 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
318 static 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
335 static 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 */
377 static 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
423 int 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;
426 int r;
427
428 assert(lease);
429
430 switch(code) {
431
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
442 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
443 lease_parse_u32(option, len, &lease->lifetime, 1);
444
445 break;
446
447 case DHCP_OPTION_SERVER_IDENTIFIER:
448 lease_parse_be32(option, len, &lease->server_address);
449
450 break;
451
452 case DHCP_OPTION_SUBNET_MASK:
453 lease_parse_be32(option, len, &lease->subnet_mask);
454
455 break;
456
457 case DHCP_OPTION_BROADCAST:
458 lease_parse_be32(option, len, &lease->broadcast);
459
460 break;
461
462 case DHCP_OPTION_ROUTER:
463 lease_parse_be32(option, len, &lease->router);
464
465 break;
466
467 case DHCP_OPTION_DOMAIN_NAME_SERVER:
468 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
469 if (r < 0)
470 return r;
471
472 break;
473
474 case DHCP_OPTION_NTP_SERVER:
475 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
476 if (r < 0)
477 return r;
478
479 break;
480
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:
489 r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size,
490 &lease->static_route_allocated);
491 if (r < 0)
492 return r;
493
494 break;
495
496 case DHCP_OPTION_INTERFACE_MTU:
497 lease_parse_u16(option, len, &lease->mtu, 68);
498
499 break;
500
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
516 case DHCP_OPTION_DOMAIN_NAME:
517 {
518 _cleanup_free_ char *domainname = NULL;
519
520 r = lease_parse_string(option, len, &domainname);
521 if (r < 0)
522 return r;
523
524 if (!hostname_is_valid(domainname) || is_localhost(domainname))
525 break;
526
527 free(lease->domainname);
528 lease->domainname = domainname;
529 domainname = NULL;
530
531 break;
532 }
533 case DHCP_OPTION_HOST_NAME:
534 {
535 _cleanup_free_ char *hostname = NULL;
536
537 r = lease_parse_string(option, len, &hostname);
538 if (r < 0)
539 return r;
540
541 if (!hostname_is_valid(hostname) || is_localhost(hostname))
542 break;
543
544 free(lease->hostname);
545 lease->hostname = hostname;
546 hostname = NULL;
547
548 break;
549 }
550 case DHCP_OPTION_ROOT_PATH:
551 r = lease_parse_string(option, len, &lease->root_path);
552 if (r < 0)
553 return r;
554
555 break;
556
557 case DHCP_OPTION_RENEWAL_T1_TIME:
558 lease_parse_u32(option, len, &lease->t1, 1);
559
560 break;
561
562 case DHCP_OPTION_REBINDING_T2_TIME:
563 lease_parse_u32(option, len, &lease->t2, 1);
564
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
575 break;
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;
584 }
585
586 return 0;
587 }
588
589 int dhcp_lease_new(sd_dhcp_lease **ret) {
590 sd_dhcp_lease *lease;
591
592 lease = new0(sd_dhcp_lease, 1);
593 if (!lease)
594 return -ENOMEM;
595
596 lease->router = INADDR_ANY;
597 lease->n_ref = REFCNT_INIT;
598
599 *ret = lease;
600 return 0;
601 }
602
603 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
604 _cleanup_free_ char *temp_path = NULL;
605 _cleanup_fclose_ FILE *f = NULL;
606 struct in_addr address;
607 const struct in_addr *addresses;
608 const char *string;
609 uint16_t mtu;
610 struct sd_dhcp_route *routes;
611 int r;
612
613 assert(lease);
614 assert(lease_file);
615
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
626 fprintf(f,
627 "# This is private data. Do not parse.\n"
628 "ADDRESS=%s\n", inet_ntoa(address));
629
630 r = sd_dhcp_lease_get_netmask(lease, &address);
631 if (r < 0)
632 goto finish;
633
634 fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
635
636 r = sd_dhcp_lease_get_router(lease, &address);
637 if (r >= 0)
638 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
639
640 r = sd_dhcp_lease_get_server_identifier(lease, &address);
641 if (r >= 0)
642 fprintf(f, "SERVER_ADDRESS=%s\n",
643 inet_ntoa(address));
644
645 r = sd_dhcp_lease_get_next_server(lease, &address);
646 if (r >= 0)
647 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
648
649 r = sd_dhcp_lease_get_mtu(lease, &mtu);
650 if (r >= 0)
651 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
652
653 fputs("DNS=", f);
654 r = sd_dhcp_lease_get_dns(lease, &addresses);
655 if (r >= 0)
656 serialize_in_addrs(f, addresses, r);
657 fputs("\n", f);
658
659 fputs("NTP=", f);
660 r = sd_dhcp_lease_get_ntp(lease, &addresses);
661 if (r >= 0)
662 serialize_in_addrs(f, addresses, r);
663 fputs("\n", f);
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
673 r = sd_dhcp_lease_get_root_path(lease, &string);
674 if (r >= 0)
675 fprintf(f, "ROOT_PATH=%s\n", string);
676
677 r = sd_dhcp_lease_get_routes(lease, &routes);
678 if (r >= 0)
679 serialize_dhcp_routes(f, "ROUTES", routes, r);
680
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
691 finish:
692 if (r < 0)
693 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
694
695 return r;
696 }
697
698 int 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,
701 *server_address = NULL, *next_server = NULL,
702 *dns = NULL, *ntp = NULL, *mtu = NULL, *routes = NULL;
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,
717 "SERVER_IDENTIFIER", &server_address,
718 "NEXT_SERVER", &next_server,
719 "DNS", &dns,
720 "NTP", &ntp,
721 "MTU", &mtu,
722 "DOMAINNAME", &lease->domainname,
723 "HOSTNAME", &lease->hostname,
724 "ROOT_PATH", &lease->root_path,
725 "ROUTES", &routes,
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
741 if (router) {
742 r = inet_pton(AF_INET, router, &addr);
743 if (r < 0)
744 return r;
745
746 lease->router = addr.s_addr;
747 }
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
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
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
771 if (dns) {
772 r = deserialize_in_addrs(&lease->dns, dns);
773 if (r < 0)
774 return r;
775
776 lease->dns_size = r;
777 }
778
779 if (ntp) {
780 r = deserialize_in_addrs(&lease->ntp, ntp);
781 if (r < 0)
782 return r;
783
784 lease->ntp_size = r;
785 }
786
787 if (mtu) {
788 uint16_t u;
789 if (sscanf(mtu, "%" SCNu16, &u) > 0)
790 lease->mtu = u;
791 }
792
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
800 *ret = lease;
801 lease = NULL;
802
803 return 0;
804 }
805
806 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
807 struct in_addr address;
808 struct in_addr mask;
809 int r;
810
811 assert(lease);
812
813 address.s_addr = lease->address;
814
815 /* fall back to the default subnet masks based on address class */
816 r = in_addr_default_subnet_mask(&address, &mask);
817 if (r < 0)
818 return r;
819
820 lease->subnet_mask = mask.s_addr;
821
822 return 0;
823 }