Skip to content

Commit 1eff569

Browse files
committed
🫧 service: make TCPRelay more generic
Preparation work for unix domain socket support.
1 parent c705f06 commit 1eff569

1 file changed

Lines changed: 33 additions & 22 deletions

File tree

service/tcp.go

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"errors"
66
"io"
77
"net"
8+
"net/netip"
89
"os"
910
"sync"
1011
"time"
@@ -117,28 +118,38 @@ func (s *TCPRelay) Start(ctx context.Context) error {
117118
}
118119

119120
// handleConn handles an accepted TCP connection.
120-
func (s *TCPRelay) handleConn(ctx context.Context, lnc *tcpRelayListener, clientTCPConn *net.TCPConn) {
121-
var clientConn netio.Conn
121+
func (s *TCPRelay) handleConn(ctx context.Context, lnc *tcpRelayListener, acceptedConn netio.Conn) {
122+
var inConn netio.Conn
122123
defer func() {
123-
if clientConn != nil {
124-
_ = clientConn.Close()
124+
if inConn != nil {
125+
_ = inConn.Close()
125126
} else {
126-
_ = clientTCPConn.Close()
127+
_ = acceptedConn.Close()
127128
}
128129
}()
129130

130-
// Get client address.
131-
clientAddrPort := clientTCPConn.RemoteAddr().(*net.TCPAddr).AddrPort()
132-
clientAddress := clientAddrPort.String()
131+
var (
132+
clientAddrPort netip.AddrPort
133+
clientAddress string
134+
)
135+
clientAddr := acceptedConn.RemoteAddr()
136+
if clientTCPAddr, ok := clientAddr.(*net.TCPAddr); ok {
137+
clientAddrPort = clientTCPAddr.AddrPort()
138+
// Unlike net.TCPAddr.String, netip.AddrPort.String preserves IPv4-mapped IPv6 addresses.
139+
clientAddress = clientAddrPort.String()
140+
} else {
141+
clientAddress = clientAddr.String()
142+
}
143+
133144
logger := lnc.logger.With(
134145
zap.String("clientAddress", clientAddress),
135146
)
136147

137148
// Handshake.
138-
req, err := s.server.HandleStream(clientTCPConn, logger)
149+
req, err := s.server.HandleStream(acceptedConn, logger)
139150
if err != nil {
140151
if err == netio.ErrHandleStreamDone {
141-
logger.Debug("Handled TCP connection without bidirectional copy")
152+
logger.Debug("Handled stream connection without bidirectional copy")
142153
return
143154
}
144155
logger.Warn("Failed to complete handshake with client", zap.Error(err))
@@ -189,20 +200,20 @@ func (s *TCPRelay) handleConn(ctx context.Context, lnc *tcpRelayListener, client
189200
// 3. server did not return initial payload
190201
// 4. client has native support
191202
if len(req.Payload) == 0 && clientInfo.NativeInitialPayload && lnc.waitForInitialPayload {
192-
clientConn, err = req.PendingConn.Proceed()
203+
inConn, err = req.PendingConn.Proceed()
193204
if err != nil {
194205
logger.Warn("Failed to proceed with pending connection", zap.Error(err))
195206
return
196207
}
197208

198209
req.Payload = make([]byte, lnc.initialPayloadWaitBufferSize)
199210

200-
if err = clientConn.SetReadDeadline(time.Now().Add(lnc.initialPayloadWaitTimeout)); err != nil {
211+
if err = inConn.SetReadDeadline(time.Now().Add(lnc.initialPayloadWaitTimeout)); err != nil {
201212
logger.Error("Failed to set read deadline to initial payload wait timeout", zap.Error(err))
202213
return
203214
}
204215

205-
payloadLength, err := clientConn.Read(req.Payload)
216+
payloadLength, err := inConn.Read(req.Payload)
206217
switch {
207218
case err == nil:
208219
if ce := logger.Check(zap.DebugLevel, "Got initial payload"); ce != nil {
@@ -230,31 +241,31 @@ func (s *TCPRelay) handleConn(ctx context.Context, lnc *tcpRelayListener, client
230241

231242
req.Payload = req.Payload[:payloadLength]
232243

233-
if err = clientConn.SetReadDeadline(time.Time{}); err != nil {
244+
if err = inConn.SetReadDeadline(time.Time{}); err != nil {
234245
logger.Error("Failed to reset read deadline", zap.Error(err))
235246
return
236247
}
237248
}
238249

239-
// Create remote connection.
240-
remoteConn, err := dialer.DialStream(ctx, req.Addr, req.Payload)
250+
// Open outgoing connection to destination address.
251+
outConn, err := dialer.DialStream(ctx, req.Addr, req.Payload)
241252
if err != nil {
242-
logger.Warn("Failed to create remote connection",
253+
logger.Warn("Failed to open outgoing connection",
243254
zap.Int("initialPayloadLength", len(req.Payload)),
244255
zap.Error(err),
245256
)
246-
if clientConn == nil {
257+
if inConn == nil {
247258
dialResult := conn.DialResultFromError(err)
248259
if err = req.Abort(dialResult); err != nil {
249260
logger.Warn("Failed to abort pending connection", zap.Error(err))
250261
}
251262
}
252263
return
253264
}
254-
defer remoteConn.Close()
265+
defer outConn.Close()
255266

256-
if clientConn == nil {
257-
clientConn, err = req.PendingConn.Proceed()
267+
if inConn == nil {
268+
inConn, err = req.PendingConn.Proceed()
258269
if err != nil {
259270
logger.Warn("Failed to proceed with pending connection", zap.Error(err))
260271
return
@@ -266,7 +277,7 @@ func (s *TCPRelay) handleConn(ctx context.Context, lnc *tcpRelayListener, client
266277
)
267278

268279
// Bidirectional copy.
269-
nl2r, nr2l, err := netio.BidirectionalCopy(clientConn, remoteConn)
280+
nl2r, nr2l, err := netio.BidirectionalCopy(inConn, outConn)
270281
nl2r += int64(len(req.Payload))
271282
s.collector.CollectTCPSession(req.Username, uint64(nr2l), uint64(nl2r))
272283
if err != nil {

0 commit comments

Comments
 (0)