Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <net/if.h>
4 :
5 : #include "alloc-util.h"
6 : #include "conf-parser.h"
7 : #include "firewall-util.h"
8 : #include "memory-util.h"
9 : #include "missing_network.h"
10 : #include "netlink-util.h"
11 : #include "networkd-address.h"
12 : #include "networkd-manager.h"
13 : #include "parse-util.h"
14 : #include "set.h"
15 : #include "socket-util.h"
16 : #include "string-util.h"
17 : #include "strv.h"
18 : #include "utf8.h"
19 :
20 : #define ADDRESSES_PER_LINK_MAX 2048U
21 : #define STATIC_ADDRESSES_PER_NETWORK_MAX 1024U
22 :
23 27 : int address_new(Address **ret) {
24 27 : _cleanup_(address_freep) Address *address = NULL;
25 :
26 27 : address = new(Address, 1);
27 27 : if (!address)
28 0 : return -ENOMEM;
29 :
30 27 : *address = (Address) {
31 : .family = AF_UNSPEC,
32 : .scope = RT_SCOPE_UNIVERSE,
33 : .cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME,
34 : .cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME,
35 : };
36 :
37 27 : *ret = TAKE_PTR(address);
38 :
39 27 : return 0;
40 : }
41 :
42 25 : static int address_new_static(Network *network, const char *filename, unsigned section_line, Address **ret) {
43 25 : _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
44 25 : _cleanup_(address_freep) Address *address = NULL;
45 : int r;
46 :
47 25 : assert(network);
48 25 : assert(ret);
49 25 : assert(!!filename == (section_line > 0));
50 :
51 25 : if (filename) {
52 23 : r = network_config_section_new(filename, section_line, &n);
53 23 : if (r < 0)
54 0 : return r;
55 :
56 23 : address = hashmap_get(network->addresses_by_section, n);
57 23 : if (address) {
58 0 : *ret = TAKE_PTR(address);
59 :
60 0 : return 0;
61 : }
62 : }
63 :
64 25 : if (network->n_static_addresses >= STATIC_ADDRESSES_PER_NETWORK_MAX)
65 0 : return -E2BIG;
66 :
67 25 : r = address_new(&address);
68 25 : if (r < 0)
69 0 : return r;
70 :
71 25 : address->network = network;
72 25 : LIST_APPEND(addresses, network->static_addresses, address);
73 25 : network->n_static_addresses++;
74 :
75 25 : if (filename) {
76 23 : address->section = TAKE_PTR(n);
77 :
78 23 : r = hashmap_ensure_allocated(&network->addresses_by_section, &network_config_hash_ops);
79 23 : if (r < 0)
80 0 : return r;
81 :
82 23 : r = hashmap_put(network->addresses_by_section, address->section, address);
83 23 : if (r < 0)
84 0 : return r;
85 : }
86 :
87 25 : *ret = TAKE_PTR(address);
88 :
89 25 : return 0;
90 : }
91 :
92 27 : void address_free(Address *address) {
93 27 : if (!address)
94 0 : return;
95 :
96 27 : if (address->network) {
97 25 : LIST_REMOVE(addresses, address->network->static_addresses, address);
98 25 : assert(address->network->n_static_addresses > 0);
99 25 : address->network->n_static_addresses--;
100 :
101 25 : if (address->section)
102 23 : hashmap_remove(address->network->addresses_by_section, address->section);
103 : }
104 :
105 27 : if (address->link) {
106 0 : set_remove(address->link->addresses, address);
107 0 : set_remove(address->link->addresses_foreign, address);
108 :
109 0 : if (in_addr_equal(AF_INET6, &address->in_addr, (const union in_addr_union *) &address->link->ipv6ll_address))
110 0 : memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr));
111 : }
112 :
113 27 : network_config_section_free(address->section);
114 27 : free(address->label);
115 27 : free(address);
116 : }
117 :
118 0 : static void address_hash_func(const Address *a, struct siphash *state) {
119 0 : assert(a);
120 :
121 0 : siphash24_compress(&a->family, sizeof(a->family), state);
122 :
123 0 : switch (a->family) {
124 0 : case AF_INET:
125 0 : siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
126 :
127 : /* peer prefix */
128 0 : if (a->prefixlen != 0) {
129 : uint32_t prefix;
130 :
131 0 : if (a->in_addr_peer.in.s_addr != 0)
132 0 : prefix = be32toh(a->in_addr_peer.in.s_addr) >> (32 - a->prefixlen);
133 : else
134 0 : prefix = be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
135 :
136 0 : siphash24_compress(&prefix, sizeof(prefix), state);
137 : }
138 :
139 : _fallthrough_;
140 : case AF_INET6:
141 : /* local address */
142 0 : siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
143 :
144 0 : break;
145 0 : default:
146 : /* treat any other address family as AF_UNSPEC */
147 0 : break;
148 : }
149 0 : }
150 :
151 13 : static int address_compare_func(const Address *a1, const Address *a2) {
152 : int r;
153 :
154 13 : r = CMP(a1->family, a2->family);
155 13 : if (r != 0)
156 2 : return r;
157 :
158 11 : switch (a1->family) {
159 : /* use the same notion of equality as the kernel does */
160 7 : case AF_INET:
161 7 : r = CMP(a1->prefixlen, a2->prefixlen);
162 7 : if (r != 0)
163 1 : return r;
164 :
165 : /* compare the peer prefixes */
166 6 : if (a1->prefixlen != 0) {
167 : /* make sure we don't try to shift by 32.
168 : * See ISO/IEC 9899:TC3 ยง 6.5.7.3. */
169 : uint32_t b1, b2;
170 :
171 1 : if (a1->in_addr_peer.in.s_addr != 0)
172 1 : b1 = be32toh(a1->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
173 : else
174 0 : b1 = be32toh(a1->in_addr.in.s_addr) >> (32 - a1->prefixlen);
175 :
176 1 : if (a2->in_addr_peer.in.s_addr != 0)
177 1 : b2 = be32toh(a2->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
178 : else
179 0 : b2 = be32toh(a2->in_addr.in.s_addr) >> (32 - a1->prefixlen);
180 :
181 1 : r = CMP(b1, b2);
182 1 : if (r != 0)
183 0 : return r;
184 : }
185 :
186 : _fallthrough_;
187 : case AF_INET6:
188 9 : return memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
189 1 : default:
190 : /* treat any other address family as AF_UNSPEC */
191 1 : return 0;
192 : }
193 : }
194 :
195 : DEFINE_PRIVATE_HASH_OPS(address_hash_ops, Address, address_hash_func, address_compare_func);
196 :
197 16 : bool address_equal(Address *a1, Address *a2) {
198 16 : if (a1 == a2)
199 1 : return true;
200 :
201 15 : if (!a1 || !a2)
202 2 : return false;
203 :
204 13 : return address_compare_func(a1, a2) == 0;
205 : }
206 :
207 0 : static int address_establish(Address *address, Link *link) {
208 : bool masq;
209 : int r;
210 :
211 0 : assert(address);
212 0 : assert(link);
213 :
214 0 : masq = link->network &&
215 0 : link->network->ip_masquerade &&
216 0 : address->family == AF_INET &&
217 0 : address->scope < RT_SCOPE_LINK;
218 :
219 : /* Add firewall entry if this is requested */
220 0 : if (address->ip_masquerade_done != masq) {
221 0 : union in_addr_union masked = address->in_addr;
222 0 : in_addr_mask(address->family, &masked, address->prefixlen);
223 :
224 0 : r = fw_add_masquerade(masq, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
225 0 : if (r < 0)
226 0 : return r;
227 :
228 0 : address->ip_masquerade_done = masq;
229 : }
230 :
231 0 : return 0;
232 : }
233 :
234 0 : static int address_add_internal(Link *link, Set **addresses,
235 : int family,
236 : const union in_addr_union *in_addr,
237 : unsigned char prefixlen,
238 : Address **ret) {
239 0 : _cleanup_(address_freep) Address *address = NULL;
240 : int r;
241 :
242 0 : assert(link);
243 0 : assert(addresses);
244 0 : assert(in_addr);
245 :
246 0 : r = address_new(&address);
247 0 : if (r < 0)
248 0 : return r;
249 :
250 0 : address->family = family;
251 0 : address->in_addr = *in_addr;
252 0 : address->prefixlen = prefixlen;
253 : /* Consider address tentative until we get the real flags from the kernel */
254 0 : address->flags = IFA_F_TENTATIVE;
255 :
256 0 : r = set_ensure_allocated(addresses, &address_hash_ops);
257 0 : if (r < 0)
258 0 : return r;
259 :
260 0 : r = set_put(*addresses, address);
261 0 : if (r < 0)
262 0 : return r;
263 0 : if (r == 0)
264 0 : return -EEXIST;
265 :
266 0 : address->link = link;
267 :
268 0 : if (ret)
269 0 : *ret = address;
270 :
271 0 : address = NULL;
272 :
273 0 : return 0;
274 : }
275 :
276 0 : int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
277 0 : return address_add_internal(link, &link->addresses_foreign, family, in_addr, prefixlen, ret);
278 : }
279 :
280 0 : int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
281 : Address *address;
282 : int r;
283 :
284 0 : r = address_get(link, family, in_addr, prefixlen, &address);
285 0 : if (r == -ENOENT) {
286 : /* Address does not exist, create a new one */
287 0 : r = address_add_internal(link, &link->addresses, family, in_addr, prefixlen, &address);
288 0 : if (r < 0)
289 0 : return r;
290 0 : } else if (r == 0) {
291 : /* Take over a foreign address */
292 0 : r = set_ensure_allocated(&link->addresses, &address_hash_ops);
293 0 : if (r < 0)
294 0 : return r;
295 :
296 0 : r = set_put(link->addresses, address);
297 0 : if (r < 0)
298 0 : return r;
299 :
300 0 : set_remove(link->addresses_foreign, address);
301 0 : } else if (r == 1) {
302 : /* Already exists, do nothing */
303 : ;
304 : } else
305 0 : return r;
306 :
307 0 : if (ret)
308 0 : *ret = address;
309 :
310 0 : return 0;
311 : }
312 :
313 0 : static int address_release(Address *address) {
314 : int r;
315 :
316 0 : assert(address);
317 0 : assert(address->link);
318 :
319 : /* Remove masquerading firewall entry if it was added */
320 0 : if (address->ip_masquerade_done) {
321 0 : union in_addr_union masked = address->in_addr;
322 0 : in_addr_mask(address->family, &masked, address->prefixlen);
323 :
324 0 : r = fw_add_masquerade(false, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
325 0 : if (r < 0)
326 0 : return r;
327 :
328 0 : address->ip_masquerade_done = false;
329 : }
330 :
331 0 : return 0;
332 : }
333 :
334 0 : int address_update(
335 : Address *address,
336 : unsigned char flags,
337 : unsigned char scope,
338 : const struct ifa_cacheinfo *cinfo) {
339 :
340 : bool ready;
341 : int r;
342 :
343 0 : assert(address);
344 0 : assert(cinfo);
345 0 : assert_return(address->link, 1);
346 :
347 0 : if (IN_SET(address->link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
348 0 : return 1;
349 :
350 0 : ready = address_is_ready(address);
351 :
352 0 : address->flags = flags;
353 0 : address->scope = scope;
354 0 : address->cinfo = *cinfo;
355 :
356 0 : link_update_operstate(address->link, true);
357 0 : link_check_ready(address->link);
358 :
359 0 : if (!ready &&
360 0 : address_is_ready(address) &&
361 0 : address->family == AF_INET6 &&
362 0 : in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 &&
363 0 : in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) {
364 :
365 0 : r = link_ipv6ll_gained(address->link, &address->in_addr.in6);
366 0 : if (r < 0)
367 0 : return r;
368 : }
369 :
370 0 : return 0;
371 : }
372 :
373 0 : int address_drop(Address *address) {
374 : Link *link;
375 : bool ready;
376 : int r;
377 :
378 0 : assert(address);
379 :
380 0 : ready = address_is_ready(address);
381 0 : link = address->link;
382 :
383 0 : r = address_release(address);
384 0 : if (r < 0)
385 0 : log_link_warning_errno(link, r, "Failed to disable IP masquerading, ignoring: %m");
386 :
387 0 : address_free(address);
388 :
389 0 : link_update_operstate(link, true);
390 :
391 0 : if (link && !ready)
392 0 : link_check_ready(link);
393 :
394 0 : return 0;
395 : }
396 :
397 0 : int address_get(Link *link,
398 : int family,
399 : const union in_addr_union *in_addr,
400 : unsigned char prefixlen,
401 : Address **ret) {
402 :
403 : Address address, *existing;
404 :
405 0 : assert(link);
406 0 : assert(in_addr);
407 :
408 0 : address = (Address) {
409 : .family = family,
410 0 : .in_addr = *in_addr,
411 : .prefixlen = prefixlen,
412 : };
413 :
414 0 : existing = set_get(link->addresses, &address);
415 0 : if (existing) {
416 0 : if (ret)
417 0 : *ret = existing;
418 0 : return 1;
419 : }
420 :
421 0 : existing = set_get(link->addresses_foreign, &address);
422 0 : if (existing) {
423 0 : if (ret)
424 0 : *ret = existing;
425 0 : return 0;
426 : }
427 :
428 0 : return -ENOENT;
429 : }
430 :
431 0 : static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
432 : int r;
433 :
434 0 : assert(m);
435 0 : assert(link);
436 0 : assert(link->ifname);
437 :
438 0 : if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
439 0 : return 1;
440 :
441 0 : r = sd_netlink_message_get_errno(m);
442 0 : if (r < 0 && r != -EADDRNOTAVAIL)
443 0 : log_link_warning_errno(link, r, "Could not drop address: %m");
444 :
445 0 : return 1;
446 : }
447 :
448 0 : int address_remove(
449 : Address *address,
450 : Link *link,
451 : link_netlink_message_handler_t callback) {
452 :
453 0 : _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
454 : int r;
455 :
456 0 : assert(address);
457 0 : assert(IN_SET(address->family, AF_INET, AF_INET6));
458 0 : assert(link);
459 0 : assert(link->ifindex > 0);
460 0 : assert(link->manager);
461 0 : assert(link->manager->rtnl);
462 :
463 0 : if (DEBUG_LOGGING) {
464 0 : _cleanup_free_ char *b = NULL;
465 :
466 0 : (void) in_addr_to_string(address->family, &address->in_addr, &b);
467 0 : log_link_debug(link, "Removing address %s", strna(b));
468 : }
469 :
470 0 : r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
471 : link->ifindex, address->family);
472 0 : if (r < 0)
473 0 : return log_link_error_errno(link, r, "Could not allocate RTM_DELADDR message: %m");
474 :
475 0 : r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
476 0 : if (r < 0)
477 0 : return log_link_error_errno(link, r, "Could not set prefixlen: %m");
478 :
479 0 : r = netlink_message_append_in_addr_union(req, IFA_LOCAL, address->family, &address->in_addr);
480 0 : if (r < 0)
481 0 : return log_link_error_errno(link, r, "Could not append IFA_LOCAL attribute: %m");
482 :
483 0 : r = netlink_call_async(link->manager->rtnl, NULL, req,
484 : callback ?: address_remove_handler,
485 : link_netlink_destroy_callback, link);
486 0 : if (r < 0)
487 0 : return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
488 :
489 0 : link_ref(link);
490 :
491 0 : return 0;
492 : }
493 :
494 0 : static int address_acquire(Link *link, Address *original, Address **ret) {
495 0 : union in_addr_union in_addr = IN_ADDR_NULL;
496 0 : struct in_addr broadcast = {};
497 0 : _cleanup_(address_freep) Address *na = NULL;
498 : int r;
499 :
500 0 : assert(link);
501 0 : assert(original);
502 0 : assert(ret);
503 :
504 : /* Something useful was configured? just use it */
505 0 : r = in_addr_is_null(original->family, &original->in_addr);
506 0 : if (r <= 0)
507 0 : return r;
508 :
509 : /* The address is configured to be 0.0.0.0 or [::] by the user?
510 : * Then let's acquire something more useful from the pool. */
511 0 : r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
512 0 : if (r < 0)
513 0 : return r;
514 0 : if (r == 0)
515 0 : return -EBUSY;
516 :
517 0 : if (original->family == AF_INET) {
518 : /* Pick first address in range for ourselves ... */
519 0 : in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
520 :
521 : /* .. and use last as broadcast address */
522 0 : if (original->prefixlen > 30)
523 0 : broadcast.s_addr = 0;
524 : else
525 0 : broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
526 0 : } else if (original->family == AF_INET6)
527 0 : in_addr.in6.s6_addr[15] |= 1;
528 :
529 0 : r = address_new(&na);
530 0 : if (r < 0)
531 0 : return r;
532 :
533 0 : na->family = original->family;
534 0 : na->prefixlen = original->prefixlen;
535 0 : na->scope = original->scope;
536 0 : na->cinfo = original->cinfo;
537 :
538 0 : if (original->label) {
539 0 : na->label = strdup(original->label);
540 0 : if (!na->label)
541 0 : return -ENOMEM;
542 : }
543 :
544 0 : na->broadcast = broadcast;
545 0 : na->in_addr = in_addr;
546 :
547 0 : LIST_PREPEND(addresses, link->pool_addresses, na);
548 :
549 0 : *ret = TAKE_PTR(na);
550 :
551 0 : return 0;
552 : }
553 :
554 0 : int address_configure(
555 : Address *address,
556 : Link *link,
557 : link_netlink_message_handler_t callback,
558 : bool update) {
559 :
560 0 : _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
561 : int r;
562 :
563 0 : assert(address);
564 0 : assert(IN_SET(address->family, AF_INET, AF_INET6));
565 0 : assert(link);
566 0 : assert(link->ifindex > 0);
567 0 : assert(link->manager);
568 0 : assert(link->manager->rtnl);
569 0 : assert(callback);
570 :
571 0 : if (address->family == AF_INET6 && link_sysctl_ipv6_enabled(link) == 0) {
572 0 : log_link_warning(link, "An IPv6 address is requested, but IPv6 is disabled by sysctl, ignoring.");
573 0 : return 0;
574 : }
575 :
576 : /* If this is a new address, then refuse adding more than the limit */
577 0 : if (address_get(link, address->family, &address->in_addr, address->prefixlen, NULL) <= 0 &&
578 0 : set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
579 0 : return log_link_error_errno(link, SYNTHETIC_ERRNO(E2BIG),
580 : "Too many addresses are configured, refusing: %m");
581 :
582 0 : r = address_acquire(link, address, &address);
583 0 : if (r < 0)
584 0 : return log_link_error_errno(link, r, "Failed to acquire an address from pool: %m");
585 :
586 0 : if (update)
587 0 : r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
588 0 : link->ifindex, address->family);
589 : else
590 0 : r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
591 0 : link->ifindex, address->family);
592 0 : if (r < 0)
593 0 : return log_link_error_errno(link, r, "Could not allocate RTM_NEWADDR message: %m");
594 :
595 0 : r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
596 0 : if (r < 0)
597 0 : return log_link_error_errno(link, r, "Could not set prefixlen: %m");
598 :
599 0 : address->flags |= IFA_F_PERMANENT;
600 :
601 0 : if (address->home_address)
602 0 : address->flags |= IFA_F_HOMEADDRESS;
603 :
604 0 : if (address->duplicate_address_detection)
605 0 : address->flags |= IFA_F_NODAD;
606 :
607 0 : if (address->manage_temporary_address)
608 0 : address->flags |= IFA_F_MANAGETEMPADDR;
609 :
610 0 : if (address->prefix_route)
611 0 : address->flags |= IFA_F_NOPREFIXROUTE;
612 :
613 0 : if (address->autojoin)
614 0 : address->flags |= IFA_F_MCAUTOJOIN;
615 :
616 0 : r = sd_rtnl_message_addr_set_flags(req, (address->flags & 0xff));
617 0 : if (r < 0)
618 0 : return log_link_error_errno(link, r, "Could not set flags: %m");
619 :
620 0 : if (address->flags & ~0xff) {
621 0 : r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags);
622 0 : if (r < 0)
623 0 : return log_link_error_errno(link, r, "Could not set extended flags: %m");
624 : }
625 :
626 0 : r = sd_rtnl_message_addr_set_scope(req, address->scope);
627 0 : if (r < 0)
628 0 : return log_link_error_errno(link, r, "Could not set scope: %m");
629 :
630 0 : r = netlink_message_append_in_addr_union(req, IFA_LOCAL, address->family, &address->in_addr);
631 0 : if (r < 0)
632 0 : return log_link_error_errno(link, r, "Could not append IFA_LOCAL attribute: %m");
633 :
634 0 : if (in_addr_is_null(address->family, &address->in_addr_peer) == 0) {
635 0 : r = netlink_message_append_in_addr_union(req, IFA_ADDRESS, address->family, &address->in_addr_peer);
636 0 : if (r < 0)
637 0 : return log_link_error_errno(link, r, "Could not append IFA_ADDRESS attribute: %m");
638 0 : } else if (address->family == AF_INET && address->prefixlen <= 30) {
639 0 : r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
640 0 : if (r < 0)
641 0 : return log_link_error_errno(link, r, "Could not append IFA_BROADCAST attribute: %m");
642 : }
643 :
644 0 : if (address->label) {
645 0 : r = sd_netlink_message_append_string(req, IFA_LABEL, address->label);
646 0 : if (r < 0)
647 0 : return log_link_error_errno(link, r, "Could not append IFA_LABEL attribute: %m");
648 : }
649 :
650 0 : r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
651 0 : if (r < 0)
652 0 : return log_link_error_errno(link, r, "Could not append IFA_CACHEINFO attribute: %m");
653 :
654 0 : r = address_establish(address, link);
655 0 : if (r < 0)
656 0 : log_link_warning_errno(link, r, "Could not enable IP masquerading, ignoring: %m");
657 :
658 0 : r = netlink_call_async(link->manager->rtnl, NULL, req, callback, link_netlink_destroy_callback, link);
659 0 : if (r < 0) {
660 0 : address_release(address);
661 0 : return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
662 : }
663 :
664 0 : link_ref(link);
665 :
666 0 : if (address->family == AF_INET6 && !in_addr_is_null(address->family, &address->in_addr_peer))
667 0 : r = address_add(link, address->family, &address->in_addr_peer, address->prefixlen, NULL);
668 : else
669 0 : r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
670 0 : if (r < 0) {
671 0 : address_release(address);
672 0 : return log_link_error_errno(link, r, "Could not add address: %m");
673 : }
674 :
675 0 : return 1;
676 : }
677 :
678 0 : int config_parse_broadcast(
679 : const char *unit,
680 : const char *filename,
681 : unsigned line,
682 : const char *section,
683 : unsigned section_line,
684 : const char *lvalue,
685 : int ltype,
686 : const char *rvalue,
687 : void *data,
688 : void *userdata) {
689 :
690 0 : Network *network = userdata;
691 0 : _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
692 : int r;
693 :
694 0 : assert(filename);
695 0 : assert(section);
696 0 : assert(lvalue);
697 0 : assert(rvalue);
698 0 : assert(data);
699 :
700 0 : r = address_new_static(network, filename, section_line, &n);
701 0 : if (r < 0)
702 0 : return r;
703 :
704 0 : if (n->family == AF_INET6) {
705 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
706 : "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
707 0 : return 0;
708 : }
709 :
710 0 : r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
711 0 : if (r < 0) {
712 0 : log_syntax(unit, LOG_ERR, filename, line, r,
713 : "Broadcast is invalid, ignoring assignment: %s", rvalue);
714 0 : return 0;
715 : }
716 :
717 0 : n->family = AF_INET;
718 0 : n = NULL;
719 :
720 0 : return 0;
721 : }
722 :
723 25 : int config_parse_address(const char *unit,
724 : const char *filename,
725 : unsigned line,
726 : const char *section,
727 : unsigned section_line,
728 : const char *lvalue,
729 : int ltype,
730 : const char *rvalue,
731 : void *data,
732 : void *userdata) {
733 :
734 25 : Network *network = userdata;
735 25 : _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
736 : union in_addr_union buffer;
737 : unsigned char prefixlen;
738 : int r, f;
739 :
740 25 : assert(filename);
741 25 : assert(section);
742 25 : assert(lvalue);
743 25 : assert(rvalue);
744 25 : assert(data);
745 :
746 25 : if (streq(section, "Network")) {
747 : /* we are not in an Address section, so treat
748 : * this as the special '0' section */
749 2 : r = address_new_static(network, NULL, 0, &n);
750 : } else
751 23 : r = address_new_static(network, filename, section_line, &n);
752 :
753 25 : if (r < 0)
754 0 : return r;
755 :
756 : /* Address=address/prefixlen */
757 25 : r = in_addr_prefix_from_string_auto_internal(rvalue, PREFIXLEN_REFUSE, &f, &buffer, &prefixlen);
758 25 : if (r == -ENOANO) {
759 2 : log_syntax(unit, LOG_ERR, filename, line, r,
760 : "An address '%s' is specified without prefix length. "
761 : "The behavior of parsing addresses without prefix length will be changed in the future release. "
762 : "Please specify prefix length explicitly.", rvalue);
763 :
764 2 : r = in_addr_prefix_from_string_auto_internal(rvalue, PREFIXLEN_LEGACY, &f, &buffer, &prefixlen);
765 : }
766 25 : if (r < 0) {
767 10 : log_syntax(unit, LOG_ERR, filename, line, r, "Invalid address '%s', ignoring assignment: %m", rvalue);
768 10 : return 0;
769 : }
770 :
771 15 : if (n->family != AF_UNSPEC && f != n->family) {
772 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Address is incompatible, ignoring assignment: %s", rvalue);
773 0 : return 0;
774 : }
775 :
776 15 : if (in_addr_is_null(f, &buffer)) {
777 : /* Will use address from address pool. Note that for ipv6 case, prefix of the address
778 : * pool is 8, but 40 bit is used by the global ID and 16 bit by the subnet ID. So,
779 : * let's limit the prefix length to 64 or larger. See RFC4193. */
780 2 : if ((f == AF_INET && prefixlen < 8) ||
781 2 : (f == AF_INET6 && prefixlen < 64)) {
782 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
783 : "Null address with invalid prefixlen='%u', ignoring assignment: %s",
784 : prefixlen, rvalue);
785 0 : return 0;
786 : }
787 : }
788 :
789 15 : n->family = f;
790 15 : n->prefixlen = prefixlen;
791 :
792 15 : if (streq(lvalue, "Address"))
793 15 : n->in_addr = buffer;
794 : else
795 0 : n->in_addr_peer = buffer;
796 :
797 15 : if (n->family == AF_INET && n->broadcast.s_addr == 0 && n->prefixlen <= 30)
798 6 : n->broadcast.s_addr = n->in_addr.in.s_addr | htobe32(0xfffffffflu >> n->prefixlen);
799 :
800 15 : n = NULL;
801 :
802 15 : return 0;
803 : }
804 :
805 0 : int config_parse_label(
806 : const char *unit,
807 : const char *filename,
808 : unsigned line,
809 : const char *section,
810 : unsigned section_line,
811 : const char *lvalue,
812 : int ltype,
813 : const char *rvalue,
814 : void *data,
815 : void *userdata) {
816 :
817 0 : _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
818 0 : Network *network = userdata;
819 : int r;
820 :
821 0 : assert(filename);
822 0 : assert(section);
823 0 : assert(lvalue);
824 0 : assert(rvalue);
825 0 : assert(data);
826 :
827 0 : r = address_new_static(network, filename, section_line, &n);
828 0 : if (r < 0)
829 0 : return r;
830 :
831 0 : if (!address_label_valid(rvalue)) {
832 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
833 : "Interface label is too long or invalid, ignoring assignment: %s", rvalue);
834 0 : return 0;
835 : }
836 :
837 0 : r = free_and_strdup(&n->label, rvalue);
838 0 : if (r < 0)
839 0 : return log_oom();
840 :
841 0 : n = NULL;
842 0 : return 0;
843 : }
844 :
845 0 : int config_parse_lifetime(const char *unit,
846 : const char *filename,
847 : unsigned line,
848 : const char *section,
849 : unsigned section_line,
850 : const char *lvalue,
851 : int ltype,
852 : const char *rvalue,
853 : void *data,
854 : void *userdata) {
855 0 : Network *network = userdata;
856 0 : _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
857 : unsigned k;
858 : int r;
859 :
860 0 : assert(filename);
861 0 : assert(section);
862 0 : assert(lvalue);
863 0 : assert(rvalue);
864 0 : assert(data);
865 :
866 0 : r = address_new_static(network, filename, section_line, &n);
867 0 : if (r < 0)
868 0 : return r;
869 :
870 : /* We accept only "forever", "infinity", or "0". */
871 0 : if (STR_IN_SET(rvalue, "forever", "infinity"))
872 0 : k = CACHE_INFO_INFINITY_LIFE_TIME;
873 0 : else if (streq(rvalue, "0"))
874 0 : k = 0;
875 : else {
876 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
877 : "Invalid PreferredLifetime= value, ignoring: %s", rvalue);
878 0 : return 0;
879 : }
880 :
881 0 : n->cinfo.ifa_prefered = k;
882 0 : n = NULL;
883 :
884 0 : return 0;
885 : }
886 :
887 0 : int 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 0 : Network *network = userdata;
898 0 : _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
899 : int r;
900 :
901 0 : assert(filename);
902 0 : assert(section);
903 0 : assert(lvalue);
904 0 : assert(rvalue);
905 0 : assert(data);
906 :
907 0 : r = address_new_static(network, filename, section_line, &n);
908 0 : if (r < 0)
909 0 : return r;
910 :
911 0 : r = parse_boolean(rvalue);
912 0 : if (r < 0) {
913 0 : log_syntax(unit, LOG_ERR, filename, line, r,
914 : "Failed to parse address flag, ignoring: %s", rvalue);
915 0 : return 0;
916 : }
917 :
918 0 : if (streq(lvalue, "HomeAddress"))
919 0 : n->home_address = r;
920 0 : else if (streq(lvalue, "DuplicateAddressDetection"))
921 0 : n->duplicate_address_detection = r;
922 0 : else if (streq(lvalue, "ManageTemporaryAddress"))
923 0 : n->manage_temporary_address = r;
924 0 : else if (streq(lvalue, "PrefixRoute"))
925 0 : n->prefix_route = r;
926 0 : else if (streq(lvalue, "AutoJoin"))
927 0 : n->autojoin = r;
928 : else
929 0 : assert_not_reached("Invalid address flag type.");
930 :
931 0 : n = NULL;
932 0 : return 0;
933 : }
934 :
935 0 : int config_parse_address_scope(const char *unit,
936 : const char *filename,
937 : unsigned line,
938 : const char *section,
939 : unsigned section_line,
940 : const char *lvalue,
941 : int ltype,
942 : const char *rvalue,
943 : void *data,
944 : void *userdata) {
945 0 : Network *network = userdata;
946 0 : _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
947 : int r;
948 :
949 0 : assert(filename);
950 0 : assert(section);
951 0 : assert(lvalue);
952 0 : assert(rvalue);
953 0 : assert(data);
954 :
955 0 : r = address_new_static(network, filename, section_line, &n);
956 0 : if (r < 0)
957 0 : return r;
958 :
959 0 : if (streq(rvalue, "host"))
960 0 : n->scope = RT_SCOPE_HOST;
961 0 : else if (streq(rvalue, "link"))
962 0 : n->scope = RT_SCOPE_LINK;
963 0 : else if (streq(rvalue, "global"))
964 0 : n->scope = RT_SCOPE_UNIVERSE;
965 : else {
966 0 : r = safe_atou8(rvalue , &n->scope);
967 0 : if (r < 0) {
968 0 : log_syntax(unit, LOG_ERR, filename, line, r,
969 : "Could not parse address scope \"%s\", ignoring assignment: %m", rvalue);
970 0 : return 0;
971 : }
972 : }
973 :
974 0 : n = NULL;
975 0 : return 0;
976 : }
977 :
978 0 : bool address_is_ready(const Address *a) {
979 0 : assert(a);
980 :
981 0 : return !(a->flags & IFA_F_TENTATIVE);
982 : }
983 :
984 25 : int address_section_verify(Address *address) {
985 25 : if (section_is_invalid(address->section))
986 10 : return -EINVAL;
987 :
988 15 : if (address->family == AF_UNSPEC) {
989 0 : assert(address->section);
990 :
991 0 : return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
992 : "%s: Address section without Address= field configured. "
993 : "Ignoring [Address] section from line %u.",
994 : address->section->filename, address->section->line);
995 : }
996 :
997 15 : return 0;
998 : }
|