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