stream reassembly: simplify base_seq tracking for protocol detection. Shrinks TcpStream structure.

remotes/origin/master-1.2.x
Victor Julien 14 years ago
parent 7e3c15e54a
commit a0b532dc45

@ -43,32 +43,29 @@ typedef struct TcpSegment_ {
} TcpSegment;
typedef struct TcpStream_ {
uint32_t isn; /**< initial sequence number */
uint32_t next_seq; /**< next expected sequence number */
uint32_t last_ack; /**< last ack'd sequence number in this stream */
uint32_t next_win; /**< next max seq within window */
uint32_t window; /**< current window setting */
uint16_t flags; /**< Flag specific to the stream e.g. Timestamp */
uint8_t wscale; /**< wscale setting in this direction */
uint8_t os_policy; /**< target based OS policy used for reassembly and handling packets*/
uint32_t isn; /**< initial sequence number */
uint32_t next_seq; /**< next expected sequence number */
uint32_t last_ack; /**< last ack'd sequence number in this stream */
uint32_t next_win; /**< next max seq within window */
uint32_t window; /**< current window setting, after wscale is applied */
uint32_t last_ts; /**< Time stamp (TSVAL) of the last seen packet for this stream*/
uint32_t last_pkt_ts; /**< Time of last seen packet for this stream (needed for PAWS update)
This will be used to validate the last_ts, when connection has been idle for
longer time.(RFC 1323)*/
/* reassembly */
uint32_t ra_app_base_seq; /**< reassembled seq. We've reassembled up to this point. */
uint32_t ra_raw_base_seq; /**< reassembled seq. We've reassembled up to this point. */
uint32_t last_ts; /**< Time stamp (TSVAL) of the last seen packet for this stream*/
uint32_t last_pkt_ts; /**< Time of last seen packet for this stream (needed for PAWS update)
This will be used to validate the last_ts, when connection has been idle for
longer time.(RFC 1323)*/
TcpSegment *seg_list; /**< list of TCP segments that are not yet (fully) used in reassembly */
TcpSegment *seg_list_tail; /**< Last segment in the reassembled stream seg list*/
/* reassembly */
uint32_t ra_app_base_seq; /**< reassembled seq. We've reassembled up to this point. */
uint32_t tmp_ra_app_base_seq; /**< Temporary reassembled seq, to be used until
app layer protocol has not been detected,
beacuse every smsg needs to contain all the
initial segments too */
uint32_t ra_raw_base_seq; /**< reassembled seq. We've reassembled up to this point. */
TcpSegment *seg_list; /**< list of TCP segments that are not yet (fully) used in reassembly */
uint8_t wscale; /**< wscale setting in this direction */
uint8_t os_policy; /**< target based OS policy used for reassembly and handling packets*/
uint16_t flags; /**< Flag specific to the stream e.g. Timestamp */
TcpSegment *seg_list_tail; /**< Last segment in the reassembled stream seg list*/
StreamTcpSackRecord *sack_head;
StreamTcpSackRecord *sack_tail;
StreamTcpSackRecord *sack_head; /**< head of list of SACK records */
StreamTcpSackRecord *sack_tail; /**< tail of list of SACK records */
} TcpStream;
/* from /usr/include/netinet/tcp.h */
@ -164,7 +161,6 @@ enum
do { \
(stream)->ra_raw_base_seq = (seq); \
(stream)->ra_app_base_seq = (seq); \
(stream)->tmp_ra_app_base_seq = (seq); \
} while(0); \
}

@ -1658,7 +1658,7 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre
#define STREAM_SET_FLAGS(ssn, stream, p, flag) { \
flag = 0; \
if ((stream)->ra_app_base_seq == (stream)->isn) { \
if (!(ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) {\
flag |= STREAM_START; \
} \
if ((ssn)->state > TCP_ESTABLISHED) { \
@ -1673,7 +1673,7 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre
#define STREAM_SET_INLINE_FLAGS(ssn, stream, p, flag) { \
flag = 0; \
if ((stream)->ra_app_base_seq == (stream)->isn) { \
if (!(ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) {\
flag |= STREAM_START; \
} \
if ((ssn)->state > TCP_ESTABLISHED) { \
@ -1878,6 +1878,8 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
SCReturnInt(0);
}
/* stream->ra_app_base_seq remains at stream->isn until protocol is
* detected. */
uint32_t ra_base_seq = stream->ra_app_base_seq;
uint8_t data[4096];
uint32_t data_len = 0;
@ -1939,27 +1941,11 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags);
/* if app layer protocol has not been detected till yet,
then check did we have sent message to app layer already
or not. If not then sent the message and set flag that first
message has been sent. No more data till proto has not
been detected */
if (!(ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) {
/* process what we have so far */
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
stream->tmp_ra_app_base_seq = ra_base_seq;
} else {
/* process what we have so far */
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
/* process what we have so far */
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
stream->ra_app_base_seq = ra_base_seq;
}
data_sent += data_len;
data_len = 0;
}
@ -1979,16 +1965,6 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
next_seq = seg->seq;
/* we need to update the ra_base_seq, if app layer proto has
been detected and we are setting new stream message. Otherwise
every smsg will be with flag STREAM_START set, which we
don't want :-) */
if (ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED) {
stream->ra_app_base_seq = ra_base_seq;
} else {
stream->tmp_ra_app_base_seq = ra_base_seq;
}
/* We have missed the packet and end host has ack'd it, so
* IDS should advance it's ra_base_seq and should not consider this
* packet any longer, even if it is retransmitted, as end host will
@ -2066,34 +2042,14 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
/* queue the smsg if it's full */
if (data_len == sizeof(data)) {
/* if app layer protocol has not been detected till yet,
then check did we have sent message to app layer already
or not. If not then sent the message and set flag that first
message has been sent. No more data till proto has not
been detected */
if (!(ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) {
/* process what we have so far */
STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags);
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
data_sent += data_len;
data_len = 0;
stream->tmp_ra_app_base_seq = ra_base_seq;
} else {
/* process what we have so far */
STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags);
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
data_sent += data_len;
data_len = 0;
stream->ra_app_base_seq = ra_base_seq;
}
/* process what we have so far */
STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags);
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
data_sent += data_len;
data_len = 0;
}
/* if the payload len is bigger than what we copied, we handle the
@ -2140,34 +2096,14 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
payload_offset, data_len, copy_size);
if (data_len == sizeof(data)) {
/* if app layer protocol has not been detected till yet,
then check did we have sent message to app layer already
or not. If not then sent the message and set flag that first
message has been sent. No more data till proto has not
been detected */
if (!(ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) {
/* process what we have so far */
STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags);
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
data_sent += data_len;
data_len = 0;
stream->tmp_ra_app_base_seq = ra_base_seq;
} else {
/* process what we have so far */
STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags);
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
data_sent += data_len;
data_len = 0;
stream->ra_app_base_seq = ra_base_seq;
}
/* process what we have so far */
STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags);
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
data_sent += data_len;
data_len = 0;
}
/* see if we have segment payload left to process */
@ -2198,31 +2134,18 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
/* put the partly filled smsg in the queue to the l7 handler */
if (data_len > 0) {
SCLogDebug("data_len > 0, %u", data_len);
if (!(ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) {
/* process what we have so far */
STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags);
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
data_sent += data_len;
stream->tmp_ra_app_base_seq = ra_base_seq;
} else {
/* process what we have so far */
STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags);
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
data_sent += data_len;
stream->ra_app_base_seq = ra_base_seq;
}
/* process what we have so far */
STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags);
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
data_sent += data_len;
}
if (ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED) {
SCLogDebug("proto detection already completed");
ssn->flags |= STREAMTCP_FLAG_TOSERVER_REASSEMBLY_STARTED;
stream->ra_app_base_seq = ra_base_seq;
} else {
SCLogDebug("protocol detection not yet completed");
}
@ -2240,6 +2163,11 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
ssn->flags |= STREAMTCP_FLAG_TOSERVER_REASSEMBLY_STARTED;
}
/* store ra_base_seq in the stream */
if ((ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) {
stream->ra_app_base_seq = ra_base_seq;
}
SCLogDebug("stream->ra_app_base_seq %u", stream->ra_app_base_seq);
SCReturnInt(0);
}
@ -2635,37 +2563,9 @@ static int StreamTcpReassembleAppLayer (TcpReassemblyThreadCtx *ra_ctx,
SCReturnInt(0);
}
uint32_t ra_base_seq;
/* check if we have detected the app layer protocol or not. If it has been
detected then, process data normally, as we have sent one smsg from
toserver side already to the app layer */
if (ssn->state <= TCP_ESTABLISHED) {
if (!(ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) {
/* initialize the tmp_ra_base_seq for each new run */
stream->tmp_ra_app_base_seq = stream->ra_app_base_seq;
ra_base_seq = stream->tmp_ra_app_base_seq;
/* if app layer protocol has been detected, then restore the reassembled
seq. to the value till reassembling has been done and unset the queue
init flag permanently for this tcp session */
} else if (SEQ_GT(stream->tmp_ra_app_base_seq, stream->ra_app_base_seq)) {
stream->ra_app_base_seq = stream->tmp_ra_app_base_seq;
ra_base_seq = stream->ra_app_base_seq;
SCLogDebug("the app layer protocol has been detected");
} else {
ra_base_seq = stream->ra_app_base_seq;
}
/* set the ra_bas_seq to stream->ra_base_seq as now app layer protocol
has been detected */
} else {
if (SEQ_GT(stream->tmp_ra_app_base_seq, stream->ra_app_base_seq)) {
stream->ra_app_base_seq = stream->tmp_ra_app_base_seq;
ra_base_seq = stream->ra_app_base_seq;
} else {
ra_base_seq = stream->ra_app_base_seq;
}
}
/* stream->ra_app_base_seq remains at stream->isn until protocol is
* detected. */
uint32_t ra_base_seq = stream->ra_app_base_seq;
uint8_t data[4096];
uint32_t data_len = 0;
uint16_t payload_offset = 0;
@ -2736,27 +2636,10 @@ static int StreamTcpReassembleAppLayer (TcpReassemblyThreadCtx *ra_ctx,
STREAM_SET_FLAGS(ssn, stream, p, flags);
/* if app layer protocol has not been detected till yet,
then check did we have sent message to app layer already
or not. If not then sent the message and set flag that first
message has been sent. No more data till proto has not
been detected */
if (!(ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) {
/* process what we have so far */
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
stream->tmp_ra_app_base_seq = ra_base_seq;
} else {
/* process what we have so far */
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
stream->ra_app_base_seq = ra_base_seq;
}
/* process what we have so far */
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
}
/* don't conclude it's a gap straight away. If ra_base_seq is lower
@ -2775,16 +2658,6 @@ static int StreamTcpReassembleAppLayer (TcpReassemblyThreadCtx *ra_ctx,
next_seq = seg->seq;
/* we need to update the ra_base_seq, if app layer proto has
been detected and we are setting new stream message. Otherwise
every smsg will be with flag STREAM_START set, which we
don't want :-) */
if (ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED) {
stream->ra_app_base_seq = ra_base_seq;
} else {
stream->tmp_ra_app_base_seq = ra_base_seq;
}
/* We have missed the packet and end host has ack'd it, so
* IDS should advance it's ra_base_seq and should not consider this
* packet any longer, even if it is retransmitted, as end host will
@ -2887,31 +2760,19 @@ static int StreamTcpReassembleAppLayer (TcpReassemblyThreadCtx *ra_ctx,
/* queue the smsg if it's full */
if (data_len == sizeof(data)) {
/* if app layer protocol has not been detected till yet,
then check did we have sent message to app layer already
or not. If not then sent the message and set flag that first
message has been sent. No more data till proto has not
been detected */
if (!(ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) {
/* process what we have so far */
STREAM_SET_FLAGS(ssn, stream, p, flags);
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
data_len = 0;
stream->tmp_ra_app_base_seq = ra_base_seq;
} else {
/* process what we have so far */
STREAM_SET_FLAGS(ssn, stream, p, flags);
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
data_len = 0;
/* process what we have so far */
STREAM_SET_FLAGS(ssn, stream, p, flags);
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
data_len = 0;
stream->ra_app_base_seq = ra_base_seq;
/* if after the first data chunk we have no alproto yet,
* there is no point in continueing here. */
if (!(ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) {
SCLogDebug("no alproto after first data chunk");
break;
}
}
@ -2959,31 +2820,19 @@ static int StreamTcpReassembleAppLayer (TcpReassemblyThreadCtx *ra_ctx,
payload_offset, data_len, copy_size);
if (data_len == sizeof(data)) {
/* if app layer protocol has not been detected till yet,
then check did we have sent message to app layer already
or not. If not then sent the message and set flag that first
message has been sent. No more data till proto has not
been detected */
/* process what we have so far */
STREAM_SET_FLAGS(ssn, stream, p, flags);
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
data_len = 0;
/* if after the first data chunk we have no alproto yet,
* there is no point in continueing here. */
if (!(ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) {
/* process what we have so far */
STREAM_SET_FLAGS(ssn, stream, p, flags);
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
data_len = 0;
stream->tmp_ra_app_base_seq = ra_base_seq;
} else {
/* process what we have so far */
STREAM_SET_FLAGS(ssn, stream, p, flags);
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
data_len = 0;
stream->ra_app_base_seq = ra_base_seq;
SCLogDebug("no alproto after first data chunk");
break;
}
}
@ -3020,24 +2869,12 @@ static int StreamTcpReassembleAppLayer (TcpReassemblyThreadCtx *ra_ctx,
/* put the partly filled smsg in the queue to the l7 handler */
if (data_len > 0) {
SCLogDebug("data_len > 0, %u", data_len);
if (!(ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) {
/* process what we have so far */
STREAM_SET_FLAGS(ssn, stream, p, flags);
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
stream->tmp_ra_app_base_seq = ra_base_seq;
} else {
/* process what we have so far */
STREAM_SET_FLAGS(ssn, stream, p, flags);
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
stream->ra_app_base_seq = ra_base_seq;
}
/* process what we have so far */
STREAM_SET_FLAGS(ssn, stream, p, flags);
BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags);
PACKET_PROFILING_APP_STORE(&ra_ctx->dp_ctx, p);
}
if (ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED) {
@ -3047,6 +2884,11 @@ static int StreamTcpReassembleAppLayer (TcpReassemblyThreadCtx *ra_ctx,
SCLogDebug("protocol detection not yet completed");
}
/* store ra_base_seq in the stream */
if ((ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED)) {
stream->ra_app_base_seq = ra_base_seq;
}
SCLogDebug("stream->ra_app_base_seq %u", stream->ra_app_base_seq);
SCReturnInt(0);
}
@ -6686,7 +6528,9 @@ static int StreamTcpReassembleTest40 (void) {
"been sent (16): ");
goto end;
/* Process stream smsgs we may have in queue */
} else if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) {
}
if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) {
printf("failed in processing stream smsgs (17): ");
goto end;
}
@ -8818,8 +8662,9 @@ static int StreamTcpReassembleInlineTest10(void) {
goto end;
}
if (ssn.server.tmp_ra_app_base_seq != 3) {
printf("expected tmp_ra_app_base_seq 3, got %u: ", ssn.server.tmp_ra_app_base_seq);
/* ssn.server.ra_app_base_seq should be isn here. */
if (ssn.server.ra_app_base_seq != 1 || ssn.server.ra_app_base_seq != ssn.server.isn) {
printf("expected ra_app_base_seq 1, got %u: ", ssn.server.ra_app_base_seq);
goto end;
}

Loading…
Cancel
Save