diff --git a/plugins/in_ebpf/in_ebpf.c b/plugins/in_ebpf/in_ebpf.c index c4371700384..96d97a3f18b 100644 --- a/plugins/in_ebpf/in_ebpf.c +++ b/plugins/in_ebpf/in_ebpf.c @@ -24,7 +24,9 @@ #include "traces/traces.h" int trace_register(struct flb_in_ebpf_context *ctx, const char *name, - struct bpf_object *obj, trace_event_handler_t handler) { + void *skel, struct bpf_object *obj, + trace_skel_destroy_func_t skel_destroy, + trace_event_handler_t handler) { struct trace_context *trace; struct bpf_map *map, *events_map; int map_fd; @@ -38,7 +40,9 @@ int trace_register(struct flb_in_ebpf_context *ctx, const char *name, trace = &ctx->traces[ctx->trace_count]; trace->name = name; + trace->skel = skel; trace->obj = obj; + trace->skel_destroy = skel_destroy; trace->handler = handler; bpf_object__for_each_map(map, obj) { @@ -102,7 +106,8 @@ int trace_setup(struct flb_in_ebpf_context *ctx, const char *trace_name) { return -1; } - if (trace_register(ctx, trace_name, obj, reg->handler) != 0) { + if (trace_register(ctx, trace_name, skel, obj, + reg->skel_destroy, reg->handler) != 0) { flb_plg_error(ctx->ins, "failed to register trace handler for: %s", trace_name); reg->skel_destroy(skel); return -1; @@ -137,6 +142,7 @@ static int in_ebpf_collect(struct flb_input_instance *ins, struct flb_config *co } static int in_ebpf_init(struct flb_input_instance *ins, struct flb_config *config, void *data) { + int i; struct flb_in_ebpf_context *ctx; struct mk_list *head; struct flb_kv *kv; @@ -170,6 +176,14 @@ static int in_ebpf_init(struct flb_input_instance *ins, struct flb_config *confi flb_plg_debug(ctx->ins, "processing trace: %s", trace_name); if (trace_setup(ctx, trace_name) != 0) { flb_plg_error(ctx->ins, "failed to configure trace: %s", trace_name); + for (i = 0; i < ctx->trace_count; i++) { + ring_buffer__free(ctx->traces[i].rb); + if (ctx->traces[i].skel_destroy) { + ctx->traces[i].skel_destroy(ctx->traces[i].skel); + } + } + flb_log_event_encoder_destroy(ctx->log_encoder); + flb_free(ctx->traces); flb_free(ctx); return -1; } @@ -185,7 +199,9 @@ static int in_ebpf_init(struct flb_input_instance *ins, struct flb_config *confi flb_plg_error(ctx->ins, "failed to set up collector"); for (int i = 0; i < ctx->trace_count; i++) { ring_buffer__free(ctx->traces[i].rb); - bpf_object__close(ctx->traces[i].obj); + if (ctx->traces[i].skel_destroy) { + ctx->traces[i].skel_destroy(ctx->traces[i].skel); + } } flb_log_event_encoder_destroy(ctx->log_encoder); flb_free(ctx); @@ -217,7 +233,9 @@ static int in_ebpf_exit(void *in_context, struct flb_config *config) { for (int i = 0; i < ctx->trace_count; i++) { ring_buffer__free(ctx->traces[i].rb); - bpf_object__close(ctx->traces[i].obj); + if (ctx->traces[i].skel_destroy) { + ctx->traces[i].skel_destroy(ctx->traces[i].skel); + } } if (ctx->log_encoder) { @@ -244,7 +262,7 @@ static struct flb_config_map config_map[] = { { FLB_CONFIG_MAP_STR, "Trace", NULL, FLB_CONFIG_MAP_MULT, FLB_FALSE, 0, - "Set the eBPF trace to enable (for example, bind, malloc, signal, vfs). Can be set multiple times" + "Set the eBPF trace to enable (for example, bind, malloc, signal, vfs, tcp). Can be set multiple times" }, /* EOF */ {0} diff --git a/plugins/in_ebpf/traces/includes/common/encoder.h b/plugins/in_ebpf/traces/includes/common/encoder.h index ae0c0b33ff0..91d7b4379e2 100644 --- a/plugins/in_ebpf/traces/includes/common/encoder.h +++ b/plugins/in_ebpf/traces/includes/common/encoder.h @@ -19,6 +19,12 @@ static inline char *event_type_to_string(enum event_type type) { return "bind"; case EVENT_TYPE_VFS: return "vfs"; + case EVENT_TYPE_LISTEN: + return "listen"; + case EVENT_TYPE_ACCEPT: + return "accept"; + case EVENT_TYPE_CONNECT: + return "connect"; default: return "unknown"; } diff --git a/plugins/in_ebpf/traces/includes/common/events.h b/plugins/in_ebpf/traces/includes/common/events.h index 34051c4e0f4..42eb60b5eef 100644 --- a/plugins/in_ebpf/traces/includes/common/events.h +++ b/plugins/in_ebpf/traces/includes/common/events.h @@ -13,6 +13,9 @@ enum event_type { EVENT_TYPE_MEM, // For memory operations EVENT_TYPE_BIND, // Added event type for bind operations EVENT_TYPE_VFS, + EVENT_TYPE_LISTEN, + EVENT_TYPE_ACCEPT, + EVENT_TYPE_CONNECT, }; enum vfs_op { @@ -35,40 +38,35 @@ enum memop { MEMOP_PVALLOC, }; -/* Common fields for all events */ struct event_common { - __u64 timestamp_raw; // Event timestamp in nanoseconds - __u32 pid; // Process ID - __u32 tid; // Thread ID - __u32 uid; // User ID - __u32 gid; // Group ID - __u64 mntns_id; // Mount namespace ID - char comm[TASK_COMM_LEN]; // Command name (process name) + __u64 timestamp_raw; + __u32 pid; + __u32 tid; + __u32 uid; + __u32 gid; + __u64 mntns_id; + char comm[TASK_COMM_LEN]; }; -/* Specific fields for execve events */ struct execve_event { - __u32 tpid; // Target Process ID (for execve) - char filename[PATH_MAX]; // Filename being executed - char argv[256]; // Arguments (simplified for example) - __u32 argc; // Argument count + __u32 tpid; + char filename[PATH_MAX]; + char argv[256]; + __u32 argc; }; -/* Specific fields for signal events */ struct signal_event { - __u32 tpid; // Target Process ID (for signal) - int sig_raw; // Signal number - int error_raw; // Error code (for failed syscalls) + __u32 tpid; + int sig_raw; + int error_raw; }; -/* Specific fields for memory operations */ struct mem_event { - enum memop operation; // Memory operation type (malloc, free, etc.) - __u64 addr; // Address of the operation - __u64 size; // Size of the memory operation (for malloc) + enum memop operation; + __u64 addr; + __u64 size; }; -/* Specific fields for bind events */ struct bind_event { struct { __u16 port; @@ -93,17 +91,48 @@ struct vfs_event { int error_raw; }; -/* The main event structure */ +struct tcp_addr { + __u16 port; + __u8 version; + __u8 proto_raw; + union { + __u32 v4; + __u32 v6[4]; + } addr_raw; +}; + +struct listen_event { + int fd; + int backlog; + int error_raw; +}; + +struct accept_event { + int fd; + int new_fd; + struct tcp_addr peer; + int error_raw; +}; + +struct connect_event { + int fd; + struct tcp_addr remote; + int error_raw; +}; + struct event { enum event_type type; // Type of event (execve, signal, mem, bind) struct event_common common; // Common fields for all events union { struct execve_event execve; struct signal_event signal; - struct mem_event mem; // Memory event details - struct bind_event bind; // Bind event details - struct vfs_event vfs; // VFS event details - } details; // Event-specific details + struct mem_event mem; + struct bind_event bind; + struct vfs_event vfs; + struct listen_event listen; + struct accept_event accept; + struct connect_event connect; + } details; }; #endif // TRACE_EVENTS_H diff --git a/plugins/in_ebpf/traces/tcp/bpf.c b/plugins/in_ebpf/traces/tcp/bpf.c new file mode 100644 index 00000000000..c5b39e452fd --- /dev/null +++ b/plugins/in_ebpf/traces/tcp/bpf.c @@ -0,0 +1,373 @@ +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) + +#include + +#define _LINUX_TYPES_H +#define _LINUX_POSIX_TYPES_H + +#include +#include +#include + +#include +#include +#include +#include + +#include "common/events.h" + +#ifndef AF_UNSPEC +#define AF_UNSPEC 0 +#endif + +#ifndef AF_INET +#define AF_INET 2 +#endif + +#ifndef AF_INET6 +#define AF_INET6 10 +#endif + +#define MAX_ENTRIES 10240 + +struct listen_args { + int fd; + int backlog; + gadget_mntns_id mntns_id; +}; + +struct accept_args { + int fd; + const struct sockaddr *upeer_sockaddr; + __u32 addrlen; + gadget_mntns_id mntns_id; +}; + +struct connect_args { + int fd; + __u32 addrlen; + struct tcp_addr remote; + gadget_mntns_id mntns_id; +}; + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, MAX_ENTRIES); + __type(key, __u32); + __type(value, struct listen_args); +} listens SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, MAX_ENTRIES); + __type(key, __u32); + __type(value, struct accept_args); +} accepts SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, MAX_ENTRIES); + __type(key, __u32); + __type(value, struct connect_args); +} connects SEC(".maps"); + +GADGET_TRACER_MAP(events, 1024 * 256); + +static __always_inline void fill_common(struct event *event, __u64 mntns_id) +{ + __u64 pid_tgid; + __u64 uid_gid; + + pid_tgid = bpf_get_current_pid_tgid(); + uid_gid = bpf_get_current_uid_gid(); + + event->common.timestamp_raw = bpf_ktime_get_boot_ns(); + event->common.pid = (__u32) (pid_tgid >> 32); + event->common.tid = (__u32) pid_tgid; + event->common.uid = (__u32) uid_gid; + event->common.gid = (__u32) (uid_gid >> 32); + event->common.mntns_id = mntns_id; + bpf_get_current_comm(event->common.comm, sizeof(event->common.comm)); +} + +static __always_inline void parse_sockaddr(const struct sockaddr *addr, + __u32 addrlen, + struct tcp_addr *out) +{ + int ret; + sa_family_t family; + + if (!out) { + return; + } + + __builtin_memset(out, 0, sizeof(*out)); + + if (!addr || addrlen < sizeof(sa_family_t)) { + return; + } + + family = AF_UNSPEC; + ret = bpf_probe_read_user(&family, sizeof(family), &addr->sa_family); + if (ret != 0) { + return; + } + + if (family == AF_INET) { + struct sockaddr_in in4 = {}; + + if (addrlen < sizeof(in4)) { + return; + } + + ret = bpf_probe_read_user(&in4, sizeof(in4), addr); + if (ret != 0) { + return; + } + + out->version = 4; + out->port = bpf_ntohs(in4.sin_port); + out->addr_raw.v4 = in4.sin_addr.s_addr; + } + else if (family == AF_INET6) { + struct sockaddr_in6 in6 = {}; + + if (addrlen < sizeof(in6)) { + return; + } + + ret = bpf_probe_read_user(&in6, sizeof(in6), addr); + if (ret != 0) { + return; + } + + out->version = 6; + out->port = bpf_ntohs(in6.sin6_port); + __builtin_memcpy(out->addr_raw.v6, + &in6.sin6_addr.in6_u.u6_addr32, + sizeof(out->addr_raw.v6)); + } +} + +SEC("tracepoint/syscalls/sys_enter_listen") +int trace_tcp_listen_enter(struct syscall_trace_enter *ctx) +{ + __u32 tid; + __u64 pid_tgid; + __u64 mntns_id; + struct listen_args args = {}; + + mntns_id = gadget_get_mntns_id(); + if (gadget_should_discard_mntns_id(mntns_id)) { + return 0; + } + + pid_tgid = bpf_get_current_pid_tgid(); + tid = (__u32) pid_tgid; + + args.fd = (int) ctx->args[0]; + args.backlog = (int) ctx->args[1]; + args.mntns_id = mntns_id; + + bpf_map_update_elem(&listens, &tid, &args, BPF_ANY); + + return 0; +} + +SEC("tracepoint/syscalls/sys_exit_listen") +int trace_tcp_listen_exit(struct syscall_trace_exit *ctx) +{ + __u32 tid; + __u64 pid_tgid; + struct listen_args *args; + struct event *event; + + pid_tgid = bpf_get_current_pid_tgid(); + tid = (__u32) pid_tgid; + + args = bpf_map_lookup_elem(&listens, &tid); + if (!args) { + return 0; + } + + event = gadget_reserve_buf(&events, sizeof(*event)); + if (!event) { + bpf_map_delete_elem(&listens, &tid); + return 0; + } + + fill_common(event, args->mntns_id); + + event->type = EVENT_TYPE_LISTEN; + event->details.listen.fd = args->fd; + event->details.listen.backlog = args->backlog; + event->details.listen.error_raw = ctx->ret < 0 ? -ctx->ret : 0; + + gadget_submit_buf(ctx, &events, event, sizeof(*event)); + bpf_map_delete_elem(&listens, &tid); + + return 0; +} + +static __always_inline int handle_accept_enter(struct syscall_trace_enter *ctx) +{ + __u32 tid; + __u64 pid_tgid; + __u64 mntns_id; + int addrlen_val; + int *upeer_addrlen; + struct accept_args args = {}; + + mntns_id = gadget_get_mntns_id(); + if (gadget_should_discard_mntns_id(mntns_id)) { + return 0; + } + + pid_tgid = bpf_get_current_pid_tgid(); + tid = (__u32) pid_tgid; + + args.fd = (int) ctx->args[0]; + args.upeer_sockaddr = (const struct sockaddr *) ctx->args[1]; + args.mntns_id = mntns_id; + args.addrlen = 0; + + upeer_addrlen = (int *) ctx->args[2]; + if (upeer_addrlen) { + addrlen_val = 0; + if (bpf_probe_read_user(&addrlen_val, sizeof(addrlen_val), upeer_addrlen) == 0 && + addrlen_val > 0) { + args.addrlen = (__u32) addrlen_val; + } + } + + bpf_map_update_elem(&accepts, &tid, &args, BPF_ANY); + + return 0; +} + +static __always_inline int handle_accept_exit(struct syscall_trace_exit *ctx) +{ + __u32 tid; + __u64 pid_tgid; + struct accept_args *args; + struct event *event; + + pid_tgid = bpf_get_current_pid_tgid(); + tid = (__u32) pid_tgid; + + args = bpf_map_lookup_elem(&accepts, &tid); + if (!args) { + return 0; + } + + event = gadget_reserve_buf(&events, sizeof(*event)); + if (!event) { + bpf_map_delete_elem(&accepts, &tid); + return 0; + } + + fill_common(event, args->mntns_id); + + event->type = EVENT_TYPE_ACCEPT; + event->details.accept.fd = args->fd; + event->details.accept.new_fd = (int) ctx->ret; + event->details.accept.error_raw = ctx->ret < 0 ? -ctx->ret : 0; + if (ctx->ret >= 0) { + parse_sockaddr(args->upeer_sockaddr, args->addrlen, + &event->details.accept.peer); + } + + gadget_submit_buf(ctx, &events, event, sizeof(*event)); + bpf_map_delete_elem(&accepts, &tid); + + return 0; +} + +SEC("tracepoint/syscalls/sys_enter_accept") +int trace_tcp_accept_enter(struct syscall_trace_enter *ctx) +{ + return handle_accept_enter(ctx); +} + +SEC("tracepoint/syscalls/sys_exit_accept") +int trace_tcp_accept_exit(struct syscall_trace_exit *ctx) +{ + return handle_accept_exit(ctx); +} + +SEC("tracepoint/syscalls/sys_enter_accept4") +int trace_tcp_accept4_enter(struct syscall_trace_enter *ctx) +{ + return handle_accept_enter(ctx); +} + +SEC("tracepoint/syscalls/sys_exit_accept4") +int trace_tcp_accept4_exit(struct syscall_trace_exit *ctx) +{ + return handle_accept_exit(ctx); +} + +SEC("tracepoint/syscalls/sys_enter_connect") +int trace_tcp_connect_enter(struct syscall_trace_enter *ctx) +{ + __u32 tid; + __u64 pid_tgid; + __u64 mntns_id; + struct connect_args args = {}; + const struct sockaddr *uservaddr; + + mntns_id = gadget_get_mntns_id(); + if (gadget_should_discard_mntns_id(mntns_id)) { + return 0; + } + + pid_tgid = bpf_get_current_pid_tgid(); + tid = (__u32) pid_tgid; + + args.fd = (int) ctx->args[0]; + uservaddr = (const struct sockaddr *) ctx->args[1]; + args.addrlen = (__u32) ctx->args[2]; + args.mntns_id = mntns_id; + parse_sockaddr(uservaddr, args.addrlen, &args.remote); + + bpf_map_update_elem(&connects, &tid, &args, BPF_ANY); + + return 0; +} + +SEC("tracepoint/syscalls/sys_exit_connect") +int trace_tcp_connect_exit(struct syscall_trace_exit *ctx) +{ + __u32 tid; + __u64 pid_tgid; + struct connect_args *args; + struct event *event; + + pid_tgid = bpf_get_current_pid_tgid(); + tid = (__u32) pid_tgid; + + args = bpf_map_lookup_elem(&connects, &tid); + if (!args) { + return 0; + } + + event = gadget_reserve_buf(&events, sizeof(*event)); + if (!event) { + bpf_map_delete_elem(&connects, &tid); + return 0; + } + + fill_common(event, args->mntns_id); + + event->type = EVENT_TYPE_CONNECT; + event->details.connect.fd = args->fd; + event->details.connect.remote = args->remote; + event->details.connect.error_raw = ctx->ret < 0 ? -ctx->ret : 0; + + gadget_submit_buf(ctx, &events, event, sizeof(*event)); + bpf_map_delete_elem(&connects, &tid); + + return 0; +} + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; diff --git a/plugins/in_ebpf/traces/tcp/handler.c b/plugins/in_ebpf/traces/tcp/handler.c new file mode 100644 index 00000000000..fcfdaa99f83 --- /dev/null +++ b/plugins/in_ebpf/traces/tcp/handler.c @@ -0,0 +1,191 @@ +#include +#include +#include + +#include "common/events.h" +#include "common/event_context.h" +#include "common/encoder.h" + +#include "handler.h" + +static int encode_tcp_addr(struct flb_log_event_encoder *log_encoder, + const char *key_prefix, + struct tcp_addr *addr) +{ + int ret; + char key[64]; + + snprintf(key, sizeof(key), "%s_port", key_prefix); + ret = flb_log_event_encoder_append_body_cstring(log_encoder, key); + if (ret != FLB_EVENT_ENCODER_SUCCESS) { + return -1; + } + ret = flb_log_event_encoder_append_body_uint16(log_encoder, addr->port); + if (ret != FLB_EVENT_ENCODER_SUCCESS) { + return -1; + } + + snprintf(key, sizeof(key), "%s_version", key_prefix); + ret = flb_log_event_encoder_append_body_cstring(log_encoder, key); + if (ret != FLB_EVENT_ENCODER_SUCCESS) { + return -1; + } + ret = flb_log_event_encoder_append_body_uint32(log_encoder, addr->version); + if (ret != FLB_EVENT_ENCODER_SUCCESS) { + return -1; + } + + if (addr->version == 6) { + int i; + + for (i = 0; i < 4; i++) { + snprintf(key, sizeof(key), "%s_addr_v6_%d", key_prefix, i); + ret = flb_log_event_encoder_append_body_cstring(log_encoder, key); + if (ret != FLB_EVENT_ENCODER_SUCCESS) { + return -1; + } + + ret = flb_log_event_encoder_append_body_uint32(log_encoder, + addr->addr_raw.v6[i]); + if (ret != FLB_EVENT_ENCODER_SUCCESS) { + return -1; + } + } + } + else { + snprintf(key, sizeof(key), "%s_addr_v4", key_prefix); + ret = flb_log_event_encoder_append_body_cstring(log_encoder, key); + if (ret != FLB_EVENT_ENCODER_SUCCESS) { + return -1; + } + + ret = flb_log_event_encoder_append_body_uint32(log_encoder, addr->addr_raw.v4); + if (ret != FLB_EVENT_ENCODER_SUCCESS) { + return -1; + } + } + + return 0; +} + +int encode_tcp_event(struct flb_input_instance *ins, + struct flb_log_event_encoder *log_encoder, + const struct event *ev) +{ + int ret; + + ret = flb_log_event_encoder_begin_record(log_encoder); + if (ret != FLB_EVENT_ENCODER_SUCCESS) { + return -1; + } + + ret = encode_common_fields(log_encoder, ev); + if (ret != FLB_EVENT_ENCODER_SUCCESS) { + flb_log_event_encoder_rollback_record(log_encoder); + return -1; + } + + if (ev->type == EVENT_TYPE_LISTEN) { + ret = flb_log_event_encoder_append_body_cstring(log_encoder, "fd"); + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = flb_log_event_encoder_append_body_int32(log_encoder, ev->details.listen.fd); + } + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = flb_log_event_encoder_append_body_cstring(log_encoder, "backlog"); + } + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = flb_log_event_encoder_append_body_int32(log_encoder, ev->details.listen.backlog); + } + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = flb_log_event_encoder_append_body_cstring(log_encoder, "error_raw"); + } + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = flb_log_event_encoder_append_body_int32(log_encoder, ev->details.listen.error_raw); + } + } + else if (ev->type == EVENT_TYPE_ACCEPT) { + ret = flb_log_event_encoder_append_body_cstring(log_encoder, "fd"); + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = flb_log_event_encoder_append_body_int32(log_encoder, ev->details.accept.fd); + } + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = flb_log_event_encoder_append_body_cstring(log_encoder, "new_fd"); + } + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = flb_log_event_encoder_append_body_int32(log_encoder, ev->details.accept.new_fd); + } + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = encode_tcp_addr(log_encoder, "peer", (struct tcp_addr *) &ev->details.accept.peer); + } + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = flb_log_event_encoder_append_body_cstring(log_encoder, "error_raw"); + } + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = flb_log_event_encoder_append_body_int32(log_encoder, ev->details.accept.error_raw); + } + } + else if (ev->type == EVENT_TYPE_CONNECT) { + ret = flb_log_event_encoder_append_body_cstring(log_encoder, "fd"); + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = flb_log_event_encoder_append_body_int32(log_encoder, ev->details.connect.fd); + } + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = encode_tcp_addr(log_encoder, "remote", (struct tcp_addr *) &ev->details.connect.remote); + } + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = flb_log_event_encoder_append_body_cstring(log_encoder, "error_raw"); + } + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = flb_log_event_encoder_append_body_int32(log_encoder, ev->details.connect.error_raw); + } + } + else { + ret = -1; + } + + if (ret != FLB_EVENT_ENCODER_SUCCESS) { + flb_log_event_encoder_rollback_record(log_encoder); + return -1; + } + + ret = flb_log_event_encoder_commit_record(log_encoder); + if (ret != FLB_EVENT_ENCODER_SUCCESS) { + return -1; + } + + return 0; +} + +int trace_tcp_handler(void *ctx, void *data, size_t data_sz) +{ + struct trace_event_context *event_ctx = (struct trace_event_context *) ctx; + struct event *ev = (struct event *) data; + struct flb_log_event_encoder *encoder = event_ctx->log_encoder; + int ret; + + if (data_sz < sizeof(struct event)) { + return -1; + } + + if (ev->type != EVENT_TYPE_LISTEN && + ev->type != EVENT_TYPE_ACCEPT && + ev->type != EVENT_TYPE_CONNECT) { + return -1; + } + + ret = encode_tcp_event(event_ctx->ins, encoder, ev); + if (ret != 0) { + return -1; + } + + ret = flb_input_log_append(event_ctx->ins, NULL, 0, + encoder->output_buffer, + encoder->output_length); + if (ret == -1) { + return -1; + } + + flb_log_event_encoder_reset(encoder); + + return 0; +} diff --git a/plugins/in_ebpf/traces/tcp/handler.h b/plugins/in_ebpf/traces/tcp/handler.h new file mode 100644 index 00000000000..7f8e60892b0 --- /dev/null +++ b/plugins/in_ebpf/traces/tcp/handler.h @@ -0,0 +1,12 @@ +#ifndef TRACE_TCP_HANDLER_H +#define TRACE_TCP_HANDLER_H + +#include +#include + +int trace_tcp_handler(void *ctx, void *data, size_t data_sz); +int encode_tcp_event(struct flb_input_instance *ins, + struct flb_log_event_encoder *log_encoder, + const struct event *ev); + +#endif diff --git a/plugins/in_ebpf/traces/traces.h b/plugins/in_ebpf/traces/traces.h index 9e5a9a0ae87..925b686d421 100644 --- a/plugins/in_ebpf/traces/traces.h +++ b/plugins/in_ebpf/traces/traces.h @@ -7,11 +7,13 @@ #include "generated/trace_malloc.skel.h" #include "generated/trace_bind.skel.h" #include "generated/trace_vfs.skel.h" +#include "generated/trace_tcp.skel.h" #include "bind/handler.h" #include "signal/handler.h" // Include signal handler #include "malloc/handler.h" // Include malloc handler #include "vfs/handler.h" +#include "tcp/handler.h" /* Skeleton function pointer types */ typedef void *(*trace_skel_open_func_t)(void); @@ -26,7 +28,9 @@ typedef int (*trace_event_handler_t)(void *ctx, void *data, size_t data_sz); struct trace_context { const char *name; struct ring_buffer *rb; + void *skel; struct bpf_object *obj; + trace_skel_destroy_func_t skel_destroy; trace_event_handler_t handler; }; @@ -61,12 +65,14 @@ DEFINE_GET_BPF_OBJECT(trace_signal) DEFINE_GET_BPF_OBJECT(trace_malloc) DEFINE_GET_BPF_OBJECT(trace_bind) DEFINE_GET_BPF_OBJECT(trace_vfs) +DEFINE_GET_BPF_OBJECT(trace_tcp) static struct trace_registration trace_table[] = { REGISTER_TRACE(trace_signal, trace_signal_handler), REGISTER_TRACE(trace_malloc, trace_malloc_handler), REGISTER_TRACE(trace_bind, trace_bind_handler), REGISTER_TRACE(trace_vfs, trace_vfs_handler), + REGISTER_TRACE(trace_tcp, trace_tcp_handler), }; #endif // TRACE_TRACES_H diff --git a/tests/runtime/CMakeLists.txt b/tests/runtime/CMakeLists.txt index 132faa84d57..1f0c008b6c9 100644 --- a/tests/runtime/CMakeLists.txt +++ b/tests/runtime/CMakeLists.txt @@ -164,9 +164,16 @@ if(FLB_IN_EBPF) "../../plugins/in_ebpf/traces/malloc/handler.c" ) + add_ebpf_handler_test( + "tcp" + "in_ebpf_tcp_handler.c" + "../../plugins/in_ebpf/traces/tcp/handler.c" + ) + add_dependencies(flb-rt-in_ebpf_bind_handler fluent-bit-static) add_dependencies(flb-rt-in_ebpf_signal_handler fluent-bit-static) add_dependencies(flb-rt-in_ebpf_malloc_handler fluent-bit-static) + add_dependencies(flb-rt-in_ebpf_tcp_handler fluent-bit-static) endif() diff --git a/tests/runtime/in_ebpf_tcp_handler.c b/tests/runtime/in_ebpf_tcp_handler.c new file mode 100644 index 00000000000..6a11cc45b32 --- /dev/null +++ b/tests/runtime/in_ebpf_tcp_handler.c @@ -0,0 +1,142 @@ +#include +#include + +#include +#include +#include + +#include "flb_tests_runtime.h" + +#include "../../plugins/in_ebpf/traces/includes/common/event_context.h" +#include "../../plugins/in_ebpf/traces/includes/common/events.h" +#include "../../plugins/in_ebpf/traces/tcp/handler.h" + +struct test_context { + struct trace_event_context event_ctx; + struct flb_input_instance *ins; + struct flb_log_event_decoder *decoder; +}; + +static struct test_context *init_test_context(void) +{ + struct test_context *ctx; + + ctx = flb_calloc(1, sizeof(struct test_context)); + if (!ctx) { + return NULL; + } + + ctx->ins = flb_calloc(1, sizeof(struct flb_input_instance)); + if (!ctx->ins) { + flb_free(ctx); + return NULL; + } + + ctx->event_ctx.log_encoder = flb_log_event_encoder_create(FLB_LOG_EVENT_FORMAT_DEFAULT); + if (!ctx->event_ctx.log_encoder) { + flb_free(ctx->ins); + flb_free(ctx); + return NULL; + } + + ctx->decoder = flb_log_event_decoder_create(NULL, 0); + if (!ctx->decoder) { + flb_log_event_encoder_destroy(ctx->event_ctx.log_encoder); + flb_free(ctx->ins); + flb_free(ctx); + return NULL; + } + + ctx->ins->context = &ctx->event_ctx; + ctx->event_ctx.ins = ctx->ins; + + return ctx; +} + +static void cleanup_test_context(struct test_context *ctx) +{ + if (!ctx) { + return; + } + + if (ctx->decoder) { + flb_log_event_decoder_destroy(ctx->decoder); + } + + if (ctx->event_ctx.log_encoder) { + flb_log_event_encoder_destroy(ctx->event_ctx.log_encoder); + } + + if (ctx->ins) { + flb_free(ctx->ins); + } + + flb_free(ctx); +} + +void test_tcp_event_encoding(void) +{ + struct test_context *ctx; + struct event listen_ev = {0}; + struct event accept_ev = {0}; + struct event connect_ev = {0}; + int ret; + + ctx = init_test_context(); + TEST_CHECK(ctx != NULL); + + listen_ev.type = EVENT_TYPE_LISTEN; + listen_ev.common.pid = 100; + listen_ev.common.tid = 101; + strncpy(listen_ev.common.comm, "tcpd", sizeof(listen_ev.common.comm)); + listen_ev.details.listen.fd = 3; + listen_ev.details.listen.backlog = 128; + listen_ev.details.listen.error_raw = 0; + + ret = encode_tcp_event(ctx->ins, ctx->event_ctx.log_encoder, &listen_ev); + TEST_CHECK(ret == 0); + + accept_ev.type = EVENT_TYPE_ACCEPT; + accept_ev.common.pid = 100; + accept_ev.common.tid = 101; + strncpy(accept_ev.common.comm, "tcpd", sizeof(accept_ev.common.comm)); + accept_ev.details.accept.fd = 3; + accept_ev.details.accept.new_fd = 5; + accept_ev.details.accept.peer.version = 4; + accept_ev.details.accept.peer.port = 443; + accept_ev.details.accept.peer.addr_raw.v4 = 0x0100007f; + accept_ev.details.accept.error_raw = 0; + + ret = encode_tcp_event(ctx->ins, ctx->event_ctx.log_encoder, &accept_ev); + TEST_CHECK(ret == 0); + + connect_ev.type = EVENT_TYPE_CONNECT; + connect_ev.common.pid = 200; + connect_ev.common.tid = 201; + strncpy(connect_ev.common.comm, "curl", sizeof(connect_ev.common.comm)); + connect_ev.details.connect.fd = 7; + connect_ev.details.connect.remote.version = 4; + connect_ev.details.connect.remote.port = 80; + connect_ev.details.connect.remote.addr_raw.v4 = 0x0101a8c0; + connect_ev.details.connect.error_raw = 0; + + ret = encode_tcp_event(ctx->ins, ctx->event_ctx.log_encoder, &connect_ev); + TEST_CHECK(ret == 0); + + connect_ev.details.connect.remote.version = 6; + connect_ev.details.connect.remote.port = 8080; + connect_ev.details.connect.remote.addr_raw.v6[0] = 0x20010db8; + connect_ev.details.connect.remote.addr_raw.v6[1] = 0; + connect_ev.details.connect.remote.addr_raw.v6[2] = 0; + connect_ev.details.connect.remote.addr_raw.v6[3] = 1; + + ret = encode_tcp_event(ctx->ins, ctx->event_ctx.log_encoder, &connect_ev); + TEST_CHECK(ret == 0); + + cleanup_test_context(ctx); +} + +TEST_LIST = { + {"tcp_event_encoding", test_tcp_event_encoding}, + {NULL, NULL} +};