mirror of https://github.com/XTLS/Xray-core
				
				
				
			Add UDPFilter to Socks5 server when `auth == password` (#3371)
Co-authored-by: RPRX <63339210+RPRX@users.noreply.github.com>pull/3381/head
							parent
							
								
									544f7661ca
								
							
						
					
					
						commit
						9ee9a0634e
					
				| 
						 | 
				
			
			@ -27,6 +27,7 @@ type Server struct {
 | 
			
		|||
	config        *ServerConfig
 | 
			
		||||
	policyManager policy.Manager
 | 
			
		||||
	cone          bool
 | 
			
		||||
	udpFilter     *UDPFilter
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewServer creates a new Server object.
 | 
			
		||||
| 
						 | 
				
			
			@ -37,6 +38,9 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
 | 
			
		|||
		policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
 | 
			
		||||
		cone:          ctx.Value("cone").(bool),
 | 
			
		||||
	}
 | 
			
		||||
	if config.AuthType == AuthType_PASSWORD {
 | 
			
		||||
		s.udpFilter = new(UDPFilter) // We only use this when auth is enabled
 | 
			
		||||
	}
 | 
			
		||||
	return s, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -135,6 +139,9 @@ func (s *Server) processTCP(ctx context.Context, conn stat.Connection, dispatche
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if request.Command == protocol.RequestCommandUDP {
 | 
			
		||||
		if s.udpFilter != nil {
 | 
			
		||||
			s.udpFilter.Add(conn.RemoteAddr())
 | 
			
		||||
		}
 | 
			
		||||
		return s.handleUDP(conn)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -193,6 +200,10 @@ func (s *Server) transport(ctx context.Context, reader io.Reader, writer io.Writ
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func (s *Server) handleUDPPayload(ctx context.Context, conn stat.Connection, dispatcher routing.Dispatcher) error {
 | 
			
		||||
	if s.udpFilter != nil && !s.udpFilter.Check(conn.RemoteAddr()) {
 | 
			
		||||
		newError("Unauthorized UDP access from ", conn.RemoteAddr().String()).AtDebug().WriteToLog(session.ExportIDToError(ctx))
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	udpServer := udp.NewDispatcher(dispatcher, func(ctx context.Context, packet *udp_proto.Packet) {
 | 
			
		||||
		payload := packet.Payload
 | 
			
		||||
		newError("writing back UDP response with ", payload.Len(), " bytes").AtDebug().WriteToLog(session.ExportIDToError(ctx))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,31 @@
 | 
			
		|||
package socks
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
In the sock implementation of * ray, UDP authentication is flawed and can be bypassed.
 | 
			
		||||
Tracking a UDP connection may be a bit troublesome.
 | 
			
		||||
Here is a simple solution.
 | 
			
		||||
We creat a filter, add remote IP to the pool when it try to establish a UDP connection with auth.
 | 
			
		||||
And drop UDP packets from unauthorized IP.
 | 
			
		||||
After discussion, we believe it is not necessary to add a timeout mechanism to this filter.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
type UDPFilter struct {
 | 
			
		||||
	ips sync.Map
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *UDPFilter) Add(addr net.Addr) bool {
 | 
			
		||||
	ip, _, _ := net.SplitHostPort(addr.String())
 | 
			
		||||
	f.ips.Store(ip, true)
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *UDPFilter) Check(addr net.Addr) bool {
 | 
			
		||||
	ip, _, _ := net.SplitHostPort(addr.String())
 | 
			
		||||
	_, ok := f.ips.Load(ip)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue