@ -81,6 +81,14 @@ static int DNSUDPRequestParse(Flow *f, void *dstate,
if ( DNSValidateRequestHeader ( dns_state , dns_header ) < 0 )
goto bad_data ;
if ( dns_state ! = NULL ) {
if ( timercmp ( & dns_state - > last_req , & dns_state - > last_resp , > = ) ) {
if ( dns_state - > window < = dns_state - > unreplied_cnt ) {
dns_state - > window + + ;
}
}
}
uint16_t q ;
const uint8_t * data = input + sizeof ( DNSHeader ) ;
for ( q = 0 ; q < ntohs ( dns_header - > questions ) ; q + + ) {
@ -151,6 +159,10 @@ static int DNSUDPRequestParse(Flow *f, void *dstate,
}
}
if ( dns_state ! = NULL & & f ! = NULL ) {
dns_state - > last_req = f - > lastts ;
}
SCReturnInt ( 1 ) ;
bad_data :
insufficient_data :
@ -196,6 +208,8 @@ static int DNSUDPResponseParse(Flow *f, void *dstate,
if ( ! found ) {
SCLogDebug ( " DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE " ) ;
DNSSetEvent ( dns_state , DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE ) ;
} else if ( dns_state - > unreplied_cnt > 0 ) {
dns_state - > unreplied_cnt - - ;
}
if ( DNSValidateResponseHeader ( dns_state , dns_header ) < 0 )
@ -300,6 +314,9 @@ static int DNSUDPResponseParse(Flow *f, void *dstate,
tx - > replied = 1 ;
}
if ( dns_state ! = NULL & & f ! = NULL ) {
dns_state - > last_resp = f - > lastts ;
}
SCReturnInt ( 1 ) ;
bad_data :
@ -627,6 +644,233 @@ end:
return ( result ) ;
}
/**
* \ test Test subsequent requests before response .
*
* This test sends 2 DNS requests on the same state then sends the response
* to the first request checking that it is seen and associated with the
* transaction .
*/
static int DNSUDPParserTestDelayedResponse ( void )
{
/* DNS request:
* - Flags : 0x0100 Standard query
* - A www . google . com
*/
uint8_t req [ ] = {
0x00 , 0x01 , 0x01 , 0x00 , 0x00 , 0x01 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x03 , 0x77 , 0x77 , 0x77 ,
0x06 , 0x67 , 0x6f , 0x6f , 0x67 , 0x6c , 0x65 , 0x03 ,
0x63 , 0x6f , 0x6d , 0x00 , 0x00 , 0x01 , 0x00 , 0x01 ,
} ;
size_t reqlen = sizeof ( req ) ;
/* DNS response:
* - Flags : 0x8180 Standard query response , no error
* - www . google . com A 24.244 .4 .56
* - www . google . com A 24.244 .4 .54
* - www . google . com A 24.244 .4 .57
* - www . google . com A 24.244 .4 .55
* - www . google . com A 24.244 .4 .52
* - www . google . com A 24.244 .4 .53
* - www . google . com A 24.244 .4 .58
* - www . google . com A 24.244 .4 .59
*/
uint8_t res [ ] = {
0x00 , 0x01 , 0x81 , 0x80 , 0x00 , 0x01 , 0x00 , 0x08 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x03 , 0x77 , 0x77 , 0x77 ,
0x06 , 0x67 , 0x6f , 0x6f , 0x67 , 0x6c , 0x65 , 0x03 ,
0x63 , 0x6f , 0x6d , 0x00 , 0x00 , 0x01 , 0x00 , 0x01 ,
0xc0 , 0x0c , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 ,
0x01 , 0x08 , 0x00 , 0x04 , 0x18 , 0xf4 , 0x04 , 0x38 ,
0xc0 , 0x0c , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 ,
0x01 , 0x08 , 0x00 , 0x04 , 0x18 , 0xf4 , 0x04 , 0x39 ,
0xc0 , 0x0c , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 ,
0x01 , 0x08 , 0x00 , 0x04 , 0x18 , 0xf4 , 0x04 , 0x34 ,
0xc0 , 0x0c , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 ,
0x01 , 0x08 , 0x00 , 0x04 , 0x18 , 0xf4 , 0x04 , 0x35 ,
0xc0 , 0x0c , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 ,
0x01 , 0x08 , 0x00 , 0x04 , 0x18 , 0xf4 , 0x04 , 0x36 ,
0xc0 , 0x0c , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 ,
0x01 , 0x08 , 0x00 , 0x04 , 0x18 , 0xf4 , 0x04 , 0x3b ,
0xc0 , 0x0c , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 ,
0x01 , 0x08 , 0x00 , 0x04 , 0x18 , 0xf4 , 0x04 , 0x37 ,
0xc0 , 0x0c , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 ,
0x01 , 0x08 , 0x00 , 0x04 , 0x18 , 0xf4 , 0x04 , 0x3a
} ;
size_t reslen = sizeof ( res ) ;
DNSState * state = DNSStateAlloc ( ) ;
FAIL_IF_NULL ( state ) ;
Flow * f = UTHBuildFlow ( AF_INET , " 1.1.1.1 " , " 2.2.2.2 " , 1024 , 53 ) ;
FAIL_IF_NULL ( f ) ;
f - > proto = IPPROTO_UDP ;
f - > alproto = ALPROTO_DNS ;
f - > alstate = state ;
/* Send to requests with an incrementing tx id. */
FAIL_IF_NOT ( DNSUDPRequestParse ( f , f - > alstate , NULL , req , reqlen , NULL ) ) ;
req [ 1 ] = 0x02 ;
FAIL_IF_NOT ( DNSUDPRequestParse ( f , f - > alstate , NULL , req , reqlen , NULL ) ) ;
/* Send response to the first request. */
FAIL_IF_NOT ( DNSUDPResponseParse ( f , f - > alstate , NULL , res , reslen , NULL ) ) ;
DNSTransaction * tx = TAILQ_FIRST ( & state - > tx_list ) ;
FAIL_IF_NULL ( tx ) ;
FAIL_IF_NOT ( tx - > replied ) ;
/* Also free's state. */
UTHFreeFlow ( f ) ;
PASS ;
}
/**
* \ test Test entering the flood / givenup state .
*/
static int DNSUDPParserTestFlood ( void )
{
/* DNS request:
* - Flags : 0x0100 Standard query
* - A www . google . com
*/
uint8_t req [ ] = {
0x00 , 0x01 , 0x01 , 0x00 , 0x00 , 0x01 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x03 , 0x77 , 0x77 , 0x77 ,
0x06 , 0x67 , 0x6f , 0x6f , 0x67 , 0x6c , 0x65 , 0x03 ,
0x63 , 0x6f , 0x6d , 0x00 , 0x00 , 0x01 , 0x00 , 0x01 ,
} ;
size_t reqlen = sizeof ( req ) ;
DNSState * state = DNSStateAlloc ( ) ;
FAIL_IF_NULL ( state ) ;
Flow * f = UTHBuildFlow ( AF_INET , " 1.1.1.1 " , " 2.2.2.2 " , 1024 , 53 ) ;
FAIL_IF_NULL ( f ) ;
f - > proto = IPPROTO_UDP ;
f - > alproto = ALPROTO_DNS ;
f - > alstate = state ;
uint16_t txid ;
for ( txid = 1 ; txid < = DNS_CONFIG_DEFAULT_REQUEST_FLOOD + 1 ; txid + + ) {
req [ 0 ] = ( txid > > 8 ) & 0xff ;
req [ 1 ] = txid & 0xff ;
FAIL_IF_NOT ( DNSUDPRequestParse ( f , f - > alstate , NULL , req , reqlen , NULL ) ) ;
FAIL_IF ( state - > givenup ) ;
}
/* With one more request we should enter a flooded state. */
txid + + ;
req [ 0 ] = ( txid > > 8 ) & 0xff ;
req [ 1 ] = txid & 0xff ;
FAIL_IF_NOT ( DNSUDPRequestParse ( f , f - > alstate , NULL , req , reqlen , NULL ) ) ;
FAIL_IF ( ! state - > givenup ) ;
/* Also free's state. */
UTHFreeFlow ( f ) ;
PASS ;
}
static int DNSUDPParserTestLostResponse ( void )
{
/* DNS request:
* - Flags : 0x0100 Standard query
* - A www . google . com
*/
uint8_t req [ ] = {
0x00 , 0x01 , 0x01 , 0x00 , 0x00 , 0x01 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x03 , 0x77 , 0x77 , 0x77 ,
0x06 , 0x67 , 0x6f , 0x6f , 0x67 , 0x6c , 0x65 , 0x03 ,
0x63 , 0x6f , 0x6d , 0x00 , 0x00 , 0x01 , 0x00 , 0x01 ,
} ;
size_t reqlen = sizeof ( req ) ;
uint8_t res [ ] = {
0x00 , 0x01 , 0x81 , 0x80 , 0x00 , 0x01 , 0x00 , 0x08 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x03 , 0x77 , 0x77 , 0x77 ,
0x06 , 0x67 , 0x6f , 0x6f , 0x67 , 0x6c , 0x65 , 0x03 ,
0x63 , 0x6f , 0x6d , 0x00 , 0x00 , 0x01 , 0x00 , 0x01 ,
0xc0 , 0x0c , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 ,
0x01 , 0x08 , 0x00 , 0x04 , 0x18 , 0xf4 , 0x04 , 0x38 ,
0xc0 , 0x0c , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 ,
0x01 , 0x08 , 0x00 , 0x04 , 0x18 , 0xf4 , 0x04 , 0x39 ,
0xc0 , 0x0c , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 ,
0x01 , 0x08 , 0x00 , 0x04 , 0x18 , 0xf4 , 0x04 , 0x34 ,
0xc0 , 0x0c , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 ,
0x01 , 0x08 , 0x00 , 0x04 , 0x18 , 0xf4 , 0x04 , 0x35 ,
0xc0 , 0x0c , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 ,
0x01 , 0x08 , 0x00 , 0x04 , 0x18 , 0xf4 , 0x04 , 0x36 ,
0xc0 , 0x0c , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 ,
0x01 , 0x08 , 0x00 , 0x04 , 0x18 , 0xf4 , 0x04 , 0x3b ,
0xc0 , 0x0c , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 ,
0x01 , 0x08 , 0x00 , 0x04 , 0x18 , 0xf4 , 0x04 , 0x37 ,
0xc0 , 0x0c , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 , 0x00 ,
0x01 , 0x08 , 0x00 , 0x04 , 0x18 , 0xf4 , 0x04 , 0x3a
} ;
size_t reslen = sizeof ( res ) ;
DNSTransaction * tx ;
DNSState * state = DNSStateAlloc ( ) ;
FAIL_IF_NULL ( state ) ;
Flow * f = UTHBuildFlow ( AF_INET , " 1.1.1.1 " , " 2.2.2.2 " , 1024 , 53 ) ;
FAIL_IF_NULL ( f ) ;
f - > proto = IPPROTO_UDP ;
f - > alproto = ALPROTO_DNS ;
f - > alstate = state ;
/* First request. */
req [ 1 ] = 0x01 ;
FAIL_IF_NOT ( DNSUDPRequestParse ( f , f - > alstate , NULL , req , reqlen , NULL ) ) ;
FAIL_IF_NOT ( state - > transaction_max = = 1 ) ;
FAIL_IF_NOT ( state - > unreplied_cnt = = 1 ) ;
FAIL_IF_NOT ( state - > window = = 1 ) ;
/* Second request. */
req [ 1 ] = 0x02 ;
FAIL_IF_NOT ( DNSUDPRequestParse ( f , f - > alstate , NULL , req , reqlen , NULL ) ) ;
FAIL_IF_NOT ( state - > transaction_max = = 2 ) ;
FAIL_IF_NOT ( state - > unreplied_cnt = = 2 ) ;
FAIL_IF_NOT ( state - > window = = 2 ) ;
/* Third request. */
req [ 1 ] = 0x03 ;
FAIL_IF_NOT ( DNSUDPRequestParse ( f , f - > alstate , NULL , req , reqlen , NULL ) ) ;
FAIL_IF_NOT ( state - > transaction_max = = 3 ) ;
FAIL_IF_NOT ( state - > unreplied_cnt = = 3 ) ;
FAIL_IF_NOT ( state - > window = = 3 ) ;
/* Now respond to the second. */
res [ 1 ] = 0x02 ;
FAIL_IF_NOT ( DNSUDPResponseParse ( f , f - > alstate , NULL , res , reslen , NULL ) ) ;
FAIL_IF_NOT ( state - > unreplied_cnt = = 2 ) ;
FAIL_IF_NOT ( state - > window = = 3 ) ;
tx = TAILQ_FIRST ( & state - > tx_list ) ;
FAIL_IF_NULL ( tx ) ;
FAIL_IF ( tx - > replied ) ;
FAIL_IF ( tx - > reply_lost ) ;
/* Send a 4th request. */
req [ 1 ] = 0x04 ;
FAIL_IF_NOT ( DNSUDPRequestParse ( f , f - > alstate , NULL , req , reqlen , NULL ) ) ;
FAIL_IF_NOT ( state - > unreplied_cnt = = 3 ) ;
FAIL_IF ( state - > window ! = 3 ) ;
FAIL_IF_NOT ( state - > transaction_max = = 4 ) ;
/* Response to the third request. */
res [ 1 ] = 0x03 ;
FAIL_IF_NOT ( DNSUDPResponseParse ( f , f - > alstate , NULL , res , reslen , NULL ) ) ;
FAIL_IF_NOT ( state - > unreplied_cnt = = 2 ) ;
FAIL_IF_NOT ( state - > window = = 3 ) ;
tx = TAILQ_FIRST ( & state - > tx_list ) ;
FAIL_IF_NULL ( tx ) ;
FAIL_IF ( tx - > replied ) ;
FAIL_IF ( ! tx - > reply_lost ) ;
/* Also free's state. */
UTHFreeFlow ( f ) ;
PASS ;
}
void DNSUDPParserRegisterTests ( void )
{
@ -635,5 +879,10 @@ void DNSUDPParserRegisterTests(void)
UtRegisterTest ( " DNSUDPParserTest03 " , DNSUDPParserTest03 ) ;
UtRegisterTest ( " DNSUDPParserTest04 " , DNSUDPParserTest04 ) ;
UtRegisterTest ( " DNSUDPParserTest05 " , DNSUDPParserTest05 ) ;
UtRegisterTest ( " DNSUDPParserTestFlood " , DNSUDPParserTestFlood ) ;
UtRegisterTest ( " DNSUDPParserTestDelayedResponse " ,
DNSUDPParserTestDelayedResponse ) ;
UtRegisterTest ( " DNSUDPParserTestLostResponse " ,
DNSUDPParserTestLostResponse ) ;
}
# endif