Forum Discussion

Stephen_Robin_8's avatar
Stephen_Robin_8
Icon for Nimbostratus rankNimbostratus
Jan 25, 2011

Selecting pool using custom protocol over SSL

Our application uses a custom protocol (NOT HTTP) between clients and servers. We're investigating using a BIG-IP device to:

(1) Encrypt the traffic between the client and the BIG-IP using SSL.

(2) Select the server that will handle the connection based on the contents of the first packet that is sent after the SSL connection is established.

First I tried selecting a pool without using SSL. This iRule works fine:

when CLIENT_ACCEPTED {
  log local0. "Connection accepted from [IP::client_addr]:[TCP::client_port]"
  TCP::collect 10
}

when CLIENT_DATA {
  log local0. "Data received [TCP::payload]"

   We would select the pool here based on the payload.

  pool StephenTest
  TCP::release
}

when SERVER_CONNECTED {
  log local0. "Connection mapped to [serverside {IP::local_addr}]:[serverside {TCP::local_port}]"
}

Then I tried encrypting using SSL. I changed my client to use SSL and selected an SSL profile for the virtual server. The new iRule does not work:

when CLIENTSSL_HANDSHAKE {
  log local0. "[IP::client_addr]:[TCP::client_port]: SSL handshake completed, collecting SSL payload"
  SSL::collect 10
}

when CLIENTSSL_DATA {
  log local0. "Data received [SSL::payload]"

   We would select the pool here based on the payload.

  pool "StephenTest"
  SSL::release
}

when LB_FAILED {
  log local0. "LB failed"
}

when SERVER_CONNECTED {
  log local0. "Connection mapped to [serverside {IP::local_addr}]:[serverside {TCP::local_port}]"
}

No data is received by the server process. The client process authenticates the server but fails when it sends the first packet because the BIG-IP has closed the connection. The log shows the CLIENTSSL_HANDSHAKE and LB_FAILED events firing.

If I move the pool statement from the CLIENTSSL_DATA event to the end of the CLIENTSSL_HANDSHAKE event then the server process receives the data as expected and the log shows the CLIENTSSL_HANDSHAKE, CLIENTSSL_DATA and SERVER_CONNECTED firing with the expected payload. Obviously, I can't then select a pool based on the data.

Any help would be greatly appreciated.

Thanks

Stephen

8 Replies

  • Hi Stefan,

     

     

    Yup, I have a Client Side SSL profile on the Virtual Server so the BIG-IP handles SSL. The first rule does still work when using SSL. However, the CLIENT_DATA event receives encrypted traffic, not the decrypted SSL payload. I need to route to a particular pool based on the decrypted traffic.

     

     

    Thanks

     

    Stephen
  • Is your log statement from CLIENTSSL_DATA logging anything? Since we're hitting LB_FAILED, I'll assume not?
  • Hi Chris,

     

     

    No it's not, the only log messages are from CLIENTSSL_HANDSHAKE and LB_FAILED.

     

     

    Thanks

     

    Stephen
  • Just looked at the wiki page for pool and it's not usable from CLIENTSSL_DATA,

     

     

    http://devcentral.f5.com/wiki/default.aspx/iRules/pool.html

     

     

    This might sound ridiculous but I wonder if we can do something from LB_FAILED here.

     

     

    From CLIENTSSL_DATA, perhaps setting a variable to SSL::payload and calling that variable from LB_FAILED. If I think of something better, I'll let you know.

     

  • Thanks Chris. The documentation says that it's not available from CLIENTSSL_HANDSHAKE either, but it seems to work.

     

     

    http://devcentral.f5.com/wiki/default.aspx/iRules/CLIENTSSL_HANDSHAKE.html

     

     

    I've tried from LB_FAILED too and can't make it work yet.
  • Colin_Walker_12's avatar
    Colin_Walker_12
    Historic F5 Account
    What about making use of the LB::reselect command inside the LB_SELECTED event? Set up a default pool for the VIP and then change your code a little bit:

     

     

    
    when CLIENTSSL_HANDSHAKE {
      log local0. "[IP::client_addr]:[TCP::client_port]: SSL handshake completed, collecting SSL payload"
      SSL::collect 10
    }
    
    when CLIENTSSL_DATA {
      log local0. "Data received [SSL::payload]"
    
      Store whatever data you need to make an LB decision in local variables here
    
      SSL::release
    
    }
    
    when LB_SELECTED {
       We would select the pool here based on the local variables you set in the CLIENTSSL_DATA event
    
      LB::reselect pool "StephenTest"
    }
    
    when LB_FAILED {
      log local0. "LB failed"
    }
    
    when SERVER_CONNECTED {
      log local0. "Connection mapped to [serverside {IP::local_addr}]:[serverside {TCP::local_port}]"
    }
    

     

     

    This should effectively do the same thing as your original rule, I believe.

     

     

    Colin
  • spark_86682's avatar
    spark_86682
    Historic F5 Account
    This really sounds like ID 224958, which is fixed in 10.2.0 HF2. Basically, SSL::collect is (erroneously) not holding up the connection, so a server pick is attempted before CLIENTSSL_DATA ever fires, and since there's no pool (since you're trying to specify one in CLIENTSSL_DATA), the connection fails. Also, as you've found, you can't just specify a pool earlier, because the server connection will already be established (or be in the process of getting established) by the time CLIENTSSL_DATA fires. You *might* be able to do something like specify a default pool, and then when CLIENTSSL_DATA fires do an LB::detach and then specify a new pool, but I'd do a lot of testing before putting that sort of a solution into production. Your best bet is to just upgrade. Hope this helps!
  • It looks like ID 224958 is also fixed in 10.2.1:

     

     

     

    http://support.f5.com/kb/en-us/products/big-ip_ltm/releasenotes/product/relnote_10_2_1_ltm.html

     

     

    Unconfigured pool or profile and CLIENTSSL_DATA (ID 224958)

     

    The CLIENTSSL_DATA event now fires correctly regardless of whether or not a pool or profile is configured.

     

     

     

    Aaron