chore: Cache and skip multiple failed addresses

This commit is contained in:
Skyxim 2022-10-11 21:35:26 +08:00
parent 7b1427b843
commit 4948f3f213

View file

@ -2,10 +2,13 @@ package sniffer
import ( import (
"errors" "errors"
"fmt"
"github.com/Dreamacro/clash/common/cache"
"github.com/Dreamacro/clash/constant/sniffer" "github.com/Dreamacro/clash/constant/sniffer"
"net" "net"
"net/netip" "net/netip"
"strconv" "strconv"
"sync"
"time" "time"
"github.com/Dreamacro/clash/component/trie" "github.com/Dreamacro/clash/component/trie"
@ -33,6 +36,8 @@ type (
foreDomain *trie.DomainTrie[bool] foreDomain *trie.DomainTrie[bool]
skipSNI *trie.DomainTrie[bool] skipSNI *trie.DomainTrie[bool]
portRanges *[]utils.Range[uint16] portRanges *[]utils.Range[uint16]
skipList *cache.LruCache[string, uint8]
rwMux sync.RWMutex
} }
) )
@ -43,6 +48,7 @@ func (sd *SnifferDispatcher) TCPSniff(conn net.Conn, metadata *C.Metadata) {
} }
if metadata.Host == "" || sd.foreDomain.Search(metadata.Host) != nil { if metadata.Host == "" || sd.foreDomain.Search(metadata.Host) != nil {
port, err := strconv.ParseUint(metadata.DstPort, 10, 16) port, err := strconv.ParseUint(metadata.DstPort, 10, 16)
if err != nil { if err != nil {
log.Debugln("[Sniffer] Dst port is error") log.Debugln("[Sniffer] Dst port is error")
@ -61,7 +67,17 @@ func (sd *SnifferDispatcher) TCPSniff(conn net.Conn, metadata *C.Metadata) {
return return
} }
sd.rwMux.RLock()
dst := fmt.Sprintf("%s:%s", metadata.DstIP, metadata.DstPort)
if count, ok := sd.skipList.Get(dst); ok && count > 5 {
log.Debugln("[Sniffer] Skip sniffing[%s] due to multiple failures", dst)
defer sd.rwMux.RUnlock()
return
}
sd.rwMux.RUnlock()
if host, err := sd.sniffDomain(bufConn, metadata); err != nil { if host, err := sd.sniffDomain(bufConn, metadata); err != nil {
sd.cacheSniffFailed(metadata)
log.Debugln("[Sniffer] All sniffing sniff failed with from [%s:%s] to [%s:%s]", metadata.SrcIP, metadata.SrcPort, metadata.String(), metadata.DstPort) log.Debugln("[Sniffer] All sniffing sniff failed with from [%s:%s] to [%s:%s]", metadata.SrcIP, metadata.SrcPort, metadata.String(), metadata.DstPort)
return return
} else { } else {
@ -70,6 +86,10 @@ func (sd *SnifferDispatcher) TCPSniff(conn net.Conn, metadata *C.Metadata) {
return return
} }
sd.rwMux.RLock()
sd.skipList.Delete(dst)
sd.rwMux.RUnlock()
sd.replaceDomain(metadata, host) sd.replaceDomain(metadata, host)
} }
} }
@ -95,14 +115,15 @@ func (sd *SnifferDispatcher) Enable() bool {
} }
func (sd *SnifferDispatcher) sniffDomain(conn *CN.BufferedConn, metadata *C.Metadata) (string, error) { func (sd *SnifferDispatcher) sniffDomain(conn *CN.BufferedConn, metadata *C.Metadata) (string, error) {
for _, sniffer := range sd.sniffers { for _, s := range sd.sniffers {
if sniffer.SupportNetwork() == C.TCP { if s.SupportNetwork() == C.TCP {
_ = conn.SetReadDeadline(time.Now().Add(3 * time.Second)) _ = conn.SetReadDeadline(time.Now().Add(1 * time.Second))
_, err := conn.Peek(1) _, err := conn.Peek(1)
_ = conn.SetReadDeadline(time.Time{}) _ = conn.SetReadDeadline(time.Time{})
if err != nil { if err != nil {
_, ok := err.(*net.OpError) _, ok := err.(*net.OpError)
if ok { if ok {
sd.cacheSniffFailed(metadata)
log.Errorln("[Sniffer] [%s] may not have any sent data, Consider adding skip", metadata.DstIP.String()) log.Errorln("[Sniffer] [%s] may not have any sent data, Consider adding skip", metadata.DstIP.String())
_ = conn.Close() _ = conn.Close()
} }
@ -117,15 +138,15 @@ func (sd *SnifferDispatcher) sniffDomain(conn *CN.BufferedConn, metadata *C.Meta
continue continue
} }
host, err := sniffer.SniffTCP(bytes) host, err := s.SniffTCP(bytes)
if err != nil { if err != nil {
//log.Debugln("[Sniffer] [%s] Sniff data failed %s", sniffer.Protocol(), metadata.DstIP) //log.Debugln("[Sniffer] [%s] Sniff data failed %s", s.Protocol(), metadata.DstIP)
continue continue
} }
_, err = netip.ParseAddr(host) _, err = netip.ParseAddr(host)
if err == nil { if err == nil {
//log.Debugln("[Sniffer] [%s] Sniff data failed %s", sniffer.Protocol(), metadata.DstIP) //log.Debugln("[Sniffer] [%s] Sniff data failed %s", s.Protocol(), metadata.DstIP)
continue continue
} }
@ -136,6 +157,17 @@ func (sd *SnifferDispatcher) sniffDomain(conn *CN.BufferedConn, metadata *C.Meta
return "", ErrorSniffFailed return "", ErrorSniffFailed
} }
func (sd *SnifferDispatcher) cacheSniffFailed(metadata *C.Metadata) {
sd.rwMux.Lock()
dst := fmt.Sprintf("%s:%s", metadata.DstIP, metadata.DstPort)
count, _ := sd.skipList.Get(dst)
if count <= 5 {
count++
}
sd.skipList.Set(dst, count)
sd.rwMux.Unlock()
}
func NewCloseSnifferDispatcher() (*SnifferDispatcher, error) { func NewCloseSnifferDispatcher() (*SnifferDispatcher, error) {
dispatcher := SnifferDispatcher{ dispatcher := SnifferDispatcher{
enable: false, enable: false,
@ -151,16 +183,17 @@ func NewSnifferDispatcher(needSniffer []sniffer.Type, forceDomain *trie.DomainTr
foreDomain: forceDomain, foreDomain: forceDomain,
skipSNI: skipSNI, skipSNI: skipSNI,
portRanges: ports, portRanges: ports,
skipList: cache.NewLRUCache[string, uint8](cache.WithSize[string, uint8](128), cache.WithAge[string, uint8](600)),
} }
for _, snifferName := range needSniffer { for _, snifferName := range needSniffer {
sniffer, err := NewSniffer(snifferName) s, err := NewSniffer(snifferName)
if err != nil { if err != nil {
log.Errorln("Sniffer name[%s] is error", snifferName) log.Errorln("Sniffer name[%s] is error", snifferName)
return &SnifferDispatcher{enable: false}, err return &SnifferDispatcher{enable: false}, err
} }
dispatcher.sniffers = append(dispatcher.sniffers, sniffer) dispatcher.sniffers = append(dispatcher.sniffers, s)
} }
return &dispatcher, nil return &dispatcher, nil