[Dovecot] F5 SLB iRule - POP3 TLS Offload & Add Realm

Lee Standen lee at standen.id.au
Wed Apr 11 06:54:35 EEST 2012


Hey Guys,

I figured someone might have use of this at some point.  I've created an
iRule for our F5 Load Balancer which performs the following tasks:

   - Appends STLS to the POP3 Capability list (it does this blindly, so
   expects the backend POP3 server to not return this)
   - Watches for the STLS command and initiates SSL negotiation with the
   client (leaves the connection to the backend POP3 server unencrypted)
   - Watches for the USER command (login attempt) and appends a realm if
   the user hasn't supplied one
   - Stops watching once a successful login occurs

It's designed to be attached to port 110 and port 995 at the same time, and
will disable SSL if the user is connecting to port 110 until the STLS
command is issued.

This is a first pass, so there's probably room for improvement, but it does
seem to work.  This will require LTM v10 (at least), as the SSL::collect
command didn't exist prior to that version.

Here's the rule:

when CLIENT_ACCEPTED {
  if { [TCP::local_port clientside] == "110" } {
    # Disable SSL if we're on port 110 (as we're doing TLS Offload)
    set secure 0
    SSL::disable
  } else {
    set secure 1
  }
  set realm "mydomain.com"
  set debug 0
  set loggedin 0
}

when SERVER_CONNECTED {
  TCP::collect
}

when CLIENTSSL_HANDSHAKE {
  SSL::collect
  set secure 1
}

when CLIENTSSL_DATA {
  if { $debug } { log local0. "CLIENT DATA: [SSL::payload]" }

  set lcpayload [string tolower [SSL::payload]]

  if { $lcpayload starts_with "user" } {
    scan [SSL::payload] {%s%s} command user
    set pos [string first $user [SSL::payload] 0]
    SSL::payload replace $pos [string length $user] "$user@$realm"
    if { $debug } { log local0. [SSL::payload] }
  }

  SSL::release
  if { $loggedin == 0 } {
    SSL::collect
  }
}

when CLIENT_DATA {
  if { $debug } { log local0. "CLIENT DATA: [TCP::payload]" }
  set lcpayload [string tolower [TCP::payload]]
  if { $lcpayload starts_with "stls" } {
    TCP::respond "+OK Begin TLS negotiation\r\n"
    TCP::payload replace 0 [TCP::payload length] ""
    TCP::release
    SSL::enable
    return
  } elseif { $lcpayload starts_with "user" } {
    scan [TCP::payload] {%s%s} command user
    set pos [string first $user [TCP::payload] 0]
    TCP::payload replace $pos [string length $user] "$user@$realm"
    if { $debug } { log local0. [TCP::payload] }
  }
  TCP::release
  if { $loggedin == 0 } {
    TCP::collect
  }
}

when SERVER_DATA {
  if { $debug } { log local0. "SERVER DATA: [TCP::payload]" }

  set lcpayload [string tolower [TCP::payload]]
  if { $lcpayload starts_with "+ok logged in" } {
    TCP::release
    set loggedin 1
    event disable
    if { $debug } { log local0. "POP3 Login Successful" }
    return
  } elseif { $lcpayload contains "capa" } {
    TCP::payload replace [expr [TCP::payload length] - 3] 0 "STLS\r\n"

  }

  if { $secure == 1 && $loggedin == 0 } {
    clientside { SSL::collect }
  } elseif { $secure == 0 && $loggedin == 0 } {
    clientside { TCP::collect }
  }
  TCP::release
  if { $loggedin == 0 } {
    TCP::collect
  }
}


More information about the dovecot mailing list