Forum Discussion
Load balance to specific pool by reading the X-Forwarded-For IP address
I've been asked if we can send specific client to a different pool based on the X-Forwarded-For IP address. I suspect this must be done via an IRule. Any help would be appreciated.
Thanks
19 Replies
- Ryannnnnnnnn
Altocumulus
Hi mate,
maybe something like the following
when HTTP_REQUEST { if {[HTTP::header values "X-Forwarded-For"] contains "1.2.3.4"}{ pool some_pool } } - nitass_89166
Noctilucent
you can retrieve x-forwarded-for header value by using HTTP::header command and then you can do whatever you want e.g. send to specific node (node command) or pool (pool command), etc.
HTTP::header
">https://devcentral.f5.com/wiki/iRules.HTTP__header.ashx" target="_blank">">https://devcentral.f5.com/wiki/iRules.HTTP__header.ashx- Lou_125071
Nimbostratus
Thanks this worked by just ORing the other IP addresses. I was going to try and do it with a data group list which was why I was having trouble getting it to work. I'll probably also add the real client IP in case the IP comes in not in the X-Forwarded-For. Thanks again for the help - shaggy
Nimbostratus
this should be doable as a data-group - do you foresee the list of IP addresses changing often over time? - Lou_125071
Nimbostratus
Shaggy, This is what we have so far and all works except if you do not have an X-Forwarded-For address and you are not in the Data group list you do not fall into the default pool. If you are in the list it works for both real client and X-Forwarded-For. Can you see anything here that would make it react this way? when HTTP_REQUEST { if {( [ class match [IP::client_addr] equals MY-List] )} { pool MY-pool } elseif {( [class match [_HTTP::header "X-Forwarded-For"] equals MY-List] )}{ pool TEST-pool } }
- nitass
Employee
you can retrieve x-forwarded-for header value by using HTTP::header command and then you can do whatever you want e.g. send to specific node (node command) or pool (pool command), etc.
HTTP::header
">https://devcentral.f5.com/wiki/iRules.HTTP__header.ashx" target="_blank">">https://devcentral.f5.com/wiki/iRules.HTTP__header.ashx- Lou_125071
Nimbostratus
Thanks this worked by just ORing the other IP addresses. I was going to try and do it with a data group list which was why I was having trouble getting it to work. I'll probably also add the real client IP in case the IP comes in not in the X-Forwarded-For. Thanks again for the help - shaggy
Nimbostratus
this should be doable as a data-group - do you foresee the list of IP addresses changing often over time? - Lou_125071
Nimbostratus
Shaggy, This is what we have so far and all works except if you do not have an X-Forwarded-For address and you are not in the Data group list you do not fall into the default pool. If you are in the list it works for both real client and X-Forwarded-For. Can you see anything here that would make it react this way? when HTTP_REQUEST { if {( [ class match [IP::client_addr] equals MY-List] )} { pool MY-pool } elseif {( [class match [_HTTP::header "X-Forwarded-For"] equals MY-List] )}{ pool TEST-pool } }
- nitass
Employee
This is what we have so far and all works except if you do not have an X-Forwarded-For address and you are not in the Data group list you do not fall into the default pool.
have you checked /var/log/ltm? if i am correct, you would see something like this in the log. it is because HTTP::header returns null.
Dec 12 23:05:43 ve11a err tmm[14890]: 01220001:3: TCL error: /Common/qux - bad IP network address format (line 1)invalid IP match item for IP class /Common/MY-List (line 1) invoked from within "class match -- [HTTP::header "X-Forwarded-For"] equals MY-List"to prevent it, you may try catch command.
e.g.
configuration [root@ve11a:Active:In Sync] config tmsh list ltm virtual norf ltm virtual norf { destination 172.28.24.10:80 ip-protocol tcp mask 255.255.255.255 pool foo profiles { http { } tcp { } } rules { qux } source 0.0.0.0/0 source-address-translation { type automap } vs-index 7 } [root@ve11a:Active:In Sync] config tmsh list ltm data-group internal MY-List ltm data-group internal MY-List { records { 1.1.1.1/32 { } } type ip } [root@ve11a:Active:In Sync] config tmsh list ltm rule qux ltm rule qux { when HTTP_REQUEST { set xff [HTTP::header "X-Forwarded-For"] if { [class match [IP::client_addr] equals MY-List] } { pool MY-pool } elseif { not [catch {class match [HTTP::header "X-Forwarded-For"] equals MY-List}] } { pool TEST-pool } } when HTTP_RESPONSE { log local0. "ip=[IP::client_addr] xff=$xff pool=[LB::server pool]" } } /var/log/ltm Dec 12 23:06:55 ve11a info tmm1[14890]: Rule /Common/qux : ip=192.168.207.97 xff= pool=/Common/foo- Dan_Pacheco
Cirrus
Hi Nitass, I tried to replicate your logic with the "catch" command but if I send traffic without an x-forward-for header my browser gets a TCP Reset and the following error message logged:
Feb 3 22:02:48 DCO-F5VE-LAB-1 err tmm[19467]: 01220001:3: TCL error: /Common/business-bell-ca-obe_irule - Could not find class remote-virtual-servers_dg (line 5) invoked from within "class match $xff equals remote-virtual-servers_dgHere is the irule, does anything jump out at you?
when HTTP_REQUEST { put x-forward-for value into memory as a variable called xff set xff [HTTP::header "X-Forwarded-For"] Check if the x-forward IP address is in data-group named remote-virtual-servers_dg if { [class match $xff equals remote-virtual-servers_dg ] } { pool obe-bus-bell-ca_webtier-local_443_pool if there is no xff value in the header, the catch command will ensure we don't get a runtime error that produces a TCP Reset } elseif { not [catch {class match [HTTP::header "X-Forwarded-For"] equals remote-virtual-servers_dg}] } { pool http_pool_default } }
- nitass_89166
Noctilucent
This is what we have so far and all works except if you do not have an X-Forwarded-For address and you are not in the Data group list you do not fall into the default pool.
have you checked /var/log/ltm? if i am correct, you would see something like this in the log. it is because HTTP::header returns null.
Dec 12 23:05:43 ve11a err tmm[14890]: 01220001:3: TCL error: /Common/qux - bad IP network address format (line 1)invalid IP match item for IP class /Common/MY-List (line 1) invoked from within "class match -- [HTTP::header "X-Forwarded-For"] equals MY-List"to prevent it, you may try catch command.
e.g.
configuration [root@ve11a:Active:In Sync] config tmsh list ltm virtual norf ltm virtual norf { destination 172.28.24.10:80 ip-protocol tcp mask 255.255.255.255 pool foo profiles { http { } tcp { } } rules { qux } source 0.0.0.0/0 source-address-translation { type automap } vs-index 7 } [root@ve11a:Active:In Sync] config tmsh list ltm data-group internal MY-List ltm data-group internal MY-List { records { 1.1.1.1/32 { } } type ip } [root@ve11a:Active:In Sync] config tmsh list ltm rule qux ltm rule qux { when HTTP_REQUEST { set xff [HTTP::header "X-Forwarded-For"] if { [class match [IP::client_addr] equals MY-List] } { pool MY-pool } elseif { not [catch {class match [HTTP::header "X-Forwarded-For"] equals MY-List}] } { pool TEST-pool } } when HTTP_RESPONSE { log local0. "ip=[IP::client_addr] xff=$xff pool=[LB::server pool]" } } /var/log/ltm Dec 12 23:06:55 ve11a info tmm1[14890]: Rule /Common/qux : ip=192.168.207.97 xff= pool=/Common/foo- Dan_Pacheco
Cirrus
Hi Nitass, I tried to replicate your logic with the "catch" command but if I send traffic without an x-forward-for header my browser gets a TCP Reset and the following error message logged:
Feb 3 22:02:48 DCO-F5VE-LAB-1 err tmm[19467]: 01220001:3: TCL error: /Common/business-bell-ca-obe_irule - Could not find class remote-virtual-servers_dg (line 5) invoked from within "class match $xff equals remote-virtual-servers_dgHere is the irule, does anything jump out at you?
when HTTP_REQUEST { put x-forward-for value into memory as a variable called xff set xff [HTTP::header "X-Forwarded-For"] Check if the x-forward IP address is in data-group named remote-virtual-servers_dg if { [class match $xff equals remote-virtual-servers_dg ] } { pool obe-bus-bell-ca_webtier-local_443_pool if there is no xff value in the header, the catch command will ensure we don't get a runtime error that produces a TCP Reset } elseif { not [catch {class match [HTTP::header "X-Forwarded-For"] equals remote-virtual-servers_dg}] } { pool http_pool_default } }
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)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