iRULE – True-Client-IP Block

Sometimes a customer may serve the content from a Virtual Server via Akamai and may want to block a specific client IP that is presented in the “True-Client-IP” that is inserted by Akamai. The following iRULE would provide the required functionality:

when HTTP_REQUEST { set HOST [string tolower [HTTP::host]] if { ([HTTP::header exists "True-Client-IP"]) and ([HTTP::header "True-Client-IP"] != "") } { set True_Client_IP [HTTP::header "True-Client-IP"] } else { set True_Client_IP 0.0.0.0 } if { [class match $True_Client_IP equals CLASS_BLOCK_IP] } { discard } }

Discard would silently drop the connection. Reject can be utilized instead of Discard. Reject would send a TCP reset to the client. Instead of Reject or Discard, we can also serve a sorry page or a redirect, if required.

iRule – Altering Header Information

This iRULE example will alter the incoming URI before passing the request to the servers:

when HTTP_REQUEST { switch -glob [HTTP::uri] { /old_URI/* { HTTP::uri /new_URI[HTTP::uri] } } }

In this case, for any incoming request that starts with the URI “/old_URI/” (http://domain.com/old_URI/), the “/old_URI/” will be replaced with “/new_URI/old_URI” and this will be passed to the servers (http://domain.com/new_URI/old_URI/)

The various interpretations within the switch statement:

/old_URI/      – URI equals /old_URI/
/old_URI/*    – URI starts with /old_URI/
*/old_URI/* – URI contains /old_URI/

Instead of the “switch” statement, we can also use an “if-statement” like this:

when HTTP_REQUEST { if { [HTTP::uri] starts_with "/old_URI/" } { HTTP::uri /new_URI[HTTP::uri] } }

A slightly more complex version of the URI function alteration is provided here:

when HTTP_REQUEST { set HOST [string tolower [HTTP::host]] set URI [string tolower [HTTP::uri]] if { $URI contains "/NEW_Session_ID=" } {HTTP::uri [string map {/NEW_Session_ID= /OLD_Session_ID=} [HTTP::uri]] pool POOL-WEB-Server } } when HTTP_RESPONSE { if { [HTTP::header values Location] contains "/OLD_Session_ID=" } { HTTP::header replace Location [string map {/OLD_Session_ID= /NEW_Session_ID=} [HTTP::header value Location]] } }

For any incoming HTTP Request, “/NEW_Session_ID=” within the URI is replaced with “/OLD_Session_ID=” and passed to the servers in the pool “POOL-WEB-Server”.

For any HTTP Response from the server to the client that contains the HTTP Header Location, “/OLD_Session_ID=” is replaced with “/NEW_Session_ID=”

This can be used to “mask” the URI or any other header information between the client and the server.

The following iRule will remove “/m/” in the incoming URI and send a redirect:


when HTTP_REQUEST {
set URI [string tolower [HTTP::uri]]
if {$URI starts_with "/m/" }{ 
set NEW_URI [string map {"/m/" "/"} [HTTP::uri]] 
HTTP::respond 301 Location "http://www.domain.com$NEW_URI"
}
}

TEST:

$ curl -I http://10.10.10.10/m/OLD_URI
HTTP/1.0 301 Moved Permanently
Location: http://www.domain.com/OLD_URI
Server: BigIP
Connection: Keep-Alive
Content-Length: 0

The “/m/” in the URI is replaced with “/” as seen in the “Location” header.

This has been tested in production environment on 10.x code of F5 LTM

iRULE – non-English Characters

The web browser will URL encode URI’s that contain special characters.

For example, http://www.domain.com/été is encoded as follows: http://www.domain.com/%C3%A9t%C3%A9

when HTTP_REQUEST { 

set ENCODED_URI [ b64encode [HTTP::uri]]

    switch [HTTP::host] { "domain.com" { 

          if { (($ENCODED_URI eq "LyVDMyVBOXQlQzMlQTk=") or ($ENCODED_URI eq "L2ZyLyVDMyVBOXQlQzMlQTk=")) } 

{ pool POOL_Web-Servers } 

} 

}

}

“/été” URL encodes to “/%C3%A9t%C3%A9″ which base64 encodes to “LyVDMyVBOXQlQzMlQTk=”

“/fr/été” URL encodes to “/fr/%C3%A9t%C3%A9” which base64 encodes to “L2ZyLyVDMyVBOXQlQzMlQTk=”

An Intro to iRULE

This post will provide basic information related to iRULE. The intention of writing this post is to provide someone new to iRULE with basic introduction and cover some of the often used Functionality. This isn’t an in-depth coverage of iRule.

What is an iRULE:

TCL based scripting that is utilized by F5 Application Delivery Modules to manipulate traffic.

Structure of an iRULE:

when <EVENT> {
<PERFORM ACTION>
}

Commonly used iRULE Events:

  • HTTP_REQUEST
  • HTTP_RESPONSE
  • CLIENT_ACCEPTED

Having worked with iRules for almost 5 years, the above 3 events are what I utilize on a daily basis. Almost 9 out of 10 iRules that I have written cover the above events. For an iRule rookie, I would recommend understanding the above 3 events.

Within the structure of the iRule, <PERFORM_ACTION> provides the ACTION to be performed if certain CONDITIONS are matched. For example:

if { [HTTP::host] equals “domain.com” } {
pool POOL_WEB-SERVER
}

Even if you don’t understand scripting, the above information should be quite clear that you are sending the traffic to the pool: POOL_WEB-SERVER, if the incoming host header equals “domain.com” 🙂

Common ACTIONS that I have utilized:

  • Load Balancing based on incoming header values
  • Redirection based on incoming header values
  • Persistence based on incoming header values

As seen above, the vast majority of ACTIONS involve one of three actions based on the incoming header value. We can also perform more complicated actions based on the content of the incoming packet. However, in my opinion, it is better to avoid performing such actions on the load balancer. As the code gets complex, there is a serious question on accountability and ownership – who owns the code (Dev guys, Network guys ?!?) – this requires a separate post just to hash out the realms of control.

Points to Remember:

  • iRULE is TCL based scripting utilized to manipulate traffic on an F5 device
  • iRULE, like TCL is EVENT based
  • iRULE’s structure consists of EVENT, CONDITIONAL statements & ACTION to perform

Migrating DNS Providers

When migrating your DNS records from a DNS provider to another DNS provider, make sure to follow the following:

  • Lower the TTL for your DNS records to the lowest possible value provided by your DNS provider
  • Create a copy of the DNS records at the new DNS provider.
  • Do NOT delete the DNS records at your old DNS provider.
  • Update the name servers at your domain registrar.
It takes about 48 hours for the NS record to be updated as the TLD (Top Level Domains) have a default TTL of 48 hours. For the duration of 48 hours, both your old and new DNS provider will be queried for DNS record information, depending on the cached DNS records information at the Local DNS servers. After you can verify from different locations in the world that the NS record has changed, I would recommend waiting for another 2 days before deleting the old NS records.

Changing DNS Records

Whenever you have to change your existing DNS records, without migrating your DNS provider (without changing the name servers), make sure to lower the TTL value of your DNS records to as low as possible. Some DNS providers have a default TTL value and your DNS record’s TTL will reset to the default value after a specific number of days. In order to prevent this reset to your DNS provider’s default TTL value, make sure to “freeze” the TTL value for a few days before and after the actual change is made.