From 6ffb9da9be94b0999b1b7c59e861ab3b5b7af8ad Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 9 Jan 2011 21:20:40 +0100 Subject: [PATCH] Better support ack/psh data packets on several states. Updates to ack validation code. --- src/decode-events.h | 2 +- src/stream-tcp.c | 121 +++++++++++++++++++++++++------------------- 2 files changed, 71 insertions(+), 52 deletions(-) diff --git a/src/decode-events.h b/src/decode-events.h index 3075aed409..f43900d1a6 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -143,7 +143,7 @@ enum { STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW, STREAM_CLOSING_ACK_WRONG_SEQ, STREAM_EST_PACKET_OUT_OF_WINDOW, - STREAM_EST_SEQ_BEFORE_LAST_ACK, + STREAM_EST_PKT_BEFORE_LAST_ACK, STREAM_EST_SYNACK_RESEND, STREAM_EST_SYNACK_RESEND_WITH_DIFFERENT_ACK, STREAM_EST_SYNACK_RESEND_WITH_DIFF_SEQ, diff --git a/src/stream-tcp.c b/src/stream-tcp.c index a8f3f29b33..ae44f563ad 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -613,17 +613,20 @@ void StreamTcpSetEvent(Packet *p, uint8_t e) { * * \retval on valid ACK it return TRUE and on invalid ACK, it returns FALSE */ -static inline uint8_t StreamTcpValidateAck(TcpStream *stream, Packet *p) +static inline int StreamTcpValidateAck(TcpStream *stream, Packet *p) { - uint8_t ret = FALSE; + SCEnter(); - if (SEQ_GT(TCP_GET_ACK(p), stream->last_ack) && - (SEQ_LEQ(TCP_GET_ACK(p) + p->payload_len, stream->next_win))) - { - ret = TRUE; + if (SEQ_GEQ(TCP_GET_ACK(p), stream->last_ack)) { + if (SEQ_LEQ(TCP_GET_ACK(p) + p->payload_len, stream->next_win)) + { + SCReturnInt(1); + } + } else { + SCLogDebug("pkt ACK %"PRIu32" < stream last ACK %"PRIu32, TCP_GET_ACK(p), stream->last_ack); } - return ret; + SCReturnInt(0); } /** @@ -1342,8 +1345,9 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, /* we need to make sure that both sequence and the ack are of sane values */ - if ((StreamTcpValidateAck(&ssn->client, p) == TRUE)) + if (StreamTcpValidateAck(&ssn->client, p)) ssn->client.last_ack = TCP_GET_ACK(p); + ssn->server.next_seq += p->payload_len; ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; @@ -1403,7 +1407,7 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, /* we need to make sure that both sequence and the ack are of sane values */ - if ((StreamTcpValidateAck(&ssn->server, p) == TRUE)) + if (StreamTcpValidateAck(&ssn->server, p)) ssn->server.last_ack = TCP_GET_ACK(p); ssn->client.next_seq += p->payload_len; @@ -1568,7 +1572,7 @@ static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Pack "ACK %" PRIu32 ", WIN %"PRIu16"", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p), TCP_GET_WINDOW(p)); - if (!(SEQ_GEQ(TCP_GET_SEQ(p), ssn->client.last_ack))) { + if (!(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len), ssn->client.last_ack))) { if (ssn->flags & STREAMTCP_FLAG_ASYNC) { SCLogDebug("ssn %p: server => Asynchrouns stream, packet SEQ" " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 ")," @@ -1625,7 +1629,7 @@ static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Pack ssn->client.last_ack, ssn->client.next_win, TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win); - StreamTcpSetEvent(p, STREAM_EST_SEQ_BEFORE_LAST_ACK); + StreamTcpSetEvent(p, STREAM_EST_PKT_BEFORE_LAST_ACK); return -1; } } @@ -1648,7 +1652,7 @@ static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Pack ssn->server.window); /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->server, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->server, p)) { ssn->server.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the server packet and client has already received and acked it */ @@ -1711,7 +1715,7 @@ static int HandleEstablishedPacketToClient(ThreadVars *tv, TcpSession *ssn, Pack " %" PRIu32 "", ssn, ssn->server.next_win); } - if (!(SEQ_GEQ(TCP_GET_SEQ(p), ssn->server.last_ack))) { + if (!(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len), ssn->server.last_ack))) { if (ssn->flags & STREAMTCP_FLAG_ASYNC) { SCLogDebug("ssn %p: client => Asynchrouns stream, packet SEQ" @@ -1725,7 +1729,10 @@ static int HandleEstablishedPacketToClient(ThreadVars *tv, TcpSession *ssn, Pack ssn->server.last_ack = TCP_GET_SEQ(p); } else { - StreamTcpSetEvent(p, STREAM_EST_SEQ_BEFORE_LAST_ACK); + SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16 + " before last_ack %"PRIu32, + ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack); + StreamTcpSetEvent(p, STREAM_EST_PKT_BEFORE_LAST_ACK); return -1; } } @@ -1746,7 +1753,7 @@ static int HandleEstablishedPacketToClient(ThreadVars *tv, TcpSession *ssn, Pack ssn->client.window); /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->client, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->client, p)) { ssn->client.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -1918,7 +1925,7 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, return -1; } - SCLogDebug("StreamTcpPacketStateEstablished (%p): FIN received SEQ" + SCLogDebug("ssn (%p: FIN received SEQ" " %" PRIu32 ", last ACK %" PRIu32 ", next win %"PRIu32"," " win %" PRIu32 "", ssn, ssn->server.next_seq, ssn->client.last_ack, ssn->server.next_win, @@ -1950,7 +1957,7 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->server, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->server, p)) { ssn->server.last_ack = TCP_GET_ACK(p); } @@ -1973,7 +1980,7 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->client, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->client, p)) { ssn->client.last_ack = TCP_GET_ACK(p); } @@ -2035,7 +2042,7 @@ static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->server, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->server, p)) { ssn->server.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -2074,7 +2081,7 @@ static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->client, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->client, p)) { ssn->client.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -2109,6 +2116,7 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, switch (p->tcph->th_flags) { case TH_ACK: + case TH_ACK|TH_PUSH: case TH_ACK|TH_URG: case TH_ACK|TH_ECN: case TH_ACK|TH_ECN|TH_CWR: @@ -2137,7 +2145,7 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->server, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->server, p)) { ssn->server.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -2174,7 +2182,7 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->client, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->client, p)) { ssn->client.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -2232,7 +2240,7 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->server, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->server, p)) { ssn->server.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -2274,7 +2282,7 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->client, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->client, p)) { ssn->client.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -2341,6 +2349,7 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, switch (p->tcph->th_flags) { case TH_ACK: + case TH_ACK|TH_PUSH: case TH_ACK|TH_URG: case TH_ACK|TH_ECN: case TH_ACK|TH_ECN|TH_CWR: @@ -2368,7 +2377,7 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->server, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->server, p)) { ssn->server.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -2406,7 +2415,7 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->client, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->client, p)) { ssn->client.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -2476,7 +2485,7 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->server, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->server, p)) { ssn->server.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -2511,7 +2520,7 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->client, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->client, p)) { ssn->client.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -2552,6 +2561,7 @@ static int StreamTcpPacketStateClosing(ThreadVars *tv, Packet *p, switch(p->tcph->th_flags) { case TH_ACK: + case TH_ACK|TH_PUSH: case TH_ACK|TH_ECN: case TH_ACK|TH_ECN|TH_CWR: @@ -2579,7 +2589,7 @@ static int StreamTcpPacketStateClosing(ThreadVars *tv, Packet *p, ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->server, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->server, p)) { ssn->server.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -2610,7 +2620,7 @@ static int StreamTcpPacketStateClosing(ThreadVars *tv, Packet *p, ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->client, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->client, p)) { ssn->client.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -2693,7 +2703,7 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->client, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->client, p)) { ssn->client.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -2727,7 +2737,7 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->server, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->server, p)) { ssn->server.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -2770,7 +2780,7 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->client, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->client, p)) { ssn->client.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -2804,7 +2814,7 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->server, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->server, p)) { ssn->server.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -2847,6 +2857,7 @@ static int StreamTcpPakcetStateLastAck(ThreadVars *tv, Packet *p, switch(p->tcph->th_flags) { case TH_ACK: + case TH_ACK|TH_PUSH: case TH_ACK|TH_ECN: case TH_ACK|TH_ECN|TH_CWR: @@ -2874,7 +2885,7 @@ static int StreamTcpPakcetStateLastAck(ThreadVars *tv, Packet *p, ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->server, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->server, p)) { ssn->server.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -2916,6 +2927,7 @@ static int StreamTcpPacketStateTimeWait(ThreadVars *tv, Packet *p, switch(p->tcph->th_flags) { case TH_ACK: + case TH_ACK|TH_PUSH: case TH_ACK|TH_ECN: case TH_ACK|TH_ECN|TH_CWR: @@ -2943,7 +2955,7 @@ static int StreamTcpPacketStateTimeWait(ThreadVars *tv, Packet *p, ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->server, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->server, p)) { ssn->server.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -2976,7 +2988,7 @@ static int StreamTcpPacketStateTimeWait(ThreadVars *tv, Packet *p, ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; /* Check if the ACK value is sane and inside the window limit */ - if (StreamTcpValidateAck(&ssn->client, p) == TRUE) { + if (StreamTcpValidateAck(&ssn->client, p)) { ssn->client.last_ack = TCP_GET_ACK(p); /* Update the next_seq, in case if we have missed the client packet and server has already received and acked it */ @@ -3006,6 +3018,9 @@ static int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, PacketQueue *pq) { SCEnter(); + + SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt); + TcpSession *ssn = (TcpSession *)p->flow->protoctx; /* If we are on IPS mode, and got a drop action triggered from @@ -6168,9 +6183,6 @@ end: static int StreamTcpTest23(void) { TcpSession ssn; - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (p == NULL) - return 0; Flow f; TCPHdr tcph; TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); @@ -6178,7 +6190,18 @@ static int StreamTcpTest23(void) ThreadVars tv; int result = 1; PacketQueue pq; + + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (p == NULL) + return 0; + memset(&pq,0,sizeof(PacketQueue)); + memset(&ssn, 0, sizeof (TcpSession)); + memset(p, 0, SIZE_OF_PACKET); + p->pkt = (uint8_t *)(p + 1); + memset(&f, 0, sizeof (Flow)); + memset(&tcph, 0, sizeof (TCPHdr)); + memset(&tv, 0, sizeof (ThreadVars)); StreamTcpInitConfig(TRUE); @@ -6188,12 +6211,6 @@ static int StreamTcpTest23(void) StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); - memset(&ssn, 0, sizeof (TcpSession)); - memset(p, 0, SIZE_OF_PACKET); - p->pkt = (uint8_t *)(p + 1); - memset(&f, 0, sizeof (Flow)); - memset(&tcph, 0, sizeof (TCPHdr)); - memset(&tv, 0, sizeof (ThreadVars)); ssn.client.os_policy = OS_POLICY_BSD; f.protoctx = &ssn; p->src.family = AF_INET; @@ -6205,13 +6222,14 @@ static int StreamTcpTest23(void) p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; p->payload = packet; + ssn.client.ra_app_base_seq = ssn.client.ra_raw_base_seq = ssn.client.last_ack = 3184324453UL; p->tcph->th_seq = htonl(3184324453UL); p->tcph->th_ack = htonl(3373419609UL); p->payload_len = 2; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) { - printf("failed in segment reassmebling\n"); + printf("failed in segment reassmebling: "); result &= 0; goto end; } @@ -6221,7 +6239,7 @@ static int StreamTcpTest23(void) p->payload_len = 2; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) { - printf("failed in segment reassmebling\n"); + printf("failed in segment reassmebling: "); result &= 0; goto end; } @@ -6231,13 +6249,13 @@ static int StreamTcpTest23(void) p->payload_len = 6; if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) { - printf("failed in segment reassmebling\n"); + printf("failed in segment reassmebling: "); result &= 0; - goto end; +// goto end; } if(ssn.client.seg_list_tail->payload_len != 4) { - printf("failed in segment reassmebling\n"); + printf("failed in segment reassmebling: "); result &= 0; } @@ -6294,6 +6312,7 @@ static int StreamTcpTest24(void) p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; p->payload = packet; + ssn.client.ra_app_base_seq = ssn.client.ra_raw_base_seq = ssn.client.last_ack = 3184324453UL; p->tcph->th_seq = htonl(3184324455UL); p->tcph->th_ack = htonl(3373419621UL);