arp: Do not fill cache from random packets.

On paper this looks great, and in a sane network it should work.
However the world out there is full of horribly broken, screwed up
networks, which *of course* ruin this.

I've seen a customer's network where the router is IP 192.168.1.1,
MAC addr xx:03. However, every 1 minute the router broadcasts some
"mikrotik discovery" UDP garbage with source IP 192.168.1.1, source MAC
addr xx:02 (one less!). This accidentally poisons smoltcp's ARP cache,
which then sends all traffic for the default gateway to xx:02, which
unsurprisingly blackholes it.

And, of course, the broadcast is every 1min and the ARP cache lifetime
is 1min. This means the cache is almsot all the time poisoned, and the
smoltcp device barely works. Fantastic.

Screw you mikrotik.
master
Dario Nieuwenhuis 2021-10-01 21:50:45 +02:00
parent 6fee12dcee
commit f98a89ba61
1 changed files with 0 additions and 31 deletions

View File

@ -952,43 +952,12 @@ impl<'a> InterfaceInner<'a> {
#[cfg(feature = "proto-ipv4")]
EthernetProtocol::Ipv4 => {
let ipv4_packet = Ipv4Packet::new_checked(eth_frame.payload())?;
if eth_frame.src_addr().is_unicast() && ipv4_packet.src_addr().is_unicast() {
// Fill the neighbor cache from IP header of unicast frames.
let ip_addr = IpAddress::Ipv4(ipv4_packet.src_addr());
if self.in_same_network(&ip_addr) {
self.neighbor_cache.as_mut().unwrap().fill(
ip_addr,
eth_frame.src_addr(),
cx.now,
);
}
}
self.process_ipv4(cx, sockets, &ipv4_packet)
.map(|o| o.map(EthernetPacket::Ip))
}
#[cfg(feature = "proto-ipv6")]
EthernetProtocol::Ipv6 => {
let ipv6_packet = Ipv6Packet::new_checked(eth_frame.payload())?;
if eth_frame.src_addr().is_unicast() && ipv6_packet.src_addr().is_unicast() {
// Fill the neighbor cache from IP header of unicast frames.
let ip_addr = IpAddress::Ipv6(ipv6_packet.src_addr());
if self.in_same_network(&ip_addr)
&& self
.neighbor_cache
.as_mut()
.unwrap()
.lookup(&ip_addr, cx.now)
.found()
{
self.neighbor_cache.as_mut().unwrap().fill(
ip_addr,
eth_frame.src_addr(),
cx.now,
);
}
}
self.process_ipv6(cx, sockets, &ipv6_packet)
.map(|o| o.map(EthernetPacket::Ip))
}