diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b12b53..1f84eb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Return actuall amount of bytes sent to peers instead of the amount of bytes received from them. +- Improve handling of completely local packets on MacOS. This will allow the kernel + to reply to ping packets send from the local system to the TUN interface, among + other things. ## [0.6.2] - 2025-09-19 diff --git a/mycelium/src/tun/darwin.rs b/mycelium/src/tun/darwin.rs index 11b84f2..7414ff7 100644 --- a/mycelium/src/tun/darwin.rs +++ b/mycelium/src/tun/darwin.rs @@ -3,7 +3,7 @@ use std::{ ffi::CString, io::{self, IoSlice}, - net::IpAddr, + net::{IpAddr, Ipv6Addr}, os::fd::AsRawFd, str::FromStr, }; @@ -126,6 +126,19 @@ pub async fn new( }); + // On Mac, packets from the tun ip to the tun ip (e.g. ping tun ip) need to be + // passed explicitly to the TUN interface again for them to be picked up by the + // kernel, since they are not routed on the loopback interface. + if let Ok(ref buf) = rr { + if buf.len() >= 40 && tun_config.node_subnet.contains_ip(IpAddr::V6(Ipv6Addr::from(<[u8;16] as TryFrom<&[u8]>>::try_from(&buf[24..40]).expect("Valid 16 byte buffer; qed")))) { + if let Err(err) = tun.write_vectored(&[IoSlice::new(&HEADER), IoSlice::new(&buf)]).await { + error!(%err, "Failed to send data to tun interface"); + } + } + } + + + if tun_stream.send(rr).is_err() { error!("Could not forward data to tun stream, receiver is gone"); break;