mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2026-02-26 08:47:09 +00:00
chore: remove the redundant layer of udpnat in sing-tun to reduce resource usage when processing udp
This commit is contained in:
@@ -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