feat(proto): validate negotiated datagram budgets
PLAN.md keeps MVP traffic to one Ethernet frame per QUIC datagram with no fragmentation. The relay already negotiates a datagram budget, but the client and gateway send paths still relied on Quinn to reject oversized encoded Ethernet datagrams. Add a shared protocol validation helper for encoded datagram length versus the negotiated QUIC budget. Thread the negotiated budget into client and gateway send boundaries, reject oversized datagrams before send, and count those valid but unsent frames as local drops. Document the budget check in the workspace decomposition and gateway behavior. Test Plan: - cargo fmt --check - cargo test -p lanparty-proto -p lanparty-client-core -p lanparty-gateway - cargo test --workspace - cargo clippy --workspace --all-targets -- -D warnings - git diff --check Refs: PLAN.md
This commit is contained in:
@@ -170,6 +170,8 @@ pub enum ProtoError {
|
||||
UnknownFrameType(u8),
|
||||
#[error("payload length {len} exceeds wire maximum {max}")]
|
||||
PayloadTooLarge { len: usize, max: usize },
|
||||
#[error("encoded datagram length {len} exceeds negotiated QUIC datagram budget {max}")]
|
||||
DatagramExceedsBudget { len: usize, max: usize },
|
||||
#[error("declared payload length {declared} does not match actual length {actual}")]
|
||||
PayloadLengthMismatch { declared: usize, actual: usize },
|
||||
#[error("Ethernet frame is too short: got {actual} bytes, need at least {minimum}")]
|
||||
@@ -190,6 +192,20 @@ pub fn encode_datagram(
|
||||
Ok(datagram)
|
||||
}
|
||||
|
||||
pub fn validate_datagram_budget(
|
||||
datagram_len: usize,
|
||||
max_datagram_size: usize,
|
||||
) -> Result<(), ProtoError> {
|
||||
if datagram_len > max_datagram_size {
|
||||
return Err(ProtoError::DatagramExceedsBudget {
|
||||
len: datagram_len,
|
||||
max: max_datagram_size,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn decode_datagram(bytes: &[u8]) -> Result<OverlayPacket<'_>, ProtoError> {
|
||||
let header = OverlayHeader::decode(bytes)?;
|
||||
let payload = &bytes[OVERLAY_HEADER_LEN..];
|
||||
@@ -281,4 +297,18 @@ mod tests {
|
||||
ProtoError::PayloadTooLarge { .. }
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_datagrams_over_negotiated_budget() {
|
||||
let datagram = encode_datagram(FrameType::Ethernet, 1, 2, 0, &[1, 2, 3]).unwrap();
|
||||
|
||||
assert!(validate_datagram_budget(datagram.len(), datagram.len()).is_ok());
|
||||
assert_eq!(
|
||||
validate_datagram_budget(datagram.len(), datagram.len() - 1).unwrap_err(),
|
||||
ProtoError::DatagramExceedsBudget {
|
||||
len: datagram.len(),
|
||||
max: datagram.len() - 1
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user