1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
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"
30 #include "parse-util.h"
32 #include "string-util.h"
36 int address_new(Address
**ret
) {
37 _cleanup_address_free_ Address
*address
= NULL
;
39 address
= new0(Address
, 1);
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
;
54 int address_new_static(Network
*network
, unsigned section
, Address
**ret
) {
55 _cleanup_address_free_ Address
*address
= NULL
;
59 address
= hashmap_get(network
->addresses_by_section
, UINT_TO_PTR(section
));
68 r
= address_new(&address
);
72 address
->network
= network
;
74 LIST_APPEND(addresses
, network
->static_addresses
, address
);
77 address
->section
= section
;
78 hashmap_put(network
->addresses_by_section
,
79 UINT_TO_PTR(address
->section
), address
);
88 void address_free(Address
*address
) {
92 if (address
->network
) {
93 LIST_REMOVE(addresses
, address
->network
->static_addresses
, address
);
96 hashmap_remove(address
->network
->addresses_by_section
,
97 UINT_TO_PTR(address
->section
));
101 set_remove(address
->link
->addresses
, address
);
102 set_remove(address
->link
->addresses_foreign
, address
);
108 static void address_hash_func(const void *b
, struct siphash
*state
) {
109 const Address
*a
= b
;
113 siphash24_compress(&a
->family
, sizeof(a
->family
), state
);
117 siphash24_compress(&a
->prefixlen
, sizeof(a
->prefixlen
), state
);
120 if (a
->prefixlen
!= 0) {
123 if (a
->in_addr_peer
.in
.s_addr
!= 0)
124 prefix
= be32toh(a
->in_addr_peer
.in
.s_addr
) >> (32 - a
->prefixlen
);
126 prefix
= be32toh(a
->in_addr
.in
.s_addr
) >> (32 - a
->prefixlen
);
128 siphash24_compress(&prefix
, sizeof(prefix
), state
);
134 siphash24_compress(&a
->in_addr
, FAMILY_ADDRESS_SIZE(a
->family
), state
);
138 /* treat any other address family as AF_UNSPEC */
143 static int address_compare_func(const void *c1
, const void *c2
) {
144 const Address
*a1
= c1
, *a2
= c2
;
146 if (a1
->family
< a2
->family
)
148 if (a1
->family
> a2
->family
)
151 switch (a1
->family
) {
152 /* use the same notion of equality as the kernel does */
154 if (a1
->prefixlen
< a2
->prefixlen
)
156 if (a1
->prefixlen
> a2
->prefixlen
)
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. */
165 if (a1
->in_addr_peer
.in
.s_addr
!= 0)
166 b1
= be32toh(a1
->in_addr_peer
.in
.s_addr
) >> (32 - a1
->prefixlen
);
168 b1
= be32toh(a1
->in_addr
.in
.s_addr
) >> (32 - a1
->prefixlen
);
170 if (a2
->in_addr_peer
.in
.s_addr
!= 0)
171 b2
= be32toh(a2
->in_addr_peer
.in
.s_addr
) >> (32 - a1
->prefixlen
);
173 b2
= be32toh(a2
->in_addr
.in
.s_addr
) >> (32 - a1
->prefixlen
);
183 return memcmp(&a1
->in_addr
, &a2
->in_addr
, FAMILY_ADDRESS_SIZE(a1
->family
));
185 /* treat any other address family as AF_UNSPEC */
190 static const struct hash_ops address_hash_ops
= {
191 .hash
= address_hash_func
,
192 .compare
= address_compare_func
195 bool address_equal(Address
*a1
, Address
*a2
) {
202 return address_compare_func(a1
, a2
) == 0;
205 static int address_establish(Address
*address
, Link
*link
) {
212 masq
= link
->network
&&
213 link
->network
->ip_masquerade
&&
214 address
->family
== AF_INET
&&
215 address
->scope
< RT_SCOPE_LINK
;
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
);
222 r
= fw_add_masquerade(masq
, AF_INET
, 0, &masked
, address
->prefixlen
, NULL
, NULL
, 0);
224 log_link_warning_errno(link
, r
, "Could not enable IP masquerading: %m");
226 address
->ip_masquerade_done
= masq
;
232 static int address_add_internal(Link
*link
, Set
**addresses
,
234 const union in_addr_union
*in_addr
,
235 unsigned char prefixlen
,
237 _cleanup_address_free_ Address
*address
= NULL
;
244 r
= address_new(&address
);
248 address
->family
= family
;
249 address
->in_addr
= *in_addr
;
250 address
->prefixlen
= prefixlen
;
252 r
= set_ensure_allocated(addresses
, &address_hash_ops
);
256 r
= set_put(*addresses
, address
);
260 address
->link
= link
;
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
);
274 static int address_add(Link
*link
, int family
, const union in_addr_union
*in_addr
, unsigned char prefixlen
, Address
**ret
) {
277 r
= address_add_internal(link
, &link
->addresses
, family
, in_addr
, prefixlen
, ret
);
281 link_update_operstate(link
);
287 static int address_release(Address
*address
) {
291 assert(address
->link
);
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
);
298 r
= fw_add_masquerade(false, AF_INET
, 0, &masked
, address
->prefixlen
, NULL
, NULL
, 0);
300 log_link_warning_errno(address
->link
, r
, "Failed to disable IP masquerading: %m");
302 address
->ip_masquerade_done
= false;
308 int address_update(Address
*address
, unsigned char flags
, unsigned char scope
, struct ifa_cacheinfo
*cinfo
) {
314 ready
= address_is_ready(address
);
316 address
->added
= true;
317 address
->flags
= flags
;
318 address
->scope
= scope
;
319 address
->cinfo
= *cinfo
;
321 if (!ready
&& address_is_ready(address
) && address
->link
)
322 link_check_ready(address
->link
);
327 int address_drop(Address
*address
) {
333 ready
= address_is_ready(address
);
334 link
= address
->link
;
336 address_release(address
);
337 address_free(address
);
339 link_update_operstate(link
);
342 link_check_ready(link
);
347 int address_get(Link
*link
, int family
, const union in_addr_union
*in_addr
, unsigned char prefixlen
, Address
**ret
) {
348 Address address
= {}, *existing
;
354 address
.family
= family
;
355 address
.in_addr
= *in_addr
;
356 address
.prefixlen
= prefixlen
;
358 existing
= set_get(link
->addresses
, &address
);
360 existing
= set_get(link
->addresses_foreign
, &address
);
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
;
376 assert(address
->family
== AF_INET
|| address
->family
== AF_INET6
);
378 assert(link
->ifindex
> 0);
379 assert(link
->manager
);
380 assert(link
->manager
->rtnl
);
382 r
= sd_rtnl_message_new_addr(link
->manager
->rtnl
, &req
, RTM_DELADDR
,
383 link
->ifindex
, address
->family
);
385 return log_error_errno(r
, "Could not allocate RTM_DELADDR message: %m");
387 r
= sd_rtnl_message_addr_set_prefixlen(req
, address
->prefixlen
);
389 return log_error_errno(r
, "Could not set prefixlen: %m");
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
);
396 return log_error_errno(r
, "Could not append IFA_LOCAL attribute: %m");
398 r
= sd_netlink_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
400 return log_error_errno(r
, "Could not send rtnetlink message: %m");
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
;
417 /* Something useful was configured? just use it */
418 if (in_addr_is_null(original
->family
, &original
->in_addr
) <= 0)
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
);
425 return log_link_error_errno(link
, r
, "Failed to acquire address from pool: %m");
427 log_link_error(link
, "Couldn't find free address for interface, all taken.");
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);
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;
440 r
= address_new(&na
);
444 na
->family
= original
->family
;
445 na
->prefixlen
= original
->prefixlen
;
446 na
->scope
= original
->scope
;
447 na
->cinfo
= original
->cinfo
;
449 if (original
->label
) {
450 na
->label
= strdup(original
->label
);
455 na
->broadcast
= broadcast
;
456 na
->in_addr
= in_addr
;
458 LIST_PREPEND(addresses
, link
->pool_addresses
, na
);
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
;
471 assert(address
->family
== AF_INET
|| address
->family
== AF_INET6
);
473 assert(link
->ifindex
> 0);
474 assert(link
->manager
);
475 assert(link
->manager
->rtnl
);
477 r
= address_acquire(link
, address
, &address
);
482 r
= sd_rtnl_message_new_addr_update(link
->manager
->rtnl
, &req
,
483 link
->ifindex
, address
->family
);
485 r
= sd_rtnl_message_new_addr(link
->manager
->rtnl
, &req
, RTM_NEWADDR
,
486 link
->ifindex
, address
->family
);
488 return log_error_errno(r
, "Could not allocate RTM_NEWADDR message: %m");
490 r
= sd_rtnl_message_addr_set_prefixlen(req
, address
->prefixlen
);
492 return log_error_errno(r
, "Could not set prefixlen: %m");
494 address
->flags
|= IFA_F_PERMANENT
;
496 r
= sd_rtnl_message_addr_set_flags(req
, (address
->flags
& 0xff));
498 return log_error_errno(r
, "Could not set flags: %m");
500 if (address
->flags
& ~0xff) {
501 r
= sd_netlink_message_append_u32(req
, IFA_FLAGS
, address
->flags
);
503 return log_error_errno(r
, "Could not set extended flags: %m");
506 r
= sd_rtnl_message_addr_set_scope(req
, address
->scope
);
508 return log_error_errno(r
, "Could not set scope: %m");
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
);
515 return log_error_errno(r
, "Could not append IFA_LOCAL attribute: %m");
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
);
523 return log_error_errno(r
, "Could not append IFA_ADDRESS attribute: %m");
525 if (address
->family
== AF_INET
) {
526 r
= sd_netlink_message_append_in_addr(req
, IFA_BROADCAST
, &address
->broadcast
);
528 return log_error_errno(r
, "Could not append IFA_BROADCAST attribute: %m");
532 if (address
->label
) {
533 r
= sd_netlink_message_append_string(req
, IFA_LABEL
, address
->label
);
535 return log_error_errno(r
, "Could not append IFA_LABEL attribute: %m");
538 r
= sd_netlink_message_append_cache_info(req
, IFA_CACHEINFO
,
541 return log_error_errno(r
, "Could not append IFA_CACHEINFO attribute: %m");
543 r
= address_establish(address
, link
);
547 r
= sd_netlink_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
549 address_release(address
);
550 return log_error_errno(r
, "Could not send rtnetlink message: %m");
555 r
= address_add(link
, address
->family
, &address
->in_addr
, address
->prefixlen
, NULL
);
557 address_release(address
);
558 return log_error_errno(r
, "Could not add address: %m");
564 int config_parse_broadcast(
566 const char *filename
,
569 unsigned section_line
,
576 Network
*network
= userdata
;
577 _cleanup_address_free_ Address
*n
= NULL
;
586 r
= address_new_static(network
, section_line
, &n
);
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
);
595 r
= in_addr_from_string(AF_INET
, rvalue
, (union in_addr_union
*) &n
->broadcast
);
597 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Broadcast is invalid, ignoring assignment: %s", rvalue
);
607 int config_parse_address(const char *unit
,
608 const char *filename
,
611 unsigned section_line
,
618 Network
*network
= userdata
;
619 _cleanup_address_free_ Address
*n
= NULL
;
620 const char *address
, *e
;
621 union in_addr_union buffer
;
630 if (streq(section
, "Network")) {
631 /* we are not in an Address section, so treat
632 * this as the special '0' section */
636 r
= address_new_static(network
, section_line
, &n
);
640 /* Address=address/prefixlen */
643 e
= strchr(rvalue
, '/');
647 r
= safe_atou(e
+ 1, &i
);
649 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Prefix length is invalid, ignoring assignment: %s", e
+ 1);
653 n
->prefixlen
= (unsigned char) i
;
655 address
= strndupa(rvalue
, e
- rvalue
);
659 r
= in_addr_from_string_auto(address
, &f
, &buffer
);
661 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Address is invalid, ignoring assignment: %s", address
);
665 if (!e
&& f
== AF_INET
) {
666 r
= in_addr_default_prefixlen(&buffer
.in
, &n
->prefixlen
);
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
);
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
);
680 if (streq(lvalue
, "Address"))
683 n
->in_addr_peer
= buffer
;
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
);
693 int config_parse_label(const char *unit
,
694 const char *filename
,
697 unsigned section_line
,
703 Network
*network
= userdata
;
704 _cleanup_address_free_ Address
*n
= NULL
;
714 r
= address_new_static(network
, section_line
, &n
);
718 label
= strdup(rvalue
);
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
);
741 bool address_is_ready(const Address
*a
) {
744 return a
->added
&& !(a
->flags
& (IFA_F_TENTATIVE
| IFA_F_DEPRECATED
));