mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2025-07-18 17:08:06 +08:00
chore: remove the redundant layer of udpnat in sing-tun to reduce resource usage when processing udp
This commit is contained in:
2
go.mod
2
go.mod
@ -31,7 +31,7 @@ require (
|
||||
github.com/metacubex/sing-shadowsocks v0.2.9
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.3
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250523121712-972bc1c2b1e7
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250524070426-1a615b3de4c5
|
||||
github.com/metacubex/sing-vmess v0.2.1
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f
|
||||
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee
|
||||
|
4
go.sum
4
go.sum
@ -128,8 +128,8 @@ github.com/metacubex/sing-shadowsocks2 v0.2.3 h1:v3rNS/5Ywh0NIZ6VU/NmdERQIN5RePz
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.3/go.mod h1:/WNy/Q8ahLCoPRriWuFZFD0Jy+JNp1MEQl28Zw6SaF8=
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MYPm7Wme3/OAY2FFzVq9d9GxPHOqu5AQfg/ddhI=
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250523121712-972bc1c2b1e7 h1:vxkBCkZocH2de2tqeeCZxWvT1VjSJPFkE/8hGqvcLCQ=
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250523121712-972bc1c2b1e7/go.mod h1:HDaHDL6onAX2ZGbAGUXKp++PohRdNb7Nzt6zxzhox+U=
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250524070426-1a615b3de4c5 h1:i+aNFgMMcGFl0vxh7xf4LwAWhc7OzOBdd9SKsWx6vdQ=
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250524070426-1a615b3de4c5/go.mod h1:HDaHDL6onAX2ZGbAGUXKp++PohRdNb7Nzt6zxzhox+U=
|
||||
github.com/metacubex/sing-vmess v0.2.1 h1:I6gM3VUjtvJ15D805EUbNH+SRBuqzJeFnuIbKYUsWZ0=
|
||||
github.com/metacubex/sing-vmess v0.2.1/go.mod h1:DsODWItJtOMZNna8Qhheg8r3tUivrcO3vWgaTYKnfTo=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU=
|
||||
|
@ -146,11 +146,11 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta
|
||||
func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.PacketConn, metadata M.Metadata) error {
|
||||
defer func() { _ = conn.Close() }()
|
||||
mutex := sync.Mutex{}
|
||||
conn2 := bufio.NewNetPacketConn(conn) // a new interface to set nil in defer
|
||||
writer := bufio.NewNetPacketWriter(conn) // a new interface to set nil in defer
|
||||
defer func() {
|
||||
mutex.Lock() // this goroutine must exit after all conn.WritePacket() is not running
|
||||
defer mutex.Unlock()
|
||||
conn2 = nil
|
||||
writer = nil
|
||||
}()
|
||||
rwOptions := network.ReadWaitOptions{}
|
||||
readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn)
|
||||
@ -180,32 +180,48 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.
|
||||
return err
|
||||
}
|
||||
cPacket := &packet{
|
||||
conn: &conn2,
|
||||
mutex: &mutex,
|
||||
rAddr: metadata.Source.UDPAddr(),
|
||||
lAddr: conn.LocalAddr(),
|
||||
buff: buff,
|
||||
writer: &writer,
|
||||
mutex: &mutex,
|
||||
rAddr: metadata.Source.UDPAddr(),
|
||||
lAddr: conn.LocalAddr(),
|
||||
buff: buff,
|
||||
}
|
||||
|
||||
cMetadata := &C.Metadata{
|
||||
NetWork: C.UDP,
|
||||
Type: h.Type,
|
||||
}
|
||||
if metadata.Source.IsIP() && metadata.Source.Fqdn == "" {
|
||||
cMetadata.RawSrcAddr = metadata.Source.Unwrap().UDPAddr()
|
||||
}
|
||||
if dest.IsIP() && dest.Fqdn == "" {
|
||||
cMetadata.RawDstAddr = dest.Unwrap().UDPAddr()
|
||||
}
|
||||
inbound.ApplyAdditions(cMetadata, inbound.WithDstAddr(dest), inbound.WithSrcAddr(metadata.Source), inbound.WithInAddr(conn.LocalAddr()))
|
||||
inbound.ApplyAdditions(cMetadata, h.Additions...)
|
||||
inbound.ApplyAdditions(cMetadata, getAdditions(ctx)...)
|
||||
|
||||
h.Tunnel.HandleUDPPacket(cPacket, cMetadata)
|
||||
h.handlePacket(ctx, cPacket, metadata.Source, dest)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *ListenerHandler) NewPacket(ctx context.Context, key netip.AddrPort, buffer *buf.Buffer, metadata M.Metadata, init func(natConn network.PacketConn) network.PacketWriter) {
|
||||
writer := bufio.NewNetPacketWriter(init(nil))
|
||||
mutex := sync.Mutex{}
|
||||
cPacket := &packet{
|
||||
writer: &writer,
|
||||
mutex: &mutex,
|
||||
rAddr: metadata.Source.UDPAddr(),
|
||||
lAddr: metadata.Source.UDPAddr(), // tun does not have real inAddr
|
||||
buff: buffer,
|
||||
}
|
||||
h.handlePacket(ctx, cPacket, metadata.Source, metadata.Destination)
|
||||
}
|
||||
|
||||
func (h *ListenerHandler) handlePacket(ctx context.Context, cPacket *packet, source M.Socksaddr, destination M.Socksaddr) {
|
||||
cMetadata := &C.Metadata{
|
||||
NetWork: C.UDP,
|
||||
Type: h.Type,
|
||||
}
|
||||
if source.IsIP() && source.Fqdn == "" {
|
||||
cMetadata.RawSrcAddr = source.Unwrap().UDPAddr()
|
||||
}
|
||||
if destination.IsIP() && destination.Fqdn == "" {
|
||||
cMetadata.RawDstAddr = destination.Unwrap().UDPAddr()
|
||||
}
|
||||
inbound.ApplyAdditions(cMetadata, inbound.WithDstAddr(destination), inbound.WithSrcAddr(source), inbound.WithInAddr(cPacket.InAddr()))
|
||||
inbound.ApplyAdditions(cMetadata, h.Additions...)
|
||||
inbound.ApplyAdditions(cMetadata, getAdditions(ctx)...)
|
||||
|
||||
h.Tunnel.HandleUDPPacket(cPacket, cMetadata)
|
||||
}
|
||||
|
||||
func (h *ListenerHandler) NewError(ctx context.Context, err error) {
|
||||
log.Warnln("%s listener get error: %+v", h.Type.String(), err)
|
||||
}
|
||||
@ -225,11 +241,11 @@ func ShouldIgnorePacketError(err error) bool {
|
||||
}
|
||||
|
||||
type packet struct {
|
||||
conn *network.NetPacketConn
|
||||
mutex *sync.Mutex
|
||||
rAddr net.Addr
|
||||
lAddr net.Addr
|
||||
buff *buf.Buffer
|
||||
writer *network.NetPacketWriter
|
||||
mutex *sync.Mutex
|
||||
rAddr net.Addr
|
||||
lAddr net.Addr
|
||||
buff *buf.Buffer
|
||||
}
|
||||
|
||||
func (c *packet) Data() []byte {
|
||||
@ -245,7 +261,7 @@ func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) {
|
||||
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
conn := *c.conn
|
||||
conn := *c.writer
|
||||
if conn == nil {
|
||||
err = errors.New("writeBack to closed connection")
|
||||
return
|
||||
|
@ -43,16 +43,31 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta
|
||||
return h.ListenerHandler.NewConnection(ctx, conn, metadata)
|
||||
}
|
||||
|
||||
func (h *ListenerHandler) NewPacket(ctx context.Context, key netip.AddrPort, buffer *buf.Buffer, metadata M.Metadata, init func(natConn network.PacketConn) network.PacketWriter) {
|
||||
if h.ShouldHijackDns(metadata.Destination.AddrPort()) {
|
||||
log.Debugln("[DNS] hijack udp:%s from %s", metadata.Destination.String(), metadata.Source.String())
|
||||
writer := init(nil)
|
||||
rwOptions := network.ReadWaitOptions{
|
||||
FrontHeadroom: network.CalculateFrontHeadroom(writer),
|
||||
RearHeadroom: network.CalculateRearHeadroom(writer),
|
||||
MTU: resolver.SafeDnsPacketSize,
|
||||
}
|
||||
go relayDnsPacket(ctx, buffer, rwOptions, metadata.Destination, nil, &writer)
|
||||
return
|
||||
}
|
||||
h.ListenerHandler.NewPacket(ctx, key, buffer, metadata, init)
|
||||
}
|
||||
|
||||
func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.PacketConn, metadata M.Metadata) error {
|
||||
if h.ShouldHijackDns(metadata.Destination.AddrPort()) {
|
||||
log.Debugln("[DNS] hijack udp:%s from %s", metadata.Destination.String(), metadata.Source.String())
|
||||
defer func() { _ = conn.Close() }()
|
||||
mutex := sync.Mutex{}
|
||||
conn2 := conn // a new interface to set nil in defer
|
||||
var writer network.PacketWriter = conn // a new interface to set nil in defer
|
||||
defer func() {
|
||||
mutex.Lock() // this goroutine must exit after all conn.WritePacket() is not running
|
||||
defer mutex.Unlock()
|
||||
conn2 = nil
|
||||
writer = nil
|
||||
}()
|
||||
rwOptions := network.ReadWaitOptions{
|
||||
FrontHeadroom: network.CalculateFrontHeadroom(conn),
|
||||
@ -89,43 +104,47 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.
|
||||
}
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
ctx, cancel := context.WithTimeout(ctx, resolver.DefaultDnsRelayTimeout)
|
||||
defer cancel()
|
||||
inData := readBuff.Bytes()
|
||||
writeBuff := readBuff
|
||||
writeBuff.Resize(writeBuff.Start(), 0)
|
||||
if len(writeBuff.FreeBytes()) < resolver.SafeDnsPacketSize { // only create a new buffer when space don't enough
|
||||
writeBuff = rwOptions.NewPacketBuffer()
|
||||
}
|
||||
msg, err := resolver.RelayDnsPacket(ctx, inData, writeBuff.FreeBytes())
|
||||
if writeBuff != readBuff {
|
||||
readBuff.Release()
|
||||
}
|
||||
if err != nil {
|
||||
writeBuff.Release()
|
||||
return
|
||||
}
|
||||
writeBuff.Truncate(len(msg))
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
conn := conn2
|
||||
if conn == nil {
|
||||
writeBuff.Release()
|
||||
return
|
||||
}
|
||||
err = conn.WritePacket(writeBuff, dest) // WritePacket will release writeBuff
|
||||
if err != nil {
|
||||
writeBuff.Release()
|
||||
return
|
||||
}
|
||||
}()
|
||||
go relayDnsPacket(ctx, readBuff, rwOptions, dest, &mutex, &writer)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return h.ListenerHandler.NewPacketConnection(ctx, conn, metadata)
|
||||
}
|
||||
|
||||
func relayDnsPacket(ctx context.Context, readBuff *buf.Buffer, rwOptions network.ReadWaitOptions, dest M.Socksaddr, mutex *sync.Mutex, writer *network.PacketWriter) {
|
||||
ctx, cancel := context.WithTimeout(ctx, resolver.DefaultDnsRelayTimeout)
|
||||
defer cancel()
|
||||
inData := readBuff.Bytes()
|
||||
writeBuff := readBuff
|
||||
writeBuff.Resize(writeBuff.Start(), 0)
|
||||
if len(writeBuff.FreeBytes()) < resolver.SafeDnsPacketSize { // only create a new buffer when space don't enough
|
||||
writeBuff = rwOptions.NewPacketBuffer()
|
||||
}
|
||||
msg, err := resolver.RelayDnsPacket(ctx, inData, writeBuff.FreeBytes())
|
||||
if writeBuff != readBuff {
|
||||
readBuff.Release()
|
||||
}
|
||||
if err != nil {
|
||||
writeBuff.Release()
|
||||
return
|
||||
}
|
||||
writeBuff.Truncate(len(msg))
|
||||
if mutex != nil {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
}
|
||||
conn := *writer
|
||||
if conn == nil {
|
||||
writeBuff.Release()
|
||||
return
|
||||
}
|
||||
err = conn.WritePacket(writeBuff, dest) // WritePacket will release writeBuff
|
||||
if err != nil {
|
||||
writeBuff.Release()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (h *ListenerHandler) TypeMutation(typ C.Type) *ListenerHandler {
|
||||
handle := *h
|
||||
handle.ListenerHandler = h.ListenerHandler.TypeMutation(typ)
|
||||
|
Reference in New Issue
Block a user