Branch data 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 : 108 : int address_new(Address **ret) {
24 : 108 : _cleanup_(address_freep) Address *address = NULL;
25 : :
26 : 108 : address = new(Address, 1);
27 [ - + ]: 108 : if (!address)
28 : 0 : return -ENOMEM;
29 : :
30 : 108 : *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 : 108 : *ret = TAKE_PTR(address);
38 : :
39 : 108 : return 0;
40 : : }
41 : :
42 : 100 : static int address_new_static(Network *network, const char *filename, unsigned section_line, Address **ret) {
43 : 100 : _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
44 : 100 : _cleanup_(address_freep) Address *address = NULL;
45 : : int r;
46 : :
47 [ - + ]: 100 : assert(network);
48 [ - + ]: 100 : assert(ret);
49 [ - + ]: 100 : assert(!!filename == (section_line > 0));
50 : :
51 [ + + ]: 100 : if (filename) {
52 : 92 : r = network_config_section_new(filename, section_line, &n);
53 [ - + ]: 92 : if (r < 0)
54 : 0 : return r;
55 : :
56 : 92 : address = hashmap_get(network->addresses_by_section, n);
57 [ - + ]: 92 : if (address) {
58 : 0 : *ret = TAKE_PTR(address);
59 : :
60 : 0 : return 0;
61 : : }
62 : : }
63 : :
64 [ - + ]: 100 : if (network->n_static_addresses >= STATIC_ADDRESSES_PER_NETWORK_MAX)
65 : 0 : return -E2BIG;
66 : :
67 : 100 : r = address_new(&address);
68 [ - + ]: 100 : if (r < 0)
69 : 0 : return r;
70 : :
71 : 100 : address->network = network;
72 [ + - # # : 100 : LIST_APPEND(addresses, network->static_addresses, address);
- + + - -
+ # # ]
73 : 100 : network->n_static_addresses++;
74 : :
75 [ + + ]: 100 : if (filename) {
76 : 92 : address->section = TAKE_PTR(n);
77 : :
78 : 92 : r = hashmap_ensure_allocated(&network->addresses_by_section, &network_config_hash_ops);
79 [ - + ]: 92 : if (r < 0)
80 : 0 : return r;
81 : :
82 : 92 : r = hashmap_put(network->addresses_by_section, address->section, address);
83 [ - + ]: 92 : if (r < 0)
84 : 0 : return r;
85 : : }
86 : :
87 : 100 : *ret = TAKE_PTR(address);
88 : :
89 : 100 : return 0;
90 : : }
91 : :
92 : 108 : void address_free(Address *address) {
93 [ - + ]: 108 : if (!address)
94 : 0 : return;
95 : :
96 [ + + ]: 108 : if (address->network) {
97 [ - + - + : 100 : LIST_REMOVE(addresses, address->network->static_addresses, address);
- + - + ]
98 [ - + ]: 100 : assert(address->network->n_static_addresses > 0);
99 : 100 : address->network->n_static_addresses--;
100 : :
101 [ + + ]: 100 : if (address->section)
102 : 92 : hashmap_remove(address->network->addresses_by_section, address->section);
103 : : }
104 : :
105 [ - + ]: 108 : 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 : 108 : network_config_section_free(address->section);
114 : 108 : free(address->label);
115 : 108 : 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 : 52 : static int address_compare_func(const Address *a1, const Address *a2) {
152 : : int r;
153 : :
154 [ + - ]: 52 : r = CMP(a1->family, a2->family);
155 [ + + ]: 52 : if (r != 0)
156 : 8 : return r;
157 : :
158 [ + + + ]: 44 : switch (a1->family) {
159 : : /* use the same notion of equality as the kernel does */
160 : 28 : case AF_INET:
161 [ + - ]: 28 : r = CMP(a1->prefixlen, a2->prefixlen);
162 [ + + ]: 28 : if (r != 0)
163 : 4 : return r;
164 : :
165 : : /* compare the peer prefixes */
166 [ + + ]: 24 : 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 [ + - ]: 4 : if (a1->in_addr_peer.in.s_addr != 0)
172 : 4 : 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 [ + - ]: 4 : if (a2->in_addr_peer.in.s_addr != 0)
177 : 4 : 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 [ + - ]: 4 : r = CMP(b1, b2);
182 [ - + ]: 4 : if (r != 0)
183 : 0 : return r;
184 : : }
185 : :
186 : : _fallthrough_;
187 : : case AF_INET6:
188 : 36 : return memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
189 : 4 : default:
190 : : /* treat any other address family as AF_UNSPEC */
191 : 4 : return 0;
192 : : }
193 : : }
194 : :
195 : : DEFINE_PRIVATE_HASH_OPS(address_hash_ops, Address, address_hash_func, address_compare_func);
196 : :
197 : 64 : bool address_equal(Address *a1, Address *a2) {
198 [ + + ]: 64 : if (a1 == a2)
199 : 4 : return true;
200 : :
201 [ + + + + ]: 60 : if (!a1 || !a2)
202 : 8 : return false;
203 : :
204 : 52 : 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 : 100 : 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 : 100 : Network *network = userdata;
735 : 100 : _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 [ - + ]: 100 : assert(filename);
741 [ - + ]: 100 : assert(section);
742 [ - + ]: 100 : assert(lvalue);
743 [ - + ]: 100 : assert(rvalue);
744 [ - + ]: 100 : assert(data);
745 : :
746 [ + + ]: 100 : if (streq(section, "Network")) {
747 : : /* we are not in an Address section, so treat
748 : : * this as the special '0' section */
749 : 8 : r = address_new_static(network, NULL, 0, &n);
750 : : } else
751 : 92 : r = address_new_static(network, filename, section_line, &n);
752 : :
753 [ - + ]: 100 : if (r < 0)
754 : 0 : return r;
755 : :
756 : : /* Address=address/prefixlen */
757 : 100 : r = in_addr_prefix_from_string_auto_internal(rvalue, PREFIXLEN_REFUSE, &f, &buffer, &prefixlen);
758 [ + + ]: 100 : if (r == -ENOANO) {
759 [ + - ]: 8 : 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 : 8 : r = in_addr_prefix_from_string_auto_internal(rvalue, PREFIXLEN_LEGACY, &f, &buffer, &prefixlen);
765 : : }
766 [ + + ]: 100 : if (r < 0) {
767 [ + - ]: 40 : log_syntax(unit, LOG_ERR, filename, line, r, "Invalid address '%s', ignoring assignment: %m", rvalue);
768 : 40 : return 0;
769 : : }
770 : :
771 [ - + # # ]: 60 : 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 [ + + ]: 60 : 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 [ + - + - ]: 8 : if ((f == AF_INET && prefixlen < 8) ||
781 [ - + # # ]: 8 : (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 : 60 : n->family = f;
790 : 60 : n->prefixlen = prefixlen;
791 : :
792 [ + - ]: 60 : if (streq(lvalue, "Address"))
793 : 60 : n->in_addr = buffer;
794 : : else
795 : 0 : n->in_addr_peer = buffer;
796 : :
797 [ + + + - : 60 : if (n->family == AF_INET && n->broadcast.s_addr == 0 && n->prefixlen <= 30)
+ + ]
798 : 24 : n->broadcast.s_addr = n->in_addr.in.s_addr | htobe32(0xfffffffflu >> n->prefixlen);
799 : :
800 : 60 : n = NULL;
801 : :
802 : 60 : 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 : 100 : int address_section_verify(Address *address) {
985 [ + + ]: 100 : if (section_is_invalid(address->section))
986 : 40 : return -EINVAL;
987 : :
988 [ - + ]: 60 : 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 : 60 : return 0;
998 : : }
|