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

     1  package socks
     2  
     3  import (
     4  	"net"
     5  
     6  	"github.com/phuslu/log"
     7  
     8  	"github.com/yaling888/clash/adapter/inbound"
     9  	"github.com/yaling888/clash/common/pool"
    10  	"github.com/yaling888/clash/common/sockopt"
    11  	C "github.com/yaling888/clash/constant"
    12  	"github.com/yaling888/clash/transport/socks5"
    13  )
    14  
    15  type UDPListener struct {
    16  	packetConn net.PacketConn
    17  	addr       string
    18  	closed     bool
    19  }
    20  
    21  // RawAddress implements C.Listener
    22  func (l *UDPListener) RawAddress() string {
    23  	return l.addr
    24  }
    25  
    26  // Address implements C.Listener
    27  func (l *UDPListener) Address() string {
    28  	return l.packetConn.LocalAddr().String()
    29  }
    30  
    31  // Close implements C.Listener
    32  func (l *UDPListener) Close() error {
    33  	l.closed = true
    34  	return l.packetConn.Close()
    35  }
    36  
    37  func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (C.Listener, error) {
    38  	l, err := net.ListenPacket("udp", addr)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  
    43  	if err := sockopt.UDPReuseaddr(l.(*net.UDPConn)); err != nil {
    44  		log.Warn().Err(err).Msg("[SOCKS] reuse UDP address failed")
    45  	}
    46  
    47  	sl := &UDPListener{
    48  		packetConn: l,
    49  		addr:       addr,
    50  	}
    51  	go func() {
    52  		buf := make([]byte, pool.NetBufferSize)
    53  		for {
    54  			n, remoteAddr, err := l.ReadFrom(buf)
    55  			if err != nil {
    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  		return
    72  	}
    73  	bufP := pool.GetNetBuf()
    74  	n := copy(*bufP, payload)
    75  	*bufP = (*bufP)[:n]
    76  	pkt := &packet{
    77  		pc:      pc,
    78  		rAddr:   addr,
    79  		payload: bufP,
    80  	}
    81  	select {
    82  	case in <- inbound.NewPacket(target, pc.LocalAddr(), pkt, C.SOCKS5):
    83  	default:
    84  		pkt.Drop()
    85  	}
    86  }