]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-address.c
util-lib: split our string related calls from util.[ch] into its own file string...
[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"
07630cea 27#include "networkd.h"
3ac8e543 28#include "set.h"
07630cea 29#include "string-util.h"
3ac8e543
TG
30#include "utf8.h"
31#include "util.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) {
e7780c8d
TG
273 int r;
274
275 r = address_add_internal(link, &link->addresses, family, in_addr, prefixlen, ret);
276 if (r < 0)
277 return r;
278
84de38c5
TG
279 link_update_operstate(link);
280 link_dirty(link);
e7780c8d
TG
281
282 return 0;
adda1ed9
TG
283}
284
fcf50cff 285static int address_release(Address *address) {
5a8bcb67
LP
286 int r;
287
288 assert(address);
fcf50cff 289 assert(address->link);
5a8bcb67 290
91b5f997
TG
291 /* Remove masquerading firewall entry if it was added */
292 if (address->ip_masquerade_done) {
5a8bcb67
LP
293 union in_addr_union masked = address->in_addr;
294 in_addr_mask(address->family, &masked, address->prefixlen);
295
91b5f997 296 r = fw_add_masquerade(false, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
5a8bcb67 297 if (r < 0)
fcf50cff 298 log_link_warning_errno(address->link, r, "Failed to disable IP masquerading: %m");
5a8bcb67 299
91b5f997 300 address->ip_masquerade_done = false;
5a8bcb67
LP
301 }
302
303 return 0;
304}
305
36c32f61
TG
306int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo) {
307 bool ready;
308
309 assert(address);
310 assert(cinfo);
311
312 ready = address_is_ready(address);
313
adda1ed9 314 address->added = true;
36c32f61
TG
315 address->flags = flags;
316 address->scope = scope;
317 address->cinfo = *cinfo;
318
319 if (!ready && address_is_ready(address) && address->link)
320 link_check_ready(address->link);
321
322 return 0;
323}
324
91b5f997 325int address_drop(Address *address) {
8012cd39
TG
326 Link *link;
327 bool ready;
328
5a8bcb67 329 assert(address);
91b5f997 330
8012cd39
TG
331 ready = address_is_ready(address);
332 link = address->link;
333
fcf50cff 334 address_release(address);
91b5f997
TG
335 address_free(address);
336
84de38c5
TG
337 link_update_operstate(link);
338
8012cd39
TG
339 if (link && !ready)
340 link_check_ready(link);
341
91b5f997
TG
342 return 0;
343}
344
345int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
346 Address address = {}, *existing;
347
5a8bcb67 348 assert(link);
91b5f997
TG
349 assert(in_addr);
350 assert(ret);
5a8bcb67 351
91b5f997
TG
352 address.family = family;
353 address.in_addr = *in_addr;
354 address.prefixlen = prefixlen;
5a8bcb67 355
91b5f997 356 existing = set_get(link->addresses, &address);
adda1ed9
TG
357 if (!existing) {
358 existing = set_get(link->addresses_foreign, &address);
359 if (!existing)
360 return -ENOENT;
361 }
5a8bcb67 362
91b5f997 363 *ret = existing;
5a8bcb67
LP
364
365 return 0;
366}
367
91b5f997 368int address_remove(Address *address, Link *link,
1c4baffc
TG
369 sd_netlink_message_handler_t callback) {
370 _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
407fe036
TG
371 int r;
372
373 assert(address);
374 assert(address->family == AF_INET || address->family == AF_INET6);
375 assert(link);
376 assert(link->ifindex > 0);
377 assert(link->manager);
378 assert(link->manager->rtnl);
379
151b9b96
LP
380 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
381 link->ifindex, address->family);
eb56eb9b
MS
382 if (r < 0)
383 return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m");
407fe036 384
5a723174 385 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
eb56eb9b
MS
386 if (r < 0)
387 return log_error_errno(r, "Could not set prefixlen: %m");
5a723174 388
407fe036 389 if (address->family == AF_INET)
1c4baffc 390 r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
407fe036 391 else if (address->family == AF_INET6)
1c4baffc 392 r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
eb56eb9b
MS
393 if (r < 0)
394 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
407fe036 395
1c4baffc 396 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
eb56eb9b
MS
397 if (r < 0)
398 return log_error_errno(r, "Could not send rtnetlink message: %m");
407fe036 399
563c69c6
TG
400 link_ref(link);
401
407fe036
TG
402 return 0;
403}
404
11bf3cce
LP
405static int address_acquire(Link *link, Address *original, Address **ret) {
406 union in_addr_union in_addr = {};
407 struct in_addr broadcast = {};
0099bc15 408 _cleanup_address_free_ Address *na = NULL;
11bf3cce
LP
409 int r;
410
411 assert(link);
412 assert(original);
413 assert(ret);
414
415 /* Something useful was configured? just use it */
af93291c 416 if (in_addr_is_null(original->family, &original->in_addr) <= 0)
11bf3cce
LP
417 return 0;
418
419 /* The address is configured to be 0.0.0.0 or [::] by the user?
420 * Then let's acquire something more useful from the pool. */
421 r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
6a7a4e4d
LP
422 if (r < 0)
423 return log_link_error_errno(link, r, "Failed to acquire address from pool: %m");
11bf3cce 424 if (r == 0) {
79008bdd 425 log_link_error(link, "Couldn't find free address for interface, all taken.");
11bf3cce
LP
426 return -EBUSY;
427 }
428
429 if (original->family == AF_INET) {
d076c6f9 430 /* Pick first address in range for ourselves ... */
11bf3cce
LP
431 in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
432
433 /* .. and use last as broadcast address */
434 broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
435 } else if (original->family == AF_INET6)
436 in_addr.in6.s6_addr[15] |= 1;
437
f0213e37 438 r = address_new(&na);
11bf3cce
LP
439 if (r < 0)
440 return r;
441
442 na->family = original->family;
443 na->prefixlen = original->prefixlen;
444 na->scope = original->scope;
445 na->cinfo = original->cinfo;
446
447 if (original->label) {
448 na->label = strdup(original->label);
0099bc15 449 if (!na->label)
11bf3cce 450 return -ENOMEM;
11bf3cce
LP
451 }
452
453 na->broadcast = broadcast;
454 na->in_addr = in_addr;
455
456 LIST_PREPEND(addresses, link->pool_addresses, na);
457
458 *ret = na;
0099bc15
SS
459 na = NULL;
460
11bf3cce
LP
461 return 0;
462}
463
66669078 464int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback, bool update) {
1c4baffc 465 _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
f579559b
TG
466 int r;
467
c166a070
TG
468 assert(address);
469 assert(address->family == AF_INET || address->family == AF_INET6);
470 assert(link);
471 assert(link->ifindex > 0);
f882c247 472 assert(link->manager);
c166a070 473 assert(link->manager->rtnl);
f882c247 474
11bf3cce
LP
475 r = address_acquire(link, address, &address);
476 if (r < 0)
477 return r;
478
66669078
TG
479 if (update)
480 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
481 link->ifindex, address->family);
482 else
483 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
484 link->ifindex, address->family);
eb56eb9b
MS
485 if (r < 0)
486 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
f579559b 487
5a723174 488 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
eb56eb9b
MS
489 if (r < 0)
490 return log_error_errno(r, "Could not set prefixlen: %m");
5a723174 491
851c9f82
PF
492 address->flags |= IFA_F_PERMANENT;
493
494 r = sd_rtnl_message_addr_set_flags(req, (address->flags & 0xff));
eb56eb9b
MS
495 if (r < 0)
496 return log_error_errno(r, "Could not set flags: %m");
5a723174 497
851c9f82 498 if (address->flags & ~0xff) {
1c4baffc 499 r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags);
851c9f82
PF
500 if (r < 0)
501 return log_error_errno(r, "Could not set extended flags: %m");
502 }
503
5c1d3fc9 504 r = sd_rtnl_message_addr_set_scope(req, address->scope);
eb56eb9b
MS
505 if (r < 0)
506 return log_error_errno(r, "Could not set scope: %m");
5a723174 507
0a0dc69b 508 if (address->family == AF_INET)
1c4baffc 509 r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
0a0dc69b 510 else if (address->family == AF_INET6)
1c4baffc 511 r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
eb56eb9b
MS
512 if (r < 0)
513 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
f579559b 514
af93291c 515 if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
c081882f 516 if (address->family == AF_INET)
1c4baffc 517 r = sd_netlink_message_append_in_addr(req, IFA_ADDRESS, &address->in_addr_peer.in);
c081882f 518 else if (address->family == AF_INET6)
1c4baffc 519 r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6);
eb56eb9b
MS
520 if (r < 0)
521 return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
c081882f
SS
522 } else {
523 if (address->family == AF_INET) {
1c4baffc 524 r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
eb56eb9b
MS
525 if (r < 0)
526 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
c081882f 527 }
f579559b
TG
528 }
529
530 if (address->label) {
1c4baffc 531 r = sd_netlink_message_append_string(req, IFA_LABEL, address->label);
eb56eb9b
MS
532 if (r < 0)
533 return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
f579559b
TG
534 }
535
1c4baffc 536 r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO,
68ceb9df 537 &address->cinfo);
eb56eb9b
MS
538 if (r < 0)
539 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
68ceb9df 540
fcf50cff 541 r = address_establish(address, link);
eb56eb9b 542 if (r < 0)
fcf50cff
TG
543 return r;
544
545 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
546 if (r < 0) {
547 address_release(address);
eb56eb9b 548 return log_error_errno(r, "Could not send rtnetlink message: %m");
fcf50cff 549 }
f579559b 550
563c69c6
TG
551 link_ref(link);
552
adda1ed9
TG
553 r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
554 if (r < 0) {
555 address_release(address);
556 return log_error_errno(r, "Could not add address: %m");
557 }
558
f579559b
TG
559 return 0;
560}
561
44e7b949
LP
562int config_parse_broadcast(
563 const char *unit,
eb0ea358
TG
564 const char *filename,
565 unsigned line,
566 const char *section,
567 unsigned section_line,
568 const char *lvalue,
569 int ltype,
570 const char *rvalue,
571 void *data,
572 void *userdata) {
44e7b949 573
eb0ea358
TG
574 Network *network = userdata;
575 _cleanup_address_free_ Address *n = NULL;
eb0ea358
TG
576 int r;
577
578 assert(filename);
579 assert(section);
580 assert(lvalue);
581 assert(rvalue);
582 assert(data);
583
584 r = address_new_static(network, section_line, &n);
585 if (r < 0)
586 return r;
587
482e2ac1 588 if (n->family == AF_INET6) {
12ca818f 589 log_syntax(unit, LOG_ERR, filename, line, 0, "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
482e2ac1
TG
590 return 0;
591 }
592
44e7b949 593 r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
eb0ea358 594 if (r < 0) {
12ca818f 595 log_syntax(unit, LOG_ERR, filename, line, r, "Broadcast is invalid, ignoring assignment: %s", rvalue);
eb0ea358
TG
596 return 0;
597 }
598
44e7b949 599 n->family = AF_INET;
eb0ea358
TG
600 n = NULL;
601
602 return 0;
603}
604
f579559b
TG
605int config_parse_address(const char *unit,
606 const char *filename,
607 unsigned line,
608 const char *section,
71a61510 609 unsigned section_line,
f579559b
TG
610 const char *lvalue,
611 int ltype,
612 const char *rvalue,
613 void *data,
614 void *userdata) {
44e7b949 615
6ae115c1 616 Network *network = userdata;
f579559b 617 _cleanup_address_free_ Address *n = NULL;
44e7b949
LP
618 const char *address, *e;
619 union in_addr_union buffer;
620 int r, f;
f579559b
TG
621
622 assert(filename);
6ae115c1 623 assert(section);
f579559b
TG
624 assert(lvalue);
625 assert(rvalue);
626 assert(data);
627
92fe133a
TG
628 if (streq(section, "Network")) {
629 /* we are not in an Address section, so treat
630 * this as the special '0' section */
631 section_line = 0;
632 }
633
f048a16b 634 r = address_new_static(network, section_line, &n);
f579559b
TG
635 if (r < 0)
636 return r;
637
638 /* Address=address/prefixlen */
639
640 /* prefixlen */
641 e = strchr(rvalue, '/');
642 if (e) {
643 unsigned i;
12ca818f 644
f579559b
TG
645 r = safe_atou(e + 1, &i);
646 if (r < 0) {
12ca818f 647 log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is invalid, ignoring assignment: %s", e + 1);
f579559b
TG
648 return 0;
649 }
650
651 n->prefixlen = (unsigned char) i;
8cd11a0f 652
44e7b949
LP
653 address = strndupa(rvalue, e - rvalue);
654 } else
655 address = rvalue;
f579559b 656
44e7b949 657 r = in_addr_from_string_auto(address, &f, &buffer);
f579559b 658 if (r < 0) {
12ca818f 659 log_syntax(unit, LOG_ERR, filename, line, r, "Address is invalid, ignoring assignment: %s", address);
f579559b
TG
660 return 0;
661 }
662
a2a85a22
TG
663 if (!e && f == AF_INET) {
664 r = in_addr_default_prefixlen(&buffer.in, &n->prefixlen);
665 if (r < 0) {
12ca818f 666 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
667 return 0;
668 }
669 }
670
44e7b949 671 if (n->family != AF_UNSPEC && f != n->family) {
12ca818f 672 log_syntax(unit, LOG_ERR, filename, line, 0, "Address is incompatible, ignoring assignment: %s", address);
44e7b949
LP
673 return 0;
674 }
675
676 n->family = f;
677
678 if (streq(lvalue, "Address"))
679 n->in_addr = buffer;
680 else
681 n->in_addr_peer = buffer;
682
683 if (n->family == AF_INET && n->broadcast.s_addr == 0)
684 n->broadcast.s_addr = n->in_addr.in.s_addr | htonl(0xfffffffflu >> n->prefixlen);
eb0ea358 685
f579559b
TG
686 n = NULL;
687
688 return 0;
689}
6ae115c1
TG
690
691int config_parse_label(const char *unit,
692 const char *filename,
693 unsigned line,
694 const char *section,
695 unsigned section_line,
696 const char *lvalue,
697 int ltype,
698 const char *rvalue,
699 void *data,
700 void *userdata) {
701 Network *network = userdata;
702 _cleanup_address_free_ Address *n = NULL;
6ae115c1
TG
703 char *label;
704 int r;
705
706 assert(filename);
707 assert(section);
708 assert(lvalue);
709 assert(rvalue);
710 assert(data);
711
f048a16b 712 r = address_new_static(network, section_line, &n);
6ae115c1
TG
713 if (r < 0)
714 return r;
715
716 label = strdup(rvalue);
717 if (!label)
718 return log_oom();
719
720 if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
12ca818f 721 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
6ae115c1
TG
722 free(label);
723 return 0;
724 }
725
726 free(n->label);
727 if (*label)
728 n->label = label;
729 else {
730 free(label);
731 n->label = NULL;
732 }
733
734 n = NULL;
735
736 return 0;
737}
ce6c77eb
TG
738
739bool address_is_ready(const Address *a) {
740 assert(a);
741
adda1ed9 742 return a->added && !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED));
ce6c77eb 743}