mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2025-07-30 10:47:28 +02:00
Merge pull request #4403 from dgarske/zd12852_sniffer
Sniffer improvements for handling TCP ack unseen and retransmission issues
This commit is contained in:
146
src/sniffer.c
146
src/sniffer.c
@ -492,6 +492,10 @@ typedef struct KeyShareInfo {
|
|||||||
int curve_id;
|
int curve_id;
|
||||||
} KeyShareInfo;
|
} KeyShareInfo;
|
||||||
|
|
||||||
|
/* maximum previous acks to capture */
|
||||||
|
#ifndef WC_SNIFFER_HS_ACK_HIST_MAX
|
||||||
|
#define WC_SNIFFER_HS_ACK_HIST_MAX 10
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Sniffer Session holds info for each client/server SSL/TLS session */
|
/* Sniffer Session holds info for each client/server SSL/TLS session */
|
||||||
typedef struct SnifferSession {
|
typedef struct SnifferSession {
|
||||||
@ -506,6 +510,8 @@ typedef struct SnifferSession {
|
|||||||
word32 srvSeqStart; /* server start sequence */
|
word32 srvSeqStart; /* server start sequence */
|
||||||
word32 cliExpected; /* client expected sequence (relative) */
|
word32 cliExpected; /* client expected sequence (relative) */
|
||||||
word32 srvExpected; /* server expected sequence (relative) */
|
word32 srvExpected; /* server expected sequence (relative) */
|
||||||
|
word32 cliAcks[WC_SNIFFER_HS_ACK_HIST_MAX]; /* history of acks during handshake */
|
||||||
|
word32 srvAcks[WC_SNIFFER_HS_ACK_HIST_MAX]; /* history of acks during handshake */
|
||||||
FinCapture finCapture; /* retain out of order FIN s */
|
FinCapture finCapture; /* retain out of order FIN s */
|
||||||
Flags flags; /* session flags */
|
Flags flags; /* session flags */
|
||||||
time_t lastUsed; /* last used ticks */
|
time_t lastUsed; /* last used ticks */
|
||||||
@ -4740,12 +4746,53 @@ static int AddFinCapture(SnifferSession* session, word32 sequence)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int FindPrevAck(SnifferSession* session, word32 realAck)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
word32* acks = (session->flags.side == WOLFSSL_SERVER_END) ?
|
||||||
|
session->cliAcks : session->srvAcks;
|
||||||
|
/* if previous ack found return 1, otherwise 0 */
|
||||||
|
for (i=0; i<WC_SNIFFER_HS_ACK_HIST_MAX; i++) {
|
||||||
|
if (acks[i] == realAck) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static void AddAck(SnifferSession* session, word32 realAck)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
word32* acks = (session->flags.side == WOLFSSL_SERVER_END) ?
|
||||||
|
session->cliAcks : session->srvAcks;
|
||||||
|
/* find first empty ack slot */
|
||||||
|
for (i=0; i<WC_SNIFFER_HS_ACK_HIST_MAX; i++) {
|
||||||
|
if (acks[i] == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* if out of slots, find oldest */
|
||||||
|
if (i == WC_SNIFFER_HS_ACK_HIST_MAX) {
|
||||||
|
int idx = 0;
|
||||||
|
word32 lastAck = realAck;
|
||||||
|
for (i=0; i<WC_SNIFFER_HS_ACK_HIST_MAX; i++) {
|
||||||
|
if (acks[i] < lastAck) {
|
||||||
|
idx = i;
|
||||||
|
lastAck = acks[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
acks[i] = realAck;
|
||||||
|
}
|
||||||
|
|
||||||
/* Adjust incoming sequence based on side */
|
/* Adjust incoming sequence based on side */
|
||||||
/* returns 0 on success (continue), -1 on error, 1 on success (end) */
|
/* returns 0 on success (continue), -1 on error, 1 on success (end) */
|
||||||
static int AdjustSequence(TcpInfo* tcpInfo, SnifferSession* session,
|
static int AdjustSequence(TcpInfo* tcpInfo, SnifferSession* session,
|
||||||
int* sslBytes, const byte** sslFrame, char* error)
|
int* sslBytes, const byte** sslFrame, char* error)
|
||||||
{
|
{
|
||||||
|
int ret = 0;
|
||||||
word32 seqStart = (session->flags.side == WOLFSSL_SERVER_END) ?
|
word32 seqStart = (session->flags.side == WOLFSSL_SERVER_END) ?
|
||||||
session->cliSeqStart :session->srvSeqStart;
|
session->cliSeqStart :session->srvSeqStart;
|
||||||
word32 real = tcpInfo->sequence - seqStart;
|
word32 real = tcpInfo->sequence - seqStart;
|
||||||
@ -4764,21 +4811,22 @@ static int AdjustSequence(TcpInfo* tcpInfo, SnifferSession* session,
|
|||||||
TraceRelativeSequence(*expected, real);
|
TraceRelativeSequence(*expected, real);
|
||||||
|
|
||||||
if (real < *expected) {
|
if (real < *expected) {
|
||||||
Trace(DUPLICATE_STR);
|
|
||||||
if (real + *sslBytes > *expected) {
|
|
||||||
int overlap = *expected - real;
|
|
||||||
Trace(OVERLAP_DUPLICATE_STR);
|
|
||||||
|
|
||||||
/* adjust to expected, remove duplicate */
|
if (real + *sslBytes > *expected) {
|
||||||
*sslFrame += overlap;
|
Trace(OVERLAP_DUPLICATE_STR);
|
||||||
*sslBytes -= overlap;
|
|
||||||
|
|
||||||
/* The following conditional block is duplicated below. It is the
|
/* The following conditional block is duplicated below. It is the
|
||||||
* same action but for a different setup case. If changing this
|
* same action but for a different setup case. If changing this
|
||||||
* block be sure to also update the block below. */
|
* block be sure to also update the block below. */
|
||||||
if (reassemblyList) {
|
if (reassemblyList) {
|
||||||
word32 newEnd = *expected + *sslBytes;
|
int overlap = *expected - real;
|
||||||
|
word32 newEnd;
|
||||||
|
|
||||||
|
/* adjust to expected, remove duplicate */
|
||||||
|
*sslFrame += overlap;
|
||||||
|
*sslBytes -= overlap;
|
||||||
|
|
||||||
|
newEnd = *expected + *sslBytes;
|
||||||
if (newEnd > reassemblyList->begin) {
|
if (newEnd > reassemblyList->begin) {
|
||||||
Trace(OVERLAP_REASSEMBLY_BEGIN_STR);
|
Trace(OVERLAP_REASSEMBLY_BEGIN_STR);
|
||||||
|
|
||||||
@ -4795,12 +4843,33 @@ static int AdjustSequence(TcpInfo* tcpInfo, SnifferSession* session,
|
|||||||
newEnd - reassemblyList->end, session, error);
|
newEnd - reassemblyList->end, session, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
/* DUP overlap, allow */
|
||||||
|
if (*sslBytes > 0) {
|
||||||
|
skipPartial = 0; /* do not reset sslBytes */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* This can happen with out of order packets, or possible spurious
|
/* This can happen with unseen acks, out of order packets, or
|
||||||
* retransmission. If packet has data attempt to process packet */
|
* possible spurious retransmission. */
|
||||||
if (*sslBytes == 0) {
|
if (*sslBytes > 0) {
|
||||||
return 1;
|
/* If packet has data attempt to process packet, if hasn't
|
||||||
|
* already been ack'd during handshake */
|
||||||
|
if (FindPrevAck(session, real)) {
|
||||||
|
Trace(DUPLICATE_STR);
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* DUP: allow */
|
||||||
|
skipPartial = 0; /* do not reset sslBytes */
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* DUP empty, ignore */
|
||||||
|
ret = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4809,25 +4878,17 @@ static int AdjustSequence(TcpInfo* tcpInfo, SnifferSession* session,
|
|||||||
if (*sslBytes > 0) {
|
if (*sslBytes > 0) {
|
||||||
int addResult = AddToReassembly(session->flags.side, real,
|
int addResult = AddToReassembly(session->flags.side, real,
|
||||||
*sslFrame, *sslBytes, session, error);
|
*sslFrame, *sslBytes, session, error);
|
||||||
if (skipPartial) {
|
ret = (skipPartial) ? 0 : addResult;
|
||||||
*sslBytes = 0;
|
}
|
||||||
return 0;
|
else if (tcpInfo->fin) {
|
||||||
}
|
ret = AddFinCapture(session, real);
|
||||||
else
|
|
||||||
return addResult;
|
|
||||||
}
|
}
|
||||||
else if (tcpInfo->fin)
|
|
||||||
return AddFinCapture(session, real);
|
|
||||||
}
|
}
|
||||||
else if (*sslBytes > 0) {
|
else if (*sslBytes > 0) {
|
||||||
if (skipPartial) {
|
if (skipPartial) {
|
||||||
AddToReassembly(session->flags.side, real,
|
AddToReassembly(session->flags.side, real,
|
||||||
*sslFrame, *sslBytes, session, error);
|
*sslFrame, *sslBytes, session, error);
|
||||||
*expected += *sslBytes;
|
ret = 0;
|
||||||
*sslBytes = 0;
|
|
||||||
if (tcpInfo->fin)
|
|
||||||
*expected += 1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
/* The following conditional block is duplicated above. It is the
|
/* The following conditional block is duplicated above. It is the
|
||||||
* same action but for a different setup case. If changing this
|
* same action but for a different setup case. If changing this
|
||||||
@ -4852,12 +4913,24 @@ static int AdjustSequence(TcpInfo* tcpInfo, SnifferSession* session,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* got expected sequence */
|
else {
|
||||||
*expected += *sslBytes;
|
/* no data present */
|
||||||
if (tcpInfo->fin)
|
}
|
||||||
*expected += 1;
|
|
||||||
|
|
||||||
return 0;
|
if (ret == 0) {
|
||||||
|
/* got expected sequence */
|
||||||
|
*expected += *sslBytes;
|
||||||
|
if (tcpInfo->fin)
|
||||||
|
*expected += 1;
|
||||||
|
}
|
||||||
|
if (*sslBytes > 0) {
|
||||||
|
AddAck(session, real);
|
||||||
|
}
|
||||||
|
if (*sslBytes > 0 && skipPartial) {
|
||||||
|
*sslBytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -5280,8 +5353,9 @@ doMessage:
|
|||||||
}
|
}
|
||||||
if (sslBytes >= RECORD_HEADER_SZ) {
|
if (sslBytes >= RECORD_HEADER_SZ) {
|
||||||
if (GetRecordHeader(sslFrame, &rh, &rhSize) != 0) {
|
if (GetRecordHeader(sslFrame, &rh, &rhSize) != 0) {
|
||||||
SetError(BAD_RECORD_HDR_STR, error, session, FATAL_ERROR_STATE);
|
/* ignore packet if record header errors */
|
||||||
return -1;
|
SetError(BAD_RECORD_HDR_STR, error, session, 0);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -5360,8 +5434,12 @@ doMessage:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (errCode != 0) {
|
if (errCode != 0) {
|
||||||
SetError(BAD_DECRYPT, error, session, FATAL_ERROR_STATE);
|
if ((enum ContentType)rh.type == application_data) {
|
||||||
return -1;
|
SetError(BAD_DECRYPT, error, session, FATAL_ERROR_STATE);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* do not end session for failures on handshake packets */
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user