]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-address.c
networkd: address - distinguish between addresses added by us and by others
[thirdparty/systemd.git] / src / network / networkd-address.c
CommitLineData
f579559b
TG
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <net/if.h>
23
f579559b 24#include "conf-parser.h"
12c2884c 25#include "firewall-util.h"
fc2f9534 26#include "netlink-util.h"
3ac8e543
TG
27#include "set.h"
28#include "utf8.h"
29#include "util.h"
fc2f9534 30
5a8bcb67 31#include "networkd.h"
fc2f9534 32#include "networkd-address.h"
f579559b 33
f0213e37
TG
34int address_new(Address **ret) {
35 _cleanup_address_free_ Address *address = NULL;
36
37 address = new0(Address, 1);
38 if (!address)
39 return -ENOMEM;
aba496a5
UTL
40
41 address->family = AF_UNSPEC;
42 address->scope = RT_SCOPE_UNIVERSE;
43 address->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
44 address->cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME;
f0213e37
TG
45
46 *ret = address;
47 address = NULL;
48
49 return 0;
aba496a5
UTL
50}
51
f048a16b 52int address_new_static(Network *network, unsigned section, Address **ret) {
f579559b 53 _cleanup_address_free_ Address *address = NULL;
f0213e37 54 int r;
f579559b 55
6ae115c1 56 if (section) {
16aa63a0 57 address = hashmap_get(network->addresses_by_section, UINT_TO_PTR(section));
6ae115c1
TG
58 if (address) {
59 *ret = address;
60 address = NULL;
61
62 return 0;
63 }
64 }
65
f0213e37
TG
66 r = address_new(&address);
67 if (r < 0)
68 return r;
801bd9e8 69
f579559b
TG
70 address->network = network;
71
1e39ff92 72 LIST_APPEND(addresses, network->static_addresses, address);
f579559b 73
6ae115c1
TG
74 if (section) {
75 address->section = section;
16aa63a0
TG
76 hashmap_put(network->addresses_by_section,
77 UINT_TO_PTR(address->section), address);
6ae115c1
TG
78 }
79
f579559b
TG
80 *ret = address;
81 address = NULL;
82
83 return 0;
84}
85
86void address_free(Address *address) {
87 if (!address)
88 return;
89
f048a16b 90 if (address->network) {
3d3d4255 91 LIST_REMOVE(addresses, address->network->static_addresses, address);
f579559b 92
f048a16b
TG
93 if (address->section)
94 hashmap_remove(address->network->addresses_by_section,
16aa63a0 95 UINT_TO_PTR(address->section));
f048a16b 96 }
6ae115c1 97
adda1ed9 98 if (address->link) {
cf1d700d 99 set_remove(address->link->addresses, address);
adda1ed9
TG
100 set_remove(address->link->addresses_foreign, address);
101 }
cf1d700d 102
f579559b
TG
103 free(address);
104}
105
3ac8e543
TG
106static void address_hash_func(const void *b, struct siphash *state) {
107 const Address *a = b;
108
109 assert(a);
110
111 siphash24_compress(&a->family, sizeof(a->family), state);
112
113 switch (a->family) {
114 case AF_INET:
115 siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
116
117 /* peer prefix */
118 if (a->prefixlen != 0) {
119 uint32_t prefix;
120
121 if (a->in_addr_peer.in.s_addr != 0)
122 prefix = be32toh(a->in_addr_peer.in.s_addr) >> (32 - a->prefixlen);
123 else
124 prefix = be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
125
126 siphash24_compress(&prefix, sizeof(prefix), state);
127 }
128
129 /* fallthrough */
130 case AF_INET6:
131 /* local address */
132 siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
133
134 break;
135 default:
136 /* treat any other address family as AF_UNSPEC */
137 break;
138 }
139}
140
141static int address_compare_func(const void *c1, const void *c2) {
142 const Address *a1 = c1, *a2 = c2;
143
144 if (a1->family < a2->family)
145 return -1;
146 if (a1->family > a2->family)
147 return 1;
148
149 switch (a1->family) {
150 /* use the same notion of equality as the kernel does */
151 case AF_INET:
152 if (a1->prefixlen < a2->prefixlen)
153 return -1;
154 if (a1->prefixlen > a2->prefixlen)
155 return 1;
156
157 /* compare the peer prefixes */
158 if (a1->prefixlen != 0) {
159 /* make sure we don't try to shift by 32.
160 * See ISO/IEC 9899:TC3 § 6.5.7.3. */
161 uint32_t b1, b2;
162
163 if (a1->in_addr_peer.in.s_addr != 0)
164 b1 = be32toh(a1->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
165 else
166 b1 = be32toh(a1->in_addr.in.s_addr) >> (32 - a1->prefixlen);
167
168 if (a2->in_addr_peer.in.s_addr != 0)
169 b2 = be32toh(a2->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
170 else
171 b2 = be32toh(a2->in_addr.in.s_addr) >> (32 - a1->prefixlen);
172
173 if (b1 < b2)
174 return -1;
175 if (b1 > b2)
176 return 1;
177 }
178
179 /* fall-through */
180 case AF_INET6:
181 return memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
182 default:
183 /* treat any other address family as AF_UNSPEC */
184 return 0;
185 }
186}
187
188static const struct hash_ops address_hash_ops = {
189 .hash = address_hash_func,
190 .compare = address_compare_func
191};
192
193bool address_equal(Address *a1, Address *a2) {
194 if (a1 == a2)
195 return true;
196
197 if (!a1 || !a2)
198 return false;
199
200 return address_compare_func(a1, a2) == 0;
201}
202
91b5f997
TG
203static int address_establish(Address *address, Link *link) {
204 bool masq;
205 int r;
206
207 assert(address);
208 assert(link);
209
210 masq = link->network &&
fcf50cff
TG
211 link->network->ip_masquerade &&
212 address->family == AF_INET &&
213 address->scope < RT_SCOPE_LINK;
91b5f997
TG
214
215 /* Add firewall entry if this is requested */
216 if (address->ip_masquerade_done != masq) {
217 union in_addr_union masked = address->in_addr;
218 in_addr_mask(address->family, &masked, address->prefixlen);
219
220 r = fw_add_masquerade(masq, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
221 if (r < 0)
222 log_link_warning_errno(link, r, "Could not enable IP masquerading: %m");
223
224 address->ip_masquerade_done = masq;
225 }
226
227 return 0;
228}
229
adda1ed9
TG
230static int address_add_internal(Link *link, Set **addresses,
231 int family,
232 const union in_addr_union *in_addr,
233 unsigned char prefixlen,
234 Address **ret) {
054f0db4 235 _cleanup_address_free_ Address *address = NULL;
cf1d700d
TG
236 int r;
237
238 assert(link);
adda1ed9 239 assert(addresses);
054f0db4 240 assert(in_addr);
054f0db4
TG
241
242 r = address_new(&address);
243 if (r < 0)
244 return r;
245
246 address->family = family;
247 address->in_addr = *in_addr;
248 address->prefixlen = prefixlen;
cf1d700d 249
adda1ed9 250 r = set_ensure_allocated(addresses, &address_hash_ops);
cf1d700d
TG
251 if (r < 0)
252 return r;
253
adda1ed9 254 r = set_put(*addresses, address);
cf1d700d
TG
255 if (r < 0)
256 return r;
257
258 address->link = link;
259
adda1ed9
TG
260 if (ret)
261 *ret = address;
262
054f0db4
TG
263 address = NULL;
264
cf1d700d
TG
265 return 0;
266}
267
adda1ed9
TG
268int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
269 return address_add_internal(link, &link->addresses_foreign, family, in_addr, prefixlen, ret);
270}
271
272static int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
273 return address_add_internal(link, &link->addresses, family, in_addr, prefixlen, ret);
274}
275
fcf50cff 276static int address_release(Address *address) {
5a8bcb67
LP
277 int r;
278
279 assert(address);
fcf50cff 280 assert(address->link);
5a8bcb67 281
91b5f997
TG
282 /* Remove masquerading firewall entry if it was added */
283 if (address->ip_masquerade_done) {
5a8bcb67
LP
284 union in_addr_union masked = address->in_addr;
285 in_addr_mask(address->family, &masked, address->prefixlen);
286
91b5f997 287 r = fw_add_masquerade(false, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
5a8bcb67 288 if (r < 0)
fcf50cff 289 log_link_warning_errno(address->link, r, "Failed to disable IP masquerading: %m");
5a8bcb67 290
91b5f997 291 address->ip_masquerade_done = false;
5a8bcb67
LP
292 }
293
294 return 0;
295}
296
36c32f61
TG
297int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo) {
298 bool ready;
299
300 assert(address);
301 assert(cinfo);
302
303 ready = address_is_ready(address);
304
adda1ed9 305 address->added = true;
36c32f61
TG
306 address->flags = flags;
307 address->scope = scope;
308 address->cinfo = *cinfo;
309
310 if (!ready && address_is_ready(address) && address->link)
311 link_check_ready(address->link);
312
313 return 0;
314}
315
91b5f997 316int address_drop(Address *address) {
8012cd39
TG
317 Link *link;
318 bool ready;
319
5a8bcb67 320 assert(address);
91b5f997 321
8012cd39
TG
322 ready = address_is_ready(address);
323 link = address->link;
324
fcf50cff 325 address_release(address);
91b5f997
TG
326 address_free(address);
327
8012cd39
TG
328 if (link && !ready)
329 link_check_ready(link);
330
91b5f997
TG
331 return 0;
332}
333
334int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
335 Address address = {}, *existing;
336
5a8bcb67 337 assert(link);
91b5f997
TG
338 assert(in_addr);
339 assert(ret);
5a8bcb67 340
91b5f997
TG
341 address.family = family;
342 address.in_addr = *in_addr;
343 address.prefixlen = prefixlen;
5a8bcb67 344
91b5f997 345 existing = set_get(link->addresses, &address);
adda1ed9
TG
346 if (!existing) {
347 existing = set_get(link->addresses_foreign, &address);
348 if (!existing)
349 return -ENOENT;
350 }
5a8bcb67 351
91b5f997 352 *ret = existing;
5a8bcb67
LP
353
354 return 0;
355}
356
91b5f997 357int address_remove(Address *address, Link *link,
1c4baffc
TG
358 sd_netlink_message_handler_t callback) {
359 _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
407fe036
TG
360 int r;
361
362 assert(address);
363 assert(address->family == AF_INET || address->family == AF_INET6);
364 assert(link);
365 assert(link->ifindex > 0);
366 assert(link->manager);
367 assert(link->manager->rtnl);
368
151b9b96
LP
369 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
370 link->ifindex, address->family);
eb56eb9b
MS
371 if (r < 0)
372 return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m");
407fe036 373
5a723174 374 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
eb56eb9b
MS
375 if (r < 0)
376 return log_error_errno(r, "Could not set prefixlen: %m");
5a723174 377
407fe036 378 if (address->family == AF_INET)
1c4baffc 379 r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
407fe036 380 else if (address->family == AF_INET6)
1c4baffc 381 r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
eb56eb9b
MS
382 if (r < 0)
383 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
407fe036 384
1c4baffc 385 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
eb56eb9b
MS
386 if (r < 0)
387 return log_error_errno(r, "Could not send rtnetlink message: %m");
407fe036 388
563c69c6
TG
389 link_ref(link);
390
407fe036
TG
391 return 0;
392}
393
11bf3cce
LP
394static int address_acquire(Link *link, Address *original, Address **ret) {
395 union in_addr_union in_addr = {};
396 struct in_addr broadcast = {};
0099bc15 397 _cleanup_address_free_ Address *na = NULL;
11bf3cce
LP
398 int r;
399
400 assert(link);
401 assert(original);
402 assert(ret);
403
404 /* Something useful was configured? just use it */
af93291c 405 if (in_addr_is_null(original->family, &original->in_addr) <= 0)
11bf3cce
LP
406 return 0;
407
408 /* The address is configured to be 0.0.0.0 or [::] by the user?
409 * Then let's acquire something more useful from the pool. */
410 r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
6a7a4e4d
LP
411 if (r < 0)
412 return log_link_error_errno(link, r, "Failed to acquire address from pool: %m");
11bf3cce 413 if (r == 0) {
79008bdd 414 log_link_error(link, "Couldn't find free address for interface, all taken.");
11bf3cce
LP
415 return -EBUSY;
416 }
417
418 if (original->family == AF_INET) {
d076c6f9 419 /* Pick first address in range for ourselves ... */
11bf3cce
LP
420 in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
421
422 /* .. and use last as broadcast address */
423 broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
424 } else if (original->family == AF_INET6)
425 in_addr.in6.s6_addr[15] |= 1;
426
f0213e37 427 r = address_new(&na);
11bf3cce
LP
428 if (r < 0)
429 return r;
430
431 na->family = original->family;
432 na->prefixlen = original->prefixlen;
433 na->scope = original->scope;
434 na->cinfo = original->cinfo;
435
436 if (original->label) {
437 na->label = strdup(original->label);
0099bc15 438 if (!na->label)
11bf3cce 439 return -ENOMEM;
11bf3cce
LP
440 }
441
442 na->broadcast = broadcast;
443 na->in_addr = in_addr;
444
445 LIST_PREPEND(addresses, link->pool_addresses, na);
446
447 *ret = na;
0099bc15
SS
448 na = NULL;
449
11bf3cce
LP
450 return 0;
451}
452
66669078 453int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback, bool update) {
1c4baffc 454 _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
f579559b
TG
455 int r;
456
c166a070
TG
457 assert(address);
458 assert(address->family == AF_INET || address->family == AF_INET6);
459 assert(link);
460 assert(link->ifindex > 0);
f882c247 461 assert(link->manager);
c166a070 462 assert(link->manager->rtnl);
f882c247 463
11bf3cce
LP
464 r = address_acquire(link, address, &address);
465 if (r < 0)
466 return r;
467
66669078
TG
468 if (update)
469 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
470 link->ifindex, address->family);
471 else
472 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
473 link->ifindex, address->family);
eb56eb9b
MS
474 if (r < 0)
475 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
f579559b 476
5a723174 477 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
eb56eb9b
MS
478 if (r < 0)
479 return log_error_errno(r, "Could not set prefixlen: %m");
5a723174 480
851c9f82
PF
481 address->flags |= IFA_F_PERMANENT;
482
483 r = sd_rtnl_message_addr_set_flags(req, (address->flags & 0xff));
eb56eb9b
MS
484 if (r < 0)
485 return log_error_errno(r, "Could not set flags: %m");
5a723174 486
851c9f82 487 if (address->flags & ~0xff) {
1c4baffc 488 r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags);
851c9f82
PF
489 if (r < 0)
490 return log_error_errno(r, "Could not set extended flags: %m");
491 }
492
5c1d3fc9 493 r = sd_rtnl_message_addr_set_scope(req, address->scope);
eb56eb9b
MS
494 if (r < 0)
495 return log_error_errno(r, "Could not set scope: %m");
5a723174 496
0a0dc69b 497 if (address->family == AF_INET)
1c4baffc 498 r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
0a0dc69b 499 else if (address->family == AF_INET6)
1c4baffc 500 r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
eb56eb9b
MS
501 if (r < 0)
502 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
f579559b 503
af93291c 504 if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
c081882f 505 if (address->family == AF_INET)
1c4baffc 506 r = sd_netlink_message_append_in_addr(req, IFA_ADDRESS, &address->in_addr_peer.in);
c081882f 507 else if (address->family == AF_INET6)
1c4baffc 508 r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6);
eb56eb9b
MS
509 if (r < 0)
510 return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
c081882f
SS
511 } else {
512 if (address->family == AF_INET) {
1c4baffc 513 r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
eb56eb9b
MS
514 if (r < 0)
515 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
c081882f 516 }
f579559b
TG
517 }
518
519 if (address->label) {
1c4baffc 520 r = sd_netlink_message_append_string(req, IFA_LABEL, address->label);
eb56eb9b
MS
521 if (r < 0)
522 return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
f579559b
TG
523 }
524
1c4baffc 525 r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO,
68ceb9df 526 &address->cinfo);
eb56eb9b
MS
527 if (r < 0)
528 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
68ceb9df 529
fcf50cff 530 r = address_establish(address, link);
eb56eb9b 531 if (r < 0)
fcf50cff
TG
532 return r;
533
534 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
535 if (r < 0) {
536 address_release(address);
eb56eb9b 537 return log_error_errno(r, "Could not send rtnetlink message: %m");
fcf50cff 538 }
f579559b 539
563c69c6
TG
540 link_ref(link);
541
adda1ed9
TG
542 r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
543 if (r < 0) {
544 address_release(address);
545 return log_error_errno(r, "Could not add address: %m");
546 }
547
f579559b
TG
548 return 0;
549}
550
44e7b949
LP
551int config_parse_broadcast(
552 const char *unit,
eb0ea358
TG
553 const char *filename,
554 unsigned line,
555 const char *section,
556 unsigned section_line,
557 const char *lvalue,
558 int ltype,
559 const char *rvalue,
560 void *data,
561 void *userdata) {
44e7b949 562
eb0ea358
TG
563 Network *network = userdata;
564 _cleanup_address_free_ Address *n = NULL;
eb0ea358
TG
565 int r;
566
567 assert(filename);
568 assert(section);
569 assert(lvalue);
570 assert(rvalue);
571 assert(data);
572
573 r = address_new_static(network, section_line, &n);
574 if (r < 0)
575 return r;
576
482e2ac1 577 if (n->family == AF_INET6) {
12ca818f 578 log_syntax(unit, LOG_ERR, filename, line, 0, "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
482e2ac1
TG
579 return 0;
580 }
581
44e7b949 582 r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
eb0ea358 583 if (r < 0) {
12ca818f 584 log_syntax(unit, LOG_ERR, filename, line, r, "Broadcast is invalid, ignoring assignment: %s", rvalue);
eb0ea358
TG
585 return 0;
586 }
587
44e7b949 588 n->family = AF_INET;
eb0ea358
TG
589 n = NULL;
590
591 return 0;
592}
593
f579559b
TG
594int config_parse_address(const char *unit,
595 const char *filename,
596 unsigned line,
597 const char *section,
71a61510 598 unsigned section_line,
f579559b
TG
599 const char *lvalue,
600 int ltype,
601 const char *rvalue,
602 void *data,
603 void *userdata) {
44e7b949 604
6ae115c1 605 Network *network = userdata;
f579559b 606 _cleanup_address_free_ Address *n = NULL;
44e7b949
LP
607 const char *address, *e;
608 union in_addr_union buffer;
609 int r, f;
f579559b
TG
610
611 assert(filename);
6ae115c1 612 assert(section);
f579559b
TG
613 assert(lvalue);
614 assert(rvalue);
615 assert(data);
616
92fe133a
TG
617 if (streq(section, "Network")) {
618 /* we are not in an Address section, so treat
619 * this as the special '0' section */
620 section_line = 0;
621 }
622
f048a16b 623 r = address_new_static(network, section_line, &n);
f579559b
TG
624 if (r < 0)
625 return r;
626
627 /* Address=address/prefixlen */
628
629 /* prefixlen */
630 e = strchr(rvalue, '/');
631 if (e) {
632 unsigned i;
12ca818f 633
f579559b
TG
634 r = safe_atou(e + 1, &i);
635 if (r < 0) {
12ca818f 636 log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is invalid, ignoring assignment: %s", e + 1);
f579559b
TG
637 return 0;
638 }
639
640 n->prefixlen = (unsigned char) i;
8cd11a0f 641
44e7b949
LP
642 address = strndupa(rvalue, e - rvalue);
643 } else
644 address = rvalue;
f579559b 645
44e7b949 646 r = in_addr_from_string_auto(address, &f, &buffer);
f579559b 647 if (r < 0) {
12ca818f 648 log_syntax(unit, LOG_ERR, filename, line, r, "Address is invalid, ignoring assignment: %s", address);
f579559b
TG
649 return 0;
650 }
651
a2a85a22
TG
652 if (!e && f == AF_INET) {
653 r = in_addr_default_prefixlen(&buffer.in, &n->prefixlen);
654 if (r < 0) {
12ca818f 655 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
656 return 0;
657 }
658 }
659
44e7b949 660 if (n->family != AF_UNSPEC && f != n->family) {
12ca818f 661 log_syntax(unit, LOG_ERR, filename, line, 0, "Address is incompatible, ignoring assignment: %s", address);
44e7b949
LP
662 return 0;
663 }
664
665 n->family = f;
666
667 if (streq(lvalue, "Address"))
668 n->in_addr = buffer;
669 else
670 n->in_addr_peer = buffer;
671
672 if (n->family == AF_INET && n->broadcast.s_addr == 0)
673 n->broadcast.s_addr = n->in_addr.in.s_addr | htonl(0xfffffffflu >> n->prefixlen);
eb0ea358 674
f579559b
TG
675 n = NULL;
676
677 return 0;
678}
6ae115c1
TG
679
680int config_parse_label(const char *unit,
681 const char *filename,
682 unsigned line,
683 const char *section,
684 unsigned section_line,
685 const char *lvalue,
686 int ltype,
687 const char *rvalue,
688 void *data,
689 void *userdata) {
690 Network *network = userdata;
691 _cleanup_address_free_ Address *n = NULL;
6ae115c1
TG
692 char *label;
693 int r;
694
695 assert(filename);
696 assert(section);
697 assert(lvalue);
698 assert(rvalue);
699 assert(data);
700
f048a16b 701 r = address_new_static(network, section_line, &n);
6ae115c1
TG
702 if (r < 0)
703 return r;
704
705 label = strdup(rvalue);
706 if (!label)
707 return log_oom();
708
709 if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
12ca818f 710 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
6ae115c1
TG
711 free(label);
712 return 0;
713 }
714
715 free(n->label);
716 if (*label)
717 n->label = label;
718 else {
719 free(label);
720 n->label = NULL;
721 }
722
723 n = NULL;
724
725 return 0;
726}
ce6c77eb
TG
727
728bool address_is_ready(const Address *a) {
729 assert(a);
730
adda1ed9 731 return a->added && !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED));
ce6c77eb 732}