dns: accept gaps in TCP DNS

On gap notification a flag is set, on the next call the input
data is reprobed to make sure it can be processed.
pull/2737/head
Jason Ish 8 years ago committed by Victor Julien
parent c862bbdc4b
commit c8ac479f90

@ -232,6 +232,8 @@ typedef struct DNSState_ {
uint16_t offset;
uint16_t record_len;
uint8_t *buffer;
uint8_t gap_ts; /**< Flag set when a gap has occurred. */
uint8_t gap_tc; /**< Flag set when a gap has occurred. */
} DNSState;
#define DNS_CONFIG_DEFAULT_REQUEST_FLOOD 500

@ -58,6 +58,9 @@ struct DNSTcpHeader_ {
} __attribute__((__packed__));
typedef struct DNSTcpHeader_ DNSTcpHeader;
static uint16_t DNSTcpProbingParser(uint8_t *input, uint32_t ilen,
uint32_t *offset);
/** \internal
* \param input_len at least enough for the DNSTcpHeader
*/
@ -288,6 +291,13 @@ static int DNSTCPRequestParse(Flow *f, void *dstate,
DNSState *dns_state = (DNSState *)dstate;
SCLogDebug("starting %u", input_len);
if (input == NULL && input_len > 0) {
SCLogDebug("Input is NULL, but len is %"PRIu32": must be a gap.",
input_len);
dns_state->gap_ts = 1;
SCReturnInt(1);
}
if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
SCReturnInt(1);
}
@ -301,6 +311,18 @@ static int DNSTCPRequestParse(Flow *f, void *dstate,
goto insufficient_data;
}
/* Clear gap state. */
if (dns_state->gap_ts) {
if (DNSTcpProbingParser(input, input_len, NULL) == ALPROTO_DNS) {
SCLogDebug("New data probed as DNS, clearing gap state.");
BufferReset(dns_state);
dns_state->gap_ts = 0;
} else {
SCLogDebug("Unable to sync DNS parser, leaving gap state.");
SCReturnInt(1);
}
}
next_record:
/* if this is the beginning of a record, we need at least the header */
if (dns_state->offset == 0 && input_len < sizeof(DNSTcpHeader)) {
@ -508,6 +530,13 @@ static int DNSTCPResponseParse(Flow *f, void *dstate,
{
DNSState *dns_state = (DNSState *)dstate;
if (input == NULL && input_len > 0) {
SCLogDebug("Input is NULL, but len is %"PRIu32": must be a gap.",
input_len);
dns_state->gap_tc = 1;
SCReturnInt(1);
}
if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
SCReturnInt(1);
}
@ -521,6 +550,18 @@ static int DNSTCPResponseParse(Flow *f, void *dstate,
goto insufficient_data;
}
/* Clear gap state. */
if (dns_state->gap_tc) {
if (DNSTcpProbingParser(input, input_len, NULL) == ALPROTO_DNS) {
SCLogDebug("New data probed as DNS, clearing gap state.");
BufferReset(dns_state);
dns_state->gap_tc = 0;
} else {
SCLogDebug("Unable to sync DNS parser, leaving gap state.");
SCReturnInt(1);
}
}
next_record:
/* if this is the beginning of a record, we need at least the header */
if (dns_state->offset == 0 && input_len < sizeof(DNSTcpHeader)) {
@ -712,6 +753,11 @@ void RegisterDNSTCPParsers(void)
AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_DNS,
DNSGetAlstateProgressCompletionStatus);
DNSAppLayerRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_DNS);
/* This parser accepts gaps. */
AppLayerParserRegisterOptionFlags(IPPROTO_TCP, ALPROTO_DNS,
APP_LAYER_PARSER_OPT_ACCEPT_GAPS);
} else {
SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
"still on.", proto_name);

Loading…
Cancel
Save