iRule

F5 iRule — Syslog Dynamic DPort Translator

An interesting question came up the other day, we have multiple endpoints sending syslogs into a F5 VIP fronting a syslog collector…all on port 514. Our logging team wanted to change the port from 514 to different ports depending on the originating endpoint. Without changing each endpoints configuration to the desired new port, we thought maybe we could do this with an iRule.

 

when CLIENT_ACCEPTED {
  #Grab CLLIENT IP
  set clientIP [IP::client_addr] 
  
  #set default syslog port
  set destSyslogPort 514
  
  #check IP against DataGroup
  if {[class match $clientIP equals DG_SplunkPorts] } {
    #get corrisponding port fro DG_SplunkPorts
    set destSyslogPort [class lookup $clientIP DG_SplunkPorts]
   
  } else {
    #set as default 514
    set destSyslogPort 514
  }
}
when LB_SELECTED {
        LB::reselect node [LB::server addr] $destSyslogPort 
}

First we grab the $clientIP, as we will need this to lookup the corresponding value in the DataGroup. We also need to set the variable $destSyslogPortto 514 by default in case the $clientIPis not found…Next we use a class match statement to search for the value, if any, using the $clientIPWith the found port value, or the default, we then need to modify the LB selection process.

At this point the F5 has already chosen a backend server to load balance to, so we need to intercept this with the ‘when LB_SELECTED‘ event.  Within this event we tell the F5 to ‘reselect’ the chosen backend node t, in this case [LB::server addr] which is same node already selected, cleverly retaining the same backend node selected.  Lastly we set the destination port with $destSyslogPort.

DG_SplunkPorts “The Data Group Used”

F5 iRule — Syslog Cloning iRule with HSL or Sideband

HSL_syslog_cloning

First lets create two(2) pools with a single node in each. These will be used in our iRule to clone the UDP datagram to both.

pool_SyslogServer001

pool_SyslogServer001

Now that we created the two(2) pools with single nodes in each, we can craft the irule to utilize HighSpeedLogging(HSL) in an iRule and tie it alltogether.

when CLIENT_ACCEPTED {
    set syslog_pool1 [HSL::open -proto UDP -pool pool_SyslogServer001] 
    set syslog_pool2 [HSL::open -proto UDP -pool pool_SyslogServer002] 
}
when CLIENT_DATA {
  HSL::send $syslog_pool1 [UDP::payload]
  HSL::send $syslog_pool2 [UDP::payload] 

}
Pros Cons
  • Each HSL send destination requires a unique pool with one node in it.
  • Cannot change source address (has to be self IP F5 LTM)

SIDEBAND_syslog_cloning

Now a different approach is to use iRule sideband method. Sideband was introduced in TMOS-LTMv11.0.0 so it will be needed for the SIDEBAND method to be available for use. It pretty much opens a TCP or UDP connection when the iRule get triggered.

when CLIENT_ACCEPTED {

  # grab UDP payload
  set data [UDP::payload]
  
  # create connection objects to both servers
  set conn_id1 [connect -protocol UDP -myaddr 1.1.1.1 -timeout 100 -idle 30 10.10.10.1:514]
  set conn_id2 [connect -protocol UDP -myaddr 1.1.1.1 -timeout 100 -idle 30 10.10.10.2:514]
  
  # send sideband request to server1
  send -timeout 1000 $conn_id1 $data
  close $conn_id1
  # send sideband request to server1
  send -timeout 1000 $conn_id2 $data
  close $conn_id2
}
Pros Cons
  • More control, we can change things like source address and timeouts
  • No pools needed, can craft connection object directly in iRule

 

References:

F5 iRule — No Pool Members Available Vanity Page

I wrote a iRule post located here, where I describe the essentials behind how beneficial iRules can be and the many use cases they have. I stumbled across a situation the other day for a client. This client had an F5 VIP load balancing 2 web servers of theirs. Now if those web servers for some reason are not available due to their healthcheck monitor failing, the users of that web site will receive a white page as the F5 will not proxy the traffic because there are no available pool members. I thought what if this was a big site, should users be left in the dark about a web site they use frequently when it’s not available? Then the idea of having the F5 LTM bounce back a well-formed splash page. This splash page would inform the user that the web site temporarily down, and if they believe this result is in error to contact their helpdesk.

This situation can be remedied with a couple of lines in an iRule.

when HTTP_REQUEST {
    #check if no members available
    if { [active_members [LB::server pool]] == 0 } {
       #create data variables with HTML content to send to client
       set httphost [string tolower [HTTP::host]]
       set data "<h2>$httphost</h2><h3>NOTICE: Site Unavailable.</h3>If you believe you are receiving this message in error, contact your site administrator."
       #send the HTML string
       HTTP::respond 200 content $data
    }
    #unset variables
    unset $httphost
    unset $data
}

Continue reading…

F5 BIGIP — iRule Server Selection based on Client Source Address and Port

A interesting request came up today regarding a Web Service we provide to multiple clients, all of whom have peering points connecting their IP network to ours using private address. The request was to have certain clients hit a particular Web box in a Server Pool, while others hitting the other. At the same time only for certain ports. Some of our web applications use a variety of ports because of the proprietary application running. Ports include, all TCP, 80, 443, 5555, 6050.  So I set off to create an iRule to handle this and have it log to show how everything is being mapped, start to finish for each connection.

A Service little info:

  • Client PAT = 10.99.29.10
  • PrimaryWebCluster = 10.43.1.6
  • Web01 = 10.43.4.231
  • Web02 = 10.43.4.232
  • Ports = 80, 443, 5555, 6050

iRule: irule_SrvSelection_byClientSrcAndPort

when CLIENT_ACCEPTED {    
     if { [TCP::local_port] == 80 } {  
        if { [IP::addr [IP::client_addr] equals 10.99.29.10] } {        
        pool pool_ct_primarywebcluster_80 member 10.43.4.231 80
        log local0. "[IP::client_addr] is Web01"            
        } else {        
         pool pool_ct_primarywebcluster_80 member 10.43.4.232 80    
        log local0. "[IP::client_addr] is Web02"          
        }
    }
    if { [TCP::local_port] == 443 } {
        if { [IP::addr [IP::client_addr] equals 10.99.29.10] } {        
        pool pool_ct_primarywebcluster_443 member 10.43.4.231 443
        log local0. "[IP::client_addr] is Web01"            
        } else {        
         pool pool_ct_primarywebcluster_443 member 10.43.4.232 443
        log local0. "[IP::client_addr] is Web02"  
        }
    }
if { [TCP::local_port] == 5555 } {
        if { [IP::addr [IP::client_addr] equals 10.99.29.10] } {        
        pool pool_ct_primarywebcluster_5022 member 10.43.4.231 5022
        log local0. "[IP::client_addr] is Web01"   
        } else {        
         pool pool_ct_primarywebcluster_5022 member 10.43.4.232 5022
        log local0. "[IP::client_addr] is Web02"  
        }
    }
}

if { [TCP::local_port] == 6050 } {
        if { [IP::addr [IP::client_addr] equals 10.99.29.10] } {        
        pool pool_ct_primarywebcluster_5022 member 10.43.4.231 5022
        log local0. "[IP::client_addr] is Web01"   
        } else {        
         pool pool_ct_primarywebcluster_5022 member 10.43.4.232 5022
        log local0. "[IP::client_addr] is Web02"  
        }
    }
}
when SERVER_CONNECTED {
  log local0. "Connection from [IP::client_addr]:[TCP::client_port]. \
    Mapped to F5 Floating IP [serverside {IP::local_addr}]:[serverside {TCP::local_port}] \
    -->> [IP::server_addr]:[serverside {TCP::remote_port}]"
}

 

And to check, SSH into the Primary F5 in the pair and type bash to give you shell access. (BIGIP v11.5+),

tailf /var/log/ltm
tmm3[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : 10.99.29.10 is Web02
tmm3[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : Connection from 10.99.29.10:22524. to VIP 10.43.1.6  -->> 10.43.4.232:443
tmm3[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : 10.99.29.10 is Web02
tmm3[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : Connection from 10.99.29.10:10972. to VIP 10.43.1.6  -->> 10.43.4.232:443
tmm[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : 10.99.29.10 is Web02
tmm[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : Connection from 10.99.29.10:53187. to VIP 10.43.1.6  -->> 10.43.4.232:443
tmm2[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : 10.99.29.10 is Web02
tmm2[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : Connection from 10.99.29.10:15709. to VIP 10.43.1.6  -->> 10.43.4.232:443
tmm3[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : 10.99.29.10 is Web02
tmm3[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : Connection from 10.99.29.10:62364. to VIP 10.43.1.6  -->> 10.43.4.232:443
tmm3[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : 10.99.29.10 is Web02
tmm3[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : Connection from 10.99.29.10:62496. to VIP 10.43.1.6  -->> 10.43.4.232:443
tmm[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : 10.99.29.10 is Web02
tmm[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : Connection from 10.99.29.10:42691. to VIP 10.43.1.6  -->> 10.43.4.232:443
tmm1[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : 10.99.29.10 is Web02
tmm1[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : Connection from 10.99.29.10:28510. to VIP 10.43.1.6  -->> 10.43.4.232:443
tmm3[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : 10.99.29.10 is Web02
tmm3[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : Connection from 10.99.29.10:40464. to VIP 10.43.1.6  -->> 10.43.4.232:443
tmm1[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : 10.99.29.10 is Web02
tmm1[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : Connection from 10.99.29.10:4082. to VIP 10.43.1.6  -->> 10.43.4.232:443
tmm[14225]: Rule /Common/irule_SrvSelection_byClientSrcAndPort : 10.99.29.10 is Web02

Nice!!

F5 BIGIP — iRule Block URI for external Client’s only

So, I had a cool question asked to me today regarding an F5 VIP used by a web application.
“Can we block a certain URI from external client’s but allow internal client’s to visit it?”

Of course there is!! Now there are probably a billion different ways to do this, but this is what I came up with.

First the condition, we want only 10.0.0.0/8 hosts to be able to access this restricted URI. Anyone else should be dropped. I say dropped and not denied, because that way if a user tries to navigate to the URI that shouldn’t it just timesout, and doesn’t give them any more information then they need. Second, I want to log blocks, so I can see it working and get an idea of how many times it gets hit. Lastly we need to know the Virtual server to apply the iRule to.

Here is the finished iRule, hope it helps!

when RULE_INIT {
	set static::drop_notallowed 0

}

when CLIENT_ACCEPTED {
	if {not [IP::addr [IP::client_addr] equals 10.0.0.0/8]} {
                log local0. "[IP::client_addr] does not match 10.0.0.0/8 AND access URI = /restricted-URI/"
		set static::drop_notallowed 1
	}
}

when HTTP_REQUEST {
	if { [string tolower [HTTP::uri]] starts_with "/restricted-URI" }{
		if {$static::drop_notallowed==1}{
			drop
		}
	}

}

Continue reading…

F5 BIGIP — iRules….What are they?

What is an iRule? What are iRules? What can I do with iRules? What is an iRule example?

One of the most advantageous features that an BIG IP F5 Local Traffic Manager brings is it’s iRule feature. This feature allows the F5 to manipulate and perform event driven functions to the application traffic as it passes through the F5 LTM. This is very useful and has many use cases. For example, a common iRule is as follows. Let’s say you have a typical load balancing setup, with 5 web servers being balanced in a round robin fashion. The traffic that passes through is HTTP. For security purposes only HTTP-SSL is allowed to this site, however you don’t want users to have to remember to put https:// rather than http:// in their internet browser’s address bar. Instead of putting a redirect page on the port 80(insecure) instance on each of the 5 web servers, a simple iRule will take care of that!

Example HTTP to HTTPS redirect iRule:

#my first iRule 
when HTTP_REQUEST { 
    HTTP::redirect "https://[HTTP::host][HTTP::uri]" 
}

When we look at this iRule we see a few things. We see an event that must be triggered in order to for the iRule to execute, “when HTTP_REQUEST“. Next we see a HTTP redirect function being performed with a few parameters. HTTP::redirect is the function and the target URL string “https://[HTTP::host][HTTP::uri]”. Let’s break this statement down as it is the meat and potatoes of the iRule.

https:// is what protocol to send the users browser when it performs the redirect.

[HTTP::host] which is derived from the clients host-header as it comes across to the F5 LTM. The host header is set when you open a new browser and type the domain/host you are requesting to go to. For example, if you type http://www.google.com in your browser, when you hit enter in the HTTP stream the host-header is set to www.google.com. This is essential when using SSL, but more on that in another post.

[HTTP::uri] the last part is the URI the user is trying to GET. If this is a standalone site such as www.mysite.com, usually users will hit that first and be redirect already via our iRule before they browse to any URIs. However, perhaps a user tries to go to http://yousite.com/URI, they are not coming across HTTPS so the iRule will intercept it and redirect them to https://yoursite.com, but wait we don’t want them to get kicked back to the root of the site, so the [HTTP::uri] is appended to the redirect target string.

URIs vs URLs:
You will see people use these interchangeably, or used in-properly. Even Wikipedia’s article on them is confusing. A URI is what is appended at the end of the host or FQDN, and a URL is the whole thing.

So,
http://en.wikipedia.org/wiki/Computer

FQDN = en.wikipedia.org
URI = wiki/Computer
URL = http://en.wikipedia.org/wiki/Computer