nd6: fix Duplicate Address Detection

Previously, Duplicate Address Detection (DAD) would work only for the
link-local address. For DAD-spawned Neighbor Solicitation requests for
any other address, the request would use the link-local address as the
source, meaning the other side would send a targeted reply (RFC 4861
Sec. 7.2.4). However, the nd6 implementation currently does not
consider targeted replies for DAD--even though technically an RFC 4862
Sec. 5.4.4 violation--supposedly because no real-world scenario could
trigger that case. The combination of these factors resulted in DAD
being entirely ineffective for non-link-local addresses.

This patch forces all DAD-spawned Neighbor Solicitation packets to use
the unspecified ('any') address as source, as per RFC 4862 Sec. 5.4.2.
As a result, other nodes would reply with multicast replies, for which
there is appropriate DAD checking code.

The patch also makes a slight rearrangement of statements such that
MLD join messages are sent before the NS packets, rather than after.
This commit is contained in:
David van Moolenbroek 2016-12-29 22:13:12 +00:00 committed by Dirk Ziegelmeier
parent 2ff04a931a
commit d99334573b

View File

@ -105,6 +105,7 @@ static err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf *q);
#define ND6_SEND_FLAG_MULTICAST_DEST 0x01
#define ND6_SEND_FLAG_ALLNODES_DEST 0x02
#define ND6_SEND_FLAG_ANY_SRC 0x04
static void nd6_send_ns(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags);
static void nd6_send_na(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags);
static void nd6_send_neighbor_cache_probe(struct nd6_neighbor_cache_entry *entry, u8_t flags);
@ -1005,10 +1006,13 @@ nd6_tmr(void)
#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */
netif_ip6_addr_set_state(netif, i, addr_state);
} else if (netif_is_up(netif) && netif_is_link_up(netif)) {
/* Send a NS for this address. */
nd6_send_ns(netif, netif_ip6_addr(netif, i), ND6_SEND_FLAG_MULTICAST_DEST);
/* tentative: set next state by increasing by one */
netif_ip6_addr_set_state(netif, i, addr_state + 1);
/* Send a NS for this address. Use the unspecified address as source
* address in all cases (RFC 4862 Sec. 5.4.2), not in the least
* because as it is, we only consider multicast replies for DAD. */
nd6_send_ns(netif, netif_ip6_addr(netif, i),
ND6_SEND_FLAG_MULTICAST_DEST | ND6_SEND_FLAG_ANY_SRC);
}
}
}
@ -1056,7 +1060,8 @@ nd6_send_ns(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags)
const ip6_addr_t *src_addr;
u16_t lladdr_opt_len;
if (ip6_addr_isvalid(netif_ip6_addr_state(netif,0))) {
if (!(flags & ND6_SEND_FLAG_ANY_SRC) &&
ip6_addr_isvalid(netif_ip6_addr_state(netif,0))) {
/* Use link-local address as source address. */
src_addr = netif_ip6_addr(netif, 0);
/* calculate option length (in 8-byte-blocks) */