cap RX buffers in UDP rather than callers

This commit is contained in:
JackDoan
2026-07-31 13:58:52 -05:00
parent d7bcfb5d6b
commit bc70bf47f8
7 changed files with 15 additions and 8 deletions
+1 -1
View File
@@ -231,7 +231,7 @@ func (f *Interface) handleOutsideRelayPacket(hostinfo *HostInfo, via ViaSender,
case ForwardingType: case ForwardingType:
// Forward this packet through the relay tunnel, rebuilding it in place. // Forward this packet through the relay tunnel, rebuilding it in place.
// Encode overwrites the old outer header, and the new AEAD tag lands where the old one was // Encode overwrites the old outer header, and the new AEAD tag lands where the old one was
fwdBuf := packet[:0:len(packet)] // Cap to len(packet) to protect memory from a larger parent buffer fwdBuf := packet[:0]
//todo it would potentially be nice to batch these //todo it would potentially be nice to batch these
f.SendVia(targetHI, targetRelay, signedPayload, nb, fwdBuf, true, q) f.SendVia(targetHI, targetRelay, signedPayload, nb, fwdBuf, true, q)
case TerminalType: case TerminalType:
+1 -1
View File
@@ -195,7 +195,7 @@ func (u *StdConn) ListenOut(r EncReader, flush func()) error {
continue continue
} }
r(netip.AddrPortFrom(rua.Addr().Unmap(), rua.Port()), buffer[:n]) r(netip.AddrPortFrom(rua.Addr().Unmap(), rua.Port()), buffer[:n:n])
flush() flush()
} }
} }
+1 -1
View File
@@ -106,7 +106,7 @@ func (u *GenericConn) ListenOut(r EncReader, flush func()) error {
continue continue
} }
r(netip.AddrPortFrom(rua.Addr().Unmap(), rua.Port()), buffer[:n]) r(netip.AddrPortFrom(rua.Addr().Unmap(), rua.Port()), buffer[:n:n])
flush() flush()
} }
} }
+2 -2
View File
@@ -305,7 +305,7 @@ func (u *StdConn) ListenOut(r EncReader, flush func()) error {
// deliverSegments hands a received superdatagram to r, splitting it back into pre-coalesce packets // deliverSegments hands a received superdatagram to r, splitting it back into pre-coalesce packets
func deliverSegments(r EncReader, from netip.AddrPort, payload []byte, segSize int) { func deliverSegments(r EncReader, from netip.AddrPort, payload []byte, segSize int) {
if segSize <= 0 || segSize >= len(payload) { //avoid bogus values if segSize <= 0 || segSize >= len(payload) { //avoid bogus values
r(from, payload) r(from, payload[:len(payload):len(payload)])
return return
} }
for off := 0; off < len(payload); off += segSize { for off := 0; off < len(payload); off += segSize {
@@ -313,7 +313,7 @@ func deliverSegments(r EncReader, from netip.AddrPort, payload []byte, segSize i
if end > len(payload) { if end > len(payload) {
end = len(payload) end = len(payload)
} }
r(from, payload[off:end]) r(from, payload[off:end:end])
} }
} }
+8 -1
View File
@@ -210,8 +210,10 @@ func TestParseRecvCmsgCorruptLenNoPanic(t *testing.T) {
// error here shreds encrypted packets and every decrypt downstream fails. // error here shreds encrypted packets and every decrypt downstream fails.
func TestDeliverSegments(t *testing.T) { func TestDeliverSegments(t *testing.T) {
from := netip.MustParseAddrPort("192.0.2.1:4242") from := netip.MustParseAddrPort("192.0.2.1:4242")
// Spare backing capacity mimics the recvmmsg row a real payload sits in;
// the cap checks below prove none of it leaks to a delivered segment.
pay := func(n int) []byte { pay := func(n int) []byte {
b := make([]byte, n) b := make([]byte, n, n+512)
for i := range b { for i := range b {
b[i] = byte(i) b[i] = byte(i)
} }
@@ -262,6 +264,11 @@ func TestDeliverSegments(t *testing.T) {
if len(seg) != wantLens[i] { if len(seg) != wantLens[i] {
t.Fatalf("segment %d len=%d want %d", i, len(seg), wantLens[i]) t.Fatalf("segment %d len=%d want %d", i, len(seg), wantLens[i])
} }
if cap(seg) != len(seg) {
// EncReader contract: an append into spare capacity would
// scribble into the next segment of the shared row.
t.Errorf("segment %d cap=%d, want %d (capacity must not reach into the row)", i, cap(seg), len(seg))
}
if len(seg) > 0 && &seg[0] != &c.payload[off] { if len(seg) > 0 && &seg[0] != &c.payload[off] {
t.Errorf("segment %d does not alias payload at offset %d", i, off) t.Errorf("segment %d does not alias payload at offset %d", i, off)
} }
+1 -1
View File
@@ -161,7 +161,7 @@ func (u *RIOConn) ListenOut(r EncReader, flush func()) error {
continue continue
} }
r(netip.AddrPortFrom(netip.AddrFrom16(rua.Addr).Unmap(), (rua.Port>>8)|((rua.Port&0xff)<<8)), buffer[:n]) r(netip.AddrPortFrom(netip.AddrFrom16(rua.Addr).Unmap(), (rua.Port>>8)|((rua.Port&0xff)<<8)), buffer[:n:n])
flush() flush()
} }
} }
+1 -1
View File
@@ -189,7 +189,7 @@ func (u *TesterConn) ListenOut(r EncReader, flush func()) error {
case <-u.done: case <-u.done:
return os.ErrClosed return os.ErrClosed
case p := <-u.RxPackets: case p := <-u.RxPackets:
r(p.From, p.Data) r(p.From, p.Data[:len(p.Data):len(p.Data)])
// The batcher borrows plaintext decrypted in place inside p.Data // The batcher borrows plaintext decrypted in place inside p.Data
// until Flush, so the packet must stay alive across flush() // until Flush, so the packet must stay alive across flush()
flush() flush()