-
Notifications
You must be signed in to change notification settings - Fork 0
/
ebpf.go
137 lines (121 loc) · 2.75 KB
/
ebpf.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package main
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"log"
"net"
"time"
"github.com/cilium/ebpf/link"
"github.com/cilium/ebpf/ringbuf"
"github.com/cilium/ebpf/rlimit"
)
type connKey struct {
Saddr uint32
Dport uint16
Daddr uint32
}
type connData struct {
created time.Time
bpfEvent
}
var openConnections = make(map[connKey]connData)
var rbReader *ringbuf.Reader
var event bpfEvent
var objs bpfObjects
var ltcpSetState link.Link
func StopEBPF() {
if err := rbReader.Close(); err != nil {
log.Fatalf("closing ringbuf reader: %s", err)
}
objs.TcpSetState.Unpin()
objs.Events.Unpin()
ltcpSetState.Unpin()
objs.Close()
ltcpSetState.Close()
}
func InitEBPF() {
// Allow the current process to lock memory for eBPF resources.
if err := rlimit.RemoveMemlock(); err != nil {
log.Fatal(err)
}
// Load pre-compiled programs and maps into the kernel.
objs = bpfObjects{}
if err := loadBpfObjects(&objs, nil); err != nil {
log.Fatalf("loading objects: %v", err)
}
var err error
ltcpSetState, err = link.AttachTracing(link.TracingOptions{
Program: objs.TcpSetState,
})
if err != nil {
log.Fatal(err)
}
rbReader, err = ringbuf.NewReader(objs.Events)
if err != nil {
log.Fatalf("opening ringbuf reader: %s", err)
}
go startEBPFLoop()
}
func startEBPFLoop() {
var localhost = uint32(2130706433)
for {
record, err := rbReader.Read()
if err != nil {
if errors.Is(err, ringbuf.ErrClosed) {
log.Println("received signal, exiting..")
return
}
log.Printf("reading from reader: %s", err)
continue
}
// Parse the ringbuf event entry into a bpfEvent structure.
if err := binary.Read(bytes.NewBuffer(record.RawSample), binary.BigEndian, &event); err != nil {
log.Printf("parsing ringbuf event: %s", err)
continue
}
if (event.Saddr == localhost && event.Daddr == localhost) ||
event.Sport == 0 {
continue
}
// fmt.Printf("%-18s %-15s %-6d -> %-15s %-6d %-5d\n",
// B2S(event.Comm),
// intToIP(event.Saddr),
// event.Sport,
// intToIP(event.Daddr),
// event.Dport,
// event.State,
// )
switch event.State {
case TCP_ESTABLISHED:
openConnections[connKey{
Saddr: event.Saddr,
Daddr: event.Daddr,
Dport: event.Dport,
}] = connData{bpfEvent: event, created: time.Now()}
case TCP_CLOSE:
delete(openConnections, connKey{
Dport: event.Dport,
Saddr: event.Saddr,
Daddr: event.Daddr,
})
default:
fmt.Printf("Unhandled state %d", event.State)
}
}
}
// intToIP converts IPv4 number to net.IP
func intToIP(ipNum uint32) net.IP {
ip := make(net.IP, 4)
binary.BigEndian.PutUint32(ip, ipNum)
return ip
}
func B2S(bs [16]uint8) string {
b := make([]byte, len(bs))
for i, v := range bs {
b[i] = byte(v)
}
b = bytes.Trim(b, "\x00")
return string(b)
}