Merge branch 'sniffer-recovery'

This commit is contained in:
John Safranek
2015-10-02 15:58:57 -07:00
4 changed files with 241 additions and 17 deletions

View File

@@ -244,7 +244,11 @@ static const char* const msgTable[] =
"Secure Renegotiation Not Supported", "Secure Renegotiation Not Supported",
/* 76 */ /* 76 */
"Get Session Stats Failure" "Get Session Stats Failure",
"Reassembly Buffer Size Exceeded",
"Dropping Lost Fragment",
"Dropping Partial Record",
"Clear ACK Fault"
}; };
@@ -316,6 +320,10 @@ typedef struct Flags {
byte clientHello; /* processed client hello yet, for SSLv2 */ byte clientHello; /* processed client hello yet, for SSLv2 */
byte finCount; /* get both FINs before removing */ byte finCount; /* get both FINs before removing */
byte fatalError; /* fatal error state */ byte fatalError; /* fatal error state */
byte cliAckFault; /* client acked unseen data from server */
byte srvAckFault; /* server acked unseen data from client */
byte cliSkipPartial; /* client skips partial data to catch up */
byte srvSkipPartial; /* server skips partial data to catch up */
} Flags; } Flags;
@@ -346,6 +354,8 @@ typedef struct SnifferSession {
time_t lastUsed; /* last used ticks */ time_t lastUsed; /* last used ticks */
PacketBuffer* cliReassemblyList; /* client out of order packets */ PacketBuffer* cliReassemblyList; /* client out of order packets */
PacketBuffer* srvReassemblyList; /* server out of order packets */ PacketBuffer* srvReassemblyList; /* server out of order packets */
word32 cliReassemblyMemory; /* client packet memory used */
word32 srvReassemblyMemory; /* server packet memory used */
struct SnifferSession* next; /* for hash table list */ struct SnifferSession* next; /* for hash table list */
byte* ticketID; /* mac ID of session ticket */ byte* ticketID; /* mac ID of session ticket */
} SnifferSession; } SnifferSession;
@@ -366,7 +376,14 @@ static wolfSSL_Mutex RecoveryMutex; /* for stats */
static int RecoveryEnabled = 0; /* global switch */ static int RecoveryEnabled = 0; /* global switch */
static int MaxRecoveryMemory = -1; /* per session max recovery memory */ static int MaxRecoveryMemory = -1; /* per session max recovery memory */
static word32 MissedDataSessions = 0; /* # of sessions with missed data */ static word32 MissedDataSessions = 0; /* # of sessions with missed data */
static word32 ReassemblyMemory = 0; /* total reassembly memory in use */
static void UpdateMissedDataSessions(void)
{
LockMutex(&RecoveryMutex);
MissedDataSessions += 1;
UnLockMutex(&RecoveryMutex);
}
/* Initialize overall Sniffer */ /* Initialize overall Sniffer */
@@ -537,6 +554,10 @@ static void InitFlags(Flags* flags)
flags->clientHello = 0; flags->clientHello = 0;
flags->finCount = 0; flags->finCount = 0;
flags->fatalError = 0; flags->fatalError = 0;
flags->cliAckFault = 0;
flags->srvAckFault = 0;
flags->cliSkipPartial = 0;
flags->srvSkipPartial = 0;
} }
@@ -567,6 +588,8 @@ static void InitSession(SnifferSession* session)
session->lastUsed = 0; session->lastUsed = 0;
session->cliReassemblyList = 0; session->cliReassemblyList = 0;
session->srvReassemblyList = 0; session->srvReassemblyList = 0;
session->cliReassemblyMemory = 0;
session->srvReassemblyMemory = 0;
session->next = 0; session->next = 0;
session->ticketID = 0; session->ticketID = 0;
@@ -2333,18 +2356,26 @@ static int AddToReassembly(byte from, word32 seq, const byte* sslFrame,
PacketBuffer* curr = *front; PacketBuffer* curr = *front;
PacketBuffer* prev = curr; PacketBuffer* prev = curr;
word32* reassemblyMemory = (from == WOLFSSL_SERVER_END) ?
&session->cliReassemblyMemory : &session->srvReassemblyMemory;
word32 startSeq = seq; word32 startSeq = seq;
word32 added; word32 added;
int bytesLeft = sslBytes; /* could be overlapping fragment */ int bytesLeft = sslBytes; /* could be overlapping fragment */
/* if list is empty add full frame to front */ /* if list is empty add full frame to front */
if (!curr) { if (!curr) {
if (MaxRecoveryMemory != -1 &&
(int)(*reassemblyMemory + sslBytes) > MaxRecoveryMemory) {
SetError(REASSEMBLY_MAX_STR, error, session, FATAL_ERROR_STATE);
return -1;
}
add = CreateBuffer(&seq, seq + sslBytes - 1, sslFrame, &bytesLeft); add = CreateBuffer(&seq, seq + sslBytes - 1, sslFrame, &bytesLeft);
if (add == NULL) { if (add == NULL) {
SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE);
return -1; return -1;
} }
*front = add; *front = add;
*reassemblyMemory += sslBytes;
return 1; return 1;
} }
@@ -2355,6 +2386,11 @@ static int AddToReassembly(byte from, word32 seq, const byte* sslFrame,
if (end >= curr->begin) if (end >= curr->begin)
end = curr->begin - 1; end = curr->begin - 1;
if (MaxRecoveryMemory -1 &&
(int)(*reassemblyMemory + sslBytes) > MaxRecoveryMemory) {
SetError(REASSEMBLY_MAX_STR, error, session, FATAL_ERROR_STATE);
return -1;
}
add = CreateBuffer(&seq, end, sslFrame, &bytesLeft); add = CreateBuffer(&seq, end, sslFrame, &bytesLeft);
if (add == NULL) { if (add == NULL) {
SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE);
@@ -2362,6 +2398,7 @@ static int AddToReassembly(byte from, word32 seq, const byte* sslFrame,
} }
add->next = curr; add->next = curr;
*front = add; *front = add;
*reassemblyMemory += sslBytes;
} }
/* while we have bytes left, try to find a gap to fill */ /* while we have bytes left, try to find a gap to fill */
@@ -2391,6 +2428,11 @@ static int AddToReassembly(byte from, word32 seq, const byte* sslFrame,
if (added == 0) if (added == 0)
continue; continue;
if (MaxRecoveryMemory != -1 &&
(int)(*reassemblyMemory + added) > MaxRecoveryMemory) {
SetError(REASSEMBLY_MAX_STR, error, session, FATAL_ERROR_STATE);
return -1;
}
add = CreateBuffer(&seq, seq + added - 1, &sslFrame[seq - startSeq], add = CreateBuffer(&seq, seq + added - 1, &sslFrame[seq - startSeq],
&bytesLeft); &bytesLeft);
if (add == NULL) { if (add == NULL) {
@@ -2399,6 +2441,7 @@ static int AddToReassembly(byte from, word32 seq, const byte* sslFrame,
} }
add->next = prev->next; add->next = prev->next;
prev->next = add; prev->next = add;
*reassemblyMemory += added;
} }
return 1; return 1;
} }
@@ -2432,6 +2475,9 @@ static int AdjustSequence(TcpInfo* tcpInfo, SnifferSession* session,
&session->cliExpected : &session->srvExpected; &session->cliExpected : &session->srvExpected;
PacketBuffer* reassemblyList = (session->flags.side == WOLFSSL_SERVER_END) ? PacketBuffer* reassemblyList = (session->flags.side == WOLFSSL_SERVER_END) ?
session->cliReassemblyList : session->srvReassemblyList; session->cliReassemblyList : session->srvReassemblyList;
byte skipPartial = (session->flags.side == WOLFSSL_SERVER_END) ?
session->flags.srvSkipPartial :
session->flags.cliSkipPartial;
/* handle rollover of sequence */ /* handle rollover of sequence */
if (tcpInfo->sequence < seqStart) if (tcpInfo->sequence < seqStart)
@@ -2477,17 +2523,33 @@ static int AdjustSequence(TcpInfo* tcpInfo, SnifferSession* session,
} }
else if (real > *expected) { else if (real > *expected) {
Trace(OUT_OF_ORDER_STR); Trace(OUT_OF_ORDER_STR);
if (*sslBytes > 0) if (*sslBytes > 0) {
return AddToReassembly(session->flags.side, real, *sslFrame, int addResult = AddToReassembly(session->flags.side, real,
*sslBytes, session, error); *sslFrame, *sslBytes, session, error);
if (skipPartial) {
*sslBytes = 0;
return 0;
}
else
return addResult;
}
else if (tcpInfo->fin) else if (tcpInfo->fin)
return AddFinCapture(session, real); return AddFinCapture(session, real);
} }
else { else if (*sslBytes > 0) {
if (skipPartial) {
AddToReassembly(session->flags.side, real,
*sslFrame, *sslBytes, session, error);
*expected += *sslBytes;
*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
* block be sure to also update the block above. */ * block be sure to also update the block above. */
if (reassemblyList) { else if (reassemblyList) {
word32 newEnd = *expected + *sslBytes; word32 newEnd = *expected + *sslBytes;
if (newEnd > reassemblyList->begin) { if (newEnd > reassemblyList->begin) {
@@ -2516,6 +2578,110 @@ static int AdjustSequence(TcpInfo* tcpInfo, SnifferSession* session,
} }
static int FindNextRecordInAssembly(SnifferSession* session,
const byte** sslFrame, int* sslBytes,
const byte** end, char* error)
{
PacketBuffer** front = (session->flags.side == WOLFSSL_SERVER_END) ?
&session->cliReassemblyList :
&session->srvReassemblyList;
PacketBuffer* curr = *front;
PacketBuffer* prev = NULL;
byte* skipPartial = (session->flags.side == WOLFSSL_SERVER_END) ?
&session->flags.srvSkipPartial :
&session->flags.cliSkipPartial;
word32* reassemblyMemory = (session->flags.side == WOLFSSL_SERVER_END) ?
&session->cliReassemblyMemory :
&session->srvReassemblyMemory;
SSL* ssl = (session->flags.side == WOLFSSL_SERVER_END) ?
session->sslServer :
session->sslClient;
ProtocolVersion pv = ssl->version;
word32* expected = (session->flags.side == WOLFSSL_SERVER_END) ?
&session->cliExpected :
&session->srvExpected;
while (curr != NULL) {
*expected = curr->end + 1;
if (curr->data[0] == application_data &&
curr->data[1] == pv.major &&
curr->data[2] == pv.minor) {
if (ssl->buffers.inputBuffer.length > 0)
Trace(DROPPING_PARTIAL_RECORD);
*sslBytes = curr->end - curr->begin + 1;
if ( (word32)*sslBytes > ssl->buffers.inputBuffer.bufferSize) {
if (GrowInputBuffer(ssl, *sslBytes, 0) < 0) {
SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE);
return -1;
}
}
XMEMCPY(ssl->buffers.inputBuffer.buffer, curr->data, *sslBytes);
*front = curr->next;
*reassemblyMemory -= *sslBytes;
FreePacketBuffer(curr);
ssl->buffers.inputBuffer.length = *sslBytes;
*sslFrame = ssl->buffers.inputBuffer.buffer;
*end = *sslFrame + *sslBytes;
*skipPartial = 0;
return 0;
}
else if (ssl->specs.cipher_type == block) {
if (ssl->specs.bulk_cipher_algorithm == wolfssl_aes)
wc_AesSetIV(ssl->decrypt.aes,
curr->data + curr->end - curr->begin
- ssl->specs.block_size + 1);
else if (ssl->specs.bulk_cipher_algorithm == wolfssl_triple_des)
wc_Des3_SetIV(ssl->decrypt.des3,
curr->data + curr->end - curr->begin
- ssl->specs.block_size + 1);
}
Trace(DROPPING_LOST_FRAG_STR);
prev = curr;
curr = curr->next;
*reassemblyMemory -= (prev->end - prev->begin + 1);
FreePacketBuffer(prev);
}
*front = curr;
return 0;
}
static int FixSequence(TcpInfo* tcpInfo, SnifferSession* session)
{
word32* expected = (session->flags.side == WOLFSSL_SERVER_END) ?
&session->srvExpected : &session->cliExpected;
PacketBuffer* list = (session->flags.side == WOLFSSL_SERVER_END) ?
session->srvReassemblyList :
session->cliReassemblyList;
byte* skipPartial = (session->flags.side != WOLFSSL_SERVER_END) ?
&session->flags.srvSkipPartial :
&session->flags.cliSkipPartial;
*skipPartial = 1;
if (list != NULL)
*expected = list->begin;
else {
word32 seqStart = (session->flags.side == WOLFSSL_SERVER_END) ?
session->srvSeqStart : session->cliSeqStart;
word32 real = tcpInfo->ackNumber - seqStart;
*expected = real;
}
return 1;
}
/* Check latest ack number for missing packets /* Check latest ack number for missing packets
return 0 ok, <0 on error */ return 0 ok, <0 on error */
static int CheckAck(TcpInfo* tcpInfo, SnifferSession* session) static int CheckAck(TcpInfo* tcpInfo, SnifferSession* session)
@@ -2547,6 +2713,9 @@ static int CheckSequence(IpInfo* ipInfo, TcpInfo* tcpInfo,
const byte** sslFrame, char* error) const byte** sslFrame, char* error)
{ {
int actualLen; int actualLen;
byte* ackFault = (session->flags.side == WOLFSSL_SERVER_END) ?
&session->flags.cliAckFault :
&session->flags.srvAckFault;
/* init SEQ from server to client */ /* init SEQ from server to client */
if (tcpInfo->syn && tcpInfo->ack) { if (tcpInfo->syn && tcpInfo->ack) {
@@ -2564,9 +2733,25 @@ static int CheckSequence(IpInfo* ipInfo, TcpInfo* tcpInfo,
TraceSequence(tcpInfo->sequence, *sslBytes); TraceSequence(tcpInfo->sequence, *sslBytes);
if (CheckAck(tcpInfo, session) < 0) { if (CheckAck(tcpInfo, session) < 0) {
if (!RecoveryEnabled) {
UpdateMissedDataSessions();
SetError(ACK_MISSED_STR, error, session, FATAL_ERROR_STATE); SetError(ACK_MISSED_STR, error, session, FATAL_ERROR_STATE);
return -1; return -1;
} }
else {
SetError(ACK_MISSED_STR, error, session, 0);
if (*ackFault == 0) {
*ackFault = 1;
UpdateMissedDataSessions();
}
return FixSequence(tcpInfo, session);
}
}
if (*ackFault) {
Trace(CLEAR_ACK_FAULT);
*ackFault = 0;
}
return AdjustSequence(tcpInfo, session, sslBytes, sslFrame, error); return AdjustSequence(tcpInfo, session, sslBytes, sslFrame, error);
} }
@@ -2581,6 +2766,9 @@ static int CheckPreRecord(IpInfo* ipInfo, TcpInfo* tcpInfo,
word32 length; word32 length;
SSL* ssl = ((*session)->flags.side == WOLFSSL_SERVER_END) ? SSL* ssl = ((*session)->flags.side == WOLFSSL_SERVER_END) ?
(*session)->sslServer : (*session)->sslClient; (*session)->sslServer : (*session)->sslClient;
byte skipPartial = ((*session)->flags.side == WOLFSSL_SERVER_END) ?
(*session)->flags.srvSkipPartial :
(*session)->flags.cliSkipPartial;
/* remove SnifferSession on 2nd FIN or RST */ /* remove SnifferSession on 2nd FIN or RST */
if (tcpInfo->fin || tcpInfo->rst) { if (tcpInfo->fin || tcpInfo->rst) {
/* flag FIN and RST */ /* flag FIN and RST */
@@ -2601,13 +2789,22 @@ static int CheckPreRecord(IpInfo* ipInfo, TcpInfo* tcpInfo,
return -1; return -1;
} }
if (skipPartial) {
if (FindNextRecordInAssembly(*session,
sslFrame, sslBytes, end, error) < 0) {
return -1;
}
}
if (*sslBytes == 0) { if (*sslBytes == 0) {
Trace(NO_DATA_STR); Trace(NO_DATA_STR);
return 1; return 1;
} }
/* if current partial data, add to end of partial */ /* if current partial data, add to end of partial */
if ( (length = ssl->buffers.inputBuffer.length) ) { /* if skipping, the data is alread at the end of partial */
if ( !skipPartial &&
(length = ssl->buffers.inputBuffer.length) ) {
Trace(PARTIAL_ADD_STR); Trace(PARTIAL_ADD_STR);
if ( (*sslBytes + length) > ssl->buffers.inputBuffer.bufferSize) { if ( (*sslBytes + length) > ssl->buffers.inputBuffer.bufferSize) {
@@ -2671,6 +2868,8 @@ static int HaveMoreInput(SnifferSession* session, const byte** sslFrame,
&session->sslClient->buffers.inputBuffer.bufferSize; &session->sslClient->buffers.inputBuffer.bufferSize;
SSL* ssl = (session->flags.side == WOLFSSL_SERVER_END) ? SSL* ssl = (session->flags.side == WOLFSSL_SERVER_END) ?
session->sslServer : session->sslClient; session->sslServer : session->sslClient;
word32* reassemblyMemory = (session->flags.side == WOLFSSL_SERVER_END) ?
&session->cliReassemblyMemory : &session->srvReassemblyMemory;
while (*front && ((*front)->begin == *expected) ) { while (*front && ((*front)->begin == *expected) ) {
word32 room = *bufferSize - *length; word32 room = *bufferSize - *length;
@@ -2694,6 +2893,8 @@ static int HaveMoreInput(SnifferSession* session, const byte** sslFrame,
/* remove used packet */ /* remove used packet */
*front = (*front)->next; *front = (*front)->next;
*reassemblyMemory -= packetLen;
FreePacketBuffer(del); FreePacketBuffer(del);
moreInput = 1; moreInput = 1;
@@ -3023,14 +3224,28 @@ int ssl_GetSessionStats(unsigned int* active, unsigned int* total,
{ {
int ret; int ret;
if (missedData) {
LockMutex(&RecoveryMutex); LockMutex(&RecoveryMutex);
if (missedData)
*missedData = MissedDataSessions; *missedData = MissedDataSessions;
if (reassemblyMem)
*reassemblyMem = ReassemblyMemory;
UnLockMutex(&RecoveryMutex); UnLockMutex(&RecoveryMutex);
}
if (reassemblyMem) {
SnifferSession* session;
int i;
*reassemblyMem = 0;
LockMutex(&SessionMutex);
for (i = 0; i < HASH_SIZE; i++) {
session = SessionTable[i];
while (session) {
*reassemblyMem += session->cliReassemblyMemory;
*reassemblyMem += session->srvReassemblyMemory;
session = session->next;
}
}
UnLockMutex(&SessionMutex);
}
ret = wolfSSL_get_session_stats(active, total, peak, maxSessions); ret = wolfSSL_get_session_stats(active, total, peak, maxSessions);

View File

@@ -143,6 +143,7 @@ int main(int argc, char** argv)
ssl_InitSniffer(); /* dll load on Windows */ ssl_InitSniffer(); /* dll load on Windows */
#endif #endif
ssl_Trace("./tracefile.txt", err); ssl_Trace("./tracefile.txt", err);
ssl_EnableRecovery(1, -1, err);
if (argc == 1) { if (argc == 1) {
/* normal case, user chooses device and port */ /* normal case, user chooses device and port */

View File

@@ -110,6 +110,10 @@
#define NO_SECURE_RENEGOTIATION 75 #define NO_SECURE_RENEGOTIATION 75
#define BAD_SESSION_STATS 76 #define BAD_SESSION_STATS 76
#define REASSEMBLY_MAX_STR 77
#define DROPPING_LOST_FRAG_STR 78
#define DROPPING_PARTIAL_RECORD 79
#define CLEAR_ACK_FAULT 80
/* !!!! also add to msgTable in sniffer.c and .rc file !!!! */ /* !!!! also add to msgTable in sniffer.c and .rc file !!!! */

View File

@@ -92,5 +92,9 @@ STRINGTABLE
75, "Secure Renegotiation Not Supported" 75, "Secure Renegotiation Not Supported"
76, "Get Session Stats Failure" 76, "Get Session Stats Failure"
77, "Reassembly Buffer Size Exceeded"
78, "Dropping Lost Fragment"
79, "Dropping Partial Record"
80, "Clear ACK Fault"
} }