What could you do with your code in 20 Lines or Less?

That's the question I like to ask for the DevCentral community, and every time I go looking to find cool new examples that show just how flexible and powerful iRules can be without getting in over your head.

This week we’ve got some great community driven examples, including one that’s so good I stretch the rules just a bit. Not that I’ve never done that before, but you know, it’s pretty rare. Mostly. Sort of.

 

Subnet based URI restriction

https://devcentral.f5.com/questions/can-anyone-explain-the-behaviour-of-this-irule

When a user posts a questions saying “Could someone please explain this code?” things are often a bit concerning for them. They’re in a bad place, and hoping for some help. Lucky for them, help is something of a speciality around the DC Q&A parts (rolls right off the tongue…), and help is what this user got. Not only did they get an explanation of what the code does, which is to block access to a particular URI unless traffic is coming from a couple of specific IP ranges; they also got a bit of help optimizing and cleaning up the code. Because community, that’s why.

when HTTP_REQUEST {
    log local0. " Request in [IP::client_addr] [HTTP::host][HTTP::uri]"
    if { ( [HTTP::uri] contains "/down.php" ) and not ( ( [IP::addr [IP::client_addr] equals 75.66.12.0/255.255.255.0] ) or ( [IP::addr [IP::client_addr] equals 15.150.0.0/255.255.0.0] ) ) } {
        log local0. " Blocked access [IP::client_addr] [HTTP::host][HTTP::uri]"
        # drop the request
        reject
    }
}

 

Remove Persistence Records

https://devcentral.f5.com/questions/can-i-delete-my-persistence-record-in-an-irule

Persistence is something that gets used a lot. Really a lot. Pretty much all the time. On all the apps. All over the place. Always. Perhaps that’s a slight exaggeration, but not by much. As such, it gets talked about often. Whether on DevCentral or elsewhere, persistence is a common theme and there is much conversation about how to do it right for each application. That’s why I was intrigued to see someone asking how to remove persistence records from their BIG-IP with an iRule. it stands to reason that if you’re doing persistence often, you might want to undo it at some point, too. Here’s a super simple way to do just that, at least for this specific case (the persist delete command is universal, though). Stick it in your back pocket for later.

when HTTP_REQUEST {
  if {[HTTP::uri] contains "persist=0"} {
    persist delete source_addr [IP::client_addr]
  }
}

 

Randomize SNAT

https://devcentral.f5.com/questions/randomize-snat

SNAT, or Secure/Source (It exists both ways in our docs, don’t blame me) Network Address Translation is a pretty common theme at F5. The idea is to translate one IP to another in a particular way. This isn’t a tutorial on SNAT, rather it’s a lesson in how to randomize the address you’re snatting to. That’s not something I’ve seen done before, and given just how cool this iRule is (making use of procs even!) I had to squeeze it in. For those of you going through each iRule and counting the number of lines, you may end up one or two over 20 on this one. It could easily be tweaked to fit inside 20, but I didn’t want to touch the grandeur. Nice work!

proc ip2int { ip } {
  set octets [split $ip .]
  set ipint [expr {(256 * 256 * 256 * [lindex $octets 0]) + (256 * 256 * [lindex $octets 1]) + (256 * [lindex $octets 2]) + [lindex $octets 3]}]
  return $ipint
}

proc random { max } {
  return [expr {int(rand()*($max+1))}]
}

when RULE_INIT {
  set static::snat_list {}
  foreach elm [class get snat_class] {
    scan [lindex $elm 0] {%[^/]/%s} ip mask
    set st [IP::addr $ip mask $mask]
    set num [expr {[call ip2int 255.255.255.255] - [call ip2int $mask] + 1}]
    for {set i 0} {$i < $num} {incr i} {
      set t [expr {[call ip2int $ip] + $i}]
      lappend static::snat_list [IP::addr parse -ipv4 [binary format I $t]]
    }
  }
  set static::snat_len [llength $static::snat_list]
  unset elm ip mask st num i t
}

when CLIENT_ACCEPTED {
  snat [lindex $static::snat_list [call random $static::snat_len]]
}