github.com/chwjbn/xclash@v0.2.0/listener/socks/udp.go (about)

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