v1.0.12: Fix link MTU clamping, echo-back prevention, oversized frame detection
MTU Clamping (Bug 8a): Clamp link MTU signalling in LINKREQUEST packets when forwarding through transport node, matching Python reference impl. Without this, TCP endpoints negotiate 8192-byte segments that exceed the V3's 1064-byte HDLC buffer, causing silent truncation and permanent resource transfer stalls at ~70%. Fixed MTU declaration (Bug 8b): Set FIXED_MTU=true on TcpInterface so Transport uses HW_MTU for clamping decisions. Oversized frame detection (Bug 8c): Track truncated HDLC frames and drop them with a diagnostic log instead of silently delivering corrupt data to Transport. Echo-back prevention (v1.0.10): Track which TCP client originated each inbound frame and skip that client in send_outgoing() to prevent flooding TCP buffers. Register local client interface: Enable Transport forwarding of announces, link packets, and proofs to TCP clients. Document all discovered microReticulum bugs in MICRORETICULUM_BUGS.md.
This commit is contained in:
@@ -1730,6 +1730,34 @@ static bool is_backbone_interface(const Interface& iface) {
|
||||
TRACE("Transport::inbound: Packet is next-hop LINKREQUEST");
|
||||
double now = OS::time();
|
||||
double proof_timeout = now + Type::Link::ESTABLISHMENT_TIMEOUT_PER_HOP * std::max((uint8_t)1, remaining_hops);
|
||||
|
||||
// === MTU Clamping (v1.0.12) ===
|
||||
// When forwarding a LINKREQUEST through this transport node,
|
||||
// clamp the link MTU signalling to min(prev-hop, next-hop)
|
||||
// interface HW_MTU. Without this, endpoints negotiate a
|
||||
// segment size that exceeds this node's buffer capacity,
|
||||
// causing silent truncation and resource transfer stalls.
|
||||
uint16_t path_mtu = Link::mtu_from_lr_packet(packet);
|
||||
if (path_mtu > 0) {
|
||||
uint16_t ph_mtu = packet.receiving_interface().HW_MTU();
|
||||
uint16_t nh_mtu = outbound_interface.HW_MTU();
|
||||
if (nh_mtu == 0) {
|
||||
DEBUG("MTU CLAMP: No next-hop HW MTU, stripping link MTU signalling");
|
||||
new_raw = new_raw.left(new_raw.size() - Type::Link::LINK_MTU_SIZE);
|
||||
} else if (!outbound_interface.AUTOCONFIGURE_MTU() && !outbound_interface.FIXED_MTU()) {
|
||||
DEBUG("MTU CLAMP: Outbound interface doesn't support MTU config, stripping link MTU signalling");
|
||||
new_raw = new_raw.left(new_raw.size() - Type::Link::LINK_MTU_SIZE);
|
||||
} else {
|
||||
if (nh_mtu < path_mtu || (ph_mtu > 0 && ph_mtu < path_mtu)) {
|
||||
uint16_t clamped = std::min(nh_mtu, (ph_mtu > 0) ? ph_mtu : nh_mtu);
|
||||
RNS::Type::Link::link_mode mode = Link::mode_from_lr_packet(packet);
|
||||
Bytes clamped_mtu_bytes = Link::signalling_bytes(clamped, mode);
|
||||
new_raw = new_raw.left(new_raw.size() - Type::Link::LINK_MTU_SIZE) + clamped_mtu_bytes;
|
||||
DEBUGF("MTU CLAMP: path=%u ph=%u nh=%u -> clamped=%u", path_mtu, ph_mtu, nh_mtu, clamped);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LinkEntry link_entry(
|
||||
now,
|
||||
next_hop,
|
||||
@@ -1848,6 +1876,25 @@ static bool is_backbone_interface(const Interface& iface) {
|
||||
double now = OS::time();
|
||||
double proof_timeout = now + Type::Link::ESTABLISHMENT_TIMEOUT_PER_HOP
|
||||
* std::max((uint8_t)1, remaining_hops);
|
||||
|
||||
// === MTU Clamping (v1.0.12) ===
|
||||
uint16_t path_mtu = Link::mtu_from_lr_packet(packet);
|
||||
if (path_mtu > 0) {
|
||||
uint16_t ph_mtu = packet.receiving_interface().HW_MTU();
|
||||
uint16_t nh_mtu = outbound_interface.HW_MTU();
|
||||
if (nh_mtu == 0) {
|
||||
new_raw = new_raw.left(new_raw.size() - Type::Link::LINK_MTU_SIZE);
|
||||
} else if (!outbound_interface.AUTOCONFIGURE_MTU() && !outbound_interface.FIXED_MTU()) {
|
||||
new_raw = new_raw.left(new_raw.size() - Type::Link::LINK_MTU_SIZE);
|
||||
} else if (nh_mtu < path_mtu || (ph_mtu > 0 && ph_mtu < path_mtu)) {
|
||||
uint16_t clamped = std::min(nh_mtu, (ph_mtu > 0) ? ph_mtu : nh_mtu);
|
||||
RNS::Type::Link::link_mode mode = Link::mode_from_lr_packet(packet);
|
||||
Bytes clamped_mtu_bytes = Link::signalling_bytes(clamped, mode);
|
||||
new_raw = new_raw.left(new_raw.size() - Type::Link::LINK_MTU_SIZE) + clamped_mtu_bytes;
|
||||
DEBUGF("MTU CLAMP: local->backbone path=%u ph=%u nh=%u -> %u", path_mtu, ph_mtu, nh_mtu, clamped);
|
||||
}
|
||||
}
|
||||
|
||||
LinkEntry link_entry(
|
||||
now, next_hop, outbound_interface, remaining_hops,
|
||||
packet.receiving_interface(), packet.hops(),
|
||||
@@ -1913,6 +1960,25 @@ static bool is_backbone_interface(const Interface& iface) {
|
||||
double now = OS::time();
|
||||
double proof_timeout = now + Type::Link::ESTABLISHMENT_TIMEOUT_PER_HOP
|
||||
* std::max((uint8_t)1, remaining_hops);
|
||||
|
||||
// === MTU Clamping (v1.0.12) ===
|
||||
uint16_t path_mtu = Link::mtu_from_lr_packet(packet);
|
||||
if (path_mtu > 0) {
|
||||
uint16_t ph_mtu = packet.receiving_interface().HW_MTU();
|
||||
uint16_t nh_mtu = outbound_interface.HW_MTU();
|
||||
if (nh_mtu == 0) {
|
||||
new_raw = new_raw.left(new_raw.size() - Type::Link::LINK_MTU_SIZE);
|
||||
} else if (!outbound_interface.AUTOCONFIGURE_MTU() && !outbound_interface.FIXED_MTU()) {
|
||||
new_raw = new_raw.left(new_raw.size() - Type::Link::LINK_MTU_SIZE);
|
||||
} else if (nh_mtu < path_mtu || (ph_mtu > 0 && ph_mtu < path_mtu)) {
|
||||
uint16_t clamped = std::min(nh_mtu, (ph_mtu > 0) ? ph_mtu : nh_mtu);
|
||||
RNS::Type::Link::link_mode mode = Link::mode_from_lr_packet(packet);
|
||||
Bytes clamped_mtu_bytes = Link::signalling_bytes(clamped, mode);
|
||||
new_raw = new_raw.left(new_raw.size() - Type::Link::LINK_MTU_SIZE) + clamped_mtu_bytes;
|
||||
DEBUGF("MTU CLAMP: backbone->local path=%u ph=%u nh=%u -> %u", path_mtu, ph_mtu, nh_mtu, clamped);
|
||||
}
|
||||
}
|
||||
|
||||
LinkEntry link_entry(
|
||||
now, next_hop, outbound_interface, remaining_hops,
|
||||
packet.receiving_interface(), packet.hops(),
|
||||
|
||||
@@ -312,6 +312,7 @@ namespace RNS {
|
||||
static void handle_tunnel(const Bytes& tunnel_id, const Interface& interface);
|
||||
static void register_interface(Interface& interface);
|
||||
static void deregister_interface(const Interface& interface);
|
||||
static void register_local_client_interface(const Interface& interface) { _local_client_interfaces.insert(std::cref(interface)); }
|
||||
inline static const std::map<Bytes, Interface&> get_interfaces() { return _interfaces; }
|
||||
static void register_destination(Destination& destination);
|
||||
static void deregister_destination(const Destination& destination);
|
||||
|
||||
Reference in New Issue
Block a user