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