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