mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2025-01-03 16:13:30 +08:00
cache: add dns cache in udp packet sender
reduce the cost of re-resolving DNS for each packet received and prevent the target IP from jumping between multiple resolution results
This commit is contained in:
parent
4fa15c6334
commit
43cb48231a
@ -298,7 +298,11 @@ type PacketSender interface {
|
|||||||
// Send will send PacketAdapter nonblocking
|
// Send will send PacketAdapter nonblocking
|
||||||
// the implement must call UDPPacket.Drop() inside Send
|
// the implement must call UDPPacket.Drop() inside Send
|
||||||
Send(PacketAdapter)
|
Send(PacketAdapter)
|
||||||
|
// Process is a blocking loop to send PacketAdapter to PacketConn and update the WriteBackProxy
|
||||||
Process(PacketConn, WriteBackProxy)
|
Process(PacketConn, WriteBackProxy)
|
||||||
|
// ResolveUDP do a local resolve UDP dns blocking if metadata is not resolved
|
||||||
|
ResolveUDP(*Metadata) error
|
||||||
|
// Close stop the Process loop
|
||||||
Close()
|
Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,9 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/metacubex/mihomo/common/lru"
|
||||||
N "github.com/metacubex/mihomo/common/net"
|
N "github.com/metacubex/mihomo/common/net"
|
||||||
|
"github.com/metacubex/mihomo/component/resolver"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
"github.com/metacubex/mihomo/log"
|
"github.com/metacubex/mihomo/log"
|
||||||
)
|
)
|
||||||
@ -16,6 +18,7 @@ type packetSender struct {
|
|||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
ch chan C.PacketAdapter
|
ch chan C.PacketAdapter
|
||||||
|
cache *lru.LruCache[string, netip.Addr]
|
||||||
}
|
}
|
||||||
|
|
||||||
// newPacketSender return a chan based C.PacketSender
|
// newPacketSender return a chan based C.PacketSender
|
||||||
@ -27,6 +30,7 @@ func newPacketSender() C.PacketSender {
|
|||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
ch: ch,
|
ch: ch,
|
||||||
|
cache: lru.New[string, netip.Addr](lru.WithSize[string, netip.Addr](senderCapacity)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +43,11 @@ func (s *packetSender) Process(pc C.PacketConn, proxy C.WriteBackProxy) {
|
|||||||
if proxy != nil {
|
if proxy != nil {
|
||||||
proxy.UpdateWriteBack(packet)
|
proxy.UpdateWriteBack(packet)
|
||||||
}
|
}
|
||||||
_ = handleUDPToRemote(packet, pc, packet.Metadata())
|
if err := s.ResolveUDP(packet.Metadata()); err != nil {
|
||||||
|
log.Warnln("[UDP] Resolve Ip error: %s", err)
|
||||||
|
} else {
|
||||||
|
_ = handleUDPToRemote(packet, pc, packet.Metadata())
|
||||||
|
}
|
||||||
packet.Drop()
|
packet.Drop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,11 +87,24 @@ func (s *packetSender) Close() {
|
|||||||
s.dropAll()
|
s.dropAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata) error {
|
func (s *packetSender) ResolveUDP(metadata *C.Metadata) (err error) {
|
||||||
if err := resolveUDP(metadata); err != nil {
|
// local resolve UDP dns
|
||||||
return err
|
if !metadata.Resolved() {
|
||||||
}
|
ip, ok := s.cache.Get(metadata.Host)
|
||||||
|
if !ok {
|
||||||
|
ip, err = resolver.ResolveIP(s.ctx, metadata.Host)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.cache.Set(metadata.Host, ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata.DstIP = ip
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata) error {
|
||||||
addr := metadata.UDPAddr()
|
addr := metadata.UDPAddr()
|
||||||
if addr == nil {
|
if addr == nil {
|
||||||
return errors.New("udp addr invalid")
|
return errors.New("udp addr invalid")
|
||||||
|
@ -346,18 +346,6 @@ func resolveMetadata(metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err erro
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveUDP(metadata *C.Metadata) error {
|
|
||||||
// local resolve UDP dns
|
|
||||||
if !metadata.Resolved() {
|
|
||||||
ip, err := resolver.ResolveIP(context.Background(), metadata.Host)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
metadata.DstIP = ip
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// processUDP starts a loop to handle udp packet
|
// processUDP starts a loop to handle udp packet
|
||||||
func processUDP(queue chan C.PacketAdapter) {
|
func processUDP(queue chan C.PacketAdapter) {
|
||||||
for conn := range queue {
|
for conn := range queue {
|
||||||
@ -398,7 +386,7 @@ func handleUDPConn(packet C.PacketAdapter) {
|
|||||||
sender, loaded := natTable.GetOrCreate(key, newPacketSender)
|
sender, loaded := natTable.GetOrCreate(key, newPacketSender)
|
||||||
if !loaded {
|
if !loaded {
|
||||||
dial := func() (C.PacketConn, C.WriteBackProxy, error) {
|
dial := func() (C.PacketConn, C.WriteBackProxy, error) {
|
||||||
if err := resolveUDP(metadata); err != nil {
|
if err := sender.ResolveUDP(metadata); err != nil {
|
||||||
log.Warnln("[UDP] Resolve Ip error: %s", err)
|
log.Warnln("[UDP] Resolve Ip error: %s", err)
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user