]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-address.c
networkd: Do not set config to NULL immediately.
[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 hashmap_put(network->addresses_by_section, address->section, address);
91 }
92
93 address->network = network;
94 LIST_APPEND(addresses, network->static_addresses, address);
95 network->n_static_addresses++;
96
97 *ret = address;
98 address = NULL;
99
100 return 0;
101 }
102
103 void address_free(Address *address) {
104 if (!address)
105 return;
106
107 if (address->network) {
108 LIST_REMOVE(addresses, address->network->static_addresses, address);
109 assert(address->network->n_static_addresses > 0);
110 address->network->n_static_addresses--;
111
112 if (address->section) {
113 hashmap_remove(address->network->addresses_by_section, address->section);
114 network_config_section_free(address->section);
115 }
116 }
117
118 if (address->link) {
119 set_remove(address->link->addresses, address);
120 set_remove(address->link->addresses_foreign, address);
121
122 if (in_addr_equal(AF_INET6, &address->in_addr, (const union in_addr_union *) &address->link->ipv6ll_address))
123 memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr));
124 }
125
126 free(address);
127 }
128
129 static void address_hash_func(const void *b, struct siphash *state) {
130 const Address *a = b;
131
132 assert(a);
133
134 siphash24_compress(&a->family, sizeof(a->family), state);
135
136 switch (a->family) {
137 case AF_INET:
138 siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
139
140 /* peer prefix */
141 if (a->prefixlen != 0) {
142 uint32_t prefix;
143
144 if (a->in_addr_peer.in.s_addr != 0)
145 prefix = be32toh(a->in_addr_peer.in.s_addr) >> (32 - a->prefixlen);
146 else
147 prefix = be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
148
149 siphash24_compress(&prefix, sizeof(prefix), state);
150 }
151
152 /* fallthrough */
153 case AF_INET6:
154 /* local address */
155 siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
156
157 break;
158 default:
159 /* treat any other address family as AF_UNSPEC */
160 break;
161 }
162 }
163
164 static int address_compare_func(const void *c1, const void *c2) {
165 const Address *a1 = c1, *a2 = c2;
166
167 if (a1->family < a2->family)
168 return -1;
169 if (a1->family > a2->family)
170 return 1;
171
172 switch (a1->family) {
173 /* use the same notion of equality as the kernel does */
174 case AF_INET:
175 if (a1->prefixlen < a2->prefixlen)
176 return -1;
177 if (a1->prefixlen > a2->prefixlen)
178 return 1;
179
180 /* compare the peer prefixes */
181 if (a1->prefixlen != 0) {
182 /* make sure we don't try to shift by 32.
183 * See ISO/IEC 9899:TC3 ยง 6.5.7.3. */
184 uint32_t b1, b2;
185
186 if (a1->in_addr_peer.in.s_addr != 0)
187 b1 = be32toh(a1->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
188 else
189 b1 = be32toh(a1->in_addr.in.s_addr) >> (32 - a1->prefixlen);
190
191 if (a2->in_addr_peer.in.s_addr != 0)
192 b2 = be32toh(a2->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
193 else
194 b2 = be32toh(a2->in_addr.in.s_addr) >> (32 - a1->prefixlen);
195
196 if (b1 < b2)
197 return -1;
198 if (b1 > b2)
199 return 1;
200 }
201
202 /* fall-through */
203 case AF_INET6:
204 return memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
205 default:
206 /* treat any other address family as AF_UNSPEC */
207 return 0;
208 }
209 }
210
211 static const struct hash_ops address_hash_ops = {
212 .hash = address_hash_func,
213 .compare = address_compare_func
214 };
215
216 bool address_equal(Address *a1, Address *a2) {
217 if (a1 == a2)
218 return true;
219
220 if (!a1 || !a2)
221 return false;
222
223 return address_compare_func(a1, a2) == 0;
224 }
225
226 static int address_establish(Address *address, Link *link) {
227 bool masq;
228 int r;
229
230 assert(address);
231 assert(link);
232
233 masq = link->network &&
234 link->network->ip_masquerade &&
235 address->family == AF_INET &&
236 address->scope < RT_SCOPE_LINK;
237
238 /* Add firewall entry if this is requested */
239 if (address->ip_masquerade_done != masq) {
240 union in_addr_union masked = address->in_addr;
241 in_addr_mask(address->family, &masked, address->prefixlen);
242
243 r = fw_add_masquerade(masq, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
244 if (r < 0)
245 log_link_warning_errno(link, r, "Could not enable IP masquerading: %m");
246
247 address->ip_masquerade_done = masq;
248 }
249
250 return 0;
251 }
252
253 static int address_add_internal(Link *link, Set **addresses,
254 int family,
255 const union in_addr_union *in_addr,
256 unsigned char prefixlen,
257 Address **ret) {
258 _cleanup_address_free_ Address *address = NULL;
259 int r;
260
261 assert(link);
262 assert(addresses);
263 assert(in_addr);
264
265 r = address_new(&address);
266 if (r < 0)
267 return r;
268
269 address->family = family;
270 address->in_addr = *in_addr;
271 address->prefixlen = prefixlen;
272 /* Consider address tentative until we get the real flags from the kernel */
273 address->flags = IFA_F_TENTATIVE;
274
275 r = set_ensure_allocated(addresses, &address_hash_ops);
276 if (r < 0)
277 return r;
278
279 r = set_put(*addresses, address);
280 if (r < 0)
281 return r;
282
283 address->link = link;
284
285 if (ret)
286 *ret = address;
287
288 address = NULL;
289
290 return 0;
291 }
292
293 int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
294 return address_add_internal(link, &link->addresses_foreign, family, in_addr, prefixlen, ret);
295 }
296
297 int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
298 Address *address;
299 int r;
300
301 r = address_get(link, family, in_addr, prefixlen, &address);
302 if (r == -ENOENT) {
303 /* Address does not exist, create a new one */
304 r = address_add_internal(link, &link->addresses, family, in_addr, prefixlen, &address);
305 if (r < 0)
306 return r;
307 } else if (r == 0) {
308 /* Take over a foreign address */
309 r = set_ensure_allocated(&link->addresses, &address_hash_ops);
310 if (r < 0)
311 return r;
312
313 r = set_put(link->addresses, address);
314 if (r < 0)
315 return r;
316
317 set_remove(link->addresses_foreign, address);
318 } else if (r == 1) {
319 /* Already exists, do nothing */
320 ;
321 } else
322 return r;
323
324 if (ret)
325 *ret = address;
326
327 return 0;
328 }
329
330 static int address_release(Address *address) {
331 int r;
332
333 assert(address);
334 assert(address->link);
335
336 /* Remove masquerading firewall entry if it was added */
337 if (address->ip_masquerade_done) {
338 union in_addr_union masked = address->in_addr;
339 in_addr_mask(address->family, &masked, address->prefixlen);
340
341 r = fw_add_masquerade(false, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
342 if (r < 0)
343 log_link_warning_errno(address->link, r, "Failed to disable IP masquerading: %m");
344
345 address->ip_masquerade_done = false;
346 }
347
348 return 0;
349 }
350
351 int address_update(
352 Address *address,
353 unsigned char flags,
354 unsigned char scope,
355 const struct ifa_cacheinfo *cinfo) {
356
357 bool ready;
358 int r;
359
360 assert(address);
361 assert(cinfo);
362 assert_return(address->link, 1);
363
364 if (IN_SET(address->link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
365 return 1;
366
367 ready = address_is_ready(address);
368
369 address->flags = flags;
370 address->scope = scope;
371 address->cinfo = *cinfo;
372
373 link_update_operstate(address->link);
374
375 if (!ready && address_is_ready(address)) {
376 link_check_ready(address->link);
377
378 if (address->family == AF_INET6 &&
379 in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 &&
380 in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) {
381
382 r = link_ipv6ll_gained(address->link, &address->in_addr.in6);
383 if (r < 0)
384 return r;
385 }
386 }
387
388 return 0;
389 }
390
391 int address_drop(Address *address) {
392 Link *link;
393 bool ready;
394
395 assert(address);
396
397 ready = address_is_ready(address);
398 link = address->link;
399
400 address_release(address);
401 address_free(address);
402
403 link_update_operstate(link);
404
405 if (link && !ready)
406 link_check_ready(link);
407
408 return 0;
409 }
410
411 int address_get(Link *link,
412 int family,
413 const union in_addr_union *in_addr,
414 unsigned char prefixlen,
415 Address **ret) {
416
417 Address address, *existing;
418
419 assert(link);
420 assert(in_addr);
421
422 address = (Address) {
423 .family = family,
424 .in_addr = *in_addr,
425 .prefixlen = prefixlen,
426 };
427
428 existing = set_get(link->addresses, &address);
429 if (existing) {
430 if (ret)
431 *ret = existing;
432 return 1;
433 }
434
435 existing = set_get(link->addresses_foreign, &address);
436 if (existing) {
437 if (ret)
438 *ret = existing;
439 return 0;
440 }
441
442 return -ENOENT;
443 }
444
445 int address_remove(
446 Address *address,
447 Link *link,
448 sd_netlink_message_handler_t callback) {
449
450 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
451 int r;
452
453 assert(address);
454 assert(address->family == AF_INET || address->family == AF_INET6);
455 assert(link);
456 assert(link->ifindex > 0);
457 assert(link->manager);
458 assert(link->manager->rtnl);
459
460 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
461 link->ifindex, address->family);
462 if (r < 0)
463 return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m");
464
465 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
466 if (r < 0)
467 return log_error_errno(r, "Could not set prefixlen: %m");
468
469 if (address->family == AF_INET)
470 r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
471 else if (address->family == AF_INET6)
472 r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
473 if (r < 0)
474 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
475
476 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
477 if (r < 0)
478 return log_error_errno(r, "Could not send rtnetlink message: %m");
479
480 link_ref(link);
481
482 return 0;
483 }
484
485 static int address_acquire(Link *link, Address *original, Address **ret) {
486 union in_addr_union in_addr = {};
487 struct in_addr broadcast = {};
488 _cleanup_address_free_ Address *na = NULL;
489 int r;
490
491 assert(link);
492 assert(original);
493 assert(ret);
494
495 /* Something useful was configured? just use it */
496 if (in_addr_is_null(original->family, &original->in_addr) <= 0)
497 return 0;
498
499 /* The address is configured to be 0.0.0.0 or [::] by the user?
500 * Then let's acquire something more useful from the pool. */
501 r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
502 if (r < 0)
503 return log_link_error_errno(link, r, "Failed to acquire address from pool: %m");
504 if (r == 0) {
505 log_link_error(link, "Couldn't find free address for interface, all taken.");
506 return -EBUSY;
507 }
508
509 if (original->family == AF_INET) {
510 /* Pick first address in range for ourselves ... */
511 in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
512
513 /* .. and use last as broadcast address */
514 broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
515 } else if (original->family == AF_INET6)
516 in_addr.in6.s6_addr[15] |= 1;
517
518 r = address_new(&na);
519 if (r < 0)
520 return r;
521
522 na->family = original->family;
523 na->prefixlen = original->prefixlen;
524 na->scope = original->scope;
525 na->cinfo = original->cinfo;
526
527 if (original->label) {
528 na->label = strdup(original->label);
529 if (!na->label)
530 return -ENOMEM;
531 }
532
533 na->broadcast = broadcast;
534 na->in_addr = in_addr;
535
536 LIST_PREPEND(addresses, link->pool_addresses, na);
537
538 *ret = na;
539 na = NULL;
540
541 return 0;
542 }
543
544 int address_configure(
545 Address *address,
546 Link *link,
547 sd_netlink_message_handler_t callback,
548 bool update) {
549
550 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
551 int r;
552
553 assert(address);
554 assert(address->family == AF_INET || address->family == AF_INET6);
555 assert(link);
556 assert(link->ifindex > 0);
557 assert(link->manager);
558 assert(link->manager->rtnl);
559
560 /* If this is a new address, then refuse adding more than the limit */
561 if (address_get(link, address->family, &address->in_addr, address->prefixlen, NULL) <= 0 &&
562 set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
563 return -E2BIG;
564
565 r = address_acquire(link, address, &address);
566 if (r < 0)
567 return r;
568
569 if (update)
570 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
571 link->ifindex, address->family);
572 else
573 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
574 link->ifindex, address->family);
575 if (r < 0)
576 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
577
578 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
579 if (r < 0)
580 return log_error_errno(r, "Could not set prefixlen: %m");
581
582 address->flags |= IFA_F_PERMANENT;
583
584 if (address->home_address)
585 address->flags |= IFA_F_HOMEADDRESS;
586
587 if (address->duplicate_address_detection)
588 address->flags |= IFA_F_NODAD;
589
590 if (address->manage_temporary_address)
591 address->flags |= IFA_F_MANAGETEMPADDR;
592
593 if (address->prefix_route)
594 address->flags |= IFA_F_NOPREFIXROUTE;
595
596 if (address->autojoin)
597 address->flags |= IFA_F_MCAUTOJOIN;
598
599 r = sd_rtnl_message_addr_set_flags(req, (address->flags & 0xff));
600 if (r < 0)
601 return log_error_errno(r, "Could not set flags: %m");
602
603 if (address->flags & ~0xff) {
604 r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags);
605 if (r < 0)
606 return log_error_errno(r, "Could not set extended flags: %m");
607 }
608
609 r = sd_rtnl_message_addr_set_scope(req, address->scope);
610 if (r < 0)
611 return log_error_errno(r, "Could not set scope: %m");
612
613 if (address->family == AF_INET)
614 r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
615 else if (address->family == AF_INET6)
616 r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
617 if (r < 0)
618 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
619
620 if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
621 if (address->family == AF_INET)
622 r = sd_netlink_message_append_in_addr(req, IFA_ADDRESS, &address->in_addr_peer.in);
623 else if (address->family == AF_INET6)
624 r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6);
625 if (r < 0)
626 return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
627 } else {
628 if (address->family == AF_INET) {
629 r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
630 if (r < 0)
631 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
632 }
633 }
634
635 if (address->label) {
636 r = sd_netlink_message_append_string(req, IFA_LABEL, address->label);
637 if (r < 0)
638 return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
639 }
640
641 r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO,
642 &address->cinfo);
643 if (r < 0)
644 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
645
646 r = address_establish(address, link);
647 if (r < 0)
648 return r;
649
650 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
651 if (r < 0) {
652 address_release(address);
653 return log_error_errno(r, "Could not send rtnetlink message: %m");
654 }
655
656 link_ref(link);
657
658 r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
659 if (r < 0) {
660 address_release(address);
661 return log_error_errno(r, "Could not add address: %m");
662 }
663
664 return 0;
665 }
666
667 int config_parse_broadcast(
668 const char *unit,
669 const char *filename,
670 unsigned line,
671 const char *section,
672 unsigned section_line,
673 const char *lvalue,
674 int ltype,
675 const char *rvalue,
676 void *data,
677 void *userdata) {
678
679 Network *network = userdata;
680 _cleanup_address_free_ Address *n = NULL;
681 int r;
682
683 assert(filename);
684 assert(section);
685 assert(lvalue);
686 assert(rvalue);
687 assert(data);
688
689 r = address_new_static(network, filename, section_line, &n);
690 if (r < 0)
691 return r;
692
693 if (n->family == AF_INET6) {
694 log_syntax(unit, LOG_ERR, filename, line, 0, "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
695 return 0;
696 }
697
698 r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
699 if (r < 0) {
700 log_syntax(unit, LOG_ERR, filename, line, r, "Broadcast is invalid, ignoring assignment: %s", rvalue);
701 return 0;
702 }
703
704 n->family = AF_INET;
705 n = NULL;
706
707 return 0;
708 }
709
710 int config_parse_address(const char *unit,
711 const char *filename,
712 unsigned line,
713 const char *section,
714 unsigned section_line,
715 const char *lvalue,
716 int ltype,
717 const char *rvalue,
718 void *data,
719 void *userdata) {
720
721 Network *network = userdata;
722 _cleanup_address_free_ Address *n = NULL;
723 const char *address, *e;
724 union in_addr_union buffer;
725 int r, f;
726
727 assert(filename);
728 assert(section);
729 assert(lvalue);
730 assert(rvalue);
731 assert(data);
732
733 if (streq(section, "Network")) {
734 /* we are not in an Address section, so treat
735 * this as the special '0' section */
736 r = address_new_static(network, NULL, 0, &n);
737 } else
738 r = address_new_static(network, filename, section_line, &n);
739
740 if (r < 0)
741 return r;
742
743 /* Address=address/prefixlen */
744
745 /* prefixlen */
746 e = strchr(rvalue, '/');
747 if (e) {
748 unsigned i;
749
750 r = safe_atou(e + 1, &i);
751 if (r < 0) {
752 log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is invalid, ignoring assignment: %s", e + 1);
753 return 0;
754 }
755
756 n->prefixlen = (unsigned char) i;
757
758 address = strndupa(rvalue, e - rvalue);
759 } else
760 address = rvalue;
761
762 r = in_addr_from_string_auto(address, &f, &buffer);
763 if (r < 0) {
764 log_syntax(unit, LOG_ERR, filename, line, r, "Address is invalid, ignoring assignment: %s", address);
765 return 0;
766 }
767
768 if (!e && f == AF_INET) {
769 r = in_addr_default_prefixlen(&buffer.in, &n->prefixlen);
770 if (r < 0) {
771 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);
772 return 0;
773 }
774 }
775
776 if (n->family != AF_UNSPEC && f != n->family) {
777 log_syntax(unit, LOG_ERR, filename, line, 0, "Address is incompatible, ignoring assignment: %s", address);
778 return 0;
779 }
780
781 n->family = f;
782
783 if (streq(lvalue, "Address"))
784 n->in_addr = buffer;
785 else
786 n->in_addr_peer = buffer;
787
788 if (n->family == AF_INET && n->broadcast.s_addr == 0)
789 n->broadcast.s_addr = n->in_addr.in.s_addr | htonl(0xfffffffflu >> n->prefixlen);
790
791 n = NULL;
792
793 return 0;
794 }
795
796 int config_parse_label(
797 const char *unit,
798 const char *filename,
799 unsigned line,
800 const char *section,
801 unsigned section_line,
802 const char *lvalue,
803 int ltype,
804 const char *rvalue,
805 void *data,
806 void *userdata) {
807
808 _cleanup_address_free_ Address *n = NULL;
809 Network *network = userdata;
810 int r;
811
812 assert(filename);
813 assert(section);
814 assert(lvalue);
815 assert(rvalue);
816 assert(data);
817
818 r = address_new_static(network, filename, section_line, &n);
819 if (r < 0)
820 return r;
821
822 if (strlen(rvalue) >= IFNAMSIZ) {
823 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is too long, ignoring assignment: %s", rvalue);
824 return 0;
825 }
826
827 r = free_and_strdup(&n->label, rvalue);
828 if (r < 0)
829 return log_oom();
830
831 n = NULL;
832
833 return 0;
834 }
835
836 int config_parse_lifetime(const char *unit,
837 const char *filename,
838 unsigned line,
839 const char *section,
840 unsigned section_line,
841 const char *lvalue,
842 int ltype,
843 const char *rvalue,
844 void *data,
845 void *userdata) {
846 Network *network = userdata;
847 _cleanup_address_free_ Address *n = NULL;
848 unsigned k;
849 int r;
850
851 assert(filename);
852 assert(section);
853 assert(lvalue);
854 assert(rvalue);
855 assert(data);
856
857 r = address_new_static(network, filename, section_line, &n);
858 if (r < 0)
859 return r;
860
861 if (STR_IN_SET(rvalue, "forever", "infinity")) {
862 n->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
863 n = NULL;
864
865 return 0;
866 }
867
868 r = safe_atou(rvalue, &k);
869 if (r < 0) {
870 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse PreferredLifetime, ignoring: %s", rvalue);
871 return 0;
872 }
873
874 if (k != 0)
875 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid PreferredLifetime value, ignoring: %d", k);
876 else {
877 n->cinfo.ifa_prefered = k;
878 n = NULL;
879 }
880
881 return 0;
882 }
883
884 int config_parse_address_flags(const char *unit,
885 const char *filename,
886 unsigned line,
887 const char *section,
888 unsigned section_line,
889 const char *lvalue,
890 int ltype,
891 const char *rvalue,
892 void *data,
893 void *userdata) {
894 Network *network = userdata;
895 _cleanup_address_free_ Address *n = NULL;
896 int r;
897
898 assert(filename);
899 assert(section);
900 assert(lvalue);
901 assert(rvalue);
902 assert(data);
903
904 r = address_new_static(network, filename, section_line, &n);
905 if (r < 0)
906 return r;
907
908 r = parse_boolean(rvalue);
909 if (r < 0) {
910 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address flag, ignoring: %s", rvalue);
911 return 0;
912 }
913
914 if (streq(lvalue, "HomeAddress"))
915 n->home_address = r;
916 else if (streq(lvalue, "DuplicateAddressDetection"))
917 n->duplicate_address_detection = r;
918 else if (streq(lvalue, "ManageTemporaryAddress"))
919 n->manage_temporary_address = r;
920 else if (streq(lvalue, "PrefixRoute"))
921 n->prefix_route = r;
922 else if (streq(lvalue, "AutoJoin"))
923 n->autojoin = r;
924
925 return 0;
926 }
927
928 bool address_is_ready(const Address *a) {
929 assert(a);
930
931 return !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED));
932 }