Fix #614: Properly reply to local packets for local subnet

Previously packets for the local subnet would trigger a route lookup,
which leads to a no-route entry being generated. Instead, reply to such
packets with an ICMP host unreachable - address uncreachable. This can
be done unilaterally since IF the address would exist on the host, the
packet would not be pushed to the TUN interface by the kernel and thus,
by extension, if such a packet is handled by mycelium, it means there is
no address or local subnet configuration.

Signed-off-by: Lee Smet <lee.smet@hotmail.com>
This commit is contained in:
Lee Smet
2025-05-05 13:40:40 +02:00
parent 1eec5651bf
commit 2687ecabc2
2 changed files with 29 additions and 0 deletions

View File

@@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed an unsoundness issue in the routing table clone implementation.
- Clear dead peer buffer once peers have been removed from the routing table.
- Properly reply with an address unreachable ICMP when pinging an IP in the local
subnet which does not exist.
## [0.6.0] - 2025-04-25

View File

@@ -102,6 +102,8 @@ where
T: Sink<PacketBuffer> + Clone + Send + Unpin + 'static,
T::Error: std::fmt::Display,
{
let node_subnet = self.router.node_tun_subnet();
while let Some(packet) = l3_packet_stream.next().await {
let mut packet = match packet {
Err(e) => {
@@ -146,6 +148,31 @@ where
.expect("Static range bounds on slice are correct length"),
);
// If this is a packet for our own Subnet, it means there is no local configuration for
// the destination ip or /64 subnet, and the IP is unreachable
if node_subnet.contains_ip(dst_ip.into()) {
trace!(
"Replying to local packet for unexisting address: {}",
dst_ip
);
let mut icmp_packet = PacketBuffer::new();
let host = self.router.node_public_key().address().octets();
let icmp = PacketBuilder::ipv6(host, src_ip.octets(), 64).icmpv6(
Icmpv6Type::DestinationUnreachable(DestUnreachableCode::Address),
);
icmp_packet.set_size(icmp.size(packet.len().min(1280 - 48)));
let mut writer = &mut icmp_packet.buffer_mut()[..];
if let Err(e) = icmp.write(&mut writer, &packet[..packet.len().min(1280 - 48)]) {
error!("Failed to construct ICMP packet: {e}");
continue;
}
if let Err(e) = l3_packet_sink.send(icmp_packet).await {
error!("Failed to send ICMP packet to host: {e}");
}
continue;
}
trace!("Received packet from TUN with dest addr: {:?}", dst_ip);
// Check if the source address is part of 400::/7
let first_src_byte = src_ip.segments()[0] >> 8;