feat: recovering preHandleMetadata failure from sniffing (#769)

This commit is contained in:
Kiva 2023-09-24 19:27:55 +08:00 committed by GitHub
parent e6366f7442
commit 67d7e53f7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 11 deletions

View file

@ -35,7 +35,8 @@ type SnifferDispatcher struct {
parsePureIp bool parsePureIp bool
} }
func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata) { // TCPSniff returns true if the connection is sniffed to have a domain
func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata) bool {
if (metadata.Host == "" && sd.parsePureIp) || sd.forceDomain.Has(metadata.Host) || (metadata.DNSMode == C.DNSMapping && sd.forceDnsMapping) { if (metadata.Host == "" && sd.parsePureIp) || sd.forceDomain.Has(metadata.Host) || (metadata.DNSMode == C.DNSMapping && sd.forceDnsMapping) {
inWhitelist := false inWhitelist := false
overrideDest := false overrideDest := false
@ -50,7 +51,7 @@ func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata
} }
if !inWhitelist { if !inWhitelist {
return return false
} }
sd.rwMux.RLock() sd.rwMux.RLock()
@ -58,18 +59,18 @@ func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata
if count, ok := sd.skipList.Get(dst); ok && count > 5 { if count, ok := sd.skipList.Get(dst); ok && count > 5 {
log.Debugln("[Sniffer] Skip sniffing[%s] due to multiple failures", dst) log.Debugln("[Sniffer] Skip sniffing[%s] due to multiple failures", dst)
defer sd.rwMux.RUnlock() defer sd.rwMux.RUnlock()
return return false
} }
sd.rwMux.RUnlock() sd.rwMux.RUnlock()
if host, err := sd.sniffDomain(conn, metadata); err != nil { if host, err := sd.sniffDomain(conn, metadata); err != nil {
sd.cacheSniffFailed(metadata) sd.cacheSniffFailed(metadata)
log.Debugln("[Sniffer] All sniffing sniff failed with from [%s:%d] to [%s:%d]", metadata.SrcIP, metadata.SrcPort, metadata.String(), metadata.DstPort) log.Debugln("[Sniffer] All sniffing sniff failed with from [%s:%d] to [%s:%d]", metadata.SrcIP, metadata.SrcPort, metadata.String(), metadata.DstPort)
return return false
} else { } else {
if sd.skipSNI.Has(host) { if sd.skipSNI.Has(host) {
log.Debugln("[Sniffer] Skip sni[%s]", host) log.Debugln("[Sniffer] Skip sni[%s]", host)
return return false
} }
sd.rwMux.RLock() sd.rwMux.RLock()
@ -77,20 +78,23 @@ func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata
sd.rwMux.RUnlock() sd.rwMux.RUnlock()
sd.replaceDomain(metadata, host, overrideDest) sd.replaceDomain(metadata, host, overrideDest)
return true
} }
} }
return false
} }
func (sd *SnifferDispatcher) replaceDomain(metadata *C.Metadata, host string, overrideDest bool) { func (sd *SnifferDispatcher) replaceDomain(metadata *C.Metadata, host string, overrideDest bool) {
// show log early, since the following code may mutate `metadata.Host`
log.Debugln("[Sniffer] Sniff TCP [%s]-->[%s] success, replace domain [%s]-->[%s]",
metadata.SourceDetail(),
metadata.RemoteAddress(),
metadata.Host, host)
metadata.SniffHost = host metadata.SniffHost = host
if overrideDest { if overrideDest {
metadata.Host = host metadata.Host = host
} }
metadata.DNSMode = C.DNSNormal metadata.DNSMode = C.DNSNormal
log.Debugln("[Sniffer] Sniff TCP [%s]-->[%s] success, replace domain [%s]-->[%s]",
metadata.SourceDetail(),
metadata.RemoteAddress(),
metadata.Host, host)
} }
func (sd *SnifferDispatcher) Enable() bool { func (sd *SnifferDispatcher) Enable() bool {

View file

@ -419,15 +419,28 @@ func handleTCPConn(connCtx C.ConnContext) {
return return
} }
preHandleFailed := false
if err := preHandleMetadata(metadata); err != nil { if err := preHandleMetadata(metadata); err != nil {
log.Debugln("[Metadata PreHandle] error: %s", err) log.Debugln("[Metadata PreHandle] error: %s", err)
return preHandleFailed = true
} }
conn := connCtx.Conn() conn := connCtx.Conn()
conn.ResetPeeked() // reset before sniffer conn.ResetPeeked() // reset before sniffer
if sniffer.Dispatcher.Enable() && sniffingEnable { if sniffer.Dispatcher.Enable() && sniffingEnable {
sniffer.Dispatcher.TCPSniff(conn, metadata) // Try to sniff a domain when `preHandleMetadata` failed, this is usually
// caused by a "Fake DNS record missing" error when enhanced-mode is fake-ip.
if sniffer.Dispatcher.TCPSniff(conn, metadata) {
// we now have a domain name
preHandleFailed = false
}
}
// If both trials have failed, we can do nothing but give up
if preHandleFailed {
log.Debugln("[Metadata PreHandle] failed to sniff a domain for connection %s --> %s, give up",
metadata.SourceDetail(), metadata.RemoteAddress())
return
} }
peekMutex := sync.Mutex{} peekMutex := sync.Mutex{}