mirror of
https://github.com/eunomia-bpf/bpf-developer-tutorial.git
synced 2026-02-03 10:14:44 +08:00
Deploying to gh-pages from @ eunomia-bpf/bpf-developer-tutorial@af2d46a846 🚀
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
25-signal/.gitignore
vendored
2
25-signal/.gitignore
vendored
@@ -7,3 +7,5 @@ package.yaml
|
||||
ecli
|
||||
bootstrap
|
||||
bpfdos
|
||||
ecc
|
||||
ecli
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -3,7 +3,7 @@
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include <bpf/bpf_core_read.h>
|
||||
#include "common.h"
|
||||
#include "signal.h"
|
||||
|
||||
char LICENSE[] SEC("license") = "Dual BSD/GPL";
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,41 +0,0 @@
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
#define debug_bpf_printk(fmt, ...) \
|
||||
do { \
|
||||
char s[] = fmt; \
|
||||
bpf_trace_printk(s, sizeof(s), ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define debug_bpf_printk(fmt, ...)
|
||||
#endif
|
||||
|
||||
#define TASK_COMM_LEN 16
|
||||
#define MAX_DATA_SIZE_OPENSSL 1024 * 4
|
||||
#define MAX_DATA_SIZE_MYSQL 256
|
||||
#define MAX_DATA_SIZE_POSTGRES 256
|
||||
#define MAX_DATA_SIZE_BASH 256
|
||||
|
||||
// enum_server_command, via
|
||||
// https://dev.mysql.com/doc/internals/en/com-query.html COM_QUERT command 03
|
||||
#define COM_QUERY 3
|
||||
|
||||
#define AF_INET 2
|
||||
#define AF_INET6 10
|
||||
#define SA_DATA_LEN 14
|
||||
#define BASH_ERRNO_DEFAULT 128
|
||||
|
||||
// Optional Target PID
|
||||
// .rodata section bug via : https://github.com/ehids/ecapture/issues/39
|
||||
#ifndef KERNEL_LESS_5_2
|
||||
const volatile u64 target_pid = 0;
|
||||
const volatile int target_errno = BASH_ERRNO_DEFAULT;
|
||||
#else
|
||||
// u64 target_pid = 0;
|
||||
#endif
|
||||
|
||||
char __license[] SEC("license") = "Dual MIT/GPL";
|
||||
__u32 _version SEC("version") = 0xFFFFFFFE;
|
||||
|
||||
#endif
|
||||
@@ -1,248 +0,0 @@
|
||||
#include "openssl_trace.bpf.h"
|
||||
|
||||
enum ssl_data_event_type { kSSLRead, kSSLWrite };
|
||||
const u32 invalidFD = 0;
|
||||
|
||||
struct ssl_data_event_t {
|
||||
enum ssl_data_event_type type;
|
||||
u64 timestamp_ns;
|
||||
u32 pid;
|
||||
u32 tid;
|
||||
char data[MAX_DATA_SIZE_OPENSSL];
|
||||
s32 data_len;
|
||||
char comm[TASK_COMM_LEN];
|
||||
u32 fd;
|
||||
};
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
} tls_events SEC(".maps");
|
||||
|
||||
struct active_ssl_buf {
|
||||
u32 fd;
|
||||
const char* buf;
|
||||
};
|
||||
|
||||
// BPF programs are limited to a 512-byte stack. We store this value per CPU
|
||||
// and use it as a heap allocated value.
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
|
||||
__type(key, u32);
|
||||
__type(value, struct ssl_data_event_t);
|
||||
__uint(max_entries, 1);
|
||||
} data_buffer_heap SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__type(key, u64);
|
||||
__type(value, struct active_ssl_buf);
|
||||
__uint(max_entries, 1024);
|
||||
} active_ssl_read_args_map SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__type(key, u64);
|
||||
__type(value, struct active_ssl_buf);
|
||||
__uint(max_entries, 1024);
|
||||
} active_ssl_write_args_map SEC(".maps");
|
||||
|
||||
// OPENSSL struct to offset , via kern/README.md
|
||||
typedef long (*unused_fn)();
|
||||
|
||||
struct unused {};
|
||||
|
||||
struct BIO {
|
||||
const struct unused* method;
|
||||
unused_fn callback;
|
||||
unused_fn callback_ex;
|
||||
char* cb_arg; /* first argument for the callback */
|
||||
int init;
|
||||
int shutdown;
|
||||
int flags; /* extra storage */
|
||||
int retry_reason;
|
||||
int num;
|
||||
};
|
||||
|
||||
struct ssl_st {
|
||||
int version;
|
||||
struct unused* method;
|
||||
struct BIO* rbio; // used by SSL_read
|
||||
struct BIO* wbio; // used by SSL_write
|
||||
};
|
||||
|
||||
/***********************************************************
|
||||
* General helper functions
|
||||
***********************************************************/
|
||||
static __inline struct ssl_data_event_t* create_ssl_data_event(
|
||||
u64 current_pid_tgid) {
|
||||
u32 kZero = 0;
|
||||
struct ssl_data_event_t* event =
|
||||
bpf_map_lookup_elem(&data_buffer_heap, &kZero);
|
||||
if (event == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const u32 kMask32b = 0xffffffff;
|
||||
event->timestamp_ns = bpf_ktime_get_ns();
|
||||
event->pid = current_pid_tgid >> 32;
|
||||
event->tid = current_pid_tgid & kMask32b;
|
||||
event->fd = invalidFD;
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
* BPF syscall processing functions
|
||||
***********************************************************/
|
||||
static int process_SSL_data(struct pt_regs* ctx, u64 id,
|
||||
enum ssl_data_event_type type, const char* buf,
|
||||
u32 fd) {
|
||||
int len = (int)PT_REGS_RC(ctx);
|
||||
if (len < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ssl_data_event_t* event = create_ssl_data_event(id);
|
||||
if (event == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
event->type = type;
|
||||
event->fd = fd;
|
||||
// This is a max function, but it is written in such a way to keep older BPF
|
||||
// verifiers happy.
|
||||
event->data_len =
|
||||
(len < MAX_DATA_SIZE_OPENSSL ? (len & (MAX_DATA_SIZE_OPENSSL - 1))
|
||||
: MAX_DATA_SIZE_OPENSSL);
|
||||
bpf_probe_read(event->data, event->data_len, buf);
|
||||
bpf_get_current_comm(&event->comm, sizeof(event->comm));
|
||||
bpf_perf_event_output(ctx, &tls_events, BPF_F_CURRENT_CPU, event,
|
||||
sizeof(struct ssl_data_event_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
* BPF probe function entry-points
|
||||
***********************************************************/
|
||||
|
||||
// Function signature being probed:
|
||||
// int SSL_write(SSL *ssl, const void *buf, int num);
|
||||
SEC("uprobe/SSL_write")
|
||||
int probe_entry_SSL_write(struct pt_regs* ctx) {
|
||||
u64 current_pid_tgid = bpf_get_current_pid_tgid();
|
||||
u32 pid = current_pid_tgid >> 32;
|
||||
|
||||
#ifndef KERNEL_LESS_5_2
|
||||
// if target_ppid is 0 then we target all pids
|
||||
if (target_pid != 0 && target_pid != pid) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
// debug_bpf_printk("openssl uprobe/SSL_write pid :%d\n", pid);
|
||||
|
||||
void* ssl = (void*)PT_REGS_PARM1(ctx);
|
||||
// https://github.com/openssl/openssl/blob/OpenSSL_1_1_1-stable/crypto/bio/bio_local.h
|
||||
struct ssl_st ssl_info;
|
||||
bpf_probe_read_user(&ssl_info, sizeof(ssl_info), ssl);
|
||||
|
||||
struct BIO bio_w;
|
||||
bpf_probe_read_user(&bio_w, sizeof(bio_w), ssl_info.wbio);
|
||||
|
||||
// get fd ssl->wbio->num
|
||||
u32 fd = bio_w.num;
|
||||
// debug_bpf_printk("openssl uprobe SSL_write FD:%d\n", fd);
|
||||
|
||||
const char* buf = (const char*)PT_REGS_PARM2(ctx);
|
||||
struct active_ssl_buf active_ssl_buf_t;
|
||||
__builtin_memset(&active_ssl_buf_t, 0, sizeof(active_ssl_buf_t));
|
||||
active_ssl_buf_t.fd = fd;
|
||||
active_ssl_buf_t.buf = buf;
|
||||
bpf_map_update_elem(&active_ssl_write_args_map, ¤t_pid_tgid,
|
||||
&active_ssl_buf_t, BPF_ANY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("uretprobe/SSL_write")
|
||||
int probe_ret_SSL_write(struct pt_regs* ctx) {
|
||||
u64 current_pid_tgid = bpf_get_current_pid_tgid();
|
||||
u32 pid = current_pid_tgid >> 32;
|
||||
|
||||
#ifndef KERNEL_LESS_5_2
|
||||
// if target_ppid is 0 then we target all pids
|
||||
if (target_pid != 0 && target_pid != pid) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
// debug_bpf_printk("openssl uretprobe/SSL_write pid :%d\n", pid);
|
||||
struct active_ssl_buf* active_ssl_buf_t =
|
||||
bpf_map_lookup_elem(&active_ssl_write_args_map, ¤t_pid_tgid);
|
||||
if (active_ssl_buf_t != NULL) {
|
||||
const char* buf;
|
||||
u32 fd = active_ssl_buf_t->fd;
|
||||
bpf_probe_read(&buf, sizeof(const char*), &active_ssl_buf_t->buf);
|
||||
process_SSL_data(ctx, current_pid_tgid, kSSLWrite, buf, fd);
|
||||
}
|
||||
bpf_map_delete_elem(&active_ssl_write_args_map, ¤t_pid_tgid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Function signature being probed:
|
||||
// int SSL_read(SSL *s, void *buf, int num)
|
||||
SEC("uprobe/SSL_read")
|
||||
int probe_entry_SSL_read(struct pt_regs* ctx) {
|
||||
u64 current_pid_tgid = bpf_get_current_pid_tgid();
|
||||
u32 pid = current_pid_tgid >> 32;
|
||||
|
||||
#ifndef KERNEL_LESS_5_2
|
||||
// if target_ppid is 0 then we target all pids
|
||||
if (target_pid != 0 && target_pid != pid) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void* ssl = (void*)PT_REGS_PARM1(ctx);
|
||||
// https://github.com/openssl/openssl/blob/OpenSSL_1_1_1-stable/crypto/bio/bio_local.h
|
||||
struct ssl_st ssl_info;
|
||||
bpf_probe_read_user(&ssl_info, sizeof(ssl_info), ssl);
|
||||
|
||||
struct BIO bio_r;
|
||||
bpf_probe_read_user(&bio_r, sizeof(bio_r), ssl_info.rbio);
|
||||
|
||||
// get fd ssl->rbio->num
|
||||
u32 fd = bio_r.num;
|
||||
debug_bpf_printk("openssl uprobe PID:%d, SSL_read FD:%d\n", pid, fd);
|
||||
|
||||
const char* buf = (const char*)PT_REGS_PARM2(ctx);
|
||||
struct active_ssl_buf active_ssl_buf_t;
|
||||
__builtin_memset(&active_ssl_buf_t, 0, sizeof(active_ssl_buf_t));
|
||||
active_ssl_buf_t.fd = fd;
|
||||
active_ssl_buf_t.buf = buf;
|
||||
bpf_map_update_elem(&active_ssl_read_args_map, ¤t_pid_tgid,
|
||||
&active_ssl_buf_t, BPF_ANY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("uretprobe/SSL_read")
|
||||
int probe_ret_SSL_read(struct pt_regs* ctx) {
|
||||
u64 current_pid_tgid = bpf_get_current_pid_tgid();
|
||||
u32 pid = current_pid_tgid >> 32;
|
||||
|
||||
#ifndef KERNEL_LESS_5_2
|
||||
// if target_ppid is 0 then we target all pids
|
||||
if (target_pid != 0 && target_pid != pid) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct active_ssl_buf* active_ssl_buf_t =
|
||||
bpf_map_lookup_elem(&active_ssl_read_args_map, ¤t_pid_tgid);
|
||||
if (active_ssl_buf_t != NULL) {
|
||||
const char* buf;
|
||||
u32 fd = active_ssl_buf_t->fd;
|
||||
bpf_probe_read(&buf, sizeof(const char*), &active_ssl_buf_t->buf);
|
||||
process_SSL_data(ctx, current_pid_tgid, kSSLRead, buf, fd);
|
||||
}
|
||||
bpf_map_delete_elem(&active_ssl_read_args_map, ¤t_pid_tgid);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#ifndef OPENSS_TRACE_BPF_H
|
||||
#define OPENSS_TRACE_BPF_H
|
||||
|
||||
//CO:RE is enabled
|
||||
#include "headers/vmlinux.h"
|
||||
#include <bpf/bpf_core_read.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include "common.h"
|
||||
|
||||
#endif
|
||||
@@ -1,173 +0,0 @@
|
||||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
/* Copyright (c) 2020 Facebook */
|
||||
#include <argp.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <bpf/libbpf.h>
|
||||
#include "openssl.h"
|
||||
#include "openssl.skel.h"
|
||||
|
||||
static struct env {
|
||||
bool verbose;
|
||||
long min_duration_ms;
|
||||
} env;
|
||||
|
||||
const char *argp_program_version = "openssl 0.0";
|
||||
const char *argp_program_bug_address = "<bpf@vger.kernel.org>";
|
||||
const char argp_program_doc[] =
|
||||
"BPF openssl demo application.\n"
|
||||
"\n"
|
||||
"It traces process start and exits and shows associated \n"
|
||||
"information (filename, process duration, PID and PPID, etc).\n"
|
||||
"\n"
|
||||
"USAGE: ./openssl [-d <min-duration-ms>] [-v]\n";
|
||||
|
||||
static const struct argp_option opts[] = {
|
||||
{ "verbose", 'v', NULL, 0, "Verbose debug output" },
|
||||
{ "duration", 'd', "DURATION-MS", 0, "Minimum process duration (ms) to report" },
|
||||
{},
|
||||
};
|
||||
|
||||
static error_t parse_arg(int key, char *arg, struct argp_state *state)
|
||||
{
|
||||
switch (key) {
|
||||
case 'v':
|
||||
env.verbose = true;
|
||||
break;
|
||||
case 'd':
|
||||
errno = 0;
|
||||
env.min_duration_ms = strtol(arg, NULL, 10);
|
||||
if (errno || env.min_duration_ms <= 0) {
|
||||
fprintf(stderr, "Invalid duration: %s\n", arg);
|
||||
argp_usage(state);
|
||||
}
|
||||
break;
|
||||
case ARGP_KEY_ARG:
|
||||
argp_usage(state);
|
||||
break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct argp argp = {
|
||||
.options = opts,
|
||||
.parser = parse_arg,
|
||||
.doc = argp_program_doc,
|
||||
};
|
||||
|
||||
static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
|
||||
{
|
||||
if (level == LIBBPF_DEBUG && !env.verbose)
|
||||
return 0;
|
||||
return vfprintf(stderr, format, args);
|
||||
}
|
||||
|
||||
static volatile bool exiting = false;
|
||||
|
||||
static void sig_handler(int sig)
|
||||
{
|
||||
exiting = true;
|
||||
}
|
||||
|
||||
static int handle_event(void *ctx, void *data, size_t data_sz)
|
||||
{
|
||||
const struct event *e = data;
|
||||
struct tm *tm;
|
||||
char ts[32];
|
||||
time_t t;
|
||||
|
||||
time(&t);
|
||||
tm = localtime(&t);
|
||||
strftime(ts, sizeof(ts), "%H:%M:%S", tm);
|
||||
|
||||
if (e->exit_event) {
|
||||
printf("%-8s %-5s %-16s %-7d %-7d [%u]",
|
||||
ts, "EXIT", e->comm, e->pid, e->ppid, e->exit_code);
|
||||
if (e->duration_ns)
|
||||
printf(" (%llums)", e->duration_ns / 1000000);
|
||||
printf("\n");
|
||||
} else {
|
||||
printf("%-8s %-5s %-16s %-7d %-7d %s\n",
|
||||
ts, "EXEC", e->comm, e->pid, e->ppid, e->filename);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct ring_buffer *rb = NULL;
|
||||
struct openssl_bpf *skel;
|
||||
int err;
|
||||
|
||||
/* Parse command line arguments */
|
||||
err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Set up libbpf errors and debug info callback */
|
||||
libbpf_set_print(libbpf_print_fn);
|
||||
|
||||
/* Cleaner handling of Ctrl-C */
|
||||
signal(SIGINT, sig_handler);
|
||||
signal(SIGTERM, sig_handler);
|
||||
|
||||
/* Load and verify BPF application */
|
||||
skel = openssl_bpf__open();
|
||||
if (!skel) {
|
||||
fprintf(stderr, "Failed to open and load BPF skeleton\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Parameterize BPF code with minimum duration parameter */
|
||||
skel->rodata->min_duration_ns = env.min_duration_ms * 1000000ULL;
|
||||
|
||||
/* Load & verify BPF programs */
|
||||
err = openssl_bpf__load(skel);
|
||||
if (err) {
|
||||
fprintf(stderr, "Failed to load and verify BPF skeleton\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Attach tracepoints */
|
||||
err = openssl_bpf__attach(skel);
|
||||
if (err) {
|
||||
fprintf(stderr, "Failed to attach BPF skeleton\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Set up ring buffer polling */
|
||||
rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), handle_event, NULL, NULL);
|
||||
if (!rb) {
|
||||
err = -1;
|
||||
fprintf(stderr, "Failed to create ring buffer\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Process events */
|
||||
printf("%-8s %-5s %-16s %-7s %-7s %s\n",
|
||||
"TIME", "EVENT", "COMM", "PID", "PPID", "FILENAME/EXIT CODE");
|
||||
while (!exiting) {
|
||||
err = ring_buffer__poll(rb, 100 /* timeout, ms */);
|
||||
/* Ctrl-C will cause -EINTR */
|
||||
if (err == -EINTR) {
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
if (err < 0) {
|
||||
printf("Error polling perf buffer: %d\n", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
/* Clean up */
|
||||
ring_buffer__free(rb);
|
||||
openssl_bpf__destroy(skel);
|
||||
|
||||
return err < 0 ? -err : 0;
|
||||
}
|
||||
@@ -24,7 +24,7 @@ INCLUDES := -I$(OUTPUT) -I../third_party/libbpf/include/uapi -I$(dir $(VMLINUX))
|
||||
CFLAGS := -g -Wall
|
||||
ALL_LDFLAGS := $(LDFLAGS) $(EXTRA_LDFLAGS)
|
||||
|
||||
APPS = bootstrap # minimal minimal_legacy uprobe kprobe fentry usdt sockfilter tc ksyscall
|
||||
APPS = sslsniff # minimal minimal_legacy uprobe kprobe fentry usdt sockfilter tc ksyscall
|
||||
|
||||
CARGO ?= $(shell which cargo)
|
||||
ifeq ($(strip $(CARGO)),)
|
||||
648
30-sslsniff/index.html
Normal file
648
30-sslsniff/index.html
Normal file
File diff suppressed because one or more lines are too long
220
30-sslsniff/sslsniff.bpf.c
Normal file
220
30-sslsniff/sslsniff.bpf.c
Normal file
@@ -0,0 +1,220 @@
|
||||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
// Copyright (c) 2023 Yusheng Zheng
|
||||
//
|
||||
// Based on sslsniff from BCC by Adrian Lopez & Mark Drayton.
|
||||
// 15-Aug-2023 Yusheng Zheng Created this.
|
||||
#include <vmlinux.h>
|
||||
#include <bpf/bpf_core_read.h>
|
||||
#include <bpf/bpf_endian.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include "sslsniff.h"
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
||||
__uint(key_size, sizeof(__u32));
|
||||
__uint(value_size, sizeof(__u32));
|
||||
} perf_SSL_events SEC(".maps");
|
||||
|
||||
#define BASE_EVENT_SIZE ((size_t)(&((struct probe_SSL_data_t *)0)->buf))
|
||||
#define EVENT_SIZE(X) (BASE_EVENT_SIZE + ((size_t)(X)))
|
||||
#define MAX_ENTRIES 10240
|
||||
|
||||
#define min(x, y) \
|
||||
({ \
|
||||
typeof(x) _min1 = (x); \
|
||||
typeof(y) _min2 = (y); \
|
||||
(void)(&_min1 == &_min2); \
|
||||
_min1 < _min2 ? _min1 : _min2; \
|
||||
})
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__type(key, u32);
|
||||
__type(value, struct probe_SSL_data_t);
|
||||
} ssl_data SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, MAX_ENTRIES);
|
||||
__type(key, __u32);
|
||||
__type(value, __u64);
|
||||
} start_ns SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, MAX_ENTRIES);
|
||||
__type(key, __u32);
|
||||
__type(value, __u64);
|
||||
} bufs SEC(".maps");
|
||||
|
||||
const volatile pid_t targ_pid = 0;
|
||||
const volatile uid_t targ_uid = -1;
|
||||
|
||||
static __always_inline bool trace_allowed(u32 uid, u32 pid)
|
||||
{
|
||||
/* filters */
|
||||
if (targ_pid && targ_pid != pid)
|
||||
return false;
|
||||
if (targ_uid != -1) {
|
||||
if (targ_uid != uid) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SEC("uprobe/do_handshake")
|
||||
int BPF_UPROBE(probe_SSL_rw_enter, void *ssl, void *buf, int num) {
|
||||
u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
u32 pid = pid_tgid >> 32;
|
||||
u32 tid = pid_tgid;
|
||||
u32 uid = bpf_get_current_uid_gid();
|
||||
u64 ts = bpf_ktime_get_ns();
|
||||
|
||||
if (!trace_allowed(uid, pid)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* store arg info for later lookup */
|
||||
bpf_map_update_elem(&bufs, &tid, &buf, BPF_ANY);
|
||||
bpf_map_update_elem(&start_ns, &tid, &ts, BPF_ANY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SSL_exit(struct pt_regs *ctx, int rw) {
|
||||
int ret = 0;
|
||||
u32 zero = 0;
|
||||
u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
u32 pid = pid_tgid >> 32;
|
||||
u32 tid = (u32)pid_tgid;
|
||||
u32 uid = bpf_get_current_uid_gid();
|
||||
u64 ts = bpf_ktime_get_ns();
|
||||
|
||||
if (!trace_allowed(uid, pid)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* store arg info for later lookup */
|
||||
u64 *bufp = bpf_map_lookup_elem(&bufs, &tid);
|
||||
if (bufp == 0)
|
||||
return 0;
|
||||
|
||||
u64 *tsp = bpf_map_lookup_elem(&start_ns, &tid);
|
||||
if (!tsp)
|
||||
return 0;
|
||||
u64 delta_ns = ts - *tsp;
|
||||
|
||||
int len = PT_REGS_RC(ctx);
|
||||
if (len <= 0) // no data
|
||||
return 0;
|
||||
|
||||
struct probe_SSL_data_t *data = bpf_map_lookup_elem(&ssl_data, &zero);
|
||||
if (!data)
|
||||
return 0;
|
||||
|
||||
data->timestamp_ns = ts;
|
||||
data->delta_ns = delta_ns;
|
||||
data->pid = pid;
|
||||
data->tid = tid;
|
||||
data->uid = uid;
|
||||
data->len = (u32)len;
|
||||
data->buf_filled = 0;
|
||||
data->rw = rw;
|
||||
data->is_handshake = false;
|
||||
u32 buf_copy_size = min((size_t)MAX_BUF_SIZE, (size_t)len);
|
||||
|
||||
bpf_get_current_comm(&data->comm, sizeof(data->comm));
|
||||
|
||||
if (bufp != 0)
|
||||
ret = bpf_probe_read_user(&data->buf, buf_copy_size, (char *)*bufp);
|
||||
|
||||
bpf_map_delete_elem(&bufs, &tid);
|
||||
bpf_map_delete_elem(&start_ns, &tid);
|
||||
|
||||
if (!ret)
|
||||
data->buf_filled = 1;
|
||||
else
|
||||
buf_copy_size = 0;
|
||||
|
||||
bpf_perf_event_output(ctx, &perf_SSL_events, BPF_F_CURRENT_CPU, data,
|
||||
EVENT_SIZE(buf_copy_size));
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("uretprobe/SSL_read")
|
||||
int BPF_URETPROBE(probe_SSL_read_exit) {
|
||||
return (SSL_exit(ctx, 0));
|
||||
}
|
||||
|
||||
SEC("uretprobe/SSL_write")
|
||||
int BPF_URETPROBE(probe_SSL_write_exit) {
|
||||
return (SSL_exit(ctx, 1));
|
||||
}
|
||||
|
||||
SEC("uprobe/do_handshake")
|
||||
int BPF_UPROBE(probe_SSL_do_handshake_enter, void *ssl) {
|
||||
u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
u32 pid = pid_tgid >> 32;
|
||||
u32 tid = (u32)pid_tgid;
|
||||
u64 ts = bpf_ktime_get_ns();
|
||||
u32 uid = bpf_get_current_uid_gid();
|
||||
|
||||
if (!trace_allowed(uid, pid)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* store arg info for later lookup */
|
||||
bpf_map_update_elem(&start_ns, &tid, &ts, BPF_ANY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("uretprobe/do_handshake")
|
||||
int BPF_URETPROBE(probe_SSL_do_handshake_exit) {
|
||||
u32 zero = 0;
|
||||
u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
u32 pid = pid_tgid >> 32;
|
||||
u32 tid = (u32)pid_tgid;
|
||||
u32 uid = bpf_get_current_uid_gid();
|
||||
u64 ts = bpf_ktime_get_ns();
|
||||
int ret = 0;
|
||||
|
||||
/* use kernel terminology here for tgid/pid: */
|
||||
u32 tgid = pid_tgid >> 32;
|
||||
|
||||
/* store arg info for later lookup */
|
||||
if (!trace_allowed(tgid, pid)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 *tsp = bpf_map_lookup_elem(&start_ns, &tid);
|
||||
if (tsp == 0)
|
||||
return 0;
|
||||
|
||||
ret = PT_REGS_RC(ctx);
|
||||
if (ret <= 0) // handshake failed
|
||||
return 0;
|
||||
|
||||
struct probe_SSL_data_t *data = bpf_map_lookup_elem(&ssl_data, &zero);
|
||||
if (!data)
|
||||
return 0;
|
||||
|
||||
data->timestamp_ns = ts;
|
||||
data->delta_ns = ts - *tsp;
|
||||
data->pid = pid;
|
||||
data->tid = tid;
|
||||
data->uid = uid;
|
||||
data->len = ret;
|
||||
data->buf_filled = 0;
|
||||
data->rw = 2;
|
||||
data->is_handshake = true;
|
||||
bpf_get_current_comm(&data->comm, sizeof(data->comm));
|
||||
bpf_map_delete_elem(&start_ns, &tid);
|
||||
|
||||
bpf_perf_event_output(ctx, &perf_SSL_events, BPF_F_CURRENT_CPU, data,
|
||||
EVENT_SIZE(0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
char LICENSE[] SEC("license") = "GPL";
|
||||
452
30-sslsniff/sslsniff.c
Normal file
452
30-sslsniff/sslsniff.c
Normal file
@@ -0,0 +1,452 @@
|
||||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
// Copyright (c) 2023 Yusheng Zheng
|
||||
//
|
||||
// Based on sslsniff from BCC by Adrian Lopez & Mark Drayton.
|
||||
// 15-Aug-2023 Yusheng Zheng Created this.
|
||||
#include <argp.h>
|
||||
#include <bpf/bpf.h>
|
||||
#include <bpf/libbpf.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sslsniff.skel.h"
|
||||
#include "sslsniff.h"
|
||||
|
||||
#define INVALID_UID -1
|
||||
#define INVALID_PID -1
|
||||
#define DEFAULT_BUFFER_SIZE 8192
|
||||
|
||||
#define __ATTACH_UPROBE(skel, binary_path, sym_name, prog_name, is_retprobe) \
|
||||
do { \
|
||||
LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts, .func_name = #sym_name, \
|
||||
.retprobe = is_retprobe); \
|
||||
skel->links.prog_name = bpf_program__attach_uprobe_opts( \
|
||||
skel->progs.prog_name, env.pid, binary_path, 0, &uprobe_opts); \
|
||||
} while (false)
|
||||
|
||||
#define __CHECK_PROGRAM(skel, prog_name) \
|
||||
do { \
|
||||
if (!skel->links.prog_name) { \
|
||||
perror("no program attached for " #prog_name); \
|
||||
return -errno; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define __ATTACH_UPROBE_CHECKED(skel, binary_path, sym_name, prog_name, \
|
||||
is_retprobe) \
|
||||
do { \
|
||||
__ATTACH_UPROBE(skel, binary_path, sym_name, prog_name, is_retprobe); \
|
||||
__CHECK_PROGRAM(skel, prog_name); \
|
||||
} while (false)
|
||||
|
||||
#define ATTACH_UPROBE_CHECKED(skel, binary_path, sym_name, prog_name) \
|
||||
__ATTACH_UPROBE_CHECKED(skel, binary_path, sym_name, prog_name, false)
|
||||
#define ATTACH_URETPROBE_CHECKED(skel, binary_path, sym_name, prog_name) \
|
||||
__ATTACH_UPROBE_CHECKED(skel, binary_path, sym_name, prog_name, true)
|
||||
|
||||
volatile sig_atomic_t exiting = 0;
|
||||
|
||||
const char *argp_program_version = "sslsniff 0.1";
|
||||
const char *argp_program_bug_address = "https://github.com/iovisor/bcc/tree/master/libbpf-tools";
|
||||
const char argp_program_doc[] =
|
||||
"Sniff SSL data.\n"
|
||||
"\n"
|
||||
"USAGE: sslsniff [OPTIONS]\n"
|
||||
"\n"
|
||||
"EXAMPLES:\n"
|
||||
" ./sslsniff # sniff OpenSSL and GnuTLS functions\n"
|
||||
" ./sslsniff -p 181 # sniff PID 181 only\n"
|
||||
" ./sslsniff -u 1000 # sniff only UID 1000\n"
|
||||
" ./sslsniff -c curl # sniff curl command only\n"
|
||||
" ./sslsniff --no-openssl # don't show OpenSSL calls\n"
|
||||
" ./sslsniff --no-gnutls # don't show GnuTLS calls\n"
|
||||
" ./sslsniff --no-nss # don't show NSS calls\n"
|
||||
" ./sslsniff --hexdump # show data as hex instead of trying to "
|
||||
"decode it as UTF-8\n"
|
||||
" ./sslsniff -x # show process UID and TID\n"
|
||||
" ./sslsniff -l # show function latency\n"
|
||||
" ./sslsniff -l --handshake # show SSL handshake latency\n"
|
||||
" ./sslsniff --extra-lib openssl:/path/libssl.so.1.1 # sniff extra "
|
||||
"library\n";
|
||||
|
||||
struct env {
|
||||
pid_t pid;
|
||||
int uid;
|
||||
bool extra;
|
||||
char *comm;
|
||||
bool openssl;
|
||||
bool gnutls;
|
||||
bool nss;
|
||||
bool hexdump;
|
||||
bool latency;
|
||||
bool handshake;
|
||||
char *extra_lib;
|
||||
} env = {
|
||||
.uid = INVALID_UID,
|
||||
.pid = INVALID_PID,
|
||||
.openssl = true,
|
||||
.gnutls = true,
|
||||
.nss = true,
|
||||
.comm = NULL,
|
||||
};
|
||||
|
||||
#define HEXDUMP_KEY 1000
|
||||
#define HANDSHAKE_KEY 1002
|
||||
#define EXTRA_LIB_KEY 1003
|
||||
|
||||
static const struct argp_option opts[] = {
|
||||
{"pid", 'p', "PID", 0, "Sniff this PID only."},
|
||||
{"uid", 'u', "UID", 0, "Sniff this UID only."},
|
||||
{"extra", 'x', NULL, 0, "Show extra fields (UID, TID)"},
|
||||
{"comm", 'c', "COMMAND", 0, "Sniff only commands matching string."},
|
||||
{"no-openssl", 'o', NULL, 0, "Do not show OpenSSL calls."},
|
||||
{"no-gnutls", 'g', NULL, 0, "Do not show GnuTLS calls."},
|
||||
{"no-nss", 'n', NULL, 0, "Do not show NSS calls."},
|
||||
{"hexdump", HEXDUMP_KEY, NULL, 0,
|
||||
"Show data as hexdump instead of trying to decode it as UTF-8"},
|
||||
{"latency", 'l', NULL, 0, "Show function latency"},
|
||||
{"handshake", HANDSHAKE_KEY, NULL, 0,
|
||||
"Show SSL handshake latency, enabled only if latency option is on."},
|
||||
{"verbose", 'v', NULL, 0, "Verbose debug output"},
|
||||
{ NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" },
|
||||
{},
|
||||
};
|
||||
|
||||
static bool verbose = false;
|
||||
|
||||
static error_t parse_arg(int key, char *arg, struct argp_state *state) {
|
||||
switch (key) {
|
||||
case 'p':
|
||||
env.pid = atoi(arg);
|
||||
break;
|
||||
case 'u':
|
||||
env.uid = atoi(arg);
|
||||
break;
|
||||
case 'x':
|
||||
env.extra = true;
|
||||
break;
|
||||
case 'c':
|
||||
env.comm = strdup(arg);
|
||||
break;
|
||||
case 'o':
|
||||
env.openssl = false;
|
||||
break;
|
||||
case 'g':
|
||||
env.gnutls = false;
|
||||
break;
|
||||
case 'n':
|
||||
env.nss = false;
|
||||
break;
|
||||
case 'l':
|
||||
env.latency = true;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
case HEXDUMP_KEY:
|
||||
env.hexdump = true;
|
||||
break;
|
||||
case HANDSHAKE_KEY:
|
||||
env.handshake = true;
|
||||
break;
|
||||
case 'h':
|
||||
argp_state_help(state, stderr, ARGP_HELP_STD_HELP);
|
||||
break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PERF_BUFFER_PAGES 16
|
||||
#define PERF_POLL_TIMEOUT_MS 100
|
||||
#define warn(...) fprintf(stderr, __VA_ARGS__)
|
||||
|
||||
static struct argp argp = {
|
||||
opts,
|
||||
parse_arg,
|
||||
NULL,
|
||||
argp_program_doc
|
||||
};
|
||||
|
||||
static int libbpf_print_fn(enum libbpf_print_level level, const char *format,
|
||||
va_list args) {
|
||||
if (level == LIBBPF_DEBUG && !verbose)
|
||||
return 0;
|
||||
return vfprintf(stderr, format, args);
|
||||
}
|
||||
|
||||
static void handle_lost_events(void *ctx, int cpu, __u64 lost_cnt) {
|
||||
warn("lost %llu events on CPU #%d\n", lost_cnt, cpu);
|
||||
}
|
||||
|
||||
static void sig_int(int signo) {
|
||||
exiting = 1;
|
||||
}
|
||||
|
||||
int attach_openssl(struct sslsniff_bpf *skel, const char *lib) {
|
||||
ATTACH_UPROBE_CHECKED(skel, lib, SSL_write, probe_SSL_rw_enter);
|
||||
ATTACH_URETPROBE_CHECKED(skel, lib, SSL_write, probe_SSL_write_exit);
|
||||
ATTACH_UPROBE_CHECKED(skel, lib, SSL_read, probe_SSL_rw_enter);
|
||||
ATTACH_URETPROBE_CHECKED(skel, lib, SSL_read, probe_SSL_read_exit);
|
||||
|
||||
if (env.latency && env.handshake) {
|
||||
ATTACH_UPROBE_CHECKED(skel, lib, SSL_do_handshake,
|
||||
probe_SSL_do_handshake_enter);
|
||||
ATTACH_URETPROBE_CHECKED(skel, lib, SSL_do_handshake,
|
||||
probe_SSL_do_handshake_exit);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int attach_gnutls(struct sslsniff_bpf *skel, const char *lib) {
|
||||
ATTACH_UPROBE_CHECKED(skel, lib, gnutls_record_send, probe_SSL_rw_enter);
|
||||
ATTACH_URETPROBE_CHECKED(skel, lib, gnutls_record_send, probe_SSL_write_exit);
|
||||
ATTACH_UPROBE_CHECKED(skel, lib, gnutls_record_recv, probe_SSL_rw_enter);
|
||||
ATTACH_URETPROBE_CHECKED(skel, lib, gnutls_record_recv, probe_SSL_read_exit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int attach_nss(struct sslsniff_bpf *skel, const char *lib) {
|
||||
ATTACH_UPROBE_CHECKED(skel, lib, PR_Write, probe_SSL_rw_enter);
|
||||
ATTACH_URETPROBE_CHECKED(skel, lib, PR_Write, probe_SSL_write_exit);
|
||||
ATTACH_UPROBE_CHECKED(skel, lib, PR_Send, probe_SSL_rw_enter);
|
||||
ATTACH_URETPROBE_CHECKED(skel, lib, PR_Send, probe_SSL_write_exit);
|
||||
ATTACH_UPROBE_CHECKED(skel, lib, PR_Read, probe_SSL_rw_enter);
|
||||
ATTACH_URETPROBE_CHECKED(skel, lib, PR_Read, probe_SSL_read_exit);
|
||||
ATTACH_UPROBE_CHECKED(skel, lib, PR_Recv, probe_SSL_rw_enter);
|
||||
ATTACH_URETPROBE_CHECKED(skel, lib, PR_Recv, probe_SSL_read_exit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the path of a library using ldconfig.
|
||||
*/
|
||||
char *find_library_path(const char *libname) {
|
||||
char cmd[128];
|
||||
static char path[512];
|
||||
FILE *fp;
|
||||
|
||||
// Construct the ldconfig command with grep
|
||||
snprintf(cmd, sizeof(cmd), "ldconfig -p | grep %s", libname);
|
||||
|
||||
// Execute the command and read the output
|
||||
fp = popen(cmd, "r");
|
||||
if (fp == NULL) {
|
||||
perror("Failed to run ldconfig");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Read the first line of output which should have the library path
|
||||
if (fgets(path, sizeof(path) - 1, fp) != NULL) {
|
||||
// Extract the path from the ldconfig output
|
||||
char *start = strrchr(path, '>');
|
||||
if (start && *(start + 1) == ' ') {
|
||||
memmove(path, start + 2, strlen(start + 2) + 1);
|
||||
char *end = strchr(path, '\n');
|
||||
if (end) {
|
||||
*end = '\0'; // Null-terminate the path
|
||||
}
|
||||
pclose(fp);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
pclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void buf_to_hex(const uint8_t *buf, size_t len, char *hex_str) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
sprintf(hex_str + 2 * i, "%02x", buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to print the event from the perf buffer
|
||||
void print_event(struct probe_SSL_data_t *event, const char *evt) {
|
||||
static unsigned long long start =
|
||||
0; // Use static to retain value across function calls
|
||||
char buf[MAX_BUF_SIZE + 1] = {0}; // +1 for null terminator
|
||||
unsigned int buf_size;
|
||||
|
||||
if (event->len <= MAX_BUF_SIZE) {
|
||||
buf_size = event->len;
|
||||
} else {
|
||||
buf_size = MAX_BUF_SIZE;
|
||||
}
|
||||
|
||||
if (event->buf_filled == 1) {
|
||||
memcpy(buf, event->buf, buf_size);
|
||||
} else {
|
||||
buf_size = 0;
|
||||
}
|
||||
|
||||
if (env.comm && strcmp(env.comm, event->comm) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (start == 0) {
|
||||
start = event->timestamp_ns;
|
||||
}
|
||||
double time_s = (double)(event->timestamp_ns - start) / 1000000000;
|
||||
|
||||
char lat_str[10];
|
||||
if (event->delta_ns) {
|
||||
snprintf(lat_str, sizeof(lat_str), "%.3f",
|
||||
(double)event->delta_ns / 1000000);
|
||||
} else {
|
||||
strncpy(lat_str, "N/A", sizeof(lat_str));
|
||||
}
|
||||
|
||||
char s_mark[] = "----- DATA -----";
|
||||
char e_mark[64] = "----- END DATA -----";
|
||||
if (buf_size < event->len) {
|
||||
snprintf(e_mark, sizeof(e_mark),
|
||||
"----- END DATA (TRUNCATED, %d bytes lost) -----",
|
||||
event->len - buf_size);
|
||||
}
|
||||
|
||||
char *rw_event[] = {
|
||||
"READ/RECV",
|
||||
"WRITE/SEND",
|
||||
"HANDSHAKE"
|
||||
};
|
||||
|
||||
#define BASE_FMT "%-12s %-18.9f %-16s %-7d %-6d"
|
||||
#define EXTRA_FMT " %-7d %-7d"
|
||||
#define LATENCY_FMT " %-7s"
|
||||
|
||||
if (env.extra && env.latency) {
|
||||
printf(BASE_FMT EXTRA_FMT LATENCY_FMT, rw_event[event->rw],
|
||||
time_s, event->comm, event->pid,
|
||||
event->len, event->uid, event->tid, lat_str);
|
||||
} else if (env.extra) {
|
||||
printf(BASE_FMT EXTRA_FMT, rw_event[event->rw], time_s, event->comm, event->pid,
|
||||
event->len, event->uid, event->tid);
|
||||
} else if (env.latency) {
|
||||
printf(BASE_FMT LATENCY_FMT, rw_event[event->rw], time_s, event->comm, event->pid,
|
||||
event->len, lat_str);
|
||||
} else {
|
||||
printf(BASE_FMT, rw_event[event->rw], time_s, event->comm, event->pid,
|
||||
event->len);
|
||||
}
|
||||
|
||||
if (buf_size != 0) {
|
||||
if (env.hexdump) {
|
||||
// 2 characters for each byte + null terminator
|
||||
char hex_data[MAX_BUF_SIZE * 2 + 1] = {0};
|
||||
buf_to_hex((uint8_t *)buf, buf_size, hex_data);
|
||||
|
||||
printf("\n%s\n", s_mark);
|
||||
for (size_t i = 0; i < strlen(hex_data); i += 32) {
|
||||
printf("%.32s\n", hex_data + i);
|
||||
}
|
||||
printf("%s\n\n", e_mark);
|
||||
} else {
|
||||
printf("\n%s\n%s\n%s\n\n", s_mark, buf, e_mark);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_event(void *ctx, int cpu, void *data, __u32 data_size) {
|
||||
struct probe_SSL_data_t *e = data;
|
||||
if (e->is_handshake) {
|
||||
print_event(e, "perf_SSL_do_handshake");
|
||||
} else {
|
||||
print_event(e, "perf_SSL_rw");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
LIBBPF_OPTS(bpf_object_open_opts, open_opts);
|
||||
struct sslsniff_bpf *obj = NULL;
|
||||
struct perf_buffer *pb = NULL;
|
||||
int err;
|
||||
|
||||
err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
libbpf_set_print(libbpf_print_fn);
|
||||
|
||||
obj = sslsniff_bpf__open_opts(&open_opts);
|
||||
if (!obj) {
|
||||
warn("failed to open BPF object\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
obj->rodata->targ_uid = env.uid;
|
||||
obj->rodata->targ_pid = env.pid == INVALID_PID ? 0 : env.pid;
|
||||
|
||||
err = sslsniff_bpf__load(obj);
|
||||
if (err) {
|
||||
warn("failed to load BPF object: %d\n", err);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (env.openssl) {
|
||||
char *openssl_path = find_library_path("libssl.so");
|
||||
printf("OpenSSL path: %s\n", openssl_path);
|
||||
attach_openssl(obj, "/lib/x86_64-linux-gnu/libssl.so.3");
|
||||
}
|
||||
if (env.gnutls) {
|
||||
char *gnutls_path = find_library_path("libgnutls.so");
|
||||
printf("GnuTLS path: %s\n", gnutls_path);
|
||||
attach_gnutls(obj, gnutls_path);
|
||||
}
|
||||
if (env.nss) {
|
||||
char *nss_path = find_library_path("libnspr4.so");
|
||||
printf("NSS path: %s\n", nss_path);
|
||||
attach_nss(obj, nss_path);
|
||||
}
|
||||
|
||||
pb = perf_buffer__new(bpf_map__fd(obj->maps.perf_SSL_events),
|
||||
PERF_BUFFER_PAGES, handle_event, handle_lost_events,
|
||||
NULL, NULL);
|
||||
if (!pb) {
|
||||
err = -errno;
|
||||
warn("failed to open perf buffer: %d\n", err);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (signal(SIGINT, sig_int) == SIG_ERR) {
|
||||
warn("can't set signal handler: %s\n", strerror(errno));
|
||||
err = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Print header
|
||||
printf("%-12s %-18s %-16s %-7s %-7s", "FUNC", "TIME(s)", "COMM", "PID",
|
||||
"LEN");
|
||||
if (env.extra) {
|
||||
printf(" %-7s %-7s", "UID", "TID");
|
||||
}
|
||||
if (env.latency) {
|
||||
printf(" %-7s", "LAT(ms)");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
while (!exiting) {
|
||||
err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS);
|
||||
if (err < 0 && err != -EINTR) {
|
||||
warn("error polling perf buffer: %s\n", strerror(-err));
|
||||
goto cleanup;
|
||||
}
|
||||
err = 0;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
perf_buffer__free(pb);
|
||||
sslsniff_bpf__destroy(obj);
|
||||
return err != 0;
|
||||
}
|
||||
26
30-sslsniff/sslsniff.h
Normal file
26
30-sslsniff/sslsniff.h
Normal file
@@ -0,0 +1,26 @@
|
||||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
// Copyright (c) 2023 Yusheng Zheng
|
||||
//
|
||||
// Based on sslsniff from BCC by Adrian Lopez & Mark Drayton.
|
||||
// 15-Aug-2023 Yusheng Zheng Created this.
|
||||
#ifndef __SSLSNIFF_H
|
||||
#define __SSLSNIFF_H
|
||||
|
||||
#define MAX_BUF_SIZE 8192
|
||||
#define TASK_COMM_LEN 16
|
||||
|
||||
struct probe_SSL_data_t {
|
||||
__u64 timestamp_ns;
|
||||
__u64 delta_ns;
|
||||
__u32 pid;
|
||||
__u32 tid;
|
||||
__u32 uid;
|
||||
__u32 len;
|
||||
int buf_filled;
|
||||
int rw;
|
||||
char comm[TASK_COMM_LEN];
|
||||
__u8 buf[MAX_BUF_SIZE];
|
||||
int is_handshake;
|
||||
};
|
||||
|
||||
#endif /* __SSLSNIFF_H */
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
582
print.html
582
print.html
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user