chiark / gitweb /
sd-dhcp-client/networkd: set lifetimes for IPv4 addresses
[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
34 #include "dhcp-protocol.h"
35 #include "dhcp-internal.h"
36 #include "dhcp-lease-internal.h"
37 #include "sd-dhcp-lease.h"
38 #include "sd-dhcp-client.h"
39 #include "network-internal.h"
40
41 int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
42         assert_return(lease, -EINVAL);
43         assert_return(addr, -EINVAL);
44
45         addr->s_addr = lease->address;
46
47         return 0;
48 }
49
50 int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
51         assert_return(lease, -EINVAL);
52         assert_return(lease, -EINVAL);
53
54         *lifetime = lease->lifetime;
55
56         return 0;
57 }
58
59 int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
60         assert_return(lease, -EINVAL);
61         assert_return(mtu, -EINVAL);
62
63         if (lease->mtu)
64                 *mtu = lease->mtu;
65         else
66                 return -ENOENT;
67
68         return 0;
69 }
70
71 int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, struct in_addr **addr, size_t *addr_size) {
72         assert_return(lease, -EINVAL);
73         assert_return(addr, -EINVAL);
74         assert_return(addr_size, -EINVAL);
75
76         if (lease->dns_size) {
77                 *addr_size = lease->dns_size;
78                 *addr = lease->dns;
79         } else
80                 return -ENOENT;
81
82         return 0;
83 }
84
85 int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, struct in_addr **addr, size_t *addr_size) {
86         assert_return(lease, -EINVAL);
87         assert_return(addr, -EINVAL);
88         assert_return(addr_size, -EINVAL);
89
90         if (lease->ntp_size) {
91                 *addr_size = lease->ntp_size;
92                 *addr = lease->ntp;
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 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
175         if (lease)
176                 assert_se(REFCNT_INC(lease->n_ref) >= 2);
177
178         return lease;
179 }
180
181 sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
182         if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
183                 free(lease->hostname);
184                 free(lease->domainname);
185                 free(lease->dns);
186                 free(lease->ntp);
187                 free(lease);
188         }
189
190         return NULL;
191 }
192
193 static void lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
194         be32_t val;
195
196         assert(option);
197         assert(ret);
198
199         if (len == 4) {
200                 memcpy(&val, option, 4);
201                 *ret = be32toh(val);
202
203                 if (*ret < min)
204                         *ret = min;
205         }
206 }
207
208 static void lease_parse_s32(const uint8_t *option, size_t len, int32_t *ret) {
209         lease_parse_u32(option, len, (uint32_t *)ret, 0);
210 }
211
212 static void lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
213         be16_t val;
214
215         assert(option);
216         assert(ret);
217
218         if (len == 2) {
219                 memcpy(&val, option, 2);
220                 *ret = be16toh(val);
221
222                 if (*ret < min)
223                         *ret = min;
224         }
225 }
226
227 static void lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
228         assert(option);
229         assert(ret);
230
231         if (len == 4)
232                 memcpy(ret, option, 4);
233 }
234
235 static void lease_parse_bool(const uint8_t *option, size_t len, bool *ret) {
236         assert(option);
237         assert(ret);
238
239         if (len == 1)
240                 *ret = !!(*option);
241 }
242
243 static void lease_parse_u8(const uint8_t *option, size_t len, uint8_t *ret, uint8_t min) {
244         assert(option);
245         assert(ret);
246
247         if (len == 1) {
248                 *ret = *option;
249
250                 if (*ret < min)
251                         *ret = min;
252         }
253 }
254
255 static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
256         assert(option);
257         assert(ret);
258
259         if (len >= 1) {
260                 char *string;
261
262                 string = strndup((const char *)option, len);
263                 if (!string)
264                         return -errno;
265
266                 free(*ret);
267                 *ret = string;
268         }
269
270         return 0;
271 }
272
273 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) {
274         assert(option);
275         assert(ret);
276         assert(ret_size);
277
278         if (len && !(len % (4 * mult))) {
279                 size_t size;
280                 struct in_addr *addresses;
281
282                 size = len / 4;
283
284                 addresses = newdup(struct in_addr, option, size);
285                 if (!addresses)
286                         return -ENOMEM;
287
288                 free(*ret);
289                 *ret = addresses;
290                 *ret_size = size;
291         }
292
293         return 0;
294 }
295
296 static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
297         return lease_parse_in_addrs_aux(option, len, ret, ret_size, 1);
298 }
299
300 static int lease_parse_in_addrs_pairs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) {
301         return lease_parse_in_addrs_aux(option, len, ret, ret_size, 2);
302 }
303
304 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
305                               void *user_data) {
306         sd_dhcp_lease *lease = user_data;
307         int r;
308
309         assert(lease);
310
311         switch(code) {
312
313         case DHCP_OPTION_TIME_OFFSET:
314                 lease_parse_s32(option, len, &lease->time_offset);
315
316                 break;
317
318         case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT:
319                 lease_parse_u32(option, len, &lease->mtu_aging_timeout, 0);
320
321                 break;
322
323         case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
324                 lease_parse_u32(option, len, &lease->lifetime, 1);
325
326                 break;
327
328         case DHCP_OPTION_SERVER_IDENTIFIER:
329                 lease_parse_be32(option, len, &lease->server_address);
330
331                 break;
332
333         case DHCP_OPTION_SUBNET_MASK:
334                 lease_parse_be32(option, len, &lease->subnet_mask);
335
336                 break;
337
338         case DHCP_OPTION_BROADCAST:
339                 lease_parse_be32(option, len, &lease->broadcast);
340
341                 break;
342
343         case DHCP_OPTION_ROUTER:
344                 lease_parse_be32(option, len, &lease->router);
345
346                 break;
347
348         case DHCP_OPTION_DOMAIN_NAME_SERVER:
349                 r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size);
350                 if (r < 0)
351                         return r;
352
353                 break;
354
355         case DHCP_OPTION_NTP_SERVER:
356                 r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size);
357                 if (r < 0)
358                         return r;
359
360                 break;
361
362         case DHCP_OPTION_POLICY_FILTER:
363                 r = lease_parse_in_addrs_pairs(option, len, &lease->policy_filter, &lease->policy_filter_size);
364                 if (r < 0)
365                         return r;
366
367                 break;
368
369         case DHCP_OPTION_STATIC_ROUTE:
370                 r = lease_parse_in_addrs_pairs(option, len, &lease->static_route, &lease->static_route_size);
371                 if (r < 0)
372                         return r;
373
374                 break;
375
376         case DHCP_OPTION_INTERFACE_MTU:
377                 lease_parse_u16(option, len, &lease->mtu, 68);
378
379                 break;
380
381         case DHCP_OPTION_INTERFACE_MDR:
382                 lease_parse_u16(option, len, &lease->mdr, 576);
383
384                 break;
385
386         case DHCP_OPTION_INTERFACE_TTL:
387                 lease_parse_u8(option, len, &lease->ttl, 1);
388
389                 break;
390
391         case DHCP_OPTION_BOOT_FILE_SIZE:
392                 lease_parse_u16(option, len, &lease->boot_file_size, 0);
393
394                 break;
395
396         case DHCP_OPTION_DOMAIN_NAME:
397                 r = lease_parse_string(option, len, &lease->domainname);
398                 if (r < 0)
399                         return r;
400
401                 break;
402
403         case DHCP_OPTION_HOST_NAME:
404                 r = lease_parse_string(option, len, &lease->hostname);
405                 if (r < 0)
406                         return r;
407
408                 break;
409
410         case DHCP_OPTION_ROOT_PATH:
411                 r = lease_parse_string(option, len, &lease->root_path);
412                 if (r < 0)
413                         return r;
414
415                 break;
416
417         case DHCP_OPTION_RENEWAL_T1_TIME:
418                 lease_parse_u32(option, len, &lease->t1, 1);
419
420                 break;
421
422         case DHCP_OPTION_REBINDING_T2_TIME:
423                 lease_parse_u32(option, len, &lease->t2, 1);
424
425                 break;
426
427         case DHCP_OPTION_ENABLE_IP_FORWARDING:
428                 lease_parse_bool(option, len, &lease->ip_forward);
429
430                 break;
431
432         case DHCP_OPTION_ENABLE_IP_FORWARDING_NL:
433                 lease_parse_bool(option, len, &lease->ip_forward_non_local);
434
435                 break;
436         }
437
438         return 0;
439 }
440
441 int dhcp_lease_new(sd_dhcp_lease **ret) {
442         sd_dhcp_lease *lease;
443
444         lease = new0(sd_dhcp_lease, 1);
445         if (!lease)
446                 return -ENOMEM;
447
448         lease->router = INADDR_ANY;
449         lease->n_ref = REFCNT_INIT;
450
451         *ret = lease;
452         return 0;
453 }
454
455 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
456         _cleanup_free_ char *temp_path = NULL;
457         _cleanup_fclose_ FILE *f = NULL;
458         struct in_addr address;
459         struct in_addr *addresses;
460         size_t addresses_size;
461         const char *string;
462         uint16_t mtu;
463         int r;
464
465         assert(lease);
466         assert(lease_file);
467
468         r = fopen_temporary(lease_file, &f, &temp_path);
469         if (r < 0)
470                 goto finish;
471
472         fchmod(fileno(f), 0644);
473
474         r = sd_dhcp_lease_get_address(lease, &address);
475         if (r < 0)
476                 goto finish;
477
478         fprintf(f,
479                 "# This is private data. Do not parse.\n"
480                 "ADDRESS=%s\n", inet_ntoa(address));
481
482         r = sd_dhcp_lease_get_netmask(lease, &address);
483         if (r < 0)
484                 goto finish;
485
486         fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
487
488         r = sd_dhcp_lease_get_router(lease, &address);
489         if (r >= 0)
490                 fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
491
492         r = sd_dhcp_lease_get_server_identifier(lease, &address);
493         if (r >= 0)
494                 fprintf(f, "SERVER_ADDRESS=%s\n",
495                         inet_ntoa(address));
496
497         r = sd_dhcp_lease_get_next_server(lease, &address);
498         if (r >= 0)
499                 fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
500
501         r = sd_dhcp_lease_get_mtu(lease, &mtu);
502         if (r >= 0)
503                 fprintf(f, "MTU=%" PRIu16 "\n", mtu);
504
505         r = sd_dhcp_lease_get_dns(lease, &addresses, &addresses_size);
506         if (r >= 0)
507                 serialize_in_addrs(f, "DNS", addresses, addresses_size);
508
509         r = sd_dhcp_lease_get_ntp(lease, &addresses, &addresses_size);
510         if (r >= 0)
511                 serialize_in_addrs(f, "NTP", addresses, addresses_size);
512
513         r = sd_dhcp_lease_get_domainname(lease, &string);
514         if (r >= 0)
515                 fprintf(f, "DOMAINNAME=%s\n", string);
516
517         r = sd_dhcp_lease_get_hostname(lease, &string);
518         if (r >= 0)
519                 fprintf(f, "HOSTNAME=%s\n", string);
520
521         r = sd_dhcp_lease_get_root_path(lease, &string);
522         if (r >= 0)
523                 fprintf(f, "ROOT_PATH=%s\n", string);
524
525         r = 0;
526
527         fflush(f);
528
529         if (ferror(f) || rename(temp_path, lease_file) < 0) {
530                 r = -errno;
531                 unlink(lease_file);
532                 unlink(temp_path);
533         }
534
535 finish:
536         if (r < 0)
537                 log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
538
539         return r;
540 }
541
542 int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
543         _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
544         _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
545                             *server_address = NULL, *next_server = NULL,
546                             *dns = NULL, *ntp = NULL, *mtu = NULL;
547         struct in_addr addr;
548         int r;
549
550         assert(lease_file);
551         assert(ret);
552
553         r = dhcp_lease_new(&lease);
554         if (r < 0)
555                 return r;
556
557         r = parse_env_file(lease_file, NEWLINE,
558                            "ADDRESS", &address,
559                            "ROUTER", &router,
560                            "NETMASK", &netmask,
561                            "SERVER_IDENTIFIER", &server_address,
562                            "NEXT_SERVER", &next_server,
563                            "DNS", &dns,
564                            "NTP", &ntp,
565                            "MTU", &mtu,
566                            "DOMAINNAME", &lease->domainname,
567                            "HOSTNAME", &lease->hostname,
568                            "ROOT_PATH", &lease->root_path,
569                            NULL);
570         if (r < 0) {
571                 if (r == -ENOENT)
572                         return 0;
573
574                 log_error("Failed to read %s: %s", lease_file, strerror(-r));
575                 return r;
576         }
577
578         r = inet_pton(AF_INET, address, &addr);
579         if (r < 0)
580                 return r;
581
582         lease->address = addr.s_addr;
583
584         if (router) {
585                 r = inet_pton(AF_INET, router, &addr);
586                 if (r < 0)
587                         return r;
588
589                 lease->router = addr.s_addr;
590         }
591
592         r = inet_pton(AF_INET, netmask, &addr);
593         if (r < 0)
594                 return r;
595
596         lease->subnet_mask = addr.s_addr;
597
598         if (server_address) {
599                 r = inet_pton(AF_INET, server_address, &addr);
600                 if (r < 0)
601                         return r;
602
603                 lease->server_address = addr.s_addr;
604         }
605
606         if (next_server) {
607                 r = inet_pton(AF_INET, next_server, &addr);
608                 if (r < 0)
609                         return r;
610
611                 lease->next_server = addr.s_addr;
612         }
613
614         if (dns) {
615                 r = deserialize_in_addrs(&lease->dns, &lease->dns_size, dns);
616                 if (r < 0)
617                         return r;
618         }
619
620         if (ntp) {
621                 r = deserialize_in_addrs(&lease->ntp, &lease->ntp_size, dns);
622                 if (r < 0)
623                         return r;
624         }
625
626         if (mtu) {
627                 uint16_t u;
628                 if (sscanf(mtu, "%" SCNu16, &u) > 0)
629                         lease->mtu = u;
630         }
631
632         *ret = lease;
633         lease = NULL;
634
635         return 0;
636 }
637
638 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
639         uint32_t address;
640
641         assert(lease);
642         assert(lease->address != INADDR_ANY);
643
644         address = be32toh(lease->address);
645
646         /* fall back to the default subnet masks based on address class */
647
648         if ((address >> 31) == 0x0)
649                 /* class A, leading bits: 0 */
650                 lease->subnet_mask = htobe32(0xff000000);
651         else if ((address >> 30) == 0x2)
652                 /* class B, leading bits 10 */
653                 lease->subnet_mask = htobe32(0xffff0000);
654         else if ((address >> 29) == 0x6)
655                 /* class C, leading bits 110 */
656                 lease->subnet_mask = htobe32(0xffffff00);
657         else
658                 /* class D or E, no default mask. give up */
659                 return -ERANGE;
660
661         return 0;
662 }