Forum Discussion

Tony2020's avatar
Tony2020
Icon for Nimbostratus rankNimbostratus
Jun 27, 2016

Parse XFF header for Client IP and allow based on URI and DataGroup match

Hi Guys,

 

I am trying to restrict access to certain URIs and looking at the XFF header (read/strip) from an iRule but having issue paring the IPs from XFF to make logical decision off of it.

 

Below is a code Iam trying to get working...any help or recommendation would be great.

 

Here is what I need to happen.

 

  1. User coming in from the internet (non-internal IP range) going to those URIs gets dropped
  2. User coming in from internally that has the XFF original client IP going to those two URI gets allowed. Note, the reason why we need to read the XFF is because users goes out to a CDN (they will add orginal IP) and bounce back in. I need to add to the data group the external IP of our FW since this is the egress point. External IP for this site points to the CDN public IP, so there is no way to get to this unless you go through the CDN.

Appreciate all the help!

 

Flow:

 

Internal users for CompanyX --> Website ---> CompanyX FW --> external CDN --> Back to CompanyX FW --> CompanyX webserver --website

 

ltm data-group internal DG-ALLLOWED-IPs { records { 10.0.0.0/8 { } 1.1.1.1/32 { } Example of our external FW IP } type ip }

 

when HTTP_REQUEST { switch -glob [string tolower [HTTP::uri]] { "/login-developer" - "/login-admin.asp" {

 

if {[HTTP::header "X-Forwarded-For"] ne ""}{ log local0. "XFF: [HTTP::header "X-Forwarded-For"]" foreach xff [split [string map [list " " ""] [HTTP::header "X-Forwarded-For"]] ","] { log local0. "Current XFF element: $xff"

 

if { !([matchclass [IP::client_addr] equals DG-ALLLOWED-IPs])} {
    reject
     log local0. "Matched $xff in datagroup"

      }
    }
  }
}

} }

 

2 Replies

  • I am using 2 datagroups - CLASS_RESTRICTED_URI is string datagroup with the 2 URI. CLASS_RFC1918 has the private address space (RFC1918).

    Untested example that may answer your requirements:

    when HTTP_REQUEST {
     if { [class match [HTTP::uri] eq "CLASS_RESTRICTED_URI"] } {
      if { ( not ([class match [IP::client_addr] eq "CLASS_RFC1918"])) } {
        drop
      } elseif { ([HTTP::header exists "X-Forwarded-For"]) and ([HTTP::header values X-Forwarded-For] ne "") and ([class match [HTTP::header "X-Forwarded-For"] eq "CLASS_RFC1918"]) } {
        pool POOL_WEB_SERVERS
      } else {
        drop
      }
    }
    }
    
  • when HTTP_REQUEST {
     if { [class match [HTTP::uri] eq "CLASS_RESTRICTED_URI"] } {
        if { ([HTTP::header exists "X-Forwarded-For"]) and ([HTTP::header values X-Forwarded-For] ne "") and ([class match [getfield [HTTP::header values X-Forwarded-For] " " 1] eq "CLASS_RFC1918"]) } {
        log local0."[HTTP::header X-Forwarded-For]"
        pool POOL_WEB_SERVERS
      } else {
        drop
      }
    }
    }
    

    Another possible option:

    when HTTP_REQUEST {
     if { [class match [HTTP::uri] eq "CLASS_RESTRICTED_URI"] } {
        if { ([HTTP::header exists "X-Forwarded-For"]) and ([HTTP::header values X-Forwarded-For] ne "") and ([class match [lindex [split [HTTP::header values X-Forwarded-For] " "] 0] eq "CLASS_RFC1918"]) } {
        log local0."[HTTP::header X-Forwarded-For]"
        pool POOL_WEB_SERVERS
      } else {
        drop
      }
    }
    }