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