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