mihomo/component/sniffer/dispatcher.go
Skyxim 544e0f137d feat: sniffer support
sniffer:
  enable: true
  force: false # Overwrite domain
  sniffing:
    - tls
2022-04-09 22:30:36 +08:00

104 lines
2.1 KiB
Go

package sniffer
import (
"errors"
"net"
CN "github.com/Dreamacro/clash/common/net"
"github.com/Dreamacro/clash/component/resolver"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
)
var (
ErrorUnsupportedSniffer = errors.New("unsupported sniffer")
)
var Dispatcher SnifferDispatcher
type SnifferDispatcher struct {
enable bool
force bool
sniffers []C.Sniffer
}
func (sd *SnifferDispatcher) Tcp(conn net.Conn, metadata *C.Metadata) {
bufConn, ok := conn.(*CN.BufferedConn)
if !ok {
return
}
if sd.force {
sd.cover(bufConn, metadata)
} else {
if metadata.Host != "" {
return
}
sd.cover(bufConn, metadata)
}
}
func (sd *SnifferDispatcher) Enable() bool {
return sd.enable
}
func (sd *SnifferDispatcher) cover(conn *CN.BufferedConn, metadata *C.Metadata) {
for _, sniffer := range sd.sniffers {
if sniffer.SupportNetwork() == C.TCP {
conn.Peek(1)
len := conn.Buffered()
bytes, err := conn.Peek(len)
if err != nil {
log.Warnln("the data lenght not enough")
continue
}
host, err := sniffer.SniffTCP(bytes)
if err != nil {
log.Warnln("Sniff data failed on Sniffer[%s]", sniffer.Protocol())
continue
}
metadata.Host = host
metadata.DstIP = nil
metadata.AddrType = C.AtypDomainName
if resolver.FakeIPEnabled() {
metadata.DNSMode = C.DNSFakeIP
} else {
metadata.DNSMode = C.DNSMapping
}
resolver.InsertHostByIP(metadata.DstIP, host)
break
}
}
}
func NewSnifferDispatcher(needSniffer []C.SnifferType, force bool) (SnifferDispatcher, error) {
dispatcher := SnifferDispatcher{
enable: true,
force: force,
}
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
}
}