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