fix(client): drop misdirected relayed unicast frames
The relay should only send a remote client unicast traffic for that client's virtual MAC, while broadcast and multicast traffic fan out to every relevant peer. The Windows client is still the last boundary before TAP, so it should not write a relayed unicast frame for some other MAC into the adapter if the relay or a future code path misroutes it. Add a receive-side destination guard in client-core. Relayed frames now reach TAP only when their destination is the client's virtual MAC or a broadcast/multicast address; other unicast frames are counted and skipped. Extend the client relay-session test with a wrong-client unicast before the valid frame, and document the client-side skip in the README. Test Plan: - cargo test -p lanparty-client-core - cargo test --workspace - cargo clippy --workspace --all-targets -- -D warnings - cargo fmt --check - git diff --check Refs: PLAN.md LAN frames to matching remote clients
This commit is contained in:
@@ -449,6 +449,10 @@ impl ClientRelayIo {
|
||||
self.stats.record_dropped_frame();
|
||||
continue;
|
||||
}
|
||||
if !is_accepted_relay_destination(ethernet_frame, self.virtual_mac) {
|
||||
self.stats.record_dropped_frame();
|
||||
continue;
|
||||
}
|
||||
|
||||
return Ok(ReceivedEthernetFrame {
|
||||
source_peer_id: header.peer_id(),
|
||||
@@ -468,6 +472,11 @@ impl ClientRelayIo {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_accepted_relay_destination(frame: EthernetFrame<'_>, virtual_mac: MacAddr) -> bool {
|
||||
let destination = frame.destination();
|
||||
destination == virtual_mac || destination.is_multicast()
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct ClientTunnelStats {
|
||||
ethernet_frames_tx: AtomicU64,
|
||||
@@ -823,9 +832,26 @@ mod tests {
|
||||
.send_datagram(Bytes::from(filtered_response))
|
||||
.unwrap();
|
||||
|
||||
let response =
|
||||
encode_datagram(FrameType::Ethernet, 7, 1, 0, ðernet_frame(b"from relay"))
|
||||
.unwrap();
|
||||
let misdirected_response = encode_datagram(
|
||||
FrameType::Ethernet,
|
||||
7,
|
||||
1,
|
||||
0,
|
||||
&misdirected_unicast_ethernet_frame(),
|
||||
)
|
||||
.unwrap();
|
||||
connection
|
||||
.send_datagram(Bytes::from(misdirected_response))
|
||||
.unwrap();
|
||||
|
||||
let response = encode_datagram(
|
||||
FrameType::Ethernet,
|
||||
7,
|
||||
1,
|
||||
0,
|
||||
&relay_ethernet_frame(b"from relay"),
|
||||
)
|
||||
.unwrap();
|
||||
connection.send_datagram(Bytes::from(response)).unwrap();
|
||||
|
||||
let event = encode_control_message(&ControlMessage::PeerJoined(
|
||||
@@ -842,7 +868,7 @@ mod tests {
|
||||
let ControlMessage::Stats(stats) = stats_message else {
|
||||
panic!("expected client stats event");
|
||||
};
|
||||
assert_eq!(stats, TunnelStats::new(1, 2, 1, 2, 8, 1));
|
||||
assert_eq!(stats, TunnelStats::new(1, 3, 1, 3, 9, 1));
|
||||
stats_received_tx.send(()).unwrap();
|
||||
|
||||
let mut disconnect_recv = connection.accept_uni().await.unwrap();
|
||||
@@ -906,7 +932,10 @@ mod tests {
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(received.source_peer_id(), 1);
|
||||
assert_eq!(received.payload(), ethernet_frame(b"from relay").as_slice());
|
||||
assert_eq!(
|
||||
received.payload(),
|
||||
relay_ethernet_frame(b"from relay").as_slice()
|
||||
);
|
||||
|
||||
let event = tokio::time::timeout(Duration::from_secs(5), client.recv_control_event())
|
||||
.await
|
||||
@@ -968,12 +997,12 @@ mod tests {
|
||||
);
|
||||
let stats = relay_io.stats_snapshot();
|
||||
assert_eq!(stats.ethernet_frames_tx(), 1);
|
||||
assert_eq!(stats.ethernet_frames_rx(), 2);
|
||||
assert_eq!(stats.ethernet_frames_rx(), 3);
|
||||
assert_eq!(stats.broadcast_frames_tx(), 0);
|
||||
assert_eq!(stats.broadcast_frames_rx(), 0);
|
||||
assert_eq!(stats.datagrams_tx(), 1);
|
||||
assert_eq!(stats.datagrams_rx(), 2);
|
||||
assert_eq!(stats.dropped_frames(), 8);
|
||||
assert_eq!(stats.datagrams_rx(), 3);
|
||||
assert_eq!(stats.dropped_frames(), 9);
|
||||
assert_eq!(stats.malformed_frames(), 1);
|
||||
assert_eq!(client.stats_snapshot(), stats);
|
||||
|
||||
@@ -1075,6 +1104,24 @@ mod tests {
|
||||
)
|
||||
}
|
||||
|
||||
fn relay_ethernet_frame(payload: &[u8]) -> Vec<u8> {
|
||||
ethernet_frame_with_headers(
|
||||
MacAddr::new([0x02, 0, 0, 0, 0, 1]),
|
||||
MacAddr::new([0x02, 0, 0, 0, 0, 2]),
|
||||
lanparty_proto::ETHERTYPE_IPV4,
|
||||
payload,
|
||||
)
|
||||
}
|
||||
|
||||
fn misdirected_unicast_ethernet_frame() -> Vec<u8> {
|
||||
ethernet_frame_with_headers(
|
||||
MacAddr::new([0x02, 0, 0, 0, 0, 9]),
|
||||
MacAddr::new([0x02, 0, 0, 0, 0, 2]),
|
||||
lanparty_proto::ETHERTYPE_IPV4,
|
||||
b"wrong client",
|
||||
)
|
||||
}
|
||||
|
||||
fn ethernet_frame_with_headers(
|
||||
destination: MacAddr,
|
||||
source: MacAddr,
|
||||
|
||||
Reference in New Issue
Block a user