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  }