Forum Discussion

Lou_125071's avatar
Lou_125071
Icon for Nimbostratus rankNimbostratus
Dec 09, 2014

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

  • 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
        } 
    }
    
    • Lou_125071's avatar
      Lou_125071
      Icon for Nimbostratus rankNimbostratus
      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's avatar
      shaggy
      Icon for Nimbostratus rankNimbostratus
      this should be doable as a data-group - do you foresee the list of IP addresses changing often over time?
    • Lou_125071's avatar
      Lou_125071
      Icon for Nimbostratus rankNimbostratus
      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 } }
    • Lou_125071's avatar
      Lou_125071
      Icon for Nimbostratus rankNimbostratus
      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's avatar
      shaggy
      Icon for Nimbostratus rankNimbostratus
      this should be doable as a data-group - do you foresee the list of IP addresses changing often over time?
    • Lou_125071's avatar
      Lou_125071
      Icon for Nimbostratus rankNimbostratus
      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 } }
  • 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's avatar
      Dan_Pacheco
      Icon for Cirrus rankCirrus

      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_dg

      Here 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
        } 
      }
      
  • 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's avatar
      Dan_Pacheco
      Icon for Cirrus rankCirrus

      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_dg

      Here 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
        } 
      }