]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-address.c
Add SPDX license identifiers to source files under the LGPL
[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
155 /* fallthrough */
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
205 /* fall-through */
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 */
517 broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
518 } else if (original->family == AF_INET6)
519 in_addr.in6.s6_addr[15] |= 1;
520
f0213e37 521 r = address_new(&na);
11bf3cce
LP
522 if (r < 0)
523 return r;
524
525 na->family = original->family;
526 na->prefixlen = original->prefixlen;
527 na->scope = original->scope;
528 na->cinfo = original->cinfo;
529
530 if (original->label) {
531 na->label = strdup(original->label);
0099bc15 532 if (!na->label)
11bf3cce 533 return -ENOMEM;
11bf3cce
LP
534 }
535
536 na->broadcast = broadcast;
537 na->in_addr = in_addr;
538
539 LIST_PREPEND(addresses, link->pool_addresses, na);
540
541 *ret = na;
0099bc15
SS
542 na = NULL;
543
11bf3cce
LP
544 return 0;
545}
546
1b566071
LP
547int address_configure(
548 Address *address,
549 Link *link,
550 sd_netlink_message_handler_t callback,
551 bool update) {
552
4afd3348 553 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
f579559b
TG
554 int r;
555
c166a070 556 assert(address);
4c701096 557 assert(IN_SET(address->family, AF_INET, AF_INET6));
c166a070
TG
558 assert(link);
559 assert(link->ifindex > 0);
f882c247 560 assert(link->manager);
c166a070 561 assert(link->manager->rtnl);
f882c247 562
1b566071
LP
563 /* If this is a new address, then refuse adding more than the limit */
564 if (address_get(link, address->family, &address->in_addr, address->prefixlen, NULL) <= 0 &&
565 set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
566 return -E2BIG;
567
11bf3cce
LP
568 r = address_acquire(link, address, &address);
569 if (r < 0)
570 return r;
571
66669078
TG
572 if (update)
573 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
574 link->ifindex, address->family);
575 else
576 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
577 link->ifindex, address->family);
eb56eb9b
MS
578 if (r < 0)
579 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
f579559b 580
5a723174 581 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
eb56eb9b
MS
582 if (r < 0)
583 return log_error_errno(r, "Could not set prefixlen: %m");
5a723174 584
851c9f82
PF
585 address->flags |= IFA_F_PERMANENT;
586
e63be084
SS
587 if (address->home_address)
588 address->flags |= IFA_F_HOMEADDRESS;
589
590 if (address->duplicate_address_detection)
591 address->flags |= IFA_F_NODAD;
592
593 if (address->manage_temporary_address)
594 address->flags |= IFA_F_MANAGETEMPADDR;
595
596 if (address->prefix_route)
597 address->flags |= IFA_F_NOPREFIXROUTE;
598
599 if (address->autojoin)
600 address->flags |= IFA_F_MCAUTOJOIN;
601
851c9f82 602 r = sd_rtnl_message_addr_set_flags(req, (address->flags & 0xff));
eb56eb9b
MS
603 if (r < 0)
604 return log_error_errno(r, "Could not set flags: %m");
5a723174 605
851c9f82 606 if (address->flags & ~0xff) {
1c4baffc 607 r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags);
851c9f82
PF
608 if (r < 0)
609 return log_error_errno(r, "Could not set extended flags: %m");
610 }
611
5c1d3fc9 612 r = sd_rtnl_message_addr_set_scope(req, address->scope);
eb56eb9b
MS
613 if (r < 0)
614 return log_error_errno(r, "Could not set scope: %m");
5a723174 615
0a0dc69b 616 if (address->family == AF_INET)
1c4baffc 617 r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
0a0dc69b 618 else if (address->family == AF_INET6)
1c4baffc 619 r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
eb56eb9b
MS
620 if (r < 0)
621 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
f579559b 622
af93291c 623 if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
c081882f 624 if (address->family == AF_INET)
1c4baffc 625 r = sd_netlink_message_append_in_addr(req, IFA_ADDRESS, &address->in_addr_peer.in);
c081882f 626 else if (address->family == AF_INET6)
1c4baffc 627 r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6);
eb56eb9b
MS
628 if (r < 0)
629 return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
c081882f
SS
630 } else {
631 if (address->family == AF_INET) {
1c4baffc 632 r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
eb56eb9b
MS
633 if (r < 0)
634 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
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) {
12ca818f 774 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
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
63bbe5c7 977 return !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED));
ce6c77eb 978}
057abfd8 979
7d5cac19
PF
980int config_parse_router_preference(const char *unit,
981 const char *filename,
982 unsigned line,
983 const char *section,
984 unsigned section_line,
985 const char *lvalue,
986 int ltype,
987 const char *rvalue,
988 void *data,
989 void *userdata) {
990 Network *network = userdata;
991
992 assert(filename);
993 assert(section);
994 assert(lvalue);
995 assert(rvalue);
996 assert(data);
997
998 if (streq(rvalue, "high"))
999 network->router_preference = SD_NDISC_PREFERENCE_HIGH;
1000 else if (STR_IN_SET(rvalue, "medium", "normal", "default"))
1001 network->router_preference = SD_NDISC_PREFERENCE_MEDIUM;
1002 else if (streq(rvalue, "low"))
1003 network->router_preference = SD_NDISC_PREFERENCE_LOW;
1004 else
1005 log_syntax(unit, LOG_ERR, filename, line, -EINVAL, "Router preference '%s' is invalid, ignoring assignment: %m", rvalue);
1006
1007 return 0;
1008}
1009
057abfd8
PF
1010void prefix_free(Prefix *prefix) {
1011 if (!prefix)
1012 return;
1013
1014 if (prefix->network) {
1015 LIST_REMOVE(prefixes, prefix->network->static_prefixes, prefix);
1016 assert(prefix->network->n_static_prefixes > 0);
1017 prefix->network->n_static_prefixes--;
1018
1019 if (prefix->section)
1020 hashmap_remove(prefix->network->prefixes_by_section,
1021 prefix->section);
1022 }
1023
9d5d0090
PF
1024 prefix->radv_prefix = sd_radv_prefix_unref(prefix->radv_prefix);
1025
057abfd8
PF
1026 free(prefix);
1027}
1028
1029int prefix_new(Prefix **ret) {
1030 Prefix *prefix = NULL;
1031
1032 prefix = new0(Prefix, 1);
1033 if (!prefix)
1034 return -ENOMEM;
1035
9d5d0090
PF
1036 if (sd_radv_prefix_new(&prefix->radv_prefix) < 0)
1037 return -ENOMEM;
1038
057abfd8
PF
1039 *ret = prefix;
1040 prefix = NULL;
1041
1042 return 0;
1043}
1044
1045int prefix_new_static(Network *network, const char *filename,
1046 unsigned section_line, Prefix **ret) {
1047 _cleanup_network_config_section_free_ NetworkConfigSection *n = NULL;
1048 _cleanup_prefix_free_ Prefix *prefix = NULL;
1049 int r;
1050
1051 assert(network);
1052 assert(ret);
1053 assert(!!filename == (section_line > 0));
1054
1055 if (filename) {
1056 r = network_config_section_new(filename, section_line, &n);
1057 if (r < 0)
1058 return r;
1059
1060 if (section_line) {
1061 prefix = hashmap_get(network->prefixes_by_section, n);
1062 if (prefix) {
1063 *ret = prefix;
1064 prefix = NULL;
1065
1066 return 0;
1067 }
1068 }
1069 }
1070
1071 r = prefix_new(&prefix);
1072 if (r < 0)
1073 return r;
1074
1075 if (filename) {
1076 prefix->section = n;
1077 n = NULL;
1078
1079 r = hashmap_put(network->prefixes_by_section, prefix->section,
1080 prefix);
1081 if (r < 0)
1082 return r;
1083 }
1084
1085 prefix->network = network;
1086 LIST_APPEND(prefixes, network->static_prefixes, prefix);
1087 network->n_static_prefixes++;
1088
1089 *ret = prefix;
1090 prefix = NULL;
1091
1092 return 0;
1093}
9d5d0090
PF
1094
1095int config_parse_prefix(const char *unit,
1096 const char *filename,
1097 unsigned line,
1098 const char *section,
1099 unsigned section_line,
1100 const char *lvalue,
1101 int ltype,
1102 const char *rvalue,
1103 void *data,
1104 void *userdata) {
1105
1106 Network *network = userdata;
1107 _cleanup_prefix_free_ Prefix *p = NULL;
1108 uint8_t prefixlen = 64;
1109 union in_addr_union in6addr;
1110 int r;
1111
1112 assert(filename);
1113 assert(section);
1114 assert(lvalue);
1115 assert(rvalue);
1116 assert(data);
1117
1118 r = prefix_new_static(network, filename, section_line, &p);
1119 if (r < 0)
1120 return r;
1121
1122 r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen);
1123 if (r < 0) {
1124 log_syntax(unit, LOG_ERR, filename, line, r, "Prefix is invalid, ignoring assignment: %s", rvalue);
1125 return 0;
1126 }
1127
1128 if (sd_radv_prefix_set_prefix(p->radv_prefix, &in6addr.in6, prefixlen) < 0)
1129 return -EADDRNOTAVAIL;
1130
1131 log_syntax(unit, LOG_INFO, filename, line, r, "Found prefix %s", rvalue);
1132
1133 p = NULL;
1134
1135 return 0;
1136}
1137
1138int config_parse_prefix_flags(const char *unit,
1139 const char *filename,
1140 unsigned line,
1141 const char *section,
1142 unsigned section_line,
1143 const char *lvalue,
1144 int ltype,
1145 const char *rvalue,
1146 void *data,
1147 void *userdata) {
1148 Network *network = userdata;
1149 _cleanup_prefix_free_ Prefix *p = NULL;
1150 int r, val;
1151
1152 assert(filename);
1153 assert(section);
1154 assert(lvalue);
1155 assert(rvalue);
1156 assert(data);
1157
1158 r = prefix_new_static(network, filename, section_line, &p);
1159 if (r < 0)
1160 return r;
1161
1162 r = parse_boolean(rvalue);
1163 if (r < 0) {
1164 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address flag, ignoring: %s", rvalue);
1165 return 0;
1166 }
1167
1168 val = r;
1169
1170 if (streq(lvalue, "OnLink"))
1171 r = sd_radv_prefix_set_onlink(p->radv_prefix, val);
1172 else if (streq(lvalue, "AddressAutoconfiguration"))
1173 r = sd_radv_prefix_set_address_autoconfiguration(p->radv_prefix, val);
1174 if (r < 0)
1175 return r;
1176
1177 p = NULL;
1178
1179 return 0;
1180}
1181
1182int config_parse_prefix_lifetime(const char *unit,
1183 const char *filename,
1184 unsigned line,
1185 const char *section,
1186 unsigned section_line,
1187 const char *lvalue,
1188 int ltype,
1189 const char *rvalue,
1190 void *data,
1191 void *userdata) {
1192 Network *network = userdata;
1193 _cleanup_prefix_free_ Prefix *p = NULL;
1194 usec_t usec;
1195 int r;
1196
1197 assert(filename);
1198 assert(section);
1199 assert(lvalue);
1200 assert(rvalue);
1201 assert(data);
1202
1203 r = prefix_new_static(network, filename, section_line, &p);
1204 if (r < 0)
1205 return r;
1206
1207 r = parse_sec(rvalue, &usec);
1208 if (r < 0) {
1209 log_syntax(unit, LOG_ERR, filename, line, r, "Lifetime is invalid, ignoring assignment: %s", rvalue);
1210 return 0;
1211 }
1212
301a2fb9 1213 /* a value of 0xffffffff represents infinity */
9d5d0090
PF
1214 if (streq(lvalue, "PreferredLifetimeSec"))
1215 r = sd_radv_prefix_set_preferred_lifetime(p->radv_prefix,
6abd0ef3 1216 DIV_ROUND_UP(usec, USEC_PER_SEC));
9d5d0090
PF
1217 else if (streq(lvalue, "ValidLifetimeSec"))
1218 r = sd_radv_prefix_set_valid_lifetime(p->radv_prefix,
6abd0ef3 1219 DIV_ROUND_UP(usec, USEC_PER_SEC));
9d5d0090
PF
1220 if (r < 0)
1221 return r;
1222
1223 p = NULL;
1224
1225 return 0;
2959fb07 1226}