Forum Discussion
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)
- It replaces the original uri with a new uri (going to the server)
- Have my current source to pool mapping
- 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 trywhen 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
- Injeyan_Kostas
Nacreous
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 } }
- sjy2025
Nimbostratus
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
Nacreous
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?
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 } }
- sjy2025
Nimbostratus
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
Nacreous
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?
- sjy2025
Nimbostratus
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
Nacreous
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 trywhen 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
Nimbostratus
This has solved my issue, specifically the HTTP_REQUEST section. The response has been dealt with by another means. Thanks for your help
- sjy2025
Nimbostratus
I will try this out tomorrow, thank you for your input, its very much appreciated
- sjy2025
Nimbostratus
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
Nacreous
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
Recent Discussions
Related Content
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com