mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-04 02:30:45 +00:00
Merge pull request #2162 from weaveworks/2155-dot1q-decoding-and-rl
DNSSnooper: Support Dot1Q and limit decoding errors
This commit is contained in:
@@ -15,15 +15,18 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
bufSize = 8 * 1024 * 1024 // 8MB
|
||||
maxReverseDNSrecords = 10000
|
||||
bufSize = 8 * 1024 * 1024 // 8MB
|
||||
maxReverseDNSrecords = 10000
|
||||
maxLogsPerDecodingError = 4
|
||||
maxDecodingErrorCardinality = 1000
|
||||
)
|
||||
|
||||
// DNSSnooper is a snopper of DNS queries
|
||||
type DNSSnooper struct {
|
||||
stop chan struct{}
|
||||
pcapHandle *pcap.Handle
|
||||
reverseDNSCache gcache.Cache
|
||||
stop chan struct{}
|
||||
pcapHandle *pcap.Handle
|
||||
reverseDNSCache gcache.Cache
|
||||
decodingErrorCounts map[string]uint64 // for limiting
|
||||
}
|
||||
|
||||
// NewDNSSnooper creates a new snooper of DNS queries
|
||||
@@ -35,9 +38,10 @@ func NewDNSSnooper() (*DNSSnooper, error) {
|
||||
reverseDNSCache := gcache.New(maxReverseDNSrecords).LRU().Build()
|
||||
|
||||
s := &DNSSnooper{
|
||||
stop: make(chan struct{}),
|
||||
pcapHandle: pcapHandle,
|
||||
reverseDNSCache: reverseDNSCache,
|
||||
stop: make(chan struct{}),
|
||||
pcapHandle: pcapHandle,
|
||||
reverseDNSCache: reverseDNSCache,
|
||||
decodingErrorCounts: map[string]uint64{},
|
||||
}
|
||||
go s.run()
|
||||
return s, nil
|
||||
@@ -163,11 +167,12 @@ func (s *DNSSnooper) run() {
|
||||
ip4 layers.IPv4
|
||||
ip6 layers.IPv6
|
||||
eth layers.Ethernet
|
||||
dot1q layers.Dot1Q
|
||||
sll layers.LinuxSLL
|
||||
)
|
||||
|
||||
// assumes that the "any" interface is being used (see https://wiki.wireshark.org/SLL)
|
||||
packetParser := gopacket.NewDecodingLayerParser(layers.LayerTypeLinuxSLL, &sll, ð, &ip4, &ip6, &udp, &tcp, &dns)
|
||||
packetParser := gopacket.NewDecodingLayerParser(layers.LayerTypeLinuxSLL, &sll, &dot1q, ð, &ip4, &ip6, &udp, &tcp, &dns)
|
||||
|
||||
for {
|
||||
select {
|
||||
@@ -190,7 +195,7 @@ func (s *DNSSnooper) run() {
|
||||
if err := packetParser.DecodeLayers(packet, &decodedLayers); err != nil {
|
||||
// LayerTypePayload indicates the TCP payload has non-DNS data, which we are not interested in
|
||||
if layer, ok := err.(gopacket.UnsupportedLayerType); !ok || gopacket.LayerType(layer) != gopacket.LayerTypePayload {
|
||||
log.Errorf("DNSSnooper: error decoding packet: %s", err)
|
||||
s.handleDecodingError(err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
@@ -203,6 +208,25 @@ func (s *DNSSnooper) run() {
|
||||
}
|
||||
}
|
||||
|
||||
// handleDecodeError logs errors up to the maximum allowed count
|
||||
func (s *DNSSnooper) handleDecodingError(err error) {
|
||||
// prevent potential memory leak
|
||||
if len(s.decodingErrorCounts) > maxDecodingErrorCardinality {
|
||||
return
|
||||
}
|
||||
|
||||
str := err.Error()
|
||||
count := s.decodingErrorCounts[str]
|
||||
count++
|
||||
s.decodingErrorCounts[str] = count
|
||||
switch {
|
||||
case count == maxLogsPerDecodingError:
|
||||
log.Errorf("DNSSnooper: error decoding packet: %s (reached %d occurrences, silencing)", str, maxLogsPerDecodingError)
|
||||
case count < maxLogsPerDecodingError:
|
||||
log.Errorf("DNSSnooper: error decoding packet: %s", str)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DNSSnooper) processDNSMessage(dns *layers.DNS) {
|
||||
|
||||
// Only consider responses to singleton, A-record questions
|
||||
|
||||
Reference in New Issue
Block a user