bpf/accesslog/syscalls/transfer.h (144 lines of code) (raw):
// Licensed to Apache Software Foundation (ASF) under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Apache Software Foundation (ASF) licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include "api.h"
#include "socket_opts.h"
#include "socket_data.h"
#include "socket_reader.h"
#include "queue.h"
#include "protocol_analyzer.h"
#include "../common/connection.h"
#include "../common/data_args.h"
// openssl read or write
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 10000);
__type(key, __u64);
__type(value, struct sock_data_args_t);
} openssl_sock_data_args SEC(".maps");
struct socket_detail_t {
// basic information
__u64 connection_id;
__u64 random_id;
__u64 data_id;
// socket data operation times
__u64 start_nacs;
__u64 end_nacs;
// l2-l4
__u32 l4_duration;
__u32 l3_duration;
__u32 l3_local_duration;
__u32 l3_output_duration;
__u32 l3_resolve_mac_duration;
__u32 l3_net_filter_duration;
__u32 l2_duration;
__u32 l2_ready_send_duration;
__u32 l2_send_duration;
__u32 l2_package_to_queue_time;
__u32 l3_total_recv_time;
__u32 ifindex;
__u64 l4_package_rcv_from_queue_time;
__u64 l4_total_package_size;
__u8 l2_enter_queue_count;
__u8 l4_package_count;
__u8 l4_retransmit_package_count;
__u8 l3_resolve_mac_count;
__u8 l3_net_filter_count;
__u8 op_func_name;
__u8 data_protocol;
__u8 ssl;
};
DATA_QUEUE(socket_detail_queue);
static __always_inline void process_write_data(void *ctx, __u64 id, struct sock_data_args_t *args, ssize_t bytes_count,
__u32 data_direction, const bool vecs, __u8 func_name, bool ssl) {
__u64 curr_nacs = bpf_ktime_get_ns();
__u32 tgid = (__u32)(id >> 32);
if (vecs && args->iovlen <= 0) {
return;
}
if (args->fd < 0) {
return;
}
if (bytes_count <= 0) {
return;
}
// get current connection
struct active_connection_t *conn = get_or_create_active_conn(ctx, tgid, args->fd, func_name, args->sk_role);
if (conn == NULL) {
return;
}
// only trace ipv4, v6, or unknown
if (family_should_trace(conn->socket_family) == false) {
return;
}
// process the ssl request if the fd not found
struct sock_data_args_t *ssl_data_args = bpf_map_lookup_elem(&openssl_sock_data_args, &id);
if (ssl_data_args != NULL && ssl_data_args->fd == 0) {
ssl_data_args->fd = args->fd;
conn->ssl = true;
} else if (ssl) {
conn->ssl = true;
}
// if the cannot getting the package size and count, then try to get it from the data args
if (args->total_package_size == 0 && args->package_count == 0) {
args->total_package_size = bytes_count;
args->package_count = 1;
}
// if the protocol or role is unknown in the connection and the current data content is plaintext
// then try to use protocol analyzer to analyze request or response and protocol type
__u32 msg_type = 0;
if ((conn->role == CONNECTION_ROLE_TYPE_UNKNOWN || conn->protocol == 0) && conn->ssl == ssl) {
struct socket_buffer_reader_t *buf_reader = read_socket_data(args->buf, args->iovec, bytes_count);
if (buf_reader != NULL) {
msg_type = analyze_protocol(buf_reader->buffer, buf_reader->data_len, &conn->protocol);
// if send request data to remote address or receive response data from remote address
// then, recognized current connection is client
if ((msg_type == CONNECTION_MESSAGE_TYPE_REQUEST && data_direction == SOCK_DATA_DIRECTION_EGRESS) ||
(msg_type == CONNECTION_MESSAGE_TYPE_RESPONSE && data_direction == SOCK_DATA_DIRECTION_INGRESS)) {
conn->role = CONNECTION_ROLE_TYPE_CLIENT;
// if send response data to remote address or receive request data from remote address
// then, recognized current connection is server
} else if ((msg_type == CONNECTION_MESSAGE_TYPE_RESPONSE && data_direction == SOCK_DATA_DIRECTION_EGRESS) ||
(msg_type == CONNECTION_MESSAGE_TYPE_REQUEST && data_direction == SOCK_DATA_DIRECTION_INGRESS)) {
conn->role = CONNECTION_ROLE_TYPE_SERVER;
}
}
}
__u64 conid = gen_tgid_fd(tgid, args->fd);
// upload the socket detail, detail can only be send when the ssl are same:
// 1. when the SSL connection sends SSL(unencrypted) message
// 2. when the not SSL connection sends plain data
if (conn->ssl == ssl) {
struct socket_detail_t *detail;
detail = rover_reserve_buf(&socket_detail_queue, sizeof(*detail));
if (detail != NULL) {
detail->connection_id = conid;
detail->random_id = conn->random_id;
detail->data_id = args->data_id;
detail->start_nacs = args->start_nacs;
detail->end_nacs = curr_nacs;
detail->l4_duration = args->exit_l4_time - args->enter_l4_time;
detail->l3_duration = args->l3_duration;
detail->l3_local_duration = args->l3_local_duration;
detail->l3_output_duration = args->l3_output_duration;
detail->l3_resolve_mac_duration = args->total_resolve_mac_time;
detail->l3_net_filter_duration = args->total_net_filter_time;
detail->l2_duration = args->l2_duration;
detail->l2_ready_send_duration = args->l2_ready_send_duration;
detail->l2_send_duration = args->l2_send_duration;
detail->ifindex = args->ifindex;
detail->l4_total_package_size = args->total_package_size;
detail->l4_package_count = args->package_count;
detail->l4_retransmit_package_count = args->retransmit_package_count;
detail->l3_resolve_mac_count = args->total_resolve_mac_count;
detail->l3_net_filter_count = args->total_net_filter_count;
detail->op_func_name = func_name;
detail->data_protocol = conn->protocol;
detail->ssl = conn->ssl;
detail->l2_package_to_queue_time = args->total_package_to_queue_time;
detail->l3_total_recv_time = args->l3_rcv_duration;
detail->l2_enter_queue_count = args->l2_enter_queue_count;
detail->l4_package_rcv_from_queue_time = args->total_package_receive_from_queue_time;
rover_submit_buf(ctx, &socket_detail_queue, detail, sizeof(*detail));
}
}
// upload the socket data if need
struct upload_data_args *upload_data_args = generate_socket_upload_args();
if (upload_data_args != NULL) {
upload_data_args->start_time = args->start_nacs;
upload_data_args->end_time = curr_nacs;
upload_data_args->con_id = conid;
upload_data_args->random_id = conn->random_id;
upload_data_args->socket_data_id = args->data_id;
upload_data_args->socket_data_iovec = args->iovec;
upload_data_args->socket_data_iovlen = args->iovlen;
upload_data_args->bytes_count = bytes_count;
upload_data_args->socket_data_buf = args->buf;
upload_data_args->data_direction = data_direction;
upload_data_args->connection_protocol = conn->protocol;
upload_data_args->connection_ssl = conn->ssl;
upload_data_args->socket_ssl_buffer_force_unfinished = args->ssl_buffer_force_unfinished;
upload_data_args->connection_skip_data_upload = conn->skip_data_upload;
upload_data_args->socket_data_ssl = ssl;
upload_socket_data(ctx, upload_data_args);
};
}