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 "conf-parser.h"
25 #include "firewall-util.h"
26 #include "netlink-util.h"
32 #include "networkd-address.h"
34 int address_new(Address
**ret
) {
35 _cleanup_address_free_ Address
*address
= NULL
;
37 address
= new0(Address
, 1);
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
;
52 int address_new_static(Network
*network
, unsigned section
, Address
**ret
) {
53 _cleanup_address_free_ Address
*address
= NULL
;
57 address
= hashmap_get(network
->addresses_by_section
, UINT_TO_PTR(section
));
66 r
= address_new(&address
);
70 address
->network
= network
;
72 LIST_APPEND(addresses
, network
->static_addresses
, address
);
75 address
->section
= section
;
76 hashmap_put(network
->addresses_by_section
,
77 UINT_TO_PTR(address
->section
), address
);
86 void address_free(Address
*address
) {
90 if (address
->network
) {
91 LIST_REMOVE(addresses
, address
->network
->static_addresses
, address
);
94 hashmap_remove(address
->network
->addresses_by_section
,
95 UINT_TO_PTR(address
->section
));
99 set_remove(address
->link
->addresses
, address
);
100 set_remove(address
->link
->addresses_foreign
, address
);
106 static void address_hash_func(const void *b
, struct siphash
*state
) {
107 const Address
*a
= b
;
111 siphash24_compress(&a
->family
, sizeof(a
->family
), state
);
115 siphash24_compress(&a
->prefixlen
, sizeof(a
->prefixlen
), state
);
118 if (a
->prefixlen
!= 0) {
121 if (a
->in_addr_peer
.in
.s_addr
!= 0)
122 prefix
= be32toh(a
->in_addr_peer
.in
.s_addr
) >> (32 - a
->prefixlen
);
124 prefix
= be32toh(a
->in_addr
.in
.s_addr
) >> (32 - a
->prefixlen
);
126 siphash24_compress(&prefix
, sizeof(prefix
), state
);
132 siphash24_compress(&a
->in_addr
, FAMILY_ADDRESS_SIZE(a
->family
), state
);
136 /* treat any other address family as AF_UNSPEC */
141 static int address_compare_func(const void *c1
, const void *c2
) {
142 const Address
*a1
= c1
, *a2
= c2
;
144 if (a1
->family
< a2
->family
)
146 if (a1
->family
> a2
->family
)
149 switch (a1
->family
) {
150 /* use the same notion of equality as the kernel does */
152 if (a1
->prefixlen
< a2
->prefixlen
)
154 if (a1
->prefixlen
> a2
->prefixlen
)
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. */
163 if (a1
->in_addr_peer
.in
.s_addr
!= 0)
164 b1
= be32toh(a1
->in_addr_peer
.in
.s_addr
) >> (32 - a1
->prefixlen
);
166 b1
= be32toh(a1
->in_addr
.in
.s_addr
) >> (32 - a1
->prefixlen
);
168 if (a2
->in_addr_peer
.in
.s_addr
!= 0)
169 b2
= be32toh(a2
->in_addr_peer
.in
.s_addr
) >> (32 - a1
->prefixlen
);
171 b2
= be32toh(a2
->in_addr
.in
.s_addr
) >> (32 - a1
->prefixlen
);
181 return memcmp(&a1
->in_addr
, &a2
->in_addr
, FAMILY_ADDRESS_SIZE(a1
->family
));
183 /* treat any other address family as AF_UNSPEC */
188 static const struct hash_ops address_hash_ops
= {
189 .hash
= address_hash_func
,
190 .compare
= address_compare_func
193 bool address_equal(Address
*a1
, Address
*a2
) {
200 return address_compare_func(a1
, a2
) == 0;
203 static int address_establish(Address
*address
, Link
*link
) {
210 masq
= link
->network
&&
211 link
->network
->ip_masquerade
&&
212 address
->family
== AF_INET
&&
213 address
->scope
< RT_SCOPE_LINK
;
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
);
220 r
= fw_add_masquerade(masq
, AF_INET
, 0, &masked
, address
->prefixlen
, NULL
, NULL
, 0);
222 log_link_warning_errno(link
, r
, "Could not enable IP masquerading: %m");
224 address
->ip_masquerade_done
= masq
;
230 static int address_add_internal(Link
*link
, Set
**addresses
,
232 const union in_addr_union
*in_addr
,
233 unsigned char prefixlen
,
235 _cleanup_address_free_ Address
*address
= NULL
;
242 r
= address_new(&address
);
246 address
->family
= family
;
247 address
->in_addr
= *in_addr
;
248 address
->prefixlen
= prefixlen
;
250 r
= set_ensure_allocated(addresses
, &address_hash_ops
);
254 r
= set_put(*addresses
, address
);
258 address
->link
= link
;
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
);
272 static int address_add(Link
*link
, int family
, const union in_addr_union
*in_addr
, unsigned char prefixlen
, Address
**ret
) {
275 r
= address_add_internal(link
, &link
->addresses
, family
, in_addr
, prefixlen
, ret
);
279 link_update_operstate(link
);
285 static int address_release(Address
*address
) {
289 assert(address
->link
);
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
);
296 r
= fw_add_masquerade(false, AF_INET
, 0, &masked
, address
->prefixlen
, NULL
, NULL
, 0);
298 log_link_warning_errno(address
->link
, r
, "Failed to disable IP masquerading: %m");
300 address
->ip_masquerade_done
= false;
306 int address_update(Address
*address
, unsigned char flags
, unsigned char scope
, struct ifa_cacheinfo
*cinfo
) {
312 ready
= address_is_ready(address
);
314 address
->added
= true;
315 address
->flags
= flags
;
316 address
->scope
= scope
;
317 address
->cinfo
= *cinfo
;
319 if (!ready
&& address_is_ready(address
) && address
->link
)
320 link_check_ready(address
->link
);
325 int address_drop(Address
*address
) {
331 ready
= address_is_ready(address
);
332 link
= address
->link
;
334 address_release(address
);
335 address_free(address
);
337 link_update_operstate(link
);
340 link_check_ready(link
);
345 int address_get(Link
*link
, int family
, const union in_addr_union
*in_addr
, unsigned char prefixlen
, Address
**ret
) {
346 Address address
= {}, *existing
;
352 address
.family
= family
;
353 address
.in_addr
= *in_addr
;
354 address
.prefixlen
= prefixlen
;
356 existing
= set_get(link
->addresses
, &address
);
358 existing
= set_get(link
->addresses_foreign
, &address
);
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
;
374 assert(address
->family
== AF_INET
|| address
->family
== AF_INET6
);
376 assert(link
->ifindex
> 0);
377 assert(link
->manager
);
378 assert(link
->manager
->rtnl
);
380 r
= sd_rtnl_message_new_addr(link
->manager
->rtnl
, &req
, RTM_DELADDR
,
381 link
->ifindex
, address
->family
);
383 return log_error_errno(r
, "Could not allocate RTM_DELADDR message: %m");
385 r
= sd_rtnl_message_addr_set_prefixlen(req
, address
->prefixlen
);
387 return log_error_errno(r
, "Could not set prefixlen: %m");
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
);
394 return log_error_errno(r
, "Could not append IFA_LOCAL attribute: %m");
396 r
= sd_netlink_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
398 return log_error_errno(r
, "Could not send rtnetlink message: %m");
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
;
415 /* Something useful was configured? just use it */
416 if (in_addr_is_null(original
->family
, &original
->in_addr
) <= 0)
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
);
423 return log_link_error_errno(link
, r
, "Failed to acquire address from pool: %m");
425 log_link_error(link
, "Couldn't find free address for interface, all taken.");
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);
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;
438 r
= address_new(&na
);
442 na
->family
= original
->family
;
443 na
->prefixlen
= original
->prefixlen
;
444 na
->scope
= original
->scope
;
445 na
->cinfo
= original
->cinfo
;
447 if (original
->label
) {
448 na
->label
= strdup(original
->label
);
453 na
->broadcast
= broadcast
;
454 na
->in_addr
= in_addr
;
456 LIST_PREPEND(addresses
, link
->pool_addresses
, na
);
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
;
469 assert(address
->family
== AF_INET
|| address
->family
== AF_INET6
);
471 assert(link
->ifindex
> 0);
472 assert(link
->manager
);
473 assert(link
->manager
->rtnl
);
475 r
= address_acquire(link
, address
, &address
);
480 r
= sd_rtnl_message_new_addr_update(link
->manager
->rtnl
, &req
,
481 link
->ifindex
, address
->family
);
483 r
= sd_rtnl_message_new_addr(link
->manager
->rtnl
, &req
, RTM_NEWADDR
,
484 link
->ifindex
, address
->family
);
486 return log_error_errno(r
, "Could not allocate RTM_NEWADDR message: %m");
488 r
= sd_rtnl_message_addr_set_prefixlen(req
, address
->prefixlen
);
490 return log_error_errno(r
, "Could not set prefixlen: %m");
492 address
->flags
|= IFA_F_PERMANENT
;
494 r
= sd_rtnl_message_addr_set_flags(req
, (address
->flags
& 0xff));
496 return log_error_errno(r
, "Could not set flags: %m");
498 if (address
->flags
& ~0xff) {
499 r
= sd_netlink_message_append_u32(req
, IFA_FLAGS
, address
->flags
);
501 return log_error_errno(r
, "Could not set extended flags: %m");
504 r
= sd_rtnl_message_addr_set_scope(req
, address
->scope
);
506 return log_error_errno(r
, "Could not set scope: %m");
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
);
513 return log_error_errno(r
, "Could not append IFA_LOCAL attribute: %m");
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
);
521 return log_error_errno(r
, "Could not append IFA_ADDRESS attribute: %m");
523 if (address
->family
== AF_INET
) {
524 r
= sd_netlink_message_append_in_addr(req
, IFA_BROADCAST
, &address
->broadcast
);
526 return log_error_errno(r
, "Could not append IFA_BROADCAST attribute: %m");
530 if (address
->label
) {
531 r
= sd_netlink_message_append_string(req
, IFA_LABEL
, address
->label
);
533 return log_error_errno(r
, "Could not append IFA_LABEL attribute: %m");
536 r
= sd_netlink_message_append_cache_info(req
, IFA_CACHEINFO
,
539 return log_error_errno(r
, "Could not append IFA_CACHEINFO attribute: %m");
541 r
= address_establish(address
, link
);
545 r
= sd_netlink_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
547 address_release(address
);
548 return log_error_errno(r
, "Could not send rtnetlink message: %m");
553 r
= address_add(link
, address
->family
, &address
->in_addr
, address
->prefixlen
, NULL
);
555 address_release(address
);
556 return log_error_errno(r
, "Could not add address: %m");
562 int config_parse_broadcast(
564 const char *filename
,
567 unsigned section_line
,
574 Network
*network
= userdata
;
575 _cleanup_address_free_ Address
*n
= NULL
;
584 r
= address_new_static(network
, section_line
, &n
);
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
);
593 r
= in_addr_from_string(AF_INET
, rvalue
, (union in_addr_union
*) &n
->broadcast
);
595 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Broadcast is invalid, ignoring assignment: %s", rvalue
);
605 int config_parse_address(const char *unit
,
606 const char *filename
,
609 unsigned section_line
,
616 Network
*network
= userdata
;
617 _cleanup_address_free_ Address
*n
= NULL
;
618 const char *address
, *e
;
619 union in_addr_union buffer
;
628 if (streq(section
, "Network")) {
629 /* we are not in an Address section, so treat
630 * this as the special '0' section */
634 r
= address_new_static(network
, section_line
, &n
);
638 /* Address=address/prefixlen */
641 e
= strchr(rvalue
, '/');
645 r
= safe_atou(e
+ 1, &i
);
647 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Prefix length is invalid, ignoring assignment: %s", e
+ 1);
651 n
->prefixlen
= (unsigned char) i
;
653 address
= strndupa(rvalue
, e
- rvalue
);
657 r
= in_addr_from_string_auto(address
, &f
, &buffer
);
659 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Address is invalid, ignoring assignment: %s", address
);
663 if (!e
&& f
== AF_INET
) {
664 r
= in_addr_default_prefixlen(&buffer
.in
, &n
->prefixlen
);
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
);
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
);
678 if (streq(lvalue
, "Address"))
681 n
->in_addr_peer
= buffer
;
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
);
691 int config_parse_label(const char *unit
,
692 const char *filename
,
695 unsigned section_line
,
701 Network
*network
= userdata
;
702 _cleanup_address_free_ Address
*n
= NULL
;
712 r
= address_new_static(network
, section_line
, &n
);
716 label
= strdup(rvalue
);
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
);
739 bool address_is_ready(const Address
*a
) {
742 return a
->added
&& !(a
->flags
& (IFA_F_TENTATIVE
| IFA_F_DEPRECATED
));