]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-address.c
Merge pull request #6910 from ssahani/issue-6359
[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 if (original->prefixlen > 30)
518 broadcast.s_addr = 0;
519 else
520 broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
521 } else if (original->family == AF_INET6)
522 in_addr.in6.s6_addr[15] |= 1;
523
524 r = address_new(&na);
525 if (r < 0)
526 return r;
527
528 na->family = original->family;
529 na->prefixlen = original->prefixlen;
530 na->scope = original->scope;
531 na->cinfo = original->cinfo;
532
533 if (original->label) {
534 na->label = strdup(original->label);
535 if (!na->label)
536 return -ENOMEM;
537 }
538
539 na->broadcast = broadcast;
540 na->in_addr = in_addr;
541
542 LIST_PREPEND(addresses, link->pool_addresses, na);
543
544 *ret = na;
545 na = NULL;
546
547 return 0;
548 }
549
550 int address_configure(
551 Address *address,
552 Link *link,
553 sd_netlink_message_handler_t callback,
554 bool update) {
555
556 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
557 int r;
558
559 assert(address);
560 assert(IN_SET(address->family, AF_INET, AF_INET6));
561 assert(link);
562 assert(link->ifindex > 0);
563 assert(link->manager);
564 assert(link->manager->rtnl);
565
566 /* If this is a new address, then refuse adding more than the limit */
567 if (address_get(link, address->family, &address->in_addr, address->prefixlen, NULL) <= 0 &&
568 set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
569 return -E2BIG;
570
571 r = address_acquire(link, address, &address);
572 if (r < 0)
573 return r;
574
575 if (update)
576 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
577 link->ifindex, address->family);
578 else
579 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
580 link->ifindex, address->family);
581 if (r < 0)
582 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
583
584 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
585 if (r < 0)
586 return log_error_errno(r, "Could not set prefixlen: %m");
587
588 address->flags |= IFA_F_PERMANENT;
589
590 if (address->home_address)
591 address->flags |= IFA_F_HOMEADDRESS;
592
593 if (address->duplicate_address_detection)
594 address->flags |= IFA_F_NODAD;
595
596 if (address->manage_temporary_address)
597 address->flags |= IFA_F_MANAGETEMPADDR;
598
599 if (address->prefix_route)
600 address->flags |= IFA_F_NOPREFIXROUTE;
601
602 if (address->autojoin)
603 address->flags |= IFA_F_MCAUTOJOIN;
604
605 r = sd_rtnl_message_addr_set_flags(req, (address->flags & 0xff));
606 if (r < 0)
607 return log_error_errno(r, "Could not set flags: %m");
608
609 if (address->flags & ~0xff) {
610 r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags);
611 if (r < 0)
612 return log_error_errno(r, "Could not set extended flags: %m");
613 }
614
615 r = sd_rtnl_message_addr_set_scope(req, address->scope);
616 if (r < 0)
617 return log_error_errno(r, "Could not set scope: %m");
618
619 if (address->family == AF_INET)
620 r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
621 else if (address->family == AF_INET6)
622 r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
623 if (r < 0)
624 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
625
626 if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
627 if (address->family == AF_INET)
628 r = sd_netlink_message_append_in_addr(req, IFA_ADDRESS, &address->in_addr_peer.in);
629 else if (address->family == AF_INET6)
630 r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6);
631 if (r < 0)
632 return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
633 } else {
634 if (address->family == AF_INET) {
635 if (address->prefixlen <= 30) {
636 r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
637 if (r < 0)
638 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
639 }
640 }
641 }
642
643 if (address->label) {
644 r = sd_netlink_message_append_string(req, IFA_LABEL, address->label);
645 if (r < 0)
646 return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
647 }
648
649 r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO,
650 &address->cinfo);
651 if (r < 0)
652 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
653
654 r = address_establish(address, link);
655 if (r < 0)
656 return r;
657
658 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
659 if (r < 0) {
660 address_release(address);
661 return log_error_errno(r, "Could not send rtnetlink message: %m");
662 }
663
664 link_ref(link);
665
666 r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
667 if (r < 0) {
668 address_release(address);
669 return log_error_errno(r, "Could not add address: %m");
670 }
671
672 return 0;
673 }
674
675 int config_parse_broadcast(
676 const char *unit,
677 const char *filename,
678 unsigned line,
679 const char *section,
680 unsigned section_line,
681 const char *lvalue,
682 int ltype,
683 const char *rvalue,
684 void *data,
685 void *userdata) {
686
687 Network *network = userdata;
688 _cleanup_address_free_ Address *n = NULL;
689 int r;
690
691 assert(filename);
692 assert(section);
693 assert(lvalue);
694 assert(rvalue);
695 assert(data);
696
697 r = address_new_static(network, filename, section_line, &n);
698 if (r < 0)
699 return r;
700
701 if (n->family == AF_INET6) {
702 log_syntax(unit, LOG_ERR, filename, line, 0, "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
703 return 0;
704 }
705
706 r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
707 if (r < 0) {
708 log_syntax(unit, LOG_ERR, filename, line, r, "Broadcast is invalid, ignoring assignment: %s", rvalue);
709 return 0;
710 }
711
712 n->family = AF_INET;
713 n = NULL;
714
715 return 0;
716 }
717
718 int config_parse_address(const char *unit,
719 const char *filename,
720 unsigned line,
721 const char *section,
722 unsigned section_line,
723 const char *lvalue,
724 int ltype,
725 const char *rvalue,
726 void *data,
727 void *userdata) {
728
729 Network *network = userdata;
730 _cleanup_address_free_ Address *n = NULL;
731 const char *address, *e;
732 union in_addr_union buffer;
733 int r, f;
734
735 assert(filename);
736 assert(section);
737 assert(lvalue);
738 assert(rvalue);
739 assert(data);
740
741 if (streq(section, "Network")) {
742 /* we are not in an Address section, so treat
743 * this as the special '0' section */
744 r = address_new_static(network, NULL, 0, &n);
745 } else
746 r = address_new_static(network, filename, section_line, &n);
747
748 if (r < 0)
749 return r;
750
751 /* Address=address/prefixlen */
752
753 /* prefixlen */
754 e = strchr(rvalue, '/');
755 if (e) {
756 unsigned i;
757
758 r = safe_atou(e + 1, &i);
759 if (r < 0) {
760 log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is invalid, ignoring assignment: %s", e + 1);
761 return 0;
762 }
763
764 n->prefixlen = (unsigned char) i;
765
766 address = strndupa(rvalue, e - rvalue);
767 } else
768 address = rvalue;
769
770 r = in_addr_from_string_auto(address, &f, &buffer);
771 if (r < 0) {
772 log_syntax(unit, LOG_ERR, filename, line, r, "Address is invalid, ignoring assignment: %s", address);
773 return 0;
774 }
775
776 if (!e && f == AF_INET) {
777 r = in4_addr_default_prefixlen(&buffer.in, &n->prefixlen);
778 if (r < 0) {
779 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);
780 return 0;
781 }
782 }
783
784 if (n->family != AF_UNSPEC && f != n->family) {
785 log_syntax(unit, LOG_ERR, filename, line, 0, "Address is incompatible, ignoring assignment: %s", address);
786 return 0;
787 }
788
789 n->family = f;
790
791 if (streq(lvalue, "Address"))
792 n->in_addr = buffer;
793 else
794 n->in_addr_peer = buffer;
795
796 if (n->family == AF_INET && n->broadcast.s_addr == 0)
797 n->broadcast.s_addr = n->in_addr.in.s_addr | htonl(0xfffffffflu >> n->prefixlen);
798
799 n = NULL;
800
801 return 0;
802 }
803
804 int config_parse_label(
805 const char *unit,
806 const char *filename,
807 unsigned line,
808 const char *section,
809 unsigned section_line,
810 const char *lvalue,
811 int ltype,
812 const char *rvalue,
813 void *data,
814 void *userdata) {
815
816 _cleanup_address_free_ Address *n = NULL;
817 Network *network = userdata;
818 int r;
819
820 assert(filename);
821 assert(section);
822 assert(lvalue);
823 assert(rvalue);
824 assert(data);
825
826 r = address_new_static(network, filename, section_line, &n);
827 if (r < 0)
828 return r;
829
830 if (!address_label_valid(rvalue)) {
831 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is too long or invalid, ignoring assignment: %s", rvalue);
832 return 0;
833 }
834
835 r = free_and_strdup(&n->label, rvalue);
836 if (r < 0)
837 return log_oom();
838
839 n = NULL;
840
841 return 0;
842 }
843
844 int config_parse_lifetime(const char *unit,
845 const char *filename,
846 unsigned line,
847 const char *section,
848 unsigned section_line,
849 const char *lvalue,
850 int ltype,
851 const char *rvalue,
852 void *data,
853 void *userdata) {
854 Network *network = userdata;
855 _cleanup_address_free_ Address *n = NULL;
856 unsigned k;
857 int r;
858
859 assert(filename);
860 assert(section);
861 assert(lvalue);
862 assert(rvalue);
863 assert(data);
864
865 r = address_new_static(network, filename, section_line, &n);
866 if (r < 0)
867 return r;
868
869 if (STR_IN_SET(rvalue, "forever", "infinity")) {
870 n->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
871 n = NULL;
872
873 return 0;
874 }
875
876 r = safe_atou(rvalue, &k);
877 if (r < 0) {
878 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse PreferredLifetime, ignoring: %s", rvalue);
879 return 0;
880 }
881
882 if (k != 0)
883 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid PreferredLifetime value, ignoring: %d", k);
884 else {
885 n->cinfo.ifa_prefered = k;
886 n = NULL;
887 }
888
889 return 0;
890 }
891
892 int config_parse_address_flags(const char *unit,
893 const char *filename,
894 unsigned line,
895 const char *section,
896 unsigned section_line,
897 const char *lvalue,
898 int ltype,
899 const char *rvalue,
900 void *data,
901 void *userdata) {
902 Network *network = userdata;
903 _cleanup_address_free_ Address *n = NULL;
904 int r;
905
906 assert(filename);
907 assert(section);
908 assert(lvalue);
909 assert(rvalue);
910 assert(data);
911
912 r = address_new_static(network, filename, section_line, &n);
913 if (r < 0)
914 return r;
915
916 r = parse_boolean(rvalue);
917 if (r < 0) {
918 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address flag, ignoring: %s", rvalue);
919 return 0;
920 }
921
922 if (streq(lvalue, "HomeAddress"))
923 n->home_address = r;
924 else if (streq(lvalue, "DuplicateAddressDetection"))
925 n->duplicate_address_detection = r;
926 else if (streq(lvalue, "ManageTemporaryAddress"))
927 n->manage_temporary_address = r;
928 else if (streq(lvalue, "PrefixRoute"))
929 n->prefix_route = r;
930 else if (streq(lvalue, "AutoJoin"))
931 n->autojoin = r;
932
933 return 0;
934 }
935
936 int config_parse_address_scope(const char *unit,
937 const char *filename,
938 unsigned line,
939 const char *section,
940 unsigned section_line,
941 const char *lvalue,
942 int ltype,
943 const char *rvalue,
944 void *data,
945 void *userdata) {
946 Network *network = userdata;
947 _cleanup_address_free_ Address *n = NULL;
948 int r;
949
950 assert(filename);
951 assert(section);
952 assert(lvalue);
953 assert(rvalue);
954 assert(data);
955
956 r = address_new_static(network, filename, section_line, &n);
957 if (r < 0)
958 return r;
959
960 if (streq(rvalue, "host"))
961 n->scope = RT_SCOPE_HOST;
962 else if (streq(rvalue, "link"))
963 n->scope = RT_SCOPE_LINK;
964 else if (streq(rvalue, "global"))
965 n->scope = RT_SCOPE_UNIVERSE;
966 else {
967 r = safe_atou8(rvalue , &n->scope);
968 if (r < 0) {
969 log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse address scope \"%s\", ignoring assignment: %m", rvalue);
970 return 0;
971 }
972 }
973
974 n = NULL;
975
976 return 0;
977 }
978
979 bool address_is_ready(const Address *a) {
980 assert(a);
981
982 if (a->family == AF_INET6)
983 return !(a->flags & IFA_F_TENTATIVE);
984 else
985 return !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED));
986 }
987
988 int config_parse_router_preference(const char *unit,
989 const char *filename,
990 unsigned line,
991 const char *section,
992 unsigned section_line,
993 const char *lvalue,
994 int ltype,
995 const char *rvalue,
996 void *data,
997 void *userdata) {
998 Network *network = userdata;
999
1000 assert(filename);
1001 assert(section);
1002 assert(lvalue);
1003 assert(rvalue);
1004 assert(data);
1005
1006 if (streq(rvalue, "high"))
1007 network->router_preference = SD_NDISC_PREFERENCE_HIGH;
1008 else if (STR_IN_SET(rvalue, "medium", "normal", "default"))
1009 network->router_preference = SD_NDISC_PREFERENCE_MEDIUM;
1010 else if (streq(rvalue, "low"))
1011 network->router_preference = SD_NDISC_PREFERENCE_LOW;
1012 else
1013 log_syntax(unit, LOG_ERR, filename, line, -EINVAL, "Router preference '%s' is invalid, ignoring assignment: %m", rvalue);
1014
1015 return 0;
1016 }
1017
1018 void prefix_free(Prefix *prefix) {
1019 if (!prefix)
1020 return;
1021
1022 if (prefix->network) {
1023 LIST_REMOVE(prefixes, prefix->network->static_prefixes, prefix);
1024 assert(prefix->network->n_static_prefixes > 0);
1025 prefix->network->n_static_prefixes--;
1026
1027 if (prefix->section)
1028 hashmap_remove(prefix->network->prefixes_by_section,
1029 prefix->section);
1030 }
1031
1032 prefix->radv_prefix = sd_radv_prefix_unref(prefix->radv_prefix);
1033
1034 free(prefix);
1035 }
1036
1037 int prefix_new(Prefix **ret) {
1038 Prefix *prefix = NULL;
1039
1040 prefix = new0(Prefix, 1);
1041 if (!prefix)
1042 return -ENOMEM;
1043
1044 if (sd_radv_prefix_new(&prefix->radv_prefix) < 0)
1045 return -ENOMEM;
1046
1047 *ret = prefix;
1048 prefix = NULL;
1049
1050 return 0;
1051 }
1052
1053 int prefix_new_static(Network *network, const char *filename,
1054 unsigned section_line, Prefix **ret) {
1055 _cleanup_network_config_section_free_ NetworkConfigSection *n = NULL;
1056 _cleanup_prefix_free_ Prefix *prefix = NULL;
1057 int r;
1058
1059 assert(network);
1060 assert(ret);
1061 assert(!!filename == (section_line > 0));
1062
1063 if (filename) {
1064 r = network_config_section_new(filename, section_line, &n);
1065 if (r < 0)
1066 return r;
1067
1068 if (section_line) {
1069 prefix = hashmap_get(network->prefixes_by_section, n);
1070 if (prefix) {
1071 *ret = prefix;
1072 prefix = NULL;
1073
1074 return 0;
1075 }
1076 }
1077 }
1078
1079 r = prefix_new(&prefix);
1080 if (r < 0)
1081 return r;
1082
1083 if (filename) {
1084 prefix->section = n;
1085 n = NULL;
1086
1087 r = hashmap_put(network->prefixes_by_section, prefix->section,
1088 prefix);
1089 if (r < 0)
1090 return r;
1091 }
1092
1093 prefix->network = network;
1094 LIST_APPEND(prefixes, network->static_prefixes, prefix);
1095 network->n_static_prefixes++;
1096
1097 *ret = prefix;
1098 prefix = NULL;
1099
1100 return 0;
1101 }
1102
1103 int config_parse_prefix(const char *unit,
1104 const char *filename,
1105 unsigned line,
1106 const char *section,
1107 unsigned section_line,
1108 const char *lvalue,
1109 int ltype,
1110 const char *rvalue,
1111 void *data,
1112 void *userdata) {
1113
1114 Network *network = userdata;
1115 _cleanup_prefix_free_ Prefix *p = NULL;
1116 uint8_t prefixlen = 64;
1117 union in_addr_union in6addr;
1118 int r;
1119
1120 assert(filename);
1121 assert(section);
1122 assert(lvalue);
1123 assert(rvalue);
1124 assert(data);
1125
1126 r = prefix_new_static(network, filename, section_line, &p);
1127 if (r < 0)
1128 return r;
1129
1130 r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen);
1131 if (r < 0) {
1132 log_syntax(unit, LOG_ERR, filename, line, r, "Prefix is invalid, ignoring assignment: %s", rvalue);
1133 return 0;
1134 }
1135
1136 if (sd_radv_prefix_set_prefix(p->radv_prefix, &in6addr.in6, prefixlen) < 0)
1137 return -EADDRNOTAVAIL;
1138
1139 log_syntax(unit, LOG_INFO, filename, line, r, "Found prefix %s", rvalue);
1140
1141 p = NULL;
1142
1143 return 0;
1144 }
1145
1146 int config_parse_prefix_flags(const char *unit,
1147 const char *filename,
1148 unsigned line,
1149 const char *section,
1150 unsigned section_line,
1151 const char *lvalue,
1152 int ltype,
1153 const char *rvalue,
1154 void *data,
1155 void *userdata) {
1156 Network *network = userdata;
1157 _cleanup_prefix_free_ Prefix *p = NULL;
1158 int r, val;
1159
1160 assert(filename);
1161 assert(section);
1162 assert(lvalue);
1163 assert(rvalue);
1164 assert(data);
1165
1166 r = prefix_new_static(network, filename, section_line, &p);
1167 if (r < 0)
1168 return r;
1169
1170 r = parse_boolean(rvalue);
1171 if (r < 0) {
1172 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address flag, ignoring: %s", rvalue);
1173 return 0;
1174 }
1175
1176 val = r;
1177
1178 if (streq(lvalue, "OnLink"))
1179 r = sd_radv_prefix_set_onlink(p->radv_prefix, val);
1180 else if (streq(lvalue, "AddressAutoconfiguration"))
1181 r = sd_radv_prefix_set_address_autoconfiguration(p->radv_prefix, val);
1182 if (r < 0)
1183 return r;
1184
1185 p = NULL;
1186
1187 return 0;
1188 }
1189
1190 int config_parse_prefix_lifetime(const char *unit,
1191 const char *filename,
1192 unsigned line,
1193 const char *section,
1194 unsigned section_line,
1195 const char *lvalue,
1196 int ltype,
1197 const char *rvalue,
1198 void *data,
1199 void *userdata) {
1200 Network *network = userdata;
1201 _cleanup_prefix_free_ Prefix *p = NULL;
1202 usec_t usec;
1203 int r;
1204
1205 assert(filename);
1206 assert(section);
1207 assert(lvalue);
1208 assert(rvalue);
1209 assert(data);
1210
1211 r = prefix_new_static(network, filename, section_line, &p);
1212 if (r < 0)
1213 return r;
1214
1215 r = parse_sec(rvalue, &usec);
1216 if (r < 0) {
1217 log_syntax(unit, LOG_ERR, filename, line, r, "Lifetime is invalid, ignoring assignment: %s", rvalue);
1218 return 0;
1219 }
1220
1221 /* a value of 0xffffffff represents infinity */
1222 if (streq(lvalue, "PreferredLifetimeSec"))
1223 r = sd_radv_prefix_set_preferred_lifetime(p->radv_prefix,
1224 DIV_ROUND_UP(usec, USEC_PER_SEC));
1225 else if (streq(lvalue, "ValidLifetimeSec"))
1226 r = sd_radv_prefix_set_valid_lifetime(p->radv_prefix,
1227 DIV_ROUND_UP(usec, USEC_PER_SEC));
1228 if (r < 0)
1229 return r;
1230
1231 p = NULL;
1232
1233 return 0;
1234 }