github.com/metacubex/mihomo@v1.18.5/listener/tunnel/udp.go (about)

     1  package tunnel
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  
     7  	"github.com/metacubex/mihomo/adapter/inbound"
     8  	"github.com/metacubex/mihomo/common/pool"
     9  	C "github.com/metacubex/mihomo/constant"
    10  	"github.com/metacubex/mihomo/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, tunnel C.Tunnel, additions ...inbound.Addition) (*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  
    55  	if proxy != "" {
    56  		additions = append([]inbound.Addition{inbound.WithSpecialProxy(proxy)}, additions...)
    57  	}
    58  
    59  	go func() {
    60  		for {
    61  			buf := pool.Get(pool.UDPBufferSize)
    62  			n, remoteAddr, err := l.ReadFrom(buf)
    63  			if err != nil {
    64  				pool.Put(buf)
    65  				if sl.closed {
    66  					break
    67  				}
    68  				continue
    69  			}
    70  			sl.handleUDP(l, tunnel, buf[:n], remoteAddr, additions...)
    71  		}
    72  	}()
    73  
    74  	return sl, nil
    75  }
    76  
    77  func (l *PacketConn) handleUDP(pc net.PacketConn, tunnel C.Tunnel, buf []byte, addr net.Addr, additions ...inbound.Addition) {
    78  	cPacket := &packet{
    79  		pc:      pc,
    80  		rAddr:   addr,
    81  		payload: buf,
    82  	}
    83  
    84  	tunnel.HandleUDPPacket(inbound.NewPacket(l.target, cPacket, C.TUNNEL, additions...))
    85  }