Refactor TCP reassembly, the session knows where the TCP segment comes from: raw packet or tcp segment queue
This commit is contained in:
@@ -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
|
||||
******************************************************************************/
|
||||
|
||||
Reference in New Issue
Block a user