Skip to content

Commit 33c93d8

Browse files
authored
Open separate captures for each interface and add timeout for opening captures (#188)
1 parent 8b1ae60 commit 33c93d8

File tree

2 files changed

+74
-7
lines changed

2 files changed

+74
-7
lines changed

Diff for: .github/workflows/golangci-lint.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
steps:
1919
- uses: actions/setup-go@v3
2020
with:
21-
go-version: '1.21'
21+
go-version: '1.21.3'
2222
- uses: actions/checkout@v3
2323
- name: Install dependencies
2424
run: sudo apt update && sudo apt install libpcap-dev # required for the linter to be able to lint github.com/google/gopacket

Diff for: src/sniffer/pkg/collectors/dnssniffer.go

+73-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package collectors
22

33
import (
4+
"context"
45
"github.com/google/gopacket"
56
"github.com/google/gopacket/layers"
67
"github.com/google/gopacket/pcap"
@@ -9,6 +10,8 @@ import (
910
"github.com/otterize/network-mapper/src/sniffer/pkg/ipresolver"
1011
"github.com/sirupsen/logrus"
1112
"github.com/spf13/viper"
13+
"net"
14+
"sync"
1215
"time"
1316
)
1417

@@ -39,18 +42,82 @@ func NewDNSSniffer(resolver ipresolver.IPResolver) *DNSSniffer {
3942
return &s
4043
}
4144

42-
func (s *DNSSniffer) CreateDNSPacketStream() (chan gopacket.Packet, error) {
43-
handle, err := pcap.OpenLive("any", 0, true, pcap.BlockForever)
45+
type PacketChannelCombiner struct {
46+
Channels []chan gopacket.Packet
47+
combined chan gopacket.Packet
48+
combinedOnce sync.Once
49+
}
50+
51+
func NewPacketChannelCombiner(channels []chan gopacket.Packet) *PacketChannelCombiner {
52+
return &PacketChannelCombiner{
53+
Channels: channels,
54+
}
55+
}
56+
57+
func (p *PacketChannelCombiner) Packets() chan gopacket.Packet {
58+
p.combinedOnce.Do(func() {
59+
p.combined = make(chan gopacket.Packet)
60+
for _, c := range p.Channels {
61+
go func(channel chan gopacket.Packet) {
62+
for packet := range channel {
63+
p.combined <- packet
64+
}
65+
}(c)
66+
}
67+
})
68+
return p.combined
69+
}
70+
71+
func (s *DNSSniffer) CreatePacketChannelForInterface(iface net.Interface) (result chan gopacket.Packet, err error) {
72+
doneCtx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
73+
defer cancel()
74+
go func() {
75+
defer cancel()
76+
handle, openLiveErr := pcap.OpenLive(iface.Name, 0, true, pcap.BlockForever)
77+
if openLiveErr != nil {
78+
err = errors.Wrap(openLiveErr)
79+
return
80+
}
81+
bpfErr := handle.SetBPFFilter("udp port 53")
82+
if bpfErr != nil {
83+
err = errors.Wrap(bpfErr)
84+
return
85+
}
86+
87+
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
88+
result = packetSource.Packets()
89+
return
90+
}()
91+
<-doneCtx.Done()
92+
if errors.Is(doneCtx.Err(), context.DeadlineExceeded) {
93+
return nil, errors.Errorf("timed out starting capture on interface '%s': %w", iface.Name, doneCtx.Err())
94+
}
4495
if err != nil {
45-
return nil, errors.Wrap(err)
96+
return nil, errors.Errorf("failed to start capture on interface '%s': %w", iface.Name, err)
4697
}
47-
err = handle.SetBPFFilter("udp port 53")
98+
return result, nil
99+
}
100+
101+
func (s *DNSSniffer) CreateDNSPacketStream() (chan gopacket.Packet, error) {
102+
interfaceList, err := net.Interfaces()
48103
if err != nil {
49104
return nil, errors.Wrap(err)
50105
}
51106

52-
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
53-
return packetSource.Packets(), nil
107+
packetChans := make([]chan gopacket.Packet, 0)
108+
for _, iface := range interfaceList {
109+
logrus.Debugf("Starting capture on interface '%s'", iface.Name)
110+
packetChannel, err := s.CreatePacketChannelForInterface(iface)
111+
if err != nil {
112+
logrus.WithError(err).Errorf("failed to open packet channel for interface '%s', skipping", iface.Name)
113+
continue
114+
}
115+
packetChans = append(packetChans, packetChannel)
116+
}
117+
if len(packetChans) == 0 {
118+
return nil, errors.New("no captures opened successfully")
119+
}
120+
return NewPacketChannelCombiner(packetChans).Packets(), nil
54121
}
55122

56123
func (s *DNSSniffer) HandlePacket(packet gopacket.Packet) {

0 commit comments

Comments
 (0)