-
-
Notifications
You must be signed in to change notification settings - Fork 476
Expand file tree
/
Copy pathmonitor.c
More file actions
198 lines (166 loc) Β· 5.64 KB
/
monitor.c
File metadata and controls
198 lines (166 loc) Β· 5.64 KB
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#include "vmlinux-x86.h"
#include "bpf/bpf_helpers.h"
#include "bpf/bpf_tracing.h"
// IP Version
#define AF_INET 2
#define AF_INET6 10
// Protocols
#define TCP 6
#define UDP 17
#define UDPLite 136
#define OUTBOUND 0
#define INBOUND 1
char __license[] SEC("license") = "GPL";
// Ring buffer for all connection events
struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 1 << 24);
} pm_connection_events SEC(".maps");
// Event struct that will be sent to Go on each new connection. (The name should be the same as the go generate command)
struct Event {
u32 saddr[4];
u32 daddr[4];
u16 sport;
u16 dport;
u32 pid;
u8 ipVersion;
u8 protocol;
u8 direction;
};
struct Event *unused __attribute__((unused));
// Fentry of tcp_connect will be executed when equivalent kernel function is called.
// In the kernel all IP address and ports should be set before tcp_connect is called. [this-function] -> tcp_connect
SEC("fentry/tcp_connect")
int BPF_PROG(tcp_connect, struct sock *sk) {
// Alloc space for the event
struct Event *tcp_info;
tcp_info = bpf_ringbuf_reserve(&pm_connection_events, sizeof(struct Event), 0);
if (!tcp_info) {
return 0;
}
// Read PID (Careful: This is the Thread Group ID in kernel speak!)
tcp_info->pid = __builtin_bswap32((u32)(bpf_get_current_pid_tgid() >> 32));
// Set protocol
tcp_info->protocol = TCP;
// Set direction
tcp_info->direction = OUTBOUND;
// Set src and dist ports
tcp_info->sport = __builtin_bswap16(sk->__sk_common.skc_num);
tcp_info->dport = sk->__sk_common.skc_dport;
// Set src and dist IPs
if (sk->__sk_common.skc_family == AF_INET) {
tcp_info->saddr[0] = __builtin_bswap32(sk->__sk_common.skc_rcv_saddr);
tcp_info->daddr[0] = __builtin_bswap32(sk->__sk_common.skc_daddr);
// Set IP version
tcp_info->ipVersion = 4;
} else if (sk->__sk_common.skc_family == AF_INET6) {
for(int i = 0; i < 4; i++) {
tcp_info->saddr[i] = __builtin_bswap32(sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32[i]);
}
for(int i = 0; i < 4; i++) {
tcp_info->daddr[i] = __builtin_bswap32(sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32[i]);
}
// Set IP version
tcp_info->ipVersion = 6;
}
// Send event
bpf_ringbuf_submit(tcp_info, 0);
return 0;
};
// Fexit(function exit) of `udp_v4_connect` will be executed after the `udp_connect` kernel function is called.
//
// Kernel compatibility note:
// - Linux kernels < 6.13: use `ip4_datagram_connect` function
// https://elixir.bootlin.com/linux/v6.12.34/source/net/ipv4/udp.c#L2997
// - Linux kernels >= 6.13: function renamed to `udp_connect`
// https://elixir.bootlin.com/linux/v6.13-rc1/source/net/ipv4/udp.c#L3131
//
SEC("fexit/udp_connect") // Note: This attach point name may be overwritten (see worker.go: modifyProgramsAttachPoints())
int BPF_PROG(udp_v4_connect, struct sock *sk) {
// Ignore everything else then IPv4
if (sk->__sk_common.skc_family != AF_INET) {
return 0;
}
// ip4_datagram_connect return error
if (sk->__sk_common.skc_dport == 0) {
return 0;
}
// Allocate space for the event.
struct Event *udp_info;
udp_info = bpf_ringbuf_reserve(&pm_connection_events, sizeof(struct Event), 0);
if (!udp_info) {
return 0;
}
// Read PID (Careful: This is the Thread Group ID in kernel speak!)
udp_info->pid = __builtin_bswap32((u32)(bpf_get_current_pid_tgid() >> 32));
// Set src and dst ports
udp_info->sport = __builtin_bswap16(sk->__sk_common.skc_num);
udp_info->dport = sk->__sk_common.skc_dport;
// Set src and dst IPs
udp_info->saddr[0] = __builtin_bswap32(sk->__sk_common.skc_rcv_saddr);
udp_info->daddr[0] = __builtin_bswap32(sk->__sk_common.skc_daddr);
// Set IP version
udp_info->ipVersion = 4;
// Set protocol
if(sk->sk_protocol == IPPROTO_UDPLITE) {
udp_info->protocol = UDPLite;
} else {
udp_info->protocol = UDP;
}
// Send event
bpf_ringbuf_submit(udp_info, 0);
return 0;
}
// Fentry(function enter) of `udp_v6_connect` will be executed after the `udpv6_connect` kernel function is called.
//
// Kernel compatibility note:
// - Linux kernels < 6.13: use `ip6_datagram_connect` function
// https://elixir.bootlin.com/linux/v6.12.34/source/net/ipv4/udp.c#L2997
// - Linux kernels >= 6.13: function renamed to `udpv6_connect`
// https://elixir.bootlin.com/linux/v6.13-rc1/source/net/ipv4/udp.c#L3131
//
SEC("fexit/udpv6_connect") // Note: This attach point name may be overwritten (see worker.go: modifyProgramsAttachPoints())
int BPF_PROG(udp_v6_connect, struct sock *sk) {
// Ignore everything else then IPv6
if (sk->__sk_common.skc_family != AF_INET6) {
return 0;
}
// ip6_datagram_connect return error
if (sk->__sk_common.skc_dport == 0) {
return 0;
}
// Make sure its udp6 socket
struct udp6_sock *us = bpf_skc_to_udp6_sock(sk);
if (!us) {
return 0;
}
// Allocate space for the event.
struct Event *udp_info;
udp_info = bpf_ringbuf_reserve(&pm_connection_events, sizeof(struct Event), 0);
if (!udp_info) {
return 0;
}
// Read PID (Careful: This is the Thread Group ID in kernel speak!)
udp_info->pid = __builtin_bswap32((u32)(bpf_get_current_pid_tgid() >> 32));
// Set src and dst ports
udp_info->sport = __builtin_bswap16(sk->__sk_common.skc_num);
udp_info->dport = sk->__sk_common.skc_dport;
// Set src and dst IPs
for(int i = 0; i < 4; i++) {
udp_info->saddr[i] = __builtin_bswap32(sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32[i]);
}
for(int i = 0; i < 4; i++) {
udp_info->daddr[i] = __builtin_bswap32(sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32[i]);
}
// IP version
udp_info->ipVersion = 6;
// Set protocol
if(sk->sk_protocol == IPPROTO_UDPLITE) {
udp_info->protocol = UDPLite;
} else {
udp_info->protocol = UDP;
}
// Send event
bpf_ringbuf_submit(udp_info, 0);
return 0;
}