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

keiti_4329's avatar
keiti_4329
Icon for Nimbostratus rankNimbostratus
Apr 28, 2014

Does LTM support websocket protocol with cookie persistence?

Hi, guys.

 

I've been trying to configure VS for websocket communications using cookie persistence in v10.2.1 and I've used the following irules:

 

when CLIENT_ACCEPTED { HTTP::enable } when HTTP_REQUEST { if { ([string tolower [HTTP::header value Upgrade]] equals "websocket" ) && ([string tolower [HTTP::header value Connection]] equals "upgrade" ) } { log local0. "HTTP Disable" HTTP::disable } }

 

There are no problems when it's configured for a single member, but causes communication errors when more than one pool members exist. I believe it was unable to persist because http is disabled when using this irules.

 

If my theory is correct, it would be best for me to avoid using this irules whenever possible, so for VS for websocket configuration in v11.4, is this irules still necessary? Is cookie persistence with websocket communications available as default in v11.4?

 

9 Replies

  • Hi!

    We're currently testing Web sockets at my company as well so this is an interesting topic. 🙂

    Why do you use the HTTP::enable part of the rule? Assigning the HTTP profile to the virtual server should accomplish the same thing.

    The load balancer should not change server in mid connection and the clients are using normal HTTP before the upgrade (right?), so the cookie persistence should work. Have you tried logging the client cookies to verify that the subsequent connections actually uses the cookie you set?

    Cleaned up the format of the iRule to make it easier for others to read it.

    when CLIENT_ACCEPTED { 
        HTTP::enable
    } 
    
    when HTTP_REQUEST { 
        if { ([string tolower [HTTP::header value Upgrade]] equals "websocket" ) && ([string tolower [HTTP::header value Connection]] equals "upgrade" ) } { 
            log local0. "HTTP Disable" 
            HTTP::disable
        }
    }
    

    /Patrik

  • Patrick, the TMOS HTTP parser does not support WebSockets until v11.4. You cannot insert cookies prior to this version as you either need to remove all HTTP profiles or, as you have done, disable HTTP parsing using an iRule.

     

  • I believe it was unable to persist because http is disabled when using this irules.

     

    can you try to set source address as fallback persistence?

     

  • What if you add LB::select before HTTP::disable to force a pool decision?

    I tried it in my lab and it chose the right pool member all the time, but my stats was a bit strange. Worth a try at least?

    when CLIENT_ACCEPTED { 
        HTTP::enable
    } 
    
    when HTTP_REQUEST { 
        if { ([string tolower [HTTP::header value Upgrade]] equals "websocket" ) && ([string tolower [HTTP::header value Connection]] equals "upgrade" ) } { 
            log local0. "HTTP Disable" 
            LB::select
            HTTP::disable
        }
    }
    

    /Patrik

  • Hi All,

    We're currently using BIG-IP 11.3.0 Build 3164.27. Currently, we trying to enable WebSocket technology on this F5 device. We set up the iRule below to make it work on all browsers.

    CASE 1: 
    when CLIENT_ACCEPTED { 
    HTTP::enable
    } 
    
    when HTTP_REQUEST { 
    if { ([string tolower [HTTP::header value Upgrade]] equals "websocket" ) && ([string tolower               [HTTP::header value Connection]] contains "upgrade" ) } { 
     log local0. "HTTP Disable" 
     LB::select
     HTTP::disable
    }
    

    }

    The main problem that we're facing is with JSESSION ID mapping. When we take a look at the Request and Response headers that JSESSION ID mapping is different as shown below as a result the communication is broken [See Cookie and Set-Cookie fields in Request and Response headers].

    *Request Header:* 
    Accept-Encoding:gzip, deflate, sdch, br
    Accept-Language:en-US,en;q=0.8
    Cache-Control:no-cache
    Connection:Upgrade
    Cookie:togglePanel=0; JSESSIONID=67D1ED8704774B7B254A3249D6AE1F5D.XXXX01;`
    
    *Response Header:* 
    Connection:upgrade
    Date:Fri, 09 Dec 2016 06:04:31 GMT
    Sec-WebSocket-Accept:D1YD5WuwCtcc4kL5MeYZ5kT/cHc=
    Sec-WebSocket-Extensions:permessage-deflate;client_max_window_bits=15
    Server:Apache-Coyote/1.1
    Set-Cookie:JSESSIONID=F9C8FFD641B1E42E99F632BF3D2D6BCD.XXXX02; Path=/Portal/
    Set-Cookie:remember_me=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT
    Upgrade:websocket
    

    We tried using this iRule shown below to fix the mismatch in JSESSION ID, but in vain.

    CASE 2
    when CLIENT_ACCEPTED {
    HTTP::enable
        }
    when HTTP_REQUEST {
    if { ([string tolower [HTTP::header value Upgrade ]] equals "websocket" ) && ([string tolower [HTTP::header value Connection]] contains "upgrade" ) } {
    if {[HTTP::is_keepalive]} {
        HTTP::header replace "Connection" "Upgrade"
       }
    HTTP::disable
    }
    }
    when HTTP_RESPONSE {
    if { [string map {\" ""} [HTTP::cookie "JSESSIONID"]] ne "" } {
    persist add uie [HTTP::cookie "JSESSIONID"]
    }
    }
    }
    

    Is there a workaround in iRule to fix this? Any help would be appreciated.

    Thanks

    • Patrik_Jonsson's avatar
      Patrik_Jonsson
      Icon for MVP rankMVP

      Hi!

       

      Could you please try to clean up the tcl rules by posting with the "Preformatted code" option? That would make it more likely that people will help. :)

       

      /Patrik

       

    • riyer_206339's avatar
      riyer_206339
      Icon for Nimbostratus rankNimbostratus

      Hi,

       

      I've posted formatted TCL code. Please have a look.

       

      Thanks, Ram

       

  • I think this will be a bit tricky without some application side sorcery.

     

    What seems to be happening is that you're disabling the HTTP profile when the client requests a connection upgrade, but then you try to add persistence based on information in the HTTP payload.

     

    However since the HTTP profile has been disabled the F5 is not expecting any HTTP traffic and the response even won't fire.

     

    I don't have a 11.3 version to test with and I doubt this will work, but what if you disable the HTTP profile in the response (after setting the persistence?

     

    /Patrik

     

  • Why do you need cookie persistence? Is this a service with few clients, or where the majority is behind NAT addresses? Otherwise you might consider to persist on source IP?

     

    If you have control over the client you might be able to ask the developers to add a custom header in the initial request, ie "Persist: [client hostname].

     

    Or, and this is an ugly one (not for sensitive eyes), if you have no control over the client you might consider persisting on IP and user agent (concatenate them, make an md5/crc32 hash out of them). Then you might have a bit more spread between browser and browser versions at least.

     

    /Patrik