@ -4805,6 +4805,130 @@ static int DetectFwLteCoverageTest03(void)
PASS ;
}
/** \test a pending <hook accept rule holds first-match priority over a later
* same - hook rule for the whole tx , and a TD rule at the hook still runs .
*
* Add order sets the candidate ( iid ) order , newest first : the TD rule first ,
* then the scaffold , the early rule and finally the late rule , so the late
* rule is walked first and holds the hook priority while pending . */
static int DetectFwLteMpmWalkTest01 ( void )
{
EngineModeSetFirewall ( ENGINE_HOST_IS_ROUTER ) ;
ThreadVars th_v ;
memset ( & th_v , 0 , sizeof ( th_v ) ) ;
StatsThreadInit ( & th_v . stats ) ;
Flow f ;
TcpSession ssn ;
memset ( & f , 0 , sizeof ( f ) ) ;
memset ( & ssn , 0 , sizeof ( ssn ) ) ;
FLOW_INITIALIZE ( & f ) ;
f . protoctx = ( void * ) & ssn ;
f . flags | = FLOW_IPV4 ;
f . proto = IPPROTO_TCP ;
f . alproto = ALPROTO_HTTP1 ;
AppLayerParserThreadCtx * alp_tctx = AppLayerParserThreadCtxAlloc ( ) ;
FAIL_IF_NULL ( alp_tctx ) ;
StreamTcpInitConfig ( true ) ;
DetectEngineCtx * de_ctx = DetectEngineCtxInit ( ) ;
FAIL_IF_NULL ( de_ctx ) ;
de_ctx - > flags | = DE_QUIET ;
FAIL_IF ( DetectFirewallInitDefaultPolicies ( de_ctx ) ! = 0 ) ;
/* TD rule at the hook: must still run while the accept rules are pending */
Signature * s_td = DetectEngineAppendSig ( de_ctx ,
" alert http1:request_headers any any -> any any "
" (http.host.raw; content: \" early.example.com \" ; sid:1103;) " ) ;
FAIL_IF_NULL ( s_td ) ;
/* accept the packet hook for all tcp: suppresses the default drop and lets
* the app - layer rules decide */
Signature * s_scaf1 = DetectFirewallRuleAppendNew (
de_ctx , " accept:hook tcp:all any any -> any any (flow:not_established; sid:1021;) " ) ;
FAIL_IF_NULL ( s_scaf1 ) ;
Signature * s_scaf2 = DetectFirewallRuleAppendNew (
de_ctx , " accept:hook tcp:all any any -> any any (flow:established; sid:1022;) " ) ;
FAIL_IF_NULL ( s_scaf2 ) ;
/* content present from the first segment */
Signature * s_early = DetectFirewallRuleAppendNew ( de_ctx ,
" accept:flow,alert http1:<request_headers any any -> any any "
" (http.host.raw; content: \" early.example.com \" ; sid:1102;) " ) ;
FAIL_IF_NULL ( s_early ) ;
/* the header only arrives in the second segment */
Signature * s_late = DetectFirewallRuleAppendNew ( de_ctx ,
" accept:flow,alert http1:<request_headers any any -> any any "
" (http.header; content: \" X-Late: a \" ; sid:1101;) " ) ;
FAIL_IF_NULL ( s_late ) ;
SigGroupBuild ( de_ctx ) ;
DetectEngineThreadCtx * det_ctx = NULL ;
DetectEngineThreadCtxInit ( & th_v , ( void * ) de_ctx , ( void * ) & det_ctx ) ;
FAIL_IF_NULL ( det_ctx ) ;
/* segment 1: request line + host, the header block is open */
const uint8_t * seg1 = ( const uint8_t * ) " GET / HTTP/1.1 \r \n Host: early.example.com \r \n " ;
Packet * p1 = UTHBuildPacket ( ( uint8_t * ) seg1 , ( uint16_t ) strlen ( ( const char * ) seg1 ) , IPPROTO_TCP ) ;
FAIL_IF_NULL ( p1 ) ;
p1 - > flow = & f ;
p1 - > flowflags | = FLOW_PKT_TOSERVER ;
p1 - > flowflags | = FLOW_PKT_ESTABLISHED ;
p1 - > flags | = PKT_HAS_FLOW | PKT_STREAM_EST ;
p1 - > app_update_direction = STREAM_TOSERVER ;
int r = AppLayerParserParse ( NULL , alp_tctx , & f , ALPROTO_HTTP1 , STREAM_TOSERVER , seg1 ,
( uint16_t ) strlen ( ( const char * ) seg1 ) ) ;
FAIL_IF ( r ! = 0 ) ;
SigMatchSignatures ( & th_v , de_ctx , det_ctx , p1 ) ;
/* 1101 is pending: 1102 must not have accepted the flow yet */
FAIL_IF ( f . flags & FLOW_ACTION_ACCEPT ) ;
/* segment 2: the late header completes the block */
const uint8_t * seg2 = ( const uint8_t * ) " X-Late: a \r \n \r \n " ;
Packet * p2 = UTHBuildPacket ( ( uint8_t * ) seg2 , ( uint16_t ) strlen ( ( const char * ) seg2 ) , IPPROTO_TCP ) ;
FAIL_IF_NULL ( p2 ) ;
p2 - > flow = & f ;
p2 - > flowflags | = FLOW_PKT_TOSERVER ;
p2 - > flowflags | = FLOW_PKT_ESTABLISHED ;
p2 - > flags | = PKT_HAS_FLOW | PKT_STREAM_EST ;
p2 - > app_update_direction = STREAM_TOSERVER ;
r = AppLayerParserParse ( NULL , alp_tctx , & f , ALPROTO_HTTP1 , STREAM_TOSERVER , seg2 ,
( uint16_t ) strlen ( ( const char * ) seg2 ) ) ;
FAIL_IF ( r ! = 0 ) ;
SigMatchSignatures ( & th_v , de_ctx , det_ctx , p2 ) ;
/* 1101 matched on completion: the flow is accepted by the pending rule */
FAIL_IF ( ! ( f . flags & FLOW_ACTION_ACCEPT ) ) ;
/* the pending rule won; the early rule never matched. The TD rule ran
* once , on completion . */
uint32_t late = 0 , early = 0 , td = 0 ;
for ( uint16_t i = 0 ; i < det_ctx - > alert_queue_size ; i + + ) {
if ( det_ctx - > alert_queue [ i ] . s = = s_late )
late + + ;
else if ( det_ctx - > alert_queue [ i ] . s = = s_early )
early + + ;
else if ( det_ctx - > alert_queue [ i ] . s = = s_td )
td + + ;
}
FAIL_IF ( late ! = 1 ) ;
FAIL_IF ( early ! = 0 ) ;
FAIL_IF ( td ! = 1 ) ;
UTHFreePackets ( & p2 , 1 ) ;
UTHFreePackets ( & p1 , 1 ) ;
DetectEngineThreadCtxDeinit ( & th_v , ( void * ) det_ctx ) ;
DetectEngineCtxFree ( de_ctx ) ;
AppLayerParserThreadCtxFree ( alp_tctx ) ;
StreamTcpFreeConfig ( true ) ;
FLOW_DESTROY ( & f ) ;
StatsThreadCleanup ( & th_v . stats ) ;
EngineModeSetIDS ( ) ;
PASS ;
}
/** \test a pending LTE rule the walk would discard must not hold the hook.
* Pins the filters in DetectFwLteRuleStillLive ( ) : a rule whose header and protocol
* checks pass but whose packet engines fail is no barrier , as the full walk would
@ -4971,6 +5095,7 @@ void SigRegisterTests(void)
UtRegisterTest ( " DetectFwLteCoverageTest01 " , DetectFwLteCoverageTest01 ) ;
UtRegisterTest ( " DetectFwLteCoverageTest02 " , DetectFwLteCoverageTest02 ) ;
UtRegisterTest ( " DetectFwLteCoverageTest03 " , DetectFwLteCoverageTest03 ) ;
UtRegisterTest ( " DetectFwLteMpmWalkTest01 " , DetectFwLteMpmWalkTest01 ) ;
UtRegisterTest ( " DetectFwLtePendingLiveTest01 " , DetectFwLtePendingLiveTest01 ) ;
UtRegisterTest ( " DetectFwLtePendingLivePolicyTest01 " , DetectFwLtePendingLivePolicyTest01 ) ;