Update API of manipulation session

This commit is contained in:
luwenpeng
2024-04-01 17:13:26 +08:00
parent 772860c1be
commit a509f0ce3b
32 changed files with 1145 additions and 1347 deletions

View File

@@ -1,6 +1,7 @@
#include <assert.h>
#include "session_private.h"
#include "session.h"
#include "tcp_utils.h"
#define EX_KEY_MAX_LEN 64
@@ -20,7 +21,7 @@ struct ex_manager
static struct ex_manager g_ex_manager = {0};
/******************************************************************************
* session
* session set/get
******************************************************************************/
void session_init(struct session *sess)
@@ -28,7 +29,6 @@ void session_init(struct session *sess)
memset(sess, 0, sizeof(struct session));
}
// session id
void session_set_id(struct session *sess, uint64_t id)
{
sess->id = id;
@@ -39,28 +39,36 @@ uint64_t session_get_id(const struct session *sess)
return sess->id;
}
// session tuple6
void session_set_key(struct session *sess, const struct tuple6 *tuple)
void session_set_tuple(struct session *sess, const struct tuple6 *tuple)
{
memcpy(&sess->tuple, tuple, sizeof(struct tuple6));
}
const struct tuple6 *session_get0_key(const struct session *sess)
const struct tuple6 *session_get_tuple(const struct session *sess)
{
return &sess->tuple;
}
void session_set_key_dir(struct session *sess, enum session_dir dir)
void session_set_tuple_dir(struct session *sess, enum session_dir dir)
{
sess->tuple_dir = dir;
}
enum session_dir session_get_key_dir(const struct session *sess)
enum session_dir session_get_tuple_dir(const struct session *sess)
{
return sess->tuple_dir;
}
// session state
void session_set_cur_dir(struct session *sess, enum session_dir dir)
{
sess->cur_dir = dir;
}
enum session_dir session_get_cur_dir(const struct session *sess)
{
return sess->cur_dir;
}
void session_set_state(struct session *sess, enum session_state state)
{
sess->state = state;
@@ -71,7 +79,6 @@ enum session_state session_get_state(const struct session *sess)
return sess->state;
}
// session type
void session_set_type(struct session *sess, enum session_type type)
{
sess->type = type;
@@ -82,83 +89,85 @@ enum session_type session_get_type(const struct session *sess)
return sess->type;
}
// session dup traffic flag
void session_set_dup_traffic_flag(struct session *sess, enum dup_traffic_flag flag)
void session_set_dup_traffic(struct session *sess)
{
sess->dup_flag = flag;
sess->dup = 1;
}
enum dup_traffic_flag session_get_dup_traffic_flag(const struct session *sess)
int session_has_dup_traffic(const struct session *sess)
{
return sess->dup_flag;
return sess->dup;
}
// closing reason
void session_set_closing_reason(struct session *sess, enum closing_reason reason)
{
sess->closing_reason = reason;
sess->reason = reason;
}
enum closing_reason session_get_closing_reason(const struct session *sess)
{
return sess->closing_reason;
return sess->reason;
}
// session metrics
void session_inc_c2s_metrics(struct session *sess, uint64_t packets, uint64_t bytes)
void session_inc_metric(struct session *sess, enum session_metric_index idx, uint64_t val)
{
sess->c2s_bytes += bytes;
sess->c2s_packets += packets;
sess->metrics[idx] += val;
}
void session_inc_s2c_metrics(struct session *sess, uint64_t packets, uint64_t bytes)
void session_set_metric(struct session *sess, enum session_metric_index idx, uint64_t val)
{
sess->s2c_bytes += bytes;
sess->s2c_packets += packets;
sess->metrics[idx] = val;
}
uint64_t session_get_c2s_bytes(const struct session *sess)
uint64_t session_get_metric(const struct session *sess, enum session_metric_index idx)
{
return sess->c2s_bytes;
return sess->metrics[idx];
}
uint64_t session_get_s2c_bytes(const struct session *sess)
void session_set_timestamp(struct session *sess, enum session_timestamp_index idx, uint64_t timestamp)
{
return sess->s2c_bytes;
sess->timestamps[idx] = timestamp;
}
uint64_t session_get_c2s_packets(const struct session *sess)
uint64_t session_get_timestamp(const struct session *sess, enum session_timestamp_index idx)
{
return sess->c2s_packets;
return sess->timestamps[idx];
}
uint64_t session_get_s2c_packets(const struct session *sess)
void session_set_packet(struct session *sess, enum session_packet_index idx, const struct packet *pkt)
{
return sess->s2c_packets;
if (idx == SESSION_PACKET_CURRENT)
{
sess->packets[idx] = pkt;
}
else
{
if (sess->packets[idx])
{
return;
}
sess->packets[idx] = packet_dup(pkt);
}
}
// session timestamp
void session_set_new_time(struct session *sess, uint64_t timestamp)
void session_clean_packet(struct session *sess, enum session_packet_index idx)
{
sess->create_time = timestamp;
if (idx == SESSION_PACKET_CURRENT)
{
sess->packets[idx] = NULL;
}
else
{
packet_free((struct packet *)sess->packets[idx]);
sess->packets[idx] = NULL;
}
}
void session_set_last_time(struct session *sess, uint64_t timestamp)
const struct packet *session_get_packet(const struct session *sess, enum session_packet_index idx)
{
sess->last_time = timestamp;
return sess->packets[idx];
}
uint64_t session_get_new_time(const struct session *sess)
{
return sess->create_time;
}
uint64_t session_get_last_time(const struct session *sess)
{
return sess->last_time;
}
// session user data
void session_set_user_data(struct session *sess, void *user_data)
{
sess->user_data = user_data;
@@ -170,204 +179,236 @@ void *session_get_user_data(const struct session *sess)
}
/******************************************************************************
* session packet
* to string
******************************************************************************/
void session_set_c2s_1st_pkt(struct session *sess, const struct packet *pkt)
const char *closing_reason_to_str(enum closing_reason reason)
{
if (sess->c2s_1st_pkt)
switch (reason)
{
return;
}
sess->c2s_1st_pkt = packet_dup(pkt);
}
void session_set_s2c_1st_pkt(struct session *sess, const struct packet *pkt)
{
if (sess->s2c_1st_pkt)
{
return;
}
sess->s2c_1st_pkt = packet_dup(pkt);
}
const struct packet *session_get0_c2s_1st_pkt(const struct session *sess)
{
return sess->c2s_1st_pkt;
}
const struct packet *session_get0_s2c_1st_pkt(const struct session *sess)
{
return sess->s2c_1st_pkt;
}
const struct packet *session_get0_1st_pkt(const struct session *sess)
{
const struct packet *c2s_1st_pkt = session_get0_c2s_1st_pkt(sess);
if (c2s_1st_pkt)
{
return c2s_1st_pkt;
}
else
{
return session_get0_s2c_1st_pkt(sess);
case CLOSING_BY_TIMEOUT:
return "closing by timeout";
case CLOSING_BY_EVICTED:
return "closing by evicted";
case CLOSING_BY_CLIENT_FIN:
return "closing by client FIN";
case CLOSING_BY_CLIENT_RST:
return "closing by client RST";
case CLOSING_BY_SERVER_FIN:
return "closing by server FIN";
case CLOSING_BY_SERVER_RST:
return "closing by server RST";
default:
return "unknown";
}
}
// session current packet
void session_set0_cur_pkt(struct session *sess, const struct packet *pkt)
const char *session_state_to_str(enum session_state state)
{
sess->cur_pkt = pkt;
switch (state)
{
case SESSION_STATE_INIT:
return "init";
case SESSION_STATE_OPENING:
return "opening";
case SESSION_STATE_ACTIVE:
return "active";
case SESSION_STATE_CLOSING:
return "closing";
case SESSION_STATE_DISCARD:
return "discard";
case SESSION_STATE_CLOSED:
return "closed";
default:
return "unknown";
}
}
const struct packet *session_get0_cur_pkt(const struct session *sess)
const char *session_type_to_str(enum session_type type)
{
return sess->cur_pkt;
switch (type)
{
case SESSION_TYPE_TCP:
return "TCP";
case SESSION_TYPE_UDP:
return "UDP";
default:
return "unknown";
}
}
// session current dir
void session_set_cur_dir(struct session *sess, enum session_dir dir)
const char *session_dir_to_str(enum session_dir dir)
{
sess->cur_dir = dir;
switch (dir)
{
case SESSION_DIR_C2S:
return "C2S";
case SESSION_DIR_S2C:
return "S2C";
default:
return "unknown";
}
}
enum session_dir session_get_cur_dir(const struct session *sess)
void session_dump(struct session *sess)
{
return sess->cur_dir;
char buffer[1024] = {0};
tuple6_to_str(session_get_tuple(sess), buffer, sizeof(buffer));
printf("session id : %" PRIu64 "\n", session_get_id(sess));
printf("session tuple : %s\n", buffer);
printf("session tuple dir : %s\n", session_dir_to_str(session_get_tuple_dir(sess)));
printf("session state : %s\n", session_state_to_str(session_get_state(sess)));
printf("session type : %s\n", session_type_to_str(session_get_type(sess)));
printf("session dup traffic : %d\n", session_has_dup_traffic(sess));
printf("session closing reason : %s\n", closing_reason_to_str(session_get_closing_reason(sess)));
printf("session C2S packets : %" PRIu64 "\n", session_get_metric(sess, SESSION_METRIC_C2S_PACKETS));
printf("session C2S bytes : %" PRIu64 "\n", session_get_metric(sess, SESSION_METRIC_C2S_BYTES));
printf("session S2C packets : %" PRIu64 "\n", session_get_metric(sess, SESSION_METRIC_S2C_PACKETS));
printf("session S2C bytes : %" PRIu64 "\n", session_get_metric(sess, SESSION_METRIC_S2C_BYTES));
printf("session new time : %" PRIu64 "\n", session_get_timestamp(sess, SESSION_TIMESTAMP_NEW));
printf("session last time : %" PRIu64 "\n", session_get_timestamp(sess, SESSION_TIMESTAMP_LAST));
printf("session current packet ptr : %p\n", (void *)session_get_packet(sess, SESSION_PACKET_CURRENT));
printf("session current packet dir : %s\n", session_dir_to_str(session_get_cur_dir(sess)));
printf("session ex data: \n");
for (uint8_t i = 0; i < g_ex_manager.count; i++)
{
printf(" ex_idx: %d, ex_key: %s, ex_data: %p\n", i, g_ex_manager.schemas[i].key, sess->ex_data[i]);
}
}
/******************************************************************************
* session tcp reassembly
* tcp session
******************************************************************************/
int session_new_tcp_reassembly(struct session *sess, struct tcp_reassembly_options *opts)
static void tcp_sub_state_update(struct tcp_session *tcp_sess, enum session_dir dir, uint8_t tcp_flags)
{
sess->c2s_reassembly = tcp_reassembly_new(opts);
if (sess->c2s_reassembly == NULL)
if (tcp_flags & TH_SYN)
{
tcp_sess->sub_state |= (tcp_flags & TH_ACK) ? TCP_SYN_ACK_RCVD : TCP_SYN_RCVD;
}
if (tcp_flags & TH_FIN)
{
tcp_sess->sub_state |= dir == SESSION_DIR_C2S ? TCP_C2S_FIN_RCVD : TCP_S2C_FIN_RCVD;
}
if (tcp_flags & TH_RST)
{
/*
* https://www.rfc-editor.org/rfc/rfc5961#section-3.2
*
* If the RST bit is set and the sequence number exactly matches the
* next expected sequence number (RCV.NXT), then TCP MUST reset the
* connection.
*/
uint16_t curr_seq = dir == SESSION_DIR_C2S ? tcp_sess->c2s_seq : tcp_sess->s2c_seq;
uint16_t expect_seq = dir == SESSION_DIR_C2S ? tcp_sess->s2c_ack : tcp_sess->c2s_ack;
// if fin is received, the expected sequence number should be increased by 1
expect_seq += dir == SESSION_DIR_C2S ? (tcp_sess->sub_state & TCP_S2C_FIN_RCVD ? 1 : 0) : (tcp_sess->sub_state & TCP_C2S_FIN_RCVD ? 1 : 0);
if (curr_seq == expect_seq)
{
tcp_sess->sub_state |= dir == SESSION_DIR_C2S ? TCP_C2S_RST_RCVD : TCP_S2C_RST_RCVD;
}
// RST is unverified if the sequence number is not as expected
else
{
tcp_sess->sub_state |= dir == SESSION_DIR_C2S ? TCP_C2S_UNVERIFIED_RST_RCVD : TCP_S2C_UNVERIFIED_RST_RCVD;
}
}
}
int tcp_sess_init(struct session *sess, struct tcp_reassembly_options *opts)
{
struct tcp_session *tcp_sess = &sess->data.tcp;
tcp_sess->c2s_data_queue = tcp_reassembly_new(opts);
if (tcp_sess->c2s_data_queue == NULL)
{
return -1;
}
sess->s2c_reassembly = tcp_reassembly_new(opts);
if (sess->s2c_reassembly == NULL)
tcp_sess->s2c_data_queue = tcp_reassembly_new(opts);
if (tcp_sess->s2c_data_queue == NULL)
{
tcp_reassembly_free(sess->c2s_reassembly);
tcp_reassembly_free(tcp_sess->c2s_data_queue);
return -1;
}
return 0;
}
void session_free_tcp_reassembly(struct session *sess)
void tcp_sess_clean(struct session *sess)
{
tcp_reassembly_free(sess->c2s_reassembly);
tcp_reassembly_free(sess->s2c_reassembly);
struct tcp_session *tcp_sess = &sess->data.tcp;
tcp_reassembly_free(tcp_sess->c2s_data_queue);
tcp_reassembly_free(tcp_sess->s2c_data_queue);
}
void session_init_tcp_seq(struct session *sess, uint32_t syn_seq)
void tcp_data_enqueue(struct session *sess, const struct pkt_layer *tcp_layer, uint64_t now)
{
if (sess->type != SESSION_TYPE_TCP)
{
assert(0);
return;
}
struct tcp_session *tcp_sess = &sess->data.tcp;
struct tcphdr *hdr = (struct tcphdr *)tcp_layer->hdr_ptr;
uint8_t flags = tcp_hdr_get_flags(hdr);
if (sess->cur_dir == SESSION_DIR_C2S)
{
sess->c2s_seq = syn_seq;
tcp_reassembly_init(sess->c2s_reassembly, syn_seq);
tcp_sess->c2s_seq = tcp_hdr_get_seq(hdr);
tcp_sess->c2s_ack = tcp_hdr_get_ack(hdr);
if (flags & TH_SYN)
{
tcp_reassembly_init(tcp_sess->c2s_data_queue, tcp_sess->c2s_seq);
}
tcp_reassembly_insert(tcp_sess->c2s_data_queue, tcp_sess->c2s_seq, tcp_layer->pld_ptr, tcp_layer->pld_len, now);
}
else
{
sess->s2c_seq = syn_seq;
tcp_reassembly_init(sess->s2c_reassembly, syn_seq);
tcp_sess->s2c_seq = tcp_hdr_get_seq(hdr);
tcp_sess->s2c_ack = tcp_hdr_get_ack(hdr);
if (flags & TH_SYN)
{
tcp_reassembly_init(tcp_sess->s2c_data_queue, tcp_sess->s2c_seq);
}
tcp_reassembly_insert(tcp_sess->s2c_data_queue, tcp_sess->s2c_seq, tcp_layer->pld_ptr, tcp_layer->pld_len, now);
}
tcp_sub_state_update(tcp_sess, sess->cur_dir, flags);
}
void session_set_tcp_seq_ack(struct session *sess, uint32_t seq, uint32_t ack)
void tcp_data_dequeue(struct session *sess, uint32_t len)
{
if (sess->type != SESSION_TYPE_TCP)
{
assert(0);
return;
}
struct tcp_session *tcp_sess = &sess->data.tcp;
if (sess->cur_dir == SESSION_DIR_C2S)
{
sess->c2s_seq = seq;
sess->c2s_ack = ack;
tcp_reassembly_consume(tcp_sess->c2s_data_queue, len);
}
else
{
sess->s2c_seq = seq;
sess->s2c_ack = ack;
tcp_reassembly_consume(tcp_sess->s2c_data_queue, len);
}
}
void session_insert_tcp_payload(struct session *sess, uint32_t seq, const char *payload, uint32_t len, uint64_t now)
const char *tcp_data_peek(struct session *sess, uint32_t *len)
{
if (sess->type != SESSION_TYPE_TCP)
{
assert(0);
return;
}
struct tcp_session *tcp_sess = &sess->data.tcp;
if (sess->cur_dir == SESSION_DIR_C2S)
{
tcp_reassembly_insert(sess->c2s_reassembly, seq, payload, len, now);
return tcp_reassembly_peek(tcp_sess->c2s_data_queue, len);
}
else
{
tcp_reassembly_insert(sess->s2c_reassembly, seq, payload, len, now);
return tcp_reassembly_peek(tcp_sess->s2c_data_queue, len);
}
}
void session_expire_tcp_payload(struct session *sess, uint64_t now)
void tcp_data_expire(struct session *sess, uint64_t now)
{
if (sess->type != SESSION_TYPE_TCP)
{
assert(0);
return;
}
struct tcp_session *tcp_sess = &sess->data.tcp;
tcp_reassembly_expire(sess->c2s_reassembly, now);
tcp_reassembly_expire(sess->s2c_reassembly, now);
}
const char *session_peek_tcp_payload(struct session *sess, uint32_t *len)
{
if (sess->type != SESSION_TYPE_TCP)
{
*len = 0;
assert(0);
return NULL;
}
if (sess->cur_dir == SESSION_DIR_C2S)
{
return tcp_reassembly_peek(sess->c2s_reassembly, len);
}
else
{
return tcp_reassembly_peek(sess->s2c_reassembly, len);
}
}
void session_consume_tcp_payload(struct session *sess, uint32_t len)
{
if (sess->type != SESSION_TYPE_TCP)
{
assert(0);
return;
}
if (sess->cur_dir == SESSION_DIR_C2S)
{
tcp_reassembly_consume(sess->c2s_reassembly, len);
}
else
{
tcp_reassembly_consume(sess->s2c_reassembly, len);
}
tcp_reassembly_expire(tcp_sess->c2s_data_queue, now);
tcp_reassembly_expire(tcp_sess->s2c_data_queue, now);
}
/******************************************************************************
@@ -471,115 +512,3 @@ void session_free_all_ex_data(struct session *sess)
}
}
}
/******************************************************************************
* session dump
******************************************************************************/
const char *session_closing_reason_to_str(enum closing_reason reason)
{
switch (reason)
{
case CLOSING_BY_TIMEOUT:
return "closing by timeout";
case CLOSING_BY_EVICTED:
return "closing by evicted";
case CLOSING_BY_CLIENT_FIN:
return "closing by client FIN";
case CLOSING_BY_CLIENT_RST:
return "closing by client RST";
case CLOSING_BY_SERVER_FIN:
return "closing by server FIN";
case CLOSING_BY_SERVER_RST:
return "closing by server RST";
default:
return "unknown";
}
}
const char *session_state_to_str(enum session_state state)
{
switch (state)
{
case SESSION_STATE_INIT:
return "init";
case SESSION_STATE_OPENING:
return "opening";
case SESSION_STATE_ACTIVE:
return "active";
case SESSION_STATE_CLOSING:
return "closing";
case SESSION_STATE_DISCARD:
return "discard";
case SESSION_STATE_CLOSED:
return "closed";
default:
return "unknown";
}
}
const char *session_type_to_str(enum session_type type)
{
switch (type)
{
case SESSION_TYPE_TCP:
return "TCP";
case SESSION_TYPE_UDP:
return "UDP";
default:
return "unknown";
}
}
const char *session_dir_to_str(enum session_dir dir)
{
switch (dir)
{
case SESSION_DIR_C2S:
return "C2S";
case SESSION_DIR_S2C:
return "S2C";
default:
return "unknown";
}
}
const char *dup_traffic_flag_to_str(enum dup_traffic_flag flag)
{
switch (flag)
{
case DUP_TRAFFIC_YES:
return "YES";
case DUP_TRAFFIC_NO:
return "NO";
default:
return "unknown";
}
}
void session_dump(struct session *sess)
{
char buffer[1024] = {0};
tuple6_to_str(session_get0_key(sess), buffer, sizeof(buffer));
printf("session id : %" PRIu64 "\n", session_get_id(sess));
printf("session key : %s\n", buffer);
printf("session key dir : %s\n", session_dir_to_str(session_get_key_dir(sess)));
printf("session state : %s\n", session_state_to_str(session_get_state(sess)));
printf("session type : %s\n", session_type_to_str(session_get_type(sess)));
printf("session dup traffic flag : %s\n", dup_traffic_flag_to_str(session_get_dup_traffic_flag(sess)));
printf("session closing reason : %s\n", session_closing_reason_to_str(session_get_closing_reason(sess)));
printf("session C2S packets : %" PRIu64 "\n", session_get_c2s_packets(sess));
printf("session C2S bytes : %" PRIu64 "\n", session_get_c2s_bytes(sess));
printf("session S2C packets : %" PRIu64 "\n", session_get_s2c_packets(sess));
printf("session S2C bytes : %" PRIu64 "\n", session_get_s2c_bytes(sess));
printf("session create time : %" PRIu64 "\n", session_get_new_time(sess));
printf("session last time : %" PRIu64 "\n", session_get_last_time(sess));
printf("session current packet ptr : %p\n", (void *)session_get0_cur_pkt(sess));
printf("session current packet dir : %s\n", session_dir_to_str(session_get_cur_dir(sess)));
printf("session ex data: \n");
for (uint8_t i = 0; i < g_ex_manager.count; i++)
{
printf(" ex_idx: %d, ex_key: %s, ex_data: %p\n", i, g_ex_manager.schemas[i].key, sess->ex_data[i]);
}
}