@@ -9,13 +9,15 @@ import (
99 "net"
1010 "os"
1111 "os/signal"
12- "strings "
12+ "runtime "
1313 "syscall"
1414 "time"
1515
16+ "github.com/cilium/ebpf"
17+ "github.com/cilium/ebpf/link"
18+ "github.com/cilium/ebpf/ringbuf"
1619 "github.com/evilsocket/opensnitch/daemon/core"
1720 "github.com/evilsocket/opensnitch/daemon/log"
18- bpf "github.com/iovisor/gobpf/elf"
1921)
2022
2123/*
@@ -49,6 +51,7 @@ char* find_libc() {
4951 break;
5052 }
5153
54+ //printf("map->l_name: %s\n", map->l_name);
5255 if(strstr(map->l_name, "libc.so")){
5356 fprintf(stderr,"found %s\n", map->l_name);
5457 return map->l_name;
@@ -57,8 +60,6 @@ char* find_libc() {
5760 }
5861 return NULL;
5962}
60-
61-
6263*/
6364import "C"
6465
@@ -68,6 +69,25 @@ type nameLookupEvent struct {
6869 Host [252 ]byte
6970}
7071
72+ // ProbeDefs holds the hooks defined in the module
73+ type ProbeDefs struct {
74+ URProbeGethostByname * ebpf.Program `ebpf:"uretprobe__gethostbyname"`
75+ UProbeGetAddrinfo * ebpf.Program `ebpf:"uprobe__getaddrinfo"`
76+ URProbeGetAddrinfo * ebpf.Program `ebpf:"uretprobe__getaddrinfo"`
77+ }
78+
79+ // MapDefs holds the maps defined in the module
80+ type MapDefs struct {
81+ // BPF_MAP_TYPE_RINGBUF
82+ PerfEvents * ebpf.Map `ebpf:"events"`
83+ }
84+
85+ // container of hooks and maps
86+ type dnsDefsT struct {
87+ ProbeDefs
88+ MapDefs
89+ }
90+
7191func findLibc () (string , error ) {
7292 ret := C .find_libc ()
7393
@@ -95,83 +115,120 @@ func lookupSymbol(elffile *elf.File, symbolName string) (uint64, error) {
95115
96116// ListenerEbpf starts listening for DNS events.
97117func ListenerEbpf (ebpfModPath string ) error {
118+ probesAttached := 0
98119 m , err := core .LoadEbpfModule ("opensnitch-dns.o" , ebpfModPath )
99120 if err != nil {
100- log .Warning ("[eBPF DNS]: %s" , err )
101121 return err
102122 }
103123 defer m .Close ()
104124
125+ ebpfMod := dnsDefsT {}
126+ if err := m .Assign (& ebpfMod ); err != nil {
127+ return err
128+ }
129+
130+ // --------------
131+
105132 // libbcc resolves the offsets for us. without bcc the offset for uprobes must parsed from the elf files
106133 // some how 0 must be replaced with the offset of getaddrinfo bcc does this using bcc_resolve_symname
107134
108135 // Attaching to uprobe using perf open might be a better aproach requires https://github.com/iovisor/gobpf/pull/277
109- libcFile , err := findLibc ()
110136
137+ libcFile , err := findLibc ()
111138 if err != nil {
112- log .Error ("[eBPF DNS]: Failed to find libc.so: %v" , err )
139+ log .Error ("[eBPF DNS] Failed to find libc.so: %v" , err )
113140 return err
114141 }
142+ ex , err := link .OpenExecutable (libcFile )
143+ if err != nil {
144+ return err
145+ }
146+
147+ // --------------
115148
116- libcElf , err := elf .Open (libcFile )
149+ // User space needs to call perf_event_open() (...) before eBPF program can send data into it.
150+ rd , err := ringbuf .NewReader (ebpfMod .PerfEvents )
117151 if err != nil {
118- log .Error ("[eBPF DNS]: Failed to open %s: %v" , libcFile , err )
119152 return err
120153 }
121- probesAttached := 0
122- for uprobe := range m .IterUprobes () {
123- probeFunction := strings .Replace (uprobe .Name , "uretprobe/" , "" , 1 )
124- probeFunction = strings .Replace (probeFunction , "uprobe/" , "" , 1 )
125- offset , err := lookupSymbol (libcElf , probeFunction )
126- if err != nil {
127- log .Warning ("[eBPF DNS]: Failed to find symbol for uprobe %s (offset: %d): %s\n " , uprobe .Name , offset , err )
128- continue
129- }
130- err = bpf .AttachUprobe (uprobe , libcFile , offset )
131- if err != nil {
132- log .Warning ("[eBPF DNS]: Failed to attach uprobe %s : %s, (%s, %d)\n " , uprobe .Name , err , libcFile , offset )
133- continue
134- }
135- probesAttached ++
154+ defer rd .Close ()
155+
156+ // --------------
157+
158+ urg , err := ex .Uretprobe ("gethostbyname" , ebpfMod .URProbeGethostByname , nil )
159+ if err != nil {
160+ log .Error ("[eBPF DNS] uretprobe__gethostbyname: %s" , err )
161+ }
162+ defer urg .Close ()
163+ probesAttached ++
164+
165+ up , err := ex .Uprobe ("getaddrinfo" , ebpfMod .UProbeGetAddrinfo , nil )
166+ if err != nil {
167+ log .Error ("[eBPF DNS] uprobe__getaddrinfo: %s" , err )
168+ }
169+ defer up .Close ()
170+ probesAttached ++
171+
172+ urp , err := ex .Uretprobe ("getaddrinfo" , ebpfMod .URProbeGetAddrinfo , nil )
173+ if err != nil {
174+ log .Error ("[eBPF-DNS] uretprobe__getaddrinfo: %s" , err )
136175 }
176+ defer urp .Close ()
177+ probesAttached ++
137178
138179 if probesAttached == 0 {
139180 log .Warning ("[eBPF DNS]: Failed to find symbols for uprobes." )
140181 return errors .New ("Failed to find symbols for uprobes" )
141182 }
142183
143- // Reading Events
144- channel := make ( chan [] byte )
145- //log.Warning("EBPF-DNS: %+v\n", m )
146- perfMap , err := bpf . InitPerfMap ( m , "events" , channel , nil )
147- if err != nil {
148- log . Error ( "[eBPF DNS]: Failed to init perf map: %s \n " , err )
149- return err
184+ // --------------
185+
186+ exitChannel := make ( chan struct {} )
187+ perfChan := make ( chan [] byte , 0 )
188+
189+ for i := 0 ; i < runtime . NumCPU (); i ++ {
190+ go spawnDNSWorker ( i , perfChan , exitChannel )
150191 }
192+
193+ go func (perfChan chan []byte , rd * ringbuf.Reader ) {
194+ for {
195+ select {
196+ case <- exitChannel :
197+ goto Exit
198+ default :
199+ record , err := rd .Read ()
200+ if err != nil {
201+ if errors .Is (err , ringbuf .ErrClosed ) {
202+ goto Exit
203+ }
204+ log .Debug ("[eBPF DNS] reader error: %s" , err )
205+ continue
206+ }
207+ perfChan <- record .RawSample
208+ }
209+ }
210+ Exit:
211+ log .Debug ("[eBPF DNS] reader closed" )
212+ }(perfChan , rd )
213+
151214 sig := make (chan os.Signal , 1 )
152- exitChannel := make (chan bool )
153215 signal .Notify (sig ,
154216 syscall .SIGHUP ,
155217 syscall .SIGINT ,
156218 syscall .SIGTERM ,
157219 syscall .SIGKILL ,
158220 syscall .SIGQUIT )
159221
160- for i := 0 ; i < 5 ; i ++ {
161- go spawnDNSWorker (i , channel , exitChannel )
162- }
163-
164- perfMap .PollStart ()
165222 <- sig
166223 log .Info ("[eBPF DNS]: Received signal: terminating ebpf dns hook." )
167- perfMap . PollStop ()
168- for i := 0 ; i < 5 ; i ++ {
169- exitChannel <- true
224+ exitChannel <- struct {}{}
225+ for i := 0 ; i < runtime . NumCPU () ; i ++ {
226+ exitChannel <- struct {}{}
170227 }
171228 return nil
172229}
173230
174- func spawnDNSWorker (id int , channel chan []byte , exitChannel chan bool ) {
231+ func spawnDNSWorker (id int , channel chan []byte , exitChannel chan struct {} ) {
175232
176233 log .Debug ("[eBPF DNS] worker initialized #%d" , id )
177234 var event nameLookupEvent
0 commit comments