99 "net"
1010 "os"
1111 "os/signal"
12- "runtime"
1312 "syscall"
14- "time"
1513
1614 "github.com/cilium/ebpf"
1715 "github.com/cilium/ebpf/link"
@@ -116,6 +114,7 @@ func lookupSymbol(elffile *elf.File, symbolName string) (uint64, error) {
116114// ListenerEbpf starts listening for DNS events.
117115func ListenerEbpf (ebpfModPath string ) error {
118116 probesAttached := 0
117+ probesList := []link.Link {}
119118 m , err := core .LoadEbpfModule ("opensnitch-dns.o" , ebpfModPath )
120119 if err != nil {
121120 return err
@@ -159,23 +158,23 @@ func ListenerEbpf(ebpfModPath string) error {
159158 if err != nil {
160159 log .Error ("[eBPF DNS] uretprobe__gethostbyname: %s" , err )
161160 } else {
162- defer urg . Close ( )
161+ probesList = append ( probesList , urg )
163162 probesAttached ++
164163 }
165164
166165 up , err := ex .Uprobe ("getaddrinfo" , ebpfMod .UProbeGetAddrinfo , nil )
167166 if err != nil {
168167 log .Error ("[eBPF DNS] uprobe__getaddrinfo: %s" , err )
169168 } else {
170- defer up . Close ( )
169+ probesList = append ( probesList , up )
171170 probesAttached ++
172171 }
173172
174173 urp , err := ex .Uretprobe ("getaddrinfo" , ebpfMod .URProbeGetAddrinfo , nil )
175174 if err != nil {
176175 log .Error ("[eBPF-DNS] uretprobe__getaddrinfo: %s" , err )
177176 } else {
178- defer urp . Close ( )
177+ probesList = append ( probesList , urp )
179178 probesAttached ++
180179 }
181180
@@ -187,13 +186,27 @@ func ListenerEbpf(ebpfModPath string) error {
187186 // --------------
188187
189188 exitChannel := make (chan struct {})
190- perfChan := make (chan []byte , 0 )
191189
192- for i := 0 ; i < runtime .NumCPU (); i ++ {
193- go spawnDNSWorker (i , perfChan , exitChannel )
190+ // TODO: make these options configurable
191+
192+ // 30 is the maximum amount of IPs sent from kernel to user-space.
193+ // Defined in opensnitch-dns.c.
194+ perfChan := make (chan []byte , 30 )
195+ for i := 0 ; i < 4 ; i ++ {
196+ go dnsWorker (i , perfChan , exitChannel )
194197 }
195198
196199 go func (perfChan chan []byte , rd * ringbuf.Reader ) {
200+ drainPerfChan := func () {
201+ for {
202+ select {
203+ case <- perfChan :
204+ default :
205+ return
206+ }
207+ }
208+ }
209+
197210 for {
198211 select {
199212 case <- exitChannel :
@@ -207,7 +220,12 @@ func ListenerEbpf(ebpfModPath string) error {
207220 log .Debug ("[eBPF DNS] reader error: %s" , err )
208221 continue
209222 }
210- perfChan <- record .RawSample
223+ select {
224+ case perfChan <- record .RawSample :
225+ default :
226+ log .Debug ("[eBPF DNS] events queue full, emptying queue (if you see this error too often, report it to the developers)." )
227+ drainPerfChan ()
228+ }
211229 }
212230 }
213231 Exit:
@@ -224,27 +242,28 @@ func ListenerEbpf(ebpfModPath string) error {
224242
225243 <- sig
226244 log .Info ("[eBPF DNS]: Received signal: terminating ebpf dns hook." )
227- exitChannel <- struct {}{}
228- for i := 0 ; i < runtime .NumCPU (); i ++ {
245+ for _ , p := range probesList {
246+ p .Close ()
247+ }
248+ for i := 0 ; i < 4 ; i ++ {
229249 exitChannel <- struct {}{}
230250 }
231251 return nil
232252}
233253
234- func spawnDNSWorker (id int , channel chan []byte , exitChannel chan struct {}) {
254+ func dnsWorker (id int , channel chan []byte , exitChannel chan struct {}) {
235255
236256 log .Debug ("[eBPF DNS] worker initialized #%d" , id )
237257 var event nameLookupEvent
238258 var ip net.IP
239- for {
240- select {
241259
242- case <- time . After ( 1 * time . Millisecond ):
243- continue
260+ for data := range channel {
261+ select {
244262 case <- exitChannel :
245263 goto Exit
264+ // case data := <-channel:
246265 default :
247- data := <- channel
266+ event = nameLookupEvent {}
248267 if len (data ) > 0 {
249268 log .Trace ("(%d) [eBPF DNS]: LookupEvent %d %x %x %x" , id , len (data ), data [:4 ], data [4 :20 ], data [20 :])
250269 }
0 commit comments