github.com/yaling888/clash@v1.53.0/listener/tunnel/udp.go (about)

     1  package tunnel
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     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 PacketConn struct {
    14  	conn   net.PacketConn
    15  	addr   string
    16  	target socks5.Addr
    17  	proxy  string
    18  	closed bool
    19  }
    20  
    21  // RawAddress implements C.Listener
    22  func (l *PacketConn) RawAddress() string {
    23  	return l.addr
    24  }
    25  
    26  // Address implements C.Listener
    27  func (l *PacketConn) Address() string {
    28  	return l.conn.LocalAddr().String()
    29  }
    30  
    31  // Close implements C.Listener
    32  func (l *PacketConn) Close() error {
    33  	l.closed = true
    34  	return l.conn.Close()
    35  }
    36  
    37  func NewUDP(addr, target, proxy string, in chan<- *inbound.PacketAdapter) (*PacketConn, error) {
    38  	l, err := net.ListenPacket("udp", addr)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  
    43  	targetAddr := socks5.ParseAddr(target)
    44  	if targetAddr == nil {
    45  		return nil, fmt.Errorf("invalid target address %s", target)
    46  	}
    47  
    48  	sl := &PacketConn{
    49  		conn:   l,
    50  		target: targetAddr,
    51  		proxy:  proxy,
    52  		addr:   addr,
    53  	}
    54  	go func() {
    55  		for {
    56  			bufP := pool.GetNetBuf()
    57  			n, remoteAddr, err := l.ReadFrom(*bufP)
    58  			if err != nil {
    59  				pool.PutNetBuf(bufP)
    60  				if sl.closed {
    61  					break
    62  				}
    63  				continue
    64  			}
    65  			*bufP = (*bufP)[:n]
    66  			sl.handleUDP(l, in, bufP, remoteAddr)
    67  		}
    68  	}()
    69  
    70  	return sl, nil
    71  }
    72  
    73  func (l *PacketConn) handleUDP(pc net.PacketConn, in chan<- *inbound.PacketAdapter, bufP *[]byte, addr net.Addr) {
    74  	pkt := &packet{
    75  		pc:      pc,
    76  		rAddr:   addr,
    77  		payload: bufP,
    78  	}
    79  
    80  	ctx := inbound.NewPacket(l.target, pc.LocalAddr(), pkt, C.TUNNEL)
    81  	ctx.Metadata().SpecialProxy = l.proxy
    82  	select {
    83  	case in <- ctx:
    84  	default:
    85  		pkt.Drop()
    86  	}
    87  }