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