diff --git a/lib/dialer/internal.go b/lib/dialer/internal.go index e67859258..1eb44ca94 100644 --- a/lib/dialer/internal.go +++ b/lib/dialer/internal.go @@ -7,6 +7,7 @@ package dialer import ( + "net" "net/http" "net/url" "os" @@ -58,3 +59,36 @@ func socksDialerFunction(u *url.URL, forward proxy.Dialer) (proxy.Dialer, error) return proxy.SOCKS5("tcp", u.Host, auth, forward) } + +// dialerConn is needed because proxy dialed connections have RemoteAddr() pointing at the proxy, +// which then screws up various things such as IsLAN checks, and "let's populate the relay invitation address from +// existing connection" shenanigans. +type dialerConn struct { + net.Conn + addr net.Addr +} + +func (c dialerConn) RemoteAddr() net.Addr { + return c.addr +} + +func newDialerAddr(network, addr string) net.Addr { + netAddr, err := net.ResolveIPAddr(network, addr) + if err == nil { + return netAddr + } + return fallbackAddr{network, addr} +} + +type fallbackAddr struct { + network string + addr string +} + +func (a fallbackAddr) Network() string { + return a.network +} + +func (a fallbackAddr) String() string { + return a.addr +} diff --git a/lib/dialer/public.go b/lib/dialer/public.go index 6014aa932..beb69b36e 100644 --- a/lib/dialer/public.go +++ b/lib/dialer/public.go @@ -24,6 +24,8 @@ var errUnexpectedInterfaceType = errors.New("unexpected interface type") // digging through dialerConn to extract the *net.TCPConn func SetTCPOptions(conn net.Conn) error { switch conn := conn.(type) { + case dialerConn: + return SetTCPOptions(conn.Conn) case *net.TCPConn: var err error if err = conn.SetLinger(0); err != nil { @@ -46,6 +48,8 @@ func SetTCPOptions(conn net.Conn) error { func SetTrafficClass(conn net.Conn, class int) error { switch conn := conn.(type) { + case dialerConn: + return SetTrafficClass(conn.Conn, class) case *net.TCPConn: e1 := ipv4.NewConn(conn).SetTOS(class) e2 := ipv6.NewConn(conn).SetTrafficClass(class) @@ -72,6 +76,9 @@ func dialContextWithFallback(ctx context.Context, fallback proxy.ContextDialer, if noFallback { conn, err := dialer.DialContext(ctx, network, addr) l.Debugf("Dialing no fallback result %s %s: %v %v", network, addr, conn, err) + conn = dialerConn{ + conn, newDialerAddr(network, addr), + } return conn, err } @@ -84,6 +91,9 @@ func dialContextWithFallback(ctx context.Context, fallback proxy.ContextDialer, go func() { proxyConn, proxyErr = dialer.DialContext(ctx, network, addr) l.Debugf("Dialing proxy result %s %s: %v %v", network, addr, proxyConn, proxyErr) + proxyConn = dialerConn{ + proxyConn, newDialerAddr(network, addr), + } close(proxyDone) }() go func() { @@ -96,7 +106,7 @@ func dialContextWithFallback(ctx context.Context, fallback proxy.ContextDialer, go func() { <-fallbackDone if fallbackErr == nil { - fallbackConn.Close() + _ = fallbackConn.Close() } }() return proxyConn, nil