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 }