github.com/chwjbn/xclash@v0.2.0/listener/tproxy/udp.go (about) 1 package tproxy 2 3 import ( 4 "net" 5 6 "github.com/chwjbn/xclash/adapter/inbound" 7 "github.com/chwjbn/xclash/common/pool" 8 C "github.com/chwjbn/xclash/constant" 9 "github.com/chwjbn/xclash/transport/socks5" 10 ) 11 12 type UDPListener struct { 13 packetConn net.PacketConn 14 addr string 15 closed bool 16 } 17 18 // RawAddress implements C.Listener 19 func (l *UDPListener) RawAddress() string { 20 return l.addr 21 } 22 23 // Address implements C.Listener 24 func (l *UDPListener) Address() string { 25 return l.packetConn.LocalAddr().String() 26 } 27 28 // Close implements C.Listener 29 func (l *UDPListener) Close() error { 30 l.closed = true 31 return l.packetConn.Close() 32 } 33 34 func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error) { 35 l, err := net.ListenPacket("udp", addr) 36 if err != nil { 37 return nil, err 38 } 39 40 rl := &UDPListener{ 41 packetConn: l, 42 addr: addr, 43 } 44 45 c := l.(*net.UDPConn) 46 47 rc, err := c.SyscallConn() 48 if err != nil { 49 return nil, err 50 } 51 52 err = setsockopt(rc, addr) 53 if err != nil { 54 return nil, err 55 } 56 57 go func() { 58 oob := make([]byte, 1024) 59 for { 60 buf := pool.Get(pool.UDPBufferSize) 61 n, oobn, _, lAddr, err := c.ReadMsgUDP(buf, oob) 62 if err != nil { 63 pool.Put(buf) 64 if rl.closed { 65 break 66 } 67 continue 68 } 69 70 rAddr, err := getOrigDst(oob, oobn) 71 if err != nil { 72 continue 73 } 74 handlePacketConn(l, in, buf[:n], lAddr, rAddr) 75 } 76 }() 77 78 return rl, nil 79 } 80 81 func handlePacketConn(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, lAddr *net.UDPAddr, rAddr *net.UDPAddr) { 82 target := socks5.ParseAddrToSocksAddr(rAddr) 83 pkt := &packet{ 84 lAddr: lAddr, 85 buf: buf, 86 } 87 select { 88 case in <- inbound.NewPacket(target, pkt, C.TPROXY): 89 default: 90 } 91 }