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
);
104 static void address_hash_func(const void *b
, struct siphash
*state
) {
105 const Address
*a
= b
;
109 siphash24_compress(&a
->family
, sizeof(a
->family
), state
);
113 siphash24_compress(&a
->prefixlen
, sizeof(a
->prefixlen
), state
);
116 if (a
->prefixlen
!= 0) {
119 if (a
->in_addr_peer
.in
.s_addr
!= 0)
120 prefix
= be32toh(a
->in_addr_peer
.in
.s_addr
) >> (32 - a
->prefixlen
);
122 prefix
= be32toh(a
->in_addr
.in
.s_addr
) >> (32 - a
->prefixlen
);
124 siphash24_compress(&prefix
, sizeof(prefix
), state
);
130 siphash24_compress(&a
->in_addr
, FAMILY_ADDRESS_SIZE(a
->family
), state
);
134 /* treat any other address family as AF_UNSPEC */
139 static int address_compare_func(const void *c1
, const void *c2
) {
140 const Address
*a1
= c1
, *a2
= c2
;
142 if (a1
->family
< a2
->family
)
144 if (a1
->family
> a2
->family
)
147 switch (a1
->family
) {
148 /* use the same notion of equality as the kernel does */
150 if (a1
->prefixlen
< a2
->prefixlen
)
152 if (a1
->prefixlen
> a2
->prefixlen
)
155 /* compare the peer prefixes */
156 if (a1
->prefixlen
!= 0) {
157 /* make sure we don't try to shift by 32.
158 * See ISO/IEC 9899:TC3 ยง 6.5.7.3. */
161 if (a1
->in_addr_peer
.in
.s_addr
!= 0)
162 b1
= be32toh(a1
->in_addr_peer
.in
.s_addr
) >> (32 - a1
->prefixlen
);
164 b1
= be32toh(a1
->in_addr
.in
.s_addr
) >> (32 - a1
->prefixlen
);
166 if (a2
->in_addr_peer
.in
.s_addr
!= 0)
167 b2
= be32toh(a2
->in_addr_peer
.in
.s_addr
) >> (32 - a1
->prefixlen
);
169 b2
= be32toh(a2
->in_addr
.in
.s_addr
) >> (32 - a1
->prefixlen
);
179 return memcmp(&a1
->in_addr
, &a2
->in_addr
, FAMILY_ADDRESS_SIZE(a1
->family
));
181 /* treat any other address family as AF_UNSPEC */
186 static const struct hash_ops address_hash_ops
= {
187 .hash
= address_hash_func
,
188 .compare
= address_compare_func
191 bool address_equal(Address
*a1
, Address
*a2
) {
198 return address_compare_func(a1
, a2
) == 0;
201 static int address_establish(Address
*address
, Link
*link
) {
208 masq
= link
->network
&&
209 link
->network
->ip_masquerade
&&
210 address
->family
== AF_INET
&&
211 address
->scope
< RT_SCOPE_LINK
;
213 /* Add firewall entry if this is requested */
214 if (address
->ip_masquerade_done
!= masq
) {
215 union in_addr_union masked
= address
->in_addr
;
216 in_addr_mask(address
->family
, &masked
, address
->prefixlen
);
218 r
= fw_add_masquerade(masq
, AF_INET
, 0, &masked
, address
->prefixlen
, NULL
, NULL
, 0);
220 log_link_warning_errno(link
, r
, "Could not enable IP masquerading: %m");
222 address
->ip_masquerade_done
= masq
;
228 int address_add(Link
*link
, int family
, const union in_addr_union
*in_addr
, unsigned char prefixlen
, Address
**ret
) {
229 _cleanup_address_free_ Address
*address
= NULL
;
236 r
= address_new(&address
);
240 address
->family
= family
;
241 address
->in_addr
= *in_addr
;
242 address
->prefixlen
= prefixlen
;
244 r
= set_ensure_allocated(&link
->addresses
, &address_hash_ops
);
248 r
= set_put(link
->addresses
, address
);
252 address
->link
= link
;
260 static int address_release(Address
*address
) {
264 assert(address
->link
);
266 /* Remove masquerading firewall entry if it was added */
267 if (address
->ip_masquerade_done
) {
268 union in_addr_union masked
= address
->in_addr
;
269 in_addr_mask(address
->family
, &masked
, address
->prefixlen
);
271 r
= fw_add_masquerade(false, AF_INET
, 0, &masked
, address
->prefixlen
, NULL
, NULL
, 0);
273 log_link_warning_errno(address
->link
, r
, "Failed to disable IP masquerading: %m");
275 address
->ip_masquerade_done
= false;
281 int address_update(Address
*address
, unsigned char flags
, unsigned char scope
, struct ifa_cacheinfo
*cinfo
) {
287 ready
= address_is_ready(address
);
289 address
->flags
= flags
;
290 address
->scope
= scope
;
291 address
->cinfo
= *cinfo
;
293 if (!ready
&& address_is_ready(address
) && address
->link
)
294 link_check_ready(address
->link
);
299 int address_drop(Address
*address
) {
305 ready
= address_is_ready(address
);
306 link
= address
->link
;
308 address_release(address
);
309 address_free(address
);
312 link_check_ready(link
);
317 int address_get(Link
*link
, int family
, const union in_addr_union
*in_addr
, unsigned char prefixlen
, Address
**ret
) {
318 Address address
= {}, *existing
;
324 address
.family
= family
;
325 address
.in_addr
= *in_addr
;
326 address
.prefixlen
= prefixlen
;
328 existing
= set_get(link
->addresses
, &address
);
337 int address_remove(Address
*address
, Link
*link
,
338 sd_netlink_message_handler_t callback
) {
339 _cleanup_netlink_message_unref_ sd_netlink_message
*req
= NULL
;
343 assert(address
->family
== AF_INET
|| address
->family
== AF_INET6
);
345 assert(link
->ifindex
> 0);
346 assert(link
->manager
);
347 assert(link
->manager
->rtnl
);
349 r
= sd_rtnl_message_new_addr(link
->manager
->rtnl
, &req
, RTM_DELADDR
,
350 link
->ifindex
, address
->family
);
352 return log_error_errno(r
, "Could not allocate RTM_DELADDR message: %m");
354 r
= sd_rtnl_message_addr_set_prefixlen(req
, address
->prefixlen
);
356 return log_error_errno(r
, "Could not set prefixlen: %m");
358 if (address
->family
== AF_INET
)
359 r
= sd_netlink_message_append_in_addr(req
, IFA_LOCAL
, &address
->in_addr
.in
);
360 else if (address
->family
== AF_INET6
)
361 r
= sd_netlink_message_append_in6_addr(req
, IFA_LOCAL
, &address
->in_addr
.in6
);
363 return log_error_errno(r
, "Could not append IFA_LOCAL attribute: %m");
365 r
= sd_netlink_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
367 return log_error_errno(r
, "Could not send rtnetlink message: %m");
374 static int address_acquire(Link
*link
, Address
*original
, Address
**ret
) {
375 union in_addr_union in_addr
= {};
376 struct in_addr broadcast
= {};
377 _cleanup_address_free_ Address
*na
= NULL
;
384 /* Something useful was configured? just use it */
385 if (in_addr_is_null(original
->family
, &original
->in_addr
) <= 0)
388 /* The address is configured to be 0.0.0.0 or [::] by the user?
389 * Then let's acquire something more useful from the pool. */
390 r
= manager_address_pool_acquire(link
->manager
, original
->family
, original
->prefixlen
, &in_addr
);
392 return log_link_error_errno(link
, r
, "Failed to acquire address from pool: %m");
394 log_link_error(link
, "Couldn't find free address for interface, all taken.");
398 if (original
->family
== AF_INET
) {
399 /* Pick first address in range for ourselves ... */
400 in_addr
.in
.s_addr
= in_addr
.in
.s_addr
| htobe32(1);
402 /* .. and use last as broadcast address */
403 broadcast
.s_addr
= in_addr
.in
.s_addr
| htobe32(0xFFFFFFFFUL
>> original
->prefixlen
);
404 } else if (original
->family
== AF_INET6
)
405 in_addr
.in6
.s6_addr
[15] |= 1;
407 r
= address_new(&na
);
411 na
->family
= original
->family
;
412 na
->prefixlen
= original
->prefixlen
;
413 na
->scope
= original
->scope
;
414 na
->cinfo
= original
->cinfo
;
416 if (original
->label
) {
417 na
->label
= strdup(original
->label
);
422 na
->broadcast
= broadcast
;
423 na
->in_addr
= in_addr
;
425 LIST_PREPEND(addresses
, link
->pool_addresses
, na
);
433 int address_configure(Address
*address
, Link
*link
, sd_netlink_message_handler_t callback
, bool update
) {
434 _cleanup_netlink_message_unref_ sd_netlink_message
*req
= NULL
;
438 assert(address
->family
== AF_INET
|| address
->family
== AF_INET6
);
440 assert(link
->ifindex
> 0);
441 assert(link
->manager
);
442 assert(link
->manager
->rtnl
);
444 r
= address_acquire(link
, address
, &address
);
449 r
= sd_rtnl_message_new_addr_update(link
->manager
->rtnl
, &req
,
450 link
->ifindex
, address
->family
);
452 r
= sd_rtnl_message_new_addr(link
->manager
->rtnl
, &req
, RTM_NEWADDR
,
453 link
->ifindex
, address
->family
);
455 return log_error_errno(r
, "Could not allocate RTM_NEWADDR message: %m");
457 r
= sd_rtnl_message_addr_set_prefixlen(req
, address
->prefixlen
);
459 return log_error_errno(r
, "Could not set prefixlen: %m");
461 address
->flags
|= IFA_F_PERMANENT
;
463 r
= sd_rtnl_message_addr_set_flags(req
, (address
->flags
& 0xff));
465 return log_error_errno(r
, "Could not set flags: %m");
467 if (address
->flags
& ~0xff) {
468 r
= sd_netlink_message_append_u32(req
, IFA_FLAGS
, address
->flags
);
470 return log_error_errno(r
, "Could not set extended flags: %m");
473 r
= sd_rtnl_message_addr_set_scope(req
, address
->scope
);
475 return log_error_errno(r
, "Could not set scope: %m");
477 if (address
->family
== AF_INET
)
478 r
= sd_netlink_message_append_in_addr(req
, IFA_LOCAL
, &address
->in_addr
.in
);
479 else if (address
->family
== AF_INET6
)
480 r
= sd_netlink_message_append_in6_addr(req
, IFA_LOCAL
, &address
->in_addr
.in6
);
482 return log_error_errno(r
, "Could not append IFA_LOCAL attribute: %m");
484 if (!in_addr_is_null(address
->family
, &address
->in_addr_peer
)) {
485 if (address
->family
== AF_INET
)
486 r
= sd_netlink_message_append_in_addr(req
, IFA_ADDRESS
, &address
->in_addr_peer
.in
);
487 else if (address
->family
== AF_INET6
)
488 r
= sd_netlink_message_append_in6_addr(req
, IFA_ADDRESS
, &address
->in_addr_peer
.in6
);
490 return log_error_errno(r
, "Could not append IFA_ADDRESS attribute: %m");
492 if (address
->family
== AF_INET
) {
493 r
= sd_netlink_message_append_in_addr(req
, IFA_BROADCAST
, &address
->broadcast
);
495 return log_error_errno(r
, "Could not append IFA_BROADCAST attribute: %m");
499 if (address
->label
) {
500 r
= sd_netlink_message_append_string(req
, IFA_LABEL
, address
->label
);
502 return log_error_errno(r
, "Could not append IFA_LABEL attribute: %m");
505 r
= sd_netlink_message_append_cache_info(req
, IFA_CACHEINFO
,
508 return log_error_errno(r
, "Could not append IFA_CACHEINFO attribute: %m");
510 r
= address_establish(address
, link
);
514 r
= sd_netlink_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
516 address_release(address
);
517 return log_error_errno(r
, "Could not send rtnetlink message: %m");
525 int config_parse_broadcast(
527 const char *filename
,
530 unsigned section_line
,
537 Network
*network
= userdata
;
538 _cleanup_address_free_ Address
*n
= NULL
;
547 r
= address_new_static(network
, section_line
, &n
);
551 if (n
->family
== AF_INET6
) {
552 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue
);
556 r
= in_addr_from_string(AF_INET
, rvalue
, (union in_addr_union
*) &n
->broadcast
);
558 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Broadcast is invalid, ignoring assignment: %s", rvalue
);
568 int config_parse_address(const char *unit
,
569 const char *filename
,
572 unsigned section_line
,
579 Network
*network
= userdata
;
580 _cleanup_address_free_ Address
*n
= NULL
;
581 const char *address
, *e
;
582 union in_addr_union buffer
;
591 if (streq(section
, "Network")) {
592 /* we are not in an Address section, so treat
593 * this as the special '0' section */
597 r
= address_new_static(network
, section_line
, &n
);
601 /* Address=address/prefixlen */
604 e
= strchr(rvalue
, '/');
608 r
= safe_atou(e
+ 1, &i
);
610 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Prefix length is invalid, ignoring assignment: %s", e
+ 1);
614 n
->prefixlen
= (unsigned char) i
;
616 address
= strndupa(rvalue
, e
- rvalue
);
620 r
= in_addr_from_string_auto(address
, &f
, &buffer
);
622 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Address is invalid, ignoring assignment: %s", address
);
626 if (!e
&& f
== AF_INET
) {
627 r
= in_addr_default_prefixlen(&buffer
.in
, &n
->prefixlen
);
629 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
);
634 if (n
->family
!= AF_UNSPEC
&& f
!= n
->family
) {
635 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Address is incompatible, ignoring assignment: %s", address
);
641 if (streq(lvalue
, "Address"))
644 n
->in_addr_peer
= buffer
;
646 if (n
->family
== AF_INET
&& n
->broadcast
.s_addr
== 0)
647 n
->broadcast
.s_addr
= n
->in_addr
.in
.s_addr
| htonl(0xfffffffflu
>> n
->prefixlen
);
654 int config_parse_label(const char *unit
,
655 const char *filename
,
658 unsigned section_line
,
664 Network
*network
= userdata
;
665 _cleanup_address_free_ Address
*n
= NULL
;
675 r
= address_new_static(network
, section_line
, &n
);
679 label
= strdup(rvalue
);
683 if (!ascii_is_valid(label
) || strlen(label
) >= IFNAMSIZ
) {
684 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface label is not ASCII clean or is too long, ignoring assignment: %s", rvalue
);
702 bool address_is_ready(const Address
*a
) {
705 return !(a
->flags
& (IFA_F_TENTATIVE
| IFA_F_DEPRECATED
));