Add UDPFilter to Socks5 server when `auth == password` (#3371)

Co-authored-by: RPRX <63339210+RPRX@users.noreply.github.com>
This commit is contained in:
风扇滑翔翼 2024-05-22 11:02:45 +08:00 committed by GitHub
parent 544f7661ca
commit 9ee9a0634e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 42 additions and 0 deletions

View File

@ -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))

31
proxy/socks/udpfilter.go Normal file
View File

@ -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
}