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.

Rewrite Host Header to Server Name

Problem this snippet solves:

On each HTTP request, the selected pool member IP address is looked up against a datagroup and the corresponding hostname is inserted in the HTTP host header.

The iRule expects one string type datagroup to be defined: ip_to_host_dg

If you're using a version lower than 10.0, see the second example. For versions lower than 9.4.4, change the class reference in the second iRule from ip_to_host_dg to $::ip_to_host_dg.

Code :

# Name : host_header_rewrite_rule
#
# HTTP host header rewrite rule
#
# BIG-IP LTM
#   Tested on version 11.1.0 (but should work on 10.x or 11.x)
#
# Version: 1.1 - Initial version tested
#
# Description:
#
# On each HTTP request, the selected pool member IP address is looked up against a datagroup and the corresponding hostname
#   is replaced in the HTTP host header.
#
# Configuration requirements:
#
# 1. This iRule expects a string datagroup named ip_to_host_dg to be defined with the following format:
#
#ltm data-group internal ip_to_host_dg {
#    records {
#        1.1.1.1 {
#            data host1.example.com
#        }
#        1.1.1.2 {
#            data host2.example.com
#        }
#        1.1.1.5 {
#            data host3.example.com
#        }
#    }
#    type string
#}
#
# 2. Each pool member must be configured and any time the pool membership changes, this data group must be updated.
#
when HTTP_REQUEST_SEND {

   # Log debug messages to /var/log/ltm? 1=yes, 0=no.
   set host_debug 1

   # Need to force the host header replacement and HTTP:: commands into the clientside context
   #  as the HTTP_REQUEST_SEND event is in the serverside context
   clientside {

      if {$host_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: [HTTP::method] request to [HTTP::host][HTTP::uri]"}

      # Look up the selected server IP in the datagroup to get the host header value
      set host_header_value [class match -value [IP::server_addr] equals ip_to_host_dg]

      if {$host_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Looked up [IP::server_addr], found: $host_header_value."}

      # Check if the lookup returned a value
      if {$host_header_value ne ""}{
   
         # Replace the host header value
         HTTP::header replace Host $host_header_value
         if {$host_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Replaced Host header with $host_header_value."}
      }
   }
}

# v9.x

# Name : host_header_rewrite_rule (v9.x)
#
# HTTP host header rewrite rule
#
# BIG-IP LTM
#   Tested on version 9.4.8
#
# Version: 1.0 - Initial version tested
#
# Description:
#
# On each HTTP request, the selected pool member IP address is looked up against a datagroup and the corresponding hostname
#   is replaced in the HTTP host header.
#
# Configuration requirements:
#
# 1. This iRule expects a string datagroup named ip_to_host_dg to be defined with the following format:
#
#   pool member IP |  host header to insert
#   ---------------|-------------------
#   1.1.1.1        |  host1.example.com
#   1.1.1.2        |  host2.example.com
#   1.1.1.5        |  host3.example.com
#
# 2. Each pool member must be configured and any time the pool membership changes, this datagroup must be updated.
#
when HTTP_REQUEST_SEND {

   # Log debug messages to /var/log/ltm? 1=yes, 0=no.
   set host_debug 1

   # Need to force the host header replacement and HTTP:: commands into the clientside context
   #  as the HTTP_REQUEST_SEND event is in the serverside context
   clientside {

      if {$host_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: New [HTTP::method] request to [HTTP::host][HTTP::uri]"}

      # Look up the selected server IP in the datagroup to get the host header value
      set host_header_value [findclass [LB::server addr] ip_to_host_dg " "]

      if {$host_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Looked up [LB::server addr], found: $host_header_value."}

      # Check if the lookup returned a value
      if {$host_header_value ne ""}{
   
         # Replace the host header value
         HTTP::header replace Host $host_header_value
         if {$host_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Replaced Host header with $host_header_value."}
      }
   }
}
Published Mar 18, 2015
Version 1.0

3 Comments

  • Hey, I used the code above and it worked perfectly when I wanted to replace the hostheader from www.abc.com to "site1" for pool member 1 and "site2" for pool member 2. However the webpage has been hosted on site1/reports and site2/reports. When I enter in my browser http://www.abc.com/reports my url address change to http://site1/reports(it get redirected). How can I fix this? in other words when I enter http://www.abc.com/reports below happens. For Node member 1: Hostheader=site1 uri=site1/reports For Node member 2: Hostheader=site1 uri=site2/reports However we need to have this uri change being transparent from the user perspective. Thanks, Peyman
  • Hi paymon, maybe a bit late (2018 *cough*) but here are some ideas.

     

    1. You could configure your AppServer that its sending relative redirects and no absolute ones.
    2. Configure your AppServer to accept "X-Forwarded-Host"-Headers
    3. Create an iRule with a "HTTP_RESONSE"-Event wich is scanning for redirects and modify the Location-Header

    Have a nice day.