Merge pull request #31314 from yuwata/network-ndisc-check-conflicting-address
network/ndisc: check conflicting address
This commit is contained in:
@@ -516,11 +516,9 @@ static int address_compare_func(const Address *a1, const Address *a2) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool address_can_update(const Address *la, const Address *na) {
|
||||
assert(la);
|
||||
assert(la->link);
|
||||
assert(na);
|
||||
assert(na->network);
|
||||
bool address_can_update(const Address *existing, const Address *requesting) {
|
||||
assert(existing);
|
||||
assert(requesting);
|
||||
|
||||
/*
|
||||
* property | IPv4 | IPv6
|
||||
@@ -545,32 +543,32 @@ static bool address_can_update(const Address *la, const Address *na) {
|
||||
* IPv6 : See inet6_addr_modify() in net/ipv6/addrconf.c.
|
||||
*/
|
||||
|
||||
if (la->family != na->family)
|
||||
if (existing->family != requesting->family)
|
||||
return false;
|
||||
|
||||
if (la->prefixlen != na->prefixlen)
|
||||
if (existing->prefixlen != requesting->prefixlen)
|
||||
return false;
|
||||
|
||||
/* When a null address is requested, the address to be assigned/updated will be determined later. */
|
||||
if (!address_is_static_null(na) &&
|
||||
in_addr_equal(la->family, &la->in_addr, &na->in_addr) <= 0)
|
||||
if (!address_is_static_null(requesting) &&
|
||||
in_addr_equal(existing->family, &existing->in_addr, &requesting->in_addr) <= 0)
|
||||
return false;
|
||||
|
||||
switch (la->family) {
|
||||
switch (existing->family) {
|
||||
case AF_INET: {
|
||||
struct in_addr bcast;
|
||||
|
||||
if (la->scope != na->scope)
|
||||
if (existing->scope != requesting->scope)
|
||||
return false;
|
||||
if (((la->flags ^ na->flags) & KNOWN_FLAGS & ~IPV6ONLY_FLAGS & ~UNMANAGED_FLAGS) != 0)
|
||||
if (((existing->flags ^ requesting->flags) & KNOWN_FLAGS & ~IPV6ONLY_FLAGS & ~UNMANAGED_FLAGS) != 0)
|
||||
return false;
|
||||
if (!streq_ptr(la->label, na->label))
|
||||
if (!streq_ptr(existing->label, requesting->label))
|
||||
return false;
|
||||
if (!in4_addr_equal(&la->in_addr_peer.in, &na->in_addr_peer.in))
|
||||
if (!in4_addr_equal(&existing->in_addr_peer.in, &requesting->in_addr_peer.in))
|
||||
return false;
|
||||
if (address_get_broadcast(na, la->link, &bcast) >= 0) {
|
||||
if (existing->link && address_get_broadcast(requesting, existing->link, &bcast) >= 0) {
|
||||
/* If the broadcast address can be determined now, check if they match. */
|
||||
if (!in4_addr_equal(&la->broadcast, &bcast))
|
||||
if (!in4_addr_equal(&existing->broadcast, &bcast))
|
||||
return false;
|
||||
} else {
|
||||
/* When a null address is requested, then the broadcast address will be
|
||||
@@ -578,7 +576,7 @@ static bool address_can_update(const Address *la, const Address *na) {
|
||||
* 192.168.0.10/24 -> 192.168.0.255
|
||||
* So, here let's only check if the broadcast is the last address in the range, e.g.
|
||||
* 0.0.0.0/24 -> 0.0.0.255 */
|
||||
if (!FLAGS_SET(la->broadcast.s_addr, htobe32(UINT32_C(0xffffffff) >> la->prefixlen)))
|
||||
if (!FLAGS_SET(existing->broadcast.s_addr, htobe32(UINT32_C(0xffffffff) >> existing->prefixlen)))
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -85,6 +85,8 @@ void link_get_address_states(
|
||||
|
||||
extern const struct hash_ops address_hash_ops;
|
||||
|
||||
bool address_can_update(const Address *existing, const Address *requesting);
|
||||
|
||||
Address* address_ref(Address *address);
|
||||
Address* address_unref(Address *address);
|
||||
|
||||
|
||||
@@ -158,8 +158,7 @@ static int verify_dhcp6_address(Link *link, const Address *address) {
|
||||
} else
|
||||
log_level = LOG_DEBUG;
|
||||
|
||||
if (address->prefixlen == existing->prefixlen)
|
||||
/* Currently, only conflict in prefix length is reported. */
|
||||
if (address_can_update(existing, address))
|
||||
goto simple_log;
|
||||
|
||||
if (existing->source == NETWORK_CONFIG_SOURCE_NDISC)
|
||||
|
||||
@@ -249,8 +249,7 @@ static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Reques
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ndisc_request_address(Address *in, Link *link, sd_ndisc_router *rt) {
|
||||
_cleanup_(address_unrefp) Address *address = in;
|
||||
static int ndisc_request_address(Address *address, Link *link, sd_ndisc_router *rt) {
|
||||
struct in6_addr router;
|
||||
bool is_new;
|
||||
int r;
|
||||
@@ -270,7 +269,26 @@ static int ndisc_request_address(Address *in, Link *link, sd_ndisc_router *rt) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
is_new = address_get(link, address, NULL) < 0;
|
||||
Address *existing;
|
||||
if (address_get_harder(link, address, &existing) < 0)
|
||||
is_new = true;
|
||||
else if (address_can_update(existing, address))
|
||||
is_new = false;
|
||||
else if (existing->source == NETWORK_CONFIG_SOURCE_DHCP6) {
|
||||
/* SLAAC address is preferred over DHCPv6 address. */
|
||||
log_link_debug(link, "Conflicting DHCPv6 address %s exists, removing.",
|
||||
IN_ADDR_PREFIX_TO_STRING(existing->family, &existing->in_addr, existing->prefixlen));
|
||||
r = address_remove(existing, link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
is_new = true;
|
||||
} else {
|
||||
/* Conflicting static address is configured?? */
|
||||
log_link_debug(link, "Conflicting address %s exists, ignoring request.",
|
||||
IN_ADDR_PREFIX_TO_STRING(existing->family, &existing->in_addr, existing->prefixlen));
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = link_request_address(link, address, &link->ndisc_messages,
|
||||
ndisc_address_handler, NULL);
|
||||
@@ -485,7 +503,7 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
|
||||
address->lifetime_valid_usec = lifetime_valid_usec;
|
||||
address->lifetime_preferred_usec = lifetime_preferred_usec;
|
||||
|
||||
r = ndisc_request_address(TAKE_PTR(address), link, rt);
|
||||
r = ndisc_request_address(address, link, rt);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Could not request SLAAC address: %m");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user