iRules Common Concepts¶
1.) Logging¶
By making use of the built in logging features that are available to
you when writing iRules you’ll be able to see what the expected
outcome of a rule will be before effecting live traffic, troubleshoot
a malfunctioning rule by identifying which sections are failing,
identify errors in logic or coding that are returning unexpected
results, etc. Logging is the first step in any good troubleshooting
guide once you’ve confirmed the rule compiles properly. Logging is
your friend!
iRule Source
when HTTP_REQUEST {
log local0. "Domain: [HTTP::host]"
log local0. "URI: [HTTP::uri]"
}
when HTTP_RESPONSE {
if { [HTTP::header exists "Location"] } {
log local0. "Location: [HTTP::header Location]"
}
}
Logging is great for troubleshooting, but can impact performance.
Rather than adding logging statements for troubleshooting and removing
them when finished, you can set a debug variable and place all
appropriate logging within IF statements so the logging can be enabled
& disabled with a single variable setting.
Note: The static prefix was introduced with v10 and allows for
Clustered Multi-Processing (CMP; effectively multicore or parallel
processing) compatible variables (read only constants or per TMM
read/write). A separate copy of each variable marked static is
created on each TMM instance (effectively each processor core) and
each instance is completely independent of the others.
when RULE_INIT {
set ::debug 1
}
when HTTP_REQUEST {
if { $::debug } {
log local0. "Domain: [HTTP::host]"
log local0. "URI: [HTTP::uri]"
}
}
when HTTP_RESPONSE {
if { $::debug } {
if { [HTTP::header exists "Location"] } {
log local0. "Location: [HTTP::header Location]"
}
}
}
2.) HTTP Redirect¶
Simple HTTP redirect upon connecting to a particular URI. This is a
very commonly requested iRule function, though sometimes the logic
surrounding the redirect itself can be a bit more involved, the
concept remains the same. Make logical comparisons, if a certain
criteria is found, send the request to a given location.
iRule Source
when HTTP_REQUEST {
if {[HTTP::path] eq "/"}{
log local0. "redirecting client [IP::client_addr]"
HTTP::redirect "http://[HTTP::host]/cda/homepage.do"
}
}
Also see: HTTPToHTTPSRedirect_302
3.) URI Re-Writing¶
Users often times want to be able to seamlessly re-write the URI
portion of the HTTP request a user sends in. For instance, when you
request http://mydomain.com, you get sent to
http://mydomain.com/userlogin.aspx?login=new This can be done without
a redirect, and is transparent to the user until the response from the
server contains the new URI.
iRule Source
when HTTP_REQUEST {
if {[HTTP::uri] == "/"}{
HTTP::uri "/New/URI"
}
}
4.) JSessionID Persistence¶
This rule searches for the JSESSIONID stored in a cookie and persists
based on that information if it exists. Many different permutations of
such a rule might exist, including ones that look in the URI for the
JSESSIONID, or perform different actions when one is not found.
iRule Source
when HTTP_REQUEST {
if { [HTTP::cookie exists "JSESSIONID"] } {
persist uie [HTTP::cookie "JSESSIONID"]
} else {
set jsess [findstr [string tolower [HTTP::query]] "jsessionid" 11 ";"]
if { $jsess != "" } {
persist uie $jsess
}
}
}
5.) Limit the number of Client Requests¶
This rule limits the number of connections that any given client IP
can establish with the virtual server that the rule is applied to.
This can be modified to include a white-list of internal or trusted
IPs that wouldn’t be subject to the limiting, to redirect those that
exceed the limit to an explanation page, etc. With the normal_close
local variable, we only decrease the amount of active connections if
the close event is executed normally, and not after the reject command
execution from the CLIENT_ACCEPTED event.
iRule Source
when RULE_INIT {
array set ::active_clients { }
}
when CLIENT_ACCEPTED {
set client_ip [IP::remote_addr]
set normal_close 1
if { [info exists ::active_clients($client_ip)] } {
if {$::active_clients($client_ip) > 5 } {
set normal_close 0
reject
return
} else {
incr ::active_clients($client_ip)
}
} else {
set ::active_clients($client_ip) 1
}
}
when CLIENT_CLOSED {
if { $normal_close eq 1 }
{
if { [info exists ::active_clients($client_ip)] } {
incr ::active_clients($client_ip) -1
if { $::active_clients($client_ip) <= 0 } {
unset ::active_clients($client_ip)
}
}
}
}
6.) Information inserted into HTTP Header (Header Inserts/Reading)¶
Many users are looking to store some information from the SSL cert or
transaction in a header to be passed to their back-end servers for use
in a later
iRule Source
when CLIENTSSL_CLIENTCERT {
# set time to maintain session data (in seconds)
set session_timeout 300
set ssl_stuff [list anything1 anything2]
set ssl_cert [SSL::cert 0]
set ssl_errstr [X509::verify_cert_error_string [SSL::verify_result]]
lset ssl_stuff 0 $ssl_cert
lset ssl_stuff 1 $ssl_errstr
session add ssl [SSL::sessionid] $ssl_stuff $session_timeout
}
when HTTP_REQUEST {
set ssl_stuff2 [session lookup ssl [SSL::sessionid]]
set ssl_cert2 [lindex $ssl_stuff2 0]
set ssl_errstr2 [lindex $ssl_stuff2 1]
if { $ssl_errstr2 eq "ok" } {
HTTP::header insert SSLClientCertStatus $ssl_errstr2
HTTP::header insert SSLClientCertSN [X509::serial_number $ssl_cert2]
} else {
# send HTTP 302 redirect to an error page
HTTP::redirect "http://192.168.0.64/error.html"
}
}
7.) Loadbalance Reselect¶
There are certain situations in which users want to use the same
request that was sent from the client, but retry transmitting it to a
different member of a pool (whether it’s the same pool as the last
attempt or not). This can be because of a failure on the first attempt
or because of some application needs they have in their configuration.
iRule Source
when CLIENT_ACCEPTED {
TCP::collect 34
}
when CLIENT_DATA {
set usrid [string range [TCP::payload] 24 33]
if {[regexp {\d{10}} $usrid]} {
persist uie $usrid
log local0. "Persisting $usrid"
}
}
when LB_FAILED {
set p [LB::server pool]
set n [LB::server addr]
log local0. "Set node down: $n"
LB::down node $n
log local0. "Deleting $usrid from Pool $p"
persist delete uie $usrid
LB::detach
LB::reselect pool $p
set x [LB::server addr]
log local0. "After reselect node is $x"
}
8.) Query Pool for Information¶
Some commands allow you to query a given pool for information, whether
that’s the active_members command to see how many pool members are
marked as up, or something like the LB::status command, the
information can be used in many different and useful ways.
iRule Source
when LB_FAILED {
if { [LB::status pool $poolname member $ip $port] eq "down" } {
log "Server $ip $port down!"
}
}
when HTTP_REQUEST {
if { [active_members your_pool] < 1 } {
HTTP::redirect "http://somedomain.com/somepage.html"
} else {
pool your_pool
}
}
9.) Session / Persistence table lookups¶
Besides being extremely useful ways to retrieve information being
stored in the Session or Persistence tables, knowing how to perform
session and persistence lookups allows users to store data in those
tables as opposed to using the much more resource intensive, messier
global variable option.
iRule Source
when HTTP_REQUEST {
set persistA [persist lookup simple [IP::client_addr]]
log "persistA output is $persistA"
}
when CLIENTSSL_CLIENTCERT {
log "begining"
log "ssl cert count = + [SSL::cert count]"
if { [SSL::cert count] > 0 } {
session add ssl [SSL::sessionid] [X509::cert_fields [SSL::cert 0]
[SSL::verify_result] whole] 450
log "session ID: + [SSL::sessionid] + [X509::cert_fields [SSL::cert 0] [SSL::verify_result] whole]"
log "certfields lookup = [session lookup ssl {[SSL::sessionid] any}]"
}
}
10.) Using matchclass and findclass to query Data Groups¶
By storing data in Data Groups or “classes”, users are able to store
large data structures in an organized, reasonably efficient structure
that allows for use across multiple connections in a flexible manner.
iRule Source
class myCSID {
"b02181 pl_1"
"h05527 pl_1"
"x07770 pl_2"
"y07070 pl_3"
}
iRule Source
when HTTP_REQUEST {
set CSID [string tolower [URI::path [HTTP::uri] 1 1]]
if { [matchclass $::myCSID starts_with $CSID] } {
pool [findclass $CSID $::myCSID " "]
} else {
pool defaultPool
}
}
The BIG-IP API Reference documentation contains community-contributed content. F5 does not monitor or control community code contributions. We make no guarantees or warranties regarding the available code, and it may contain errors, defects, bugs, inaccuracies, or security vulnerabilities. Your access to and use of any code available in the BIG-IP API reference guides is solely at your own risk.