]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-address.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / network / networkd-address.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2013 Tom Gundersen <teg@jklm.no>
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 <net/if.h>
22
23 #include "alloc-util.h"
24 #include "conf-parser.h"
25 #include "firewall-util.h"
26 #include "netlink-util.h"
27 #include "networkd-address.h"
28 #include "networkd-manager.h"
29 #include "parse-util.h"
30 #include "set.h"
31 #include "socket-util.h"
32 #include "string-util.h"
33 #include "utf8.h"
34 #include "util.h"
35
36 #define ADDRESSES_PER_LINK_MAX 2048U
37 #define STATIC_ADDRESSES_PER_NETWORK_MAX 1024U
38
39 int address_new(Address **ret) {
40 _cleanup_address_free_ Address *address = NULL;
41
42 address = new0(Address, 1);
43 if (!address)
44 return -ENOMEM;
45
46 address->family = AF_UNSPEC;
47 address->scope = RT_SCOPE_UNIVERSE;
48 address->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
49 address->cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME;
50
51 *ret = address;
52 address = NULL;
53
54 return 0;
55 }
56
57 int address_new_static(Network *network, const char *filename, unsigned section_line, Address **ret) {
58 _cleanup_network_config_section_free_ NetworkConfigSection *n = NULL;
59 _cleanup_address_free_ Address *address = NULL;
60 int r;
61
62 assert(network);
63 assert(ret);
64 assert(!!filename == (section_line > 0));
65
66 if (filename) {
67 r = network_config_section_new(filename, section_line, &n);
68 if (r < 0)
69 return r;
70
71 address = hashmap_get(network->addresses_by_section, n);
72 if (address) {
73 *ret = address;
74 address = NULL;
75
76 return 0;
77 }
78 }
79
80 if (network->n_static_addresses >= STATIC_ADDRESSES_PER_NETWORK_MAX)
81 return -E2BIG;
82
83 r = address_new(&address);
84 if (r < 0)
85 return r;
86
87 if (filename) {
88 address->section = n;
89 n = NULL;
90
91 r = hashmap_put(network->addresses_by_section, address->section, address);
92 if (r < 0)
93 return r;
94 }
95
96 address->network = network;
97 LIST_APPEND(addresses, network->static_addresses, address);
98 network->n_static_addresses++;
99
100 *ret = address;
101 address = NULL;
102
103 return 0;
104 }
105
106 void address_free(Address *address) {
107 if (!address)
108 return;
109
110 if (address->network) {
111 LIST_REMOVE(addresses, address->network->static_addresses, address);
112 assert(address->network->n_static_addresses > 0);
113 address->network->n_static_addresses--;
114
115 if (address->section) {
116 hashmap_remove(address->network->addresses_by_section, address->section);
117 network_config_section_free(address->section);
118 }
119 }
120
121 if (address->link) {
122 set_remove(address->link->addresses, address);
123 set_remove(address->link->addresses_foreign, address);
124
125 if (in_addr_equal(AF_INET6, &address->in_addr, (const union in_addr_union *) &address->link->ipv6ll_address))
126 memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr));
127 }
128
129 free(address);
130 }
131
132 static void address_hash_func(const void *b, struct siphash *state) {
133 const Address *a = b;
134
135 assert(a);
136
137 siphash24_compress(&a->family, sizeof(a->family), state);
138
139 switch (a->family) {
140 case AF_INET:
141 siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
142
143 /* peer prefix */
144 if (a->prefixlen != 0) {
145 uint32_t prefix;
146
147 if (a->in_addr_peer.in.s_addr != 0)
148 prefix = be32toh(a->in_addr_peer.in.s_addr) >> (32 - a->prefixlen);
149 else
150 prefix = be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
151
152 siphash24_compress(&prefix, sizeof(prefix), state);
153 }
154
155 /* fallthrough */
156 case AF_INET6:
157 /* local address */
158 siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
159
160 break;
161 default:
162 /* treat any other address family as AF_UNSPEC */
163 break;
164 }
165 }
166
167 static int address_compare_func(const void *c1, const void *c2) {
168 const Address *a1 = c1, *a2 = c2;
169
170 if (a1->family < a2->family)
171 return -1;
172 if (a1->family > a2->family)
173 return 1;
174
175 switch (a1->family) {
176 /* use the same notion of equality as the kernel does */
177 case AF_INET:
178 if (a1->prefixlen < a2->prefixlen)
179 return -1;
180 if (a1->prefixlen > a2->prefixlen)
181 return 1;
182
183 /* compare the peer prefixes */
184 if (a1->prefixlen != 0) {
185 /* make sure we don't try to shift by 32.
186 * See ISO/IEC 9899:TC3 § 6.5.7.3. */
187 uint32_t b1, b2;
188
189 if (a1->in_addr_peer.in.s_addr != 0)
190 b1 = be32toh(a1->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
191 else
192 b1 = be32toh(a1->in_addr.in.s_addr) >> (32 - a1->prefixlen);
193
194 if (a2->in_addr_peer.in.s_addr != 0)
195 b2 = be32toh(a2->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
196 else
197 b2 = be32toh(a2->in_addr.in.s_addr) >> (32 - a1->prefixlen);
198
199 if (b1 < b2)
200 return -1;
201 if (b1 > b2)
202 return 1;
203 }
204
205 /* fall-through */
206 case AF_INET6:
207 return memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
208 default:
209 /* treat any other address family as AF_UNSPEC */
210 return 0;
211 }
212 }
213
214 static const struct hash_ops address_hash_ops = {
215 .hash = address_hash_func,
216 .compare = address_compare_func
217 };
218
219 bool address_equal(Address *a1, Address *a2) {
220 if (a1 == a2)
221 return true;
222
223 if (!a1 || !a2)
224 return false;
225
226 return address_compare_func(a1, a2) == 0;
227 }
228
229 static int address_establish(Address *address, Link *link) {
230 bool masq;
231 int r;
232
233 assert(address);
234 assert(link);
235
236 masq = link->network &&
237 link->network->ip_masquerade &&
238 address->family == AF_INET &&
239 address->scope < RT_SCOPE_LINK;
240
241 /* Add firewall entry if this is requested */
242 if (address->ip_masquerade_done != masq) {
243 union in_addr_union masked = address->in_addr;
244 in_addr_mask(address->family, &masked, address->prefixlen);
245
246 r = fw_add_masquerade(masq, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
247 if (r < 0)
248 log_link_warning_errno(link, r, "Could not enable IP masquerading: %m");
249
250 address->ip_masquerade_done = masq;
251 }
252
253 return 0;
254 }
255
256 static int address_add_internal(Link *link, Set **addresses,
257 int family,
258 const union in_addr_union *in_addr,
259 unsigned char prefixlen,
260 Address **ret) {
261 _cleanup_address_free_ Address *address = NULL;
262 int r;
263
264 assert(link);
265 assert(addresses);
266 assert(in_addr);
267
268 r = address_new(&address);
269 if (r < 0)
270 return r;
271
272 address->family = family;
273 address->in_addr = *in_addr;
274 address->prefixlen = prefixlen;
275 /* Consider address tentative until we get the real flags from the kernel */
276 address->flags = IFA_F_TENTATIVE;
277
278 r = set_ensure_allocated(addresses, &address_hash_ops);
279 if (r < 0)
280 return r;
281
282 r = set_put(*addresses, address);
283 if (r < 0)
284 return r;
285
286 address->link = link;
287
288 if (ret)
289 *ret = address;
290
291 address = NULL;
292
293 return 0;
294 }
295
296 int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
297 return address_add_internal(link, &link->addresses_foreign, family, in_addr, prefixlen, ret);
298 }
299
300 int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
301 Address *address;
302 int r;
303
304 r = address_get(link, family, in_addr, prefixlen, &address);
305 if (r == -ENOENT) {
306 /* Address does not exist, create a new one */
307 r = address_add_internal(link, &link->addresses, family, in_addr, prefixlen, &address);
308 if (r < 0)
309 return r;
310 } else if (r == 0) {
311 /* Take over a foreign address */
312 r = set_ensure_allocated(&link->addresses, &address_hash_ops);
313 if (r < 0)
314 return r;
315
316 r = set_put(link->addresses, address);
317 if (r < 0)
318 return r;
319
320 set_remove(link->addresses_foreign, address);
321 } else if (r == 1) {
322 /* Already exists, do nothing */
323 ;
324 } else
325 return r;
326
327 if (ret)
328 *ret = address;
329
330 return 0;
331 }
332
333 static int address_release(Address *address) {
334 int r;
335
336 assert(address);
337 assert(address->link);
338
339 /* Remove masquerading firewall entry if it was added */
340 if (address->ip_masquerade_done) {
341 union in_addr_union masked = address->in_addr;
342 in_addr_mask(address->family, &masked, address->prefixlen);
343
344 r = fw_add_masquerade(false, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
345 if (r < 0)
346 log_link_warning_errno(address->link, r, "Failed to disable IP masquerading: %m");
347
348 address->ip_masquerade_done = false;
349 }
350
351 return 0;
352 }
353
354 int address_update(
355 Address *address,
356 unsigned char flags,
357 unsigned char scope,
358 const struct ifa_cacheinfo *cinfo) {
359
360 bool ready;
361 int r;
362
363 assert(address);
364 assert(cinfo);
365 assert_return(address->link, 1);
366
367 if (IN_SET(address->link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
368 return 1;
369
370 ready = address_is_ready(address);
371
372 address->flags = flags;
373 address->scope = scope;
374 address->cinfo = *cinfo;
375
376 link_update_operstate(address->link);
377
378 if (!ready && address_is_ready(address)) {
379 link_check_ready(address->link);
380
381 if (address->family == AF_INET6 &&
382 in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 &&
383 in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) {
384
385 r = link_ipv6ll_gained(address->link, &address->in_addr.in6);
386 if (r < 0)
387 return r;
388 }
389 }
390
391 return 0;
392 }
393
394 int address_drop(Address *address) {
395 Link *link;
396 bool ready;
397
398 assert(address);
399
400 ready = address_is_ready(address);
401 link = address->link;
402
403 address_release(address);
404 address_free(address);
405
406 link_update_operstate(link);
407
408 if (link && !ready)
409 link_check_ready(link);
410
411 return 0;
412 }
413
414 int address_get(Link *link,
415 int family,
416 const union in_addr_union *in_addr,
417 unsigned char prefixlen,
418 Address **ret) {
419
420 Address address, *existing;
421
422 assert(link);
423 assert(in_addr);
424
425 address = (Address) {
426 .family = family,
427 .in_addr = *in_addr,
428 .prefixlen = prefixlen,
429 };
430
431 existing = set_get(link->addresses, &address);
432 if (existing) {
433 if (ret)
434 *ret = existing;
435 return 1;
436 }
437
438 existing = set_get(link->addresses_foreign, &address);
439 if (existing) {
440 if (ret)
441 *ret = existing;
442 return 0;
443 }
444
445 return -ENOENT;
446 }
447
448 int address_remove(
449 Address *address,
450 Link *link,
451 sd_netlink_message_handler_t callback) {
452
453 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
454 int r;
455
456 assert(address);
457 assert(IN_SET(address->family, AF_INET, AF_INET6));
458 assert(link);
459 assert(link->ifindex > 0);
460 assert(link->manager);
461 assert(link->manager->rtnl);
462
463 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
464 link->ifindex, address->family);
465 if (r < 0)
466 return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m");
467
468 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
469 if (r < 0)
470 return log_error_errno(r, "Could not set prefixlen: %m");
471
472 if (address->family == AF_INET)
473 r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
474 else if (address->family == AF_INET6)
475 r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
476 if (r < 0)
477 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
478
479 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
480 if (r < 0)
481 return log_error_errno(r, "Could not send rtnetlink message: %m");
482
483 link_ref(link);
484
485 return 0;
486 }
487
488 static int address_acquire(Link *link, Address *original, Address **ret) {
489 union in_addr_union in_addr = {};
490 struct in_addr broadcast = {};
491 _cleanup_address_free_ Address *na = NULL;
492 int r;
493
494 assert(link);
495 assert(original);
496 assert(ret);
497
498 /* Something useful was configured? just use it */
499 if (in_addr_is_null(original->family, &original->in_addr) <= 0)
500 return 0;
501
502 /* The address is configured to be 0.0.0.0 or [::] by the user?
503 * Then let's acquire something more useful from the pool. */
504 r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
505 if (r < 0)
506 return log_link_error_errno(link, r, "Failed to acquire address from pool: %m");
507 if (r == 0) {
508 log_link_error(link, "Couldn't find free address for interface, all taken.");
509 return -EBUSY;
510 }
511
512 if (original->family == AF_INET) {
513 /* Pick first address in range for ourselves ... */
514 in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
515
516 /* .. and use last as broadcast address */
517 broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
518 } else if (original->family == AF_INET6)
519 in_addr.in6.s6_addr[15] |= 1;
520
521 r = address_new(&na);
522 if (r < 0)
523 return r;
524
525 na->family = original->family;
526 na->prefixlen = original->prefixlen;
527 na->scope = original->scope;
528 na->cinfo = original->cinfo;
529
530 if (original->label) {
531 na->label = strdup(original->label);
532 if (!na->label)
533 return -ENOMEM;
534 }
535
536 na->broadcast = broadcast;
537 na->in_addr = in_addr;
538
539 LIST_PREPEND(addresses, link->pool_addresses, na);
540
541 *ret = na;
542 na = NULL;
543
544 return 0;
545 }
546
547 int address_configure(
548 Address *address,
549 Link *link,
550 sd_netlink_message_handler_t callback,
551 bool update) {
552
553 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
554 int r;
555
556 assert(address);
557 assert(IN_SET(address->family, AF_INET, AF_INET6));
558 assert(link);
559 assert(link->ifindex > 0);
560 assert(link->manager);
561 assert(link->manager->rtnl);
562
563 /* If this is a new address, then refuse adding more than the limit */
564 if (address_get(link, address->family, &address->in_addr, address->prefixlen, NULL) <= 0 &&
565 set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
566 return -E2BIG;
567
568 r = address_acquire(link, address, &address);
569 if (r < 0)
570 return r;
571
572 if (update)
573 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
574 link->ifindex, address->family);
575 else
576 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
577 link->ifindex, address->family);
578 if (r < 0)
579 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
580
581 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
582 if (r < 0)
583 return log_error_errno(r, "Could not set prefixlen: %m");
584
585 address->flags |= IFA_F_PERMANENT;
586
587 if (address->home_address)
588 address->flags |= IFA_F_HOMEADDRESS;
589
590 if (address->duplicate_address_detection)
591 address->flags |= IFA_F_NODAD;
592
593 if (address->manage_temporary_address)
594 address->flags |= IFA_F_MANAGETEMPADDR;
595
596 if (address->prefix_route)
597 address->flags |= IFA_F_NOPREFIXROUTE;
598
599 if (address->autojoin)
600 address->flags |= IFA_F_MCAUTOJOIN;
601
602 r = sd_rtnl_message_addr_set_flags(req, (address->flags & 0xff));
603 if (r < 0)
604 return log_error_errno(r, "Could not set flags: %m");
605
606 if (address->flags & ~0xff) {
607 r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags);
608 if (r < 0)
609 return log_error_errno(r, "Could not set extended flags: %m");
610 }
611
612 r = sd_rtnl_message_addr_set_scope(req, address->scope);
613 if (r < 0)
614 return log_error_errno(r, "Could not set scope: %m");
615
616 if (address->family == AF_INET)
617 r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
618 else if (address->family == AF_INET6)
619 r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
620 if (r < 0)
621 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
622
623 if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
624 if (address->family == AF_INET)
625 r = sd_netlink_message_append_in_addr(req, IFA_ADDRESS, &address->in_addr_peer.in);
626 else if (address->family == AF_INET6)
627 r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6);
628 if (r < 0)
629 return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
630 } else {
631 if (address->family == AF_INET) {
632 r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
633 if (r < 0)
634 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
635 }
636 }
637
638 if (address->label) {
639 r = sd_netlink_message_append_string(req, IFA_LABEL, address->label);
640 if (r < 0)
641 return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
642 }
643
644 r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO,
645 &address->cinfo);
646 if (r < 0)
647 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
648
649 r = address_establish(address, link);
650 if (r < 0)
651 return r;
652
653 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
654 if (r < 0) {
655 address_release(address);
656 return log_error_errno(r, "Could not send rtnetlink message: %m");
657 }
658
659 link_ref(link);
660
661 r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
662 if (r < 0) {
663 address_release(address);
664 return log_error_errno(r, "Could not add address: %m");
665 }
666
667 return 0;
668 }
669
670 int config_parse_broadcast(
671 const char *unit,
672 const char *filename,
673 unsigned line,
674 const char *section,
675 unsigned section_line,
676 const char *lvalue,
677 int ltype,
678 const char *rvalue,
679 void *data,
680 void *userdata) {
681
682 Network *network = userdata;
683 _cleanup_address_free_ Address *n = NULL;
684 int r;
685
686 assert(filename);
687 assert(section);
688 assert(lvalue);
689 assert(rvalue);
690 assert(data);
691
692 r = address_new_static(network, filename, section_line, &n);
693 if (r < 0)
694 return r;
695
696 if (n->family == AF_INET6) {
697 log_syntax(unit, LOG_ERR, filename, line, 0, "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
698 return 0;
699 }
700
701 r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
702 if (r < 0) {
703 log_syntax(unit, LOG_ERR, filename, line, r, "Broadcast is invalid, ignoring assignment: %s", rvalue);
704 return 0;
705 }
706
707 n->family = AF_INET;
708 n = NULL;
709
710 return 0;
711 }
712
713 int config_parse_address(const char *unit,
714 const char *filename,
715 unsigned line,
716 const char *section,
717 unsigned section_line,
718 const char *lvalue,
719 int ltype,
720 const char *rvalue,
721 void *data,
722 void *userdata) {
723
724 Network *network = userdata;
725 _cleanup_address_free_ Address *n = NULL;
726 const char *address, *e;
727 union in_addr_union buffer;
728 int r, f;
729
730 assert(filename);
731 assert(section);
732 assert(lvalue);
733 assert(rvalue);
734 assert(data);
735
736 if (streq(section, "Network")) {
737 /* we are not in an Address section, so treat
738 * this as the special '0' section */
739 r = address_new_static(network, NULL, 0, &n);
740 } else
741 r = address_new_static(network, filename, section_line, &n);
742
743 if (r < 0)
744 return r;
745
746 /* Address=address/prefixlen */
747
748 /* prefixlen */
749 e = strchr(rvalue, '/');
750 if (e) {
751 unsigned i;
752
753 r = safe_atou(e + 1, &i);
754 if (r < 0) {
755 log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is invalid, ignoring assignment: %s", e + 1);
756 return 0;
757 }
758
759 n->prefixlen = (unsigned char) i;
760
761 address = strndupa(rvalue, e - rvalue);
762 } else
763 address = rvalue;
764
765 r = in_addr_from_string_auto(address, &f, &buffer);
766 if (r < 0) {
767 log_syntax(unit, LOG_ERR, filename, line, r, "Address is invalid, ignoring assignment: %s", address);
768 return 0;
769 }
770
771 if (!e && f == AF_INET) {
772 r = in4_addr_default_prefixlen(&buffer.in, &n->prefixlen);
773 if (r < 0) {
774 log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length not specified, and a default one can not be deduced for '%s', ignoring assignment", address);
775 return 0;
776 }
777 }
778
779 if (n->family != AF_UNSPEC && f != n->family) {
780 log_syntax(unit, LOG_ERR, filename, line, 0, "Address is incompatible, ignoring assignment: %s", address);
781 return 0;
782 }
783
784 n->family = f;
785
786 if (streq(lvalue, "Address"))
787 n->in_addr = buffer;
788 else
789 n->in_addr_peer = buffer;
790
791 if (n->family == AF_INET && n->broadcast.s_addr == 0)
792 n->broadcast.s_addr = n->in_addr.in.s_addr | htonl(0xfffffffflu >> n->prefixlen);
793
794 n = NULL;
795
796 return 0;
797 }
798
799 int config_parse_label(
800 const char *unit,
801 const char *filename,
802 unsigned line,
803 const char *section,
804 unsigned section_line,
805 const char *lvalue,
806 int ltype,
807 const char *rvalue,
808 void *data,
809 void *userdata) {
810
811 _cleanup_address_free_ Address *n = NULL;
812 Network *network = userdata;
813 int r;
814
815 assert(filename);
816 assert(section);
817 assert(lvalue);
818 assert(rvalue);
819 assert(data);
820
821 r = address_new_static(network, filename, section_line, &n);
822 if (r < 0)
823 return r;
824
825 if (!address_label_valid(rvalue)) {
826 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is too long or invalid, ignoring assignment: %s", rvalue);
827 return 0;
828 }
829
830 r = free_and_strdup(&n->label, rvalue);
831 if (r < 0)
832 return log_oom();
833
834 n = NULL;
835
836 return 0;
837 }
838
839 int config_parse_lifetime(const char *unit,
840 const char *filename,
841 unsigned line,
842 const char *section,
843 unsigned section_line,
844 const char *lvalue,
845 int ltype,
846 const char *rvalue,
847 void *data,
848 void *userdata) {
849 Network *network = userdata;
850 _cleanup_address_free_ Address *n = NULL;
851 unsigned k;
852 int r;
853
854 assert(filename);
855 assert(section);
856 assert(lvalue);
857 assert(rvalue);
858 assert(data);
859
860 r = address_new_static(network, filename, section_line, &n);
861 if (r < 0)
862 return r;
863
864 if (STR_IN_SET(rvalue, "forever", "infinity")) {
865 n->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
866 n = NULL;
867
868 return 0;
869 }
870
871 r = safe_atou(rvalue, &k);
872 if (r < 0) {
873 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse PreferredLifetime, ignoring: %s", rvalue);
874 return 0;
875 }
876
877 if (k != 0)
878 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid PreferredLifetime value, ignoring: %d", k);
879 else {
880 n->cinfo.ifa_prefered = k;
881 n = NULL;
882 }
883
884 return 0;
885 }
886
887 int config_parse_address_flags(const char *unit,
888 const char *filename,
889 unsigned line,
890 const char *section,
891 unsigned section_line,
892 const char *lvalue,
893 int ltype,
894 const char *rvalue,
895 void *data,
896 void *userdata) {
897 Network *network = userdata;
898 _cleanup_address_free_ Address *n = NULL;
899 int r;
900
901 assert(filename);
902 assert(section);
903 assert(lvalue);
904 assert(rvalue);
905 assert(data);
906
907 r = address_new_static(network, filename, section_line, &n);
908 if (r < 0)
909 return r;
910
911 r = parse_boolean(rvalue);
912 if (r < 0) {
913 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address flag, ignoring: %s", rvalue);
914 return 0;
915 }
916
917 if (streq(lvalue, "HomeAddress"))
918 n->home_address = r;
919 else if (streq(lvalue, "DuplicateAddressDetection"))
920 n->duplicate_address_detection = r;
921 else if (streq(lvalue, "ManageTemporaryAddress"))
922 n->manage_temporary_address = r;
923 else if (streq(lvalue, "PrefixRoute"))
924 n->prefix_route = r;
925 else if (streq(lvalue, "AutoJoin"))
926 n->autojoin = r;
927
928 return 0;
929 }
930
931 int config_parse_address_scope(const char *unit,
932 const char *filename,
933 unsigned line,
934 const char *section,
935 unsigned section_line,
936 const char *lvalue,
937 int ltype,
938 const char *rvalue,
939 void *data,
940 void *userdata) {
941 Network *network = userdata;
942 _cleanup_address_free_ Address *n = NULL;
943 int r;
944
945 assert(filename);
946 assert(section);
947 assert(lvalue);
948 assert(rvalue);
949 assert(data);
950
951 r = address_new_static(network, filename, section_line, &n);
952 if (r < 0)
953 return r;
954
955 if (streq(rvalue, "host"))
956 n->scope = RT_SCOPE_HOST;
957 else if (streq(rvalue, "link"))
958 n->scope = RT_SCOPE_LINK;
959 else if (streq(rvalue, "global"))
960 n->scope = RT_SCOPE_UNIVERSE;
961 else {
962 r = safe_atou8(rvalue , &n->scope);
963 if (r < 0) {
964 log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse address scope \"%s\", ignoring assignment: %m", rvalue);
965 return 0;
966 }
967 }
968
969 n = NULL;
970
971 return 0;
972 }
973
974 bool address_is_ready(const Address *a) {
975 assert(a);
976
977 return !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED));
978 }
979
980 int config_parse_router_preference(const char *unit,
981 const char *filename,
982 unsigned line,
983 const char *section,
984 unsigned section_line,
985 const char *lvalue,
986 int ltype,
987 const char *rvalue,
988 void *data,
989 void *userdata) {
990 Network *network = userdata;
991
992 assert(filename);
993 assert(section);
994 assert(lvalue);
995 assert(rvalue);
996 assert(data);
997
998 if (streq(rvalue, "high"))
999 network->router_preference = SD_NDISC_PREFERENCE_HIGH;
1000 else if (STR_IN_SET(rvalue, "medium", "normal", "default"))
1001 network->router_preference = SD_NDISC_PREFERENCE_MEDIUM;
1002 else if (streq(rvalue, "low"))
1003 network->router_preference = SD_NDISC_PREFERENCE_LOW;
1004 else
1005 log_syntax(unit, LOG_ERR, filename, line, -EINVAL, "Router preference '%s' is invalid, ignoring assignment: %m", rvalue);
1006
1007 return 0;
1008 }
1009
1010 void prefix_free(Prefix *prefix) {
1011 if (!prefix)
1012 return;
1013
1014 if (prefix->network) {
1015 LIST_REMOVE(prefixes, prefix->network->static_prefixes, prefix);
1016 assert(prefix->network->n_static_prefixes > 0);
1017 prefix->network->n_static_prefixes--;
1018
1019 if (prefix->section)
1020 hashmap_remove(prefix->network->prefixes_by_section,
1021 prefix->section);
1022 }
1023
1024 prefix->radv_prefix = sd_radv_prefix_unref(prefix->radv_prefix);
1025
1026 free(prefix);
1027 }
1028
1029 int prefix_new(Prefix **ret) {
1030 Prefix *prefix = NULL;
1031
1032 prefix = new0(Prefix, 1);
1033 if (!prefix)
1034 return -ENOMEM;
1035
1036 if (sd_radv_prefix_new(&prefix->radv_prefix) < 0)
1037 return -ENOMEM;
1038
1039 *ret = prefix;
1040 prefix = NULL;
1041
1042 return 0;
1043 }
1044
1045 int prefix_new_static(Network *network, const char *filename,
1046 unsigned section_line, Prefix **ret) {
1047 _cleanup_network_config_section_free_ NetworkConfigSection *n = NULL;
1048 _cleanup_prefix_free_ Prefix *prefix = NULL;
1049 int r;
1050
1051 assert(network);
1052 assert(ret);
1053 assert(!!filename == (section_line > 0));
1054
1055 if (filename) {
1056 r = network_config_section_new(filename, section_line, &n);
1057 if (r < 0)
1058 return r;
1059
1060 if (section_line) {
1061 prefix = hashmap_get(network->prefixes_by_section, n);
1062 if (prefix) {
1063 *ret = prefix;
1064 prefix = NULL;
1065
1066 return 0;
1067 }
1068 }
1069 }
1070
1071 r = prefix_new(&prefix);
1072 if (r < 0)
1073 return r;
1074
1075 if (filename) {
1076 prefix->section = n;
1077 n = NULL;
1078
1079 r = hashmap_put(network->prefixes_by_section, prefix->section,
1080 prefix);
1081 if (r < 0)
1082 return r;
1083 }
1084
1085 prefix->network = network;
1086 LIST_APPEND(prefixes, network->static_prefixes, prefix);
1087 network->n_static_prefixes++;
1088
1089 *ret = prefix;
1090 prefix = NULL;
1091
1092 return 0;
1093 }
1094
1095 int config_parse_prefix(const char *unit,
1096 const char *filename,
1097 unsigned line,
1098 const char *section,
1099 unsigned section_line,
1100 const char *lvalue,
1101 int ltype,
1102 const char *rvalue,
1103 void *data,
1104 void *userdata) {
1105
1106 Network *network = userdata;
1107 _cleanup_prefix_free_ Prefix *p = NULL;
1108 uint8_t prefixlen = 64;
1109 union in_addr_union in6addr;
1110 int r;
1111
1112 assert(filename);
1113 assert(section);
1114 assert(lvalue);
1115 assert(rvalue);
1116 assert(data);
1117
1118 r = prefix_new_static(network, filename, section_line, &p);
1119 if (r < 0)
1120 return r;
1121
1122 r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen);
1123 if (r < 0) {
1124 log_syntax(unit, LOG_ERR, filename, line, r, "Prefix is invalid, ignoring assignment: %s", rvalue);
1125 return 0;
1126 }
1127
1128 if (sd_radv_prefix_set_prefix(p->radv_prefix, &in6addr.in6, prefixlen) < 0)
1129 return -EADDRNOTAVAIL;
1130
1131 log_syntax(unit, LOG_INFO, filename, line, r, "Found prefix %s", rvalue);
1132
1133 p = NULL;
1134
1135 return 0;
1136 }
1137
1138 int config_parse_prefix_flags(const char *unit,
1139 const char *filename,
1140 unsigned line,
1141 const char *section,
1142 unsigned section_line,
1143 const char *lvalue,
1144 int ltype,
1145 const char *rvalue,
1146 void *data,
1147 void *userdata) {
1148 Network *network = userdata;
1149 _cleanup_prefix_free_ Prefix *p = NULL;
1150 int r, val;
1151
1152 assert(filename);
1153 assert(section);
1154 assert(lvalue);
1155 assert(rvalue);
1156 assert(data);
1157
1158 r = prefix_new_static(network, filename, section_line, &p);
1159 if (r < 0)
1160 return r;
1161
1162 r = parse_boolean(rvalue);
1163 if (r < 0) {
1164 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address flag, ignoring: %s", rvalue);
1165 return 0;
1166 }
1167
1168 val = r;
1169
1170 if (streq(lvalue, "OnLink"))
1171 r = sd_radv_prefix_set_onlink(p->radv_prefix, val);
1172 else if (streq(lvalue, "AddressAutoconfiguration"))
1173 r = sd_radv_prefix_set_address_autoconfiguration(p->radv_prefix, val);
1174 if (r < 0)
1175 return r;
1176
1177 p = NULL;
1178
1179 return 0;
1180 }
1181
1182 int config_parse_prefix_lifetime(const char *unit,
1183 const char *filename,
1184 unsigned line,
1185 const char *section,
1186 unsigned section_line,
1187 const char *lvalue,
1188 int ltype,
1189 const char *rvalue,
1190 void *data,
1191 void *userdata) {
1192 Network *network = userdata;
1193 _cleanup_prefix_free_ Prefix *p = NULL;
1194 usec_t usec;
1195 int r;
1196
1197 assert(filename);
1198 assert(section);
1199 assert(lvalue);
1200 assert(rvalue);
1201 assert(data);
1202
1203 r = prefix_new_static(network, filename, section_line, &p);
1204 if (r < 0)
1205 return r;
1206
1207 r = parse_sec(rvalue, &usec);
1208 if (r < 0) {
1209 log_syntax(unit, LOG_ERR, filename, line, r, "Lifetime is invalid, ignoring assignment: %s", rvalue);
1210 return 0;
1211 }
1212
1213 /* a value of 0xffffffff represents infinity */
1214 if (streq(lvalue, "PreferredLifetimeSec"))
1215 r = sd_radv_prefix_set_preferred_lifetime(p->radv_prefix,
1216 DIV_ROUND_UP(usec, USEC_PER_SEC));
1217 else if (streq(lvalue, "ValidLifetimeSec"))
1218 r = sd_radv_prefix_set_valid_lifetime(p->radv_prefix,
1219 DIV_ROUND_UP(usec, USEC_PER_SEC));
1220 if (r < 0)
1221 return r;
1222
1223 p = NULL;
1224
1225 return 0;
1226 }