Skip to content

Commit 3b5c7c4

Browse files
[Code refactoring]: improved conntracker file organization
1 parent 5e8354a commit 3b5c7c4

6 files changed

Lines changed: 256 additions & 200 deletions

File tree

core/src/components/conntracker/src/data_structures.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub struct PacketLog {
1111
pub src_port: u16,
1212
pub dst_ip: u32,
1313
pub dst_port: u16,
14-
pub pid: u32
14+
pub pid: u32,
1515
}
1616

1717
// This structure is only for active connections
Lines changed: 46 additions & 199 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
/*
2-
* This file contains the code for the identity service
3-
*
4-
5-
* Functionalities:
6-
* 1. Creates a PacketLog structure to track incoming packets
7-
* 2. Creates a VethLog structure to track veth creation and veth eletetion events
8-
* 3. VethLog Tracking Parameters: NAME,STATE,DEVICE_ADDRESS,EVENT_TYPE,NETNS INUM.
9-
* 4. PacketLog Tracking Parameters: SRC_IP.SRC_PORT,DST_IP,DST_PORT,PROTOCOL,PID(HOOK)
10-
* 5. Store CONNECTION_ID in a BPF LRU HASHMAP and pass PID to the user space to identify ACTIVE CONNECTIONS
11-
*/
1+
// docs:
2+
// This file contains the code for the identity service
3+
// Functionalities:
4+
// 1. Creates a PacketLog structure to track incoming packets
5+
// 2. Creates a VethLog structure to track veth creation and veth eletetion events
6+
// 3. VethLog Tracking Parameters: NAME,STATE,DEVICE_ADDRESS,EVENT_TYPE,NETNS INUM.
7+
// 4. PacketLog Tracking Parameters: SRC_IP.SRC_PORT,DST_IP,DST_PORT,PROTOCOL,PID(HOOK)
8+
// 5. Store CONNECTION_ID in a BPF LRU HASHMAP and pass PID to the user space to identify ACTIVE CONNECTIONS
9+
//
1210

1311
#![no_std]
1412
#![no_main]
@@ -19,21 +17,19 @@
1917
mod bindings;
2018
mod data_structures;
2119
mod offsets;
22-
23-
use core::net::Ipv4Addr;
20+
mod tc;
21+
mod tcp_analyzer;
22+
mod veth_tracer;
2423

2524
use aya_ebpf::{
26-
bindings::{ TC_ACT_OK, TC_ACT_SHOT },
27-
helpers::{ bpf_get_current_pid_tgid, bpf_probe_read_kernel },
28-
macros::{ classifier, kprobe },
29-
programs::{ ProbeContext, TcContext },
25+
bindings::{TC_ACT_OK, TC_ACT_SHOT},
26+
macros::{classifier, kprobe},
27+
programs::{ProbeContext, TcContext},
3028
};
31-
use aya_log_ebpf::info;
3229

33-
use crate::bindings::{ net, net_device };
34-
use crate::data_structures::{ ConnArray, PacketLog, VethLog };
35-
use crate::data_structures::{ EVENTS, VETH_EVENTS, BLOCKLIST };
36-
use crate::offsets::OFFSETS;
30+
use crate::tc::try_identity_classifier;
31+
use crate::veth_tracer::try_veth_tracer;
32+
use crate::tcp_analyzer::try_tcp_analyzer;
3733

3834
#[kprobe]
3935
pub fn veth_creation_trace(ctx: ProbeContext) -> u32 {
@@ -50,114 +46,38 @@ pub fn veth_deletion_trace(ctx: ProbeContext) -> u32 {
5046
}
5147
}
5248

53-
//read linux inner struct. takes a ptr to the structure and an offset
54-
fn read_linux_inner_struct<T>(ptr: *const u8, offset: usize) -> Result<*const T, i64> {
55-
if ptr.is_null() {
56-
return Err(1);
57-
} else {
58-
let inner_ptr = unsafe { (ptr as *const u8).add(offset) };
59-
60-
let inner_field: *const T = unsafe {
61-
match bpf_probe_read_kernel(inner_ptr as *const *const T) {
62-
Ok(inner_field) => inner_field,
63-
Err(e) => {
64-
return Err(e);
65-
}
66-
}
67-
};
68-
Ok(inner_field)
69-
}
70-
}
49+
// docs;
50+
// this kprobe retrieves pid data and task id of an incoming packet
7151

72-
//T= type of return
73-
fn read_linux_inner_value<T: Copy>(ptr: *const u8, offset: usize) -> Result<T, i64> {
74-
if ptr.is_null() {
75-
return Err(1);
52+
#[kprobe]
53+
pub fn tcp_message_tracer(ctx: ProbeContext) -> u32 {
54+
match try_tcp_analyzer(ctx) {
55+
Ok(ret_val) => ret_val,
56+
Err(ret_val) => ret_val.try_into().unwrap_or(1),
7657
}
77-
78-
let inner_ptr = unsafe { (ptr as *const u8).add(offset) };
79-
80-
let inner_value = unsafe {
81-
match bpf_probe_read_kernel::<T>(inner_ptr as *const T) {
82-
Ok(inner_field) => inner_field,
83-
Err(e) => {
84-
return Err(e);
85-
}
86-
}
87-
};
88-
89-
Ok(inner_value)
9058
}
9159

92-
fn extract_netns_inum(net_device_pointer: *const u8) -> Result<u32, i64> {
93-
let possible_net_t_offset = 280;
94-
95-
let net = read_linux_inner_struct::<net>(net_device_pointer, possible_net_t_offset)?;
96-
97-
let ns_common_offset = 120;
98-
99-
let inum_offset = 16;
100-
let inum_ptr = read_linux_inner_value::<u32>(net as *const u8, ns_common_offset + inum_offset)?;
101-
Ok(inum_ptr)
102-
}
103-
104-
//mode selection:
105-
//1->veth_creation_tracer
106-
//2->veth_deletion_tracer
107-
pub fn try_veth_tracer(ctx: ProbeContext, mode: u8) -> Result<u32, i64> {
108-
let net_device_pointer: *const net_device = ctx.arg(0).ok_or(1i64)?;
109-
110-
// first control: i'm, verifying that the pointer is not null
111-
if net_device_pointer.is_null() {
112-
return Err(1);
113-
}
114-
115-
let mut name_buf = [0u8; 16];
116-
let mut dev_addr_buf = [0u32; 8];
117-
118-
//name field
119-
let name_field_offset = 304; // reading the name field offset
120-
121-
let name_array: [u8; 16] = read_linux_inner_value::<[u8; 16]>(
122-
net_device_pointer as *const u8,
123-
name_field_offset
124-
)?;
60+
// docs: this classifier acts in the very first step when a packet is logged
61+
62+
// Linux hooks stack:
63+
//
64+
// 6.Socket Layer
65+
// |
66+
// 5.TCP Stack
67+
// |
68+
// 4.Netfilter
69+
// |
70+
// 3.Traffic control (TC)
71+
// |
72+
// 2.XDP
73+
// |
74+
// 1.Network interface
75+
// |
76+
// Incoming Packet
77+
78+
// so we also need to extract the data from a second source in a kprobe context and correlate the data to catch
79+
// most of the value, without losing the ability to block a packet from the very early stages
12580

126-
//state field
127-
let state_offset = 168;
128-
let state: u8 = read_linux_inner_value::<u8>(net_device_pointer as *const u8, state_offset)?;
129-
130-
//dev_addr
131-
let dev_addr_offset = 1080;
132-
let dev_addr_array: [u32; 8] = read_linux_inner_value::<[u32; 8]>(
133-
net_device_pointer as *const u8,
134-
dev_addr_offset
135-
)?;
136-
137-
let inum: u32 = extract_netns_inum(net_device_pointer as *const u8)?;
138-
let pid: u32 = bpf_get_current_pid_tgid() as u32; //extracting lower 32 bit corresponding to the PID
139-
140-
//buffer copying for array types
141-
name_buf.copy_from_slice(&name_array);
142-
dev_addr_buf.copy_from_slice(&dev_addr_array);
143-
144-
//compose the structure
145-
let veth_data = VethLog {
146-
name: name_buf,
147-
state: state.into(),
148-
dev_addr: dev_addr_buf,
149-
event_type: mode,
150-
netns: inum,
151-
pid,
152-
};
153-
154-
//send the data to the userspace
155-
unsafe {
156-
VETH_EVENTS.output(&ctx, &veth_data, 0);
157-
}
158-
159-
Ok(0)
160-
}
16181
#[classifier]
16282
pub fn identity_classifier(ctx: TcContext) -> i32 {
16383
match try_identity_classifier(ctx) {
@@ -166,84 +86,11 @@ pub fn identity_classifier(ctx: TcContext) -> i32 {
16686
}
16787
}
16888

169-
fn try_identity_classifier(ctx: TcContext) -> Result<(), i64> {
170-
let eth_proto = u16::from_be(ctx.load::<u16>(12).map_err(|_| 1)?);
171-
172-
//only ipv4 protcol allowed
173-
if eth_proto != OFFSETS::IPV4_ETHERTYPE {
174-
return Ok(());
175-
}
176-
177-
//read if the packets has Options
178-
let first_ipv4_byte = u8::from_be(ctx.load::<u8>(OFFSETS::ETH_STACK_BYTES).map_err(|_| 1)?);
179-
let ihl = (first_ipv4_byte &
180-
0x0f) as usize; /* 0x0F=00001111 &=AND bit a bit operator to extract the last 4 bit*/
181-
let ip_header_len = ihl * 4; //returns the header lenght in bytes
182-
183-
//get the source ip,destination ip and connection id
184-
let src_ip = ctx.load::<u32>(OFFSETS::SRC_T0TAL_BYTES_OFFSET).map_err(|_| 1)?; // ETH+SOURCE_ADDRESS
185-
let src_port = u16::from_be(
186-
ctx
187-
.load::<u16>(
188-
OFFSETS::ETH_STACK_BYTES + ip_header_len + OFFSETS::SRC_PORT_OFFSET_FROM_IP_HEADER
189-
)
190-
.map_err(|_| 1)?
191-
); //14+IHL-Lenght+0
192-
let dst_ip = ctx.load::<u32>(OFFSETS::DST_T0TAL_BYTES_OFFSET).map_err(|_| 1)?; // ETH+ DESTINATION_ADDRESS
193-
let dst_port = u16::from_be(
194-
ctx
195-
.load::<u16>(
196-
OFFSETS::ETH_STACK_BYTES + ip_header_len + OFFSETS::DST_PORT_OFFSET_FROM_IP_HEADER
197-
)
198-
.map_err(|_| 1)?
199-
); //14+IHL-Lenght+0
200-
let proto = u8::from_be(ctx.load::<u8>(OFFSETS::PROTOCOL_T0TAL_BYTES_OFFSET).map_err(|_| 1)?);
201-
202-
let pid: u32 = bpf_get_current_pid_tgid() as u32;
203-
204-
//TODO: do not log internal communications such as minikube dashboard packets or kubectl api packets
205-
206-
// check if the address is in the blocklist
207-
let src_ip_be_bytes: [u8; 4] = src_ip.to_be_bytes(); //transforming the src_ip in big endian bytes
208-
209-
// ** blocklist logic
210-
if (unsafe { BLOCKLIST.get(&src_ip_be_bytes).is_some() }) {
211-
info!(
212-
&ctx,
213-
"Blocking address: {}. Reason: Address is in a BLOCKLIST",
214-
Ipv4Addr::from(src_ip_be_bytes)
215-
);
216-
return Err(1);
217-
} else {
218-
let key = ConnArray {
219-
src_ip,
220-
dst_ip,
221-
src_port,
222-
dst_port,
223-
proto,
224-
};
225-
226-
let log = PacketLog {
227-
proto,
228-
src_ip,
229-
src_port,
230-
dst_ip,
231-
dst_port,
232-
pid,
233-
};
234-
unsafe {
235-
EVENTS.output(&ctx, &log, 0); //output to userspace
236-
}
237-
}
238-
Ok(())
239-
}
240-
24189
//ref:https://elixir.bootlin.com/linux/v6.15.1/source/include/uapi/linux/ethtool.h#L536
24290
//https://elixir.bootlin.com/linux/v6.15.1/source/drivers/net/veth.c#L268
24391
//https://eunomia.dev/tutorials/3-fentry-unlink/
24492

24593
#[panic_handler]
24694
fn panic(_info: &core::panic::PanicInfo) -> ! {
247-
loop {
248-
}
95+
loop {}
24996
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
pub mod bindings;
22
pub mod data_structures;
33
pub mod offsets;
4+
pub mod tc;
5+
pub mod tcp_analyzer;
6+
pub mod veth_tracer;
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// docs:
2+
// TODO: write docs about the traffic control features
3+
4+
use core::net::Ipv4Addr;
5+
6+
use aya_ebpf::{
7+
helpers::{bpf_get_current_pid_tgid},
8+
programs::{TcContext},
9+
};
10+
use aya_log_ebpf::info;
11+
12+
use crate::data_structures::{ ConnArray, PacketLog };
13+
use crate::data_structures::{ EVENTS,BLOCKLIST };
14+
use crate::offsets::OFFSETS;
15+
16+
pub fn try_identity_classifier(ctx: TcContext) -> Result<(), i64> {
17+
let eth_proto = u16::from_be(ctx.load::<u16>(12).map_err(|_| 1)?);
18+
19+
//only ipv4 protcol allowed
20+
if eth_proto != OFFSETS::IPV4_ETHERTYPE {
21+
return Ok(());
22+
}
23+
24+
//read if the packets has Options
25+
let first_ipv4_byte = u8::from_be(ctx.load::<u8>(OFFSETS::ETH_STACK_BYTES).map_err(|_| 1)?);
26+
let ihl = (first_ipv4_byte &
27+
0x0f) as usize; /* 0x0F=00001111 &=AND bit a bit operator to extract the last 4 bit*/
28+
let ip_header_len = ihl * 4; //returns the header lenght in bytes
29+
30+
//get the source ip,destination ip and connection id
31+
let src_ip = ctx.load::<u32>(OFFSETS::SRC_T0TAL_BYTES_OFFSET).map_err(|_| 1)?; // ETH+SOURCE_ADDRESS
32+
let src_port = u16::from_be(
33+
ctx
34+
.load::<u16>(
35+
OFFSETS::ETH_STACK_BYTES + ip_header_len + OFFSETS::SRC_PORT_OFFSET_FROM_IP_HEADER
36+
)
37+
.map_err(|_| 1)?
38+
); //14+IHL-Lenght+0
39+
let dst_ip = ctx.load::<u32>(OFFSETS::DST_T0TAL_BYTES_OFFSET).map_err(|_| 1)?; // ETH+ DESTINATION_ADDRESS
40+
let dst_port = u16::from_be(
41+
ctx
42+
.load::<u16>(
43+
OFFSETS::ETH_STACK_BYTES + ip_header_len + OFFSETS::DST_PORT_OFFSET_FROM_IP_HEADER
44+
)
45+
.map_err(|_| 1)?
46+
); //14+IHL-Lenght+0
47+
let proto = u8::from_be(ctx.load::<u8>(OFFSETS::PROTOCOL_T0TAL_BYTES_OFFSET).map_err(|_| 1)?);
48+
49+
let pid: u32 = bpf_get_current_pid_tgid() as u32;
50+
51+
// check if the address is in the blocklist
52+
let src_ip_be_bytes: [u8; 4] = src_ip.to_be_bytes(); //transforming the src_ip in big endian bytes
53+
54+
// ** blocklist logic
55+
if unsafe { BLOCKLIST.get(&src_ip_be_bytes).is_some() } {
56+
info!(
57+
&ctx,
58+
"Blocking address: {}. Reason: Address is in a BLOCKLIST",
59+
Ipv4Addr::from(src_ip_be_bytes)
60+
);
61+
return Err(1);
62+
} else {
63+
let key = ConnArray {
64+
src_ip,
65+
dst_ip,
66+
src_port,
67+
dst_port,
68+
proto,
69+
};
70+
71+
let log = PacketLog {
72+
proto,
73+
src_ip,
74+
src_port,
75+
dst_ip,
76+
dst_port,
77+
pid,
78+
};
79+
unsafe {
80+
EVENTS.output(&ctx, &log, 0); //output to userspace
81+
}
82+
}
83+
Ok(())
84+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// docs:
2+
// TODO: move the kprobe tracer functions here
3+
4+
use aya_ebpf::programs::ProbeContext;
5+
6+
pub fn try_tcp_analyzer(ctx: ProbeContext) -> Result<u32, i64> {
7+
todo!()
8+
}

0 commit comments

Comments
 (0)