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

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