Forum Discussion

keith_varga_107's avatar
keith_varga_107
Icon for Nimbostratus rankNimbostratus
Jul 30, 2013

F5 irule points to websockets server, but no response back

Currently, we run 32bit 10.2.3 F5.

 

We are trying to use websockets via an irule.

 

For example, the user comes in via the https F5 virtual server, and is directed via an irule to the websockets pool (in this case EXPQA_Pool_11_12)

 

 

irule:

 

when HTTP_REQUEST {

 

HTTP::header insert "X_CLIENT_IP" [IP::client_addr]

 

HTTP::header insert "X-Forwarded-For" [IP::client_addr]

 

if { [string tolower [HTTP::uri]] starts_with "/ws" } {

 

pool EXPQA_Pool_11_12

 

return

 

} else {

 

pool EXPQA_Pool

 

return

 

}

 

}

 

 

 

 

On our test site, we are able to initially connect to the websocket server:

 

-- 2013-07-30T19:07:57.987Z: Connection is opened...

 

 

However, after two minutes, the response never makes it back from the websocket server:

 

TX 2013-07-30T19:07:58.815Z: Device info for serial 1

 

-- 2013-07-30T19:09:57.978Z: Connection is closed...

 

 

 

If we go around the F5, and connect directly to the websocket server, it works fine instantly:

 

-- 2013-07-30T19:21:48.092Z: Connection is opened...

 

TX 2013-07-30T19:21:49.532Z: Device info for serial 1

 

RX 2013-07-30T19:21:50.094Z: {"status":"Device found."}

 

-- 2013-07-30T19:21:50.094Z: Connection is closed...

 

 

 

Any idea why going through the F5 for our websockets conversation would experience that issue?

 

 

thanks much!

 

Keith Varga

 

9 Replies

  • the user comes in via the https F5 virtual server, and is directed via an irule to the websockets pool (in this case EXPQA_Pool_11_12)i am not familiar with websocket. anyway, don't you need to disable http profile (i.e. HTTP::disable) when detecting websocket traffic?
  • correct, we do need to disable http for it to work, and it does. however, we still wanted to have the irule, and the F5 said we couldn't have the irule and http profile enabled together. We found a solution though. Simply add the HTTP::disable

     

    directive to the irule, and now it works!

     

     

    when HTTP_REQUEST {

     

    HTTP::header insert "X_CLIENT_IP" [IP::client_addr]

     

    HTTP::header insert "X-Forwarded-For" [IP::client_addr]

     

    if { [string tolower [HTTP::uri]] starts_with "/ws" } {

     

    pool EXPQA_Pool_11_12

     

    HTTP::disable

     

    return

     

    } else {

     

    pool EXPQA_Pool

     

    return

     

    }

     

    }

     

     

    thanks much all

     

    -Keith

     

     

  • Hi,

    I know the original post here is about a month old but I have just set up our F5 to do just this. However we also have our iRule also restricting URIs based on a DataGroupList as below:

    when HTTP_REQUEST { 
      if { [matchclass [HTTP::uri] starts_with $::MyValidUris] } {
            HTTP::disable
      } else {
        HTTP::respond 404 content [subst $::block_page]
      }
    }
    

    The problem I have is that once HTTP::disable is invoked, F5 can no longer parse the requests as HTTP and therefore cannot restrict URIs as before.

    Is there anyway to re-enable the HTTP profile but selectively disable it when a websocket request comes through?

    Imagine a web site like Amazon, that users can browse. At some point when they want to contact an agent via a "webphone", the site creates a websocket connection to the backend server. If when they want to carry on browsing the site and happen to change the URI on their browser go to an admin page, the iRule no longer restricts that URI. This is the problem I'm trying to work through. Any ideas on what I could do with my iRule would be greatly appreciated.

    Thank you. Sachin

  • Try something like this:

    when CLIENT_ACCEPTED {
        HTTP::enable
    }
    when HTTP_REQUEST {
        if { [matchclass [HTTP::uri] starts_with $::MyValidUris] } [
            HTTP::disable
        } else {
            HTTP::respond 404 content [subst $::block_page]
        }
    }
    
  • Thank you for your reply.

     

    I looked at the docs about this and they say that CLIENT_ACCEPTED is triggered when an entry is inserted in the BIG-IP connection table - meaning only once when the TCP connection is established.

     

    It feels like that means if a website user were to navigate to an unrestricted part of the website, the HTTP profile would be disabled but never re-enabled as the TCP connection has already been established. Therefore allowing the user to change the URI to point at a restricted page.

     

    Do you know if there is a trigger that's fired every time a request is made ... other than a HTTP trigger seeing as that might have been disabled?

     

  • I'm assuming the browser and websocket connections are actually different TCP sessions, so a new websocket TCP session would disable HTTP processing, based on URI in this case but could also be by method, while the browser session would not be affected.

     

  • Thank you Kevin. I took your code and modified it slightly. I've come up with a solution that works quite well. Here's my iRule. I'd be interested in getting your opinion.

     

    Thank you again.

     

    when CLIENT_ACCEPTED {
      HTTP::enable
    }
    
    when HTTP_REQUEST { 
      if { ([HTTP::uri] starts_with "/the-websocket-uri") } {
        HTTP::disable
      } elseif { [class match [HTTP::uri] starts_with UnrestrictedUris] } { 
         Do nothing by design - leaving the HTTP profile enabled
      } else {
         Drop the request
        drop
      } 
    }
  • That looks good. I also see that you went from matchclass to class match. You could technically streamline a little bit more by negating the UnrestrictedUris condition:

    when CLIENT_ACCEPTED {
        HTTP::enable
    }
    when HTTP_REQUEST { 
        if { ([HTTP::uri] starts_with "/the-websocket-uri") } {
            HTTP::disable
        } elseif { not ( [class match [HTTP::uri] starts_with UnrestrictedUris] ) } { 
             Drop the request
            drop
        } 
    }
    
  • Perfect! I noticed that matchclass had been deprecated in v10 which is what I have, so thought it best to use the class command instead.

     

    Thank you :-)