cancel
Showing results for 
Search instead for 
Did you mean: 

rate limit based on http error codes-source ip

furkansed
Nimbostratus
Nimbostratus

I'm looking for an irule to rate limit http response error codes coming from same client .

What we want to create is a check where a client that is coming is is checked . If he gets a 500 error code , we want to log it . When the same client would get the 500 error more than 2 times ,it should be blocked .

2 REPLIES 2

Hi @furkansed ,

 

Use the table command to limit HTTP requests as one is to create a single table entry that has as key the client IP address and the value is increased each time the user connects to the VIP

 

https://clouddocs.f5.com/api/irules/table.html

https://clouddocs.f5.com/training/community/irules/html/class2/module1/lab2.html

This is blocking the source IP address for some time but if we want rate limit then the next example is better.

https://community.f5.com/t5/technical-forum/f5-irule-table-command-rate-limit-or-block-http-requests...
https://community.f5.com/t5/technical-articles/advanced-irules-tables/ta-p/290369

 

HTH

Kai_Wilke
MVP
MVP

Hi Furkansed,

you may use the iRule below as a starting point. It checks for Err500 codes and tracks the total number a given Client IP has already triggered a err500 condition via LTMs session table. If the client exceeds its configured tresholds, the iRule will redirect him to a error page URL...

 

when RULE_INIT {
	
	# Global Configuration options
	
	set static::err500_threshold 	2		;# Number of err500 responses to activate the filtering
	set static::err500_timeout 		60		;# Timeout in seconds of an active filtering. If another err500 happens during the timeout period, it will restart the timeout window and keeps the filtering active.
	set static::err500_lifetime 	300		;# Maximum lifetime in seconds of an active filtering. After the lifetime is elapsed, the filtering will be removed. (set to "indef" if filtering timers should be base on timeouts only.)  
	set static::err500_error_page 	"/" 	;# Redirect URL for err500 responses exceeeding the limits 
}

when HTTP_REQUEST {

	# Storing HTTP host and path for logging during HTTP response
	
	set temp(orig_path) [HTTP::path]
	set temp(orig_host) [HTTP::host]

}
when HTTP_RESPONSE {

	# Check if err5xx is responded...
	
	if { [HTTP::status] >= 500 } then {

		# Error 500 detected. Checking the filtering state of the requesting Client IP Adress.
		
		if { [set temp(counter_value) [table incr -mustexist "err500_[IP::client_addr]" 1]] > $static::err500_threshold } then {
			
			# Err500 treshold has been massively exceeded. Silently redirecting the response to the error page.

			HTTP::respond 302 \
							noserver \
							"Location" $static::err500_error_page
							
		} elseif { $temp(counter_value) == $static::err500_threshold } then {
			
			# Err500 treshold has been just exceeded. Logging the request and redirecting the response to the error page.

			log local0.debug "IP=\"[IP::client_addr]\" just saw an ErrorCode=\"[HTTP::status]\" on Host=\"$temp(orig_host)\" and Path=\"$temp(orig_path)\". Err500 response counter for the client has just been exceeded. Redirecting to the error page."

			HTTP::respond 302 \
							noserver \
							"Location" $static::err500_error_page

		} elseif { $temp(counter_value) eq "" } then {
			
			# Client IP generate Err500 for the first time. Logging the request, initializing a new counter for the client and allowing the response to pass.
			
			log local0.debug "IP=\"[IP::client_addr]\" just saw an ErrorCode=\"[HTTP::status]\" on Host=\"$temp(orig_host)\" and Path=\"$temp(orig_path)\". Initializing a new err500 response counter for the client and allowing the response to pass."

			table set "err500_[IP::client_addr]" 1 $static::err500_timeout $static::err500_lifetime 

		} else { 

			# Client IP subsequently generate Err500. Logging the request, increasing counter for the client and allowing the response to pass.
			
			log local0.debug "IP=\"[IP::client_addr]\" just saw an ErrorCode=\"[HTTP::status]\" on Host=\"$temp(orig_host)\" and Path=\"$temp(orig_path)\". Increasing the err500 response counter for the client and allowing the response to pass."

		}
	
	}
	
}

 

Cheers, Kai