Last active
January 11, 2024 12:38
-
-
Save theojulienne/9d78a0cb68dbe56f19a2ae6316bc6846 to your computer and use it in GitHub Desktop.
ICMP packet tracer using BCC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
bpf_text = """ | |
#include <linux/ptrace.h> | |
#include <linux/sched.h> /* For TASK_COMM_LEN */ | |
#include <linux/icmp.h> | |
#include <linux/netdevice.h> | |
struct probe_icmp_data_t | |
{ | |
u64 timestamp_ns; | |
u32 tgid; | |
u32 pid; | |
char comm[TASK_COMM_LEN]; | |
int v0; | |
}; | |
BPF_PERF_OUTPUT(probe_icmp_events); | |
static inline unsigned char *my_skb_transport_header(const struct sk_buff *skb) | |
{ | |
return skb->head + skb->transport_header; | |
} | |
static inline struct icmphdr *my_icmp_hdr(const struct sk_buff *skb) | |
{ | |
return (struct icmphdr *)my_skb_transport_header(skb); | |
} | |
int probe_icmp(struct pt_regs *ctx, struct sk_buff *skb) | |
{ | |
u64 __pid_tgid = bpf_get_current_pid_tgid(); | |
u32 __tgid = __pid_tgid >> 32; | |
u32 __pid = __pid_tgid; // implicit cast to u32 for bottom half | |
struct probe_icmp_data_t __data = {0}; | |
__data.timestamp_ns = bpf_ktime_get_ns(); | |
__data.tgid = __tgid; | |
__data.pid = __pid; | |
bpf_get_current_comm(&__data.comm, sizeof(__data.comm)); | |
__be16 seq; | |
bpf_probe_read(&seq, sizeof(seq), &my_icmp_hdr(skb)->un.echo.sequence); | |
__data.v0 = (int)seq; | |
probe_icmp_events.perf_submit(ctx, &__data, sizeof(__data)); | |
return 0; | |
} | |
""" | |
from bcc import BPF | |
import ctypes as ct | |
class Data_icmp(ct.Structure): | |
_fields_ = [ | |
("timestamp_ns", ct.c_ulonglong), | |
("tgid", ct.c_uint), | |
("pid", ct.c_uint), | |
("comm", ct.c_char * 16), # TASK_COMM_LEN | |
('v0', ct.c_uint), | |
] | |
b = BPF(text=bpf_text) | |
def print_icmp_event(cpu, data, size): | |
#event = b["probe_icmp_events"].event(data) | |
event = ct.cast(data, ct.POINTER(Data_icmp)).contents | |
print("%-7d %-7d %-15s %s" % | |
(event.tgid, event.pid, | |
event.comm.decode('utf-8', 'replace'), | |
event.v0)) | |
b.attach_kprobe(event="icmp_echo", fn_name="probe_icmp") | |
b["probe_icmp_events"].open_perf_buffer(print_icmp_event) | |
while 1: | |
try: | |
b.kprobe_poll() | |
except KeyboardInterrupt: | |
exit() |
replace bpf_probe_read()
with
void *addr = &my_icmp_hdr(skb)->un.echo.sequence;
bpf_probe_read(&seq, sizeof(seq), addr);
it works for kernel 4.18.0
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
When I ran this program in linux 5.7.7(centos 7.6), I got this error:
HINT: The invalid mem access 'inv' error can happen if you try to dereference memory without first using bpf_probe_read_kernel() to copy it to the BPF stack. Sometimes the bpf_probe_read_kernel() is automatic by the bcc rewriter, other times you'll need to be explicit.
And when i change the bpf_probe_read to bpf_probe_read_kernel it works