TUN-5659: Proxy UDP with zero-byte payload

This commit is contained in:
cthuang 2022-01-19 18:24:16 +00:00 committed by Chung Ting Huang
parent 10fc450ae5
commit c196679bc7
2 changed files with 42 additions and 0 deletions

View File

@ -106,6 +106,7 @@ func (s *Session) waitForCloseCondition(ctx context.Context, closeAfterIdle time
func (s *Session) dstToTransport(buffer []byte) error { func (s *Session) dstToTransport(buffer []byte) error {
n, err := s.dstConn.Read(buffer) n, err := s.dstConn.Read(buffer)
s.markActive() s.markActive()
// https://pkg.go.dev/io#Reader suggests caller should always process n > 0 bytes
if n > 0 { if n > 0 {
if n <= int(s.transport.MTU()) { if n <= int(s.transport.MTU()) {
err = s.transport.SendTo(s.ID, buffer[:n]) err = s.transport.SendTo(s.ID, buffer[:n])
@ -118,6 +119,10 @@ func (s *Session) dstToTransport(buffer []byte) error {
Msg("dropped packet exceeding MTU") Msg("dropped packet exceeding MTU")
} }
} }
// Some UDP application might send 0-size payload.
if err == nil && n == 0 {
err = s.transport.SendTo(s.ID, []byte{})
}
return err return err
} }

View File

@ -195,3 +195,40 @@ func TestMarkActiveNotBlocking(t *testing.T) {
} }
wg.Wait() wg.Wait()
} }
func TestZeroBytePayload(t *testing.T) {
sessionID := uuid.New()
cfdConn, originConn := net.Pipe()
transport := &mockQUICTransport{
reqChan: newDatagramChannel(1),
respChan: newDatagramChannel(1),
}
log := zerolog.Nop()
session := newSession(sessionID, transport, cfdConn, &log)
ctx, cancel := context.WithCancel(context.Background())
errGroup, ctx := errgroup.WithContext(ctx)
errGroup.Go(func() error {
// Read from underlying conn and send to transport
closedByRemote, err := session.Serve(ctx, time.Minute*2)
require.Equal(t, context.Canceled, err)
require.False(t, closedByRemote)
return nil
})
errGroup.Go(func() error {
// Write to underlying connection
n, err := originConn.Write([]byte{})
require.NoError(t, err)
require.Equal(t, 0, n)
return nil
})
receivedSessionID, payload, err := transport.respChan.Receive(ctx)
require.NoError(t, err)
require.Len(t, payload, 0)
require.Equal(t, sessionID, receivedSessionID)
cancel()
require.NoError(t, errGroup.Wait())
}