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