ADC-13.1-Rate limit gets hit unexpectedly when a rate limit identifier is used in different policies

ADC-13.1-Rate limit gets hit unexpectedly when a rate limit identifier is used in different policies

book

Article ID: CTX693304

calendar_today

Updated On:

Description

When we invoke one rate limit identifier from different polices, the rate limit gets hit unexpectedly.

The example config is as below:

add stream selector IP_URL_Selector HTTP.REQ.URL  CLIENT.IP.SRC
add ns limitIdentifier LIMIT_IP_URL -threshold 3 -selectorName IP_URL_Selector

add audit messageaction block_log_action INFORMATIONAL "\"Blocked_RATE LIMIT - \" + CLIENT.IP.SRC + \" \" + HTTP.REQ.METHOD + \" \" + HTTP.REQ.HEADER(\"HOST\") + HTTP.REQ.URL + \" \" + HTTP.REQ.VERSION +\" \"+ HTTP.REQ.HEADER(\"User-Agent\").SUBSTR(0,200) + \" <blocked>\""
add responder policy Res_policy1 "HTTP.REQ.METHOD.EQ(\"POST\") && HTTP.REQ.URL.PATH.SET_TEXT_MODE(IGNORECASE).EQUALS_ANY(\"<patset_name>") && SYS.CHECK_LIMIT(\"LIMIT_IP_URL\")" DROP -logAction block_log_action
=>Specific URLs are put in the patset and mentioned in Res_policy1

add audit messageaction noblock_log_action "\"NoBlocked_RATE LIMIT - \" + CLIENT.IP.SRC + \" \" + HTTP.REQ.METHOD + \" \" + HTTP.REQ.HEADER(\"HOST\") + HTTP.REQ.URL + \" \" + HTTP.REQ.VERSION +\" \"+ HTTP.REQ.HEADER(\"User-Agent\").SUBSTR(0,200)  + \" <not blocked>\""
add responder policy Res_policy2 "HTTP.REQ.METHOD.EQ(\"POST\")&&SYS.CHECK_LIMIT(\"LIMIT_IP_URL\")" NOOP -logAction noblock_log_action
=> URL is not specified in Res_policy2

bind responder global Res_policy1 90 END -type REQ_OVERRIDE
bind responder global Res_policy2 100 END -type REQ_DEFAULT 

 

The two polices use same rate limit identifier. One policy is bound to override global and the other is bound to default global. 

 

With the above config, you may expected that the requests to the URLs specified in the patset hit Res_policy1 and get blocked. However, the real situation is that Res_policy2 gets hit firstly

Resolution

We need to make sure that one rate limit identifer is used only in one place.  

The correct config is as below. We need to create two seperated rate limit selector and identifier and use them seperatedly in the two responder policies.

add stream selector IP_URL_Selector HTTP.REQ.URL  CLIENT.IP.SRC
add ns limitIdentifier LIMIT_IP_URL -threshold 3 -selectorName IP_URL_Selector

add stream selector IP_URL_Selector-2 HTTP.REQ.URL  CLIENT.IP.SRC
add ns limitIdentifier LIMIT_IP_URL-2 -threshold 3 -selectorName IP_URL_Selector-2
=> We need to add two Selectors and Limit Identifiers seperatedly as above

add audit messageaction block_log_action INFORMATIONAL "\"Blocked_RATE LIMIT - \" + CLIENT.IP.SRC + \" \" + HTTP.REQ.METHOD + \" \" + HTTP.REQ.HEADER(\"HOST\") + HTTP.REQ.URL + \" \" + HTTP.REQ.VERSION +\" \"+ HTTP.REQ.HEADER(\"User-Agent\").SUBSTR(0,200) + \" <blocked>\""
add responder policy Res_policy1 "HTTP.REQ.METHOD.EQ(\"POST\") && HTTP.REQ.URL.PATH.SET_TEXT_MODE(IGNORECASE).EQUALS_ANY(\"<patset_name>") && SYS.CHECK_LIMIT(\"LIMIT_IP_URL\")" DROP -logAction block_log_action
=>Invoke the first rate limite identifier in Res_policy1

add audit messageaction noblock_log_action "\"NoBlocked_RATE LIMIT - \" + CLIENT.IP.SRC + \" \" + HTTP.REQ.METHOD + \" \" + HTTP.REQ.HEADER(\"HOST\") + HTTP.REQ.URL + \" \" + HTTP.REQ.VERSION +\" \"+ HTTP.REQ.HEADER(\"User-Agent\").SUBSTR(0,200)  + \" <not blocked>\""
add responder policy Res_policy2 "HTTP.REQ.METHOD.EQ(\"POST\")&&SYS.CHECK_LIMIT(\"LIMIT_IP_URL-2\")" NOOP -logAction noblock_log_action
=> Invoke the second rate limite identifier in Res_policy2

bind responder global Res_policy1 90 END -type REQ_OVERRIDE
bind responder global Res_policy2 100 END -type REQ_DEFAULT 

 


Problem Cause

The counter of the rate limit will increase whenever it is invoked.  Using one rate limit identifer in different places will cause unexpected result. 

With the above config, we expect that the requests to the URLs specified in the patset hit Res_policy1 and get blocked. However, the real situation is that Res_policy2 will get hit firstly. The logic is as below:

------------------------------------------

When NetScaler receives the first request to the URLs specified in the patset, Res_policy1  will be evaluated firstly as it is bound to override global.  So SYS.CHECK_LIMIT(\"LIMIT_IP_URL\") will be invoked and checked for the first time. Now the counter for the rate limit will increase to 1. Since it doesn't exceed the threshold 3, Res_policy1 will not hit. 

Since Res_policy1 doesn't hit, Res_policy2 will be evaluated as it is bound to default global .  So SYS.CHECK_LIMIT(\"LIMIT_IP_URL\") will be invoked and checked for the second time. Now the counter for the rate limit will increase to 2. Since it doesn't exceed the threshold 3, Res_policy2 will also not hit. 

 

When NetScaler receives the second request to the URLs specified in the patset, Res_policy1 will be evaluated firstly.  So SYS.CHECK_LIMIT(\"LIMIT_IP_URL\") will be invoked and check for the third time. Now the counter for the rate limit will increase to 3. Since it doesn't exceed the threshold 3, Res_policy1 will not hit. 

Since Res_policy1 doesn't hit, Res_policy2 will be evaluated .  So SYS.CHECK_LIMIT(\"LIMIT_IP_URL\") will be invoked and check for the forth time. Now the counter for the rate limit will increase to 4. Since it  exceeds the threshold 3, Res_policy2 will hit.   However, it is not expected by us that Res_policy2 gets hit before Res_policy1 .

------------------------------------------