]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-address.c
network: update address infomation even if link is in failed or linger state
[thirdparty/systemd.git] / src / network / networkd-address.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
f579559b
TG
2
3#include <net/if.h>
4
b5efdb8a 5#include "alloc-util.h"
f579559b 6#include "conf-parser.h"
12c2884c 7#include "firewall-util.h"
0a970718 8#include "memory-util.h"
081aea25 9#include "missing_network.h"
fc2f9534 10#include "netlink-util.h"
6bedfcbb 11#include "networkd-address.h"
23f53b99 12#include "networkd-manager.h"
6bedfcbb 13#include "parse-util.h"
3ac8e543 14#include "set.h"
d31645ad 15#include "socket-util.h"
07630cea 16#include "string-util.h"
51517f9e 17#include "strv.h"
3ac8e543 18#include "utf8.h"
f579559b 19
1b566071 20#define ADDRESSES_PER_LINK_MAX 2048U
8c34b963
LP
21#define STATIC_ADDRESSES_PER_NETWORK_MAX 1024U
22
5ead5352
SS
23int generate_ipv6_eui_64_address(Link *link, struct in6_addr *ret) {
24 assert(link);
25 assert(ret);
26
27 /* see RFC4291 section 2.5.1 */
28 ret->s6_addr[8] = link->mac.ether_addr_octet[0];
29 ret->s6_addr[8] ^= 1 << 1;
30 ret->s6_addr[9] = link->mac.ether_addr_octet[1];
31 ret->s6_addr[10] = link->mac.ether_addr_octet[2];
32 ret->s6_addr[11] = 0xff;
33 ret->s6_addr[12] = 0xfe;
34 ret->s6_addr[13] = link->mac.ether_addr_octet[3];
35 ret->s6_addr[14] = link->mac.ether_addr_octet[4];
36 ret->s6_addr[15] = link->mac.ether_addr_octet[5];
37
38 return 0;
39}
40
f0213e37 41int address_new(Address **ret) {
8e766630 42 _cleanup_(address_freep) Address *address = NULL;
f0213e37 43
17f9c355 44 address = new(Address, 1);
f0213e37
TG
45 if (!address)
46 return -ENOMEM;
aba496a5 47
17f9c355
YW
48 *address = (Address) {
49 .family = AF_UNSPEC,
50 .scope = RT_SCOPE_UNIVERSE,
51 .cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME,
52 .cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME,
051e77ca 53 .duplicate_address_detection = ADDRESS_FAMILY_IPV6,
de697db0 54 .prefix_route = true,
17f9c355 55 };
f0213e37 56
1cc6c93a 57 *ret = TAKE_PTR(address);
f0213e37
TG
58
59 return 0;
aba496a5
UTL
60}
61
9560e5b3 62static int address_new_static(Network *network, const char *filename, unsigned section_line, Address **ret) {
8e766630
LP
63 _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
64 _cleanup_(address_freep) Address *address = NULL;
f0213e37 65 int r;
f579559b 66
8c34b963
LP
67 assert(network);
68 assert(ret);
48317c39 69 assert(!!filename == (section_line > 0));
8c34b963 70
48317c39 71 if (filename) {
f4859fc7
SS
72 r = network_config_section_new(filename, section_line, &n);
73 if (r < 0)
74 return r;
75
76 address = hashmap_get(network->addresses_by_section, n);
6ae115c1 77 if (address) {
1cc6c93a 78 *ret = TAKE_PTR(address);
6ae115c1
TG
79
80 return 0;
81 }
82 }
83
8c34b963
LP
84 if (network->n_static_addresses >= STATIC_ADDRESSES_PER_NETWORK_MAX)
85 return -E2BIG;
86
f0213e37
TG
87 r = address_new(&address);
88 if (r < 0)
89 return r;
801bd9e8 90
0f7f2769
YW
91 address->network = network;
92 LIST_APPEND(addresses, network->static_addresses, address);
93 network->n_static_addresses++;
94
48317c39 95 if (filename) {
1cc6c93a 96 address->section = TAKE_PTR(n);
fcc48287 97
3e570042
YW
98 r = hashmap_ensure_allocated(&network->addresses_by_section, &network_config_hash_ops);
99 if (r < 0)
100 return r;
101
f7fe70ea
SS
102 r = hashmap_put(network->addresses_by_section, address->section, address);
103 if (r < 0)
104 return r;
6ae115c1
TG
105 }
106
1cc6c93a 107 *ret = TAKE_PTR(address);
f579559b
TG
108
109 return 0;
110}
111
112void address_free(Address *address) {
113 if (!address)
114 return;
115
f048a16b 116 if (address->network) {
3d3d4255 117 LIST_REMOVE(addresses, address->network->static_addresses, address);
8c34b963
LP
118 assert(address->network->n_static_addresses > 0);
119 address->network->n_static_addresses--;
f579559b 120
de4224aa 121 if (address->section)
f4859fc7 122 hashmap_remove(address->network->addresses_by_section, address->section);
f048a16b 123 }
6ae115c1 124
051e77ca 125 if (address->link && !address->acd) {
cf1d700d 126 set_remove(address->link->addresses, address);
adda1ed9 127 set_remove(address->link->addresses_foreign, address);
e5526518 128 set_remove(address->link->static_addresses, address);
6e537f62
YW
129 if (address->link->dhcp_address == address)
130 address->link->dhcp_address = NULL;
131 if (address->link->dhcp_address_old == address)
132 address->link->dhcp_address_old = NULL;
1633c457
YW
133 set_remove(address->link->dhcp6_addresses, address);
134 set_remove(address->link->dhcp6_addresses_old, address);
135 set_remove(address->link->dhcp6_pd_addresses, address);
136 set_remove(address->link->dhcp6_pd_addresses_old, address);
69203fba
YW
137 set_remove(address->link->ndisc_addresses, address);
138 set_remove(address->link->ndisc_addresses_old, address);
f150100a
SS
139
140 if (in_addr_equal(AF_INET6, &address->in_addr, (const union in_addr_union *) &address->link->ipv6ll_address))
141 memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr));
adda1ed9 142 }
cf1d700d 143
051e77ca
SS
144 sd_ipv4acd_unref(address->acd);
145
de4224aa
YW
146 network_config_section_free(address->section);
147 free(address->label);
f579559b
TG
148 free(address);
149}
150
24be9181
ZJS
151static uint32_t address_prefix(const Address *a) {
152 assert(a);
153
154 /* make sure we don't try to shift by 32.
155 * See ISO/IEC 9899:TC3 § 6.5.7.3. */
156 if (a->prefixlen == 0)
157 return 0;
158
159 if (a->in_addr_peer.in.s_addr != 0)
160 return be32toh(a->in_addr_peer.in.s_addr) >> (32 - a->prefixlen);
161 else
162 return be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
163}
164
7a08d314 165static void address_hash_func(const Address *a, struct siphash *state) {
3ac8e543
TG
166 assert(a);
167
168 siphash24_compress(&a->family, sizeof(a->family), state);
169
170 switch (a->family) {
171 case AF_INET:
172 siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
173
174 /* peer prefix */
24be9181
ZJS
175 uint32_t prefix = address_prefix(a);
176 siphash24_compress(&prefix, sizeof(prefix), state);
3ac8e543 177
4831981d 178 _fallthrough_;
3ac8e543
TG
179 case AF_INET6:
180 /* local address */
181 siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
182
183 break;
184 default:
185 /* treat any other address family as AF_UNSPEC */
186 break;
187 }
188}
189
7a08d314 190static int address_compare_func(const Address *a1, const Address *a2) {
a0edd02e 191 int r;
3ac8e543 192
a0edd02e
FB
193 r = CMP(a1->family, a2->family);
194 if (r != 0)
195 return r;
3ac8e543
TG
196
197 switch (a1->family) {
198 /* use the same notion of equality as the kernel does */
199 case AF_INET:
a0edd02e
FB
200 r = CMP(a1->prefixlen, a2->prefixlen);
201 if (r != 0)
202 return r;
3ac8e543 203
24be9181
ZJS
204 uint32_t prefix1 = address_prefix(a1);
205 uint32_t prefix2 = address_prefix(a2);
206 r = CMP(prefix1, prefix2);
207 if (r != 0)
208 return r;
3ac8e543 209
4831981d 210 _fallthrough_;
3ac8e543
TG
211 case AF_INET6:
212 return memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
213 default:
214 /* treat any other address family as AF_UNSPEC */
215 return 0;
216 }
217}
218
8eec0b9d 219DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(address_hash_ops, Address, address_hash_func, address_compare_func, address_free);
3ac8e543
TG
220
221bool address_equal(Address *a1, Address *a2) {
222 if (a1 == a2)
223 return true;
224
225 if (!a1 || !a2)
226 return false;
227
228 return address_compare_func(a1, a2) == 0;
229}
230
91b5f997
TG
231static int address_establish(Address *address, Link *link) {
232 bool masq;
233 int r;
234
235 assert(address);
236 assert(link);
237
238 masq = link->network &&
fcf50cff
TG
239 link->network->ip_masquerade &&
240 address->family == AF_INET &&
241 address->scope < RT_SCOPE_LINK;
91b5f997
TG
242
243 /* Add firewall entry if this is requested */
244 if (address->ip_masquerade_done != masq) {
245 union in_addr_union masked = address->in_addr;
246 in_addr_mask(address->family, &masked, address->prefixlen);
247
248 r = fw_add_masquerade(masq, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
249 if (r < 0)
7750b796 250 return r;
91b5f997
TG
251
252 address->ip_masquerade_done = masq;
253 }
254
255 return 0;
256}
257
adda1ed9
TG
258static int address_add_internal(Link *link, Set **addresses,
259 int family,
260 const union in_addr_union *in_addr,
261 unsigned char prefixlen,
262 Address **ret) {
8e766630 263 _cleanup_(address_freep) Address *address = NULL;
cf1d700d
TG
264 int r;
265
266 assert(link);
adda1ed9 267 assert(addresses);
054f0db4 268 assert(in_addr);
054f0db4
TG
269
270 r = address_new(&address);
271 if (r < 0)
272 return r;
273
274 address->family = family;
275 address->in_addr = *in_addr;
276 address->prefixlen = prefixlen;
63bbe5c7
TG
277 /* Consider address tentative until we get the real flags from the kernel */
278 address->flags = IFA_F_TENTATIVE;
cf1d700d 279
de7fef4b 280 r = set_ensure_put(addresses, &address_hash_ops, address);
cf1d700d
TG
281 if (r < 0)
282 return r;
75a302b5
YW
283 if (r == 0)
284 return -EEXIST;
cf1d700d
TG
285
286 address->link = link;
287
adda1ed9
TG
288 if (ret)
289 *ret = address;
de7fef4b 290 TAKE_PTR(address);
cf1d700d
TG
291 return 0;
292}
293
adda1ed9
TG
294int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
295 return address_add_internal(link, &link->addresses_foreign, family, in_addr, prefixlen, ret);
296}
297
c4a03a56 298int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
cab974b0 299 Address *address;
e7780c8d
TG
300 int r;
301
cab974b0
TG
302 r = address_get(link, family, in_addr, prefixlen, &address);
303 if (r == -ENOENT) {
304 /* Address does not exist, create a new one */
305 r = address_add_internal(link, &link->addresses, family, in_addr, prefixlen, &address);
306 if (r < 0)
307 return r;
308 } else if (r == 0) {
309 /* Take over a foreign address */
de7fef4b 310 r = set_ensure_put(&link->addresses, &address_hash_ops, address);
cab974b0
TG
311 if (r < 0)
312 return r;
313
314 set_remove(link->addresses_foreign, address);
315 } else if (r == 1) {
316 /* Already exists, do nothing */
317 ;
318 } else
e7780c8d
TG
319 return r;
320
cab974b0
TG
321 if (ret)
322 *ret = address;
e7780c8d
TG
323
324 return 0;
adda1ed9
TG
325}
326
fcf50cff 327static int address_release(Address *address) {
5a8bcb67
LP
328 int r;
329
330 assert(address);
fcf50cff 331 assert(address->link);
5a8bcb67 332
91b5f997
TG
333 /* Remove masquerading firewall entry if it was added */
334 if (address->ip_masquerade_done) {
5a8bcb67
LP
335 union in_addr_union masked = address->in_addr;
336 in_addr_mask(address->family, &masked, address->prefixlen);
337
91b5f997 338 r = fw_add_masquerade(false, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
5a8bcb67 339 if (r < 0)
7750b796 340 return r;
5a8bcb67 341
91b5f997 342 address->ip_masquerade_done = false;
5a8bcb67
LP
343 }
344
345 return 0;
346}
347
889b550f
LP
348int address_update(
349 Address *address,
350 unsigned char flags,
351 unsigned char scope,
352 const struct ifa_cacheinfo *cinfo) {
353
36c32f61 354 bool ready;
e7ab854c 355 int r;
36c32f61
TG
356
357 assert(address);
ea121d8f 358 assert(address->link);
36c32f61
TG
359 assert(cinfo);
360
361 ready = address_is_ready(address);
362
363 address->flags = flags;
364 address->scope = scope;
365 address->cinfo = *cinfo;
366
ea121d8f
YW
367 if (IN_SET(address->link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
368 return 0;
369
959f65d3 370 link_update_operstate(address->link, true);
c8f7123e 371 link_check_ready(address->link);
7209086d 372
97f00074
YW
373 if (!ready && address_is_ready(address)) {
374 if (address->callback) {
375 r = address->callback(address);
376 if (r < 0)
377 return r;
378 }
7209086d 379
97f00074
YW
380 if (address->family == AF_INET6 &&
381 in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 &&
382 IN6_IS_ADDR_UNSPECIFIED(&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 }
a3a019e1 388 }
36c32f61
TG
389
390 return 0;
391}
392
91b5f997 393int address_drop(Address *address) {
8012cd39
TG
394 Link *link;
395 bool ready;
7750b796 396 int r;
8012cd39 397
5a8bcb67 398 assert(address);
91b5f997 399
8012cd39
TG
400 ready = address_is_ready(address);
401 link = address->link;
402
7750b796
YW
403 r = address_release(address);
404 if (r < 0)
405 log_link_warning_errno(link, r, "Failed to disable IP masquerading, ignoring: %m");
406
91b5f997
TG
407 address_free(address);
408
959f65d3 409 link_update_operstate(link, true);
84de38c5 410
8012cd39
TG
411 if (link && !ready)
412 link_check_ready(link);
413
91b5f997
TG
414 return 0;
415}
416
1b566071
LP
417int address_get(Link *link,
418 int family,
419 const union in_addr_union *in_addr,
420 unsigned char prefixlen,
421 Address **ret) {
422
423 Address address, *existing;
91b5f997 424
5a8bcb67 425 assert(link);
91b5f997 426 assert(in_addr);
5a8bcb67 427
1b566071
LP
428 address = (Address) {
429 .family = family,
430 .in_addr = *in_addr,
431 .prefixlen = prefixlen,
432 };
5a8bcb67 433
91b5f997 434 existing = set_get(link->addresses, &address);
cab974b0 435 if (existing) {
1b566071
LP
436 if (ret)
437 *ret = existing;
cab974b0 438 return 1;
adda1ed9 439 }
5a8bcb67 440
1b566071
LP
441 existing = set_get(link->addresses_foreign, &address);
442 if (existing) {
443 if (ret)
444 *ret = existing;
445 return 0;
446 }
5a8bcb67 447
1b566071 448 return -ENOENT;
5a8bcb67
LP
449}
450
5eec0a08
YW
451static bool address_exists_internal(Set *addresses, int family, const union in_addr_union *in_addr) {
452 Address *address;
453 Iterator i;
454
455 SET_FOREACH(address, addresses, i) {
456 if (address->family != family)
457 continue;
458 if (in_addr_equal(address->family, &address->in_addr, in_addr))
459 return true;
460 }
461
462 return false;
463}
464
465bool address_exists(Link *link, int family, const union in_addr_union *in_addr) {
466 assert(link);
467 assert(IN_SET(family, AF_INET, AF_INET6));
468 assert(in_addr);
469
470 if (address_exists_internal(link->addresses, family, in_addr))
471 return true;
472 if (address_exists_internal(link->addresses_foreign, family, in_addr))
473 return true;
474 return false;
475}
476
302a796f 477static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
63ae0569
YW
478 int r;
479
480 assert(m);
481 assert(link);
482 assert(link->ifname);
483
484 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
485 return 1;
486
487 r = sd_netlink_message_get_errno(m);
488 if (r < 0 && r != -EADDRNOTAVAIL)
5ecb131d 489 log_link_message_warning_errno(link, m, r, "Could not drop address");
93b0b88c
YW
490 else
491 (void) manager_rtnl_process_address(rtnl, m, link->manager);
63ae0569
YW
492
493 return 1;
494}
495
483d099e
ZJS
496int address_remove(
497 Address *address,
498 Link *link,
302a796f 499 link_netlink_message_handler_t callback) {
483d099e 500
4afd3348 501 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
407fe036
TG
502 int r;
503
504 assert(address);
4c701096 505 assert(IN_SET(address->family, AF_INET, AF_INET6));
407fe036
TG
506 assert(link);
507 assert(link->ifindex > 0);
508 assert(link->manager);
509 assert(link->manager->rtnl);
510
30226d27 511 if (DEBUG_LOGGING) {
7750b796
YW
512 _cleanup_free_ char *b = NULL;
513
514 (void) in_addr_to_string(address->family, &address->in_addr, &b);
515 log_link_debug(link, "Removing address %s", strna(b));
30226d27
TJ
516 }
517
151b9b96
LP
518 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
519 link->ifindex, address->family);
eb56eb9b 520 if (r < 0)
7750b796 521 return log_link_error_errno(link, r, "Could not allocate RTM_DELADDR message: %m");
407fe036 522
5a723174 523 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
eb56eb9b 524 if (r < 0)
7750b796 525 return log_link_error_errno(link, r, "Could not set prefixlen: %m");
5a723174 526
43409486 527 r = netlink_message_append_in_addr_union(req, IFA_LOCAL, address->family, &address->in_addr);
eb56eb9b 528 if (r < 0)
7750b796 529 return log_link_error_errno(link, r, "Could not append IFA_LOCAL attribute: %m");
407fe036 530
302a796f
YW
531 r = netlink_call_async(link->manager->rtnl, NULL, req,
532 callback ?: address_remove_handler,
533 link_netlink_destroy_callback, link);
eb56eb9b 534 if (r < 0)
7750b796 535 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
407fe036 536
563c69c6
TG
537 link_ref(link);
538
407fe036
TG
539 return 0;
540}
541
11bf3cce 542static int address_acquire(Link *link, Address *original, Address **ret) {
67a46833 543 union in_addr_union in_addr = IN_ADDR_NULL;
11bf3cce 544 struct in_addr broadcast = {};
8e766630 545 _cleanup_(address_freep) Address *na = NULL;
11bf3cce
LP
546 int r;
547
548 assert(link);
549 assert(original);
550 assert(ret);
551
552 /* Something useful was configured? just use it */
7e43ebfb
YW
553 r = in_addr_is_null(original->family, &original->in_addr);
554 if (r <= 0)
555 return r;
11bf3cce
LP
556
557 /* The address is configured to be 0.0.0.0 or [::] by the user?
558 * Then let's acquire something more useful from the pool. */
559 r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
6a7a4e4d 560 if (r < 0)
7750b796
YW
561 return r;
562 if (r == 0)
11bf3cce 563 return -EBUSY;
11bf3cce
LP
564
565 if (original->family == AF_INET) {
d076c6f9 566 /* Pick first address in range for ourselves ... */
11bf3cce
LP
567 in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
568
569 /* .. and use last as broadcast address */
e87e2b78
SS
570 if (original->prefixlen > 30)
571 broadcast.s_addr = 0;
572 else
573 broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
11bf3cce
LP
574 } else if (original->family == AF_INET6)
575 in_addr.in6.s6_addr[15] |= 1;
576
f0213e37 577 r = address_new(&na);
11bf3cce
LP
578 if (r < 0)
579 return r;
580
581 na->family = original->family;
582 na->prefixlen = original->prefixlen;
583 na->scope = original->scope;
584 na->cinfo = original->cinfo;
585
586 if (original->label) {
587 na->label = strdup(original->label);
0099bc15 588 if (!na->label)
11bf3cce 589 return -ENOMEM;
11bf3cce
LP
590 }
591
592 na->broadcast = broadcast;
593 na->in_addr = in_addr;
594
595 LIST_PREPEND(addresses, link->pool_addresses, na);
596
1cc6c93a 597 *ret = TAKE_PTR(na);
0099bc15 598
11bf3cce
LP
599 return 0;
600}
601
1b566071
LP
602int address_configure(
603 Address *address,
604 Link *link,
302a796f 605 link_netlink_message_handler_t callback,
80b0e860
YW
606 bool update,
607 Address **ret) {
1b566071 608
4afd3348 609 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
80b0e860 610 Address *a;
f579559b
TG
611 int r;
612
c166a070 613 assert(address);
4c701096 614 assert(IN_SET(address->family, AF_INET, AF_INET6));
c166a070
TG
615 assert(link);
616 assert(link->ifindex > 0);
f882c247 617 assert(link->manager);
c166a070 618 assert(link->manager->rtnl);
bd1175bc 619 assert(callback);
f882c247 620
1b566071
LP
621 /* If this is a new address, then refuse adding more than the limit */
622 if (address_get(link, address->family, &address->in_addr, address->prefixlen, NULL) <= 0 &&
623 set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
7750b796
YW
624 return log_link_error_errno(link, SYNTHETIC_ERRNO(E2BIG),
625 "Too many addresses are configured, refusing: %m");
1b566071 626
11bf3cce
LP
627 r = address_acquire(link, address, &address);
628 if (r < 0)
7750b796 629 return log_link_error_errno(link, r, "Failed to acquire an address from pool: %m");
11bf3cce 630
3606ca65
YW
631 if (DEBUG_LOGGING) {
632 _cleanup_free_ char *str = NULL;
633
634 (void) in_addr_to_string(address->family, &address->in_addr, &str);
635 log_link_debug(link, "%s address: %s", update ? "Updating" : "Configuring", strna(str));
636 }
637
66669078
TG
638 if (update)
639 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
640 link->ifindex, address->family);
641 else
642 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
643 link->ifindex, address->family);
eb56eb9b 644 if (r < 0)
7750b796 645 return log_link_error_errno(link, r, "Could not allocate RTM_NEWADDR message: %m");
f579559b 646
5a723174 647 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
eb56eb9b 648 if (r < 0)
7750b796 649 return log_link_error_errno(link, r, "Could not set prefixlen: %m");
5a723174 650
851c9f82
PF
651 address->flags |= IFA_F_PERMANENT;
652
e63be084
SS
653 if (address->home_address)
654 address->flags |= IFA_F_HOMEADDRESS;
655
051e77ca 656 if (!FLAGS_SET(address->duplicate_address_detection, ADDRESS_FAMILY_IPV6))
e63be084
SS
657 address->flags |= IFA_F_NODAD;
658
659 if (address->manage_temporary_address)
660 address->flags |= IFA_F_MANAGETEMPADDR;
661
de697db0 662 if (!address->prefix_route)
e63be084
SS
663 address->flags |= IFA_F_NOPREFIXROUTE;
664
665 if (address->autojoin)
666 address->flags |= IFA_F_MCAUTOJOIN;
667
851c9f82 668 r = sd_rtnl_message_addr_set_flags(req, (address->flags & 0xff));
eb56eb9b 669 if (r < 0)
7750b796 670 return log_link_error_errno(link, r, "Could not set flags: %m");
5a723174 671
851c9f82 672 if (address->flags & ~0xff) {
1c4baffc 673 r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags);
851c9f82 674 if (r < 0)
7750b796 675 return log_link_error_errno(link, r, "Could not set extended flags: %m");
851c9f82
PF
676 }
677
5c1d3fc9 678 r = sd_rtnl_message_addr_set_scope(req, address->scope);
eb56eb9b 679 if (r < 0)
7750b796 680 return log_link_error_errno(link, r, "Could not set scope: %m");
5a723174 681
43409486 682 r = netlink_message_append_in_addr_union(req, IFA_LOCAL, address->family, &address->in_addr);
eb56eb9b 683 if (r < 0)
7750b796 684 return log_link_error_errno(link, r, "Could not append IFA_LOCAL attribute: %m");
f579559b 685
d40b01e4 686 if (in_addr_is_null(address->family, &address->in_addr_peer) == 0) {
43409486 687 r = netlink_message_append_in_addr_union(req, IFA_ADDRESS, address->family, &address->in_addr_peer);
eb56eb9b 688 if (r < 0)
7750b796 689 return log_link_error_errno(link, r, "Could not append IFA_ADDRESS attribute: %m");
66e0bb33
YW
690 } else if (address->family == AF_INET && address->prefixlen <= 30) {
691 r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
692 if (r < 0)
7750b796 693 return log_link_error_errno(link, r, "Could not append IFA_BROADCAST attribute: %m");
f579559b
TG
694 }
695
696 if (address->label) {
1c4baffc 697 r = sd_netlink_message_append_string(req, IFA_LABEL, address->label);
eb56eb9b 698 if (r < 0)
7750b796 699 return log_link_error_errno(link, r, "Could not append IFA_LABEL attribute: %m");
f579559b
TG
700 }
701
66e0bb33 702 r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
eb56eb9b 703 if (r < 0)
7750b796 704 return log_link_error_errno(link, r, "Could not append IFA_CACHEINFO attribute: %m");
68ceb9df 705
fcf50cff 706 r = address_establish(address, link);
eb56eb9b 707 if (r < 0)
7750b796 708 log_link_warning_errno(link, r, "Could not enable IP masquerading, ignoring: %m");
fcf50cff 709
dfef713f 710 r = netlink_call_async(link->manager->rtnl, NULL, req, callback, link_netlink_destroy_callback, link);
fcf50cff
TG
711 if (r < 0) {
712 address_release(address);
7750b796 713 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
fcf50cff 714 }
f579559b 715
563c69c6
TG
716 link_ref(link);
717
dfef713f 718 if (address->family == AF_INET6 && !in_addr_is_null(address->family, &address->in_addr_peer))
80b0e860 719 r = address_add(link, address->family, &address->in_addr_peer, address->prefixlen, &a);
dfef713f 720 else
80b0e860 721 r = address_add(link, address->family, &address->in_addr, address->prefixlen, &a);
adda1ed9
TG
722 if (r < 0) {
723 address_release(address);
7750b796 724 return log_link_error_errno(link, r, "Could not add address: %m");
adda1ed9
TG
725 }
726
051e77ca
SS
727 if (address->acd) {
728 assert(address->family == AF_INET);
729 if (DEBUG_LOGGING) {
730 _cleanup_free_ char *pretty = NULL;
731
732 (void) in_addr_to_string(address->family, &address->in_addr, &pretty);
98b02994 733 log_link_debug(link, "Starting IPv4ACD client. Probing address %s", strna(pretty));
051e77ca
SS
734 }
735
e92b60b2 736 r = sd_ipv4acd_start(address->acd, true);
051e77ca
SS
737 if (r < 0)
738 log_link_warning_errno(link, r, "Failed to start IPv4ACD client, ignoring: %m");
739 }
740
80b0e860
YW
741 if (ret)
742 *ret = a;
743
54a1a535 744 return 1;
f579559b
TG
745}
746
051e77ca
SS
747static void static_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
748 _cleanup_free_ char *pretty = NULL;
749 Address *address;
750 Link *link;
751 int r;
752
753 assert(acd);
754 assert(userdata);
755
756 address = (Address *) userdata;
757 link = address->link;
758
759 (void) in_addr_to_string(address->family, &address->in_addr, &pretty);
760 switch (event) {
761 case SD_IPV4ACD_EVENT_STOP:
762 log_link_debug(link, "Stopping ACD client...");
763 return;
764
765 case SD_IPV4ACD_EVENT_BIND:
766 log_link_debug(link, "Successfully claimed address %s", strna(pretty));
767 link_check_ready(link);
768 break;
769
770 case SD_IPV4ACD_EVENT_CONFLICT:
771 log_link_warning(link, "DAD conflict. Dropping address %s", strna(pretty));
772 r = address_remove(address, link, NULL);
773 if (r < 0)
774 log_link_error_errno(link, r, "Failed to drop DAD conflicted address %s", strna(pretty));;
775
776 link_check_ready(link);
777 break;
778
779 default:
780 assert_not_reached("Invalid IPv4ACD event.");
781 }
782
783 sd_ipv4acd_stop(acd);
784
785 return;
786}
787
788int configure_ipv4_duplicate_address_detection(Link *link, Address *address) {
789 int r;
790
791 assert(link);
792 assert(address);
793 assert(address->family == AF_INET);
794 assert(!address->link && address->network);
795
796 address->link = link;
797
798 r = sd_ipv4acd_new(&address->acd);
799 if (r < 0)
800 return r;
801
802 r = sd_ipv4acd_attach_event(address->acd, NULL, 0);
803 if (r < 0)
804 return r;
805
806 r = sd_ipv4acd_set_ifindex(address->acd, link->ifindex);
807 if (r < 0)
808 return r;
809
810 r = sd_ipv4acd_set_mac(address->acd, &link->mac);
811 if (r < 0)
812 return r;
813
814 r = sd_ipv4acd_set_address(address->acd, &address->in_addr.in);
815 if (r < 0)
816 return r;
817
818 r = sd_ipv4acd_set_callback(address->acd, static_address_on_acd, address);
819 if (r < 0)
820 return r;
821
822 return 0;
823}
824
44e7b949
LP
825int config_parse_broadcast(
826 const char *unit,
eb0ea358
TG
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) {
44e7b949 836
eb0ea358 837 Network *network = userdata;
fcbf4cb7 838 _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
eb0ea358
TG
839 int r;
840
841 assert(filename);
842 assert(section);
843 assert(lvalue);
844 assert(rvalue);
845 assert(data);
846
f4859fc7 847 r = address_new_static(network, filename, section_line, &n);
d96edb2c
YW
848 if (r == -ENOMEM)
849 return log_oom();
850 if (r < 0) {
851 log_syntax(unit, LOG_WARNING, filename, line, r,
852 "Failed to allocate new address, ignoring assignment: %m");
853 return 0;
854 }
eb0ea358 855
482e2ac1 856 if (n->family == AF_INET6) {
d96edb2c 857 log_syntax(unit, LOG_WARNING, filename, line, 0,
2850cd40 858 "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
482e2ac1
TG
859 return 0;
860 }
861
44e7b949 862 r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
eb0ea358 863 if (r < 0) {
d96edb2c 864 log_syntax(unit, LOG_WARNING, filename, line, r,
2850cd40 865 "Broadcast is invalid, ignoring assignment: %s", rvalue);
eb0ea358
TG
866 return 0;
867 }
868
44e7b949 869 n->family = AF_INET;
eb0ea358
TG
870 n = NULL;
871
872 return 0;
873}
874
f579559b
TG
875int config_parse_address(const char *unit,
876 const char *filename,
877 unsigned line,
878 const char *section,
71a61510 879 unsigned section_line,
f579559b
TG
880 const char *lvalue,
881 int ltype,
882 const char *rvalue,
883 void *data,
884 void *userdata) {
44e7b949 885
6ae115c1 886 Network *network = userdata;
fcbf4cb7 887 _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
44e7b949 888 union in_addr_union buffer;
b7cb4452 889 unsigned char prefixlen;
44e7b949 890 int r, f;
f579559b
TG
891
892 assert(filename);
6ae115c1 893 assert(section);
f579559b
TG
894 assert(lvalue);
895 assert(rvalue);
896 assert(data);
897
92fe133a
TG
898 if (streq(section, "Network")) {
899 /* we are not in an Address section, so treat
900 * this as the special '0' section */
f4859fc7
SS
901 r = address_new_static(network, NULL, 0, &n);
902 } else
903 r = address_new_static(network, filename, section_line, &n);
d96edb2c
YW
904 if (r == -ENOMEM)
905 return log_oom();
906 if (r < 0) {
907 log_syntax(unit, LOG_WARNING, filename, line, r,
908 "Failed to allocate new address, ignoring assignment: %m");
909 return 0;
910 }
f579559b
TG
911
912 /* Address=address/prefixlen */
0f707207
YW
913 r = in_addr_prefix_from_string_auto_internal(rvalue, PREFIXLEN_REFUSE, &f, &buffer, &prefixlen);
914 if (r == -ENOANO) {
d96edb2c 915 log_syntax(unit, LOG_WARNING, filename, line, r,
0f707207
YW
916 "An address '%s' is specified without prefix length. "
917 "The behavior of parsing addresses without prefix length will be changed in the future release. "
918 "Please specify prefix length explicitly.", rvalue);
919
920 r = in_addr_prefix_from_string_auto_internal(rvalue, PREFIXLEN_LEGACY, &f, &buffer, &prefixlen);
921 }
f579559b 922 if (r < 0) {
d96edb2c 923 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid address '%s', ignoring assignment: %m", rvalue);
f579559b
TG
924 return 0;
925 }
926
44e7b949 927 if (n->family != AF_UNSPEC && f != n->family) {
d96edb2c 928 log_syntax(unit, LOG_WARNING, filename, line, 0, "Address is incompatible, ignoring assignment: %s", rvalue);
44e7b949
LP
929 return 0;
930 }
931
c9207ff3
YW
932 if (in_addr_is_null(f, &buffer)) {
933 /* Will use address from address pool. Note that for ipv6 case, prefix of the address
934 * pool is 8, but 40 bit is used by the global ID and 16 bit by the subnet ID. So,
935 * let's limit the prefix length to 64 or larger. See RFC4193. */
936 if ((f == AF_INET && prefixlen < 8) ||
937 (f == AF_INET6 && prefixlen < 64)) {
d96edb2c 938 log_syntax(unit, LOG_WARNING, filename, line, 0,
c9207ff3
YW
939 "Null address with invalid prefixlen='%u', ignoring assignment: %s",
940 prefixlen, rvalue);
941 return 0;
942 }
943 }
944
44e7b949 945 n->family = f;
b7cb4452 946 n->prefixlen = prefixlen;
44e7b949
LP
947
948 if (streq(lvalue, "Address"))
949 n->in_addr = buffer;
950 else
951 n->in_addr_peer = buffer;
952
3681d639 953 if (n->family == AF_INET && n->broadcast.s_addr == 0 && n->prefixlen <= 30)
fe2e4b69 954 n->broadcast.s_addr = n->in_addr.in.s_addr | htobe32(0xfffffffflu >> n->prefixlen);
eb0ea358 955
f579559b
TG
956 n = NULL;
957
958 return 0;
959}
6ae115c1 960
d31645ad
LP
961int config_parse_label(
962 const char *unit,
6ae115c1
TG
963 const char *filename,
964 unsigned line,
965 const char *section,
966 unsigned section_line,
967 const char *lvalue,
968 int ltype,
969 const char *rvalue,
970 void *data,
971 void *userdata) {
d31645ad 972
fcbf4cb7 973 _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
d31645ad 974 Network *network = userdata;
6ae115c1
TG
975 int r;
976
977 assert(filename);
978 assert(section);
979 assert(lvalue);
980 assert(rvalue);
981 assert(data);
982
f4859fc7 983 r = address_new_static(network, filename, section_line, &n);
d96edb2c
YW
984 if (r == -ENOMEM)
985 return log_oom();
986 if (r < 0) {
987 log_syntax(unit, LOG_WARNING, filename, line, r,
988 "Failed to allocate new address, ignoring assignment: %m");
989 return 0;
990 }
6ae115c1 991
a87d19fe 992 if (!address_label_valid(rvalue)) {
d96edb2c 993 log_syntax(unit, LOG_WARNING, filename, line, 0,
2850cd40 994 "Interface label is too long or invalid, ignoring assignment: %s", rvalue);
6ae115c1
TG
995 return 0;
996 }
997
d31645ad
LP
998 r = free_and_strdup(&n->label, rvalue);
999 if (r < 0)
1000 return log_oom();
6ae115c1
TG
1001
1002 n = NULL;
6ae115c1
TG
1003 return 0;
1004}
ce6c77eb 1005
b5834a0b
SS
1006int config_parse_lifetime(const char *unit,
1007 const char *filename,
1008 unsigned line,
1009 const char *section,
1010 unsigned section_line,
1011 const char *lvalue,
1012 int ltype,
1013 const char *rvalue,
1014 void *data,
1015 void *userdata) {
1016 Network *network = userdata;
fcbf4cb7 1017 _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
d2735796 1018 uint32_t k;
b5834a0b
SS
1019 int r;
1020
1021 assert(filename);
1022 assert(section);
1023 assert(lvalue);
1024 assert(rvalue);
1025 assert(data);
1026
f4859fc7 1027 r = address_new_static(network, filename, section_line, &n);
d96edb2c
YW
1028 if (r == -ENOMEM)
1029 return log_oom();
1030 if (r < 0) {
1031 log_syntax(unit, LOG_WARNING, filename, line, r,
1032 "Failed to allocate new address, ignoring assignment: %m");
1033 return 0;
1034 }
b5834a0b 1035
10b20e5a
ZJS
1036 /* We accept only "forever", "infinity", empty, or "0". */
1037 if (STR_IN_SET(rvalue, "forever", "infinity", ""))
33680b0a
YW
1038 k = CACHE_INFO_INFINITY_LIFE_TIME;
1039 else if (streq(rvalue, "0"))
1040 k = 0;
1041 else {
d96edb2c 1042 log_syntax(unit, LOG_WARNING, filename, line, 0,
33680b0a 1043 "Invalid PreferredLifetime= value, ignoring: %s", rvalue);
b5834a0b
SS
1044 return 0;
1045 }
1046
33680b0a 1047 n->cinfo.ifa_prefered = k;
d2735796 1048 TAKE_PTR(n);
b5834a0b
SS
1049
1050 return 0;
1051}
1052
e63be084
SS
1053int config_parse_address_flags(const char *unit,
1054 const char *filename,
1055 unsigned line,
1056 const char *section,
1057 unsigned section_line,
1058 const char *lvalue,
1059 int ltype,
1060 const char *rvalue,
1061 void *data,
1062 void *userdata) {
1063 Network *network = userdata;
fcbf4cb7 1064 _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
e63be084
SS
1065 int r;
1066
1067 assert(filename);
1068 assert(section);
1069 assert(lvalue);
1070 assert(rvalue);
1071 assert(data);
1072
f4859fc7 1073 r = address_new_static(network, filename, section_line, &n);
d96edb2c
YW
1074 if (r == -ENOMEM)
1075 return log_oom();
1076 if (r < 0) {
1077 log_syntax(unit, LOG_WARNING, filename, line, r,
1078 "Failed to allocate new address, ignoring assignment: %m");
1079 return 0;
1080 }
e63be084
SS
1081
1082 r = parse_boolean(rvalue);
1083 if (r < 0) {
d96edb2c 1084 log_syntax(unit, LOG_WARNING, filename, line, r,
051e77ca 1085 "Failed to parse %s=, ignoring: %s", lvalue, rvalue);
e63be084
SS
1086 return 0;
1087 }
1088
1089 if (streq(lvalue, "HomeAddress"))
1090 n->home_address = r;
e63be084
SS
1091 else if (streq(lvalue, "ManageTemporaryAddress"))
1092 n->manage_temporary_address = r;
1093 else if (streq(lvalue, "PrefixRoute"))
de697db0
YW
1094 n->prefix_route = !r;
1095 else if (streq(lvalue, "AddPrefixRoute"))
e63be084
SS
1096 n->prefix_route = r;
1097 else if (streq(lvalue, "AutoJoin"))
1098 n->autojoin = r;
2850cd40
YW
1099 else
1100 assert_not_reached("Invalid address flag type.");
e63be084 1101
4aa4c4b0 1102 n = NULL;
e63be084
SS
1103 return 0;
1104}
1105
2959fb07
SS
1106int config_parse_address_scope(const char *unit,
1107 const char *filename,
1108 unsigned line,
1109 const char *section,
1110 unsigned section_line,
1111 const char *lvalue,
1112 int ltype,
1113 const char *rvalue,
1114 void *data,
1115 void *userdata) {
1116 Network *network = userdata;
fcbf4cb7 1117 _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
2959fb07
SS
1118 int r;
1119
1120 assert(filename);
1121 assert(section);
1122 assert(lvalue);
1123 assert(rvalue);
1124 assert(data);
1125
1126 r = address_new_static(network, filename, section_line, &n);
d96edb2c
YW
1127 if (r == -ENOMEM)
1128 return log_oom();
1129 if (r < 0) {
1130 log_syntax(unit, LOG_WARNING, filename, line, r,
1131 "Failed to allocate new address, ignoring assignment: %m");
1132 return 0;
1133 }
2959fb07
SS
1134
1135 if (streq(rvalue, "host"))
1136 n->scope = RT_SCOPE_HOST;
1137 else if (streq(rvalue, "link"))
1138 n->scope = RT_SCOPE_LINK;
1139 else if (streq(rvalue, "global"))
1140 n->scope = RT_SCOPE_UNIVERSE;
1141 else {
1142 r = safe_atou8(rvalue , &n->scope);
1143 if (r < 0) {
d96edb2c 1144 log_syntax(unit, LOG_WARNING, filename, line, r,
2850cd40 1145 "Could not parse address scope \"%s\", ignoring assignment: %m", rvalue);
2959fb07
SS
1146 return 0;
1147 }
1148 }
1149
07336a06 1150 n->scope_set = true;
2959fb07 1151 n = NULL;
2959fb07
SS
1152 return 0;
1153}
1154
051e77ca
SS
1155int config_parse_duplicate_address_detection(
1156 const char *unit,
1157 const char *filename,
1158 unsigned line,
1159 const char *section,
1160 unsigned section_line,
1161 const char *lvalue,
1162 int ltype,
1163 const char *rvalue,
1164 void *data,
1165 void *userdata) {
1166 Network *network = userdata;
1167 _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
1168 AddressFamily a;
1169 int r;
1170
1171 assert(filename);
1172 assert(section);
1173 assert(lvalue);
1174 assert(rvalue);
1175 assert(data);
1176
1177 r = address_new_static(network, filename, section_line, &n);
d96edb2c
YW
1178 if (r == -ENOMEM)
1179 return log_oom();
1180 if (r < 0) {
1181 log_syntax(unit, LOG_WARNING, filename, line, r,
1182 "Failed to allocate new address, ignoring assignment: %m");
1183 return 0;
1184 }
051e77ca
SS
1185
1186 r = parse_boolean(rvalue);
1187 if (r >= 0) {
1188 log_syntax(unit, LOG_WARNING, filename, line, 0,
1189 "For historical reasons, %s=%s means %s=%s. "
1190 "Please use 'both', 'ipv4', 'ipv6' or 'none' instead.",
1191 lvalue, rvalue, lvalue, r ? "none" : "both");
1192 n->duplicate_address_detection = r ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_YES;
1193 n = NULL;
1194 return 0;
1195 }
1196
1197 a = duplicate_address_detection_address_family_from_string(rvalue);
1198 if (a < 0) {
d96edb2c 1199 log_syntax(unit, LOG_WARNING, filename, line, SYNTHETIC_ERRNO(EINVAL),
051e77ca
SS
1200 "Failed to parse %s=, ignoring: %s", lvalue, rvalue);
1201 return 0;
1202 }
1203
1204 n->duplicate_address_detection = a;
1205 n = NULL;
1206 return 0;
1207}
1208
ce6c77eb
TG
1209bool address_is_ready(const Address *a) {
1210 assert(a);
1211
ce158189 1212 return !(a->flags & IFA_F_TENTATIVE);
ce6c77eb 1213}
fcbf4cb7
YW
1214
1215int address_section_verify(Address *address) {
1216 if (section_is_invalid(address->section))
1217 return -EINVAL;
1218
1219 if (address->family == AF_UNSPEC) {
1220 assert(address->section);
1221
1222 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
1223 "%s: Address section without Address= field configured. "
1224 "Ignoring [Address] section from line %u.",
1225 address->section->filename, address->section->line);
1226 }
1227
07336a06
YW
1228 if (!address->scope_set && in_addr_is_localhost(address->family, &address->in_addr) > 0)
1229 address->scope = RT_SCOPE_HOST;
1230
fcbf4cb7
YW
1231 return 0;
1232}