When using ASM with conjunction with LTM+XFF sometimes based on the traffic path XFF header would have multiple IP address.
X-Forwarded-For: 8.8.8.8 4.4.4.2 10.137.255.232
Real value of XFF header is furthest left IP which is 8.8.8.8, But F5 selects the middle IP 4.4.4.2 because it's most "Trusted" in the context of RFC so we have to make sure that the leftmost one is selected via iRule.
when HTTP_REQUEST {
# Check if the X-Forwarded-For header exists
if { [HTTP::header exists "X-Forwarded-For"] } {
# Get the full XFF string and split it by comma
# The first element [lindex $list 0] is the original client IP
set xff_list [split [HTTP::header "X-Forwarded-For"] ","]
set client_ip [string trim [lindex $xff_list 0]]
# Log the extracted IP for verification
log local0. "Original Client IP extracted: $client_ip"
# Optional: Insert the extracted IP into a new custom header
# for the backend server to consume easily
HTTP::header insert "X-Actual-Client-IP" $client_ip
}
}
X-Forwarded-For: 127.0.0.1 8.8.8.8 4.4.4.2 10.137.255.232
when HTTP_REQUEST {
if { [HTTP::header exists "X-Forwarded-For"] } {
set xff_list [split [HTTP::header "X-Forwarded-For"] ","]
set client_ip ""
foreach ip_item $xff_list {
set tmp_ip [string trim $ip_item]
# Skip if IP is local or private (RFC1918)
if { [IP::addr $tmp_ip equals 127.0.0.1] or
[IP::addr $tmp_ip mask 255.0.0.0 equals 10.0.0.0] or
[IP::addr $tmp_ip mask 255.240.0.0 equals 172.16.0.0] or
[IP::addr $tmp_ip mask 255.255.0.0 equals 192.168.0.0] } {
continue
} else {
# Found the first public IP
set client_ip $tmp_ip
break
}
}
if { $client_ip ne "" } {
# Log the result: in your doc example, this would capture 8.8.8.8
log local0. "Extracted Public Client IP: $client_ip"
HTTP::header insert "X-Actual-Client-IP" $client_ip
}
}
}
No comments:
Post a Comment