Clash.Meta/component/sniffer/dispatcher.go

168 lines
3.9 KiB
Go
Raw Normal View History

package sniffer
import (
"errors"
"net"
2022-04-20 01:52:51 +08:00
"net/netip"
"strconv"
2022-04-21 23:08:37 +08:00
"time"
"github.com/Dreamacro/clash/component/trie"
CN "github.com/Dreamacro/clash/common/net"
"github.com/Dreamacro/clash/common/utils"
"github.com/Dreamacro/clash/component/resolver"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
)
var (
ErrorUnsupportedSniffer = errors.New("unsupported sniffer")
ErrorSniffFailed = errors.New("all sniffer failed")
)
var Dispatcher SnifferDispatcher
type (
SnifferDispatcher struct {
enable bool
sniffers []C.Sniffer
foreDomain *trie.DomainTrie[bool]
skipSNI *trie.DomainTrie[bool]
portRanges *[]utils.Range[uint16]
}
)
func (sd *SnifferDispatcher) TCPSniff(conn net.Conn, metadata *C.Metadata) {
bufConn, ok := conn.(*CN.BufferedConn)
if !ok {
return
}
if metadata.Host == "" || sd.foreDomain.Search(metadata.Host) != nil {
port, err := strconv.ParseUint(metadata.DstPort, 10, 16)
if err != nil {
log.Debugln("[Sniffer] Dst port is error")
return
}
2022-04-23 09:52:23 +08:00
inWhitelist := false
for _, portRange := range *sd.portRanges {
2022-04-23 09:52:23 +08:00
if portRange.Contains(uint16(port)) {
inWhitelist = true
2022-04-23 09:36:11 +08:00
break
}
}
2022-04-23 09:52:23 +08:00
if !inWhitelist {
return
}
if host, err := sd.sniffDomain(bufConn, metadata); err != nil {
log.Debugln("[Sniffer] All sniffing sniff failed with from [%s:%s] to [%s:%s]", metadata.SrcIP, metadata.SrcPort, metadata.String(), metadata.DstPort)
return
} else {
if sd.skipSNI.Search(host) != nil {
log.Debugln("[Sniffer] Skip sni[%s]", host)
return
}
sd.replaceDomain(metadata, host)
}
}
}
func (sd *SnifferDispatcher) replaceDomain(metadata *C.Metadata, host string) {
2022-04-16 09:04:43 +08:00
log.Debugln("[Sniffer] Sniff TCP [%s:%s]-->[%s:%s] success, replace domain [%s]-->[%s]",
metadata.SrcIP, metadata.SrcPort,
metadata.DstIP, metadata.DstPort,
metadata.Host, host)
metadata.AddrType = C.AtypDomainName
metadata.Host = host
2022-04-16 09:51:31 +08:00
metadata.DNSMode = C.DNSMapping
resolver.InsertHostByIP(metadata.DstIP, host)
2022-04-20 01:52:51 +08:00
metadata.DstIP = netip.Addr{}
}
func (sd *SnifferDispatcher) Enable() bool {
return sd.enable
}
func (sd *SnifferDispatcher) sniffDomain(conn *CN.BufferedConn, metadata *C.Metadata) (string, error) {
for _, sniffer := range sd.sniffers {
if sniffer.SupportNetwork() == C.TCP {
2022-04-21 23:08:37 +08:00
conn.SetReadDeadline(time.Now().Add(3 * time.Second))
2022-04-10 20:01:35 +08:00
_, err := conn.Peek(1)
2022-04-22 17:00:39 +08:00
conn.SetReadDeadline(time.Time{})
2022-04-10 20:01:35 +08:00
if err != nil {
2022-04-21 23:08:37 +08:00
_, ok := err.(*net.OpError)
if ok {
//log.Errorln("[Sniffer] [%s] Maybe read timeout, Consider adding skip", metadata.DstIP.String())
2022-04-21 23:08:37 +08:00
conn.Close()
}
//log.Errorln("[Sniffer] %v", err)
return "", err
2022-04-10 20:01:35 +08:00
}
bufferedLen := conn.Buffered()
bytes, err := conn.Peek(bufferedLen)
if err != nil {
//log.Debugln("[Sniffer] the data length not enough")
continue
}
host, err := sniffer.SniffTCP(bytes)
if err != nil {
2022-04-16 09:04:43 +08:00
log.Debugln("[Sniffer] [%s] Sniff data failed %s", sniffer.Protocol(), metadata.DstIP)
continue
}
2022-04-10 20:01:35 +08:00
return host, nil
}
}
return "", ErrorSniffFailed
}
func NewCloseSnifferDispatcher() (*SnifferDispatcher, error) {
dispatcher := SnifferDispatcher{
enable: false,
}
return &dispatcher, nil
}
func NewSnifferDispatcher(needSniffer []C.SnifferType, forceDomain *trie.DomainTrie[bool],
skipSNI *trie.DomainTrie[bool], ports *[]utils.Range[uint16]) (*SnifferDispatcher, error) {
dispatcher := SnifferDispatcher{
enable: true,
foreDomain: forceDomain,
skipSNI: skipSNI,
portRanges: ports,
}
for _, snifferName := range needSniffer {
sniffer, err := NewSniffer(snifferName)
if err != nil {
//log.Errorln("Sniffer name[%s] is error", snifferName)
return &SnifferDispatcher{enable: false}, err
}
dispatcher.sniffers = append(dispatcher.sniffers, sniffer)
}
return &dispatcher, nil
}
func NewSniffer(name C.SnifferType) (C.Sniffer, error) {
switch name {
case C.TLS:
return &TLSSniffer{}, nil
default:
return nil, ErrorUnsupportedSniffer
}
}