]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-address.c
tree-wide: use TAKE_PTR() and TAKE_FD() macros
[thirdparty/systemd.git] / src / network / networkd-address.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
f579559b
TG
2/***
3 This file is part of systemd.
4
5 Copyright 2013 Tom Gundersen <teg@jklm.no>
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <net/if.h>
22
b5efdb8a 23#include "alloc-util.h"
f579559b 24#include "conf-parser.h"
12c2884c 25#include "firewall-util.h"
fc2f9534 26#include "netlink-util.h"
6bedfcbb 27#include "networkd-address.h"
23f53b99 28#include "networkd-manager.h"
6bedfcbb 29#include "parse-util.h"
3ac8e543 30#include "set.h"
d31645ad 31#include "socket-util.h"
07630cea 32#include "string-util.h"
3ac8e543
TG
33#include "utf8.h"
34#include "util.h"
f579559b 35
1b566071 36#define ADDRESSES_PER_LINK_MAX 2048U
8c34b963
LP
37#define STATIC_ADDRESSES_PER_NETWORK_MAX 1024U
38
f0213e37
TG
39int address_new(Address **ret) {
40 _cleanup_address_free_ Address *address = NULL;
41
42 address = new0(Address, 1);
43 if (!address)
44 return -ENOMEM;
aba496a5
UTL
45
46 address->family = AF_UNSPEC;
47 address->scope = RT_SCOPE_UNIVERSE;
48 address->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
49 address->cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME;
f0213e37 50
1cc6c93a 51 *ret = TAKE_PTR(address);
f0213e37
TG
52
53 return 0;
aba496a5
UTL
54}
55
f4859fc7
SS
56int address_new_static(Network *network, const char *filename, unsigned section_line, Address **ret) {
57 _cleanup_network_config_section_free_ NetworkConfigSection *n = NULL;
f579559b 58 _cleanup_address_free_ Address *address = NULL;
f0213e37 59 int r;
f579559b 60
8c34b963
LP
61 assert(network);
62 assert(ret);
48317c39 63 assert(!!filename == (section_line > 0));
8c34b963 64
48317c39 65 if (filename) {
f4859fc7
SS
66 r = network_config_section_new(filename, section_line, &n);
67 if (r < 0)
68 return r;
69
70 address = hashmap_get(network->addresses_by_section, n);
6ae115c1 71 if (address) {
1cc6c93a 72 *ret = TAKE_PTR(address);
6ae115c1
TG
73
74 return 0;
75 }
76 }
77
8c34b963
LP
78 if (network->n_static_addresses >= STATIC_ADDRESSES_PER_NETWORK_MAX)
79 return -E2BIG;
80
f0213e37
TG
81 r = address_new(&address);
82 if (r < 0)
83 return r;
801bd9e8 84
48317c39 85 if (filename) {
1cc6c93a 86 address->section = TAKE_PTR(n);
fcc48287 87
f7fe70ea
SS
88 r = hashmap_put(network->addresses_by_section, address->section, address);
89 if (r < 0)
90 return r;
6ae115c1
TG
91 }
92
5215524d
SS
93 address->network = network;
94 LIST_APPEND(addresses, network->static_addresses, address);
8c34b963 95 network->n_static_addresses++;
5215524d 96
1cc6c93a 97 *ret = TAKE_PTR(address);
f579559b
TG
98
99 return 0;
100}
101
102void address_free(Address *address) {
103 if (!address)
104 return;
105
f048a16b 106 if (address->network) {
3d3d4255 107 LIST_REMOVE(addresses, address->network->static_addresses, address);
8c34b963
LP
108 assert(address->network->n_static_addresses > 0);
109 address->network->n_static_addresses--;
f579559b 110
f4859fc7
SS
111 if (address->section) {
112 hashmap_remove(address->network->addresses_by_section, address->section);
113 network_config_section_free(address->section);
114 }
f048a16b 115 }
6ae115c1 116
adda1ed9 117 if (address->link) {
cf1d700d 118 set_remove(address->link->addresses, address);
adda1ed9 119 set_remove(address->link->addresses_foreign, address);
f150100a
SS
120
121 if (in_addr_equal(AF_INET6, &address->in_addr, (const union in_addr_union *) &address->link->ipv6ll_address))
122 memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr));
adda1ed9 123 }
cf1d700d 124
f579559b
TG
125 free(address);
126}
127
3ac8e543
TG
128static void address_hash_func(const void *b, struct siphash *state) {
129 const Address *a = b;
130
131 assert(a);
132
133 siphash24_compress(&a->family, sizeof(a->family), state);
134
135 switch (a->family) {
136 case AF_INET:
137 siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
138
139 /* peer prefix */
140 if (a->prefixlen != 0) {
141 uint32_t prefix;
142
143 if (a->in_addr_peer.in.s_addr != 0)
144 prefix = be32toh(a->in_addr_peer.in.s_addr) >> (32 - a->prefixlen);
145 else
146 prefix = be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
147
148 siphash24_compress(&prefix, sizeof(prefix), state);
149 }
150
4831981d 151 _fallthrough_;
3ac8e543
TG
152 case AF_INET6:
153 /* local address */
154 siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
155
156 break;
157 default:
158 /* treat any other address family as AF_UNSPEC */
159 break;
160 }
161}
162
163static int address_compare_func(const void *c1, const void *c2) {
164 const Address *a1 = c1, *a2 = c2;
165
166 if (a1->family < a2->family)
167 return -1;
168 if (a1->family > a2->family)
169 return 1;
170
171 switch (a1->family) {
172 /* use the same notion of equality as the kernel does */
173 case AF_INET:
174 if (a1->prefixlen < a2->prefixlen)
175 return -1;
176 if (a1->prefixlen > a2->prefixlen)
177 return 1;
178
179 /* compare the peer prefixes */
180 if (a1->prefixlen != 0) {
181 /* make sure we don't try to shift by 32.
182 * See ISO/IEC 9899:TC3 § 6.5.7.3. */
183 uint32_t b1, b2;
184
185 if (a1->in_addr_peer.in.s_addr != 0)
186 b1 = be32toh(a1->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
187 else
188 b1 = be32toh(a1->in_addr.in.s_addr) >> (32 - a1->prefixlen);
189
190 if (a2->in_addr_peer.in.s_addr != 0)
191 b2 = be32toh(a2->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
192 else
193 b2 = be32toh(a2->in_addr.in.s_addr) >> (32 - a1->prefixlen);
194
195 if (b1 < b2)
196 return -1;
197 if (b1 > b2)
198 return 1;
199 }
200
4831981d 201 _fallthrough_;
3ac8e543
TG
202 case AF_INET6:
203 return memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
204 default:
205 /* treat any other address family as AF_UNSPEC */
206 return 0;
207 }
208}
209
210static const struct hash_ops address_hash_ops = {
211 .hash = address_hash_func,
212 .compare = address_compare_func
213};
214
215bool address_equal(Address *a1, Address *a2) {
216 if (a1 == a2)
217 return true;
218
219 if (!a1 || !a2)
220 return false;
221
222 return address_compare_func(a1, a2) == 0;
223}
224
91b5f997
TG
225static int address_establish(Address *address, Link *link) {
226 bool masq;
227 int r;
228
229 assert(address);
230 assert(link);
231
232 masq = link->network &&
fcf50cff
TG
233 link->network->ip_masquerade &&
234 address->family == AF_INET &&
235 address->scope < RT_SCOPE_LINK;
91b5f997
TG
236
237 /* Add firewall entry if this is requested */
238 if (address->ip_masquerade_done != masq) {
239 union in_addr_union masked = address->in_addr;
240 in_addr_mask(address->family, &masked, address->prefixlen);
241
242 r = fw_add_masquerade(masq, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
243 if (r < 0)
244 log_link_warning_errno(link, r, "Could not enable IP masquerading: %m");
245
246 address->ip_masquerade_done = masq;
247 }
248
249 return 0;
250}
251
adda1ed9
TG
252static int address_add_internal(Link *link, Set **addresses,
253 int family,
254 const union in_addr_union *in_addr,
255 unsigned char prefixlen,
256 Address **ret) {
054f0db4 257 _cleanup_address_free_ Address *address = NULL;
cf1d700d
TG
258 int r;
259
260 assert(link);
adda1ed9 261 assert(addresses);
054f0db4 262 assert(in_addr);
054f0db4
TG
263
264 r = address_new(&address);
265 if (r < 0)
266 return r;
267
268 address->family = family;
269 address->in_addr = *in_addr;
270 address->prefixlen = prefixlen;
63bbe5c7
TG
271 /* Consider address tentative until we get the real flags from the kernel */
272 address->flags = IFA_F_TENTATIVE;
cf1d700d 273
adda1ed9 274 r = set_ensure_allocated(addresses, &address_hash_ops);
cf1d700d
TG
275 if (r < 0)
276 return r;
277
adda1ed9 278 r = set_put(*addresses, address);
cf1d700d
TG
279 if (r < 0)
280 return r;
281
282 address->link = link;
283
adda1ed9
TG
284 if (ret)
285 *ret = address;
286
054f0db4
TG
287 address = NULL;
288
cf1d700d
TG
289 return 0;
290}
291
adda1ed9
TG
292int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
293 return address_add_internal(link, &link->addresses_foreign, family, in_addr, prefixlen, ret);
294}
295
c4a03a56 296int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
cab974b0 297 Address *address;
e7780c8d
TG
298 int r;
299
cab974b0
TG
300 r = address_get(link, family, in_addr, prefixlen, &address);
301 if (r == -ENOENT) {
302 /* Address does not exist, create a new one */
303 r = address_add_internal(link, &link->addresses, family, in_addr, prefixlen, &address);
304 if (r < 0)
305 return r;
306 } else if (r == 0) {
307 /* Take over a foreign address */
308 r = set_ensure_allocated(&link->addresses, &address_hash_ops);
309 if (r < 0)
310 return r;
311
312 r = set_put(link->addresses, address);
313 if (r < 0)
314 return r;
315
316 set_remove(link->addresses_foreign, address);
317 } else if (r == 1) {
318 /* Already exists, do nothing */
319 ;
320 } else
e7780c8d
TG
321 return r;
322
cab974b0
TG
323 if (ret)
324 *ret = address;
e7780c8d
TG
325
326 return 0;
adda1ed9
TG
327}
328
fcf50cff 329static int address_release(Address *address) {
5a8bcb67
LP
330 int r;
331
332 assert(address);
fcf50cff 333 assert(address->link);
5a8bcb67 334
91b5f997
TG
335 /* Remove masquerading firewall entry if it was added */
336 if (address->ip_masquerade_done) {
5a8bcb67
LP
337 union in_addr_union masked = address->in_addr;
338 in_addr_mask(address->family, &masked, address->prefixlen);
339
91b5f997 340 r = fw_add_masquerade(false, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
5a8bcb67 341 if (r < 0)
fcf50cff 342 log_link_warning_errno(address->link, r, "Failed to disable IP masquerading: %m");
5a8bcb67 343
91b5f997 344 address->ip_masquerade_done = false;
5a8bcb67
LP
345 }
346
347 return 0;
348}
349
889b550f
LP
350int address_update(
351 Address *address,
352 unsigned char flags,
353 unsigned char scope,
354 const struct ifa_cacheinfo *cinfo) {
355
36c32f61 356 bool ready;
e7ab854c 357 int r;
36c32f61
TG
358
359 assert(address);
360 assert(cinfo);
7209086d
SS
361 assert_return(address->link, 1);
362
363 if (IN_SET(address->link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
364 return 1;
36c32f61
TG
365
366 ready = address_is_ready(address);
367
368 address->flags = flags;
369 address->scope = scope;
370 address->cinfo = *cinfo;
371
7209086d
SS
372 link_update_operstate(address->link);
373
374 if (!ready && address_is_ready(address)) {
375 link_check_ready(address->link);
376
377 if (address->family == AF_INET6 &&
378 in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 &&
379 in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) {
380
381 r = link_ipv6ll_gained(address->link, &address->in_addr.in6);
382 if (r < 0)
383 return r;
e7ab854c 384 }
a3a019e1 385 }
36c32f61
TG
386
387 return 0;
388}
389
91b5f997 390int address_drop(Address *address) {
8012cd39
TG
391 Link *link;
392 bool ready;
393
5a8bcb67 394 assert(address);
91b5f997 395
8012cd39
TG
396 ready = address_is_ready(address);
397 link = address->link;
398
fcf50cff 399 address_release(address);
91b5f997
TG
400 address_free(address);
401
84de38c5
TG
402 link_update_operstate(link);
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
483d099e
ZJS
444int address_remove(
445 Address *address,
446 Link *link,
447 sd_netlink_message_handler_t callback) {
448
4afd3348 449 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
407fe036
TG
450 int r;
451
452 assert(address);
4c701096 453 assert(IN_SET(address->family, AF_INET, AF_INET6));
407fe036
TG
454 assert(link);
455 assert(link->ifindex > 0);
456 assert(link->manager);
457 assert(link->manager->rtnl);
458
151b9b96
LP
459 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
460 link->ifindex, address->family);
eb56eb9b
MS
461 if (r < 0)
462 return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m");
407fe036 463
5a723174 464 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
eb56eb9b
MS
465 if (r < 0)
466 return log_error_errno(r, "Could not set prefixlen: %m");
5a723174 467
407fe036 468 if (address->family == AF_INET)
1c4baffc 469 r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
407fe036 470 else if (address->family == AF_INET6)
1c4baffc 471 r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
eb56eb9b
MS
472 if (r < 0)
473 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
407fe036 474
1c4baffc 475 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
eb56eb9b
MS
476 if (r < 0)
477 return log_error_errno(r, "Could not send rtnetlink message: %m");
407fe036 478
563c69c6
TG
479 link_ref(link);
480
407fe036
TG
481 return 0;
482}
483
11bf3cce
LP
484static int address_acquire(Link *link, Address *original, Address **ret) {
485 union in_addr_union in_addr = {};
486 struct in_addr broadcast = {};
0099bc15 487 _cleanup_address_free_ Address *na = NULL;
11bf3cce
LP
488 int r;
489
490 assert(link);
491 assert(original);
492 assert(ret);
493
494 /* Something useful was configured? just use it */
af93291c 495 if (in_addr_is_null(original->family, &original->in_addr) <= 0)
11bf3cce
LP
496 return 0;
497
498 /* The address is configured to be 0.0.0.0 or [::] by the user?
499 * Then let's acquire something more useful from the pool. */
500 r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
6a7a4e4d
LP
501 if (r < 0)
502 return log_link_error_errno(link, r, "Failed to acquire address from pool: %m");
11bf3cce 503 if (r == 0) {
79008bdd 504 log_link_error(link, "Couldn't find free address for interface, all taken.");
11bf3cce
LP
505 return -EBUSY;
506 }
507
508 if (original->family == AF_INET) {
d076c6f9 509 /* Pick first address in range for ourselves ... */
11bf3cce
LP
510 in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
511
512 /* .. and use last as broadcast address */
e87e2b78
SS
513 if (original->prefixlen > 30)
514 broadcast.s_addr = 0;
515 else
516 broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
11bf3cce
LP
517 } else if (original->family == AF_INET6)
518 in_addr.in6.s6_addr[15] |= 1;
519
f0213e37 520 r = address_new(&na);
11bf3cce
LP
521 if (r < 0)
522 return r;
523
524 na->family = original->family;
525 na->prefixlen = original->prefixlen;
526 na->scope = original->scope;
527 na->cinfo = original->cinfo;
528
529 if (original->label) {
530 na->label = strdup(original->label);
0099bc15 531 if (!na->label)
11bf3cce 532 return -ENOMEM;
11bf3cce
LP
533 }
534
535 na->broadcast = broadcast;
536 na->in_addr = in_addr;
537
538 LIST_PREPEND(addresses, link->pool_addresses, na);
539
1cc6c93a 540 *ret = TAKE_PTR(na);
0099bc15 541
11bf3cce
LP
542 return 0;
543}
544
1b566071
LP
545int address_configure(
546 Address *address,
547 Link *link,
548 sd_netlink_message_handler_t callback,
549 bool update) {
550
4afd3348 551 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
f579559b
TG
552 int r;
553
c166a070 554 assert(address);
4c701096 555 assert(IN_SET(address->family, AF_INET, AF_INET6));
c166a070
TG
556 assert(link);
557 assert(link->ifindex > 0);
f882c247 558 assert(link->manager);
c166a070 559 assert(link->manager->rtnl);
f882c247 560
1b566071
LP
561 /* If this is a new address, then refuse adding more than the limit */
562 if (address_get(link, address->family, &address->in_addr, address->prefixlen, NULL) <= 0 &&
563 set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
564 return -E2BIG;
565
11bf3cce
LP
566 r = address_acquire(link, address, &address);
567 if (r < 0)
568 return r;
569
66669078
TG
570 if (update)
571 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
572 link->ifindex, address->family);
573 else
574 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
575 link->ifindex, address->family);
eb56eb9b
MS
576 if (r < 0)
577 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
f579559b 578
5a723174 579 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
eb56eb9b
MS
580 if (r < 0)
581 return log_error_errno(r, "Could not set prefixlen: %m");
5a723174 582
851c9f82
PF
583 address->flags |= IFA_F_PERMANENT;
584
e63be084
SS
585 if (address->home_address)
586 address->flags |= IFA_F_HOMEADDRESS;
587
588 if (address->duplicate_address_detection)
589 address->flags |= IFA_F_NODAD;
590
591 if (address->manage_temporary_address)
592 address->flags |= IFA_F_MANAGETEMPADDR;
593
594 if (address->prefix_route)
595 address->flags |= IFA_F_NOPREFIXROUTE;
596
597 if (address->autojoin)
598 address->flags |= IFA_F_MCAUTOJOIN;
599
851c9f82 600 r = sd_rtnl_message_addr_set_flags(req, (address->flags & 0xff));
eb56eb9b
MS
601 if (r < 0)
602 return log_error_errno(r, "Could not set flags: %m");
5a723174 603
851c9f82 604 if (address->flags & ~0xff) {
1c4baffc 605 r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags);
851c9f82
PF
606 if (r < 0)
607 return log_error_errno(r, "Could not set extended flags: %m");
608 }
609
5c1d3fc9 610 r = sd_rtnl_message_addr_set_scope(req, address->scope);
eb56eb9b
MS
611 if (r < 0)
612 return log_error_errno(r, "Could not set scope: %m");
5a723174 613
0a0dc69b 614 if (address->family == AF_INET)
1c4baffc 615 r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
0a0dc69b 616 else if (address->family == AF_INET6)
1c4baffc 617 r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
eb56eb9b
MS
618 if (r < 0)
619 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
f579559b 620
af93291c 621 if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
c081882f 622 if (address->family == AF_INET)
1c4baffc 623 r = sd_netlink_message_append_in_addr(req, IFA_ADDRESS, &address->in_addr_peer.in);
c081882f 624 else if (address->family == AF_INET6)
1c4baffc 625 r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6);
eb56eb9b
MS
626 if (r < 0)
627 return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
c081882f
SS
628 } else {
629 if (address->family == AF_INET) {
e87e2b78
SS
630 if (address->prefixlen <= 30) {
631 r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
632 if (r < 0)
633 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
634 }
c081882f 635 }
f579559b
TG
636 }
637
638 if (address->label) {
1c4baffc 639 r = sd_netlink_message_append_string(req, IFA_LABEL, address->label);
eb56eb9b
MS
640 if (r < 0)
641 return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
f579559b
TG
642 }
643
1c4baffc 644 r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO,
68ceb9df 645 &address->cinfo);
eb56eb9b
MS
646 if (r < 0)
647 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
68ceb9df 648
fcf50cff 649 r = address_establish(address, link);
eb56eb9b 650 if (r < 0)
fcf50cff
TG
651 return r;
652
653 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
654 if (r < 0) {
655 address_release(address);
eb56eb9b 656 return log_error_errno(r, "Could not send rtnetlink message: %m");
fcf50cff 657 }
f579559b 658
563c69c6
TG
659 link_ref(link);
660
adda1ed9
TG
661 r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
662 if (r < 0) {
663 address_release(address);
664 return log_error_errno(r, "Could not add address: %m");
665 }
666
f579559b
TG
667 return 0;
668}
669
44e7b949
LP
670int config_parse_broadcast(
671 const char *unit,
eb0ea358
TG
672 const char *filename,
673 unsigned line,
674 const char *section,
675 unsigned section_line,
676 const char *lvalue,
677 int ltype,
678 const char *rvalue,
679 void *data,
680 void *userdata) {
44e7b949 681
eb0ea358
TG
682 Network *network = userdata;
683 _cleanup_address_free_ Address *n = NULL;
eb0ea358
TG
684 int r;
685
686 assert(filename);
687 assert(section);
688 assert(lvalue);
689 assert(rvalue);
690 assert(data);
691
f4859fc7 692 r = address_new_static(network, filename, section_line, &n);
eb0ea358
TG
693 if (r < 0)
694 return r;
695
482e2ac1 696 if (n->family == AF_INET6) {
12ca818f 697 log_syntax(unit, LOG_ERR, filename, line, 0, "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
482e2ac1
TG
698 return 0;
699 }
700
44e7b949 701 r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
eb0ea358 702 if (r < 0) {
12ca818f 703 log_syntax(unit, LOG_ERR, filename, line, r, "Broadcast is invalid, ignoring assignment: %s", rvalue);
eb0ea358
TG
704 return 0;
705 }
706
44e7b949 707 n->family = AF_INET;
eb0ea358
TG
708 n = NULL;
709
710 return 0;
711}
712
f579559b
TG
713int config_parse_address(const char *unit,
714 const char *filename,
715 unsigned line,
716 const char *section,
71a61510 717 unsigned section_line,
f579559b
TG
718 const char *lvalue,
719 int ltype,
720 const char *rvalue,
721 void *data,
722 void *userdata) {
44e7b949 723
6ae115c1 724 Network *network = userdata;
f579559b 725 _cleanup_address_free_ Address *n = NULL;
44e7b949
LP
726 const char *address, *e;
727 union in_addr_union buffer;
728 int r, f;
f579559b
TG
729
730 assert(filename);
6ae115c1 731 assert(section);
f579559b
TG
732 assert(lvalue);
733 assert(rvalue);
734 assert(data);
735
92fe133a
TG
736 if (streq(section, "Network")) {
737 /* we are not in an Address section, so treat
738 * this as the special '0' section */
f4859fc7
SS
739 r = address_new_static(network, NULL, 0, &n);
740 } else
741 r = address_new_static(network, filename, section_line, &n);
92fe133a 742
f579559b
TG
743 if (r < 0)
744 return r;
745
746 /* Address=address/prefixlen */
747
748 /* prefixlen */
749 e = strchr(rvalue, '/');
750 if (e) {
751 unsigned i;
12ca818f 752
f579559b
TG
753 r = safe_atou(e + 1, &i);
754 if (r < 0) {
12ca818f 755 log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is invalid, ignoring assignment: %s", e + 1);
f579559b
TG
756 return 0;
757 }
758
759 n->prefixlen = (unsigned char) i;
8cd11a0f 760
44e7b949
LP
761 address = strndupa(rvalue, e - rvalue);
762 } else
763 address = rvalue;
f579559b 764
44e7b949 765 r = in_addr_from_string_auto(address, &f, &buffer);
f579559b 766 if (r < 0) {
12ca818f 767 log_syntax(unit, LOG_ERR, filename, line, r, "Address is invalid, ignoring assignment: %s", address);
f579559b
TG
768 return 0;
769 }
770
a2a85a22 771 if (!e && f == AF_INET) {
5a941f5f 772 r = in4_addr_default_prefixlen(&buffer.in, &n->prefixlen);
a2a85a22 773 if (r < 0) {
87ac8d99 774 log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length not specified, and a default one cannot be deduced for '%s', ignoring assignment", address);
a2a85a22
TG
775 return 0;
776 }
777 }
778
44e7b949 779 if (n->family != AF_UNSPEC && f != n->family) {
12ca818f 780 log_syntax(unit, LOG_ERR, filename, line, 0, "Address is incompatible, ignoring assignment: %s", address);
44e7b949
LP
781 return 0;
782 }
783
784 n->family = f;
785
786 if (streq(lvalue, "Address"))
787 n->in_addr = buffer;
788 else
789 n->in_addr_peer = buffer;
790
791 if (n->family == AF_INET && n->broadcast.s_addr == 0)
792 n->broadcast.s_addr = n->in_addr.in.s_addr | htonl(0xfffffffflu >> n->prefixlen);
eb0ea358 793
f579559b
TG
794 n = NULL;
795
796 return 0;
797}
6ae115c1 798
d31645ad
LP
799int config_parse_label(
800 const char *unit,
6ae115c1
TG
801 const char *filename,
802 unsigned line,
803 const char *section,
804 unsigned section_line,
805 const char *lvalue,
806 int ltype,
807 const char *rvalue,
808 void *data,
809 void *userdata) {
d31645ad 810
6ae115c1 811 _cleanup_address_free_ Address *n = NULL;
d31645ad 812 Network *network = userdata;
6ae115c1
TG
813 int r;
814
815 assert(filename);
816 assert(section);
817 assert(lvalue);
818 assert(rvalue);
819 assert(data);
820
f4859fc7 821 r = address_new_static(network, filename, section_line, &n);
6ae115c1
TG
822 if (r < 0)
823 return r;
824
a87d19fe
SS
825 if (!address_label_valid(rvalue)) {
826 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is too long or invalid, ignoring assignment: %s", rvalue);
6ae115c1
TG
827 return 0;
828 }
829
d31645ad
LP
830 r = free_and_strdup(&n->label, rvalue);
831 if (r < 0)
832 return log_oom();
6ae115c1
TG
833
834 n = NULL;
835
836 return 0;
837}
ce6c77eb 838
b5834a0b
SS
839int config_parse_lifetime(const char *unit,
840 const char *filename,
841 unsigned line,
842 const char *section,
843 unsigned section_line,
844 const char *lvalue,
845 int ltype,
846 const char *rvalue,
847 void *data,
848 void *userdata) {
849 Network *network = userdata;
850 _cleanup_address_free_ Address *n = NULL;
851 unsigned k;
852 int r;
853
854 assert(filename);
855 assert(section);
856 assert(lvalue);
857 assert(rvalue);
858 assert(data);
859
f4859fc7 860 r = address_new_static(network, filename, section_line, &n);
b5834a0b
SS
861 if (r < 0)
862 return r;
863
864 if (STR_IN_SET(rvalue, "forever", "infinity")) {
865 n->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
866 n = NULL;
867
868 return 0;
869 }
870
871 r = safe_atou(rvalue, &k);
872 if (r < 0) {
873 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse PreferredLifetime, ignoring: %s", rvalue);
874 return 0;
875 }
876
877 if (k != 0)
878 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid PreferredLifetime value, ignoring: %d", k);
879 else {
880 n->cinfo.ifa_prefered = k;
881 n = NULL;
882 }
883
884 return 0;
885}
886
e63be084
SS
887int config_parse_address_flags(const char *unit,
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) {
897 Network *network = userdata;
898 _cleanup_address_free_ Address *n = NULL;
899 int r;
900
901 assert(filename);
902 assert(section);
903 assert(lvalue);
904 assert(rvalue);
905 assert(data);
906
f4859fc7 907 r = address_new_static(network, filename, section_line, &n);
e63be084
SS
908 if (r < 0)
909 return r;
910
911 r = parse_boolean(rvalue);
912 if (r < 0) {
913 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address flag, ignoring: %s", rvalue);
914 return 0;
915 }
916
917 if (streq(lvalue, "HomeAddress"))
918 n->home_address = r;
919 else if (streq(lvalue, "DuplicateAddressDetection"))
920 n->duplicate_address_detection = r;
921 else if (streq(lvalue, "ManageTemporaryAddress"))
922 n->manage_temporary_address = r;
923 else if (streq(lvalue, "PrefixRoute"))
924 n->prefix_route = r;
925 else if (streq(lvalue, "AutoJoin"))
926 n->autojoin = r;
927
928 return 0;
929}
930
2959fb07
SS
931int config_parse_address_scope(const char *unit,
932 const char *filename,
933 unsigned line,
934 const char *section,
935 unsigned section_line,
936 const char *lvalue,
937 int ltype,
938 const char *rvalue,
939 void *data,
940 void *userdata) {
941 Network *network = userdata;
942 _cleanup_address_free_ Address *n = NULL;
943 int r;
944
945 assert(filename);
946 assert(section);
947 assert(lvalue);
948 assert(rvalue);
949 assert(data);
950
951 r = address_new_static(network, filename, section_line, &n);
952 if (r < 0)
953 return r;
954
955 if (streq(rvalue, "host"))
956 n->scope = RT_SCOPE_HOST;
957 else if (streq(rvalue, "link"))
958 n->scope = RT_SCOPE_LINK;
959 else if (streq(rvalue, "global"))
960 n->scope = RT_SCOPE_UNIVERSE;
961 else {
962 r = safe_atou8(rvalue , &n->scope);
963 if (r < 0) {
964 log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse address scope \"%s\", ignoring assignment: %m", rvalue);
965 return 0;
966 }
967 }
968
969 n = NULL;
970
971 return 0;
972}
973
ce6c77eb
TG
974bool address_is_ready(const Address *a) {
975 assert(a);
976
b7ed5384
SS
977 if (a->family == AF_INET6)
978 return !(a->flags & IFA_F_TENTATIVE);
979 else
980 return !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED));
ce6c77eb 981}