Forum Discussion

Michael_Harwoo1's avatar
Michael_Harwoo1
Icon for Nimbostratus rankNimbostratus
Dec 03, 2015

Need an iRule for STARTTLS for SMTPS Server side ONLY, Not Client side.

With reference to this question i asked earlier and not had any responses for yet:

 

https://devcentral.f5.com/questions/smtp-starttls-server-side-only-not-client-side-on-1160-

 

Are there any irules guru's out there that could rewrite me a STARTTLS irule suitable for the Virtual SERVERSIDE ONLY STARTTLS requirement in that i have described in that question.

 

This page describes an irule to accept STARTTLS this on the client side, possibly with serverside STARTTLS as well i'm not sure: https://devcentral.f5.com/articles/iruleology-ndashsmtp-start-tls and perhaps could be rewritten to only be server side, which is perhaps much simpler as the F5 is just a "client" itself in the STARTTLS negotiation serverside.

 

My understanding of irule programming and STARTTLS is limited and could do with some help. (For version 11.6, a serverside SSL certificate only is applied to the virtual server)

 

4 Replies

  • I have recently found this post by someone else that shows an irule that works almost for what i wanted. https://devcentral.f5.com/questions/adding-starttls-functionality-to-outbound-smtp-sessions-via-irule

    It just needed some tweaking of the "IF" statements to get it to accept the slightly different responses from the TLS SMTPS server we were trying to connect to.

    when CLIENT_ACCEPTED {
         No SSL client side, also check no SSL running already on server side
        log local0. "client accepted"
        SSL::disable serverside 
    }
    when SERVER_CONNECTED {
        TCP::collect 
    }
    when SERVER_DATA {
         Read in responses from remote server into a variable and log to /var/log/ltm
        log local0. "server payload: [string tolower [TCP::payload]]"
        set payload [string tolower [TCP::payload]]
    
    if {$payload starts_with "220" and $payload contains "esmtp"}
        {    
             Listen for remote servers opening 220 and esmtp message 
             NOTE the ‘if’ statement above may need to be tweaked to except what message the other 
             side is actually sending in reply. Logs should show this.
             Respond with a EHLO to server, most servers require a name after the EHLO as well.
    
            TCP::respond "EHLO insert.dns.certificate.server.name.here.com\r\n" 
            TCP::payload replace 0 [TCP::payload length] ""
            TCP::release
            log local0. "responded to server with EHLO"
            serverside {TCP::collect}
            }
    elseif {$payload contains "250-starttls" }
        {    
             Check server responds with "250-starttls", if so, respond with a STARTTLS 
            TCP::respond "STARTTLS\r\n" 
            TCP::payload replace 0 [TCP::payload length] ""
            TCP::release
            log local0. "Sent the server a STARTTLS"
            serverside {TCP::collect}
        }
    elseif {$payload contains "220 ready for tls" or $payload contains "220 2.0.0 continue"}
        {    
             if server gives a 220 response, then start server side ssl profile
             NOTE the ‘if’ statement above may need to be tweaked to except what message the other 
             side is actually sending in reply. Logs should show this.
            log local0. "server said he is ready for TLS, enable the SSL profile"
            TCP::payload replace 0 [TCP::payload length] ""
            TCP::release
            serverside {SSL::enable}
             TLS hanshake should now start, which is best seen in wireshark packet captures. 
        }
    }
    when SERVERSSL_HANDSHAKE {
         This will only trigger if that is completed successfully. 
             ServerSSL profile will need a certificate to match the outbound IP and DNS name, 
             and you may want to set the "Server certificate" setting to "require", 
             and the "Trusted Certificate Authorities" set to "ca-bundle".
        log local0. "SSL handshake completed."
        clientside { TCP::respond "220 SMTP ESMTP Relay F5\r\n" }
        SSL::collect
    }
    when SERVERSSL_DATA {
         Log the SMTP responses to see any errors.
        log local0. "server SSL payload: [SSL::payload]"
        SSL::release
        SSL::collect
    }
    
    • JG_249184's avatar
      JG_249184
      Icon for Altocumulus rankAltocumulus

      How can I use this and have it enable client said ssl when it detects starttls from the client but send clear text when it doesn't?

       

  • Adding on to Michaels answer above, I modified his iRule to work with O365 open relay. It took me a while to figure out, so for me the trick was to have both a ClientSSL and ServerSSL profile, and use a SMTP profile, not a SMTPS profile.

    I'm not sure if this works with client initiated STARTTLS but I suspect it's just combining this with some of the work from https://devcentral.f5.com/questions/smtp-starttls-irule

    when CLIENT_ACCEPTED {
         No SSL client side, also check no SSL running already on server side
         Debug mode
        set DEBUG 0
        if { $DEBUG } { log local0. "CLIENT_ACCEPTED" }
        SSL::disable serverside 
        SSL::disable 
    }
    when SERVER_CONNECTED {
        if { $DEBUG } { log local0. "SERVER_CONNECTED" }
        TCP::collect 
    }
    when SERVER_DATA {
         Read in responses from remote server into a variable and log to /var/log/ltm
        if { $DEBUG } { log local0. "server payload: [string tolower [TCP::payload]]" }
        set payload [string tolower [TCP::payload]]
    
        if {$payload starts_with "220" and $payload contains "esmtp"}
        {    
             Listen for remote servers opening 220 and esmtp message 
             NOTE the ‘if’ statement above may need to be tweaked to except what message the other 
             side is actually sending in reply. Logs should show this.
             Respond with a EHLO to server, most servers require a name after the EHLO as well.
    
            TCP::respond "EHLO F5.mydomain.com\r\n" 
            TCP::payload replace 0 [TCP::payload length] ""
            TCP::release
            if { $DEBUG } { log local0. "responded to server with EHLO" }
            serverside {TCP::collect}
        }
        elseif {$payload contains "250-starttls" }
        {    
             Check server responds with "250-starttls", if so, respond with a STARTTLS 
            TCP::respond "STARTTLS\r\n" 
            TCP::payload replace 0 [TCP::payload length] ""
            TCP::release
            if { $DEBUG } { log local0. "Sent the server a STARTTLS" }
            serverside {TCP::collect}
        }
        elseif {$payload contains "220 ready for tls" or $payload contains "220 2.0.0 continue" or $payload contains "220 2.0.0 smtp server ready" }
        {    
             if server gives a 220 response, then start server side ssl profile
             NOTE the ‘if’ statement above may need to be tweaked to except what message the other 
             side is actually sending in reply. Logs should show this.
             O365 Edit - O365 returns 220 2.0.0 smtp server ready after enabling TLS
            if { $DEBUG } { log local0. "server said he is ready for TLS, enable the SSL profile" }
            TCP::payload replace 0 [TCP::payload length] ""
            TCP::release
            serverside {SSL::enable}
             TLS hanshake should now start, which is best seen in wireshark packet captures. 
        }
    }
    when SERVERSSL_HANDSHAKE {
         This will only trigger if that is completed successfully. 
         ServerSSL profile will need a certificate to match the outbound IP and DNS name, 
         and you may want to set the "Server certificate" setting to "require", 
         and the "Trusted Certificate Authorities" set to "ca-bundle".
        if { $DEBUG } { log local0. "SSL handshake completed." }
        clientside { TCP::respond "220 SMTP ESMTP Relay F5\r\n" }
        SSL::collect
    }
    when SERVERSSL_DATA {
         Log the SMTP responses to see any errors.
        if { $DEBUG } { log local0. "server SSL payload: [SSL::payload]" }
        SSL::release
        SSL::collect
    }
    
    • TimkenSteel's avatar
      TimkenSteel
      Icon for Nimbostratus rankNimbostratus

      Sam: Would you mind sharing your Virtual Server configuration as well as your Client SSL and Server SSL configurations? I'm attempting to configure a SMTP relay to O365 but am not able to get SSL working for the connection between the F5 and O365.