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