Forwarded HTTP Extension Insertion (RFC 7239)
Problem this snippet solves:
Until June 2014, there was no standard HTTP headers to share with web server behind reverse proxy client side request properties like:
- Client IP Address
- requested Host header
- requested protocol (HTTP / HTTPS)
- Reverse Proxy egress IP address
These informations were injected in following non standard headers
- Client IP Address : X-Forwarded-For
- requested Host header : X-Forwarded-Host
- requested protocol (HTTP / HTTPS) : X-Forwarded-Proto
- Reverse Proxy egress IP address : Via
The RFC 7239 (Forwarded HTTP Extension) provide a single header which contains all these informations : Forwarded
Here is an examples of Forwarded header :
Forwarded: for="_gazonk" Forwarded: For="[2001:db8:cafe::17]:4711" Forwarded: for=192.0.2.60;proto=http;by=203.0.113.43 Forwarded: for=192.0.2.43, for=198.51.100.17
This code insert the Forwarded header with expected values to HTTP request
- insert for parameter with Client IP address (IPv6 format support with bracket)
- include in For parameter the client request value of For parameter
- include in For parameter the client request value of X-Forwarded-For header
- insert by parameter with IP address (IPv6 format support with bracket)
- insert proto parameter depending on clientssl profile enabled on VS
- insert host parameter with HTTP client request Host header
version 1.1 : add route domain id support (remove route domain ID from IP addresses before insert it)
How to use this snippet:
Enable this irule on virtual server an set following variables to 0 or 1 to disable / enable parameter in header:
# Insert "For" parameter set INSERT_FORWARDED_FOR 1 # Include in "For" parameter values from request Forwarded header set KEEP_FORWARDED_FOR 1 # Include in "For" parameter values from request X-Forwarded-For header set CONVERT_XFF_TO_FORWARDED_FOR 1 # Insert "By" parameter set INSERT_FORWARDED_BY 0 # Insert "Proto" parameter set INSERT_FORWARDED_PROTO 1 # Insert "Host" parameter set INSERT_FORWARDED_HOST 0
Code :
when CLIENT_ACCEPTED {
############### Configure Which info insert in Forwarded header ###############
# Insert "For" parameter
set INSERT_FORWARDED_FOR 1
# Include in "For" parameter values from request Forwarded header
set KEEP_FORWARDED_FOR 1
# Include in "For" parameter values from request X-Forwarded-For header
set CONVERT_XFF_TO_FORWARDED_FOR 1
# Insert "By" parameter
set INSERT_FORWARDED_BY 0
# Insert "Proto" parameter
set INSERT_FORWARDED_PROTO 0
# Insert "Host" parameter
set INSERT_FORWARDED_HOST 1
############### Get HTTP / HTTPS info based on the clientssl profile assigned to the VS ###############
if { [PROFILE::exists clientssl] == 1} {
set REQUEST_PROTO "https"
} else {
set REQUEST_PROTO "http"
}
############### prepare IPV6 encoding ###############
if {[set CLIENT_ADDR [getfield [IP::remote_addr] "%" 1]] contains ":"} {set CLIENT_ADDR "\[$CLIENT_ADDR\]"}
}
when HTTP_REQUEST {
set FFOR_HEADER ""
set FPROTO_HEADER ""
set FHOST_HEADER ""
############### Insert "for" parameter ###############
if {$INSERT_FORWARDED_FOR} {
set FFOR_HEADER_LIST [list]
lappend FFOR_HEADER_LIST "for=$CLIENT_ADDR"
if {$KEEP_FORWARDED_FOR} {
foreach item [split [HTTP::header "Forwarded"] ";"] {
if {[string tolower [string trimleft $item]] starts_with "for"} {
lappend FFOR_HEADER_LIST "$item"
break
}
}
}
if {$CONVERT_XFF_TO_FORWARDED_FOR && [HTTP::header exists "X-Forwarded-For"]} {
if {[HTTP::header value "X-Forwarded-For"] contains ","} {
foreach item [split [HTTP::header value "X-Forwarded-For"] ","] {
if {$item contains ":" && !($item contains "\[")} {
lappend FFOR_HEADER_LIST "for=\[[string trim $item]\]"
} else {
lappend FFOR_HEADER_LIST "for=[string trim $item]"
}
}
} else {
lappend FFOR_HEADER_LIST "for=[HTTP::header value "X-Forwarded-For"]"
}
HTTP::header remove "X-Forwarded-For"
}
set FFOR_HEADER [join $FFOR_HEADER_LIST ","]
}
############### Insert "proto" parameter ###############
if {$INSERT_FORWARDED_PROTO} {
set FPROTO_HEADER "proto=$REQUEST_PROTO"
}
############### Insert "host" parameter ###############
if {$INSERT_FORWARDED_HOST} {
set FHOST_HEADER "host=[HTTP::host]"
}
############### Insert HTTP header only if "by" parameter won't be included ###############
############### Else the whole header will be inserted in HTTP_REQUEST_RELEASE Event ###############
if {!$INSERT_FORWARDED_BY} {
HTTP::header remove "Forwarded"
HTTP::header insert "Forwarded" [join "$FFOR_HEADER $FPROTO_HEADER $FHOST_HEADER" ";"]
}
}
when HTTP_REQUEST_RELEASE {
############### Insert "by" parameter ###############
if {$INSERT_FORWARDED_BY} {
if {[set BY_ADDR [getfield [IP::local_addr] "%" 1]] contains ":"} {set CLIENT_ADDR "\[$BY_ADDR\]"}
set FBY_HEADER "by=$BY_ADDR"
HTTP::header remove "Forwarded"
HTTP::header insert "Forwarded" [join "$FFOR_HEADER $FPROTO_HEADER $FHOST_HEADER $FBY_HEADER" ";"]
}
}Tested this on version:
13.0Updated 2 years ago
Version 2.0stan_piron
Cumulonimbus
6 Comments
No CommentsBe the first to comment