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

Chathuranga50_2's avatar
Chathuranga50_2
Icon for Nimbostratus rankNimbostratus
Feb 09, 2016

Reroute traffic based on request content

Hi All,

I have trying to implement traffic route based on request content.

Request :

username
Der30T09Ur10-03-2016 12-03-2016
21US
CY1910
0
020

depend on the username I need to route specific user request to separate VIP. Is that possible with F5?

Regards, Chathuranga.

4 Replies

  • Most certainly. But you may have to consider other factors. Is this a single atomic request, or will the user make multiple requests? Will all of the user requests contain the information you're looking for?

    Let's assume for a moment that these are atomic requests, and by "VIP" you actually mean servers, or a pool of servers. You could simply use a string function to parse out the content you're looking for and make a load balancing decision based on that. Something like this:

    when HTTP_REQUEST {
        if { [HTTP::header exists Content-Length] } {
             Collect the payload and trigger the HTTP_REQUEST_DATA event
            HTTP::collect [HTTP::header Content-Length]
        }
    }
    when HTTP_REQUEST_DATA {
         The HTTP request payload is buffered and accessible here
         Now use string functions to get the username from the request payload
        set username [findstr [HTTP::payload] "" 10 ""]
        switch $username {
            "bob" { pool bob_pool }
            "alice" { pool alice_pool }
            "eve" { pool eve_pool }
            "oscar" { pool oscar_pool }
            default { pool default_pool }
        }
    }
    

    Of course this is a wildly simplistic example, and you could a) use XML_CONTENT_BASED_ROUTING to parse the XML payload with real xpath processing, and b) use something more elaborate than a static switch statement to test usernames. In any case, the findstr command is a fast and easy way to selectively extract information from a string, in this case the data between "" and "".

  • This was an example, so you'll likely need to do some tweaking. For starters, add some logging statements to see what is returned from the findstr:

    when HTTP_REQUEST {
        if { [HTTP::header exists Content-Length] } {
             Collect the payload and trigger the HTTP_REQUEST_DATA event
            HTTP::collect [HTTP::header Content-Length]
        }
    }
    when HTTP_REQUEST_DATA {
         The HTTP request payload is buffered and accessible here
         N    ow use string functions to get the username from the request payload
        set username [findstr [HTTP::payload] "" 10 ""]
        log local0. "username = $username"        
        switch $username {
            "bob" { pool bob_pool }
            "alice" { pool alice_pool }
            "eve" { pool eve_pool }
            "oscar" { pool oscar_pool }
            default { pool default_pool }
        }
    }
    

    Now test that and either look at LTM logs in the management GUI, or better, open up an SSH session to the BIG-IP and tail the LTM log:

    tail -f /var/log/ltm
    

    You'll be looking for a log statement like this:

    username = [something]
    

    If the username value is empty, then you know the findstr isn't returning something and you need to modify the search. If it is returning something, then perhaps the switch isn't right. Start there and let us know what you find.

  • Okay, do this: add a new log statement before the other log statement that displays the HTTP payload:

    log local0. [HTTP::payload]
    

    At this point you're either not sending the data that you think you are, or the fields are not as you've described. The above log statement should shed some more light on that.

  • Okay, so it looks like the HTTP (XML) payload is coming through encoded. Let's modify the findstr accordingly:

    set username [findstr [URI::decode [HTTP::payload]] ""]