network: introduce link_drop_foreign_addresses()

This commit is contained in:
Yu Watanabe 2020-10-02 11:26:12 +09:00
parent 682c65b04c
commit f8f2f880d4
4 changed files with 85 additions and 68 deletions

View File

@ -542,6 +542,85 @@ int address_remove(
return 0;
}
static bool link_is_static_address_configured(Link *link, Address *address) {
Address *net_address;
assert(link);
assert(address);
if (!link->network)
return false;
LIST_FOREACH(addresses, net_address, link->network->static_addresses)
if (address_equal(net_address, address))
return true;
else if (address->family == AF_INET6 && net_address->family == AF_INET6 &&
in_addr_equal(AF_INET6, &address->in_addr, &net_address->in_addr_peer) > 0)
return true;
return false;
}
static bool link_address_is_dynamic(Link *link, Address *address) {
Route *route;
assert(link);
assert(address);
if (address->cinfo.ifa_prefered != CACHE_INFO_INFINITY_LIFE_TIME)
return true;
/* Even when the address is leased from a DHCP server, networkd assign the address
* without lifetime when KeepConfiguration=dhcp. So, let's check that we have
* corresponding routes with RTPROT_DHCP. */
SET_FOREACH(route, link->routes_foreign) {
if (route->protocol != RTPROT_DHCP)
continue;
if (address->family != route->family)
continue;
if (in_addr_equal(address->family, &address->in_addr, &route->prefsrc))
return true;
}
return false;
}
int link_drop_foreign_addresses(Link *link) {
Address *address;
int k, r = 0;
assert(link);
SET_FOREACH(address, link->addresses_foreign) {
/* we consider IPv6LL addresses to be managed by the kernel */
if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1 && link_ipv6ll_enabled(link))
continue;
if (link_address_is_dynamic(link, address)) {
if (link->network && FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
continue;
} else if (link->network && FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
continue;
if (link_is_static_address_configured(link, address)) {
k = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
if (k < 0) {
log_link_error_errno(link, k, "Failed to add address: %m");
if (r >= 0)
r = k;
}
} else {
k = address_remove(address, link, NULL);
if (k < 0 && r >= 0)
r = k;
}
}
return r;
}
static int address_acquire(Link *link, Address *original, Address **ret) {
union in_addr_union in_addr = IN_ADDR_NULL;
struct in_addr broadcast = {};

View File

@ -76,6 +76,7 @@ int generate_ipv6_eui_64_address(Link *link, struct in6_addr *ret);
DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free);
int link_set_addresses(Link *link);
int link_drop_foreign_addresses(Link *link);
void address_hash_func(const Address *a, struct siphash *state);
int address_compare_func(const Address *a1, const Address *a2);

View File

@ -163,7 +163,7 @@ bool link_ipv4ll_enabled(Link *link, AddressFamily mask) {
return link->network->link_local & mask;
}
static bool link_ipv6ll_enabled(Link *link) {
bool link_ipv6ll_enabled(Link *link) {
assert(link);
if (!socket_ipv6_is_supported())
@ -2320,51 +2320,6 @@ static int link_set_ipv4_accept_local(Link *link) {
return 0;
}
static bool link_is_static_address_configured(Link *link, Address *address) {
Address *net_address;
assert(link);
assert(address);
if (!link->network)
return false;
LIST_FOREACH(addresses, net_address, link->network->static_addresses)
if (address_equal(net_address, address))
return true;
else if (address->family == AF_INET6 && net_address->family == AF_INET6 &&
in_addr_equal(AF_INET6, &address->in_addr, &net_address->in_addr_peer) > 0)
return true;
return false;
}
static bool link_address_is_dynamic(Link *link, Address *address) {
Route *route;
assert(link);
assert(address);
if (address->cinfo.ifa_prefered != CACHE_INFO_INFINITY_LIFE_TIME)
return true;
/* Even when the address is leased from a DHCP server, networkd assign the address
* without lifetime when KeepConfiguration=dhcp. So, let's check that we have
* corresponding routes with RTPROT_DHCP. */
SET_FOREACH(route, link->routes_foreign) {
if (route->protocol != RTPROT_DHCP)
continue;
if (address->family != route->family)
continue;
if (in_addr_equal(address->family, &address->in_addr, &route->prefsrc))
return true;
}
return false;
}
static int link_enumerate_ipv6_tentative_addresses(Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
sd_netlink_message *addr;
@ -2408,7 +2363,6 @@ static int link_enumerate_ipv6_tentative_addresses(Link *link) {
}
static int link_drop_foreign_config(Link *link) {
Address *address;
int r;
/* The kernel doesn't notify us about tentative addresses;
@ -2419,27 +2373,9 @@ static int link_drop_foreign_config(Link *link) {
return r;
}
SET_FOREACH(address, link->addresses_foreign) {
/* we consider IPv6LL addresses to be managed by the kernel */
if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1 && link_ipv6ll_enabled(link))
continue;
if (link_address_is_dynamic(link, address)) {
if (link->network && FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
continue;
} else if (link->network && FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
continue;
if (link_is_static_address_configured(link, address)) {
r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
if (r < 0)
return log_link_error_errno(link, r, "Failed to add address: %m");
} else {
r = address_remove(address, link, NULL);
if (r < 0)
return r;
}
}
r = link_drop_foreign_addresses(link);
if (r < 0)
return r;
r = link_drop_foreign_neighbors(link);
if (r < 0)

View File

@ -226,6 +226,7 @@ int link_save_and_clean(Link *link);
int link_carrier_reset(Link *link);
bool link_has_carrier(Link *link);
bool link_ipv6ll_enabled(Link *link);
int link_ipv6ll_gained(Link *link, const struct in6_addr *address);
int link_set_mtu(Link *link, uint32_t mtu);