From 22c50a70c61f18b54f9e9de82962a053261a398c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A3=8E=E6=89=87=E6=BB=91=E7=BF=94=E7=BF=BC?= Date: Thu, 13 Feb 2025 22:01:33 +0800 Subject: [PATCH] UDS: Make all remote addr 0.0.0.0 (#4390) https://github.com/XTLS/Xray-core/pull/4389#issuecomment-2656360673 --------- Co-authored-by: RPRX <63339210+RPRX@users.noreply.github.com> --- app/proxyman/inbound/worker.go | 14 +------ common/net/destination.go | 10 ++--- transport/internet/system_listener.go | 56 ++++++++++++++++++--------- 3 files changed, 43 insertions(+), 37 deletions(-) diff --git a/app/proxyman/inbound/worker.go b/app/proxyman/inbound/worker.go index 6ef8cca4..a14a338f 100644 --- a/app/proxyman/inbound/worker.go +++ b/app/proxyman/inbound/worker.go @@ -2,7 +2,6 @@ package inbound import ( "context" - "strings" "sync" "sync/atomic" "time" @@ -464,19 +463,8 @@ func (w *dsWorker) callback(conn stat.Connection) { WriteCounter: w.downlinkCounter, } } - // For most of time, unix obviously have no source addr. But if we leave it empty, it will cause panic. - // So we use gateway as source for log. - // However, there are some special situations where a valid source address might be available. - // Such as the source address parsed from X-Forwarded-For in websocket. - // In that case, we keep it. - var source net.Destination - if !strings.Contains(conn.RemoteAddr().String(), "unix") { - source = net.DestinationFromAddr(conn.RemoteAddr()) - } else { - source = net.UnixDestination(w.address) - } ctx = session.ContextWithInbound(ctx, &session.Inbound{ - Source: source, + Source: net.DestinationFromAddr(conn.RemoteAddr()), Gateway: net.UnixDestination(w.address), Tag: w.tag, Conn: conn, diff --git a/common/net/destination.go b/common/net/destination.go index 952dcc6b..90f8298b 100644 --- a/common/net/destination.go +++ b/common/net/destination.go @@ -89,12 +89,10 @@ func UnixDestination(address Address) Destination { // NetAddr returns the network address in this Destination in string form. func (d Destination) NetAddr() string { addr := "" - if d.Address != nil { - if d.Network == Network_TCP || d.Network == Network_UDP { - addr = d.Address.String() + ":" + d.Port.String() - } else if d.Network == Network_UNIX { - addr = d.Address.String() - } + if d.Network == Network_TCP || d.Network == Network_UDP { + addr = d.Address.String() + ":" + d.Port.String() + } else if d.Network == Network_UNIX { + addr = d.Address.String() } return addr } diff --git a/transport/internet/system_listener.go b/transport/internet/system_listener.go index ad7ae892..cdabd3bf 100644 --- a/transport/internet/system_listener.go +++ b/transport/internet/system_listener.go @@ -21,19 +21,6 @@ type DefaultListener struct { controllers []control.Func } -type combinedListener struct { - net.Listener - locker *FileLocker // for unix domain socket -} - -func (cl *combinedListener) Close() error { - if cl.locker != nil { - cl.locker.Release() - cl.locker = nil - } - return cl.Listener.Close() -} - func getControlFunc(ctx context.Context, sockopt *SocketConfig, controllers []control.Func) func(network, address string, c syscall.RawConn) error { return func(network, address string, c syscall.RawConn) error { return c.Control(func(fd uintptr) { @@ -54,6 +41,40 @@ func getControlFunc(ctx context.Context, sockopt *SocketConfig, controllers []co } } +// For some reason, other component of ray will assume the listener is a TCP listener and have valid remote address. +// But in fact it doesn't. So we need to wrap the listener to make it return 0.0.0.0(unspecified) as remote address. +// If other issues encountered, we should able to fix it here. +type listenUDSWrapper struct { + net.Listener + locker *FileLocker +} + +func (l *listenUDSWrapper) Accept() (net.Conn, error) { + conn, err := l.Listener.Accept() + if err != nil { + return nil, err + } + return &listenUDSWrapperConn{Conn: conn}, nil +} + +func (l *listenUDSWrapper) Close() error { + if l.locker != nil { + l.locker.Release() + l.locker = nil + } + return l.Listener.Close() +} + +type listenUDSWrapperConn struct { + net.Conn +} + +func (conn *listenUDSWrapperConn) RemoteAddr() net.Addr { + return &net.TCPAddr{ + IP: []byte{0, 0, 0, 0}, + } +} + func (dl *DefaultListener) Listen(ctx context.Context, addr net.Addr, sockopt *SocketConfig) (l net.Listener, err error) { var lc net.ListenConfig var network, address string @@ -113,9 +134,9 @@ func (dl *DefaultListener) Listen(ctx context.Context, addr net.Addr, sockopt *S callback = func(l net.Listener, err error) (net.Listener, error) { if err != nil { locker.Release() - return l, err + return nil, err } - l = &combinedListener{Listener: l, locker: locker} + l = &listenUDSWrapper{Listener: l, locker: locker} if filePerm == nil { return l, nil } @@ -129,9 +150,8 @@ func (dl *DefaultListener) Listen(ctx context.Context, addr net.Addr, sockopt *S } } - l, err = lc.Listen(ctx, network, address) - l, err = callback(l, err) - if sockopt != nil && sockopt.AcceptProxyProtocol { + l, err = callback(lc.Listen(ctx, network, address)) + if err == nil && sockopt != nil && sockopt.AcceptProxyProtocol { policyFunc := func(upstream net.Addr) (proxyproto.Policy, error) { return proxyproto.REQUIRE, nil } l = &proxyproto.Listener{Listener: l, Policy: policyFunc} }