Skip to content

Commit c196679

Browse files
committed
TUN-5659: Proxy UDP with zero-byte payload
1 parent 10fc450 commit c196679

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

datagramsession/session.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ func (s *Session) waitForCloseCondition(ctx context.Context, closeAfterIdle time
106106
func (s *Session) dstToTransport(buffer []byte) error {
107107
n, err := s.dstConn.Read(buffer)
108108
s.markActive()
109+
// https://pkg.go.dev/io#Reader suggests caller should always process n > 0 bytes
109110
if n > 0 {
110111
if n <= int(s.transport.MTU()) {
111112
err = s.transport.SendTo(s.ID, buffer[:n])
@@ -118,6 +119,10 @@ func (s *Session) dstToTransport(buffer []byte) error {
118119
Msg("dropped packet exceeding MTU")
119120
}
120121
}
122+
// Some UDP application might send 0-size payload.
123+
if err == nil && n == 0 {
124+
err = s.transport.SendTo(s.ID, []byte{})
125+
}
121126
return err
122127
}
123128

datagramsession/session_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,40 @@ func TestMarkActiveNotBlocking(t *testing.T) {
195195
}
196196
wg.Wait()
197197
}
198+
199+
func TestZeroBytePayload(t *testing.T) {
200+
sessionID := uuid.New()
201+
cfdConn, originConn := net.Pipe()
202+
transport := &mockQUICTransport{
203+
reqChan: newDatagramChannel(1),
204+
respChan: newDatagramChannel(1),
205+
}
206+
log := zerolog.Nop()
207+
session := newSession(sessionID, transport, cfdConn, &log)
208+
209+
ctx, cancel := context.WithCancel(context.Background())
210+
errGroup, ctx := errgroup.WithContext(ctx)
211+
errGroup.Go(func() error {
212+
// Read from underlying conn and send to transport
213+
closedByRemote, err := session.Serve(ctx, time.Minute*2)
214+
require.Equal(t, context.Canceled, err)
215+
require.False(t, closedByRemote)
216+
return nil
217+
})
218+
219+
errGroup.Go(func() error {
220+
// Write to underlying connection
221+
n, err := originConn.Write([]byte{})
222+
require.NoError(t, err)
223+
require.Equal(t, 0, n)
224+
return nil
225+
})
226+
227+
receivedSessionID, payload, err := transport.respChan.Receive(ctx)
228+
require.NoError(t, err)
229+
require.Len(t, payload, 0)
230+
require.Equal(t, sessionID, receivedSessionID)
231+
232+
cancel()
233+
require.NoError(t, errGroup.Wait())
234+
}

0 commit comments

Comments
 (0)