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