From 8d6f171888af231aa0235b604e9f5ce602a96a6d Mon Sep 17 00:00:00 2001 From: Ben Schwartz Date: Tue, 26 Jan 2021 17:35:59 -0500 Subject: [PATCH] Use implicit name resolution for TCP destinations When connecting to a TCP destination by name, go's implicit resolution behavior tries all available addresses until it finds one that works (fallback), with a preference for IPv6 if possible (happy eyeballs). This is better than our current behavior (pick one IPv4 address). The Outline client doesn't rely on named destinations, but other Shadowsocks clients do. This is an alternative to #100. This change has one key difference from the previous behavior: IP validation is enforced after the connection is established, not before. A hostile user cannot use this to send data to a private service, but they might be able to detect the existence of that service based on how long the server waits before closing the connection. --- service/tcp.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/service/tcp.go b/service/tcp.go index c954d3d6..90e302bd 100644 --- a/service/tcp.go +++ b/service/tcp.go @@ -149,18 +149,15 @@ func (s *tcpService) SetTargetIPValidator(targetIPValidator onet.TargetIPValidat } func dialTarget(tgtAddr socks.Addr, proxyMetrics *metrics.ProxyMetrics, targetIPValidator onet.TargetIPValidator) (onet.DuplexConn, *onet.ConnectionError) { - tgtTCPAddr, err := net.ResolveTCPAddr("tcp", tgtAddr.String()) + tgtConn, err := net.Dial("tcp", tgtAddr.String()) if err != nil { - return nil, onet.NewConnectionError("ERR_RESOLVE_ADDRESS", fmt.Sprintf("Failed to resolve target address %v", tgtAddr.String()), err) + return nil, onet.NewConnectionError("ERR_CONNECT", "Failed to connect to target", err) } - if err := targetIPValidator(tgtTCPAddr.IP); err != nil { + tgtTCPConn := tgtConn.(*net.TCPConn) + if err := targetIPValidator(tgtTCPConn.RemoteAddr().(*net.TCPAddr).IP); err != nil { + tgtTCPConn.Close() return nil, err } - - tgtTCPConn, err := net.DialTCP("tcp", nil, tgtTCPAddr) - if err != nil { - return nil, onet.NewConnectionError("ERR_CONNECT", "Failed to connect to target", err) - } tgtTCPConn.SetKeepAlive(true) return metrics.MeasureConn(tgtTCPConn, &proxyMetrics.ProxyTarget, &proxyMetrics.TargetProxy), nil }