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
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
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 .
------------------------------------------