github.com/metacubex/mihomo@v1.18.5/listener/tproxy/udp.go (about) 1 package tproxy 2 3 import ( 4 "net" 5 "net/netip" 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 UDPListener struct { 14 packetConn net.PacketConn 15 addr string 16 closed bool 17 } 18 19 // RawAddress implements C.Listener 20 func (l *UDPListener) RawAddress() string { 21 return l.addr 22 } 23 24 // Address implements C.Listener 25 func (l *UDPListener) Address() string { 26 return l.packetConn.LocalAddr().String() 27 } 28 29 // Close implements C.Listener 30 func (l *UDPListener) Close() error { 31 l.closed = true 32 return l.packetConn.Close() 33 } 34 35 func NewUDP(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*UDPListener, error) { 36 if len(additions) == 0 { 37 additions = []inbound.Addition{ 38 inbound.WithInName("DEFAULT-TPROXY"), 39 inbound.WithSpecialRules(""), 40 } 41 } 42 l, err := net.ListenPacket("udp", addr) 43 if err != nil { 44 return nil, err 45 } 46 47 rl := &UDPListener{ 48 packetConn: l, 49 addr: addr, 50 } 51 52 c := l.(*net.UDPConn) 53 54 rc, err := c.SyscallConn() 55 if err != nil { 56 return nil, err 57 } 58 59 err = setsockopt(rc, addr) 60 if err != nil { 61 return nil, err 62 } 63 64 go func() { 65 oob := make([]byte, 1024) 66 for { 67 buf := pool.Get(pool.UDPBufferSize) 68 n, oobn, _, lAddr, err := c.ReadMsgUDPAddrPort(buf, oob) 69 if err != nil { 70 pool.Put(buf) 71 if rl.closed { 72 break 73 } 74 continue 75 } 76 77 rAddr, err := getOrigDst(oob[:oobn]) 78 if err != nil { 79 continue 80 } 81 82 dscp, _ := getDSCP(oob[:oobn]) 83 additions = append(additions, inbound.WithDSCP(dscp)) 84 85 if rAddr.Addr().Is4() { 86 // try to unmap 4in6 address 87 lAddr = netip.AddrPortFrom(lAddr.Addr().Unmap(), lAddr.Port()) 88 } 89 handlePacketConn(l, tunnel, buf[:n], lAddr, rAddr, additions...) 90 } 91 }() 92 93 return rl, nil 94 } 95 96 func handlePacketConn(pc net.PacketConn, tunnel C.Tunnel, buf []byte, lAddr, rAddr netip.AddrPort, additions ...inbound.Addition) { 97 target := socks5.AddrFromStdAddrPort(rAddr) 98 pkt := &packet{ 99 pc: pc, 100 lAddr: lAddr, 101 buf: buf, 102 tunnel: tunnel, 103 } 104 tunnel.HandleUDPPacket(inbound.NewPacket(target, pkt, C.TPROXY, additions...)) 105 }