feat(client): validate TAP Ethernet frame I/O

The future client pump should exchange Ethernet frames with TAP through a narrow
API, not raw byte reads and writes. Add TAP frame validation at the adapter
boundary so malformed or jumbo frames are rejected before they enter the relay
path.

Expose `TAP_FRAME_BUFFER_LEN` and `validate_tap_ethernet_frame`, then add
Windows helpers that read a TAP frame and validate it, or validate and fully
write an Ethernet frame. Raw read/write methods remain available for lower-level
adapter work.

Test Plan:
- cargo fmt --check
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- Windows-target cargo clippy for lanparty-client-tap with -D warnings
- git diff --check

Refs: PLAN.md one TAP Ethernet frame per datagram
This commit is contained in:
2026-05-21 18:55:08 +02:00
parent c5fc13d892
commit 70fb23b538
2 changed files with 46 additions and 3 deletions
+19 -2
View File
@@ -4,7 +4,7 @@ use std::{
ptr::{null, null_mut},
};
use anyhow::{Context, Result};
use anyhow::{Context, Result, bail};
use lanparty_proto::MacAddr;
use windows_sys::Win32::{
Foundation::{
@@ -26,7 +26,7 @@ use windows_sys::Win32::{
use crate::{
TAP_ADAPTER_KEY, TapAdapterInfo, is_tap_component_id, tap_ioctl_get_mac, tap_ioctl_get_mtu,
tap_ioctl_set_media_status,
tap_ioctl_set_media_status, validate_tap_ethernet_frame,
};
#[derive(Debug)]
@@ -128,6 +128,13 @@ impl TapAdapter {
Ok(bytes_read as usize)
}
pub fn read_ethernet_frame(&self, buffer: &mut [u8]) -> Result<usize> {
let len = self.read_frame(buffer)?;
validate_tap_ethernet_frame(&buffer[..len])?;
Ok(len)
}
pub fn write_frame(&self, frame: &[u8]) -> Result<usize> {
let mut bytes_written = 0_u32;
let ok = unsafe {
@@ -148,6 +155,16 @@ impl TapAdapter {
Ok(bytes_written as usize)
}
pub fn write_ethernet_frame(&self, frame: &[u8]) -> Result<()> {
validate_tap_ethernet_frame(frame)?;
let written = self.write_frame(frame)?;
if written != frame.len() {
bail!("partial TAP frame write: {written}/{}", frame.len());
}
Ok(())
}
fn device_io_control(
&self,
code: u32,