Skip to content

Commit 51c5ef7

Browse files
committed
TUN-9882: Add write deadline for UDP origin writes
Add a deadline for origin writes as a preventative measure in the case that the kernel blocks any writes for too long. In the case that the socket exceeds the write deadline, the datagram will be dropped. Closes TUN-9882
1 parent 1fb4669 commit 51c5ef7

File tree

2 files changed

+24
-1
lines changed

2 files changed

+24
-1
lines changed

ingress/origin_dialer.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"github.com/rs/zerolog"
1212
)
1313

14+
const writeDeadlineUDP = 200 * time.Millisecond
15+
1416
// OriginTCPDialer provides a TCP dial operation to a requested address.
1517
type OriginTCPDialer interface {
1618
DialTCP(ctx context.Context, addr netip.AddrPort) (net.Conn, error)
@@ -141,6 +143,21 @@ func (d *Dialer) DialUDP(dest netip.AddrPort) (net.Conn, error) {
141143
if err != nil {
142144
return nil, fmt.Errorf("unable to dial udp to origin %s: %w", dest, err)
143145
}
146+
return &writeDeadlineConn{
147+
Conn: conn,
148+
}, nil
149+
}
144150

145-
return conn, nil
151+
// writeDeadlineConn is a wrapper around a net.Conn that sets a write deadline of 200ms.
152+
// This is to prevent the socket from blocking on the write operation if it were to occur. However,
153+
// we typically never expect this to occur except under high load or kernel issues.
154+
type writeDeadlineConn struct {
155+
net.Conn
156+
}
157+
158+
func (w *writeDeadlineConn) Write(b []byte) (int, error) {
159+
if err := w.SetWriteDeadline(time.Now().Add(writeDeadlineUDP)); err != nil {
160+
return 0, err
161+
}
162+
return w.Conn.Write(b)
146163
}

quic/v3/session.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"io"
88
"net"
9+
"os"
910
"sync"
1011
"sync/atomic"
1112
"time"
@@ -241,6 +242,11 @@ func (s *session) writeLoop() {
241242
case payload := <-s.writeChan:
242243
n, err := s.origin.Write(payload)
243244
if err != nil {
245+
// Check if this is a write deadline exceeded to the connection
246+
if errors.Is(err, os.ErrDeadlineExceeded) {
247+
s.log.Warn().Err(err).Msg("flow (write) deadline exceeded: dropping packet")
248+
continue
249+
}
244250
if isConnectionClosed(err) {
245251
s.log.Debug().Msgf("flow (write) connection closed: %v", err)
246252
}

0 commit comments

Comments
 (0)