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.

Forum Discussion

Kaloyan's avatar
Kaloyan
Icon for Cirrus rankCirrus
Oct 19, 2017

iRule pointing traffic from one pool member to another with HTTP::retry

Hi, I have the following traffic path: Client request -> External VIP ->pool with member with IP:port of internal VIP -> Internal VIP -> Pool with one member, which respond always with 307 redirect to an application server.

 

The idea is to break the 307 response on the LB Internal VIP and make HTTP::retry with the original request to the redirected Location.I was able to accomplish this by the iRule below.The customer responds that the iRule is working fine when a browser is used. With this type of connections, I am using cookies.When they use application for the requests (which are only POST requests), they see only a half of them on the backend server. The request-app don't support cookies, so I made X-Forwarded-For persistence, and I see the records in the persistence table for the right source IPs.All profiles are a default. Only X-Forwarded-For insertion on the external VIP.

 

Error on the backend server:iRule to follow...

 

3 Replies

  • Here is the iRule:
    
        when CLIENT_ACCEPTED {
                set server 0
                set retried 0
                set default_pool [LB::server pool]
        }
        when HTTP_REQUEST {
            set clientip ""
            if { [HTTP::header exists "X-Forwarded-For"] } {
                set clientip [lindex [ split [lindex [HTTP::header values X-Forwarded-For] 0] "," ] 0]
            } else {
                set clientip [IP::client_addr]
            }
            log local0. "persist lookup on REQUEST: $clientip"      
              if { [HTTP::cookie exists test1] } {
                        pool test_1
                        persist cookie insert test1 0
                        log local0. "FROM_ifcheck_cookie_exist_HDLtest1 HTTP request: [HTTP::request]"
                }
                elseif { [HTTP::cookie exists test2] } {
                        pool test_2
                        persist cookie insert test2 0
                        log local0. "FROM_ifcheck_cookie_exist_HDLtest2 HTTP request: [HTTP::request]"
                }
                elseif { ($retried == 0) } {
                        set request_headers [HTTP::request]
                         Set payload content legth to capture. 
                        if {[HTTP::header exists "Content-Length"] && [HTTP::header "Content-Length"] <= 4000000}{ 
                            set content_length [HTTP::header "Content-Length"] 
                        } 
                        else { 
                            set content_length 4000000 
                        } 
                            Capture HTTP payload from request, HTTP::collect triggers event HTTP_REQUEST_DATA 
                        if { [info exists content_length] && $content_length > 0} { 
                            HTTP::collect $content_length 
                        }
                        pool $default_pool
                        persist none
                }
                elseif { ($retried == 1) } {
                Check DGL external-ip-check for IP/X-Forwarded-For match and assign uie persistence
                if {[class match $clientip equals "external-ip-check"]} {
                        switch -glob $server {
                                "1" {
                                     pool test_1
                                     persist uie $clientip 1800
                                     log local0. "FROM_retried_check_SP_test1 HTTP request: [HTTP::request]"
                                }
                                "2" {
                                     pool test_2
                                     persist uie $clientip 1800
                                     log local0. "FROM_retried_check_SP_test2 HTTP request: [HTTP::request]"
                                    }
                                default {
                                        log local0. "Configuration needed for HTTP_REQUEST. HTTP request: [HTTP::request]"
                                }
                        }
                } else {
                        switch -glob $server {
                                "1" {
                                     pool test_1
                                     persist cookie insert test1 0
                                     log local0. "FROM_retried_check_with_cookie_test1 HTTP request: [HTTP::request]"
                                }
                                "2" {
                                     pool test_2
                                     persist cookie insert test2 0
                                     log local0. "FROM_retried_check_with_cookie_test2 HTTP request: [HTTP::request]"
                                    }
                                default {
                                        log local0. "Configuration needed for HTTP_REQUEST. HTTP request: [HTTP::request]"
                                }
                        }
                }
        }
        }
        when HTTP_REQUEST_DATA { 
                                 Set payload, depends on HTTP::collect done in HTTP_REQUEST event. 
                                set payload [HTTP::payload] 
    
                                 Append HTTP payload to HTTP request header to form a complete HTTP post request (request + payload) 
                                append request_headers [HTTP::payload [HTTP::payload length]] 
        } 
        when HTTP_RESPONSE {
                if { ([HTTP::status] == 307) } {
                        log local0. "HTTP_RESPONSE from Dispatcher: [HTTP::header Location] for HTTP request: $request_headers"
                        set retried 1
                                    switch -glob [string tolower [HTTP::header Location]] {
                                    "*:first/*" 
                                    {
                                        set server 1
                                        HTTP::retry "$request_headers"
                                    }
                                    "*:second/*"
                                    {
                                        set server 2
                                        HTTP::retry "$request_headers"
                                    }
                                    default {
                                        set server 0
                                        log local0. "Configuration needed for HTTP_RESPONSE. New location from Dispatcher: [HTTP::header Location] for HTTP request: $request_headers"
                                }
        }
                }
                else {
                        log local0. "HTTP_RESPONSE from APP-server: [HTTP::response]"
                }
        }
    
  • In general I think you should add a persistency record in the HTTP_RESPONSE event via the:

    persist add uie  
    command

    In the HTTP_REQUEST you can persist to the server by using the:

    persist uie  
    command

  • Thanks, jurgenvdmark. I was aware of this possibility for "persist add uie" in the HTTP_RESPONSE. Will add it as well... Right now, I am trying to completely modify the iRule, using sideband collection options, as HTTP::retry seems to have problems with these POST requests...