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