Forum Discussion

ant77's avatar
ant77
Icon for Cirrostratus rankCirrostratus
Jan 25, 2022

Check code for ordering of events and accuracy

Hi Everyone,

 

Can someone please check the code below to ensure we are doing the correct things for accuracy...

Objective: Since all internal users egress out via a FW and through a CDN and back in for site access, we need to check the source egress address of the firewall via the XFF header...So if it does not match this address, we consider the client as "non-internal" users and their traffic needs to be sent to a different pool then the default one tied to the VS. 

So the question here is, do we put this matching at the very beginning of this iRule or at the end...We need the other events below to still work for both external and internal users...It's just seperating out what web servers they connect to...External users goes to pool: EXTERNAL-POOL and internal users goes to the pool tied to this VS.

 

DG-INTERNAL-USERS-XFF = FW external IP since they egress out and back in...we use this to know if the client is internal.

So in this statement, if you are NOT (!) in this group, then your traffic is sent to the "EXTERNAL-POOL" containing

servers designated for external users...But if you match the FW IP defined in the "DG-INTERNAL-USERS-XFF" you get sent to the default pool (pool with different web servers than for external users) tied to this VIP...we want all the URI matching events below to still work regardless if you are internal or external.

Thanks everyone!

 

when HTTP_REQUEST {
set CHECK_IP [lindex [lsearch -all -inline -not -exact [split [HTTP::header values X-Forwarded-For] "\{\} ,"] {}] 0]
log local0. "the X-Forwarded-For header value is $CHECK_IP"

if { !([class match $CHECK_IP eq DG-INTERNAL-USERS-XFF]) } {
pool EXTERNAL-POOL

if { !([class match $CHECK_IP eq DG-INTERNAL-USERS-XFF]) } {
if { [class match [HTTP::uri] eq DG-URI-LIST] } {
reject }
  }

switch -glob [HTTP::uri] {
"*/app1/abc/portal/Tracker*" -
"*/app2/cde/Tracker*" -
"*/app3/wps/portal/CaseTracker*" {
if { ([class match $CHECK_IP eq DG-INTERNAL-USERS-XFF]) } {
if { [HTTP::uri] contains "/app2/Tracker" } {
HTTP::redirect "https://[HTTP::host]/new-app2/Tracker"
} else {
HTTP::redirect "https://[HTTP::host]/app1/old/portal/Tracker/"
               }
            }
         }
      }
   }
}

4 Replies

  • All the action exists in a single event. The client will be redirected or not, the external pool will be selected or not, so the line by line order doesn't matter so much as how you construct your logic. I personally don't like to leave logic on pool selection spread across objects, such as having a default pool that isn't visible in the rule, so even if you specify a default pool, I'd still be explicit to send traffic there if they do match internal users. But that's my preference, not required. I'd also combine your logic to set the pool and/or reject so that you don't have to check the XFF IP data-group twice, so make the if condition about the data-group, then inside that condition, you can do an if/else for the URI

    • ant77's avatar
      ant77
      Icon for Cirrostratus rankCirrostratus

      Thanks Jason...

      I added the specific pool in the irule so that if users XFF IP matches the "DG-INTERNAL-USERS-XFF" gets sent to the internal pool designated for internal employees...

      What would be the best way to group the pool/reject together here?

      f { !([class match $CHECK_IP eq DG-INTERNAL-USERS-XFF]) } {
      pool EXTERNAL-POOL
      } else {
      pool INTERNAL-POOL

      if { !([class match $CHECK_IP eq DG-INTERNAL-USERS-XFF]) } {
      if { [class match [HTTP::uri] eq DG-URI-LIST] } {
      reject }
      }

       

      ########## Modified with default internal Pool in iRule #########

      when HTTP_REQUEST {
      set CHECK_IP [lindex [lsearch -all -inline -not -exact [split [HTTP::header values X-Forwarded-For] "\{\} ,"] {}] 0]
      log local0. "the X-Forwarded-For header value is $CHECK_IP"

      if { !([class match $CHECK_IP eq DG-INTERNAL-USERS-XFF]) } {
      pool EXTERNAL-POOL
      } else {
      pool INTERNAL-POOL

      if { !([class match $CHECK_IP eq DG-INTERNAL-USERS-XFF]) } {
      if { [class match [HTTP::uri] eq DG-URI-LIST] } {
      reject }
      }

      switch -glob [HTTP::uri] {
      "*/app1/abc/portal/Tracker*" -
      "*/app2/cde/Tracker*" -
      "*/app3/wps/portal/CaseTracker*" {
      if { ([class match $CHECK_IP eq DG-INTERNAL-USERS-XFF]) } {
      if { [HTTP::uri] contains "/app2/Tracker" } {
      HTTP::redirect "https://[HTTP::host]/new-app2/Tracker"
      } else {
      HTTP::redirect "https://[HTTP::host]/app1/old/portal/Tracker/"
      }
      }
      }
      }
      }
      }

  • I'd probably rewrite the rule to look something like this (make sure to test, no guarantees):

    when HTTP_REQUEST priority 500 {
        set CHECK_IP [lindex [lsearch -all -inline -not -exact [split [HTTP::header values X-Forwarded-For] "\{\} ,"] {}] 0]
        switch -glob -- [HTTP::uri] {
            "*/app1/abc/portal/Tracker*" -
            "*/app2/cde/Tracker*" -
            "*/app3/wps/portal/CaseTracker*" {
                if { ([class match -- $CHECK_IP eq DG-INTERNAL-USERS-XFF]) } {
                    if { [HTTP::uri] contains "/app2/Tracker" } {
                        HTTP::redirect "https://[HTTP::host]/new-app2/Tracker"
                        return
                    } else {
                        HTTP::redirect "https://[HTTP::host]/app1/old/portal/Tracker/"
                        return
                    }
                }
            }
        }
        log local0. "the X-Forwarded-For header value is $CHECK_IP"
    
        if { !([class match -- $CHECK_IP eq DG-INTERNAL-USERS-XFF]) } {
            if { [class match -- [HTTP::uri] eq DG-URI-LIST] } {
                reject
                return
            }
            pool EXTERNAL-POOL
        } else {
            pool INTERNAL-POOL
        }
    }

    Some notes:

    • I like to explicitly return after a redirect, there's no need for the iRule to continue processing
    • I added "--" to the class and switch commands to terminate option processing
    • I moved the redirects up top since that isn't furthering the connections toward your pool resources

    You understand your app, so make sure this makes sense and test, test, test (and not in production.)
     

    • ant77's avatar
      ant77
      Icon for Cirrostratus rankCirrostratus

      Thank you Jason! Your version is a much cleaner and better way of doing it...Thanks again!