Skip to content

Commit 4b40d24

Browse files
authored
Merge pull request #538 from msherif1234/ipsec_support
NETOBSERV-2198: IPsec support
2 parents 1fca761 + a576882 commit 4b40d24

26 files changed

+690
-54
lines changed

.mk/bc.mk

+8-2
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

+1
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

+5
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

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

bpf/maps_definition.h

+20
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

+2
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

+8
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/agent/agent.go

+1
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ func FlowsAgent(cfg *Config) (*Flows, error) {
237237
EnablePktTranslation: cfg.EnablePktTranslationTracking,
238238
UseEbpfManager: cfg.EbpfProgramManagerMode,
239239
BpfManBpfFSPath: cfg.BpfManBpfFSPath,
240+
EnableIPsecTracker: cfg.EnableIPsecTracking,
240241
FilterConfig: filterRules,
241242
}
242243

pkg/agent/config.go

+2
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ type Config struct {
236236
BpfManBpfFSPath string `env:"BPFMAN_BPF_FS_PATH" envDefault:"/run/netobserv/maps"`
237237
// EnableUDNMapping to allow mapping pod's interface to udn label
238238
EnableUDNMapping bool `env:"ENABLE_UDN_MAPPING" envDefault:"false"`
239+
// EnableIPsecTracking enable tracking IPsec flows encryption
240+
EnableIPsecTracking bool `env:"ENABLE_IPSEC_TRACKING" envDefault:"false"`
239241
/* Deprecated configs are listed below this line
240242
* See manageDeprecatedConfigs function for details
241243
*/

pkg/decode/decode_protobuf.go

+4
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ func RecordToMap(fr *model.Record) config.GenericMap {
141141
out["XlatSrcAddr"] = model.IP(fr.Metrics.AdditionalMetrics.TranslatedFlow.Saddr).String()
142142
out["XlatDstAddr"] = model.IP(fr.Metrics.AdditionalMetrics.TranslatedFlow.Daddr).String()
143143
}
144+
if fr.Metrics.AdditionalMetrics.FlowEncrypted || fr.Metrics.AdditionalMetrics.FlowEncryptedRet != 0 {
145+
out["IPSecSuccess"] = fr.Metrics.AdditionalMetrics.FlowEncrypted
146+
out["IPSecRetCode"] = fr.Metrics.AdditionalMetrics.FlowEncryptedRet
147+
}
144148
}
145149

146150
if fr.TimeFlowRtt != 0 {

pkg/decode/decode_protobuf_test.go

+9-5
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ func TestPBFlowToMap(t *testing.T) {
9696
DstPort: 2,
9797
ZoneId: 100,
9898
},
99+
FlowEncrypted: 1,
100+
FlowEncryptedRet: 0,
99101
}
100102

101103
out := PBFlowToMap(flow)
@@ -146,10 +148,12 @@ func TestPBFlowToMap(t *testing.T) {
146148
"Direction": "egress",
147149
},
148150
},
149-
"XlatSrcAddr": "1.2.3.4",
150-
"XlatDstAddr": "5.6.7.8",
151-
"XlatSrcPort": uint16(1),
152-
"XlatDstPort": uint16(2),
153-
"ZoneId": uint16(100),
151+
"XlatSrcAddr": "1.2.3.4",
152+
"XlatDstAddr": "5.6.7.8",
153+
"XlatSrcPort": uint16(1),
154+
"XlatDstPort": uint16(2),
155+
"ZoneId": uint16(100),
156+
"IPSecSuccess": true,
157+
"IPSecRetCode": uint8(0),
154158
}, out)
155159
}

0 commit comments

Comments
 (0)