github.com/yaling888/clash@v1.53.0/listener/socks/udp.go (about) 1 package socks 2 3 import ( 4 "net" 5 6 "github.com/phuslu/log" 7 8 "github.com/yaling888/clash/adapter/inbound" 9 "github.com/yaling888/clash/common/pool" 10 "github.com/yaling888/clash/common/sockopt" 11 C "github.com/yaling888/clash/constant" 12 "github.com/yaling888/clash/transport/socks5" 13 ) 14 15 type UDPListener struct { 16 packetConn net.PacketConn 17 addr string 18 closed bool 19 } 20 21 // RawAddress implements C.Listener 22 func (l *UDPListener) RawAddress() string { 23 return l.addr 24 } 25 26 // Address implements C.Listener 27 func (l *UDPListener) Address() string { 28 return l.packetConn.LocalAddr().String() 29 } 30 31 // Close implements C.Listener 32 func (l *UDPListener) Close() error { 33 l.closed = true 34 return l.packetConn.Close() 35 } 36 37 func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (C.Listener, error) { 38 l, err := net.ListenPacket("udp", addr) 39 if err != nil { 40 return nil, err 41 } 42 43 if err := sockopt.UDPReuseaddr(l.(*net.UDPConn)); err != nil { 44 log.Warn().Err(err).Msg("[SOCKS] reuse UDP address failed") 45 } 46 47 sl := &UDPListener{ 48 packetConn: l, 49 addr: addr, 50 } 51 go func() { 52 buf := make([]byte, pool.NetBufferSize) 53 for { 54 n, remoteAddr, err := l.ReadFrom(buf) 55 if err != nil { 56 if sl.closed { 57 break 58 } 59 continue 60 } 61 handleSocksUDP(l, in, buf[:n], remoteAddr) 62 } 63 }() 64 65 return sl, nil 66 } 67 68 func handleSocksUDP(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, addr net.Addr) { 69 target, payload, err := socks5.DecodeUDPPacket(buf) 70 if err != nil { 71 return 72 } 73 bufP := pool.GetNetBuf() 74 n := copy(*bufP, payload) 75 *bufP = (*bufP)[:n] 76 pkt := &packet{ 77 pc: pc, 78 rAddr: addr, 79 payload: bufP, 80 } 81 select { 82 case in <- inbound.NewPacket(target, pc.LocalAddr(), pkt, C.SOCKS5): 83 default: 84 pkt.Drop() 85 } 86 }