Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions component/sniffer/base_sniffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import (
)

type SnifferConfig struct {
OverrideDest bool
Ports utils.IntRanges[uint16]
OverrideDest bool
Ports utils.IntRanges[uint16]
SkipThreshold uint8 // max sniff-failure count before a dst is skipped (255 = never skip)
}

type BaseSniffer struct {
Expand Down
9 changes: 7 additions & 2 deletions component/sniffer/dispatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package sniffer

import (
"errors"
"math"
"net"
"net/netip"
"time"
Expand Down Expand Up @@ -106,11 +107,15 @@ func (sd *Dispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata) bool
if sd.shouldOverride(metadata) {
inWhitelist := false
overrideDest := false
skipThreshold := uint8(5)
for sniffer, config := range sd.sniffers {
if sniffer.SupportNetwork() == C.TCP || sniffer.SupportNetwork() == C.ALLNet {
inWhitelist = sniffer.SupportPort(metadata.DstPort)
if inWhitelist {
overrideDest = config.OverrideDest
if config.SkipThreshold > 0 {
skipThreshold = config.SkipThreshold
}
break
}
}
Expand All @@ -123,7 +128,7 @@ func (sd *Dispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata) bool

dst := metadata.AddrPort()
if !forceSniffer {
if count, ok := sd.skipList.Get(dst); ok && count > 5 {
if count, ok := sd.skipList.Get(dst); ok && count > skipThreshold {
log.Debugln("[Sniffer] Skip sniffing[%s] due to multiple failures", dst)
return false
}
Expand Down Expand Up @@ -245,7 +250,7 @@ func (sd *Dispatcher) sniffDomain(conn *N.BufferedConn, metadata *C.Metadata) (s
func (sd *Dispatcher) cacheSniffFailed(metadata *C.Metadata) {
dst := metadata.AddrPort()
sd.skipList.Compute(dst, func(oldValue uint8, loaded bool) (newValue uint8, delete bool) {
if oldValue <= 5 {
if oldValue < math.MaxUint8 {
oldValue++
}
return oldValue, false
Expand Down
21 changes: 15 additions & 6 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,13 +378,15 @@ type RawSniffer struct {
Ports []string `yaml:"port-whitelist" json:"port-whitelist"`
ForceDnsMapping bool `yaml:"force-dns-mapping" json:"force-dns-mapping"`
ParsePureIp bool `yaml:"parse-pure-ip" json:"parse-pure-ip"`
SkipThreshold int `yaml:"skip-threshold" json:"skip-threshold"`

Sniff map[string]RawSniffingConfig `yaml:"sniff" json:"sniff"`
}

type RawSniffingConfig struct {
Ports []string `yaml:"ports" json:"ports"`
OverrideDest *bool `yaml:"override-destination" json:"override-destination"`
Ports []string `yaml:"ports" json:"ports"`
OverrideDest *bool `yaml:"override-destination" json:"override-destination"`
SkipThreshold *int `yaml:"skip-threshold" json:"skip-threshold"`
}

type RawTLS struct {
Expand Down Expand Up @@ -590,6 +592,7 @@ func DefaultRawConfig() *RawConfig {
ForceDnsMapping: true,
ParsePureIp: true,
OverrideDest: true,
SkipThreshold: 5,
},
ExternalUIURL: "https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip",
ExternalControllerCors: RawCors{
Expand Down Expand Up @@ -1770,12 +1773,17 @@ func parseSniffer(snifferRaw RawSniffer, ruleProviders map[string]P.RuleProvider
if sniffConfig.OverrideDest != nil {
overrideDest = *sniffConfig.OverrideDest
}
skipThreshold := snifferRaw.SkipThreshold
if sniffConfig.SkipThreshold != nil {
skipThreshold = *sniffConfig.SkipThreshold
}
for _, snifferType := range snifferTypes.List {
if snifferType.String() == strings.ToUpper(sniffType) {
find = true
loadSniffer[snifferType] = sniffer.SnifferConfig{
Ports: ports,
OverrideDest: overrideDest,
Ports: ports,
OverrideDest: overrideDest,
SkipThreshold: uint8(skipThreshold),
}
}
}
Expand All @@ -1800,8 +1808,9 @@ func parseSniffer(snifferRaw RawSniffer, ruleProviders map[string]P.RuleProvider
if snifferType.String() == strings.ToUpper(snifferName) {
find = true
loadSniffer[snifferType] = sniffer.SnifferConfig{
Ports: globalPorts,
OverrideDest: snifferRaw.OverrideDest,
Ports: globalPorts,
OverrideDest: snifferRaw.OverrideDest,
SkipThreshold: uint8(snifferRaw.SkipThreshold),
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions docs/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,10 @@ sniffer:
# 是否使用嗅探结果作为实际访问,默认 true
# 全局配置,优先级低于 sniffer.sniff 实际配置
override-destination: false
# 同一目标嗅探失败超过该次数后,在缓存有效期内跳过嗅探,默认 5
# 取值 uint8(0-255),设为 255(-1) 表示永不跳过
# 全局配置,优先级低于 sniffer.sniff 实际配置
# skip-threshold: 5
sniff: # TLS 和 QUIC 默认如果不配置 ports 默认嗅探 443
QUIC:
# ports: [ 443 ]
Expand All @@ -212,6 +216,8 @@ sniffer:
ports: [80, 8080-8880]
# 可覆盖 sniffer.override-destination
override-destination: true
# 可覆盖 sniffer.skip-threshold
# skip-threshold: 5
force-domain:
- +.v2ex.com
# skip-src-address: # 对于来源ip跳过嗅探
Expand Down