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