From b3f4c5f42b55772350978ae8179794acd3888026 Mon Sep 17 00:00:00 2001 From: Git Sagar Date: Sat, 6 Jun 2026 22:53:06 +0530 Subject: [PATCH] tunnel: add write mutex for concurrent safety WriteFrames and keepalive both write multi-part messages to the TLS connection. Without synchronization, their writes could interleave and corrupt the framing. Add writeMu to serialize all tunnel writes. Co-Authored-By: Claude Opus 4.6 (1M context) --- pkg/client/tunnel.go | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/pkg/client/tunnel.go b/pkg/client/tunnel.go index b40e407..f8d43f0 100644 --- a/pkg/client/tunnel.go +++ b/pkg/client/tunnel.go @@ -28,6 +28,7 @@ const ( // SoftEther VPN session. Each "block" is one Ethernet frame. type Tunnel struct { sess *Session + writeMu sync.Mutex stopCh chan struct{} stopped sync.Once } @@ -83,7 +84,11 @@ func (t *Tunnel) ReadFrames() ([][]byte, error) { } // WriteFrames sends a batch of Ethernet frames to the server. +// Safe for concurrent use from multiple goroutines. func (t *Tunnel) WriteFrames(frames [][]byte) error { + t.writeMu.Lock() + defer t.writeMu.Unlock() + if err := binary.Write(t.sess.Conn, binary.BigEndian, uint32(len(frames))); err != nil { return fmt.Errorf("write num blocks: %w", err) } @@ -170,14 +175,20 @@ func (t *Tunnel) StartKeepalive() { return case <-ticker.C: size := uint32(rng.Intn(int(maxKeepaliveSize))) + 1 - if err := binary.Write(t.sess.Conn, binary.BigEndian, keepAliveMagic); err != nil { - return - } - if err := binary.Write(t.sess.Conn, binary.BigEndian, size); err != nil { - return - } rng.Read(randBuf[:size]) - if _, err := t.sess.Conn.Write(randBuf[:size]); err != nil { + + t.writeMu.Lock() + err1 := binary.Write(t.sess.Conn, binary.BigEndian, keepAliveMagic) + var err2, err3 error + if err1 == nil { + err2 = binary.Write(t.sess.Conn, binary.BigEndian, size) + } + if err2 == nil { + _, err3 = t.sess.Conn.Write(randBuf[:size]) + } + t.writeMu.Unlock() + + if err1 != nil || err2 != nil || err3 != nil { return } }