Forum Discussion

Eino_Tuominen_2's avatar
Eino_Tuominen_2
Icon for Nimbostratus rankNimbostratus
Oct 28, 2009

Offloading Imap STARTTLS

Hello everybody,

The irule:

 
 when CLIENT_ACCEPTED { 
     SSL::disable 
 } 
  
 when SERVER_CONNECTED { 
     log local0.info "New connection" 
     TCP::collect 
 } 
  
 when CLIENTSSL_HANDSHAKE { 
     log local0.info "HANDSHAKE" 
 } 
  
 when CLIENT_DATA { 
     set lcpayload [string tolower [TCP::payload]] 
     if { $lcpayload contains "starttls" } { 
         set tag [getfield [TCP::payload]  " " 1] 
         TCP::respond "$tag OK STARTTLS completed\r\n" 
         TCP::payload replace 0 [TCP::payload length] "" 
         log local0.info "STARTTLS_DONE" 
         SSL::enable 
     } elseif { $lcpayload contains "logout" } { 
         serverside { TCP::collect } 
     } elseif { $lcpayload contains "capability" } { 
         log local0.info "capability command issued" 
         serverside { TCP::collect } 
     } else { 
         set tag [getfield [TCP::payload]  " " 1] 
         TCP::respond "$tag NO Mechanism not available\r\n" 
         TCP::payload replace 0 [TCP::payload length] "" 
         serverside { TCP::collect } 
     } 
     TCP::release 
 } 
  
 when SERVER_DATA { 
       log local0.info "checking for CAPABILITY" 
       set index [string first "CAPABILITY" [TCP::payload]] 
       if { $index > 0 } { 
           log local0.info "replace CAPABILITY string" 
           TCP::payload replace [expr $index + 10] 0 " STARTTLS LOGINDISABLED" 
           clientside { TCP::collect } 
       } else { 
           log local0.info "No capability string" 
           clientside { TCP::collect } 
       } 
       TCP::release 
 } 
 

This kinda works. Thunderbird is able to connect to the INBOX. But, if I try to open another mailbox, thunderbird hangs and status bar is showing message 'Checking mail server capabilities...'

On the F5 side things are looking just fine:

Oct 28 10:26:56 tmm tmm[1611]: Rule imap-starttls : New connection

Oct 28 10:26:56 tmm tmm[1611]: Rule imap-starttls : checking for CAPABILITY

Oct 28 10:26:56 tmm tmm[1611]: Rule imap-starttls : replace CAPABILITY string

Oct 28 10:26:56 tmm tmm[1611]: Rule imap-starttls : capability command issued

Oct 28 10:26:56 tmm tmm[1611]: Rule imap-starttls : checking for CAPABILITY

Oct 28 10:26:56 tmm tmm[1611]: Rule imap-starttls : replace CAPABILITY string

Oct 28 10:26:56 tmm tmm[1611]: Rule imap-starttls : STARTTLS_DONE

Oct 28 10:26:56 tmm tmm[1611]: Rule imap-starttls : HANDSHAKE

When tracing both the client and server sides I see that Tbird sends the capability command:

-1337352192[3abf240]: 4885a00:imap.utu.fi:NA:SendData: 3 capability

But the server never sees that.

I'm puzzled.

1 Reply

  • Hello. Bellow you can find a working code for imap starttls. It can force the clients to use only TLS connection(require_starttls = 1) or it can allow unencrypted communication. The irule was tested with Thunderbird, Outlook and also openssl s_client and the backend for this irule was Dovecot.

     

    Code
    
    when CLIENT_ACCEPTED { 
         set require_starttls 0
         SSL::disable 
     }   
     when SERVER_CONNECTED {   
         TCP::collect 
     }   
     when CLIENT_DATA {   
         set lcpayload [string tolower [TCP::payload]] 
         if { $lcpayload contains "starttls" } {  
             set tag [getfield [TCP::payload]  " " 1] 
             TCP::respond "$tag OK Begin TLS negotiation now\r\n"
             TCP::payload replace 0 [TCP::payload length] "" 
             TCP::release 
             SSL::enable 
         }
         elseif { $lcpayload contains "capability" } {
             serverside { TCP::collect }  
             TCP::release
             TCP::collect 
         }
     else { 
             if { $require_starttls } { 
                 set id [getfield [TCP::payload]  " " 1] 
                 TCP::respond "BAD \"Must issue a STARTTLS command first\"\r\n" 
                 TCP::payload replace 0 [TCP::payload length] "" 
                 TCP::release 
                 TCP::collect 
             } else { 
                 TCP::release 
             } 
         }   
     }   
     when SERVER_DATA { 
         if { [TCP::payload] contains "* OK \[CAPABILITY" } { 
             TCP::payload replace 16 0 " STARTTLS" 
             TCP::release 
             clientside { TCP::collect } 
        } elseif { [TCP::payload] contains "* CAPABILITY" } { 
             TCP::payload replace 12 0 " STARTTLS" 
             TCP::release 
             clientside { TCP::collect }  
         } else { 
             TCP::release 
             TCP::collect 
         } 
     }