github.com/chwjbn/xclash@v0.2.0/listener/socks/udp.go (about) 1 package socks 2 3 import ( 4 "net" 5 6 "github.com/chwjbn/xclash/adapter/inbound" 7 "github.com/chwjbn/xclash/common/pool" 8 "github.com/chwjbn/xclash/common/sockopt" 9 C "github.com/chwjbn/xclash/constant" 10 "github.com/chwjbn/xclash/log" 11 "github.com/chwjbn/xclash/transport/socks5" 12 ) 13 14 type UDPListener struct { 15 packetConn net.PacketConn 16 addr string 17 closed bool 18 } 19 20 // RawAddress implements C.Listener 21 func (l *UDPListener) RawAddress() string { 22 return l.addr 23 } 24 25 // Address implements C.Listener 26 func (l *UDPListener) Address() string { 27 return l.packetConn.LocalAddr().String() 28 } 29 30 // Close implements C.Listener 31 func (l *UDPListener) Close() error { 32 l.closed = true 33 return l.packetConn.Close() 34 } 35 36 func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error) { 37 l, err := net.ListenPacket("udp", addr) 38 if err != nil { 39 return nil, err 40 } 41 42 if err := sockopt.UDPReuseaddr(l.(*net.UDPConn)); err != nil { 43 log.Warnln("Failed to Reuse UDP Address: %s", err) 44 } 45 46 sl := &UDPListener{ 47 packetConn: l, 48 addr: addr, 49 } 50 go func() { 51 for { 52 buf := pool.Get(pool.UDPBufferSize) 53 n, remoteAddr, err := l.ReadFrom(buf) 54 if err != nil { 55 pool.Put(buf) 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 // Unresolved UDP packet, return buffer to the pool 72 pool.Put(buf) 73 return 74 } 75 packet := &packet{ 76 pc: pc, 77 rAddr: addr, 78 payload: payload, 79 bufRef: buf, 80 } 81 select { 82 case in <- inbound.NewPacket(target, packet, C.SOCKS5): 83 default: 84 } 85 }