Forum Discussion

BlurredVision_1's avatar
BlurredVision_1
Icon for Nimbostratus rankNimbostratus
Mar 12, 2008

TCP Double Dipping

All,

now that I have the HTTP_DoubleDip iRule working, there is a requirement to do exactly the same thing with a TCP connection. Essentially:

--

Conn to VS

Play to V2 server

Do not send client response

Play to V1 server

Send response to client

--

What I can't figure out is what the correct handling of TCP::collect, TCP::release, and where to put a logic gate in to loop back through to re-send to the V1 server. Anyone have any ideas?

While trying to get my head around the event nesting / structure so I have put together the following:


 when RULE_INIT {
 TCP Double Dip iRule for V2
 First connection is sent to V1, then retried to V2 for the server data to be sent to the client
 Turn logging on or off (0=off, 1=on)
set ::debug 1
 if { $::debug } {log local0. "" } 
if { $::debug } {log local0. "exiting RULE_INIT" }  
}
when CLIENT_ACCEPTED {
if { $::debug } {log local0. "Entering CLIENT_ACCEPTED" } 
set retrying 0
if { $::debug } {log local0. "TCP::collect" } 
TCP::collect
if { $::debug } {log local0. "Exiting CLIENT_ACCEPTED" }
}
when CLIENT_DATA {
if { $::debug } {log local0. "Entering CLIENT_DATA" }
if { $::debug } {log local0. "Setting Pool" }
if { $::debug } {log local0. "Changed Pool from [LB::server pool] " } 
pool Pool-V2
if { $::debug } {log local0. "Changed Pool to [LB::server pool] " } 
if { $::debug } {log local0. "TCP::release" }
TCP::release
 LB_SELECTED / LB_FAILED happens here
if { $::debug } {log local0. "Exiting CLIENT_DATA" } 
}
when CLIENT_CLOSED {
if { $::debug } {log local0. "Entering CLIENT_CLOSED" }
if { $::debug } {log local0. "Exiting CLIENT_CLOSED" } 
}
when LB_SELECTED {
if { $::debug } {log local0. "Entering LB_SELECTED" }
if { $::debug } {log local0. "LB_SELECTED chose [LB::server pool] " } 
if { $::debug } {log local0. "Exiting LB_SELECTED" } 
}
when SERVER_CONNECTED {
if { $::debug } {log local0. "Entering SERVER_CONNECTED" }
if { $::debug } {log local0. "TCP::collect" }
TCP::collect
if { $::debug } {log local0. "Exiting SERVER_CONNECTED" } 
}
when SERVER_DATA {
if { $::debug } {log local0. "Entering SERVER_DATA" }
if { $::debug } {log local0. "TCP::release" }
TCP::release
if { $::debug } {log local0. "TCP::collect" }
TCP::collect
if { $::debug } {log local0. "LB::detach" }
LB::detach
if { $::debug } {log local0. "Exiting SERVER_DATA" } 
}
when SERVER_CLOSED {
if { $::debug } {log local0. "Entering SERVER_CLOSED" }
if { $::debug } {log local0. "Exiting SERVER_CLOSED" } 
}

The log output of /var/log/ltm is as follows:

Mar 12 13:43:09 tmm tmm[9953]: Rule : exiting RULE_INIT
Mar 12 13:43:13 tmm tmm[9953]: Rule TCP_DoubleDip : Entering LB_SELECTED
Mar 12 13:43:13 tmm tmm[9953]: Rule TCP_DoubleDip : LB_SELECTED chose V1
Mar 12 13:43:13 tmm tmm[9953]: Rule TCP_DoubleDip : Exiting LB_SELECTED
Mar 12 13:43:13 tmm tmm[9953]: Rule TCP_DoubleDip : Entering SERVER_CONNECTED
Mar 12 13:43:13 tmm tmm[9953]: Rule TCP_DoubleDip : TCP::collect
Mar 12 13:43:13 tmm tmm[9953]: Rule TCP_DoubleDip : Exiting SERVER_CONNECTED
Mar 12 13:43:13 tmm tmm[9953]: Rule TCP_DoubleDip : Entering SERVER_DATA
Mar 12 13:43:13 tmm tmm[9953]: Rule TCP_DoubleDip : TCP::release
Mar 12 13:43:13 tmm tmm[9953]: Rule TCP_DoubleDip : TCP::collect
Mar 12 13:43:13 tmm tmm[9953]: Rule TCP_DoubleDip : LB::detach
Mar 12 13:43:13 tmm tmm[9953]: Rule TCP_DoubleDip : Exiting SERVER_DATA
Mar 12 13:43:13 tmm tmm[9953]: Rule TCP_DoubleDip : Entering SERVER_CLOSED
Mar 12 13:43:13 tmm tmm[9953]: Rule TCP_DoubleDip : Exiting SERVER_CLOSED
Mar 12 13:43:16 tmm tmm[9953]: Rule TCP_DoubleDip : Entering LB_SELECTED
Mar 12 13:43:16 tmm tmm[9953]: Rule TCP_DoubleDip : LB_SELECTED chose V1
Mar 12 13:43:16 tmm tmm[9953]: Rule TCP_DoubleDip : Exiting LB_SELECTED
Mar 12 13:43:16 tmm tmm[9953]: Rule TCP_DoubleDip : Entering SERVER_CONNECTED
Mar 12 13:43:16 tmm tmm[9953]: Rule TCP_DoubleDip : TCP::collect
Mar 12 13:43:16 tmm tmm[9953]: Rule TCP_DoubleDip : Exiting SERVER_CONNECTED
Mar 12 13:43:16 tmm tmm[9953]: Rule TCP_DoubleDip : Entering SERVER_DATA
Mar 12 13:43:16 tmm tmm[9953]: Rule TCP_DoubleDip : TCP::release
Mar 12 13:43:16 tmm tmm[9953]: Rule TCP_DoubleDip : TCP::collect
Mar 12 13:43:16 tmm tmm[9953]: Rule TCP_DoubleDip : LB::detach
Mar 12 13:43:16 tmm tmm[9953]: Rule TCP_DoubleDip : Exiting SERVER_DATA
Mar 12 13:43:16 tmm tmm[9953]: Rule TCP_DoubleDip : Entering SERVER_CLOSED
Mar 12 13:43:16 tmm tmm[9953]: Rule TCP_DoubleDip : Exiting SERVER_CLOSED
Mar 12 13:44:21 tmm tmm[9953]: Rule TCP_DoubleDip : Entering CLIENT_CLOSED
Mar 12 13:44:21 tmm tmm[9953]: Rule TCP_DoubleDip : Exiting CLIENT_CLOSED
  • Did you ever think of using clone pool? This is a setting on virtual server. It sounds very much like what you are doing except F5 supports it's with a mouse click.
  • if you need to do such a thing for exmaple to send traffic to an IDS or anything else, cmbhatt is right clone pool should do the job.

     

     

    Be careful, the clone pool has one restriction: the BIGIP needs to see the MAC addresses of the clone pool members.
  • Clone pools won't help here. We had to abandon this idea. iRules can't take a single TCP stream and turn it into 2 as propper TCP streams (ie: not just cloning traffic to an IDS)

     

     

    if only iRules would allow you to create new TCP sockets!!

     

     

    oh well...

     

     

  • Main reason for abandoning was that iRules cannot maintain 2 TCP sockets off a single data stream. There is no way to create an arbitrary socket to the second server and honour the TCP connection sequence incrementation etc.

     

     

    unfortunately there is no TCP::retry function...

     

     

    We can grab the TCP payload and send it somewhere else, but once you release it, there is no way to send it somewhere else after the fact.