Skip to content

Commit 2136510

Browse files
committed
Adding IPSec ebpf tracker
Signed-off-by: Mohamed Mahmoud <[email protected]>
1 parent 4c81c73 commit 2136510

15 files changed

+322
-6
lines changed

.mk/bc.mk

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ define PROGRAMS
1818
"tcp_rcv_kprobe":"kprobe",
1919
"kfree_skb":"tracepoint",
2020
"network_events_monitoring":"kprobe",
21-
"track_nat_manip_pkt":"kprobe"
21+
"track_nat_manip_pkt":"kprobe",
22+
"xfrm_input_kprobe": "kprobe",
23+
"xfrm_input_kretprobe": "kretprobe",
24+
"xfrm_output_kprobe": "kprobe",
25+
"xfrm_output_kretprobe": "kretprobe"
2226
}
2327
endef
2428

@@ -32,7 +36,9 @@ define MAPS
3236
"dns_flows":"hash",
3337
"global_counters":"per_cpu_array",
3438
"filter_map":"lpm_trie",
35-
"peer_filter_map":"lpm_trie"
39+
"peer_filter_map":"lpm_trie",
40+
"ipsec_ingress_map":"hash",
41+
"ipsec_egress_map":"hash"
3642
}
3743
endef
3844

bpf/configs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ volatile const u16 dns_port = 0;
1414
volatile const u8 enable_network_events_monitoring = 0;
1515
volatile const u8 network_events_monitoring_groupid = 0;
1616
volatile const u8 enable_pkt_translation_tracking = 0;
17+
volatile const u8 enable_ipsec = 0;
1718
#endif //__CONFIGS_H__

bpf/flows.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@
5252
*/
5353
#include "pkt_translation.h"
5454

55+
/*
56+
* Defines ipsec tracker
57+
*/
58+
#include "ipsec.h"
59+
5560
// return 0 on success, 1 if capacity reached
5661
static __always_inline int add_observed_intf(flow_metrics *value, pkt_info *pkt, u32 if_index,
5762
u8 direction) {

bpf/ipsec.h

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
/*
2+
* IPsec monitoring kretprobe eBPF hook.
3+
*/
4+
5+
#ifndef __IPSEC_H__
6+
#define __IPSEC_H__
7+
8+
#include "utils.h"
9+
10+
static inline int ipsec_lookup_and_update_flow(flow_id *id, int flow_encrypted_ret,
11+
u16 eth_protocol) {
12+
additional_metrics *extra_metrics = bpf_map_lookup_elem(&additional_flow_metrics, id);
13+
if (extra_metrics != NULL) {
14+
extra_metrics->end_mono_time_ts = bpf_ktime_get_ns();
15+
extra_metrics->eth_protocol = eth_protocol;
16+
extra_metrics->flow_encrypted_ret = flow_encrypted_ret;
17+
extra_metrics->flow_encrypted = flow_encrypted_ret == 0 ? true : false;
18+
return 0;
19+
}
20+
return -1;
21+
}
22+
23+
static inline int update_flow_with_ipsec_return(int flow_encrypted_ret, direction dir) {
24+
u64 pid_tgid = bpf_get_current_pid_tgid();
25+
u16 eth_protocol = 0;
26+
flow_id *id = NULL;
27+
int ret = 0;
28+
29+
if (dir == INGRESS) {
30+
id = bpf_map_lookup_elem(&ipsec_ingress_map, &pid_tgid);
31+
} else {
32+
id = bpf_map_lookup_elem(&ipsec_egress_map, &pid_tgid);
33+
}
34+
35+
if (!id) {
36+
BPF_PRINTK("ipsec flow id not found in dir: %d", dir);
37+
return 0;
38+
}
39+
40+
if (is_ipv4(id->src_ip)) {
41+
eth_protocol = ETH_P_IP;
42+
} else {
43+
eth_protocol = ETH_P_IPV6;
44+
}
45+
46+
BPF_PRINTK("found encrypted flow dir: %d encrypted: %d\n", dir,
47+
flow_encrypted_ret == 0 ? true : false);
48+
49+
// update flow with ipsec info
50+
ret = ipsec_lookup_and_update_flow(id, flow_encrypted_ret, eth_protocol);
51+
if (ret == 0) {
52+
goto end;
53+
}
54+
55+
u64 current_time = bpf_ktime_get_ns();
56+
additional_metrics new_flow;
57+
__builtin_memset(&new_flow, 0, sizeof(new_flow));
58+
new_flow.start_mono_time_ts = current_time;
59+
new_flow.end_mono_time_ts = current_time;
60+
new_flow.eth_protocol = eth_protocol;
61+
new_flow.flow_encrypted_ret = flow_encrypted_ret;
62+
new_flow.flow_encrypted = flow_encrypted_ret == 0 ? true : false;
63+
ret = bpf_map_update_elem(&additional_flow_metrics, id, &new_flow, BPF_NOEXIST);
64+
if (ret != 0) {
65+
if (ret != -EEXIST) {
66+
BPF_PRINTK("error ipsec creating flow err: %d\n", ret);
67+
}
68+
if (ret == -EEXIST) {
69+
ret = ipsec_lookup_and_update_flow(id, flow_encrypted_ret, eth_protocol);
70+
if (ret != 0) {
71+
BPF_PRINTK("error ipsec updating an existing flow err: %d\n", ret);
72+
}
73+
}
74+
}
75+
end:
76+
if (dir == INGRESS) {
77+
bpf_map_delete_elem(&ipsec_ingress_map, &pid_tgid);
78+
} else {
79+
bpf_map_delete_elem(&ipsec_egress_map, &pid_tgid);
80+
}
81+
return 0;
82+
}
83+
84+
static inline int enter_xfrm_func(struct sk_buff *skb, direction dir) {
85+
u64 pid_tgid = bpf_get_current_pid_tgid();
86+
u16 family = 0, flags = 0, eth_protocol = 0;
87+
u8 dscp = 0, protocol = 0;
88+
flow_id id;
89+
int ret = 0;
90+
91+
__builtin_memset(&id, 0, sizeof(id));
92+
93+
u32 if_index = BPF_CORE_READ(skb, skb_iif);
94+
95+
// read L2 info
96+
core_fill_in_l2(skb, &eth_protocol, &family);
97+
98+
// read L3 info
99+
core_fill_in_l3(skb, &id, family, &protocol, &dscp);
100+
101+
// read L4 info
102+
switch (protocol) {
103+
case IPPROTO_TCP:
104+
core_fill_in_tcp(skb, &id, &flags);
105+
break;
106+
case IPPROTO_UDP:
107+
core_fill_in_udp(skb, &id);
108+
break;
109+
case IPPROTO_SCTP:
110+
core_fill_in_sctp(skb, &id);
111+
break;
112+
case IPPROTO_ICMP:
113+
core_fill_in_icmpv4(skb, &id);
114+
break;
115+
case IPPROTO_ICMPV6:
116+
core_fill_in_icmpv6(skb, &id);
117+
break;
118+
default:
119+
fill_in_others_protocol(&id, protocol);
120+
}
121+
122+
// check if this packet need to be filtered if filtering feature is enabled
123+
bool skip = check_and_do_flow_filtering(&id, flags, 0, eth_protocol, NULL, dir);
124+
if (skip) {
125+
return 0;
126+
}
127+
128+
BPF_PRINTK("Enter xfm dir: %d protocol: %d family: %d if_index: %d \n", dir, protocol, family,
129+
if_index);
130+
131+
if (dir == INGRESS) {
132+
ret = bpf_map_update_elem(&ipsec_ingress_map, &pid_tgid, &id, BPF_NOEXIST);
133+
} else {
134+
ret = bpf_map_update_elem(&ipsec_egress_map, &pid_tgid, &id, BPF_NOEXIST);
135+
}
136+
if (ret != 0) {
137+
if (trace_messages && ret != -EEXIST) {
138+
BPF_PRINTK("error creating new ipsec map dir: %d err: %d\n", dir, ret);
139+
}
140+
}
141+
return 0;
142+
}
143+
144+
SEC("kprobe/xfrm_input")
145+
int BPF_KPROBE(xfrm_input_kprobe) {
146+
if (do_sampling == 0 || enable_ipsec == 0) {
147+
return 0;
148+
}
149+
struct sk_buff *skb = (struct sk_buff *)PT_REGS_PARM1(ctx);
150+
if (!skb) {
151+
return 0;
152+
}
153+
return enter_xfrm_func(skb, INGRESS);
154+
}
155+
156+
SEC("kretprobe/xfrm_input")
157+
int BPF_KRETPROBE(xfrm_input_kretprobe) {
158+
if (do_sampling == 0 || enable_ipsec == 0) {
159+
return 0;
160+
}
161+
int xfrm_ret = PT_REGS_RC(ctx);
162+
return update_flow_with_ipsec_return(xfrm_ret, INGRESS);
163+
}
164+
165+
SEC("kprobe/xfrm_output")
166+
int BPF_KPROBE(xfrm_output_kprobe) {
167+
if (do_sampling == 0 || enable_ipsec == 0) {
168+
return 0;
169+
}
170+
struct sk_buff *skb = (struct sk_buff *)PT_REGS_PARM2(ctx);
171+
if (!skb) {
172+
return 0;
173+
}
174+
return enter_xfrm_func(skb, EGRESS);
175+
}
176+
177+
SEC("kretprobe/xfrm_output")
178+
int BPF_KRETPROBE(xfrm_output_kretprobe) {
179+
if (do_sampling == 0 || enable_ipsec == 0) {
180+
return 0;
181+
}
182+
int xfrm_ret = PT_REGS_RC(ctx);
183+
return update_flow_with_ipsec_return(xfrm_ret, EGRESS);
184+
}
185+
186+
#endif /* __IPSEC_H__ */

bpf/maps_definition.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,24 @@ struct {
7979
__uint(pinning, LIBBPF_PIN_BY_NAME);
8080
} peer_filter_map SEC(".maps");
8181

82+
// HashMap to store ingress flowid to be able to retrieve them from kretprobe hook
83+
struct {
84+
__uint(type, BPF_MAP_TYPE_HASH);
85+
__uint(max_entries, 1 << 20); // Will take around 64MB of space.
86+
__type(key, u64);
87+
__type(value, flow_id);
88+
__uint(map_flags, BPF_F_NO_PREALLOC);
89+
__uint(pinning, LIBBPF_PIN_BY_NAME);
90+
} ipsec_ingress_map SEC(".maps");
91+
92+
// HashMap to store egress flowid to be able to retrieve them from kretprobe hook
93+
struct {
94+
__uint(type, BPF_MAP_TYPE_HASH);
95+
__uint(max_entries, 1 << 20); // Will take around 64MB of space.
96+
__type(key, u64);
97+
__type(value, flow_id);
98+
__uint(map_flags, BPF_F_NO_PREALLOC);
99+
__uint(pinning, LIBBPF_PIN_BY_NAME);
100+
} ipsec_egress_map SEC(".maps");
101+
82102
#endif //__MAPS_DEFINITION_H__

bpf/types.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ typedef struct additional_metrics_t {
140140
} translated_flow;
141141
u16 eth_protocol;
142142
u8 network_events_idx;
143+
bool flow_encrypted;
144+
u8 flow_encrypted_ret;
143145
} additional_metrics;
144146

145147
// Force emitting enums/structs into the ELF

bpf/utils.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,4 +362,12 @@ static inline bool is_transport_protocol(u8 protocol) {
362362
return false;
363363
}
364364

365+
static inline bool is_ipv4(u8 *ip) {
366+
for (int i = 0; i < IP_MAX_LEN; i++) {
367+
if (ip[i] == 255) {
368+
return true;
369+
}
370+
}
371+
return false;
372+
}
365373
#endif // __UTILS_H__

pkg/ebpf/bpf_arm64_bpfel.go

Lines changed: 23 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/ebpf/bpf_arm64_bpfel.o

42.5 KB
Binary file not shown.

0 commit comments

Comments
 (0)