Forum Discussion

sjy2025's avatar
sjy2025
Icon for Nimbostratus rankNimbostratus
Jul 22, 2025
Solved

iRule, Traffic Policy or Re-Write Policy

 

Hi,

I have created an iRule that maps source addresses to a particular pool

when CLIENT_ACCEPTED {
if {[class match [IP::client_addr] equals clients1] } {
     pool POOL_1
   } elseif {[class match [IP::client_addr] equals clients2] } {
     pool POOL_2
   } elseif {[class match [IP::client_addr] equals clients3] } {
     pool POOL_3
   } elseif {[class match [IP::client_addr] equals clients4] } {
     pool POOL_4
   } elseif {[class match [IP::client_addr] equals clients5] } {
     pool POOL_5
   }
   else {
      pool POOL_6
     }
}

I have a re-write policy that changes the uri

https://example.com to https://examples.com/test

 

When the connection completes to the backend servers, they respond with their hostname in the browser.

 

I want to keep https://example.com on the client side but I'm not sure how to achieve this. I thought I could do a response within my re-write policy but this fails.

I then looked at traffic policies but already have an ASM policy attached

 

Should I try and achieve everything under one irule (if so how, might I do this)

  1. It replaces the original uri with a new uri (going to the server)
  2. Have my current source to pool mapping
  3. Replace the server hostname with the original uri https://example.com

Thanks for any pointers

  • you may see  https://hostnameA.test.com:666 in the browser for many reasons
    thats why I am asking if there is a redirect response (301 or 302) or there is something else

    anyway give this a try

    when HTTP_REQUEST 
    {
        STREAM::disable
        HTTP::header remove "Accept-Encoding"
    
    	if {[IP::addr [IP::client_addr] equals 192.168.1.1] } 
    	{
    		pool POOL_A
    		set selected_hostname "hostnameA.test.com"
    		HTTP::header replace Host $selected_hostname
    	} 
    	elseif {[IP::addr [IP::client_addr] equals 192.168.2.1] }
    	{
    		pool POOL_B
    		set selected_hostname "hostnameB.test.com"
    		HTTP::header replace Host $selected_hostname
    	} 
    	elseif {[IP::addr [IP::client_addr] equals 192.168.3.1] }
    	{
    		pool POOL_C
    		set selected_hostname "hostnameC.test.com"
    		HTTP::header replace Host $selected_hostname
    	}
    }
    
    when HTTP_RESPONSE 
    {
        if {[HTTP::header exists "Location"] && [info exists selected_hostname]}
        {
            set loc [HTTP::header "Location"]
            if {[string match "https://$selected_hostname:666*" $loc]} 
            {
                HTTP::header replace "Location" [string map "https://$selected_hostname:666 https://example.com" $loc]
            }
        }
        if {[HTTP::header "Content-Type"] contains "text" && [info exists selected_hostname]}
        {
    		STREAM::expression "@https://$selected_hostname@https://example.com@"
    		STREAM::enable
        }
    }

     

11 Replies

  • Hi sjy2025​ 

    the best solution would be to config application use relative paths

    for now you can try this irule, you will need to apply stream profile also

    when CLIENT_ACCEPTED 
    {
        STREAM::disable
        if {[class match [IP::client_addr] equals clients1] } 
        {
            pool POOL_1
        } 
        elseif {[class match [IP::client_addr] equals clients2] } 
        {
            pool POOL_2
        } elseif {[class match [IP::client_addr] equals clients3] }
        {
            pool POOL_3
        } elseif {[class match [IP::client_addr] equals clients4] } 
        {
            pool POOL_4
        } elseif {[class match [IP::client_addr] equals clients5] } 
        {
            pool POOL_5
        }
        else {
            pool POOL_6
        }
    }
    
    
    when HTTP_REQUEST 
    {
        STREAM::disable
        HTTP::header remove "Accept-Encoding"
        set original_uri [HTTP::uri]
        HTTP::uri "/test${original_uri}"
    }
    
    when HTTP_RESPONSE 
    {
        STREAM::disable
        if {[HTTP::header exists "Location"]} 
        {
            set loc [HTTP::header "Location"]
            if {[string match "https://examples.com*" $loc]} 
            {
                HTTP::header replace "Location" [string map {"https://examples.com" "https://example.com"} $loc]
            }
        }
        if {[HTTP::header "Content-Type"] contains "text"} 
        {
            STREAM::expression {@https://examples.com@https://example.com@}
            STREAM::enable
        }
    }

     

  • Thank you for the irule. I've only just been able to get back to this project due to other work. 

     

    when HTTP_REQUEST

    {

        STREAM::disable

        HTTP::header remove "Accept-Encoding" 

        set original_uri [HTTP::uri]

        HTTP::uri "/test${original_uri}"

    }

     

    Apologises for my understanding of this but my iRules knowledge is basic

     

    So when there is an HTTP request 

    set original_uri [HTTP::uri]   >>  set the original_uri means keep the original uri and store it as a variable? This would be  https://example.com

    HTTP::uri "/test${original_uri}" } >> this is the replacement, so the $ gets the variable and appends the test to it https://example.com/test

     

    Is it possible to make the following happen?

    https://example.com to https://different.name.com:666

     

    {

        STREAM::disable

        HTTP::header remove "Accept-Encoding" 

        set original_uri [HTTP::uri]

        HTTP::uri "https://different.name.com:666"

    }

     

    Within the response, do I just substitute in as follows

    when HTTP_RESPONSE

    {

    if {[string match "https://different.name.com:666*" $loc]}

    HTTP::header replace "Location" [string map {"https://different.name.com:666" "https://example.com"} $loc]

     

    Would the stream profile be like this?

     

      Thanks

    • Injeyan_Kostas's avatar
      Injeyan_Kostas
      Icon for Nacreous rankNacreous

      Hi sjy2025​ 

      So when there is an HTTP request 

      set original_uri [HTTP::uri]   >>  set the original_uri means keep the original uri and store it as a variable? This would be  https://example.com

      HTTP::uri "/test${original_uri}" } >> this is the replacement, so the $ gets the variable and appends the test to it https://example.com/test

      that's correct

       

      Is it possible to make the following happen?

      https://example.com to https://different.name.com:666

      in this case, different.name.com is the host not the uri 

      if understand correct you want client request https://example.com but you send to the server https://different.name.com:666

      Fisrtly you have to define the port in pool itslelf, so just create a pool with the ip of the server and port 666. Suppose you name the pool 666_pool

      then you can use below irule as an example

      when HTTP_REQUEST
      {
      	if { ([string tolower [HTTP::host]] equals "example.com") }
      	{
      		HTTP::header replace Host "different.name.com"
      		pool 666_pool
      	}
      }

       

  • Thats correct, a single uri to servers on different subnets

     I have a number of pools, each has a specfic node in it, listening on a port - 666

    Each pool has a remote test client that connects to the pool

     

    I'd like all test clients to hit the same uri of https://example.com then be redirected to a specific server (based on their source IP)

    client 1 uses 192.168.1.1

        goes to pool A and https://example.com redirects to hostnameA.test.com:666

    client 2 uses 192.16821

       goes to pool B and https://example.com redirects to hostnameB.test.com:666

    client 3 uses 192.16821

       goes to pool C and https://example.com redirects to hostnameC.test.com:666

     

    I want the node name to remain hidden from client, currently I see the server name in the response, I just want the client to only ever see https://example.com if possible

    Thanks again

    • Injeyan_Kostas's avatar
      Injeyan_Kostas
      Icon for Nacreous rankNacreous

      it's not clear to me yet

      Is the pool B server (for example) responds with a redirect or you mean that you need a host header rewrite because server listens only to hostnameB.test.com?

  • There is a redirect

    The solution is partially working on a single test network.

    Client connects to uri > f5 has a re-write profile > that changes the uri to be the name of the back end server (Keycloak)

    https://hostnameA.test.com:666 

    In the browser of the client I get the https://hostnameA.test.com:666 which exposes the server name

    I'd like the client to not see this.

     

    I have this on multiple test environments, each with their own dedicated server 

     

     

     

    ....

    • Injeyan_Kostas's avatar
      Injeyan_Kostas
      Icon for Nacreous rankNacreous

      you may see  https://hostnameA.test.com:666 in the browser for many reasons
      thats why I am asking if there is a redirect response (301 or 302) or there is something else

      anyway give this a try

      when HTTP_REQUEST 
      {
          STREAM::disable
          HTTP::header remove "Accept-Encoding"
      
      	if {[IP::addr [IP::client_addr] equals 192.168.1.1] } 
      	{
      		pool POOL_A
      		set selected_hostname "hostnameA.test.com"
      		HTTP::header replace Host $selected_hostname
      	} 
      	elseif {[IP::addr [IP::client_addr] equals 192.168.2.1] }
      	{
      		pool POOL_B
      		set selected_hostname "hostnameB.test.com"
      		HTTP::header replace Host $selected_hostname
      	} 
      	elseif {[IP::addr [IP::client_addr] equals 192.168.3.1] }
      	{
      		pool POOL_C
      		set selected_hostname "hostnameC.test.com"
      		HTTP::header replace Host $selected_hostname
      	}
      }
      
      when HTTP_RESPONSE 
      {
          if {[HTTP::header exists "Location"] && [info exists selected_hostname]}
          {
              set loc [HTTP::header "Location"]
              if {[string match "https://$selected_hostname:666*" $loc]} 
              {
                  HTTP::header replace "Location" [string map "https://$selected_hostname:666 https://example.com" $loc]
              }
          }
          if {[HTTP::header "Content-Type"] contains "text" && [info exists selected_hostname]}
          {
      		STREAM::expression "@https://$selected_hostname@https://example.com@"
      		STREAM::enable
          }
      }

       

      • sjy2025's avatar
        sjy2025
        Icon for Nimbostratus rankNimbostratus

        This has solved my issue, specifically the HTTP_REQUEST section. The response has been dealt with by another means. Thanks for your help

  • I will try this out tomorrow, thank you for your input, its very much appreciated

    • sjy2025's avatar
      sjy2025
      Icon for Nimbostratus rankNimbostratus

      Hi,

      Thought I would feedback, as I couldn't get the response to work.

      I have got the source > pool > to re-write working which is great, although it does still show the backend server, its a test environment and is reducing my admin, so thank you

      I found your iRule really useful for understanding as well

       

      I think the response isn't working as there is a unusual setup, which does the following

       

      client to uri = https://example.com

      F5 rewrites to https://hostnameA.test.com:666

      Then there is another redirects that sends to the

      F5 rewrites to https://other.test.com:443 (this is returned in the browser)

      I'm still looking at it

      Thanks

       

       

       

       

      • Injeyan_Kostas's avatar
        Injeyan_Kostas
        Icon for Nacreous rankNacreous

        You mention Keycloak,
        Do you use as IDP?

        You have to check what urls are defined in the config. Either it uses SAML or OAuth