Refactor TCP reassembly, the session knows where the TCP segment comes from: raw packet or tcp segment queue

This commit is contained in:
luwenpeng
2024-04-02 16:21:39 +08:00
parent a509f0ce3b
commit e8e60cee6d
25 changed files with 678 additions and 1419 deletions

View File

@@ -2,6 +2,7 @@
#include "session.h"
#include "tcp_utils.h"
#include "tcp_reassembly.h"
#define EX_KEY_MAX_LEN 64
@@ -178,6 +179,43 @@ void *session_get_user_data(const struct session *sess)
return sess->user_data;
}
struct tcp_segment *session_get_tcp_segment(struct session *sess)
{
struct tcp_pcb *pcb = &sess->tcp_pcb;
if (pcb->order_seg.data != NULL && pcb->order_seg.len > 0)
{
return &pcb->order_seg;
}
if (session_get_cur_dir(sess) == SESSION_DIR_C2S)
{
return tcp_reassembly_pop(pcb->c2s_assembler);
}
else
{
return tcp_reassembly_pop(pcb->s2c_assembler);
}
}
void session_free_tcp_segment(struct session *sess, struct tcp_segment *seg)
{
if (seg == NULL)
{
return;
}
if (seg == &sess->tcp_pcb.order_seg)
{
sess->tcp_pcb.order_seg.data = NULL;
sess->tcp_pcb.order_seg.len = 0;
return;
}
else
{
tcp_segment_free(seg);
}
}
/******************************************************************************
* to string
******************************************************************************/
@@ -277,140 +315,6 @@ void session_dump(struct session *sess)
}
}
/******************************************************************************
* tcp session
******************************************************************************/
static void tcp_sub_state_update(struct tcp_session *tcp_sess, enum session_dir dir, uint8_t tcp_flags)
{
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;
}
tcp_sess->s2c_data_queue = tcp_reassembly_new(opts);
if (tcp_sess->s2c_data_queue == NULL)
{
tcp_reassembly_free(tcp_sess->c2s_data_queue);
return -1;
}
return 0;
}
void tcp_sess_clean(struct session *sess)
{
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 tcp_data_enqueue(struct session *sess, const struct pkt_layer *tcp_layer, uint64_t now)
{
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)
{
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
{
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 tcp_data_dequeue(struct session *sess, uint32_t len)
{
struct tcp_session *tcp_sess = &sess->data.tcp;
if (sess->cur_dir == SESSION_DIR_C2S)
{
tcp_reassembly_consume(tcp_sess->c2s_data_queue, len);
}
else
{
tcp_reassembly_consume(tcp_sess->s2c_data_queue, len);
}
}
const char *tcp_data_peek(struct session *sess, uint32_t *len)
{
struct tcp_session *tcp_sess = &sess->data.tcp;
if (sess->cur_dir == SESSION_DIR_C2S)
{
return tcp_reassembly_peek(tcp_sess->c2s_data_queue, len);
}
else
{
return tcp_reassembly_peek(tcp_sess->s2c_data_queue, len);
}
}
void tcp_data_expire(struct session *sess, uint64_t now)
{
struct tcp_session *tcp_sess = &sess->data.tcp;
tcp_reassembly_expire(tcp_sess->c2s_data_queue, now);
tcp_reassembly_expire(tcp_sess->s2c_data_queue, now);
}
/******************************************************************************
* session ex data
******************************************************************************/