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