For more information regarding the security incident at F5, the actions we are taking to address it, and our ongoing efforts to protect our customers, click here.

Forum Discussion

Jeff_Conrad's avatar
Jeff_Conrad
Icon for Nimbostratus rankNimbostratus
Dec 16, 2025

Checking for X-Forwarded-For against an Address Data-Group

Hello, I've been back and forth over this simple block of code, extracted from our f5 rule.  I'm trying to adjust to Cloudflare X-Forwarded-For header for handling source IP address comparison to an internal list of credible internal IP ranges. While I understand that the "X-Forwarded-For" header is not 100% reliable, having this value set will aid debugging in other respects.

When I call this f5 irule with no headers, it is fine, it appears to use the client_addr normally against our whitelist address Data Groups (very simple list of allowed ranges).  But when I call it with a header of X-Forwarded-For via Postman it does not respond at all to the client (fails hard).  I thought all Tcl  variables are Tcl String, but is there something I need to convert extra for headers?  -value on the header did not help either.

 

when HTTP_REQUEST {


if {[HTTP::header exists "X-Forwarded-For"]}{
 set ip [HTTP::header "X-Forwarded-For"]
} else {
 set ip [IP::client_addr]
}


set externalHost 1
if {[class match $ip equals Internal_Hosts]}{
 set externalHost 0
}


if {($externalHost == 0)}{
HTTP::respond 200 content {
 externalHost=0
}
} elseif {($externalHost == 1)}{
HTTP::respond 200 content {
 externalHost=1
}
} else {
HTTP::respond 200 content {
externalHost=unknown
}

}

3 Replies

  • Thanks for the reminder, I saw though I thought we always were sending X-Forwarded-For as a single string, instead something is also appending itself to the chain so it was a comma-separated string.  If others have this, here is some code that is fault-tolerant for single or comma-array separate (assuming the first ip in the list is the one of interest)

    when HTTP_REQUEST {
    
    if {[HTTP::header exists "X-Forwarded-For"]}{
    	set ip [HTTP::header "X-Forwarded-For"]
    } else {
    	set ip [IP::client_addr]
    }
    
    if {[string first "," $ip] != -1} {
    	set fields [split $ip ","]
    	set ip1 [lindex $fields 0]
    } else {
    	set ip1 $ip
    }
    
    set externalHost 1
    if {[class match $ip1 equals Internal_Hosts]}{
    	set externalHost 0
    }
    
    if {($externalHost == 0)}{
    HTTP::respond 200 content {
    	externalHost=0
    }
    } elseif {($externalHost == 1)}{
    HTTP::respond 200 content {
    	externalHost=1
    }
    } else {
    HTTP::respond 200 content {
    	externalHost=unknown
    }
    }

     

    • Injeyan_Kostas's avatar
      Injeyan_Kostas
      Icon for Nacreous rankNacreous

      Hello Jeff_Conrad​ 

      This is true, XFF can have multiple IPs comma separaded.
      Actually each reverse proxy in the path will potentially add the L3 IP from which it received the traffic to XFF header