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"
27 #include "networkd-address.h"
29 #include "parse-util.h"
31 #include "string-util.h"
35 int address_new(Address
**ret
) {
36 _cleanup_address_free_ Address
*address
= NULL
;
38 address
= new0(Address
, 1);
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
;
53 int address_new_static(Network
*network
, unsigned section
, Address
**ret
) {
54 _cleanup_address_free_ Address
*address
= NULL
;
58 address
= hashmap_get(network
->addresses_by_section
, UINT_TO_PTR(section
));
67 r
= address_new(&address
);
71 address
->network
= network
;
73 LIST_APPEND(addresses
, network
->static_addresses
, address
);
76 address
->section
= section
;
77 hashmap_put(network
->addresses_by_section
,
78 UINT_TO_PTR(address
->section
), address
);
87 void address_free(Address
*address
) {
91 if (address
->network
) {
92 LIST_REMOVE(addresses
, address
->network
->static_addresses
, address
);
95 hashmap_remove(address
->network
->addresses_by_section
,
96 UINT_TO_PTR(address
->section
));
100 set_remove(address
->link
->addresses
, address
);
101 set_remove(address
->link
->addresses_foreign
, address
);
107 static void address_hash_func(const void *b
, struct siphash
*state
) {
108 const Address
*a
= b
;
112 siphash24_compress(&a
->family
, sizeof(a
->family
), state
);
116 siphash24_compress(&a
->prefixlen
, sizeof(a
->prefixlen
), state
);
119 if (a
->prefixlen
!= 0) {
122 if (a
->in_addr_peer
.in
.s_addr
!= 0)
123 prefix
= be32toh(a
->in_addr_peer
.in
.s_addr
) >> (32 - a
->prefixlen
);
125 prefix
= be32toh(a
->in_addr
.in
.s_addr
) >> (32 - a
->prefixlen
);
127 siphash24_compress(&prefix
, sizeof(prefix
), state
);
133 siphash24_compress(&a
->in_addr
, FAMILY_ADDRESS_SIZE(a
->family
), state
);
137 /* treat any other address family as AF_UNSPEC */
142 static int address_compare_func(const void *c1
, const void *c2
) {
143 const Address
*a1
= c1
, *a2
= c2
;
145 if (a1
->family
< a2
->family
)
147 if (a1
->family
> a2
->family
)
150 switch (a1
->family
) {
151 /* use the same notion of equality as the kernel does */
153 if (a1
->prefixlen
< a2
->prefixlen
)
155 if (a1
->prefixlen
> a2
->prefixlen
)
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. */
164 if (a1
->in_addr_peer
.in
.s_addr
!= 0)
165 b1
= be32toh(a1
->in_addr_peer
.in
.s_addr
) >> (32 - a1
->prefixlen
);
167 b1
= be32toh(a1
->in_addr
.in
.s_addr
) >> (32 - a1
->prefixlen
);
169 if (a2
->in_addr_peer
.in
.s_addr
!= 0)
170 b2
= be32toh(a2
->in_addr_peer
.in
.s_addr
) >> (32 - a1
->prefixlen
);
172 b2
= be32toh(a2
->in_addr
.in
.s_addr
) >> (32 - a1
->prefixlen
);
182 return memcmp(&a1
->in_addr
, &a2
->in_addr
, FAMILY_ADDRESS_SIZE(a1
->family
));
184 /* treat any other address family as AF_UNSPEC */
189 static const struct hash_ops address_hash_ops
= {
190 .hash
= address_hash_func
,
191 .compare
= address_compare_func
194 bool address_equal(Address
*a1
, Address
*a2
) {
201 return address_compare_func(a1
, a2
) == 0;
204 static int address_establish(Address
*address
, Link
*link
) {
211 masq
= link
->network
&&
212 link
->network
->ip_masquerade
&&
213 address
->family
== AF_INET
&&
214 address
->scope
< RT_SCOPE_LINK
;
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
);
221 r
= fw_add_masquerade(masq
, AF_INET
, 0, &masked
, address
->prefixlen
, NULL
, NULL
, 0);
223 log_link_warning_errno(link
, r
, "Could not enable IP masquerading: %m");
225 address
->ip_masquerade_done
= masq
;
231 static int address_add_internal(Link
*link
, Set
**addresses
,
233 const union in_addr_union
*in_addr
,
234 unsigned char prefixlen
,
236 _cleanup_address_free_ Address
*address
= NULL
;
243 r
= address_new(&address
);
247 address
->family
= family
;
248 address
->in_addr
= *in_addr
;
249 address
->prefixlen
= prefixlen
;
251 r
= set_ensure_allocated(addresses
, &address_hash_ops
);
255 r
= set_put(*addresses
, address
);
259 address
->link
= link
;
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
);
273 static int address_add(Link
*link
, int family
, const union in_addr_union
*in_addr
, unsigned char prefixlen
, Address
**ret
) {
276 r
= address_add_internal(link
, &link
->addresses
, family
, in_addr
, prefixlen
, ret
);
280 link_update_operstate(link
);
286 static int address_release(Address
*address
) {
290 assert(address
->link
);
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
);
297 r
= fw_add_masquerade(false, AF_INET
, 0, &masked
, address
->prefixlen
, NULL
, NULL
, 0);
299 log_link_warning_errno(address
->link
, r
, "Failed to disable IP masquerading: %m");
301 address
->ip_masquerade_done
= false;
307 int address_update(Address
*address
, unsigned char flags
, unsigned char scope
, struct ifa_cacheinfo
*cinfo
) {
313 ready
= address_is_ready(address
);
315 address
->added
= true;
316 address
->flags
= flags
;
317 address
->scope
= scope
;
318 address
->cinfo
= *cinfo
;
320 if (!ready
&& address_is_ready(address
) && address
->link
)
321 link_check_ready(address
->link
);
326 int address_drop(Address
*address
) {
332 ready
= address_is_ready(address
);
333 link
= address
->link
;
335 address_release(address
);
336 address_free(address
);
338 link_update_operstate(link
);
341 link_check_ready(link
);
346 int address_get(Link
*link
, int family
, const union in_addr_union
*in_addr
, unsigned char prefixlen
, Address
**ret
) {
347 Address address
= {}, *existing
;
353 address
.family
= family
;
354 address
.in_addr
= *in_addr
;
355 address
.prefixlen
= prefixlen
;
357 existing
= set_get(link
->addresses
, &address
);
359 existing
= set_get(link
->addresses_foreign
, &address
);
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
;
375 assert(address
->family
== AF_INET
|| address
->family
== AF_INET6
);
377 assert(link
->ifindex
> 0);
378 assert(link
->manager
);
379 assert(link
->manager
->rtnl
);
381 r
= sd_rtnl_message_new_addr(link
->manager
->rtnl
, &req
, RTM_DELADDR
,
382 link
->ifindex
, address
->family
);
384 return log_error_errno(r
, "Could not allocate RTM_DELADDR message: %m");
386 r
= sd_rtnl_message_addr_set_prefixlen(req
, address
->prefixlen
);
388 return log_error_errno(r
, "Could not set prefixlen: %m");
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
);
395 return log_error_errno(r
, "Could not append IFA_LOCAL attribute: %m");
397 r
= sd_netlink_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
399 return log_error_errno(r
, "Could not send rtnetlink message: %m");
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
;
416 /* Something useful was configured? just use it */
417 if (in_addr_is_null(original
->family
, &original
->in_addr
) <= 0)
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
);
424 return log_link_error_errno(link
, r
, "Failed to acquire address from pool: %m");
426 log_link_error(link
, "Couldn't find free address for interface, all taken.");
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);
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;
439 r
= address_new(&na
);
443 na
->family
= original
->family
;
444 na
->prefixlen
= original
->prefixlen
;
445 na
->scope
= original
->scope
;
446 na
->cinfo
= original
->cinfo
;
448 if (original
->label
) {
449 na
->label
= strdup(original
->label
);
454 na
->broadcast
= broadcast
;
455 na
->in_addr
= in_addr
;
457 LIST_PREPEND(addresses
, link
->pool_addresses
, na
);
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
;
470 assert(address
->family
== AF_INET
|| address
->family
== AF_INET6
);
472 assert(link
->ifindex
> 0);
473 assert(link
->manager
);
474 assert(link
->manager
->rtnl
);
476 r
= address_acquire(link
, address
, &address
);
481 r
= sd_rtnl_message_new_addr_update(link
->manager
->rtnl
, &req
,
482 link
->ifindex
, address
->family
);
484 r
= sd_rtnl_message_new_addr(link
->manager
->rtnl
, &req
, RTM_NEWADDR
,
485 link
->ifindex
, address
->family
);
487 return log_error_errno(r
, "Could not allocate RTM_NEWADDR message: %m");
489 r
= sd_rtnl_message_addr_set_prefixlen(req
, address
->prefixlen
);
491 return log_error_errno(r
, "Could not set prefixlen: %m");
493 address
->flags
|= IFA_F_PERMANENT
;
495 r
= sd_rtnl_message_addr_set_flags(req
, (address
->flags
& 0xff));
497 return log_error_errno(r
, "Could not set flags: %m");
499 if (address
->flags
& ~0xff) {
500 r
= sd_netlink_message_append_u32(req
, IFA_FLAGS
, address
->flags
);
502 return log_error_errno(r
, "Could not set extended flags: %m");
505 r
= sd_rtnl_message_addr_set_scope(req
, address
->scope
);
507 return log_error_errno(r
, "Could not set scope: %m");
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
);
514 return log_error_errno(r
, "Could not append IFA_LOCAL attribute: %m");
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
);
522 return log_error_errno(r
, "Could not append IFA_ADDRESS attribute: %m");
524 if (address
->family
== AF_INET
) {
525 r
= sd_netlink_message_append_in_addr(req
, IFA_BROADCAST
, &address
->broadcast
);
527 return log_error_errno(r
, "Could not append IFA_BROADCAST attribute: %m");
531 if (address
->label
) {
532 r
= sd_netlink_message_append_string(req
, IFA_LABEL
, address
->label
);
534 return log_error_errno(r
, "Could not append IFA_LABEL attribute: %m");
537 r
= sd_netlink_message_append_cache_info(req
, IFA_CACHEINFO
,
540 return log_error_errno(r
, "Could not append IFA_CACHEINFO attribute: %m");
542 r
= address_establish(address
, link
);
546 r
= sd_netlink_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
548 address_release(address
);
549 return log_error_errno(r
, "Could not send rtnetlink message: %m");
554 r
= address_add(link
, address
->family
, &address
->in_addr
, address
->prefixlen
, NULL
);
556 address_release(address
);
557 return log_error_errno(r
, "Could not add address: %m");
563 int config_parse_broadcast(
565 const char *filename
,
568 unsigned section_line
,
575 Network
*network
= userdata
;
576 _cleanup_address_free_ Address
*n
= NULL
;
585 r
= address_new_static(network
, section_line
, &n
);
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
);
594 r
= in_addr_from_string(AF_INET
, rvalue
, (union in_addr_union
*) &n
->broadcast
);
596 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Broadcast is invalid, ignoring assignment: %s", rvalue
);
606 int config_parse_address(const char *unit
,
607 const char *filename
,
610 unsigned section_line
,
617 Network
*network
= userdata
;
618 _cleanup_address_free_ Address
*n
= NULL
;
619 const char *address
, *e
;
620 union in_addr_union buffer
;
629 if (streq(section
, "Network")) {
630 /* we are not in an Address section, so treat
631 * this as the special '0' section */
635 r
= address_new_static(network
, section_line
, &n
);
639 /* Address=address/prefixlen */
642 e
= strchr(rvalue
, '/');
646 r
= safe_atou(e
+ 1, &i
);
648 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Prefix length is invalid, ignoring assignment: %s", e
+ 1);
652 n
->prefixlen
= (unsigned char) i
;
654 address
= strndupa(rvalue
, e
- rvalue
);
658 r
= in_addr_from_string_auto(address
, &f
, &buffer
);
660 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Address is invalid, ignoring assignment: %s", address
);
664 if (!e
&& f
== AF_INET
) {
665 r
= in_addr_default_prefixlen(&buffer
.in
, &n
->prefixlen
);
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
);
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
);
679 if (streq(lvalue
, "Address"))
682 n
->in_addr_peer
= buffer
;
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
);
692 int config_parse_label(const char *unit
,
693 const char *filename
,
696 unsigned section_line
,
702 Network
*network
= userdata
;
703 _cleanup_address_free_ Address
*n
= NULL
;
713 r
= address_new_static(network
, section_line
, &n
);
717 label
= strdup(rvalue
);
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
);
740 bool address_is_ready(const Address
*a
) {
743 return a
->added
&& !(a
->flags
& (IFA_F_TENTATIVE
| IFA_F_DEPRECATED
));