Forum Discussion

Piotr_Lewandows's avatar
Piotr_Lewandows
Icon for Altostratus rankAltostratus
Apr 17, 2016

CLIENT_ACCEPTED, SERVER_ACCEPTED and TCP::collect

Hi,

 

That is probably obvious but I can't really figure out how TCP::collect is working depending on where it was enabled.

 

When CLIENT_ACCEPTED is triggered it means three-way handshake was finished and we are waiting for packet from client.

 

Now when TCP::collect is enabled what is collected:

 

  • Only packets from client to VS (on clientside of the connection)
  • Both packets from client and to client (send from VS to client)

Same for SERVER_ACCEPTED (triggered after three-way handshake between VS and pool member is finished)

 

  • Only packets from VS to pool member (on serverside of the connection)
  • Both packets from VS to pool member and from pool member to VS

What happens when iRule is like that:

 

when CLIENT_ACCEPTED {
    set ehlo 0
    SSL::disable
}
when SERVER_CONNECTED {
    TCP::collect
}
when CLIENT_DATA {
    set lcpayload [string tolower [TCP::payload]]
    if { $lcpayload starts_with "ehlo" } {
        set ehlo 1
        serverside { TCP::collect }
        TCP::release
        TCP::collect
    } elseif { $lcpayload starts_with "starttls" } {
        TCP::respond "220 Ready to start TLS\r\n"
        TCP::payload replace 0 [TCP::payload length] ""
        TCP::release
        SSL::enable
    } else {
        TCP::release
    }
}
when SERVER_DATA {
    if { $ehlo == 1 and not([string tolower [TCP::payload]] contains "starttls") } {
        TCP::payload replace 0 0 "250-STARTTLS\r\n"
    }
    TCP::release
    clientside { TCP::collect }
}

No TCP:collect in CLIENT_ACCEPTED but instead clientside { TCP::collect } in SERVER_ACCEPTED. What is exact flow here (comparing to TCP::collect triggered in CLIENT_ACCEPTED)?

 

What will be flow in case serverside { TCP::collect } is used?

 

Is TCP::release (in SERVER_DATA) used to release packet from VS to pool member or as well from client to VS?

 

My assumption for above is like that:

 

  • Packet from client to VIP is not placed in the buffer - no TCP:collect in CLIENT_ACCEPTED
  • This packet (first packet after three-way handshake on clientside) is triggering three-way handshake on serverside (between VS and pool member)
  • Then TCP::collect is triggered so packet from VS to pool member is placed into buffer
  • When full packet is placed in buffer SERVER_DATA is triggered
  • In SERVER_DATA clientside { TCP::collect} is triggered - so is that mean that second packet from client to VIP is placed into buffer?
  • After collecting full packet CLIENT_DATA is triggered for packet between VS and pool member (serverside { TCP::collect }
  • Collected clientside packet is released to the serverside (TCP::release)
  • Collecting of following clientside packet is enabled (TCP::collect) so next clientside packet will be collected

So in short this code is just skipping first clientside packet and starts collecting clientside packets from second packet or it means first packet from client to pool member is delivered without collecting and first packet from pool member to client is placed into buffer? Or I completely misunderstand it?

 

Piotr

 

4 Replies

  • Firstly, your initial assumptions are correct. In the client-side context (either in CLIENT_ACCEPTED or inside the

    clientside
    command above) a call to
    TCP::collect
    triggers collection of segments on the client-side of the connection, firing CLIENT_DATA when some amount of data are collected (although it may fall on segment boundaries, there is no guarantee of that). Similarly, in the server-side context (in SERVER_CONNECTED above), a call to
    TCP::collect
    triggers collection of segments on the server-side of the connection, firing SERVER_DATA when some amount of data are collected.

    The rule above appears to be for SMTPS. Note that the first message in SMTP is sent from server to client, not the other way around. That's probably why

    TCP::collect
    for the clientside is not invoked until after the first message is received on the serverside. One doesn't expect a clientside message until after the first serverside message is delivered to the client.

  • Hi,

     

    Thanks for info, but part that puzzles me most here if there is rule what is buffered when. Is collect in CLIENT_DATA is always capturing packets from client to VIP and SERVER_DATA capturing packets from pool member to client? Or not really?

     

    That is tricky part for me, is there any relation between where collect is performed and packet direction?

     

    Rule was just an example, I ma trying to understand generic logic here.

     

    Piotr

     

  • Hi,

     

    I was thinking about this a bit and I wonder if I am on the right track:

     

    • First of all I assume that both CLIENT_ACCEPTED and SERVER_CONNECTED events are active only when first packet after 3WHS arrives. After processing this packet events are no more active - correct?
    • Second - it is not important if this first packet is coming from client to pool member or from pool member to client (for both clientside and serverside). As in above example first packet processed will be from pool member (SMTP server) to client - correct?
    • To collect more packets than first one it's necessary to place TCP::release, then TCP::collect in CLIENT_DATA or SERVER_DATA, so first processed packet is released to client or pool member and next packet will be collected - correct?

    Now starts part in the example code I do not understand. Assuming that starttls transaction looks like below (based on Wikipedia):

     

    1. S:
    2. C:
    3. S: 220 mail.example.org ESMTP service ready
    4. C: EHLO client.example.org
    5. S: 250-mail.example.org offers a warm hug of welcome
    6. S: 250 STARTTLS
    7. C: STARTTLS
    8. S: 220 Go ahead
    9. C:
    10. C & S:
    11. C & S:
    12. C: EHLO client.example.org[3]

    My interpretation (starting from point 2):

     

    • 3WHS finished on clientside, CLIENT_ACCEPTED triggered. No data from the client but 3WHS on serverside performed as well (assuming Standard VS with just TCP profile). TCP::collect started on serverside
    • Pool member (SMTP server) sends 220... SERVER_DATA triggered. $ehlo is 0, TCP::pyload do not contain "starttls"
      • Packet released to client - because TCP::collect not jet started it's delivered to client without being captured by TCP::collect (not jet active on clientside) - is that correct?
      • TCP::collect enabled on clientside - so next packet from client to VIP will be placed in the buffer
    • Client sends EHLO...
      • CLIENT_DATA triggered
      • $ehlo set to 1
      • Collect on serverside enabled
      • Packet released to serverside - will this packet be captured, or only next one. I assume this packet will be collected - correct?
      • Collection on the clientside resumed for next packet
    • Seems that 250-mail.example.org... is skipped here?
    • SERVER_DATA is triggered again:
      • if returns true - $ehlo = 1, no starttls in payload
      • No I am lost - from Wikipedia example it's pool member that should send "250 STARTTLS" but it seems that we are replacing content of the packet going from client to pool member "TCP::payload replace 0 0 "250-STARTTLS\r\n"" - or I am totally wrong here?
      • Modified packet is released to the pool member
      • Again collection on the clientside is enabled
    • Assuming that for some reason I am wrong here, previous packet is send to the client not pool member, so client is now replying with "starttls"
      • CLIENT_DATA triggered again
      • Now elseif is true so TCP::respond is send to the client with "220 Ready to..."
      • Payload of the packet going to pool member is emptied
      • Packet is released
      • SSL on VS is re enabled
    • There is no more TCP::collect for serverside so packet is delivered directly to pool member - no SERVER_DATA triggered
    • Client is starting SSL handshake with VS, after finishing following data packets (decrypted) are delivered to pool member without further processing by iRule.

    I think I am pretty close to the truth here but still have filling that I am missing something :-(

     

    Piotr