]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-address.c
Merge pull request #6420 from keszybz/gateway-name
[thirdparty/systemd.git] / src / network / networkd-address.c
CommitLineData
f579559b
TG
1/***
2 This file is part of systemd.
3
4 Copyright 2013 Tom Gundersen <teg@jklm.no>
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
20#include <net/if.h>
21
b5efdb8a 22#include "alloc-util.h"
f579559b 23#include "conf-parser.h"
12c2884c 24#include "firewall-util.h"
fc2f9534 25#include "netlink-util.h"
6bedfcbb 26#include "networkd-address.h"
23f53b99 27#include "networkd-manager.h"
6bedfcbb 28#include "parse-util.h"
3ac8e543 29#include "set.h"
d31645ad 30#include "socket-util.h"
07630cea 31#include "string-util.h"
3ac8e543
TG
32#include "utf8.h"
33#include "util.h"
f579559b 34
1b566071 35#define ADDRESSES_PER_LINK_MAX 2048U
8c34b963
LP
36#define STATIC_ADDRESSES_PER_NETWORK_MAX 1024U
37
f0213e37
TG
38int address_new(Address **ret) {
39 _cleanup_address_free_ Address *address = NULL;
40
41 address = new0(Address, 1);
42 if (!address)
43 return -ENOMEM;
aba496a5
UTL
44
45 address->family = AF_UNSPEC;
46 address->scope = RT_SCOPE_UNIVERSE;
47 address->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
48 address->cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME;
f0213e37
TG
49
50 *ret = address;
51 address = NULL;
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
TG
71 if (address) {
72 *ret = address;
73 address = NULL;
74
75 return 0;
76 }
77 }
78
8c34b963
LP
79 if (network->n_static_addresses >= STATIC_ADDRESSES_PER_NETWORK_MAX)
80 return -E2BIG;
81
f0213e37
TG
82 r = address_new(&address);
83 if (r < 0)
84 return r;
801bd9e8 85
48317c39 86 if (filename) {
f4859fc7 87 address->section = n;
fcc48287
SS
88 n = NULL;
89
f7fe70ea
SS
90 r = hashmap_put(network->addresses_by_section, address->section, address);
91 if (r < 0)
92 return r;
6ae115c1
TG
93 }
94
5215524d
SS
95 address->network = network;
96 LIST_APPEND(addresses, network->static_addresses, address);
8c34b963 97 network->n_static_addresses++;
5215524d 98
f579559b
TG
99 *ret = address;
100 address = NULL;
101
102 return 0;
103}
104
105void address_free(Address *address) {
106 if (!address)
107 return;
108
f048a16b 109 if (address->network) {
3d3d4255 110 LIST_REMOVE(addresses, address->network->static_addresses, address);
8c34b963
LP
111 assert(address->network->n_static_addresses > 0);
112 address->network->n_static_addresses--;
f579559b 113
f4859fc7
SS
114 if (address->section) {
115 hashmap_remove(address->network->addresses_by_section, address->section);
116 network_config_section_free(address->section);
117 }
f048a16b 118 }
6ae115c1 119
adda1ed9 120 if (address->link) {
cf1d700d 121 set_remove(address->link->addresses, address);
adda1ed9 122 set_remove(address->link->addresses_foreign, address);
f150100a
SS
123
124 if (in_addr_equal(AF_INET6, &address->in_addr, (const union in_addr_union *) &address->link->ipv6ll_address))
125 memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr));
adda1ed9 126 }
cf1d700d 127
f579559b
TG
128 free(address);
129}
130
3ac8e543
TG
131static void address_hash_func(const void *b, struct siphash *state) {
132 const Address *a = b;
133
134 assert(a);
135
136 siphash24_compress(&a->family, sizeof(a->family), state);
137
138 switch (a->family) {
139 case AF_INET:
140 siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
141
142 /* peer prefix */
143 if (a->prefixlen != 0) {
144 uint32_t prefix;
145
146 if (a->in_addr_peer.in.s_addr != 0)
147 prefix = be32toh(a->in_addr_peer.in.s_addr) >> (32 - a->prefixlen);
148 else
149 prefix = be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
150
151 siphash24_compress(&prefix, sizeof(prefix), state);
152 }
153
154 /* fallthrough */
155 case AF_INET6:
156 /* local address */
157 siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
158
159 break;
160 default:
161 /* treat any other address family as AF_UNSPEC */
162 break;
163 }
164}
165
166static int address_compare_func(const void *c1, const void *c2) {
167 const Address *a1 = c1, *a2 = c2;
168
169 if (a1->family < a2->family)
170 return -1;
171 if (a1->family > a2->family)
172 return 1;
173
174 switch (a1->family) {
175 /* use the same notion of equality as the kernel does */
176 case AF_INET:
177 if (a1->prefixlen < a2->prefixlen)
178 return -1;
179 if (a1->prefixlen > a2->prefixlen)
180 return 1;
181
182 /* compare the peer prefixes */
183 if (a1->prefixlen != 0) {
184 /* make sure we don't try to shift by 32.
185 * See ISO/IEC 9899:TC3 § 6.5.7.3. */
186 uint32_t b1, b2;
187
188 if (a1->in_addr_peer.in.s_addr != 0)
189 b1 = be32toh(a1->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
190 else
191 b1 = be32toh(a1->in_addr.in.s_addr) >> (32 - a1->prefixlen);
192
193 if (a2->in_addr_peer.in.s_addr != 0)
194 b2 = be32toh(a2->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
195 else
196 b2 = be32toh(a2->in_addr.in.s_addr) >> (32 - a1->prefixlen);
197
198 if (b1 < b2)
199 return -1;
200 if (b1 > b2)
201 return 1;
202 }
203
204 /* fall-through */
205 case AF_INET6:
206 return memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
207 default:
208 /* treat any other address family as AF_UNSPEC */
209 return 0;
210 }
211}
212
213static const struct hash_ops address_hash_ops = {
214 .hash = address_hash_func,
215 .compare = address_compare_func
216};
217
218bool address_equal(Address *a1, Address *a2) {
219 if (a1 == a2)
220 return true;
221
222 if (!a1 || !a2)
223 return false;
224
225 return address_compare_func(a1, a2) == 0;
226}
227
91b5f997
TG
228static int address_establish(Address *address, Link *link) {
229 bool masq;
230 int r;
231
232 assert(address);
233 assert(link);
234
235 masq = link->network &&
fcf50cff
TG
236 link->network->ip_masquerade &&
237 address->family == AF_INET &&
238 address->scope < RT_SCOPE_LINK;
91b5f997
TG
239
240 /* Add firewall entry if this is requested */
241 if (address->ip_masquerade_done != masq) {
242 union in_addr_union masked = address->in_addr;
243 in_addr_mask(address->family, &masked, address->prefixlen);
244
245 r = fw_add_masquerade(masq, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
246 if (r < 0)
247 log_link_warning_errno(link, r, "Could not enable IP masquerading: %m");
248
249 address->ip_masquerade_done = masq;
250 }
251
252 return 0;
253}
254
adda1ed9
TG
255static int address_add_internal(Link *link, Set **addresses,
256 int family,
257 const union in_addr_union *in_addr,
258 unsigned char prefixlen,
259 Address **ret) {
054f0db4 260 _cleanup_address_free_ Address *address = NULL;
cf1d700d
TG
261 int r;
262
263 assert(link);
adda1ed9 264 assert(addresses);
054f0db4 265 assert(in_addr);
054f0db4
TG
266
267 r = address_new(&address);
268 if (r < 0)
269 return r;
270
271 address->family = family;
272 address->in_addr = *in_addr;
273 address->prefixlen = prefixlen;
63bbe5c7
TG
274 /* Consider address tentative until we get the real flags from the kernel */
275 address->flags = IFA_F_TENTATIVE;
cf1d700d 276
adda1ed9 277 r = set_ensure_allocated(addresses, &address_hash_ops);
cf1d700d
TG
278 if (r < 0)
279 return r;
280
adda1ed9 281 r = set_put(*addresses, address);
cf1d700d
TG
282 if (r < 0)
283 return r;
284
285 address->link = link;
286
adda1ed9
TG
287 if (ret)
288 *ret = address;
289
054f0db4
TG
290 address = NULL;
291
cf1d700d
TG
292 return 0;
293}
294
adda1ed9
TG
295int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
296 return address_add_internal(link, &link->addresses_foreign, family, in_addr, prefixlen, ret);
297}
298
c4a03a56 299int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
cab974b0 300 Address *address;
e7780c8d
TG
301 int r;
302
cab974b0
TG
303 r = address_get(link, family, in_addr, prefixlen, &address);
304 if (r == -ENOENT) {
305 /* Address does not exist, create a new one */
306 r = address_add_internal(link, &link->addresses, family, in_addr, prefixlen, &address);
307 if (r < 0)
308 return r;
309 } else if (r == 0) {
310 /* Take over a foreign address */
311 r = set_ensure_allocated(&link->addresses, &address_hash_ops);
312 if (r < 0)
313 return r;
314
315 r = set_put(link->addresses, address);
316 if (r < 0)
317 return r;
318
319 set_remove(link->addresses_foreign, address);
320 } else if (r == 1) {
321 /* Already exists, do nothing */
322 ;
323 } else
e7780c8d
TG
324 return r;
325
cab974b0
TG
326 if (ret)
327 *ret = address;
e7780c8d
TG
328
329 return 0;
adda1ed9
TG
330}
331
fcf50cff 332static int address_release(Address *address) {
5a8bcb67
LP
333 int r;
334
335 assert(address);
fcf50cff 336 assert(address->link);
5a8bcb67 337
91b5f997
TG
338 /* Remove masquerading firewall entry if it was added */
339 if (address->ip_masquerade_done) {
5a8bcb67
LP
340 union in_addr_union masked = address->in_addr;
341 in_addr_mask(address->family, &masked, address->prefixlen);
342
91b5f997 343 r = fw_add_masquerade(false, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
5a8bcb67 344 if (r < 0)
fcf50cff 345 log_link_warning_errno(address->link, r, "Failed to disable IP masquerading: %m");
5a8bcb67 346
91b5f997 347 address->ip_masquerade_done = false;
5a8bcb67
LP
348 }
349
350 return 0;
351}
352
889b550f
LP
353int address_update(
354 Address *address,
355 unsigned char flags,
356 unsigned char scope,
357 const struct ifa_cacheinfo *cinfo) {
358
36c32f61 359 bool ready;
e7ab854c 360 int r;
36c32f61
TG
361
362 assert(address);
363 assert(cinfo);
7209086d
SS
364 assert_return(address->link, 1);
365
366 if (IN_SET(address->link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
367 return 1;
36c32f61
TG
368
369 ready = address_is_ready(address);
370
371 address->flags = flags;
372 address->scope = scope;
373 address->cinfo = *cinfo;
374
7209086d
SS
375 link_update_operstate(address->link);
376
377 if (!ready && address_is_ready(address)) {
378 link_check_ready(address->link);
379
380 if (address->family == AF_INET6 &&
381 in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 &&
382 in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) {
383
384 r = link_ipv6ll_gained(address->link, &address->in_addr.in6);
385 if (r < 0)
386 return r;
e7ab854c 387 }
a3a019e1 388 }
36c32f61
TG
389
390 return 0;
391}
392
91b5f997 393int address_drop(Address *address) {
8012cd39
TG
394 Link *link;
395 bool ready;
396
5a8bcb67 397 assert(address);
91b5f997 398
8012cd39
TG
399 ready = address_is_ready(address);
400 link = address->link;
401
fcf50cff 402 address_release(address);
91b5f997
TG
403 address_free(address);
404
84de38c5
TG
405 link_update_operstate(link);
406
8012cd39
TG
407 if (link && !ready)
408 link_check_ready(link);
409
91b5f997
TG
410 return 0;
411}
412
1b566071
LP
413int address_get(Link *link,
414 int family,
415 const union in_addr_union *in_addr,
416 unsigned char prefixlen,
417 Address **ret) {
418
419 Address address, *existing;
91b5f997 420
5a8bcb67 421 assert(link);
91b5f997 422 assert(in_addr);
5a8bcb67 423
1b566071
LP
424 address = (Address) {
425 .family = family,
426 .in_addr = *in_addr,
427 .prefixlen = prefixlen,
428 };
5a8bcb67 429
91b5f997 430 existing = set_get(link->addresses, &address);
cab974b0 431 if (existing) {
1b566071
LP
432 if (ret)
433 *ret = existing;
cab974b0 434 return 1;
adda1ed9 435 }
5a8bcb67 436
1b566071
LP
437 existing = set_get(link->addresses_foreign, &address);
438 if (existing) {
439 if (ret)
440 *ret = existing;
441 return 0;
442 }
5a8bcb67 443
1b566071 444 return -ENOENT;
5a8bcb67
LP
445}
446
483d099e
ZJS
447int address_remove(
448 Address *address,
449 Link *link,
450 sd_netlink_message_handler_t callback) {
451
4afd3348 452 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
407fe036
TG
453 int r;
454
455 assert(address);
456 assert(address->family == AF_INET || address->family == AF_INET6);
457 assert(link);
458 assert(link->ifindex > 0);
459 assert(link->manager);
460 assert(link->manager->rtnl);
461
151b9b96
LP
462 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
463 link->ifindex, address->family);
eb56eb9b
MS
464 if (r < 0)
465 return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m");
407fe036 466
5a723174 467 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
eb56eb9b
MS
468 if (r < 0)
469 return log_error_errno(r, "Could not set prefixlen: %m");
5a723174 470
407fe036 471 if (address->family == AF_INET)
1c4baffc 472 r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
407fe036 473 else if (address->family == AF_INET6)
1c4baffc 474 r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
eb56eb9b
MS
475 if (r < 0)
476 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
407fe036 477
1c4baffc 478 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
eb56eb9b
MS
479 if (r < 0)
480 return log_error_errno(r, "Could not send rtnetlink message: %m");
407fe036 481
563c69c6
TG
482 link_ref(link);
483
407fe036
TG
484 return 0;
485}
486
11bf3cce
LP
487static int address_acquire(Link *link, Address *original, Address **ret) {
488 union in_addr_union in_addr = {};
489 struct in_addr broadcast = {};
0099bc15 490 _cleanup_address_free_ Address *na = NULL;
11bf3cce
LP
491 int r;
492
493 assert(link);
494 assert(original);
495 assert(ret);
496
497 /* Something useful was configured? just use it */
af93291c 498 if (in_addr_is_null(original->family, &original->in_addr) <= 0)
11bf3cce
LP
499 return 0;
500
501 /* The address is configured to be 0.0.0.0 or [::] by the user?
502 * Then let's acquire something more useful from the pool. */
503 r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
6a7a4e4d
LP
504 if (r < 0)
505 return log_link_error_errno(link, r, "Failed to acquire address from pool: %m");
11bf3cce 506 if (r == 0) {
79008bdd 507 log_link_error(link, "Couldn't find free address for interface, all taken.");
11bf3cce
LP
508 return -EBUSY;
509 }
510
511 if (original->family == AF_INET) {
d076c6f9 512 /* Pick first address in range for ourselves ... */
11bf3cce
LP
513 in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
514
515 /* .. and use last as broadcast address */
516 broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
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
540 *ret = na;
0099bc15
SS
541 na = NULL;
542
11bf3cce
LP
543 return 0;
544}
545
1b566071
LP
546int address_configure(
547 Address *address,
548 Link *link,
549 sd_netlink_message_handler_t callback,
550 bool update) {
551
4afd3348 552 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
f579559b
TG
553 int r;
554
c166a070
TG
555 assert(address);
556 assert(address->family == AF_INET || address->family == AF_INET6);
557 assert(link);
558 assert(link->ifindex > 0);
f882c247 559 assert(link->manager);
c166a070 560 assert(link->manager->rtnl);
f882c247 561
1b566071
LP
562 /* If this is a new address, then refuse adding more than the limit */
563 if (address_get(link, address->family, &address->in_addr, address->prefixlen, NULL) <= 0 &&
564 set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
565 return -E2BIG;
566
11bf3cce
LP
567 r = address_acquire(link, address, &address);
568 if (r < 0)
569 return r;
570
66669078
TG
571 if (update)
572 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
573 link->ifindex, address->family);
574 else
575 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
576 link->ifindex, address->family);
eb56eb9b
MS
577 if (r < 0)
578 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
f579559b 579
5a723174 580 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
eb56eb9b
MS
581 if (r < 0)
582 return log_error_errno(r, "Could not set prefixlen: %m");
5a723174 583
851c9f82
PF
584 address->flags |= IFA_F_PERMANENT;
585
e63be084
SS
586 if (address->home_address)
587 address->flags |= IFA_F_HOMEADDRESS;
588
589 if (address->duplicate_address_detection)
590 address->flags |= IFA_F_NODAD;
591
592 if (address->manage_temporary_address)
593 address->flags |= IFA_F_MANAGETEMPADDR;
594
595 if (address->prefix_route)
596 address->flags |= IFA_F_NOPREFIXROUTE;
597
598 if (address->autojoin)
599 address->flags |= IFA_F_MCAUTOJOIN;
600
851c9f82 601 r = sd_rtnl_message_addr_set_flags(req, (address->flags & 0xff));
eb56eb9b
MS
602 if (r < 0)
603 return log_error_errno(r, "Could not set flags: %m");
5a723174 604
851c9f82 605 if (address->flags & ~0xff) {
1c4baffc 606 r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags);
851c9f82
PF
607 if (r < 0)
608 return log_error_errno(r, "Could not set extended flags: %m");
609 }
610
5c1d3fc9 611 r = sd_rtnl_message_addr_set_scope(req, address->scope);
eb56eb9b
MS
612 if (r < 0)
613 return log_error_errno(r, "Could not set scope: %m");
5a723174 614
0a0dc69b 615 if (address->family == AF_INET)
1c4baffc 616 r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
0a0dc69b 617 else if (address->family == AF_INET6)
1c4baffc 618 r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
eb56eb9b
MS
619 if (r < 0)
620 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
f579559b 621
af93291c 622 if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
c081882f 623 if (address->family == AF_INET)
1c4baffc 624 r = sd_netlink_message_append_in_addr(req, IFA_ADDRESS, &address->in_addr_peer.in);
c081882f 625 else if (address->family == AF_INET6)
1c4baffc 626 r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6);
eb56eb9b
MS
627 if (r < 0)
628 return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
c081882f
SS
629 } else {
630 if (address->family == AF_INET) {
1c4baffc 631 r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
eb56eb9b
MS
632 if (r < 0)
633 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
c081882f 634 }
f579559b
TG
635 }
636
637 if (address->label) {
1c4baffc 638 r = sd_netlink_message_append_string(req, IFA_LABEL, address->label);
eb56eb9b
MS
639 if (r < 0)
640 return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
f579559b
TG
641 }
642
1c4baffc 643 r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO,
68ceb9df 644 &address->cinfo);
eb56eb9b
MS
645 if (r < 0)
646 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
68ceb9df 647
fcf50cff 648 r = address_establish(address, link);
eb56eb9b 649 if (r < 0)
fcf50cff
TG
650 return r;
651
652 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
653 if (r < 0) {
654 address_release(address);
eb56eb9b 655 return log_error_errno(r, "Could not send rtnetlink message: %m");
fcf50cff 656 }
f579559b 657
563c69c6
TG
658 link_ref(link);
659
adda1ed9
TG
660 r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
661 if (r < 0) {
662 address_release(address);
663 return log_error_errno(r, "Could not add address: %m");
664 }
665
f579559b
TG
666 return 0;
667}
668
44e7b949
LP
669int config_parse_broadcast(
670 const char *unit,
eb0ea358
TG
671 const char *filename,
672 unsigned line,
673 const char *section,
674 unsigned section_line,
675 const char *lvalue,
676 int ltype,
677 const char *rvalue,
678 void *data,
679 void *userdata) {
44e7b949 680
eb0ea358
TG
681 Network *network = userdata;
682 _cleanup_address_free_ Address *n = NULL;
eb0ea358
TG
683 int r;
684
685 assert(filename);
686 assert(section);
687 assert(lvalue);
688 assert(rvalue);
689 assert(data);
690
f4859fc7 691 r = address_new_static(network, filename, section_line, &n);
eb0ea358
TG
692 if (r < 0)
693 return r;
694
482e2ac1 695 if (n->family == AF_INET6) {
12ca818f 696 log_syntax(unit, LOG_ERR, filename, line, 0, "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
482e2ac1
TG
697 return 0;
698 }
699
44e7b949 700 r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
eb0ea358 701 if (r < 0) {
12ca818f 702 log_syntax(unit, LOG_ERR, filename, line, r, "Broadcast is invalid, ignoring assignment: %s", rvalue);
eb0ea358
TG
703 return 0;
704 }
705
44e7b949 706 n->family = AF_INET;
eb0ea358
TG
707 n = NULL;
708
709 return 0;
710}
711
f579559b
TG
712int config_parse_address(const char *unit,
713 const char *filename,
714 unsigned line,
715 const char *section,
71a61510 716 unsigned section_line,
f579559b
TG
717 const char *lvalue,
718 int ltype,
719 const char *rvalue,
720 void *data,
721 void *userdata) {
44e7b949 722
6ae115c1 723 Network *network = userdata;
f579559b 724 _cleanup_address_free_ Address *n = NULL;
44e7b949
LP
725 const char *address, *e;
726 union in_addr_union buffer;
727 int r, f;
f579559b
TG
728
729 assert(filename);
6ae115c1 730 assert(section);
f579559b
TG
731 assert(lvalue);
732 assert(rvalue);
733 assert(data);
734
92fe133a
TG
735 if (streq(section, "Network")) {
736 /* we are not in an Address section, so treat
737 * this as the special '0' section */
f4859fc7
SS
738 r = address_new_static(network, NULL, 0, &n);
739 } else
740 r = address_new_static(network, filename, section_line, &n);
92fe133a 741
f579559b
TG
742 if (r < 0)
743 return r;
744
745 /* Address=address/prefixlen */
746
747 /* prefixlen */
748 e = strchr(rvalue, '/');
749 if (e) {
750 unsigned i;
12ca818f 751
f579559b
TG
752 r = safe_atou(e + 1, &i);
753 if (r < 0) {
12ca818f 754 log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is invalid, ignoring assignment: %s", e + 1);
f579559b
TG
755 return 0;
756 }
757
758 n->prefixlen = (unsigned char) i;
8cd11a0f 759
44e7b949
LP
760 address = strndupa(rvalue, e - rvalue);
761 } else
762 address = rvalue;
f579559b 763
44e7b949 764 r = in_addr_from_string_auto(address, &f, &buffer);
f579559b 765 if (r < 0) {
12ca818f 766 log_syntax(unit, LOG_ERR, filename, line, r, "Address is invalid, ignoring assignment: %s", address);
f579559b
TG
767 return 0;
768 }
769
a2a85a22
TG
770 if (!e && f == AF_INET) {
771 r = in_addr_default_prefixlen(&buffer.in, &n->prefixlen);
772 if (r < 0) {
12ca818f 773 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
774 return 0;
775 }
776 }
777
44e7b949 778 if (n->family != AF_UNSPEC && f != n->family) {
12ca818f 779 log_syntax(unit, LOG_ERR, filename, line, 0, "Address is incompatible, ignoring assignment: %s", address);
44e7b949
LP
780 return 0;
781 }
782
783 n->family = f;
784
785 if (streq(lvalue, "Address"))
786 n->in_addr = buffer;
787 else
788 n->in_addr_peer = buffer;
789
790 if (n->family == AF_INET && n->broadcast.s_addr == 0)
791 n->broadcast.s_addr = n->in_addr.in.s_addr | htonl(0xfffffffflu >> n->prefixlen);
eb0ea358 792
f579559b
TG
793 n = NULL;
794
795 return 0;
796}
6ae115c1 797
d31645ad
LP
798int config_parse_label(
799 const char *unit,
6ae115c1
TG
800 const char *filename,
801 unsigned line,
802 const char *section,
803 unsigned section_line,
804 const char *lvalue,
805 int ltype,
806 const char *rvalue,
807 void *data,
808 void *userdata) {
d31645ad 809
6ae115c1 810 _cleanup_address_free_ Address *n = NULL;
d31645ad 811 Network *network = userdata;
6ae115c1
TG
812 int r;
813
814 assert(filename);
815 assert(section);
816 assert(lvalue);
817 assert(rvalue);
818 assert(data);
819
f4859fc7 820 r = address_new_static(network, filename, section_line, &n);
6ae115c1
TG
821 if (r < 0)
822 return r;
823
a87d19fe
SS
824 if (!address_label_valid(rvalue)) {
825 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is too long or invalid, ignoring assignment: %s", rvalue);
6ae115c1
TG
826 return 0;
827 }
828
d31645ad
LP
829 r = free_and_strdup(&n->label, rvalue);
830 if (r < 0)
831 return log_oom();
6ae115c1
TG
832
833 n = NULL;
834
835 return 0;
836}
ce6c77eb 837
b5834a0b
SS
838int config_parse_lifetime(const char *unit,
839 const char *filename,
840 unsigned line,
841 const char *section,
842 unsigned section_line,
843 const char *lvalue,
844 int ltype,
845 const char *rvalue,
846 void *data,
847 void *userdata) {
848 Network *network = userdata;
849 _cleanup_address_free_ Address *n = NULL;
850 unsigned k;
851 int r;
852
853 assert(filename);
854 assert(section);
855 assert(lvalue);
856 assert(rvalue);
857 assert(data);
858
f4859fc7 859 r = address_new_static(network, filename, section_line, &n);
b5834a0b
SS
860 if (r < 0)
861 return r;
862
863 if (STR_IN_SET(rvalue, "forever", "infinity")) {
864 n->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
865 n = NULL;
866
867 return 0;
868 }
869
870 r = safe_atou(rvalue, &k);
871 if (r < 0) {
872 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse PreferredLifetime, ignoring: %s", rvalue);
873 return 0;
874 }
875
876 if (k != 0)
877 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid PreferredLifetime value, ignoring: %d", k);
878 else {
879 n->cinfo.ifa_prefered = k;
880 n = NULL;
881 }
882
883 return 0;
884}
885
e63be084
SS
886int config_parse_address_flags(const char *unit,
887 const char *filename,
888 unsigned line,
889 const char *section,
890 unsigned section_line,
891 const char *lvalue,
892 int ltype,
893 const char *rvalue,
894 void *data,
895 void *userdata) {
896 Network *network = userdata;
897 _cleanup_address_free_ Address *n = NULL;
898 int r;
899
900 assert(filename);
901 assert(section);
902 assert(lvalue);
903 assert(rvalue);
904 assert(data);
905
f4859fc7 906 r = address_new_static(network, filename, section_line, &n);
e63be084
SS
907 if (r < 0)
908 return r;
909
910 r = parse_boolean(rvalue);
911 if (r < 0) {
912 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address flag, ignoring: %s", rvalue);
913 return 0;
914 }
915
916 if (streq(lvalue, "HomeAddress"))
917 n->home_address = r;
918 else if (streq(lvalue, "DuplicateAddressDetection"))
919 n->duplicate_address_detection = r;
920 else if (streq(lvalue, "ManageTemporaryAddress"))
921 n->manage_temporary_address = r;
922 else if (streq(lvalue, "PrefixRoute"))
923 n->prefix_route = r;
924 else if (streq(lvalue, "AutoJoin"))
925 n->autojoin = r;
926
927 return 0;
928}
929
ce6c77eb
TG
930bool address_is_ready(const Address *a) {
931 assert(a);
932
63bbe5c7 933 return !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED));
ce6c77eb 934}
057abfd8 935
7d5cac19
PF
936int config_parse_router_preference(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
948 assert(filename);
949 assert(section);
950 assert(lvalue);
951 assert(rvalue);
952 assert(data);
953
954 if (streq(rvalue, "high"))
955 network->router_preference = SD_NDISC_PREFERENCE_HIGH;
956 else if (STR_IN_SET(rvalue, "medium", "normal", "default"))
957 network->router_preference = SD_NDISC_PREFERENCE_MEDIUM;
958 else if (streq(rvalue, "low"))
959 network->router_preference = SD_NDISC_PREFERENCE_LOW;
960 else
961 log_syntax(unit, LOG_ERR, filename, line, -EINVAL, "Router preference '%s' is invalid, ignoring assignment: %m", rvalue);
962
963 return 0;
964}
965
057abfd8
PF
966void prefix_free(Prefix *prefix) {
967 if (!prefix)
968 return;
969
970 if (prefix->network) {
971 LIST_REMOVE(prefixes, prefix->network->static_prefixes, prefix);
972 assert(prefix->network->n_static_prefixes > 0);
973 prefix->network->n_static_prefixes--;
974
975 if (prefix->section)
976 hashmap_remove(prefix->network->prefixes_by_section,
977 prefix->section);
978 }
979
9d5d0090
PF
980 prefix->radv_prefix = sd_radv_prefix_unref(prefix->radv_prefix);
981
057abfd8
PF
982 free(prefix);
983}
984
985int prefix_new(Prefix **ret) {
986 Prefix *prefix = NULL;
987
988 prefix = new0(Prefix, 1);
989 if (!prefix)
990 return -ENOMEM;
991
9d5d0090
PF
992 if (sd_radv_prefix_new(&prefix->radv_prefix) < 0)
993 return -ENOMEM;
994
057abfd8
PF
995 *ret = prefix;
996 prefix = NULL;
997
998 return 0;
999}
1000
1001int prefix_new_static(Network *network, const char *filename,
1002 unsigned section_line, Prefix **ret) {
1003 _cleanup_network_config_section_free_ NetworkConfigSection *n = NULL;
1004 _cleanup_prefix_free_ Prefix *prefix = NULL;
1005 int r;
1006
1007 assert(network);
1008 assert(ret);
1009 assert(!!filename == (section_line > 0));
1010
1011 if (filename) {
1012 r = network_config_section_new(filename, section_line, &n);
1013 if (r < 0)
1014 return r;
1015
1016 if (section_line) {
1017 prefix = hashmap_get(network->prefixes_by_section, n);
1018 if (prefix) {
1019 *ret = prefix;
1020 prefix = NULL;
1021
1022 return 0;
1023 }
1024 }
1025 }
1026
1027 r = prefix_new(&prefix);
1028 if (r < 0)
1029 return r;
1030
1031 if (filename) {
1032 prefix->section = n;
1033 n = NULL;
1034
1035 r = hashmap_put(network->prefixes_by_section, prefix->section,
1036 prefix);
1037 if (r < 0)
1038 return r;
1039 }
1040
1041 prefix->network = network;
1042 LIST_APPEND(prefixes, network->static_prefixes, prefix);
1043 network->n_static_prefixes++;
1044
1045 *ret = prefix;
1046 prefix = NULL;
1047
1048 return 0;
1049}
9d5d0090
PF
1050
1051int config_parse_prefix(const char *unit,
1052 const char *filename,
1053 unsigned line,
1054 const char *section,
1055 unsigned section_line,
1056 const char *lvalue,
1057 int ltype,
1058 const char *rvalue,
1059 void *data,
1060 void *userdata) {
1061
1062 Network *network = userdata;
1063 _cleanup_prefix_free_ Prefix *p = NULL;
1064 uint8_t prefixlen = 64;
1065 union in_addr_union in6addr;
1066 int r;
1067
1068 assert(filename);
1069 assert(section);
1070 assert(lvalue);
1071 assert(rvalue);
1072 assert(data);
1073
1074 r = prefix_new_static(network, filename, section_line, &p);
1075 if (r < 0)
1076 return r;
1077
1078 r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen);
1079 if (r < 0) {
1080 log_syntax(unit, LOG_ERR, filename, line, r, "Prefix is invalid, ignoring assignment: %s", rvalue);
1081 return 0;
1082 }
1083
1084 if (sd_radv_prefix_set_prefix(p->radv_prefix, &in6addr.in6, prefixlen) < 0)
1085 return -EADDRNOTAVAIL;
1086
1087 log_syntax(unit, LOG_INFO, filename, line, r, "Found prefix %s", rvalue);
1088
1089 p = NULL;
1090
1091 return 0;
1092}
1093
1094int config_parse_prefix_flags(const char *unit,
1095 const char *filename,
1096 unsigned line,
1097 const char *section,
1098 unsigned section_line,
1099 const char *lvalue,
1100 int ltype,
1101 const char *rvalue,
1102 void *data,
1103 void *userdata) {
1104 Network *network = userdata;
1105 _cleanup_prefix_free_ Prefix *p = NULL;
1106 int r, val;
1107
1108 assert(filename);
1109 assert(section);
1110 assert(lvalue);
1111 assert(rvalue);
1112 assert(data);
1113
1114 r = prefix_new_static(network, filename, section_line, &p);
1115 if (r < 0)
1116 return r;
1117
1118 r = parse_boolean(rvalue);
1119 if (r < 0) {
1120 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address flag, ignoring: %s", rvalue);
1121 return 0;
1122 }
1123
1124 val = r;
1125
1126 if (streq(lvalue, "OnLink"))
1127 r = sd_radv_prefix_set_onlink(p->radv_prefix, val);
1128 else if (streq(lvalue, "AddressAutoconfiguration"))
1129 r = sd_radv_prefix_set_address_autoconfiguration(p->radv_prefix, val);
1130 if (r < 0)
1131 return r;
1132
1133 p = NULL;
1134
1135 return 0;
1136}
1137
1138int config_parse_prefix_lifetime(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 usec_t usec;
1151 int r;
1152
1153 assert(filename);
1154 assert(section);
1155 assert(lvalue);
1156 assert(rvalue);
1157 assert(data);
1158
1159 r = prefix_new_static(network, filename, section_line, &p);
1160 if (r < 0)
1161 return r;
1162
1163 r = parse_sec(rvalue, &usec);
1164 if (r < 0) {
1165 log_syntax(unit, LOG_ERR, filename, line, r, "Lifetime is invalid, ignoring assignment: %s", rvalue);
1166 return 0;
1167 }
1168
301a2fb9 1169 /* a value of 0xffffffff represents infinity */
9d5d0090
PF
1170 if (streq(lvalue, "PreferredLifetimeSec"))
1171 r = sd_radv_prefix_set_preferred_lifetime(p->radv_prefix,
6abd0ef3 1172 DIV_ROUND_UP(usec, USEC_PER_SEC));
9d5d0090
PF
1173 else if (streq(lvalue, "ValidLifetimeSec"))
1174 r = sd_radv_prefix_set_valid_lifetime(p->radv_prefix,
6abd0ef3 1175 DIV_ROUND_UP(usec, USEC_PER_SEC));
9d5d0090
PF
1176 if (r < 0)
1177 return r;
1178
1179 p = NULL;
1180
1181 return 0;
1182};